Method naming fixes (#1024)

This commit is contained in:
Marcin Kostrzewa 2020-07-22 12:01:35 +02:00 committed by GitHub
parent ded61865a4
commit 6137c6559b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 340 additions and 152 deletions

View File

@ -96,6 +96,8 @@ Text.it ~behavior =
## Runs a suite of tests, consisting of multiple `describe` blocks. ## Runs a suite of tests, consisting of multiple `describe` blocks.
Returns a `Suite` object containing the test report.
> Example > Example
Suite.run <| Suite.run <|
describe "Number" <| describe "Number" <|
@ -107,5 +109,20 @@ Suite.run ~specs =
r = State.run Suite (Suite Nil) <| r = State.run Suite (Suite Nil) <|
specs specs
State.get Suite State.get Suite
code = if r.is_fail then 1 else 0 r
System.exit code
## Runs a suite of tests, consisting of multiple `describe` blocks.
Exits the process with code `1` if the suite failed and `0` otherwise.
> Example
Suite.run <|
describe "Number" <|
it "should define addition" <|
2+3 . should_equal 5
it "should define multiplication" <|
2*3 . should_equal 6
Suite.runMain ~specs =
r = this.run specs
code = if r.is_fail then 1 else 0
System.exit code

View File

@ -10,8 +10,9 @@ import org.enso.languageserver.boot.LanguageServerConfig
import org.enso.pkg.PackageManager import org.enso.pkg.PackageManager
import org.enso.polyglot.{LanguageInfo, Module, PolyglotContext} import org.enso.polyglot.{LanguageInfo, Module, PolyglotContext}
import org.enso.version.VersionDescription import org.enso.version.VersionDescription
import org.graalvm.polyglot.Value import org.graalvm.polyglot.{PolyglotException, Value}
import scala.jdk.CollectionConverters._
import scala.util.Try import scala.util.Try
/** The main CLI entry point class. */ /** The main CLI entry point class. */
@ -143,7 +144,10 @@ object Main {
new HelpFormatter().printHelp(LanguageInfo.ID, options) new HelpFormatter().printHelp(LanguageInfo.ID, options)
/** Terminates the process with a failure exit code. */ /** Terminates the process with a failure exit code. */
private def exitFail(): Unit = System.exit(1) private def exitFail(): Nothing = {
System.exit(1)
throw new IllegalStateException("impossible to reach here")
}
/** Terminates the process with a success exit code. */ /** Terminates the process with a success exit code. */
private def exitSuccess(): Unit = System.exit(0) private def exitSuccess(): Unit = System.exit(0)
@ -189,7 +193,7 @@ object Main {
} }
val mainFile = main.get val mainFile = main.get
val mainModuleName = pkg.get.moduleNameForFile(mainFile).toString val mainModuleName = pkg.get.moduleNameForFile(mainFile).toString
runPackage(context, mainModuleName) runPackage(context, mainModuleName, file)
} else { } else {
runSingleFile(context, file) runSingleFile(context, file)
} }
@ -198,22 +202,81 @@ object Main {
private def runPackage( private def runPackage(
context: PolyglotContext, context: PolyglotContext,
mainModuleName: String mainModuleName: String,
projectPath: File
): Unit = { ): Unit = {
val topScope = context.getTopScope val topScope = context.getTopScope
val mainModule = topScope.getModule(mainModuleName) val mainModule = topScope.getModule(mainModuleName)
runMain(mainModule) runMain(mainModule, Some(projectPath))
} }
private def runSingleFile(context: PolyglotContext, file: File): Unit = { private def runSingleFile(context: PolyglotContext, file: File): Unit = {
val mainModule = context.evalModule(file) val mainModule = context.evalModule(file)
runMain(mainModule) runMain(mainModule, Some(file))
} }
private def runMain(mainModule: Module): Value = { private def printPolyglotException(
exception: PolyglotException,
relativeTo: Option[File]
): Unit = {
val fullStack = exception.getPolyglotStackTrace.asScala.toList
val dropInitJava = fullStack.reverse
.dropWhile(_.getLanguage.getId != LanguageInfo.ID)
.reverse
println(s"Execution finished with an error: ${exception.getMessage}")
dropInitJava.foreach { frame =>
val langId =
if (frame.isHostFrame) "java" else frame.getLanguage.getId
val fmtFrame = if (frame.getLanguage.getId == LanguageInfo.ID) {
val fName = frame.getRootName
val src = Option(frame.getSourceLocation)
.map { sourceLoc =>
val ident = Option(sourceLoc.getSource.getPath)
.map { path =>
relativeTo match {
case None => path
case Some(root) =>
val absRoot = root.getAbsoluteFile
if (path.startsWith(absRoot.getAbsolutePath)) {
val rootDir =
if (absRoot.isDirectory) absRoot
else absRoot.getParentFile
rootDir.toPath.relativize(new File(path).toPath).toString
} else {
path
}
}
}
.getOrElse(sourceLoc.getSource.getName)
val loc = if (sourceLoc.getStartLine == sourceLoc.getEndLine) {
val line = sourceLoc.getStartLine
val start = sourceLoc.getStartColumn
val end = sourceLoc.getEndColumn
s"$line:$start-$end"
} else {
s"${sourceLoc.getStartLine}-${sourceLoc.getEndLine}"
}
s"$ident:$loc"
}
.getOrElse("Internal")
s"$fName($src)"
} else {
frame.toString
}
println(s" at <$langId> $fmtFrame")
}
}
private def runMain(mainModule: Module, rootPkgPath: Option[File]): Value = {
val mainCons = mainModule.getAssociatedConstructor val mainCons = mainModule.getAssociatedConstructor
val mainFun = mainModule.getMethod(mainCons, "main") val mainFun = mainModule.getMethod(mainCons, "main")
mainFun.execute(mainCons.newInstance()) try {
mainFun.execute(mainCons.newInstance())
} catch {
case e: PolyglotException =>
printPolyglotException(e, rootPkgPath)
exitFail()
}
} }
/** /**
@ -226,7 +289,7 @@ object Main {
new ContextFactory().create("", System.in, System.out, Repl(TerminalIO())) new ContextFactory().create("", System.in, System.out, Repl(TerminalIO()))
val mainModule = val mainModule =
context.evalModule(dummySourceToTriggerRepl, replModuleName) context.evalModule(dummySourceToTriggerRepl, replModuleName)
runMain(mainModule) runMain(mainModule, None)
exitSuccess() exitSuccess()
} }
@ -299,7 +362,6 @@ object Main {
val line: CommandLine = Try(parser.parse(options, args)).getOrElse { val line: CommandLine = Try(parser.parse(options, args)).getOrElse {
printHelp(options) printHelp(options)
exitFail() exitFail()
return
} }
if (line.hasOption(HELP_OPTION)) { if (line.hasOption(HELP_OPTION)) {
printHelp(options) printHelp(options)

View File

@ -8,10 +8,14 @@ import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.*; import com.oracle.truffle.api.instrumentation.*;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import org.enso.interpreter.node.EnsoRootNode;
import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.node.MethodRootNode;
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode; import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
import org.enso.interpreter.runtime.tag.IdentifiedTag; import org.enso.interpreter.runtime.tag.IdentifiedTag;
import org.enso.interpreter.runtime.type.Types; import org.enso.interpreter.runtime.type.Types;
import org.enso.pkg.QualifiedName;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -114,7 +118,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
/** Information about the function call. */ /** Information about the function call. */
public static class FunctionCallInfo { public static class FunctionCallInfo {
private final String callTargetName; private final QualifiedName moduleName;
private final QualifiedName typeName;
private final String functionName; private final String functionName;
/** /**
@ -123,16 +128,34 @@ public class IdExecutionInstrument extends TruffleInstrument {
* @param call the function call. * @param call the function call.
*/ */
public FunctionCallInfo(FunctionCallInstrumentationNode.FunctionCall call) { public FunctionCallInfo(FunctionCallInstrumentationNode.FunctionCall call) {
this.callTargetName = call.getFunction().getCallTarget().getRootNode().getQualifiedName(); RootNode rootNode = call.getFunction().getCallTarget().getRootNode();
this.functionName = call.getFunction().getName(); if (rootNode instanceof MethodRootNode) {
MethodRootNode methodNode = (MethodRootNode) rootNode;
moduleName = methodNode.getModuleScope().getModule().getName();
typeName = methodNode.getAtomConstructor().getQualifiedName();
functionName = methodNode.getMethodName();
} else if (rootNode instanceof EnsoRootNode) {
moduleName = ((EnsoRootNode) rootNode).getModuleScope().getModule().getName();
typeName = null;
functionName = rootNode.getName();
} else {
moduleName = null;
typeName = null;
functionName = rootNode.getQualifiedName();
}
} }
/** @return call target name. */ /** @return the name of the module this function was defined in, or null if not available. */
public String getCallTargetName() { public QualifiedName getModuleName() {
return callTargetName; return moduleName;
} }
/** @return function name. */ /** @return the name of the type this method was defined for, or null if not a method. */
public QualifiedName getTypeName() {
return typeName;
}
/** @return the name of this function. */
public String getFunctionName() { public String getFunctionName() {
return functionName; return functionName;
} }

View File

@ -22,19 +22,16 @@ import org.enso.interpreter.runtime.state.Stateful;
public class ClosureRootNode extends EnsoRootNode { public class ClosureRootNode extends EnsoRootNode {
@Child private ExpressionNode body; @Child private ExpressionNode body;
private final String qualifiedName;
private ClosureRootNode( ClosureRootNode(
Language language, Language language,
LocalScope localScope, LocalScope localScope,
ModuleScope moduleScope, ModuleScope moduleScope,
ExpressionNode body, ExpressionNode body,
SourceSection section, SourceSection section,
String name, String name) {
String qualifiedName) {
super(language, localScope, moduleScope, name, section); super(language, localScope, moduleScope, name, section);
this.body = body; this.body = body;
this.qualifiedName = qualifiedName;
} }
/** /**
@ -54,10 +51,9 @@ public class ClosureRootNode extends EnsoRootNode {
ModuleScope moduleScope, ModuleScope moduleScope,
ExpressionNode body, ExpressionNode body,
SourceSection section, SourceSection section,
String name, String name) {
String qualifiedName) {
return new ClosureRootNode( return new ClosureRootNode(
language, localScope, moduleScope, body, section, name, qualifiedName); language, localScope, moduleScope, body, section, name);
} }
/** /**
@ -74,14 +70,4 @@ public class ClosureRootNode extends EnsoRootNode {
state = FrameUtil.getObjectSafe(frame, this.getStateFrameSlot()); state = FrameUtil.getObjectSafe(frame, this.getStateFrameSlot());
return new Stateful(state, result); return new Stateful(state, result);
} }
/**
* Returns a qualified name that uniquely identifies the node.
*
* @return a qualified name of this node.
*/
@Override
public String getQualifiedName() {
return qualifiedName;
}
} }

View File

@ -0,0 +1,94 @@
package org.enso.interpreter.node;
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.frame.FrameUtil;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.scope.LocalScope;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.Stateful;
@ReportPolymorphism
@NodeInfo(shortName = "Method", description = "A root node for Enso methods.")
public class MethodRootNode extends ClosureRootNode {
private final AtomConstructor atomConstructor;
private final String methodName;
private MethodRootNode(
Language language,
LocalScope localScope,
ModuleScope moduleScope,
ExpressionNode body,
SourceSection section,
AtomConstructor atomConstructor,
String methodName) {
super(
language,
localScope,
moduleScope,
body,
section,
shortName(atomConstructor.getName(), methodName));
this.atomConstructor = atomConstructor;
this.methodName = methodName;
}
private static String shortName(String atomName, String methodName) {
return atomName + "." + methodName;
}
/**
* Creates an instance of this node.
*
* @param language the language identifier
* @param localScope a description of the local scope
* @param moduleScope a description of the module scope
* @param body the program body to be executed
* @param section a mapping from {@code body} to the program source
* @param atomConstructor the constructor this method is defined for
* @param methodName the name of this method
* @return a node representing the specified closure
*/
public static MethodRootNode build(
Language language,
LocalScope localScope,
ModuleScope moduleScope,
ExpressionNode body,
SourceSection section,
AtomConstructor atomConstructor,
String methodName) {
return new MethodRootNode(
language, localScope, moduleScope, body, section, atomConstructor, methodName);
}
/**
* Computes the fully qualified name of this method.
*
* <p>The name has a form of [method's module]::[qualified type name]::[method name].
*
* @return the qualified name of this method.
*/
@Override
public String getQualifiedName() {
return getModuleScope().getModule().getName().toString()
+ "::"
+ atomConstructor.getQualifiedName().toString()
+ "::"
+ methodName;
}
/** @return the constructor this method was defined for */
public AtomConstructor getAtomConstructor() {
return atomConstructor;
}
/** @return the method name */
public String getMethodName() {
return methodName;
}
}

View File

@ -6,9 +6,12 @@ import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.Source;
import org.enso.interpreter.Language; import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.Module; import org.enso.interpreter.runtime.Module;
import org.enso.pkg.QualifiedName; import org.enso.pkg.QualifiedName;
import java.io.File;
/** /**
* This node handles static transformation of the input AST before execution and represents the root * This node handles static transformation of the input AST before execution and represents the root
* of an Enso program. * of an Enso program.
@ -48,15 +51,26 @@ public class ProgramRootNode extends RootNode {
public Object execute(VirtualFrame frame) { public Object execute(VirtualFrame frame) {
if (module == null) { if (module == null) {
CompilerDirectives.transferToInterpreterAndInvalidate(); CompilerDirectives.transferToInterpreterAndInvalidate();
QualifiedName name = QualifiedName.simpleName(canonicalizeName(sourceCode.getName()));
Context ctx = lookupContextReference(Language.class).get();
module = module =
new Module( sourceCode.getPath() != null
QualifiedName.simpleName(sourceCode.getName()), ? new Module(name, ctx.getTruffleFile(new File(sourceCode.getPath())))
sourceCode.getCharacters().toString()); : new Module(name, sourceCode.getCharacters().toString());
} }
// Note [Static Passes] // Note [Static Passes]
return module; return module;
} }
private String canonicalizeName(String name) {
String[] segs = name.split("\\.");
if (segs.length == 0) {
return "Unnamed";
} else {
return segs[0];
}
}
/* Note [Static Passes] /* Note [Static Passes]
* ~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~
* Almost all of the static analysis functionality required by the interpreter requires access to * Almost all of the static analysis functionality required by the interpreter requires access to

View File

@ -58,9 +58,7 @@ public abstract class EvalNode extends BaseNode {
RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String expression) { RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String expression) {
LocalScope localScope = scope.createChild(); LocalScope localScope = scope.createChild();
InlineContext inlineContext = InlineContext inlineContext = InlineContext.fromJava(localScope, moduleScope, isTail());
InlineContext.fromJava(
localScope, moduleScope, isTail());
ExpressionNode expr = ExpressionNode expr =
lookupContextReference(Language.class) lookupContextReference(Language.class)
.get() .get()
@ -81,8 +79,7 @@ public abstract class EvalNode extends BaseNode {
moduleScope, moduleScope,
expr, expr,
null, null,
"<dynamic_eval>", "<eval>");
null);
return Truffle.getRuntime().createCallTarget(framedNode); return Truffle.getRuntime().createCallTarget(framedNode);
} }

View File

@ -39,10 +39,10 @@ public class Module implements TruffleObject {
private boolean isParsed = false; private boolean isParsed = false;
private boolean isIndexed = false; private boolean isIndexed = false;
private IR ir; private IR ir;
private final QualifiedName name; private QualifiedName name;
private Module(TruffleFile sourceFile, Rope literalSource, private Module(
boolean isParsed, IR ir, QualifiedName name) { TruffleFile sourceFile, Rope literalSource, boolean isParsed, IR ir, QualifiedName name) {
this.sourceFile = sourceFile; this.sourceFile = sourceFile;
this.literalSource = literalSource; this.literalSource = literalSource;
this.isParsed = isParsed; this.isParsed = isParsed;
@ -205,17 +205,10 @@ public class Module implements TruffleObject {
/** /**
* Renames a project part of the QualifiedName of this module. * Renames a project part of the QualifiedName of this module.
* *
* @param oldName the old project name
* @param newName the new project name * @param newName the new project name
* @return a module with the updated QualifiedName
*/ */
public Module renameProject(String oldName, String newName) { public void renameProject(String newName) {
if (name.path().head().equals(oldName)) { this.name = name.renameProject(newName);
QualifiedName renamed = name.renameProject(oldName, newName);
return new Module(sourceFile, literalSource, false, ir, renamed);
} else {
return this;
}
} }
/** @return the indexed flag. */ /** @return the indexed flag. */

View File

@ -18,6 +18,7 @@ import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema; import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.scope.ModuleScope; import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.pkg.QualifiedName;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -181,4 +182,9 @@ public class AtomConstructor implements TruffleObject {
} }
return newInstance(arguments); return newInstance(arguments);
} }
/** @return the fully qualified name of this constructor. */
public QualifiedName getQualifiedName() {
return definitionScope.getModule().getName().createChild(getName());
}
} }

