Clean up the stopgap IR (#521)

This commit is contained in:
Ara Adkins 2020-02-19 14:41:17 +00:00 committed by GitHub
parent 06363f4126
commit e8fcb445be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 716 additions and 382 deletions

View File

@ -481,7 +481,8 @@ lazy val runtime = (project in file("engine/runtime"))
"org.scalactic" %% "scalactic" % "3.2.0-M2" % Test, "org.scalactic" %% "scalactic" % "3.2.0-M2" % Test,
"org.scalatest" %% "scalatest" % "3.2.0-M2" % Test, "org.scalatest" %% "scalatest" % "3.2.0-M2" % Test,
"org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark, "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] // Note [Unmanaged Classpath]
Compile / unmanagedClasspath += (core_definition / Compile / packageBin).value, Compile / unmanagedClasspath += (core_definition / Compile / packageBin).value,

View File

@ -390,7 +390,7 @@ object CoreGraph {
*/ */
case class CentreSection(operator: Link[G]) 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 * An explicitly forced term is one where the user has explicitly
* called the `force` operator on it. This is useful only while the * called the `force` operator on it. This is useful only while the

View File

@ -4,7 +4,7 @@ import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.RootNode;
import org.enso.compiler.core.AstArgDefinitionVisitor; 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 com.oracle.truffle.api.source.Source;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.node.ClosureRootNode; import org.enso.interpreter.node.ClosureRootNode;
@ -84,7 +84,7 @@ public class ArgDefinitionFactory implements AstArgDefinitionVisitor<ArgumentDef
*/ */
@Override @Override
public ArgumentDefinition visitArg( public ArgumentDefinition visitArg(
String name, Optional<AstExpression> defaultValue, boolean suspended, int position) { String name, Optional<Expression> defaultValue, boolean suspended, int position) {
ExpressionNode defExpression = ExpressionNode defExpression =
defaultValue defaultValue
.map( .map(

View File

@ -3,11 +3,11 @@ package org.enso.interpreter.builder;
import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.Truffle;
import org.enso.compiler.core.AstCallArgVisitor; 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.Source;
import com.oracle.truffle.api.source.SourceSection; 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.Language;
import org.enso.interpreter.node.ClosureRootNode; import org.enso.interpreter.node.ClosureRootNode;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
@ -64,12 +64,12 @@ public class CallArgFactory implements AstCallArgVisitor<CallArgument> {
* @return a runtime representation of the argument * @return a runtime representation of the argument
*/ */
@Override @Override
public CallArgument visitCallArg(Optional<String> name, AstExpression value, int position) { public CallArgument visitCallArg(Optional<String> name, Expression value, int position) {
ExpressionNode result; ExpressionNode result;
if (value instanceof AstForce) { if (value instanceof ForcedTerm) {
ExpressionFactory factory = new ExpressionFactory(language, source, scope, scopeName, moduleScope); ExpressionFactory factory = new ExpressionFactory(language, source, scope, scopeName, moduleScope);
result = ((AstForce) value).target().visit(factory); result = ((ForcedTerm) value).target().visit(factory);
} else { } else {
LocalScope childScope = new LocalScope(scope); LocalScope childScope = new LocalScope(scope);
ExpressionFactory factory = ExpressionFactory factory =

View File

@ -13,20 +13,20 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; 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.AstExpressionVisitor;
import org.enso.compiler.core.AstForce; import org.enso.compiler.core.IR.BinaryOperator;
import org.enso.compiler.core.AstFunction; import org.enso.compiler.core.IR.Binding;
import org.enso.compiler.core.AstLong; import org.enso.compiler.core.IR.CallArgumentDefinition;
import org.enso.compiler.core.AstMatch; import org.enso.compiler.core.IR.CaseFunction;
import org.enso.compiler.core.AstStringLiteral; import org.enso.compiler.core.IR.DefinitionSiteArgument;
import org.enso.compiler.core.AstVariable; 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.Constants;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.node.ClosureRootNode; import org.enso.interpreter.node.ClosureRootNode;
@ -142,7 +142,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* @param expr the expression to make executable * @param expr the expression to make executable
* @return a node representing the provided computation * @return a node representing the provided computation
*/ */
public ExpressionNode run(AstExpression expr) { public ExpressionNode run(Expression expr) {
ExpressionNode result = expr.visit(this); ExpressionNode result = expr.visit(this);
result.markNotTail(); result.markNotTail();
return result; return result;
@ -169,8 +169,8 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* @return a runtime node representing that value * @return a runtime node representing that value
*/ */
@Override @Override
public ExpressionNode visitLong(AstLong l) { public ExpressionNode visitLong(NumberLiteral l) {
return setLocation(new IntegerLiteralNode(l.value()), l.getLocation()); 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 * @return a runtime node representing this literal
*/ */
@Override @Override
public ExpressionNode visitStringLiteral(AstStringLiteral string) { public ExpressionNode visitStringLiteral(TextLiteral string) {
ExpressionNode node = new TextLiteralNode(string.string()); ExpressionNode node = new TextLiteralNode(string.text());
return setLocation(node, string.getLocation()); return setLocation(node, string.getLocation());
} }
@ -192,10 +192,10 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* @return a runtime node representing the arithmetic expression * @return a runtime node representing the arithmetic expression
*/ */
@Override @Override
public ExpressionNode visitArithOp(AstArithOp ast) { public ExpressionNode visitArithOp(BinaryOperator ast) {
ExpressionNode left = ast.left().visit(this); ExpressionNode left = ast.left().visit(this);
ExpressionNode right = ast.right().visit(this); ExpressionNode right = ast.right().visit(this);
String operator = ast.op(); String operator = ast.operator();
ExpressionNode resultOp = null; ExpressionNode resultOp = null;
if (operator.equals("+")) { if (operator.equals("+")) {
resultOp = AddOperatorNodeGen.create(left, right); 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 * <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. * 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 * @return a runtime node representing the variable
*/ */
@Override @Override
public ExpressionNode visitVariable(AstVariable astVariable) { public ExpressionNode visitName(LiteralName astName) {
String name = astVariable.name(); String name = astName.name();
Optional<ExpressionNode> currentModuleVariable = Optional<ExpressionNode> currentModuleVariable =
name.equals(Constants.Names.CURRENT_MODULE) name.equals(Constants.Names.CURRENT_MODULE)
? Optional.of(new ConstructorNode(moduleScope.getAssociatedType())) ? Optional.of(new ConstructorNode(moduleScope.getAssociatedType()))
@ -255,7 +255,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
.map(Optional::get) .map(Optional::get)
.findFirst() .findFirst()
.orElseGet(() -> new DynamicSymbolNode(new UnresolvedSymbol(name, moduleScope))); .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 * @return a runtime node representing the function body
*/ */
public CreateFunctionNode processFunctionBody( public CreateFunctionNode processFunctionBody(
Optional<Location> location, List<AstArgDefinition> arguments, AstExpression body) { Optional<Location> location, List<DefinitionSiteArgument> arguments, Expression body) {
ArgDefinitionFactory argFactory = ArgDefinitionFactory argFactory =
new ArgDefinitionFactory(scope, language, source, scopeName, moduleScope); new ArgDefinitionFactory(scope, language, source, scopeName, moduleScope);
ArgumentDefinition[] argDefinitions = new ArgumentDefinition[arguments.size()]; ArgumentDefinition[] argDefinitions = new ArgumentDefinition[arguments.size()];
@ -333,17 +333,17 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* Creates a runtime node representing a function. * Creates a runtime node representing a function.
* *
* <p>Given that most of the work takes place in {@link #processFunctionBody(Optional, List, * <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 * Expression)}, this node is solely responsible for handling the creation of a new scope for the
* the function, and marking it as tail recursive. * 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 * @return a runtime node representing the function
*/ */
@Override @Override
public ExpressionNode visitFunction(AstFunction function) { public ExpressionNode visitLambda(Lambda lambda) {
ExpressionFactory child = createChild(currentVarName); ExpressionFactory child = createChild(currentVarName);
ExpressionNode fun = ExpressionNode fun =
child.processFunctionBody(function.getLocation(), function.getArguments(), function.body()); child.processFunctionBody(lambda.getLocation(), lambda.getArguments(), lambda.body());
fun.markTail(); fun.markTail();
return fun; return fun;
} }
@ -352,17 +352,19 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* Creates a runtime node representing a case function. * Creates a runtime node representing a case function.
* *
* <p>Given that most of the work takes place in {@link #processFunctionBody(Optional, List, * <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 * Expression) processFunctionBody}, this node is solely responsible for handling the creation of
* of a new scope for the function. * a new scope for the function.
* *
* @param function the AST to represent * @param function the AST to represent
* @return a runtime node representing the function * @return a runtime node representing the function
*/ */
@Override @Override
public ExpressionNode visitCaseFunction(AstCaseFunction function) { public ExpressionNode visitCaseFunction(CaseFunction function) {
ExpressionFactory child = createChild("case_expression"); ExpressionFactory child = createChild("case_expression");
return child.processFunctionBody( return child.processFunctionBody(
function.getLocation(), function.getArguments(), function.body()); 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 * @return a runtime node representing the function call
*/ */
@Override @Override
public ExpressionNode visitFunctionApplication(AstApply application) { public ExpressionNode visitFunctionApplication(Prefix application) {
CallArgFactory argFactory = new CallArgFactory(scope, language, source, scopeName, moduleScope); CallArgFactory argFactory = new CallArgFactory(scope, language, source, scopeName, moduleScope);
List<AstCallArg> arguments = application.getArgs(); List<CallArgumentDefinition> arguments = application.getArgs();
List<CallArgument> callArgs = new ArrayList<>(); List<CallArgument> callArgs = new ArrayList<>();
for (int position = 0; position < arguments.size(); ++position) { for (int position = 0; position < arguments.size(); ++position) {
CallArgument arg = arguments.get(position).visit(argFactory, position); CallArgument arg = arguments.get(position).visit(argFactory, position);
@ -388,7 +390,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
ApplicationNode appNode = ApplicationNode appNode =
new ApplicationNode( new ApplicationNode(
application.fun().visit(this), application.function().visit(this),
callArgs.toArray(new CallArgument[0]), callArgs.toArray(new CallArgument[0]),
defaultsExecutionMode); defaultsExecutionMode);
setLocation(appNode, application.getLocation()); setLocation(appNode, application.getLocation());
@ -402,40 +404,40 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
* @return a runtime node representing the assignment * @return a runtime node representing the assignment
*/ */
@Override @Override
public ExpressionNode visitAssignment(AstAssignment ast) { public ExpressionNode visitAssignment(Binding ast) {
currentVarName = ast.name(); currentVarName = ast.name();
FrameSlot slot = scope.createVarSlot(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. * 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 * @return a runtime node representing a pattern match expression
*/ */
@Override @Override
public ExpressionNode visitMatch(AstMatch match) { public ExpressionNode visitMatch(CaseExpr caseExpr) {
// AstExpression target, List<AstCase> branches, Optional<AstCaseFunction> fallback) { // AstExpression target, List<AstCase> branches, Optional<AstCaseFunction> fallback) {
ExpressionNode targetNode = match.target().visit(this); ExpressionNode targetNode = caseExpr.scrutinee().visit(this);
CaseNode[] cases = CaseNode[] cases =
match.getBranches().stream() caseExpr.getBranches().stream()
.map( .map(
branch -> branch ->
new ConstructorCaseNode( new ConstructorCaseNode(
branch.cons().visit(this), branch.function().visit(this))) branch.pattern().visit(this), branch.expression().visit(this)))
.toArray(CaseNode[]::new); .toArray(CaseNode[]::new);
// Note [Pattern Match Fallbacks] // Note [Pattern Match Fallbacks]
CaseNode fallbackNode = CaseNode fallbackNode =
match caseExpr
.getFallback() .getFallback()
.map(fb -> (CaseNode) new FallbackNode(fb.visit(this))) .map(fb -> (CaseNode) new FallbackNode(fb.visit(this)))
.orElseGet(DefaultFallbackNode::new); .orElseGet(DefaultFallbackNode::new);
ExpressionNode matchExpr = MatchNodeGen.create(cases, fallbackNode, targetNode); ExpressionNode matchExpr = MatchNodeGen.create(cases, fallbackNode, targetNode);
return setLocation(matchExpr, match.getLocation()); return setLocation(matchExpr, caseExpr.getLocation());
} }
/* Note [Pattern Match Fallbacks] /* Note [Pattern Match Fallbacks]
@ -449,13 +451,13 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
/** /**
* Creates a runtime representation of lazy function argument forcing. * 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 * @return the AST fragment representing forcing of the requested value
*/ */
@Override @Override
public ExpressionNode visitForce(AstForce force) { public ExpressionNode visitForce(ForcedTerm forcedTerm) {
ForceNode node = ForceNodeGen.create(force.target().visit(this)); ForceNode node = ForceNodeGen.create(forcedTerm.target().visit(this));
return setLocation(node, force.getLocation()); return setLocation(node, forcedTerm.getLocation());
} }
/** /**
@ -467,7 +469,7 @@ public class ExpressionFactory implements AstExpressionVisitor<ExpressionNode> {
*/ */
@Override @Override
public ExpressionNode visitBlock( public ExpressionNode visitBlock(
List<AstExpression> statements, AstExpression retValue, boolean suspended) { List<Expression> statements, Expression retValue, boolean suspended) {
if (suspended) { if (suspended) {
ExpressionFactory childFactory = this.createChild("suspended-block"); ExpressionFactory childFactory = this.createChild("suspended-block");
LocalScope childScope = childFactory.scope; LocalScope childScope = childFactory.scope;

View File

@ -1,8 +1,19 @@
package org.enso.interpreter.builder; package org.enso.interpreter.builder;
import org.enso.compiler.core.*;
import com.oracle.truffle.api.source.Source; 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.node.callable.function.CreateFunctionNode;
import org.enso.interpreter.runtime.Context; import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition; 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.error.VariableDoesNotExistException;
import org.enso.interpreter.runtime.scope.ModuleScope; 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 * A {@code GlobalScopeExpressionFactory} is responsible for converting the top-level definitions of
* an Enso program into AST nodes for the interpreter to evaluate. * 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 * @param expr the expression to execute on
*/ */
public void run(AstModuleScope expr) { public void run(Module expr) {
expr.visit(this); expr.visit(this);
} }
@ -52,12 +58,12 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
* Processes definitions in the language global scope. * Processes definitions in the language global scope.
* *
* @param imports any imports requested by this module * @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 * @param bindings any bindings made in the global scope
*/ */
@Override @Override
public void visitModuleScope( 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(); Context context = language.getCurrentContext();
for (AstImport imp : imports) { for (AstImport imp : imports) {
@ -65,7 +71,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
} }
List<AtomConstructor> constructors = List<AtomConstructor> constructors =
typeDefs.stream() atomDefs.stream()
.map(type -> new AtomConstructor(type.name(), moduleScope)) .map(type -> new AtomConstructor(type.name(), moduleScope))
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -76,7 +82,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
idx -> { idx -> {
ArgDefinitionFactory argFactory = ArgDefinitionFactory argFactory =
new ArgDefinitionFactory(language, source, moduleScope); new ArgDefinitionFactory(language, source, moduleScope);
AstTypeDef type = typeDefs.get(idx); AtomDef type = atomDefs.get(idx);
ArgumentDefinition[] argDefs = new ArgumentDefinition[type.getArguments().size()]; ArgumentDefinition[] argDefs = new ArgumentDefinition[type.getArguments().size()];
for (int i = 0; i < type.getArguments().size(); ++i) { for (int i = 0; i < type.getArguments().size(); ++i) {
@ -86,10 +92,10 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
constructors.get(idx).initializeFields(argDefs); constructors.get(idx).initializeFields(argDefs);
}); });
for (AstMethodDef method : bindings) { for (MethodDef method : bindings) {
scala.Option<AstExpression> scalaNone = scala.Option.apply(null); scala.Option<Expression> scalaNone = scala.Option.apply(null);
AstArgDefinition thisArgument = DefinitionSiteArgument thisArgument =
new AstArgDefinition(Constants.Names.THIS_ARGUMENT, scalaNone, false); new DefinitionSiteArgument(Constants.Names.THIS_ARGUMENT, scalaNone, false);
String typeName = method.typeName(); String typeName = method.typeName();
if (typeName.equals(Constants.Names.CURRENT_MODULE)) { if (typeName.equals(Constants.Names.CURRENT_MODULE)) {
@ -103,12 +109,12 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor<Funct
typeName + Constants.SCOPE_SEPARATOR + method.methodName(), typeName + Constants.SCOPE_SEPARATOR + method.methodName(),
moduleScope); moduleScope);
List<AstArgDefinition> realArgs = new ArrayList<>(method.fun().getArguments()); List<DefinitionSiteArgument> realArgs = new ArrayList<>(method.function().getArguments());
realArgs.add(0, thisArgument); realArgs.add(0, thisArgument);
CreateFunctionNode funNode = CreateFunctionNode funNode =
expressionFactory.processFunctionBody( expressionFactory.processFunctionBody(
method.fun().getLocation(), realArgs, method.fun().body()); method.function().getLocation(), realArgs, method.function().body());
funNode.markTail(); funNode.markTail();
Function function = Function function =
new Function( new Function(

View File

@ -4,7 +4,8 @@ import java.io.StringReader
import com.oracle.truffle.api.TruffleFile import com.oracle.truffle.api.TruffleFile
import com.oracle.truffle.api.source.Source 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.compiler.generate.AstToAstExpression
import org.enso.flexer.Reader import org.enso.flexer.Reader
import org.enso.interpreter.builder.{ExpressionFactory, ModuleScopeExpressionFactory} import org.enso.interpreter.builder.{ExpressionFactory, ModuleScopeExpressionFactory}
@ -157,7 +158,7 @@ class Compiler(
* @param sourceAST the parser AST input * @param sourceAST the parser AST input
* @return an IR representation of the program represented by `sourceAST` * @return an IR representation of the program represented by `sourceAST`
*/ */
def translate(sourceAST: AST): AstModuleScope = def translate(sourceAST: AST): Module =
AstToAstExpression.translate(sourceAST) AstToAstExpression.translate(sourceAST)
/** /**
@ -167,6 +168,6 @@ class Compiler(
* @param sourceAST the parser AST representing the program source * @param sourceAST the parser AST representing the program source
* @return an IR representation of the program represented by `sourceAST` * @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) AstToAstExpression.translateInline(sourceAST)
} }

View 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
}

View File

@ -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)
}

View File

@ -2,8 +2,7 @@ package org.enso.compiler.generate
import cats.Foldable import cats.Foldable
import cats.implicits._ import cats.implicits._
import org.enso.compiler.core import org.enso.compiler.core.IR._
import org.enso.compiler.core._
import org.enso.compiler.exception.UnhandledEntity import org.enso.compiler.exception.UnhandledEntity
import org.enso.interpreter.Constants import org.enso.interpreter.Constants
import org.enso.syntax.text.{AST, Location} 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 * This file contains the functionality that translates from the parser's
* [[AST]] type to the internal representation used by the compiler. * [[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]] * [[Core]] becomes implemented. Most function docs will refer to [[Core]]
* now, as this will become true soon. * now, as this will become true soon.
*/ */
@ -27,7 +26,7 @@ object AstToAstExpression {
* @param inputAST the [[AST]] representing the program to translate * @param inputAST the [[AST]] representing the program to translate
* @return the [[Core]] representation of `inputAST` * @return the [[Core]] representation of `inputAST`
*/ */
def translate(inputAST: AST): AstModuleScope = { def translate(inputAST: AST): Module = {
inputAST match { inputAST match {
case AST.Module.any(inputAST) => translateModule(inputAST) case AST.Module.any(inputAST) => translateModule(inputAST)
case _ => { case _ => {
@ -46,7 +45,7 @@ object AstToAstExpression {
* @return the [[Core]] representation of `inputAST` if it is valid, * @return the [[Core]] representation of `inputAST` if it is valid,
* otherwise [[None]] * otherwise [[None]]
*/ */
def translateInline(inputAST: AST): Option[AstExpression] = { def translateInline(inputAST: AST): Option[Expression] = {
inputAST match { inputAST match {
case AST.Module.any(module) => case AST.Module.any(module) =>
val presentBlocks = module.lines.collect { val presentBlocks = module.lines.collect {
@ -60,7 +59,7 @@ object AstToAstExpression {
case List(expr) => Some(expr) case List(expr) => Some(expr)
case _ => case _ =>
Some( Some(
AstBlock( Block(
Foldable[List].foldMap(expressions)(_.location), Foldable[List].foldMap(expressions)(_.location),
expressions.dropRight(1), expressions.dropRight(1),
expressions.last expressions.last
@ -76,7 +75,7 @@ object AstToAstExpression {
* @param module the [[AST]] representation of the module to translate * @param module the [[AST]] representation of the module to translate
* @return the [[Core]] representation of `module` * @return the [[Core]] representation of `module`
*/ */
def translateModule(module: AST.Module): AstModuleScope = { def translateModule(module: AST.Module): Module = {
module match { module match {
case AST.Module(blocks) => { case AST.Module(blocks) => {
val presentBlocks = blocks.collect { val presentBlocks = blocks.collect {
@ -93,7 +92,7 @@ object AstToAstExpression {
} }
val statements = nonImportBlocks.map(translateModuleSymbol) 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 * @param inputAST the definition to be translated
* @return the [[Core]] representation of `inputAST` * @return the [[Core]] representation of `inputAST`
*/ */
def translateModuleSymbol(inputAST: AST): AstModuleSymbol = { def translateModuleSymbol(inputAST: AST): TopLevelSymbol = {
inputAST match { inputAST match {
case AST.Def(consName, args, body) => case AST.Def(consName, args, body) =>
if (body.isDefined) { if (body.isDefined) {
throw new RuntimeException("Cannot support complex type defs yet!!!!") throw new RuntimeException("Cannot support complex type defs yet!!!!")
} else { } else {
AstTypeDef(consName.name, args.map(translateArgumentDefinition(_))) AtomDef(consName.name, args.map(translateArgumentDefinition(_)))
} }
case AstView.MethodDefinition(targetPath, name, definition) => case AstView.MethodDefinition(targetPath, name, definition) =>
val path = if (targetPath.nonEmpty) { val path = if (targetPath.nonEmpty) {
@ -120,11 +119,11 @@ object AstToAstExpression {
} }
val nameStr = name match { case AST.Ident.Var(name) => name } val nameStr = name match { case AST.Ident.Var(name) => name }
val defExpression = translateExpression(definition) val defExpression = translateExpression(definition)
val defExpr: AstFunction = defExpression match { val defExpr: Lambda = defExpression match {
case fun: AstFunction => fun case fun: Lambda => fun
case expr => AstFunction(expr.location, List(), expr) case expr => Lambda(expr.location, List(), expr)
} }
AstMethodDef(path, nameStr, defExpr) MethodDef(path, nameStr, defExpr)
case _ => case _ =>
throw new UnhandledEntity(inputAST, "translateModuleSymbol") throw new UnhandledEntity(inputAST, "translateModuleSymbol")
} }
@ -135,14 +134,14 @@ object AstToAstExpression {
* @param inputAST the expresion to be translated * @param inputAST the expresion to be translated
* @return the [[Core]] representation of `inputAST` * @return the [[Core]] representation of `inputAST`
*/ */
def translateExpression(inputAST: AST): AstExpression = { def translateExpression(inputAST: AST): Expression = {
inputAST match { inputAST match {
case AstView case AstView
.SuspendedBlock(name, block @ AstView.Block(lines, lastLine)) => .SuspendedBlock(name, block @ AstView.Block(lines, lastLine)) =>
AstAssignment( Binding(
inputAST.location, inputAST.location,
name.name, name.name,
AstBlock( Block(
block.location, block.location,
lines.map(translateExpression), lines.map(translateExpression),
translateExpression(lastLine), translateExpression(lastLine),
@ -152,7 +151,7 @@ object AstToAstExpression {
case AstView.Assignment(name, expr) => case AstView.Assignment(name, expr) =>
translateBinding(inputAST.location, name, expr) translateBinding(inputAST.location, name, expr)
case AstView.MethodCall(target, name, args) => case AstView.MethodCall(target, name, args) =>
AstApply( Prefix(
inputAST.location, inputAST.location,
translateExpression(name), translateExpression(name),
(target :: args).map(translateCallArgument), (target :: args).map(translateCallArgument),
@ -169,7 +168,7 @@ object AstToAstExpression {
.drop(nonFallbackBranches.length) .drop(nonFallbackBranches.length)
.headOption .headOption
.map(translateFallbackBranch) .map(translateFallbackBranch)
AstMatch( CaseExpr(
inputAST.location, inputAST.location,
actualScrutinee, actualScrutinee,
nonFallbackBranches, nonFallbackBranches,
@ -182,7 +181,7 @@ object AstToAstExpression {
translateGroup(inputAST, translateExpression) translateGroup(inputAST, translateExpression)
case AST.Ident.any(inputAST) => translateIdent(inputAST) case AST.Ident.any(inputAST) => translateIdent(inputAST)
case AstView.Block(lines, retLine) => case AstView.Block(lines, retLine) =>
AstBlock( Block(
inputAST.location, inputAST.location,
lines.map(translateExpression), lines.map(translateExpression),
translateExpression(retLine) translateExpression(retLine)
@ -204,14 +203,14 @@ object AstToAstExpression {
* @param literal the literal to translate * @param literal the literal to translate
* @return the [[Core]] representation of `literal` * @return the [[Core]] representation of `literal`
*/ */
def translateLiteral(literal: AST.Literal): AstExpression = { def translateLiteral(literal: AST.Literal): Expression = {
literal match { literal match {
case AST.Literal.Number(base, number) => { case AST.Literal.Number(base, number) => {
if (base.isDefined && base.get != "10") { if (base.isDefined && base.get != "10") {
throw new RuntimeException("Only base 10 is currently supported") throw new RuntimeException("Only base 10 is currently supported")
} }
AstLong(literal.location, number.toLong) NumberLiteral(literal.location, number)
} }
case AST.Literal.Text.any(literal) => case AST.Literal.Text.any(literal) =>
literal.shape match { literal.shape match {
@ -221,7 +220,7 @@ object AstToAstExpression {
case AST.Literal.Text.Segment.RawEsc(code) => code.repr case AST.Literal.Text.Segment.RawEsc(code) => code.repr
}.mkString }.mkString
AstStringLiteral(literal.location, fullString) TextLiteral(literal.location, fullString)
case AST.Literal.Text.Block.Raw(lines, _, _) => case AST.Literal.Text.Block.Raw(lines, _, _) =>
val fullString = lines val fullString = lines
.map( .map(
@ -233,7 +232,7 @@ object AstToAstExpression {
) )
.mkString("\n") .mkString("\n")
AstStringLiteral(literal.location, fullString) TextLiteral(literal.location, fullString)
case AST.Literal.Text.Block.Fmt(_, _, _) => case AST.Literal.Text.Block.Fmt(_, _, _) =>
throw new RuntimeException("Format strings not yet supported") throw new RuntimeException("Format strings not yet supported")
case AST.Literal.Text.Line.Fmt(_) => case AST.Literal.Text.Line.Fmt(_) =>
@ -255,10 +254,10 @@ object AstToAstExpression {
def translateArgumentDefinition( def translateArgumentDefinition(
arg: AST, arg: AST,
isSuspended: Boolean = false isSuspended: Boolean = false
): AstArgDefinition = { ): DefinitionSiteArgument = {
arg match { arg match {
case AstView.LazyAssignedArgumentDefinition(name, value) => case AstView.LazyAssignedArgumentDefinition(name, value) =>
AstArgDefinition( DefinitionSiteArgument(
name.name, name.name,
Some(translateExpression(value)), Some(translateExpression(value)),
true true
@ -266,9 +265,9 @@ object AstToAstExpression {
case AstView.LazyArgument(arg) => case AstView.LazyArgument(arg) =>
translateArgumentDefinition(arg, isSuspended = true) translateArgumentDefinition(arg, isSuspended = true)
case AstView.DefinitionArgument(arg) => case AstView.DefinitionArgument(arg) =>
AstArgDefinition(arg.name, None, isSuspended) DefinitionSiteArgument(arg.name, None, isSuspended)
case AstView.AssignedArgument(name, value) => case AstView.AssignedArgument(name, value) =>
AstArgDefinition( DefinitionSiteArgument(
name.name, name.name,
Some(translateExpression(value)), Some(translateExpression(value)),
isSuspended isSuspended
@ -284,10 +283,10 @@ object AstToAstExpression {
* @param arg the argument to translate * @param arg the argument to translate
* @return the [[Core]] representation of `arg` * @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) => case AstView.AssignedArgument(left, right) =>
AstNamedCallArg(left.name, translateExpression(right)) CallArgumentDefinition(Some(left.name), translateExpression(right))
case _ => AstUnnamedCallArg(translateExpression(arg)) case _ => CallArgumentDefinition(None, translateExpression(arg))
} }
/** Translates an arbitrary expression that takes the form of a syntactic /** Translates an arbitrary expression that takes the form of a syntactic
@ -296,10 +295,10 @@ object AstToAstExpression {
* @param callable the callable to translate * @param callable the callable to translate
* @return the [[Core]] representation of `callable` * @return the [[Core]] representation of `callable`
*/ */
def translateApplicationLike(callable: AST): AstExpression = { def translateApplicationLike(callable: AST): Expression = {
callable match { callable match {
case AstView.ForcedTerm(term) => case AstView.ForcedTerm(term) =>
AstForce(callable.location, translateExpression(term)) ForcedTerm(callable.location, translateExpression(term))
case AstView.Application(name, args) => case AstView.Application(name, args) =>
val validArguments = args.filter { val validArguments = args.filter {
case AstView.SuspendDefaultsOperator(_) => false case AstView.SuspendDefaultsOperator(_) => false
@ -312,7 +311,7 @@ object AstToAstExpression {
val hasDefaultsSuspended = suspendPositions.contains(args.length - 1) val hasDefaultsSuspended = suspendPositions.contains(args.length - 1)
AstApply( Prefix(
callable.location, callable.location,
translateExpression(name), translateExpression(name),
validArguments.map(translateCallArgument), validArguments.map(translateCallArgument),
@ -321,18 +320,13 @@ object AstToAstExpression {
case AstView.Lambda(args, body) => case AstView.Lambda(args, body) =>
val realArgs = args.map(translateArgumentDefinition(_)) val realArgs = args.map(translateArgumentDefinition(_))
val realBody = translateExpression(body) val realBody = translateExpression(body)
AstFunction(callable.location, realArgs, realBody) Lambda(callable.location, realArgs, realBody)
case AST.App.Infix(left, fn, right) => case AST.App.Infix(left, fn, right) =>
// TODO [AA] We should accept all ops when translating to core // TODO [AA] We should accept all ops when translating to core
val validInfixOps = List("+", "/", "-", "*", "%") val validInfixOps = List("+", "/", "-", "*", "%")
if (validInfixOps.contains(fn.name)) { if (validInfixOps.contains(fn.name)) {
AstArithOp( BinaryOperator(callable.location, translateExpression(left), fn.name, translateExpression(right))
callable.location,
fn.name,
translateExpression(left),
translateExpression(right)
)
} else { } else {
throw new RuntimeException( throw new RuntimeException(
s"${fn.name} is not currently a valid infix operator" s"${fn.name} is not currently a valid infix operator"
@ -358,7 +352,7 @@ object AstToAstExpression {
val functionName = val functionName =
AST.Ident.Var(realNameSegments.map(_.name).mkString("_")) AST.Ident.Var(realNameSegments.map(_.name).mkString("_"))
AstApply( Prefix(
callable.location, callable.location,
translateExpression(functionName), translateExpression(functionName),
args.map(translateCallArgument).toList, args.map(translateCallArgument).toList,
@ -374,10 +368,10 @@ object AstToAstExpression {
* @param identifier the identifier to translate * @param identifier the identifier to translate
* @return the [[Core]] representation of `identifier` * @return the [[Core]] representation of `identifier`
*/ */
def translateIdent(identifier: AST.Ident): AstExpression = { def translateIdent(identifier: AST.Ident): Expression = {
identifier match { identifier match {
case AST.Ident.Var(name) => AstVariable(identifier.location, name) case AST.Ident.Var(name) => LiteralName(identifier.location, name)
case AST.Ident.Cons(name) => AstVariable(identifier.location, name) case AST.Ident.Cons(name) => LiteralName(identifier.location, name)
case AST.Ident.Blank(_) => case AST.Ident.Blank(_) =>
throw new RuntimeException("Blanks not yet properly supported") throw new RuntimeException("Blanks not yet properly supported")
case AST.Ident.Opr.any(_) => case AST.Ident.Opr.any(_) =>
@ -403,10 +397,10 @@ object AstToAstExpression {
location: Option[Location], location: Option[Location],
name: AST, name: AST,
expr: AST expr: AST
): AstAssignment = { ): Binding = {
name match { name match {
case AST.Ident.Var(name) => case AST.Ident.Var(name) =>
AstAssignment(location, name, translateExpression(expr)) Binding(location, name, translateExpression(expr))
case _ => case _ =>
throw new UnhandledEntity(name, "translateAssignment") throw new UnhandledEntity(name, "translateAssignment")
} }
@ -418,13 +412,13 @@ object AstToAstExpression {
* @param branch the case branch to translate * @param branch the case branch to translate
* @return the [[Core]] representation of `branch` * @return the [[Core]] representation of `branch`
*/ */
def translateCaseBranch(branch: AST): AstCase = { def translateCaseBranch(branch: AST): CaseBranch = {
branch match { branch match {
case AstView.ConsCaseBranch(cons, args, body) => case AstView.ConsCaseBranch(cons, args, body) =>
AstCase( CaseBranch(
branch.location, branch.location,
translateExpression(cons), translateExpression(cons),
AstCaseFunction( CaseFunction(
body.location, body.location,
args.map(translateArgumentDefinition(_)), args.map(translateArgumentDefinition(_)),
translateExpression(body) translateExpression(body)
@ -441,10 +435,10 @@ object AstToAstExpression {
* @param branch the fallback branch to translate * @param branch the fallback branch to translate
* @return the [[Core]] representation of `branch` * @return the [[Core]] representation of `branch`
*/ */
def translateFallbackBranch(branch: AST): AstCaseFunction = { def translateFallbackBranch(branch: AST): CaseFunction = {
branch match { branch match {
case AstView.FallbackCaseBranch(body) => case AstView.FallbackCaseBranch(body) =>
AstCaseFunction(body.location, List(), translateExpression(body)) CaseFunction(body.location, List(), translateExpression(body))
case _ => throw new UnhandledEntity(branch, "translateFallbackBranch") case _ => throw new UnhandledEntity(branch, "translateFallbackBranch")
} }
} }
@ -485,7 +479,7 @@ object AstToAstExpression {
* @param invalid the invalid entity to translate * @param invalid the invalid entity to translate
* @return the [[Core]] representation of `invalid` * @return the [[Core]] representation of `invalid`
*/ */
def translateInvalid(invalid: AST.Invalid): AstExpression = { def translateInvalid(invalid: AST.Invalid): Expression = {
invalid match { invalid match {
case AST.Invalid.Unexpected(_, _) => case AST.Invalid.Unexpected(_, _) =>
throw new RuntimeException( throw new RuntimeException(
@ -519,7 +513,7 @@ object AstToAstExpression {
* @param comment the comment to transform * @param comment the comment to transform
* @return the [[Core]] representation of `comment` * @return the [[Core]] representation of `comment`
*/ */
def translateComment(comment: AST): AstExpression = { def translateComment(comment: AST): Expression = {
comment match { comment match {
case AST.Comment(_) => case AST.Comment(_) =>
throw new RuntimeException( throw new RuntimeException(

View File

@ -2,7 +2,7 @@ package org.enso.interpreter.test.semantic
import org.enso.interpreter.test.InterpreterTest 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 { "Functions" should "take arguments and use them in their bodies" in {
val code = val code =
""" """