mirror of
https://github.com/enso-org/enso.git
synced 2024-11-23 08:08:34 +03:00
Clean up the stopgap IR (#521)
This commit is contained in:
parent
06363f4126
commit
e8fcb445be
@ -481,7 +481,8 @@ lazy val runtime = (project in file("engine/runtime"))
|
||||
"org.scalactic" %% "scalactic" % "3.2.0-M2" % Test,
|
||||
"org.scalatest" %% "scalatest" % "3.2.0-M2" % Test,
|
||||
"org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark,
|
||||
"org.typelevel" %% "cats-core" % catsVersion
|
||||
"org.typelevel" %% "cats-core" % catsVersion,
|
||||
"eu.timepit" %% "refined" % "0.9.12"
|
||||
),
|
||||
// Note [Unmanaged Classpath]
|
||||
Compile / unmanagedClasspath += (core_definition / Compile / packageBin).value,
|
||||
|
@ -390,7 +390,7 @@ object CoreGraph {
|
||||
*/
|
||||
case class CentreSection(operator: Link[G])
|
||||
|
||||
/** A representatin of a term that is explicitly forced.
|
||||
/** A representation of a term that is explicitly forced.
|
||||
*
|
||||
* An explicitly forced term is one where the user has explicitly
|
||||
* called the `force` operator on it. This is useful only while the
|
||||
|
@ -4,7 +4,7 @@ import com.oracle.truffle.api.RootCallTarget;
|
||||
import com.oracle.truffle.api.Truffle;
|
||||
import com.oracle.truffle.api.nodes.RootNode;
|
||||
import org.enso.compiler.core.AstArgDefinitionVisitor;
|
||||
import org.enso.compiler.core.AstExpression;
|
||||
import org.enso.compiler.core.IR.Expression;
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.ClosureRootNode;
|
||||
@ -84,7 +84,7 @@ public class ArgDefinitionFactory implements AstArgDefinitionVisitor<ArgumentDef
|
||||
*/
|
||||
@Override
|
||||
public ArgumentDefinition visitArg(
|
||||
String name, Optional<AstExpression> defaultValue, boolean suspended, int position) {
|
||||
String name, Optional<Expression> defaultValue, boolean suspended, int position) {
|
||||
ExpressionNode defExpression =
|
||||
defaultValue
|
||||
.map(
|
||||
|
@ -3,11 +3,11 @@ package org.enso.interpreter.builder;
|
||||
import com.oracle.truffle.api.RootCallTarget;
|
||||
import com.oracle.truffle.api.Truffle;
|
||||
import org.enso.compiler.core.AstCallArgVisitor;
|
||||
import org.enso.compiler.core.AstExpression;
|
||||
import org.enso.compiler.core.IR.Expression;
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.enso.compiler.core.AstForce;
|
||||
import org.enso.compiler.core.IR.ForcedTerm;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.ClosureRootNode;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
@ -64,12 +64,12 @@ public class CallArgFactory implements AstCallArgVisitor<CallArgument> {
|
||||
* @return a runtime representation of the argument
|
||||
*/
|
||||
@Override
|
||||
public CallArgument visitCallArg(Optional<String> name, AstExpression value, int position) {
|
||||
public CallArgument visitCallArg(Optional<String> name, Expression value, int position) {
|
||||
ExpressionNode result;
|
||||
|
||||
if (value instanceof AstForce) {
|
||||
if (value instanceof ForcedTerm) {
|
||||
ExpressionFactory factory = new ExpressionFactory(language, source, scope, scopeName, moduleScope);
|
||||
result = ((AstForce) value).target().visit(factory);
|
||||
result = ((ForcedTerm) value).target().visit(factory);
|
||||
} else {
|
||||
LocalScope childScope = new LocalScope(scope);
|
||||
ExpressionFactory factory =
|
||||
|
@ -13,20 +13,20 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.enso.compiler.core.AstApply;
|
||||
import org.enso.compiler.core.AstArgDefinition;
|
||||
import org.enso.compiler.core.AstArithOp;
|
||||
import org.enso.compiler.core.AstAssignment;
|
||||
import org.enso.compiler.core.AstCallArg;
|
||||
import org.enso.compiler.core.AstCaseFunction;
|
||||
import org.enso.compiler.core.AstExpression;
|
||||
import org.enso.compiler.core.AstExpressionVisitor;
|
||||
import org.enso.compiler.core.AstForce;
|
||||
import org.enso.compiler.core.AstFunction;
|
||||
import org.enso.compiler.core.AstLong;
|
||||
import org.enso.compiler.core.AstMatch;
|
||||
import org.enso.compiler.core.AstStringLiteral;
|
||||
import org.enso.compiler.core.AstVariable;
|
||||
import org.enso.compiler.core.IR.BinaryOperator;
|
||||
import org.enso.compiler.core.IR.Binding;
|
||||
import org.enso.compiler.core.IR.CallArgumentDefinition;
|
||||
import org.enso.compiler.core.IR.CaseFunction;
|
||||
import org.enso.compiler.core.IR.DefinitionSiteArgument;
|
||||
import org.enso.compiler.core.IR.Expression;
|
||||
import org.enso.compiler.core.IR.ForcedTerm;
|
||||
import org.enso.compiler.core.IR.Lambda;
|
||||
import org.enso.compiler.core.IR.CaseExpr;
|
||||
import org.enso.compiler.core.IR.LiteralName;
|
||||
import org.enso.compiler.core.IR.NumberLiteral;
|
||||
import org.enso.compiler.core.IR.Prefix;
|
||||
import org.enso.compiler.core.IR.TextLiteral;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.ClosureRootNode;
|
||||
@ -142,7 +142,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @param expr the expression to make executable
|
||||
* @return a node representing the provided computation
|
||||
*/
|
||||
public ExpressionNode run(AstExpression expr) {
|
||||
public ExpressionNode run(Expression expr) {
|
||||
ExpressionNode result = expr.visit(this);
|
||||
result.markNotTail();
|
||||
return result;
|
||||
@ -169,8 +169,8 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing that value
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitLong(AstLong l) {
|
||||
return setLocation(new IntegerLiteralNode(l.value()), l.getLocation());
|
||||
public ExpressionNode visitLong(NumberLiteral l) {
|
||||
return setLocation(new IntegerLiteralNode(Long.parseLong(l.value())), l.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,8 +180,8 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing this literal
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitStringLiteral(AstStringLiteral string) {
|
||||
ExpressionNode node = new TextLiteralNode(string.string());
|
||||
public ExpressionNode visitStringLiteral(TextLiteral string) {
|
||||
ExpressionNode node = new TextLiteralNode(string.text());
|
||||
return setLocation(node, string.getLocation());
|
||||
}
|
||||
|
||||
@ -192,10 +192,10 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing the arithmetic expression
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitArithOp(AstArithOp ast) {
|
||||
public ExpressionNode visitArithOp(BinaryOperator ast) {
|
||||
ExpressionNode left = ast.left().visit(this);
|
||||
ExpressionNode right = ast.right().visit(this);
|
||||
String operator = ast.op();
|
||||
String operator = ast.operator();
|
||||
ExpressionNode resultOp = null;
|
||||
if (operator.equals("+")) {
|
||||
resultOp = AddOperatorNodeGen.create(left, right);
|
||||
@ -233,12 +233,12 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* <p>This method is solely responsible for looking up a variable in the parent scope with the
|
||||
* provided name and does not handle associating that variable with a value.
|
||||
*
|
||||
* @param astVariable the AST to represent
|
||||
* @param astName the AST to represent
|
||||
* @return a runtime node representing the variable
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitVariable(AstVariable astVariable) {
|
||||
String name = astVariable.name();
|
||||
public ExpressionNode visitName(LiteralName astName) {
|
||||
String name = astName.name();
|
||||
Optional<ExpressionNode> currentModuleVariable =
|
||||
name.equals(Constants.Names.CURRENT_MODULE)
|
||||
? Optional.of(new ConstructorNode(moduleScope.getAssociatedType()))
|
||||
@ -255,7 +255,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
.map(Optional::get)
|
||||
.findFirst()
|
||||
.orElseGet(() -> new DynamicSymbolNode(new UnresolvedSymbol(name, moduleScope)));
|
||||
return setLocation(variableRead, astVariable.getLocation());
|
||||
return setLocation(variableRead, astName.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,7 +270,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing the function body
|
||||
*/
|
||||
public CreateFunctionNode processFunctionBody(
|
||||
Optional<Location> location, List<AstArgDefinition> arguments, AstExpression body) {
|
||||
Optional<Location> location, List<DefinitionSiteArgument> arguments, Expression body) {
|
||||
ArgDefinitionFactory argFactory =
|
||||
new ArgDefinitionFactory(scope, language, source, scopeName, moduleScope);
|
||||
ArgumentDefinition[] argDefinitions = new ArgumentDefinition[arguments.size()];
|
||||
@ -333,17 +333,17 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* Creates a runtime node representing a function.
|
||||
*
|
||||
* <p>Given that most of the work takes place in {@link #processFunctionBody(Optional, List,
|
||||
* AstExpression)}, this node is solely responsible for handling the creation of a new scope for
|
||||
* the function, and marking it as tail recursive.
|
||||
* Expression)}, this node is solely responsible for handling the creation of a new scope for the
|
||||
* function, and marking it as tail recursive.
|
||||
*
|
||||
* @param function the AST to represent
|
||||
* @param lambda the AST to represent
|
||||
* @return a runtime node representing the function
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitFunction(AstFunction function) {
|
||||
public ExpressionNode visitLambda(Lambda lambda) {
|
||||
ExpressionFactory child = createChild(currentVarName);
|
||||
ExpressionNode fun =
|
||||
child.processFunctionBody(function.getLocation(), function.getArguments(), function.body());
|
||||
child.processFunctionBody(lambda.getLocation(), lambda.getArguments(), lambda.body());
|
||||
fun.markTail();
|
||||
return fun;
|
||||
}
|
||||
@ -352,17 +352,19 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* Creates a runtime node representing a case function.
|
||||
*
|
||||
* <p>Given that most of the work takes place in {@link #processFunctionBody(Optional, List,
|
||||
* AstExpression) processFunctionBody}, this node is solely responsible for handling the creation
|
||||
* of a new scope for the function.
|
||||
* Expression) processFunctionBody}, this node is solely responsible for handling the creation of
|
||||
* a new scope for the function.
|
||||
*
|
||||
* @param function the AST to represent
|
||||
* @return a runtime node representing the function
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitCaseFunction(AstCaseFunction function) {
|
||||
public ExpressionNode visitCaseFunction(CaseFunction function) {
|
||||
ExpressionFactory child = createChild("case_expression");
|
||||
return child.processFunctionBody(
|
||||
function.getLocation(), function.getArguments(), function.body());
|
||||
|
||||
// Explicitly not marked as tail
|
||||
}
|
||||
|
||||
/**
|
||||
@ -372,9 +374,9 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing the function call
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitFunctionApplication(AstApply application) {
|
||||
public ExpressionNode visitFunctionApplication(Prefix application) {
|
||||
CallArgFactory argFactory = new CallArgFactory(scope, language, source, scopeName, moduleScope);
|
||||
List<AstCallArg> arguments = application.getArgs();
|
||||
List<CallArgumentDefinition> arguments = application.getArgs();
|
||||
List<CallArgument> callArgs = new ArrayList<>();
|
||||
for (int position = 0; position < arguments.size(); ++position) {
|
||||
CallArgument arg = arguments.get(position).visit(argFactory, position);
|
||||
@ -388,7 +390,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
|
||||
ApplicationNode appNode =
|
||||
new ApplicationNode(
|
||||
application.fun().visit(this),
|
||||
application.function().visit(this),
|
||||
callArgs.toArray(new CallArgument[0]),
|
||||
defaultsExecutionMode);
|
||||
setLocation(appNode, application.getLocation());
|
||||
@ -402,40 +404,40 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
* @return a runtime node representing the assignment
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitAssignment(AstAssignment ast) {
|
||||
public ExpressionNode visitAssignment(Binding ast) {
|
||||
currentVarName = ast.name();
|
||||
FrameSlot slot = scope.createVarSlot(ast.name());
|
||||
return setLocation(AssignmentNodeGen.create(ast.body().visit(this), slot), ast.getLocation());
|
||||
return setLocation(AssignmentNodeGen.create(ast.expression().visit(this), slot), ast.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a runtime node representing a pattern match.
|
||||
*
|
||||
* @param match the AST to represent
|
||||
* @param caseExpr the AST to represent
|
||||
* @return a runtime node representing a pattern match expression
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitMatch(AstMatch match) {
|
||||
public ExpressionNode visitMatch(CaseExpr caseExpr) {
|
||||
// AstExpression target, List<AstCase> branches, Optional<AstCaseFunction> fallback) {
|
||||
|
||||
ExpressionNode targetNode = match.target().visit(this);
|
||||
ExpressionNode targetNode = caseExpr.scrutinee().visit(this);
|
||||
CaseNode[] cases =
|
||||
match.getBranches().stream()
|
||||
caseExpr.getBranches().stream()
|
||||
.map(
|
||||
branch ->
|
||||
new ConstructorCaseNode(
|
||||
branch.cons().visit(this), branch.function().visit(this)))
|
||||
branch.pattern().visit(this), branch.expression().visit(this)))
|
||||
.toArray(CaseNode[]::new);
|
||||
|
||||
// Note [Pattern Match Fallbacks]
|
||||
CaseNode fallbackNode =
|
||||
match
|
||||
caseExpr
|
||||
.getFallback()
|
||||
.map(fb -> (CaseNode) new FallbackNode(fb.visit(this)))
|
||||
.orElseGet(DefaultFallbackNode::new);
|
||||
|
||||
ExpressionNode matchExpr = MatchNodeGen.create(cases, fallbackNode, targetNode);
|
||||
return setLocation(matchExpr, match.getLocation());
|
||||
return setLocation(matchExpr, caseExpr.getLocation());
|
||||
}
|
||||
|
||||
/* Note [Pattern Match Fallbacks]
|
||||
@ -449,13 +451,13 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
/**
|
||||
* Creates a runtime representation of lazy function argument forcing.
|
||||
*
|
||||
* @param force the AST to represent
|
||||
* @param forcedTerm the AST to represent
|
||||
* @return the AST fragment representing forcing of the requested value
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitForce(AstForce force) {
|
||||
ForceNode node = ForceNodeGen.create(force.target().visit(this));
|
||||
return setLocation(node, force.getLocation());
|
||||
public ExpressionNode visitForce(ForcedTerm forcedTerm) {
|
||||
ForceNode node = ForceNodeGen.create(forcedTerm.target().visit(this));
|
||||
return setLocation(node, forcedTerm.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -467,7 +469,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode visitBlock(
|
||||
List<AstExpression> statements, AstExpression retValue, boolean suspended) {
|
||||
List<Expression> statements, Expression retValue, boolean suspended) {
|
||||
if (suspended) {
|
||||
ExpressionFactory childFactory = this.createChild("suspended-block");
|
||||
LocalScope childScope = childFactory.scope;
|
||||
|
@ -1,8 +1,19 @@
|
||||
package org.enso.interpreter.builder;
|
||||
|
||||
import org.enso.compiler.core.*;
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
import org.enso.interpreter.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.enso.compiler.core.IR.DefinitionSiteArgument;
|
||||
import org.enso.compiler.core.IR.Expression;
|
||||
import org.enso.compiler.core.IR.AstImport;
|
||||
import org.enso.compiler.core.IR.Module;
|
||||
import org.enso.compiler.core.AstModuleScopeVisitor;
|
||||
import org.enso.compiler.core.IR.MethodDef;
|
||||
import org.enso.compiler.core.IR.AtomDef;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.callable.function.CreateFunctionNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
@ -12,11 +23,6 @@ import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.error.VariableDoesNotExistException;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* A {@code GlobalScopeExpressionFactory} is responsible for converting the top-level definitions of
|
||||
* an Enso program into AST nodes for the interpreter to evaluate.
|
||||
@ -44,7 +50,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
*
|
||||
* @param expr the expression to execute on
|
||||
*/
|
||||
public void run(AstModuleScope expr) {
|
||||
public void run(Module expr) {
|
||||
expr.visit(this);
|
||||
}
|
||||
|
||||
@ -52,12 +58,12 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
* Processes definitions in the language global scope.
|
||||
*
|
||||
* @param imports any imports requested by this module
|
||||
* @param typeDefs any type definitions defined in the global scope
|
||||
* @param atomDefs any type definitions defined in the global scope
|
||||
* @param bindings any bindings made in the global scope
|
||||
*/
|
||||
@Override
|
||||
public void visitModuleScope(
|
||||
List<AstImport> imports, List<AstTypeDef> typeDefs, List<AstMethodDef> bindings) {
|
||||
List<AstImport> imports, List<AtomDef> atomDefs, List<MethodDef> bindings) {
|
||||
Context context = language.getCurrentContext();
|
||||
|
||||
for (AstImport imp : imports) {
|
||||
@ -65,7 +71,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
}
|
||||
|
||||
List<AtomConstructor> constructors =
|
||||
typeDefs.stream()
|
||||
atomDefs.stream()
|
||||
.map(type -> new AtomConstructor(type.name(), moduleScope))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@ -76,7 +82,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
idx -> {
|
||||
ArgDefinitionFactory argFactory =
|
||||
new ArgDefinitionFactory(language, source, moduleScope);
|
||||
AstTypeDef type = typeDefs.get(idx);
|
||||
AtomDef type = atomDefs.get(idx);
|
||||
ArgumentDefinition[] argDefs = new ArgumentDefinition[type.getArguments().size()];
|
||||
|
||||
for (int i = 0; i < type.getArguments().size(); ++i) {
|
||||
@ -86,10 +92,10 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
constructors.get(idx).initializeFields(argDefs);
|
||||
});
|
||||
|
||||
for (AstMethodDef method : bindings) {
|
||||
scala.Option<AstExpression> scalaNone = scala.Option.apply(null);
|
||||
AstArgDefinition thisArgument =
|
||||
new AstArgDefinition(Constants.Names.THIS_ARGUMENT, scalaNone, false);
|
||||
for (MethodDef method : bindings) {
|
||||
scala.Option<Expression> scalaNone = scala.Option.apply(null);
|
||||
DefinitionSiteArgument thisArgument =
|
||||
new DefinitionSiteArgument(Constants.Names.THIS_ARGUMENT, scalaNone, false);
|
||||
|
||||
String typeName = method.typeName();
|
||||
if (typeName.equals(Constants.Names.CURRENT_MODULE)) {
|
||||
@ -103,12 +109,12 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
|
||||
typeName + Constants.SCOPE_SEPARATOR + method.methodName(),
|
||||
moduleScope);
|
||||
|
||||
List<AstArgDefinition> realArgs = new ArrayList<>(method.fun().getArguments());
|
||||
List<DefinitionSiteArgument> realArgs = new ArrayList<>(method.function().getArguments());
|
||||
realArgs.add(0, thisArgument);
|
||||
|
||||
CreateFunctionNode funNode =
|
||||
expressionFactory.processFunctionBody(
|
||||
method.fun().getLocation(), realArgs, method.fun().body());
|
||||
method.function().getLocation(), realArgs, method.function().body());
|
||||
funNode.markTail();
|
||||
Function function =
|
||||
new Function(
|
||||
|
@ -4,7 +4,8 @@ import java.io.StringReader
|
||||
|
||||
import com.oracle.truffle.api.TruffleFile
|
||||
import com.oracle.truffle.api.source.Source
|
||||
import org.enso.compiler.core.{AstExpression, AstModuleScope}
|
||||
import org.enso.compiler.core.IR.Expression
|
||||
import org.enso.compiler.core.IR.Module
|
||||
import org.enso.compiler.generate.AstToAstExpression
|
||||
import org.enso.flexer.Reader
|
||||
import org.enso.interpreter.builder.{ExpressionFactory, ModuleScopeExpressionFactory}
|
||||
@ -157,7 +158,7 @@ class Compiler(
|
||||
* @param sourceAST the parser AST input
|
||||
* @return an IR representation of the program represented by `sourceAST`
|
||||
*/
|
||||
def translate(sourceAST: AST): AstModuleScope =
|
||||
def translate(sourceAST: AST): Module =
|
||||
AstToAstExpression.translate(sourceAST)
|
||||
|
||||
/**
|
||||
@ -167,6 +168,6 @@ class Compiler(
|
||||
* @param sourceAST the parser AST representing the program source
|
||||
* @return an IR representation of the program represented by `sourceAST`
|
||||
*/
|
||||
def translateInline(sourceAST: AST): Option[AstExpression] =
|
||||
def translateInline(sourceAST: AST): Option[Expression] =
|
||||
AstToAstExpression.translateInline(sourceAST)
|
||||
}
|
||||
|
577
engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala
Normal file
577
engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala
Normal file
@ -0,0 +1,577 @@
|
||||
package org.enso.compiler.core
|
||||
|
||||
import java.util.Optional
|
||||
|
||||
import org.enso.compiler.core.IR._
|
||||
import org.enso.syntax.text.{AST, Location}
|
||||
import shapeless.HList
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.jdk.OptionConverters._
|
||||
|
||||
// TODO [AA] Refactor into a proper nested hierarchy once all clients are
|
||||
// written in scala.
|
||||
// TODO [AA] Add location information to the constructs that are currently
|
||||
// missing it but should have it (primarily for tracking during desugaring).
|
||||
// TODO [AA] Loosen type-based restrictions on what can appear where as
|
||||
// necessary.
|
||||
// TODO [AA] Have more things fall into the expression hierarchy as the visitor
|
||||
// goes away.
|
||||
|
||||
/** [[IR]] is a temporary and fairly unsophisticated internal representation
|
||||
* format for Enso programs.
|
||||
*
|
||||
* It is a purely tree-based representation to support basic desugaring and
|
||||
* analysis passes that do not rely on the ability to create cycles in the IR
|
||||
* itself. Its existence is the natural evolution of the older AstExpression
|
||||
* format used during the initial development of the interpreter.
|
||||
*
|
||||
* In time, it will be replaced by [[Core]], but expediency dictates that we
|
||||
* retain and evolve this representation for the near future.
|
||||
*
|
||||
* PLEASE NOTE: None of the visitor functions are documented as they are slated
|
||||
* for removal as part of the next task.
|
||||
*/
|
||||
sealed trait IR
|
||||
object IR {
|
||||
|
||||
// === Basic Shapes =========================================================
|
||||
|
||||
/** An IR node representing an empty construct. */
|
||||
sealed case class Empty() extends IR with IRKind.Primitive
|
||||
|
||||
/** Allows for the tagging of [[IR]] nodes with arbitrary [[data]].
|
||||
*
|
||||
* The [[data]] is represented as an [[HList]] to allow for the stacking of
|
||||
* multiple pieces of arbitrary data as needed.
|
||||
*
|
||||
* @param ir the [[IR]] node being tagged
|
||||
* @param data the data to associated with [[ir]]
|
||||
* @tparam T the type of the arbitrary data
|
||||
*/
|
||||
sealed case class Tagged[T <: HList](ir: IR, data: T)
|
||||
extends IR
|
||||
with IRKind.Primitive
|
||||
|
||||
// === Literals =============================================================
|
||||
|
||||
/** A trait representing all Enso literals. */
|
||||
sealed trait Literal extends Expression with IRKind.Primitive
|
||||
|
||||
/** A numeric Enso literal.
|
||||
*
|
||||
* @param location the source location of the literal
|
||||
* @param value the textual representation of the numeric literal
|
||||
*/
|
||||
sealed case class NumberLiteral(location: Option[Location], value: String)
|
||||
extends Literal {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitLong(this)
|
||||
}
|
||||
|
||||
/** A textual Enso literal.
|
||||
*
|
||||
* @param location the source location of the literal
|
||||
* @param text the text of the literal
|
||||
*/
|
||||
sealed case class TextLiteral(location: Option[Location], text: String)
|
||||
extends Literal {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitStringLiteral(this)
|
||||
}
|
||||
|
||||
// === Names ================================================================
|
||||
|
||||
/** A trait representing all kinds of name in Enso. */
|
||||
sealed trait Name extends Expression with IRKind.Primitive
|
||||
|
||||
/** The representation of a literal name.
|
||||
*
|
||||
* @param location the source location of tha name occurrence.
|
||||
* @param name the literal text of the name
|
||||
*/
|
||||
sealed case class LiteralName(location: Option[Location], name: String)
|
||||
extends Name {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitName(this)
|
||||
}
|
||||
|
||||
// TODO [AA] Add `this` and `here` as names.
|
||||
|
||||
// === Module ===============================================================
|
||||
|
||||
// TODO [AA] Need to add a `name` field to the module
|
||||
/** A representation of a top-level Enso module.
|
||||
*
|
||||
* Modules may only contain imports and top-level bindings, with no top-level
|
||||
* executable code.
|
||||
*
|
||||
* @param imports the import statements that bring other modules into scope
|
||||
* @param bindings the top-level bindings for this module
|
||||
*/
|
||||
sealed case class Module(
|
||||
imports: List[AstImport],
|
||||
bindings: List[TopLevelSymbol]
|
||||
) extends IR
|
||||
with IRKind.Primitive {
|
||||
|
||||
def visit[T](visitor: AstModuleScopeVisitor[T]): Unit = {
|
||||
val types = new java.util.ArrayList[AtomDef]()
|
||||
val defs = new java.util.ArrayList[MethodDef]()
|
||||
|
||||
bindings.foreach {
|
||||
case assignment: MethodDef => defs.add(assignment)
|
||||
case typeDef: AtomDef => types.add(typeDef)
|
||||
}
|
||||
|
||||
visitor.visitModuleScope(
|
||||
imports.asJava,
|
||||
types,
|
||||
defs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// === Top-Level Symbols ====================================================
|
||||
|
||||
/** A top-level symbol is one that can occur only at the top-level of an Enso
|
||||
* module.
|
||||
*/
|
||||
sealed trait TopLevelSymbol extends IR
|
||||
|
||||
/** The definition of an atom constructor and its associated arguments.
|
||||
*
|
||||
* @param name the name of the atom
|
||||
* @param arguments the arguments to the atom constructor
|
||||
*/
|
||||
sealed case class AtomDef(
|
||||
name: String,
|
||||
arguments: List[DefinitionSiteArgument]
|
||||
) extends TopLevelSymbol
|
||||
with IRKind.Primitive {
|
||||
def getArguments: java.util.List[DefinitionSiteArgument] = arguments.asJava
|
||||
}
|
||||
|
||||
/** The definition of a method for a given constructor [[typeName]].
|
||||
*
|
||||
* @param typeName the name of the atom that the method is being defined on
|
||||
* @param methodName the name of the method being defined on `typename`
|
||||
* @param function the body of the method
|
||||
*/
|
||||
sealed case class MethodDef(
|
||||
typeName: String,
|
||||
methodName: String,
|
||||
function: Lambda
|
||||
) extends TopLevelSymbol
|
||||
with IRKind.Primitive
|
||||
|
||||
/** An import statement.
|
||||
*
|
||||
* @param name the full `.`-separated path representing the import
|
||||
*/
|
||||
sealed case class AstImport(name: String) extends IR with IRKind.Primitive
|
||||
|
||||
// === Expression ===========================================================
|
||||
|
||||
/** A representation of all Enso program expressions. */
|
||||
sealed trait Expression extends IR {
|
||||
|
||||
/** The source location of the Expression.
|
||||
*
|
||||
* @return the expression's source location
|
||||
*/
|
||||
def location: Option[Location]
|
||||
|
||||
/** Gets the location from the expression.
|
||||
*
|
||||
* @return the location, if it exists, otherwise `null`
|
||||
*/
|
||||
def getLocation: Optional[Location] = Optional.ofNullable(location.orNull)
|
||||
|
||||
def visit[T](visitor: AstExpressionVisitor[T]): T
|
||||
}
|
||||
|
||||
// === Typing ===============================================================
|
||||
|
||||
sealed trait Type extends IR
|
||||
|
||||
// TODO [AA] Type ascription, context ascription, typeset member and the
|
||||
// typeset operators
|
||||
|
||||
// === Function =============================================================
|
||||
|
||||
/** A trait to represent all Enso function formats. */
|
||||
sealed trait Function extends Expression
|
||||
|
||||
/** The primitive function type in Enso: `->`.
|
||||
*
|
||||
* It should be noted that while the _surface_ language does not support
|
||||
* multi-argument lambdas, our internal representation does so to allow for
|
||||
* better optimisation.
|
||||
*
|
||||
* @param location the source location of the lambda definition
|
||||
* @param arguments the arguments to the lambda
|
||||
* @param body the body of the lambda
|
||||
*/
|
||||
case class Lambda(
|
||||
location: Option[Location],
|
||||
arguments: List[DefinitionSiteArgument],
|
||||
body: Expression
|
||||
) extends Function
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitLambda(this)
|
||||
|
||||
def getArguments: java.util.List[DefinitionSiteArgument] = arguments.asJava
|
||||
}
|
||||
|
||||
// === Definition-Site Arguments ============================================
|
||||
|
||||
/** The representation of an argument from a [[Lambda]] or [[AtomDef]]
|
||||
* definition site.
|
||||
*
|
||||
* @param name the name of the argument
|
||||
* @param defaultValue the default value of the argument, if present
|
||||
* @param suspended whether or not the argument has its execution suspended
|
||||
*/
|
||||
sealed case class DefinitionSiteArgument(
|
||||
name: String,
|
||||
defaultValue: Option[Expression],
|
||||
suspended: Boolean
|
||||
) extends IR
|
||||
with IRKind.Primitive {
|
||||
|
||||
def visit[T](visitor: AstArgDefinitionVisitor[T], position: Int): T =
|
||||
visitor.visitArg(
|
||||
name,
|
||||
Optional.ofNullable(defaultValue.orNull),
|
||||
suspended,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
// TODO [AA] Add support for `_` ignored arguments.
|
||||
|
||||
// === Applications =========================================================
|
||||
|
||||
/** A representation of all function applications in Enso. */
|
||||
sealed trait Application extends Expression
|
||||
|
||||
/** A standard prefix function application
|
||||
*
|
||||
* @param location the source location of the application
|
||||
* @param function the function being called
|
||||
* @param arguments the arguments to the function being called
|
||||
* @param hasDefaultsSuspended whether the function application has any
|
||||
* argument defaults in `function` suspended
|
||||
*/
|
||||
sealed case class Prefix(
|
||||
location: Option[Location],
|
||||
function: Expression,
|
||||
arguments: List[CallArgumentDefinition],
|
||||
hasDefaultsSuspended: Boolean
|
||||
) extends Application
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitFunctionApplication(this)
|
||||
def getArgs: java.util.List[CallArgumentDefinition] = arguments.asJava
|
||||
}
|
||||
|
||||
/** A representation of a generic binary operator in Enso.
|
||||
*
|
||||
* @param location the source location of the operator
|
||||
* @param left the left operand to `operator`
|
||||
* @param operator the operator function being called
|
||||
* @param right the right operand to `operator`
|
||||
*/
|
||||
sealed case class BinaryOperator(
|
||||
location: Option[Location],
|
||||
left: Expression,
|
||||
operator: String,
|
||||
right: Expression
|
||||
) extends Application
|
||||
with IRKind.Sugar {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitArithOp(this)
|
||||
}
|
||||
|
||||
/** A representation of a term that is explicitly forced.
|
||||
*
|
||||
* @param location the source location of the force
|
||||
* @param target the expression being forced
|
||||
*/
|
||||
sealed case class ForcedTerm(location: Option[Location], target: Expression)
|
||||
extends Application
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitForce(this)
|
||||
}
|
||||
|
||||
// TODO [AA] Add support for left, right, and centre sections
|
||||
|
||||
// === Call-Site Arguments ==================================================
|
||||
|
||||
/** A representation of an argument at a function call site.
|
||||
*
|
||||
* @param name the name of the argument being called, if present
|
||||
* @param value the expression being passed as the argument's value
|
||||
*/
|
||||
sealed case class CallArgumentDefinition(
|
||||
name: Option[String],
|
||||
value: Expression
|
||||
) extends IR
|
||||
with IRKind.Primitive {
|
||||
def visit[T](visitor: AstCallArgVisitor[T], position: Int): T =
|
||||
visitor.visitCallArg(name.toJava, value, position)
|
||||
}
|
||||
|
||||
// TODO [AA] Add support for the `_` lambda shorthand argument.
|
||||
|
||||
// === Structure ============================================================
|
||||
|
||||
// TODO [AA] Remove suspended blocks from Enso.
|
||||
/** A block expression.
|
||||
*
|
||||
* @param location the source location of the block
|
||||
* @param expressions the expressions in the block
|
||||
* @param returnValue the final expression in the block
|
||||
* @param suspended whether or not the block is suspended
|
||||
*/
|
||||
sealed case class Block(
|
||||
location: Option[Location],
|
||||
expressions: List[Expression],
|
||||
returnValue: Expression,
|
||||
suspended: Boolean = false
|
||||
) extends Expression
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitBlock(expressions.asJava, returnValue, suspended)
|
||||
}
|
||||
|
||||
/** A binding expression of the form `name = expr`
|
||||
*
|
||||
* @param location the source location of the binding
|
||||
* @param name the name being bound to
|
||||
* @param expression the expression being bound to `name`
|
||||
*/
|
||||
case class Binding(
|
||||
location: Option[Location],
|
||||
name: String,
|
||||
expression: Expression
|
||||
) extends Expression
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitAssignment(this)
|
||||
}
|
||||
|
||||
// === Case Expression ======================================================
|
||||
|
||||
/** The Enso case expression.
|
||||
*
|
||||
* @param location the source location of the case expression
|
||||
* @param scrutinee the expression whose value is being matched on
|
||||
* @param branches the branches of the case expression
|
||||
* @param fallback a fallback branch, if provided explicitly
|
||||
*/
|
||||
sealed case class CaseExpr(
|
||||
location: Option[Location],
|
||||
scrutinee: Expression,
|
||||
branches: Seq[CaseBranch],
|
||||
fallback: Option[CaseFunction]
|
||||
) extends Expression
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitMatch(this)
|
||||
def getBranches: java.util.List[CaseBranch] = branches.asJava
|
||||
def getFallback: Optional[CaseFunction] =
|
||||
Optional.ofNullable(fallback.orNull)
|
||||
}
|
||||
|
||||
// TODO [AA] Should become an expression
|
||||
/** A branch in a case statement.
|
||||
*
|
||||
* @param location the source location of the case branch
|
||||
* @param pattern the pattern that attempts to match against the scrutinee
|
||||
* @param expression the expression that is executed if the pattern matches
|
||||
*/
|
||||
sealed case class CaseBranch(
|
||||
location: Option[Location],
|
||||
pattern: Expression,
|
||||
expression: CaseFunction
|
||||
) extends IRKind.Primitive
|
||||
|
||||
// TODO [AA] Get rid of case function as ExpressionFactory is moved across.
|
||||
/** A representation of the expression body of a case branch.
|
||||
*
|
||||
* This function type is temporary to aid the visitor and should be removed
|
||||
* as part of the next task.
|
||||
*
|
||||
* @param location the source location of the case function
|
||||
* @param arguments the arguments to the function
|
||||
* @param body the body of the function
|
||||
*/
|
||||
case class CaseFunction(
|
||||
location: Option[Location],
|
||||
arguments: List[DefinitionSiteArgument],
|
||||
body: Expression
|
||||
) extends Expression
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitCaseFunction(this)
|
||||
|
||||
def getArguments: java.util.List[DefinitionSiteArgument] = arguments.asJava
|
||||
}
|
||||
|
||||
// TODO [AA] Better differentiate the types of patterns that can occur
|
||||
|
||||
// === Comments =============================================================
|
||||
|
||||
/** A documentation comment in the Enso source.
|
||||
*
|
||||
* @param location the source location of the comment
|
||||
* @param commented the expression with which the comment is associated
|
||||
* @param doc the documentation of `commented`
|
||||
*/
|
||||
sealed case class DocComment(
|
||||
location: Option[Location],
|
||||
commented: Expression,
|
||||
doc: String
|
||||
) extends IRKind.Primitive
|
||||
|
||||
// TODO [AA] The above needs to extend `Expression` once the visitor is gone.
|
||||
|
||||
// === Foreign ==============================================================
|
||||
|
||||
/** A foreign code definition in Enso.
|
||||
*
|
||||
* @param location the source location of the foreign code definition
|
||||
* @param lang the foreign language being written
|
||||
* @param code the code written in `lang`
|
||||
*/
|
||||
sealed case class ForeignDefinition(
|
||||
location: Option[Location],
|
||||
lang: String,
|
||||
code: String
|
||||
) extends Expression
|
||||
with IRKind.Primitive {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitForeign(lang, code)
|
||||
}
|
||||
|
||||
// === Errors ===============================================================
|
||||
|
||||
/** A trait for all errors in Enso's IR. */
|
||||
sealed trait Error extends IR with IRKind.Primitive
|
||||
object Error {
|
||||
|
||||
/** A representation of an Enso syntax error.
|
||||
*
|
||||
* @param ast the erroneous AST
|
||||
*/
|
||||
sealed case class Syntax(ast: AST) extends Error
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// === Primitive / Sugar ====================================================
|
||||
// ==========================================================================
|
||||
|
||||
/** A trait representing the classification of IR nodes into either primitive
|
||||
* (constructs which will remain after desugaring) or sugar (constructs that
|
||||
* should be removed by the desugaring passes).
|
||||
*/
|
||||
sealed trait IRKind {}
|
||||
object IRKind {
|
||||
|
||||
/** This trait encodes that a given piece of the [[IR]] is considered to be
|
||||
* a primitive construct in Enso.
|
||||
*/
|
||||
sealed trait Primitive extends IRKind
|
||||
|
||||
/** This trait encodes that a given piece of the [[IR]] is considered to
|
||||
* represent syntax sugar in Enso.
|
||||
*
|
||||
* All [[Sugar]] constructs should be desugared into [[Primitive]]
|
||||
* constructs as soon as possible.
|
||||
*/
|
||||
sealed trait Sugar extends IRKind
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// === Visitors ===============================================================
|
||||
// ============================================================================
|
||||
|
||||
/** The visitor pattern for the [[Expression]] types.
|
||||
*
|
||||
* @tparam T the type resultant from the visitor
|
||||
*/
|
||||
trait AstExpressionVisitor[+T] {
|
||||
def visitLong(l: NumberLiteral): T
|
||||
|
||||
def visitArithOp(astArithOp: BinaryOperator): T
|
||||
|
||||
def visitForeign(lang: String, code: String): T
|
||||
|
||||
def visitName(astName: LiteralName): T
|
||||
|
||||
def visitLambda(function: Lambda): T
|
||||
|
||||
def visitCaseFunction(function: CaseFunction): T
|
||||
|
||||
def visitFunctionApplication(application: Prefix): T
|
||||
|
||||
def visitAssignment(assignment: Binding): T
|
||||
|
||||
def visitMatch(astMatch: CaseExpr): T
|
||||
|
||||
def visitForce(target: ForcedTerm): T
|
||||
|
||||
def visitStringLiteral(string: TextLiteral): T
|
||||
|
||||
def visitBlock(
|
||||
statements: java.util.List[Expression],
|
||||
retValue: Expression,
|
||||
suspended: Boolean
|
||||
): T
|
||||
}
|
||||
|
||||
/** The visitor pattern for the [[AstModuleScope]] types.
|
||||
*
|
||||
* @tparam T the type resultant from the visitor
|
||||
*/
|
||||
trait AstModuleScopeVisitor[T] {
|
||||
|
||||
@throws(classOf[Exception])
|
||||
def visitModuleScope(
|
||||
imports: java.util.List[AstImport],
|
||||
typeDefs: java.util.List[AtomDef],
|
||||
bindings: java.util.List[MethodDef]
|
||||
): Unit
|
||||
}
|
||||
|
||||
/** The visitor pattern for the [[DefinitionSiteArgument]] types.
|
||||
*
|
||||
* @tparam T the type resultant from the visitor
|
||||
*/
|
||||
trait AstArgDefinitionVisitor[+T] {
|
||||
|
||||
def visitArg(
|
||||
name: String,
|
||||
value: Optional[Expression],
|
||||
suspended: Boolean,
|
||||
position: Int
|
||||
): T
|
||||
}
|
||||
|
||||
/** The visitor pattern for the [[CallArgumentDefinition]] types.
|
||||
*
|
||||
* @tparam T the type resultant from the visitor
|
||||
*/
|
||||
trait AstCallArgVisitor[+T] {
|
||||
|
||||
def visitCallArg(
|
||||
name: Optional[String],
|
||||
value: Expression,
|
||||
position: Int
|
||||
): T
|
||||
}
|
@ -1,247 +0,0 @@
|
||||
package org.enso.compiler.core
|
||||
|
||||
import java.util.Optional
|
||||
|
||||
import org.enso.syntax.text.Location
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
trait AstExpressionVisitor[+T] {
|
||||
def visitLong(l: AstLong): T
|
||||
|
||||
def visitArithOp(astArithOp: AstArithOp): T
|
||||
|
||||
def visitForeign(lang: String, code: String): T
|
||||
|
||||
def visitVariable(astVariable: AstVariable): T
|
||||
|
||||
def visitFunction(function: AstFunction): T
|
||||
|
||||
def visitCaseFunction(function: AstCaseFunction): T
|
||||
|
||||
def visitFunctionApplication(application: AstApply): T
|
||||
|
||||
def visitAssignment(assignment: AstAssignment): T
|
||||
|
||||
def visitMatch(astMatch: AstMatch): T
|
||||
|
||||
def visitForce(target: AstForce): T
|
||||
|
||||
def visitStringLiteral(string: AstStringLiteral): T
|
||||
|
||||
def visitBlock(
|
||||
statements: java.util.List[AstExpression],
|
||||
retValue: AstExpression,
|
||||
suspended: Boolean
|
||||
): T
|
||||
}
|
||||
|
||||
trait AstModuleScopeVisitor[T] {
|
||||
|
||||
@throws(classOf[Exception])
|
||||
def visitModuleScope(
|
||||
imports: java.util.List[AstImport],
|
||||
typeDefs: java.util.List[AstTypeDef],
|
||||
bindings: java.util.List[AstMethodDef],
|
||||
): Unit
|
||||
}
|
||||
|
||||
sealed trait AstModuleSymbol
|
||||
|
||||
case class AstTypeDef(name: String, arguments: List[AstArgDefinition])
|
||||
extends AstModuleSymbol {
|
||||
def getArguments: java.util.List[AstArgDefinition] = arguments.asJava
|
||||
}
|
||||
|
||||
case class AstMethodDef(typeName: String, methodName: String, fun: AstFunction)
|
||||
extends AstModuleSymbol
|
||||
|
||||
case class AstImport(name: String)
|
||||
|
||||
case class AstModuleScope(
|
||||
imports: List[AstImport],
|
||||
bindings: List[AstModuleSymbol],
|
||||
) {
|
||||
|
||||
def visit[T](visitor: AstModuleScopeVisitor[T]): Unit = {
|
||||
val types = new java.util.ArrayList[AstTypeDef]()
|
||||
val defs = new java.util.ArrayList[AstMethodDef]()
|
||||
|
||||
bindings.foreach {
|
||||
case assignment: AstMethodDef => defs.add(assignment)
|
||||
case typeDef: AstTypeDef => types.add(typeDef)
|
||||
}
|
||||
|
||||
visitor.visitModuleScope(
|
||||
imports.asJava,
|
||||
types,
|
||||
defs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait AstExpression {
|
||||
def location: Option[Location]
|
||||
def getLocation: Optional[Location] = Optional.ofNullable(location.orNull)
|
||||
def visit[T](visitor: AstExpressionVisitor[T]): T
|
||||
}
|
||||
|
||||
trait AstArgDefinitionVisitor[+T] {
|
||||
|
||||
def visitArg(
|
||||
name: String,
|
||||
value: Optional[AstExpression],
|
||||
suspended: Boolean,
|
||||
position: Int
|
||||
): T
|
||||
}
|
||||
|
||||
case class AstArgDefinition(
|
||||
name: String,
|
||||
defaultValue: Option[AstExpression],
|
||||
suspended: Boolean
|
||||
) {
|
||||
|
||||
def visit[T](visitor: AstArgDefinitionVisitor[T], position: Int): T =
|
||||
visitor.visitArg(
|
||||
name,
|
||||
Optional.ofNullable(defaultValue.orNull),
|
||||
suspended,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
sealed trait AstCallArg {
|
||||
def visit[T](visitor: AstCallArgVisitor[T], position: Int): T
|
||||
}
|
||||
|
||||
trait AstCallArgVisitor[+T] {
|
||||
|
||||
def visitCallArg(
|
||||
name: Optional[String],
|
||||
value: AstExpression,
|
||||
position: Int
|
||||
): T
|
||||
}
|
||||
|
||||
case class AstNamedCallArg(name: String, value: AstExpression)
|
||||
extends AstCallArg {
|
||||
override def visit[T](visitor: AstCallArgVisitor[T], position: Int): T =
|
||||
visitor.visitCallArg(Optional.of(name), value, position)
|
||||
}
|
||||
|
||||
case class AstUnnamedCallArg(value: AstExpression) extends AstCallArg {
|
||||
override def visit[T](visitor: AstCallArgVisitor[T], position: Int): T =
|
||||
visitor.visitCallArg(Optional.empty(), value, position)
|
||||
}
|
||||
|
||||
case class AstLong(location: Option[Location], value: Long)
|
||||
extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitLong(this)
|
||||
}
|
||||
|
||||
case class AstStringLiteral(location: Option[Location], string: String)
|
||||
extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitStringLiteral(this)
|
||||
}
|
||||
|
||||
case class AstArithOp(
|
||||
location: Option[Location],
|
||||
op: String,
|
||||
left: AstExpression,
|
||||
right: AstExpression
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitArithOp(this)
|
||||
}
|
||||
|
||||
case class AstForeign(location: Option[Location], lang: String, code: String)
|
||||
extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitForeign(lang, code)
|
||||
}
|
||||
|
||||
case class AstVariable(location: Option[Location], name: String)
|
||||
extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitVariable(this)
|
||||
}
|
||||
|
||||
case class AstApply(
|
||||
location: Option[Location],
|
||||
fun: AstExpression,
|
||||
args: List[AstCallArg],
|
||||
hasDefaultsSuspended: Boolean
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitFunctionApplication(this)
|
||||
def getArgs: java.util.List[AstCallArg] = args.asJava
|
||||
}
|
||||
|
||||
case class AstFunction(
|
||||
location: Option[Location],
|
||||
arguments: List[AstArgDefinition],
|
||||
body: AstExpression
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitFunction(this)
|
||||
|
||||
def getArguments: java.util.List[AstArgDefinition] = arguments.asJava
|
||||
}
|
||||
|
||||
case class AstCaseFunction(
|
||||
location: Option[Location],
|
||||
arguments: List[AstArgDefinition],
|
||||
body: AstExpression
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitCaseFunction(this)
|
||||
|
||||
def getArguments: java.util.List[AstArgDefinition] = arguments.asJava
|
||||
}
|
||||
|
||||
case class AstAssignment(
|
||||
location: Option[Location],
|
||||
name: String,
|
||||
body: AstExpression
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitAssignment(this)
|
||||
}
|
||||
|
||||
case class AstCase(
|
||||
location: Option[Location],
|
||||
cons: AstExpression,
|
||||
function: AstCaseFunction
|
||||
)
|
||||
|
||||
case class AstMatch(
|
||||
location: Option[Location],
|
||||
target: AstExpression,
|
||||
branches: Seq[AstCase],
|
||||
fallback: Option[AstCaseFunction]
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitMatch(this)
|
||||
def getBranches: java.util.List[AstCase] = branches.asJava
|
||||
def getFallback: Optional[AstCaseFunction] =
|
||||
Optional.ofNullable(fallback.orNull)
|
||||
}
|
||||
|
||||
case class AstForce(location: Option[Location], target: AstExpression)
|
||||
extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitForce(this)
|
||||
}
|
||||
|
||||
case class AstBlock(
|
||||
location: Option[Location],
|
||||
statements: List[AstExpression],
|
||||
retVal: AstExpression,
|
||||
suspended: Boolean = false
|
||||
) extends AstExpression {
|
||||
override def visit[T](visitor: AstExpressionVisitor[T]): T =
|
||||
visitor.visitBlock(statements.asJava, retVal, suspended)
|
||||
}
|
@ -2,8 +2,7 @@ package org.enso.compiler.generate
|
||||
|
||||
import cats.Foldable
|
||||
import cats.implicits._
|
||||
import org.enso.compiler.core
|
||||
import org.enso.compiler.core._
|
||||
import org.enso.compiler.core.IR._
|
||||
import org.enso.compiler.exception.UnhandledEntity
|
||||
import org.enso.interpreter.Constants
|
||||
import org.enso.syntax.text.{AST, Location}
|
||||
@ -15,7 +14,7 @@ import org.enso.syntax.text.{AST, Location}
|
||||
* This file contains the functionality that translates from the parser's
|
||||
* [[AST]] type to the internal representation used by the compiler.
|
||||
*
|
||||
* This representation is currently [[AstExpression]], but this will change as
|
||||
* This representation is currently [[Expression]], but this will change as
|
||||
* [[Core]] becomes implemented. Most function docs will refer to [[Core]]
|
||||
* now, as this will become true soon.
|
||||
*/
|
||||
@ -27,7 +26,7 @@ object AstToAstExpression {
|
||||
* @param inputAST the [[AST]] representing the program to translate
|
||||
* @return the [[Core]] representation of `inputAST`
|
||||
*/
|
||||
def translate(inputAST: AST): AstModuleScope = {
|
||||
def translate(inputAST: AST): Module = {
|
||||
inputAST match {
|
||||
case AST.Module.any(inputAST) => translateModule(inputAST)
|
||||
case _ => {
|
||||
@ -46,7 +45,7 @@ object AstToAstExpression {
|
||||
* @return the [[Core]] representation of `inputAST` if it is valid,
|
||||
* otherwise [[None]]
|
||||
*/
|
||||
def translateInline(inputAST: AST): Option[AstExpression] = {
|
||||
def translateInline(inputAST: AST): Option[Expression] = {
|
||||
inputAST match {
|
||||
case AST.Module.any(module) =>
|
||||
val presentBlocks = module.lines.collect {
|
||||
@ -60,7 +59,7 @@ object AstToAstExpression {
|
||||
case List(expr) => Some(expr)
|
||||
case _ =>
|
||||
Some(
|
||||
AstBlock(
|
||||
Block(
|
||||
Foldable[List].foldMap(expressions)(_.location),
|
||||
expressions.dropRight(1),
|
||||
expressions.last
|
||||
@ -76,7 +75,7 @@ object AstToAstExpression {
|
||||
* @param module the [[AST]] representation of the module to translate
|
||||
* @return the [[Core]] representation of `module`
|
||||
*/
|
||||
def translateModule(module: AST.Module): AstModuleScope = {
|
||||
def translateModule(module: AST.Module): Module = {
|
||||
module match {
|
||||
case AST.Module(blocks) => {
|
||||
val presentBlocks = blocks.collect {
|
||||
@ -93,7 +92,7 @@ object AstToAstExpression {
|
||||
}
|
||||
|
||||
val statements = nonImportBlocks.map(translateModuleSymbol)
|
||||
core.AstModuleScope(imports, statements)
|
||||
Module(imports, statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,13 +103,13 @@ object AstToAstExpression {
|
||||
* @param inputAST the definition to be translated
|
||||
* @return the [[Core]] representation of `inputAST`
|
||||
*/
|
||||
def translateModuleSymbol(inputAST: AST): AstModuleSymbol = {
|
||||
def translateModuleSymbol(inputAST: AST): TopLevelSymbol = {
|
||||
inputAST match {
|
||||
case AST.Def(consName, args, body) =>
|
||||
if (body.isDefined) {
|
||||
throw new RuntimeException("Cannot support complex type defs yet!!!!")
|
||||
} else {
|
||||
AstTypeDef(consName.name, args.map(translateArgumentDefinition(_)))
|
||||
AtomDef(consName.name, args.map(translateArgumentDefinition(_)))
|
||||
}
|
||||
case AstView.MethodDefinition(targetPath, name, definition) =>
|
||||
val path = if (targetPath.nonEmpty) {
|
||||
@ -120,11 +119,11 @@ object AstToAstExpression {
|
||||
}
|
||||
val nameStr = name match { case AST.Ident.Var(name) => name }
|
||||
val defExpression = translateExpression(definition)
|
||||
val defExpr: AstFunction = defExpression match {
|
||||
case fun: AstFunction => fun
|
||||
case expr => AstFunction(expr.location, List(), expr)
|
||||
val defExpr: Lambda = defExpression match {
|
||||
case fun: Lambda => fun
|
||||
case expr => Lambda(expr.location, List(), expr)
|
||||
}
|
||||
AstMethodDef(path, nameStr, defExpr)
|
||||
MethodDef(path, nameStr, defExpr)
|
||||
case _ =>
|
||||
throw new UnhandledEntity(inputAST, "translateModuleSymbol")
|
||||
}
|
||||
@ -135,14 +134,14 @@ object AstToAstExpression {
|
||||
* @param inputAST the expresion to be translated
|
||||
* @return the [[Core]] representation of `inputAST`
|
||||
*/
|
||||
def translateExpression(inputAST: AST): AstExpression = {
|
||||
def translateExpression(inputAST: AST): Expression = {
|
||||
inputAST match {
|
||||
case AstView
|
||||
.SuspendedBlock(name, block @ AstView.Block(lines, lastLine)) =>
|
||||
AstAssignment(
|
||||
Binding(
|
||||
inputAST.location,
|
||||
name.name,
|
||||
AstBlock(
|
||||
Block(
|
||||
block.location,
|
||||
lines.map(translateExpression),
|
||||
translateExpression(lastLine),
|
||||
@ -152,7 +151,7 @@ object AstToAstExpression {
|
||||
case AstView.Assignment(name, expr) =>
|
||||
translateBinding(inputAST.location, name, expr)
|
||||
case AstView.MethodCall(target, name, args) =>
|
||||
AstApply(
|
||||
Prefix(
|
||||
inputAST.location,
|
||||
translateExpression(name),
|
||||
(target :: args).map(translateCallArgument),
|
||||
@ -169,7 +168,7 @@ object AstToAstExpression {
|
||||
.drop(nonFallbackBranches.length)
|
||||
.headOption
|
||||
.map(translateFallbackBranch)
|
||||
AstMatch(
|
||||
CaseExpr(
|
||||
inputAST.location,
|
||||
actualScrutinee,
|
||||
nonFallbackBranches,
|
||||
@ -182,7 +181,7 @@ object AstToAstExpression {
|
||||
translateGroup(inputAST, translateExpression)
|
||||
case AST.Ident.any(inputAST) => translateIdent(inputAST)
|
||||
case AstView.Block(lines, retLine) =>
|
||||
AstBlock(
|
||||
Block(
|
||||
inputAST.location,
|
||||
lines.map(translateExpression),
|
||||
translateExpression(retLine)
|
||||
@ -204,14 +203,14 @@ object AstToAstExpression {
|
||||
* @param literal the literal to translate
|
||||
* @return the [[Core]] representation of `literal`
|
||||
*/
|
||||
def translateLiteral(literal: AST.Literal): AstExpression = {
|
||||
def translateLiteral(literal: AST.Literal): Expression = {
|
||||
literal match {
|
||||
case AST.Literal.Number(base, number) => {
|
||||
if (base.isDefined && base.get != "10") {
|
||||
throw new RuntimeException("Only base 10 is currently supported")
|
||||
}
|
||||
|
||||
AstLong(literal.location, number.toLong)
|
||||
NumberLiteral(literal.location, number)
|
||||
}
|
||||
case AST.Literal.Text.any(literal) =>
|
||||
literal.shape match {
|
||||
@ -221,7 +220,7 @@ object AstToAstExpression {
|
||||
case AST.Literal.Text.Segment.RawEsc(code) => code.repr
|
||||
}.mkString
|
||||
|
||||
AstStringLiteral(literal.location, fullString)
|
||||
TextLiteral(literal.location, fullString)
|
||||
case AST.Literal.Text.Block.Raw(lines, _, _) =>
|
||||
val fullString = lines
|
||||
.map(
|
||||
@ -233,7 +232,7 @@ object AstToAstExpression {
|
||||
)
|
||||
.mkString("\n")
|
||||
|
||||
AstStringLiteral(literal.location, fullString)
|
||||
TextLiteral(literal.location, fullString)
|
||||
case AST.Literal.Text.Block.Fmt(_, _, _) =>
|
||||
throw new RuntimeException("Format strings not yet supported")
|
||||
case AST.Literal.Text.Line.Fmt(_) =>
|
||||
@ -255,10 +254,10 @@ object AstToAstExpression {
|
||||
def translateArgumentDefinition(
|
||||
arg: AST,
|
||||
isSuspended: Boolean = false
|
||||
): AstArgDefinition = {
|
||||
): DefinitionSiteArgument = {
|
||||
arg match {
|
||||
case AstView.LazyAssignedArgumentDefinition(name, value) =>
|
||||
AstArgDefinition(
|
||||
DefinitionSiteArgument(
|
||||
name.name,
|
||||
Some(translateExpression(value)),
|
||||
true
|
||||
@ -266,9 +265,9 @@ object AstToAstExpression {
|
||||
case AstView.LazyArgument(arg) =>
|
||||
translateArgumentDefinition(arg, isSuspended = true)
|
||||
case AstView.DefinitionArgument(arg) =>
|
||||
AstArgDefinition(arg.name, None, isSuspended)
|
||||
DefinitionSiteArgument(arg.name, None, isSuspended)
|
||||
case AstView.AssignedArgument(name, value) =>
|
||||
AstArgDefinition(
|
||||
DefinitionSiteArgument(
|
||||
name.name,
|
||||
Some(translateExpression(value)),
|
||||
isSuspended
|
||||
@ -284,10 +283,10 @@ object AstToAstExpression {
|
||||
* @param arg the argument to translate
|
||||
* @return the [[Core]] representation of `arg`
|
||||
*/
|
||||
def translateCallArgument(arg: AST): AstCallArg = arg match {
|
||||
def translateCallArgument(arg: AST): CallArgumentDefinition = arg match {
|
||||
case AstView.AssignedArgument(left, right) =>
|
||||
AstNamedCallArg(left.name, translateExpression(right))
|
||||
case _ => AstUnnamedCallArg(translateExpression(arg))
|
||||
CallArgumentDefinition(Some(left.name), translateExpression(right))
|
||||
case _ => CallArgumentDefinition(None, translateExpression(arg))
|
||||
}
|
||||
|
||||
/** Translates an arbitrary expression that takes the form of a syntactic
|
||||
@ -296,10 +295,10 @@ object AstToAstExpression {
|
||||
* @param callable the callable to translate
|
||||
* @return the [[Core]] representation of `callable`
|
||||
*/
|
||||
def translateApplicationLike(callable: AST): AstExpression = {
|
||||
def translateApplicationLike(callable: AST): Expression = {
|
||||
callable match {
|
||||
case AstView.ForcedTerm(term) =>
|
||||
AstForce(callable.location, translateExpression(term))
|
||||
ForcedTerm(callable.location, translateExpression(term))
|
||||
case AstView.Application(name, args) =>
|
||||
val validArguments = args.filter {
|
||||
case AstView.SuspendDefaultsOperator(_) => false
|
||||
@ -312,7 +311,7 @@ object AstToAstExpression {
|
||||
|
||||
val hasDefaultsSuspended = suspendPositions.contains(args.length - 1)
|
||||
|
||||
AstApply(
|
||||
Prefix(
|
||||
callable.location,
|
||||
translateExpression(name),
|
||||
validArguments.map(translateCallArgument),
|
||||
@ -321,18 +320,13 @@ object AstToAstExpression {
|
||||
case AstView.Lambda(args, body) =>
|
||||
val realArgs = args.map(translateArgumentDefinition(_))
|
||||
val realBody = translateExpression(body)
|
||||
AstFunction(callable.location, realArgs, realBody)
|
||||
Lambda(callable.location, realArgs, realBody)
|
||||
case AST.App.Infix(left, fn, right) =>
|
||||
// TODO [AA] We should accept all ops when translating to core
|
||||
val validInfixOps = List("+", "/", "-", "*", "%")
|
||||
|
||||
if (validInfixOps.contains(fn.name)) {
|
||||
AstArithOp(
|
||||
callable.location,
|
||||
fn.name,
|
||||
translateExpression(left),
|
||||
translateExpression(right)
|
||||
)
|
||||
BinaryOperator(callable.location, translateExpression(left), fn.name, translateExpression(right))
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
s"${fn.name} is not currently a valid infix operator"
|
||||
@ -358,7 +352,7 @@ object AstToAstExpression {
|
||||
val functionName =
|
||||
AST.Ident.Var(realNameSegments.map(_.name).mkString("_"))
|
||||
|
||||
AstApply(
|
||||
Prefix(
|
||||
callable.location,
|
||||
translateExpression(functionName),
|
||||
args.map(translateCallArgument).toList,
|
||||
@ -374,10 +368,10 @@ object AstToAstExpression {
|
||||
* @param identifier the identifier to translate
|
||||
* @return the [[Core]] representation of `identifier`
|
||||
*/
|
||||
def translateIdent(identifier: AST.Ident): AstExpression = {
|
||||
def translateIdent(identifier: AST.Ident): Expression = {
|
||||
identifier match {
|
||||
case AST.Ident.Var(name) => AstVariable(identifier.location, name)
|
||||
case AST.Ident.Cons(name) => AstVariable(identifier.location, name)
|
||||
case AST.Ident.Var(name) => LiteralName(identifier.location, name)
|
||||
case AST.Ident.Cons(name) => LiteralName(identifier.location, name)
|
||||
case AST.Ident.Blank(_) =>
|
||||
throw new RuntimeException("Blanks not yet properly supported")
|
||||
case AST.Ident.Opr.any(_) =>
|
||||
@ -403,10 +397,10 @@ object AstToAstExpression {
|
||||
location: Option[Location],
|
||||
name: AST,
|
||||
expr: AST
|
||||
): AstAssignment = {
|
||||
): Binding = {
|
||||
name match {
|
||||
case AST.Ident.Var(name) =>
|
||||
AstAssignment(location, name, translateExpression(expr))
|
||||
Binding(location, name, translateExpression(expr))
|
||||
case _ =>
|
||||
throw new UnhandledEntity(name, "translateAssignment")
|
||||
}
|
||||
@ -418,13 +412,13 @@ object AstToAstExpression {
|
||||
* @param branch the case branch to translate
|
||||
* @return the [[Core]] representation of `branch`
|
||||
*/
|
||||
def translateCaseBranch(branch: AST): AstCase = {
|
||||
def translateCaseBranch(branch: AST): CaseBranch = {
|
||||
branch match {
|
||||
case AstView.ConsCaseBranch(cons, args, body) =>
|
||||
AstCase(
|
||||
CaseBranch(
|
||||
branch.location,
|
||||
translateExpression(cons),
|
||||
AstCaseFunction(
|
||||
CaseFunction(
|
||||
body.location,
|
||||
args.map(translateArgumentDefinition(_)),
|
||||
translateExpression(body)
|
||||
@ -441,10 +435,10 @@ object AstToAstExpression {
|
||||
* @param branch the fallback branch to translate
|
||||
* @return the [[Core]] representation of `branch`
|
||||
*/
|
||||
def translateFallbackBranch(branch: AST): AstCaseFunction = {
|
||||
def translateFallbackBranch(branch: AST): CaseFunction = {
|
||||
branch match {
|
||||
case AstView.FallbackCaseBranch(body) =>
|
||||
AstCaseFunction(body.location, List(), translateExpression(body))
|
||||
CaseFunction(body.location, List(), translateExpression(body))
|
||||
case _ => throw new UnhandledEntity(branch, "translateFallbackBranch")
|
||||
}
|
||||
}
|
||||
@ -485,7 +479,7 @@ object AstToAstExpression {
|
||||
* @param invalid the invalid entity to translate
|
||||
* @return the [[Core]] representation of `invalid`
|
||||
*/
|
||||
def translateInvalid(invalid: AST.Invalid): AstExpression = {
|
||||
def translateInvalid(invalid: AST.Invalid): Expression = {
|
||||
invalid match {
|
||||
case AST.Invalid.Unexpected(_, _) =>
|
||||
throw new RuntimeException(
|
||||
@ -519,7 +513,7 @@ object AstToAstExpression {
|
||||
* @param comment the comment to transform
|
||||
* @return the [[Core]] representation of `comment`
|
||||
*/
|
||||
def translateComment(comment: AST): AstExpression = {
|
||||
def translateComment(comment: AST): Expression = {
|
||||
comment match {
|
||||
case AST.Comment(_) =>
|
||||
throw new RuntimeException(
|
||||
|
@ -2,7 +2,7 @@ package org.enso.interpreter.test.semantic
|
||||
|
||||
import org.enso.interpreter.test.InterpreterTest
|
||||
|
||||
class FunctionArgumentsTest extends InterpreterTest {
|
||||
class LambdaArgumentsTest extends InterpreterTest {
|
||||
"Functions" should "take arguments and use them in their bodies" in {
|
||||
val code =
|
||||
"""
|
Loading…
Reference in New Issue
Block a user