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.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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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.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(

View File

@ -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 =
"""