View File

@ -28,7 +28,7 @@ public class ModuleScope {
*/ */
public ModuleScope(Module module) { public ModuleScope(Module module) {
this.module = module; this.module = module;
this.associatedType = new AtomConstructor(module.getName().module(), this).initializeFields(); this.associatedType = new AtomConstructor(module.getName().item(), this).initializeFields();
} }
/** /**

View File

@ -24,21 +24,18 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /** Represents the top scope of Enso execution, containing all the importable modules. */
* Represents the top scope of Enso execution, containing all the importable modules.
*/
@ExportLibrary(InteropLibrary.class) @ExportLibrary(InteropLibrary.class)
public class TopLevelScope implements TruffleObject { public class TopLevelScope implements TruffleObject {
private final Builtins builtins; private final Builtins builtins;
private final Map<String, Module> modules; private final Map<String, Module> modules;
private final Scope scope = Scope.newBuilder("top_scope", this).build(); private final Scope scope = Scope.newBuilder("top_scope", this).build();
/** /**
* Creates a new instance of top scope. * Creates a new instance of top scope.
* *
* @param builtins the automatically-imported builtin module. * @param builtins the automatically-imported builtin module.
* @param modules the initial modules this scope contains. * @param modules the initial modules this scope contains.
*/ */
public TopLevelScope(Builtins builtins, Map<String, Module> modules) { public TopLevelScope(Builtins builtins, Map<String, Module> modules) {
this.builtins = builtins; this.builtins = builtins;
@ -70,7 +67,7 @@ public class TopLevelScope implements TruffleObject {
/** /**
* Creates and registers a new module with given name and source file. * Creates and registers a new module with given name and source file.
* *
* @param name the module name. * @param name the module name.
* @param sourceFile the module source file. * @param sourceFile the module source file.
* @return the newly created module. * @return the newly created module.
*/ */
@ -89,19 +86,17 @@ public class TopLevelScope implements TruffleObject {
public void renameProjectInModules(String oldName, String newName) { public void renameProjectInModules(String oldName, String newName) {
String separator = QualifiedName$.MODULE$.separator(); String separator = QualifiedName$.MODULE$.separator();
List<String> keys = List<String> keys =
modules modules.keySet().stream()
.keySet()
.stream()
.filter(name -> name.startsWith(oldName + separator)) .filter(name -> name.startsWith(oldName + separator))
.collect(Collectors.toList()); .collect(Collectors.toList());
keys keys.stream()
.stream()
.map(modules::remove) .map(modules::remove)
.map(module -> module.renameProject(oldName, newName)) .forEach(
.forEach(module -> { module -> {
modules.put(module.getName().toString(), module); module.renameProject(newName);
}); modules.put(module.getName().toString(), module);
});
} }
/** /**
@ -140,9 +135,7 @@ public class TopLevelScope implements TruffleObject {
MethodNames.TopScope.UNREGISTER_MODULE); MethodNames.TopScope.UNREGISTER_MODULE);
} }
/** /** Handles member invocation through the polyglot API. */
* Handles member invocation through the polyglot API.
*/
@ExportMessage @ExportMessage
abstract static class InvokeMember { abstract static class InvokeMember {
private static Module getModule( private static Module getModule(

View File

@ -39,6 +39,7 @@ import org.enso.interpreter.node.expression.literal.{
import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode} import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode}
import org.enso.interpreter.node.{ import org.enso.interpreter.node.{
ClosureRootNode, ClosureRootNode,
MethodRootNode,
ExpressionNode => RuntimeExpression ExpressionNode => RuntimeExpression
} }
import org.enso.interpreter.runtime.Context import org.enso.interpreter.runtime.Context
@ -217,34 +218,39 @@ class IrToTruffle(
dataflowInfo dataflowInfo
) )
val funNode = methodDef.body match { val cons = moduleScope
.getConstructor(typeName)
.orElseThrow(() =>
new VariableDoesNotExistException(methodDef.typeName.name)
)
val function = methodDef.body match {
case fn: IR.Function => case fn: IR.Function =>
expressionProcessor.processFunctionBody( val (body, arguments) =
fn.arguments, expressionProcessor.buildFunctionBody(fn.arguments, fn.body)
fn.body, val rootNode = MethodRootNode.build(
methodDef.location, language,
Some(methodDef.methodName.name) expressionProcessor.scope,
moduleScope,
body,
makeSection(methodDef.location),
cons,
methodDef.methodName.name
)
val callTarget = Truffle.getRuntime.createCallTarget(rootNode)
new RuntimeFunction(
callTarget,
null,
new FunctionSchema(
FunctionSchema.CallStrategy.CALL_LOOP,
arguments: _*
)
) )
case _ => case _ =>
throw new CompilerError( throw new CompilerError(
"Method bodies must be functions at the point of codegen." "Method bodies must be functions at the point of codegen."
) )
} }
val function = new RuntimeFunction(
funNode.getCallTarget,
null,
new FunctionSchema(
FunctionSchema.CallStrategy.CALL_LOOP,
funNode.getArgs: _*
)
)
val cons = moduleScope
.getConstructor(typeName)
.orElseThrow(() =>
new VariableDoesNotExistException(methodDef.typeName.name)
)
moduleScope.registerMethod(cons, methodDef.methodName.name, function) moduleScope.registerMethod(cons, methodDef.methodName.name, function)
}) })
} }
@ -300,7 +306,7 @@ class IrToTruffle(
val scopeName: String val scopeName: String
) { ) {
private var currentVarName = "anonymous" private var currentVarName = "<anonymous>"
// === Construction ======================================================= // === Construction =======================================================
@ -412,15 +418,14 @@ class IrToTruffle(
childScope, childScope,
moduleScope, moduleScope,
blockNode, blockNode,
null, makeSection(block.location),
s"default::$scopeName", currentVarName
null
) )
val callTarget = Truffle.getRuntime.createCallTarget(defaultRootNode) val callTarget = Truffle.getRuntime.createCallTarget(defaultRootNode)
setLocation(CreateThunkNode.build(callTarget), block.location) setLocation(CreateThunkNode.build(callTarget), block.location)
} else { } else {
val statementExprs = block.expressions.map(this.run(_)).toArray val statementExprs = block.expressions.map(this.run).toArray
val retExpr = this.run(block.returnValue) val retExpr = this.run(block.returnValue)
val blockNode = BlockNode.build(statementExprs, retExpr) val blockNode = BlockNode.build(statementExprs, retExpr)
@ -520,8 +525,7 @@ class IrToTruffle(
val branchCodeNode = childProcessor.processFunctionBody( val branchCodeNode = childProcessor.processFunctionBody(
arg, arg,
branch.expression, branch.expression,
branch.location, branch.location
None
) )
val branchNode = CatchAllBranchNode.build(branchCodeNode) val branchNode = CatchAllBranchNode.build(branchCodeNode)
@ -542,8 +546,7 @@ class IrToTruffle(
val branchCodeNode = childProcessor.processFunctionBody( val branchCodeNode = childProcessor.processFunctionBody(
fieldsAsArgs, fieldsAsArgs,
branch.expression, branch.expression,
branch.location, branch.location
None
) )
moduleScope.getConstructor(constructor.name).toScala match { moduleScope.getConstructor(constructor.name).toScala match {
@ -659,8 +662,7 @@ class IrToTruffle(
val fn = child.processFunctionBody( val fn = child.processFunctionBody(
function.arguments, function.arguments,
function.body, function.body,
function.location, function.location
None
) )
fn fn
@ -755,20 +757,19 @@ class IrToTruffle(
setLocation(ErrorNode.build(payload), error.location) setLocation(ErrorNode.build(payload), error.location)
} }
/** Generates code for an Enso function body. /**
* Processes function arguments, generates arguments reads and creates
* a node to represent the whole method body.
* *
* @param arguments the arguments to the function * @param arguments the argument definitions
* @param body the body of the function * @param body the body definition
* @param location the location at which the function exists in the source * @return a node for the final shape of function body and pre-processed
* @param name the name of the function * argument definitions.
* @return a truffle node representing the described function
*/ */
def processFunctionBody( def buildFunctionBody(
arguments: List[IR.DefinitionArgument], arguments: List[IR.DefinitionArgument],
body: IR.Expression, body: IR.Expression
location: Option[IdentifiedLocation], ): (BlockNode, Array[ArgumentDefinition]) = {
name: Option[String]
): CreateFunctionNode = {
val argFactory = new DefinitionArgumentProcessor(scopeName, scope) val argFactory = new DefinitionArgumentProcessor(scopeName, scope)
val argDefinitions = new Array[ArgumentDefinition](arguments.size) val argDefinitions = new Array[ArgumentDefinition](arguments.size)
@ -809,24 +810,35 @@ class IrToTruffle(
val bodyExpr = this.run(body) val bodyExpr = this.run(body)
val fnBodyNode = BlockNode.build(argExpressions.toArray, bodyExpr) val fnBodyNode = BlockNode.build(argExpressions.toArray, bodyExpr)
fnBodyNode.setTail(bodyIsTail)
(fnBodyNode, argDefinitions)
}
/** Generates code for an Enso function body.
*
* @param arguments the arguments to the function
* @param body the body of the function
* @param location the location at which the function exists in the source
* @return a truffle node representing the described function
*/
def processFunctionBody(
arguments: List[IR.DefinitionArgument],
body: IR.Expression,
location: Option[IdentifiedLocation]
): CreateFunctionNode = {
val (fnBodyNode, argDefinitions) = buildFunctionBody(arguments, body)
val fnRootNode = ClosureRootNode.build( val fnRootNode = ClosureRootNode.build(
language, language,
scope, scope,
moduleScope, moduleScope,
fnBodyNode, fnBodyNode,
makeSection(location), makeSection(location),
scopeName, scopeName
name
.map(moduleScope.getModule.getName.createChild)
.map(_.toString)
.orNull
) )
val callTarget = Truffle.getRuntime.createCallTarget(fnRootNode) val callTarget = Truffle.getRuntime.createCallTarget(fnRootNode)
val expr = CreateFunctionNode.build(callTarget, argDefinitions) val expr = CreateFunctionNode.build(callTarget, argDefinitions)
fnBodyNode.setTail(bodyIsTail)
setLocation(expr, location) setLocation(expr, location)
} }
@ -987,7 +999,7 @@ class IrToTruffle(
argumentExpression.setTail(argExpressionIsTail) argumentExpression.setTail(argExpressionIsTail)
val displayName = val displayName =
s"call_argument<${name.getOrElse(String.valueOf(position))}>" s"argument<${name.getOrElse(String.valueOf(position))}>"
val section = value.location val section = value.location
.map(loc => source.createSection(loc.start, loc.end)) .map(loc => source.createSection(loc.start, loc.end))
@ -1000,8 +1012,7 @@ class IrToTruffle(
moduleScope, moduleScope,
argumentExpression, argumentExpression,
section, section,
displayName, displayName
null
) )
) )
@ -1077,8 +1088,7 @@ class IrToTruffle(
moduleScope, moduleScope,
defaultExpression, defaultExpression,
null, null,
s"default::$scopeName::${arg.name}", s"<default::$scopeName::${arg.name}>"
null
) )
CreateThunkNode.build( CreateThunkNode.build(

View File

@ -22,7 +22,6 @@ import org.enso.interpreter.instrument.{
Visualisation Visualisation
} }
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode.FunctionCall import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode.FunctionCall
import org.enso.pkg.QualifiedName
import org.enso.polyglot.runtime.Runtime.Api import org.enso.polyglot.runtime.Runtime.Api
import org.enso.polyglot.runtime.Runtime.Api.ContextId import org.enso.polyglot.runtime.Runtime.Api.ContextId
@ -255,10 +254,9 @@ trait ProgramExecutionSupport {
)(implicit ctx: RuntimeContext): Option[Api.MethodPointer] = )(implicit ctx: RuntimeContext): Option[Api.MethodPointer] =
for { for {
call <- Option(value.getCallInfo) call <- Option(value.getCallInfo)
qualifiedName <- QualifiedName.fromString(call.getCallTargetName) moduleName <- Option(call.getModuleName)
moduleName <- qualifiedName.getParent functionName = call.getFunctionName
functionName <- QualifiedName.fromString(call.getFunctionName) typeName <- Option(call.getTypeName).map(_.item)
typeName <- functionName.getParent
module <- OptionConverters.toScala( module <- OptionConverters.toScala(
ctx.executionService.getContext.getTopScope ctx.executionService.getContext.getTopScope
.getModule(moduleName.toString) .getModule(moduleName.toString)
@ -266,8 +264,8 @@ trait ProgramExecutionSupport {
modulePath <- Option(module.getPath) modulePath <- Option(module.getPath)
} yield Api.MethodPointer( } yield Api.MethodPointer(
new File(modulePath), new File(modulePath),
typeName.toString, typeName,
functionName.module functionName
) )
} }

View File

@ -1,15 +1,15 @@
package org.enso.pkg package org.enso.pkg
/** /**
* Represents a qualified name of a source module. * Represents a qualified name of a source item.
* *
* @param path the names of the package and directories the module is * @param path the names of the package and directories the item is
* contained in * contained in
* @param module the name of the module * @param item the name of the item
*/ */
case class QualifiedName(path: List[String], module: String) { case class QualifiedName(path: List[String], item: String) {
override def toString: String = override def toString: String =
(path :+ module).mkString(QualifiedName.separator) (path :+ item).mkString(QualifiedName.separator)
/** /**
* Get the parent of this qualified name. * Get the parent of this qualified name.
@ -26,21 +26,16 @@ case class QualifiedName(path: List[String], module: String) {
* @return a new qualified name based on this name. * @return a new qualified name based on this name.
*/ */
def createChild(name: String): QualifiedName = def createChild(name: String): QualifiedName =
QualifiedName(path :+ module, name) QualifiedName(path :+ item, name)
/** /**
* Renames a project part of this [[QualifiedName]]. * Renames a project part of this [[QualifiedName]].
* *
* @param oldName the old project name
* @param newName the new project name * @param newName the new project name
* @return a [[QualifiedName]] with the updated project name * @return a [[QualifiedName]] with the updated project name
*/ */
def renameProject(oldName: String, newName: String): QualifiedName = { def renameProject(newName: String): QualifiedName = {
if (path.head == oldName) { this.copy(path = newName :: path.tail)
this.copy(path = newName :: path.tail)
} else {
this
}
} }
} }

View File

@ -2,6 +2,6 @@ import Base.Test
import Test.List_Spec import Test.List_Spec
import Test.Number_Spec import Test.Number_Spec
main = Suite.run <| main = Suite.runMain <|
List_Spec.spec List_Spec.spec
Number_Spec.spec Number_Spec.spec