mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 11:41:56 +03:00
Method naming fixes (#1024)
This commit is contained in:
parent
ded61865a4
commit
6137c6559b
@ -96,6 +96,8 @@ Text.it ~behavior =
|
||||
|
||||
## Runs a suite of tests, consisting of multiple `describe` blocks.
|
||||
|
||||
Returns a `Suite` object containing the test report.
|
||||
|
||||
> Example
|
||||
Suite.run <|
|
||||
describe "Number" <|
|
||||
@ -107,5 +109,20 @@ Suite.run ~specs =
|
||||
r = State.run Suite (Suite Nil) <|
|
||||
specs
|
||||
State.get Suite
|
||||
code = if r.is_fail then 1 else 0
|
||||
System.exit code
|
||||
r
|
||||
|
||||
## 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
|
||||
|
@ -10,8 +10,9 @@ import org.enso.languageserver.boot.LanguageServerConfig
|
||||
import org.enso.pkg.PackageManager
|
||||
import org.enso.polyglot.{LanguageInfo, Module, PolyglotContext}
|
||||
import org.enso.version.VersionDescription
|
||||
import org.graalvm.polyglot.Value
|
||||
import org.graalvm.polyglot.{PolyglotException, Value}
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.util.Try
|
||||
|
||||
/** The main CLI entry point class. */
|
||||
@ -143,7 +144,10 @@ object Main {
|
||||
new HelpFormatter().printHelp(LanguageInfo.ID, options)
|
||||
|
||||
/** 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. */
|
||||
private def exitSuccess(): Unit = System.exit(0)
|
||||
@ -189,7 +193,7 @@ object Main {
|
||||
}
|
||||
val mainFile = main.get
|
||||
val mainModuleName = pkg.get.moduleNameForFile(mainFile).toString
|
||||
runPackage(context, mainModuleName)
|
||||
runPackage(context, mainModuleName, file)
|
||||
} else {
|
||||
runSingleFile(context, file)
|
||||
}
|
||||
@ -198,22 +202,81 @@ object Main {
|
||||
|
||||
private def runPackage(
|
||||
context: PolyglotContext,
|
||||
mainModuleName: String
|
||||
mainModuleName: String,
|
||||
projectPath: File
|
||||
): Unit = {
|
||||
val topScope = context.getTopScope
|
||||
val mainModule = topScope.getModule(mainModuleName)
|
||||
runMain(mainModule)
|
||||
runMain(mainModule, Some(projectPath))
|
||||
}
|
||||
|
||||
private def runSingleFile(context: PolyglotContext, file: File): Unit = {
|
||||
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 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()))
|
||||
val mainModule =
|
||||
context.evalModule(dummySourceToTriggerRepl, replModuleName)
|
||||
runMain(mainModule)
|
||||
runMain(mainModule, None)
|
||||
exitSuccess()
|
||||
}
|
||||
|
||||
@ -299,7 +362,6 @@ object Main {
|
||||
val line: CommandLine = Try(parser.parse(options, args)).getOrElse {
|
||||
printHelp(options)
|
||||
exitFail()
|
||||
return
|
||||
}
|
||||
if (line.hasOption(HELP_OPTION)) {
|
||||
printHelp(options)
|
||||
|
@ -8,10 +8,14 @@ import com.oracle.truffle.api.frame.FrameInstanceVisitor;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.instrumentation.*;
|
||||
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.MethodRootNode;
|
||||
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
|
||||
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
||||
import org.enso.interpreter.runtime.type.Types;
|
||||
import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -114,7 +118,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
/** Information about the function call. */
|
||||
public static class FunctionCallInfo {
|
||||
|
||||
private final String callTargetName;
|
||||
private final QualifiedName moduleName;
|
||||
private final QualifiedName typeName;
|
||||
private final String functionName;
|
||||
|
||||
/**
|
||||
@ -123,16 +128,34 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
* @param call the function call.
|
||||
*/
|
||||
public FunctionCallInfo(FunctionCallInstrumentationNode.FunctionCall call) {
|
||||
this.callTargetName = call.getFunction().getCallTarget().getRootNode().getQualifiedName();
|
||||
this.functionName = call.getFunction().getName();
|
||||
RootNode rootNode = call.getFunction().getCallTarget().getRootNode();
|
||||
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. */
|
||||
public String getCallTargetName() {
|
||||
return callTargetName;
|
||||
/** @return the name of the module this function was defined in, or null if not available. */
|
||||
public QualifiedName getModuleName() {
|
||||
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() {
|
||||
return functionName;
|
||||
}
|
||||
|
@ -22,19 +22,16 @@ import org.enso.interpreter.runtime.state.Stateful;
|
||||
public class ClosureRootNode extends EnsoRootNode {
|
||||
|
||||
@Child private ExpressionNode body;
|
||||
private final String qualifiedName;
|
||||
|
||||
private ClosureRootNode(
|
||||
ClosureRootNode(
|
||||
Language language,
|
||||
LocalScope localScope,
|
||||
ModuleScope moduleScope,
|
||||
ExpressionNode body,
|
||||
SourceSection section,
|
||||
String name,
|
||||
String qualifiedName) {
|
||||
String name) {
|
||||
super(language, localScope, moduleScope, name, section);
|
||||
this.body = body;
|
||||
this.qualifiedName = qualifiedName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,10 +51,9 @@ public class ClosureRootNode extends EnsoRootNode {
|
||||
ModuleScope moduleScope,
|
||||
ExpressionNode body,
|
||||
SourceSection section,
|
||||
String name,
|
||||
String qualifiedName) {
|
||||
String name) {
|
||||
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());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -6,9 +6,12 @@ import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import com.oracle.truffle.api.nodes.RootNode;
|
||||
import com.oracle.truffle.api.source.Source;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.Module;
|
||||
import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This node handles static transformation of the input AST before execution and represents the root
|
||||
* of an Enso program.
|
||||
@ -48,15 +51,26 @@ public class ProgramRootNode extends RootNode {
|
||||
public Object execute(VirtualFrame frame) {
|
||||
if (module == null) {
|
||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||
QualifiedName name = QualifiedName.simpleName(canonicalizeName(sourceCode.getName()));
|
||||
Context ctx = lookupContextReference(Language.class).get();
|
||||
module =
|
||||
new Module(
|
||||
QualifiedName.simpleName(sourceCode.getName()),
|
||||
sourceCode.getCharacters().toString());
|
||||
sourceCode.getPath() != null
|
||||
? new Module(name, ctx.getTruffleFile(new File(sourceCode.getPath())))
|
||||
: new Module(name, sourceCode.getCharacters().toString());
|
||||
}
|
||||
// Note [Static Passes]
|
||||
return module;
|
||||
}
|
||||
|
||||
private String canonicalizeName(String name) {
|
||||
String[] segs = name.split("\\.");
|
||||
if (segs.length == 0) {
|
||||
return "Unnamed";
|
||||
} else {
|
||||
return segs[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Note [Static Passes]
|
||||
* ~~~~~~~~~~~~~~~~~~~~
|
||||
* Almost all of the static analysis functionality required by the interpreter requires access to
|
||||
|
@ -58,9 +58,7 @@ public abstract class EvalNode extends BaseNode {
|
||||
|
||||
RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String expression) {
|
||||
LocalScope localScope = scope.createChild();
|
||||
InlineContext inlineContext =
|
||||
InlineContext.fromJava(
|
||||
localScope, moduleScope, isTail());
|
||||
InlineContext inlineContext = InlineContext.fromJava(localScope, moduleScope, isTail());
|
||||
ExpressionNode expr =
|
||||
lookupContextReference(Language.class)
|
||||
.get()
|
||||
@ -81,8 +79,7 @@ public abstract class EvalNode extends BaseNode {
|
||||
moduleScope,
|
||||
expr,
|
||||
null,
|
||||
"<dynamic_eval>",
|
||||
null);
|
||||
"<eval>");
|
||||
return Truffle.getRuntime().createCallTarget(framedNode);
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ public class Module implements TruffleObject {
|
||||
private boolean isParsed = false;
|
||||
private boolean isIndexed = false;
|
||||
private IR ir;
|
||||
private final QualifiedName name;
|
||||
private QualifiedName name;
|
||||
|
||||
private Module(TruffleFile sourceFile, Rope literalSource,
|
||||
boolean isParsed, IR ir, QualifiedName name) {
|
||||
private Module(
|
||||
TruffleFile sourceFile, Rope literalSource, boolean isParsed, IR ir, QualifiedName name) {
|
||||
this.sourceFile = sourceFile;
|
||||
this.literalSource = literalSource;
|
||||
this.isParsed = isParsed;
|
||||
@ -205,17 +205,10 @@ public class Module implements TruffleObject {
|
||||
/**
|
||||
* Renames a project part of the QualifiedName of this module.
|
||||
*
|
||||
* @param oldName the old project name
|
||||
* @param newName the new project name
|
||||
* @return a module with the updated QualifiedName
|
||||
*/
|
||||
public Module renameProject(String oldName, String newName) {
|
||||
if (name.path().head().equals(oldName)) {
|
||||
QualifiedName renamed = name.renameProject(oldName, newName);
|
||||
return new Module(sourceFile, literalSource, false, ir, renamed);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
public void renameProject(String newName) {
|
||||
this.name = name.renameProject(newName);
|
||||
}
|
||||
|
||||
/** @return the indexed flag. */
|
||||
|
@ -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.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -181,4 +182,9 @@ public class AtomConstructor implements TruffleObject {
|
||||
}
|
||||
return newInstance(arguments);
|
||||
}
|
||||
|
||||
/** @return the fully qualified name of this constructor. */
|
||||
public QualifiedName getQualifiedName() {
|
||||
return definitionScope.getModule().getName().createChild(getName());
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class ModuleScope {
|
||||
*/
|
||||
public ModuleScope(Module module) {
|
||||
this.module = module;
|
||||
this.associatedType = new AtomConstructor(module.getName().module(), this).initializeFields();
|
||||
this.associatedType = new AtomConstructor(module.getName().item(), this).initializeFields();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,21 +24,18 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
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)
|
||||
public class TopLevelScope implements TruffleObject {
|
||||
private final Builtins builtins;
|
||||
private final Map<String, Module> modules;
|
||||
private final Scope scope = Scope.newBuilder("top_scope", this).build();
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of top scope.
|
||||
*
|
||||
* @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) {
|
||||
this.builtins = builtins;
|
||||
@ -70,7 +67,7 @@ public class TopLevelScope implements TruffleObject {
|
||||
/**
|
||||
* 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.
|
||||
* @return the newly created module.
|
||||
*/
|
||||
@ -89,19 +86,17 @@ public class TopLevelScope implements TruffleObject {
|
||||
public void renameProjectInModules(String oldName, String newName) {
|
||||
String separator = QualifiedName$.MODULE$.separator();
|
||||
List<String> keys =
|
||||
modules
|
||||
.keySet()
|
||||
.stream()
|
||||
modules.keySet().stream()
|
||||
.filter(name -> name.startsWith(oldName + separator))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
keys
|
||||
.stream()
|
||||
keys.stream()
|
||||
.map(modules::remove)
|
||||
.map(module -> module.renameProject(oldName, newName))
|
||||
.forEach(module -> {
|
||||
modules.put(module.getName().toString(), module);
|
||||
});
|
||||
.forEach(
|
||||
module -> {
|
||||
module.renameProject(newName);
|
||||
modules.put(module.getName().toString(), module);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,9 +135,7 @@ public class TopLevelScope implements TruffleObject {
|
||||
MethodNames.TopScope.UNREGISTER_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles member invocation through the polyglot API.
|
||||
*/
|
||||
/** Handles member invocation through the polyglot API. */
|
||||
@ExportMessage
|
||||
abstract static class InvokeMember {
|
||||
private static Module getModule(
|
||||
|
@ -39,6 +39,7 @@ import org.enso.interpreter.node.expression.literal.{
|
||||
import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode}
|
||||
import org.enso.interpreter.node.{
|
||||
ClosureRootNode,
|
||||
MethodRootNode,
|
||||
ExpressionNode => RuntimeExpression
|
||||
}
|
||||
import org.enso.interpreter.runtime.Context
|
||||
@ -217,34 +218,39 @@ class IrToTruffle(
|
||||
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 =>
|
||||
expressionProcessor.processFunctionBody(
|
||||
fn.arguments,
|
||||
fn.body,
|
||||
methodDef.location,
|
||||
Some(methodDef.methodName.name)
|
||||
val (body, arguments) =
|
||||
expressionProcessor.buildFunctionBody(fn.arguments, fn.body)
|
||||
val rootNode = MethodRootNode.build(
|
||||
language,
|
||||
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 _ =>
|
||||
throw new CompilerError(
|
||||
"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)
|
||||
})
|
||||
}
|
||||
@ -300,7 +306,7 @@ class IrToTruffle(
|
||||
val scopeName: String
|
||||
) {
|
||||
|
||||
private var currentVarName = "anonymous"
|
||||
private var currentVarName = "<anonymous>"
|
||||
|
||||
// === Construction =======================================================
|
||||
|
||||
@ -412,15 +418,14 @@ class IrToTruffle(
|
||||
childScope,
|
||||
moduleScope,
|
||||
blockNode,
|
||||
null,
|
||||
s"default::$scopeName",
|
||||
null
|
||||
makeSection(block.location),
|
||||
currentVarName
|
||||
)
|
||||
|
||||
val callTarget = Truffle.getRuntime.createCallTarget(defaultRootNode)
|
||||
setLocation(CreateThunkNode.build(callTarget), block.location)
|
||||
} else {
|
||||
val statementExprs = block.expressions.map(this.run(_)).toArray
|
||||
val statementExprs = block.expressions.map(this.run).toArray
|
||||
val retExpr = this.run(block.returnValue)
|
||||
|
||||
val blockNode = BlockNode.build(statementExprs, retExpr)
|
||||
@ -520,8 +525,7 @@ class IrToTruffle(
|
||||
val branchCodeNode = childProcessor.processFunctionBody(
|
||||
arg,
|
||||
branch.expression,
|
||||
branch.location,
|
||||
None
|
||||
branch.location
|
||||
)
|
||||
|
||||
val branchNode = CatchAllBranchNode.build(branchCodeNode)
|
||||
@ -542,8 +546,7 @@ class IrToTruffle(
|
||||
val branchCodeNode = childProcessor.processFunctionBody(
|
||||
fieldsAsArgs,
|
||||
branch.expression,
|
||||
branch.location,
|
||||
None
|
||||
branch.location
|
||||
)
|
||||
|
||||
moduleScope.getConstructor(constructor.name).toScala match {
|
||||
@ -659,8 +662,7 @@ class IrToTruffle(
|
||||
val fn = child.processFunctionBody(
|
||||
function.arguments,
|
||||
function.body,
|
||||
function.location,
|
||||
None
|
||||
function.location
|
||||
)
|
||||
|
||||
fn
|
||||
@ -755,20 +757,19 @@ class IrToTruffle(
|
||||
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 body the body of the function
|
||||
* @param location the location at which the function exists in the source
|
||||
* @param name the name of the function
|
||||
* @return a truffle node representing the described function
|
||||
* @param arguments the argument definitions
|
||||
* @param body the body definition
|
||||
* @return a node for the final shape of function body and pre-processed
|
||||
* argument definitions.
|
||||
*/
|
||||
def processFunctionBody(
|
||||
def buildFunctionBody(
|
||||
arguments: List[IR.DefinitionArgument],
|
||||
body: IR.Expression,
|
||||
location: Option[IdentifiedLocation],
|
||||
name: Option[String]
|
||||
): CreateFunctionNode = {
|
||||
body: IR.Expression
|
||||
): (BlockNode, Array[ArgumentDefinition]) = {
|
||||
val argFactory = new DefinitionArgumentProcessor(scopeName, scope)
|
||||
|
||||
val argDefinitions = new Array[ArgumentDefinition](arguments.size)
|
||||
@ -809,24 +810,35 @@ class IrToTruffle(
|
||||
val bodyExpr = this.run(body)
|
||||
|
||||
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(
|
||||
language,
|
||||
scope,
|
||||
moduleScope,
|
||||
fnBodyNode,
|
||||
makeSection(location),
|
||||
scopeName,
|
||||
name
|
||||
.map(moduleScope.getModule.getName.createChild)
|
||||
.map(_.toString)
|
||||
.orNull
|
||||
scopeName
|
||||
)
|
||||
val callTarget = Truffle.getRuntime.createCallTarget(fnRootNode)
|
||||
|
||||
val expr = CreateFunctionNode.build(callTarget, argDefinitions)
|
||||
|
||||
fnBodyNode.setTail(bodyIsTail)
|
||||
|
||||
setLocation(expr, location)
|
||||
}
|
||||
|
||||
@ -987,7 +999,7 @@ class IrToTruffle(
|
||||
argumentExpression.setTail(argExpressionIsTail)
|
||||
|
||||
val displayName =
|
||||
s"call_argument<${name.getOrElse(String.valueOf(position))}>"
|
||||
s"argument<${name.getOrElse(String.valueOf(position))}>"
|
||||
|
||||
val section = value.location
|
||||
.map(loc => source.createSection(loc.start, loc.end))
|
||||
@ -1000,8 +1012,7 @@ class IrToTruffle(
|
||||
moduleScope,
|
||||
argumentExpression,
|
||||
section,
|
||||
displayName,
|
||||
null
|
||||
displayName
|
||||
)
|
||||
)
|
||||
|
||||
@ -1077,8 +1088,7 @@ class IrToTruffle(
|
||||
moduleScope,
|
||||
defaultExpression,
|
||||
null,
|
||||
s"default::$scopeName::${arg.name}",
|
||||
null
|
||||
s"<default::$scopeName::${arg.name}>"
|
||||
)
|
||||
|
||||
CreateThunkNode.build(
|
||||
|
@ -22,7 +22,6 @@ import org.enso.interpreter.instrument.{
|
||||
Visualisation
|
||||
}
|
||||
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.ContextId
|
||||
|
||||
@ -255,10 +254,9 @@ trait ProgramExecutionSupport {
|
||||
)(implicit ctx: RuntimeContext): Option[Api.MethodPointer] =
|
||||
for {
|
||||
call <- Option(value.getCallInfo)
|
||||
qualifiedName <- QualifiedName.fromString(call.getCallTargetName)
|
||||
moduleName <- qualifiedName.getParent
|
||||
functionName <- QualifiedName.fromString(call.getFunctionName)
|
||||
typeName <- functionName.getParent
|
||||
moduleName <- Option(call.getModuleName)
|
||||
functionName = call.getFunctionName
|
||||
typeName <- Option(call.getTypeName).map(_.item)
|
||||
module <- OptionConverters.toScala(
|
||||
ctx.executionService.getContext.getTopScope
|
||||
.getModule(moduleName.toString)
|
||||
@ -266,8 +264,8 @@ trait ProgramExecutionSupport {
|
||||
modulePath <- Option(module.getPath)
|
||||
} yield Api.MethodPointer(
|
||||
new File(modulePath),
|
||||
typeName.toString,
|
||||
functionName.module
|
||||
typeName,
|
||||
functionName
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
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
|
||||
* @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 =
|
||||
(path :+ module).mkString(QualifiedName.separator)
|
||||
(path :+ item).mkString(QualifiedName.separator)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
def createChild(name: String): QualifiedName =
|
||||
QualifiedName(path :+ module, name)
|
||||
QualifiedName(path :+ item, name)
|
||||
|
||||
/**
|
||||
* Renames a project part of this [[QualifiedName]].
|
||||
*
|
||||
* @param oldName the old project name
|
||||
* @param newName the new project name
|
||||
* @return a [[QualifiedName]] with the updated project name
|
||||
*/
|
||||
def renameProject(oldName: String, newName: String): QualifiedName = {
|
||||
if (path.head == oldName) {
|
||||
this.copy(path = newName :: path.tail)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
def renameProject(newName: String): QualifiedName = {
|
||||
this.copy(path = newName :: path.tail)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,6 @@ import Base.Test
|
||||
import Test.List_Spec
|
||||
import Test.Number_Spec
|
||||
|
||||
main = Suite.run <|
|
||||
main = Suite.runMain <|
|
||||
List_Spec.spec
|
||||
Number_Spec.spec
|
||||
|
Loading…
Reference in New Issue
Block a user