diff --git a/build.sbt b/build.sbt index 192df824bb..54d6e0f2dc 100644 --- a/build.sbt +++ b/build.sbt @@ -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, diff --git a/engine/core-definition/src/main/scala/org/enso/core/CoreGraph.scala b/engine/core-definition/src/main/scala/org/enso/core/CoreGraph.scala index 5da530cc04..350b504355 100644 --- a/engine/core-definition/src/main/scala/org/enso/core/CoreGraph.scala +++ b/engine/core-definition/src/main/scala/org/enso/core/CoreGraph.scala @@ -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 diff --git a/engine/runtime/src/main/java/org/enso/interpreter/builder/ArgDefinitionFactory.java b/engine/runtime/src/main/java/org/enso/interpreter/builder/ArgDefinitionFactory.java index 0a48b70faa..37ad3b8d9b 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/builder/ArgDefinitionFactory.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/builder/ArgDefinitionFactory.java @@ -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 defaultValue, boolean suspended, int position) { + String name, Optional defaultValue, boolean suspended, int position) { ExpressionNode defExpression = defaultValue .map( diff --git a/engine/runtime/src/main/java/org/enso/interpreter/builder/CallArgFactory.java b/engine/runtime/src/main/java/org/enso/interpreter/builder/CallArgFactory.java index fe1635cfce..51937bdff9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/builder/CallArgFactory.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/builder/CallArgFactory.java @@ -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 { * @return a runtime representation of the argument */ @Override - public CallArgument visitCallArg(Optional name, AstExpression value, int position) { + public CallArgument visitCallArg(Optional 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 = diff --git a/engine/runtime/src/main/java/org/enso/interpreter/builder/ExpressionFactory.java b/engine/runtime/src/main/java/org/enso/interpreter/builder/ExpressionFactory.java index 45dd5dd86f..057cff1a1e 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/builder/ExpressionFactory.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/builder/ExpressionFactory.java @@ -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 { * @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 { * @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 { * @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 { * @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 { *

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 currentModuleVariable = name.equals(Constants.Names.CURRENT_MODULE) ? Optional.of(new ConstructorNode(moduleScope.getAssociatedType())) @@ -255,7 +255,7 @@ public class ExpressionFactory implements AstExpressionVisitor { .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 { * @return a runtime node representing the function body */ public CreateFunctionNode processFunctionBody( - Optional location, List arguments, AstExpression body) { + Optional location, List 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 { * Creates a runtime node representing a function. * *

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 { * Creates a runtime node representing a case function. * *

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 { * @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 arguments = application.getArgs(); + List arguments = application.getArgs(); List 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 { 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 { * @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 branches, Optional 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 { /** * 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 { */ @Override public ExpressionNode visitBlock( - List statements, AstExpression retValue, boolean suspended) { + List statements, Expression retValue, boolean suspended) { if (suspended) { ExpressionFactory childFactory = this.createChild("suspended-block"); LocalScope childScope = childFactory.scope; diff --git a/engine/runtime/src/main/java/org/enso/interpreter/builder/ModuleScopeExpressionFactory.java b/engine/runtime/src/main/java/org/enso/interpreter/builder/ModuleScopeExpressionFactory.java index 95860bc04c..23c5d209f7 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/builder/ModuleScopeExpressionFactory.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/builder/ModuleScopeExpressionFactory.java @@ -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 imports, List typeDefs, List bindings) { + List imports, List atomDefs, List bindings) { Context context = language.getCurrentContext(); for (AstImport imp : imports) { @@ -65,7 +71,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor constructors = - typeDefs.stream() + atomDefs.stream() .map(type -> new AtomConstructor(type.name(), moduleScope)) .collect(Collectors.toList()); @@ -76,7 +82,7 @@ public class ModuleScopeExpressionFactory implements AstModuleScopeVisitor { 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 scalaNone = scala.Option.apply(null); - AstArgDefinition thisArgument = - new AstArgDefinition(Constants.Names.THIS_ARGUMENT, scalaNone, false); + for (MethodDef method : bindings) { + scala.Option 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 realArgs = new ArrayList<>(method.fun().getArguments()); + List 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( diff --git a/engine/runtime/src/main/scala/org/enso/compiler/Compiler.scala b/engine/runtime/src/main/scala/org/enso/compiler/Compiler.scala index 2fdb3dc95d..96f5f53643 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/Compiler.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/Compiler.scala @@ -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) } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala new file mode 100644 index 0000000000..3af1528399 --- /dev/null +++ b/engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala @@ -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 +} diff --git a/engine/runtime/src/main/scala/org/enso/compiler/core/OldAST.scala b/engine/runtime/src/main/scala/org/enso/compiler/core/OldAST.scala deleted file mode 100644 index caa97418bb..0000000000 --- a/engine/runtime/src/main/scala/org/enso/compiler/core/OldAST.scala +++ /dev/null @@ -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) -} diff --git a/engine/runtime/src/main/scala/org/enso/compiler/generate/AstToAstExpression.scala b/engine/runtime/src/main/scala/org/enso/compiler/generate/AstToAstExpression.scala index 919cef949e..8575d29207 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/generate/AstToAstExpression.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/generate/AstToAstExpression.scala @@ -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( diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/FunctionArgumentsTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaArgumentsTest.scala similarity index 97% rename from engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/FunctionArgumentsTest.scala rename to engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaArgumentsTest.scala index 04262fd584..e70bd2e0e3 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/FunctionArgumentsTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/semantic/LambdaArgumentsTest.scala @@ -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 = """