From 07b80ce5cbaac459527d4400635947a711ef4c8b Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Thu, 12 Jun 2025 23:23:29 +0300 Subject: [PATCH] init nodes, some basic nodes implementations --- .gitignore | 4 +- README.md | 2 + .../truffle_lama/FunctionObject.java | 36 ++ .../truffle_lama/GlobalScopeObject.java | 121 ++++++ .../truffle_lama/LamaContext.java | 76 ++-- .../truffle_lama/LamaLanguage.java | 344 +++++++++--------- .../programsnail/truffle_lama/LamaTypes.java | 7 - .../builtins/LamaBuiltinNode.java | 3 + .../nodes/FunctionDispatchNode.java | 34 ++ .../truffle_lama/nodes/LamaDeclNode.java | 4 + .../nodes/LamaExpressionNode.java | 21 +- .../truffle_lama/nodes/LamaRootNode.java | 21 ++ .../truffle_lama/nodes/LamaTypes.java | 6 + .../nodes/controlflow/LamaCaseNode.java | 4 + .../nodes/controlflow/LamaControlNode.java | 4 + .../nodes/controlflow/LamaDoWhileNode.java | 52 +++ .../nodes/controlflow/LamaIfNode.java | 27 ++ .../nodes/controlflow/LamaWhileNode.java | 52 +++ .../nodes/expression/LamaArrayNode.java | 4 + .../nodes/expression/LamaAssignNode.java | 4 + .../nodes/expression/LamaBinopNode.java | 52 +++ .../nodes/expression/LamaCallNode.java | 4 + .../nodes/expression/LamaConstNode.java | 28 ++ .../nodes/expression/LamaElemNode.java | 4 + .../nodes/expression/LamaElemRefNode.java | 4 + .../nodes/expression/LamaIgnoreNode.java | 16 + .../nodes/expression/LamaIntrinsicNode.java | 4 + .../nodes/expression/LamaLambdaNode.java | 4 + .../nodes/expression/LamaLeaveNode.java | 4 + .../nodes/expression/LamaRefNode.java | 4 + .../nodes/expression/LamaScopeNode.java | 4 + .../nodes/expression/LamaSeqNode.java | 4 + .../nodes/expression/LamaSexpNode.java | 4 + .../nodes/expression/LamaSkipNode.java | 4 + .../nodes/expression/LamaStringNode.java | 4 + .../nodes/expression/LamaUnitNode.java | 13 + .../nodes/expression/LamaVarNode.java | 4 + .../programsnail/truffle_lama/parser/Lama.g4 | 21 +- .../truffle_lama/parser/LamaLexer.java | 3 + .../truffle_lama/parser/LamaNodeFactory.java | 19 + .../truffle_lama/parser/LamaParseError.java | 54 +++ .../truffle_lama/parser/LamaParser.java | 26 +- .../truffle_lama/runtime/LamaException.java | 14 + .../truffle_lama/runtime/LamaSExp.java | 13 + .../truffle_lama/runtime/LamaUnit.java | 8 + src/test/java/BasicNodesTest.java | 17 + 46 files changed, 906 insertions(+), 256 deletions(-) create mode 100644 src/main/java/org/programsnail/truffle_lama/FunctionObject.java create mode 100644 src/main/java/org/programsnail/truffle_lama/GlobalScopeObject.java delete mode 100644 src/main/java/org/programsnail/truffle_lama/LamaTypes.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/FunctionDispatchNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/LamaDeclNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/LamaRootNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/LamaTypes.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaCaseNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaControlNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaDoWhileNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaIfNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaWhileNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaArrayNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaAssignNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaBinopNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaCallNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaConstNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemRefNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIgnoreNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIntrinsicNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLambdaNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLeaveNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaRefNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaScopeNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSeqNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSexpNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSkipNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaStringNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaUnitNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaVarNode.java create mode 100644 src/main/java/org/programsnail/truffle_lama/parser/LamaNodeFactory.java create mode 100644 src/main/java/org/programsnail/truffle_lama/parser/LamaParseError.java create mode 100644 src/main/java/org/programsnail/truffle_lama/runtime/LamaException.java create mode 100644 src/main/java/org/programsnail/truffle_lama/runtime/LamaSExp.java create mode 100644 src/main/java/org/programsnail/truffle_lama/runtime/LamaUnit.java create mode 100644 src/test/java/BasicNodesTest.java diff --git a/.gitignore b/.gitignore index 5ff6309..c11d9bf 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ build/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store + +gen/ diff --git a/README.md b/README.md index 920818d..4a30adf 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ This is an attempt to implement the LaMa language (https://github.com/PLTools/Lama) with GraalVM and Truffle. Code is based on: + - https://github.com/graalvm/simplelanguage - https://github.com/cesquivias/mumbler +- https://github.com/skinny85/graalvm-truffle-tutorial --- diff --git a/src/main/java/org/programsnail/truffle_lama/FunctionObject.java b/src/main/java/org/programsnail/truffle_lama/FunctionObject.java new file mode 100644 index 0000000..65e31d7 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/FunctionObject.java @@ -0,0 +1,36 @@ +package org.programsnail.truffle_lama; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import org.programsnail.truffle_lama.nodes.FunctionDispatchNode; +import org.programsnail.truffle_lama.runtime.LamaException; + +@ExportLibrary(InteropLibrary.class) +public final class FunctionObject implements TruffleObject { + public final CallTarget callTarget; + public final int argumentCount; + public final FunctionDispatchNode functionDispatchNode; + + public FunctionObject(CallTarget callTarget, int argumentCount, FunctionDispatchNode functionDispatchNode) { + this.callTarget = callTarget; + this.argumentCount = argumentCount; + this.functionDispatchNode = functionDispatchNode; + } + + @ExportMessage + boolean isExecutable() { + return true; + } + + @ExportMessage + Object execute(Object[] arguments) { + if (arguments.length != argumentCount) { + throw new LamaException("Wrong amount of function arguments: " + arguments.length + " instead of " + argumentCount); + } + // TODO: check values of arguments ?? + return this.functionDispatchNode.executeDispatch(this, arguments); + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/GlobalScopeObject.java b/src/main/java/org/programsnail/truffle_lama/GlobalScopeObject.java new file mode 100644 index 0000000..3c343db --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/GlobalScopeObject.java @@ -0,0 +1,121 @@ +package org.programsnail.truffle_lama; + +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import org.programsnail.truffle_lama.runtime.LamaException; + +import java.util.*; + +@ExportLibrary(InteropLibrary.class) +public final class GlobalScopeObject implements TruffleObject { + private final Map variables = new HashMap<>(); + private final Set constants = new HashSet<>(); + + public boolean newVariable(String name, Object value, boolean isConst) { + Object previousValue = variables.put(name, value); + if (isConst) { + constants.add(name); + } + return previousValue == null; + } + + public void newFunction(String name, FunctionObject fun) { + variables.put(name, fun); + } + + public boolean updateVariable(String name, Object value) { + if (this.constants.contains(name)) { + throw new LamaException("Can't assign to const var '" + name + "'."); + } + Object updatedValue = this.variables.computeIfPresent(name, (k, v) -> value); + return updatedValue != null; + } + + public Object getVariable(String name) { + return this.variables.get(name); + } + + // --- + + @ExportMessage + boolean isScope() { + return true; + } + + @ExportMessage + boolean hasMembers() { + return true; + } + + @ExportMessage + Object getMembers(@SuppressWarnings("unused") boolean includeInternal) { + return new GlobalVariableNamesObject(this.variables.keySet()); + } + + @ExportMessage + boolean isMemberReadable(String member) { + return this.variables.containsKey(member); + } + + @ExportMessage + Object readMember(String member) throws UnknownIdentifierException { + Object value = this.variables.get(member); + if (null == value) { + throw UnknownIdentifierException.create(member); + } + return value; + } + + @ExportMessage + Object toDisplayString(@SuppressWarnings("unused") boolean allowSideEffects) { + return "global"; + } + + @ExportMessage + boolean hasLanguage() { + return true; + } + + @ExportMessage + Class> getLanguage() { + return LamaLanguage.class; + } + +} + +@ExportLibrary(InteropLibrary.class) +final class GlobalVariablesNamesObject implements TruffleObject { + private final List names; + + GlobalVariablesNamesObject(List names) { + this.names = names; + } + + @ExportMessage + boolean hasArrayElements() { + return true; + } + + @ExportMessage + long getArraySize() { + return this.names.size(); + } + + @ExportMessage + boolean isArrayElementReadable(long index) { + return index >= 0 && index < this.names.size(); + } + + @ExportMessage + Object readArrayElement(long index) throws InvalidArrayIndexException { + if (!this.isArrayElementReadable(index)) { + throw InvalidArrayIndexException.create(index); + } + return this.names.get((int) index); + } + +} \ No newline at end of file diff --git a/src/main/java/org/programsnail/truffle_lama/LamaContext.java b/src/main/java/org/programsnail/truffle_lama/LamaContext.java index 2d0a5ff..d55cebb 100644 --- a/src/main/java/org/programsnail/truffle_lama/LamaContext.java +++ b/src/main/java/org/programsnail/truffle_lama/LamaContext.java @@ -1,47 +1,59 @@ package org.programsnail.truffle_lama; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; import java.awt.*; -// TODO -public class LamaContext { - private final FrameDescriptor globalFrameDescriptor; - private final Namespace globalNamespace; - private final MaterializedFrame globalFrame; - private final LamaLanguage language; +public final class LamaContext { + private static final TruffleLanguage.ContextReference REF = TruffleLanguage.ContextReference.create(LamaLanguage.class); - public LamaContext() { this(null); } - - public LamaContext(LamaLanguage language) { - this.globalFrameDescriptor = new FrameDescriptor(); - this.globalNamespace = new Namespace(this.globalFrameDescriptor); - this.globalFrame = this.initGlobalFrame(language); - this.language = language; + public static LamaContext get(Node node) { + return REF.get(node); } - private MaterializedFrame initGlobalFrame(LamaLanguage language) { - VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(null, this.globalFrameDescriptor); - addGlobalFunctions(language, frame); - return frame.materialize(); - } + public final GlobalScopeObject globalScopeObject; - private static void addGlobalFunctions(LamaLanguage language, VirtualFrame virtualFrame) { - // TODO - } - - /** - * @return A {@link MaterializedFrame} on the heap that contains all global - * values. - */ - public MaterializedFrame getGlobalFrame() { - return this.globalFrame; - } - - public Namespace getGlobalNamespace() { - return this.globalNamespace; + public LamaContext() { + this.globalScopeObject = new GlobalScopeObject(); } +// private final FrameDescriptor globalFrameDescriptor; +// private final Namespace globalNamespace; +// private final MaterializedFrame globalFrame; +// private final LamaLanguage language; +// +// public LamaContext() { this(null); } +// +// public LamaContext(LamaLanguage language) { +// this.globalFrameDescriptor = new FrameDescriptor(); +// this.globalNamespace = new Namespace(this.globalFrameDescriptor); +// this.globalFrame = this.initGlobalFrame(language); +// this.language = language; +// } +// +// private MaterializedFrame initGlobalFrame(LamaLanguage language) { +// VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(null, this.globalFrameDescriptor); +// addGlobalFunctions(language, frame); +// return frame.materialize(); +// } +// +// private static void addGlobalFunctions(LamaLanguage language, VirtualFrame virtualFrame) { +// // TODO +// } +// +// /** +// * @return A {@link MaterializedFrame} on the heap that contains all global +// * values. +// */ +// public MaterializedFrame getGlobalFrame() { +// return this.globalFrame; +// } +// +// public Namespace getGlobalNamespace() { +// return this.globalNamespace; +// } } diff --git a/src/main/java/org/programsnail/truffle_lama/LamaLanguage.java b/src/main/java/org/programsnail/truffle_lama/LamaLanguage.java index eb8aa62..8b8f667 100644 --- a/src/main/java/org/programsnail/truffle_lama/LamaLanguage.java +++ b/src/main/java/org/programsnail/truffle_lama/LamaLanguage.java @@ -14,6 +14,9 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; +import org.programsnail.truffle_lama.builtins.LamaBuiltinNode; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.nodes.LamaRootNode; import org.programsnail.truffle_lama.parser.LamaParser; import java.util.ArrayList; @@ -23,204 +26,185 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @TruffleLanguage.Registration(id = LamaLanguage.ID, name = "Lama", defaultMimeType = LamaLanguage.MIME_TYPE, characterMimeTypes = LamaLanguage.MIME_TYPE, contextPolicy = TruffleLanguage.ContextPolicy.SHARED, fileTypeDetectors = LamaFileDetector.class) -@ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, StandardTags.RootBodyTag.class, StandardTags.ExpressionTag.class, DebuggerTags.AlwaysHalt.class, - StandardTags.ReadVariableTag.class, StandardTags.WriteVariableTag.class}) +//@ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, StandardTags.RootBodyTag.class, StandardTags.ExpressionTag.class, DebuggerTags.AlwaysHalt.class, +// StandardTags.ReadVariableTag.class, StandardTags.WriteVariableTag.class}) public class LamaLanguage extends TruffleLanguage { - public static volatile int counter; // count class instances +// public static volatile int counter; // count class instances public static final String ID = "lama"; public static final String MIME_TYPE = "application/x-lama"; - private static final Source BUILTIN_SOURCE = Source.newBuilder(ID, "", "LaMa builtin").build(); - private static final LanguageReference REFERENCE = LanguageReference.create(LamaLanguage.class); - private static final List> EXTERNAL_BUILTINS = Collections.synchronizedList(new ArrayList<>()); +// private static final Source BUILTIN_SOURCE = Source.newBuilder(ID, "", "LaMa builtin").build(); +// private static final LanguageReference REFERENCE = LanguageReference.create(LamaLanguage.class); +// private static final List> EXTERNAL_BUILTINS = Collections.synchronizedList(new ArrayList<>()); - public static final TruffleString.Encoding STRING_ENCODING = TruffleString.Encoding.UTF_16; +// public static final TruffleString.Encoding STRING_ENCODING = TruffleString.Encoding.UTF_16; private final Assumption singleContext = Truffle.getRuntime().createAssumption("Single Lama context."); - private final Map, RootCallTarget> builtinTargets = new ConcurrentHashMap<>(); - private final Map undefinedFunctions = new ConcurrentHashMap<>(); - - private final Shape rootShape; - - // - - public LamaLanguage() { - counter++; - this.rootShape = Shape.newBuilder().layout(LamaObject.class).build(); + @Override + protected CallTarget parse(ParsingRequest request) throws Exception { + var exprNode = LamaParser.parseLama(this, request.getSource()); + var rootNode = new LamaRootNode(exprNode); + return rootNode.getCallTarget(); } @Override protected LamaContext createContext(Env env) { - return new LamaContext(this, env, new ArrayList<>(EXTERNAL_BUILTINS)); - } - - @Override - protected boolean patchContext(LamaContext context, Env newEnv) { - context.patchContext(newEnv); - return true; - } - - // - - public RootCallTarget getOrCreateUndefinedFunction(TruffleString name) { - RootCallTarget target = undefinedFunctions.get(name); - if (target == null) { - target = new LamaUndefinedFunctionRootNode(this, name).getCallTarget(); - RootCallTarget other = undefinedFunctions.putIfAbsent(name, target); - if (other != null) { - target = other; - } - } - return target; - } - - public RootCallTarget lookupBuiltin(NodeFactory factory) { - RootCallTarget target = builtinTargets.get(factory); - if (target != null) { - return target; - } - - /* - * The builtin node factory is a class that is automatically generated by the Truffle DSL. - * The signature returned by the factory reflects the signature of the @Specialization - * - * methods in the builtin classes. - */ - int argumentCount = factory.getExecutionSignature().size(); - LamaExpressionNode[] argumentNodes = new LamaExpressionNode[argumentCount]; - /* - * Builtin functions are like normal functions, i.e., the arguments are passed in as an - * Object[] array encapsulated in SLArguments. A SLReadArgumentNode extracts a parameter - * from this array. - */ - for (int i = 0; i < argumentCount; i++) { - argumentNodes[i] = new LamaReadArgumentNode(i); - } - /* Instantiate the builtin node. This node performs the actual functionality. */ - LamaBuiltinNode builtinBodyNode = factory.createNode((Object) argumentNodes); - builtinBodyNode.addRootTag(); - /* The name of the builtin function is specified via an annotation on the node class. */ - TruffleString name = LamaStrings.fromJavaString(lookupNodeInfo(builtinBodyNode.getClass()).shortName()); - builtinBodyNode.setUnavailableSourceSection(); - - /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */ - LamamRootNode rootNode = new LammaRootNode(this, new FrameDescriptor(), builtinBodyNode, BUILTIN_SOURCE.createUnavailableSection(), name); - - /* - * Register the builtin function in the builtin registry. Call targets for builtins may be - * reused across multiple contexts. - */ - RootCallTarget newTarget = rootNode.getCallTarget(); - RootCallTarget oldTarget = builtinTargets.putIfAbsent(factory, newTarget); - if (oldTarget != null) { - return oldTarget; - } - return newTarget; - } - - public static NodeInfo lookupNodeInfo(Class c) { - if (c == null) { - return null; - } - NodeInfo info = c.getAnnotation(NodeInfo.class); - if (info != null) { - return info; - } else { - return lookupNodeInfo(c.getSuperclass()); - } - } - - @Override - protected CallTarget parse(ParsingRequest request) throws Exception { - Source source = request.getSource(); - Map functions; - /* - * Parse the provided source. At this point, we do not have a SLContext yet. Registration of - * the functions with the SLContext happens lazily in SLEvalRootNode. - */ - if (request.getArgumentNames().isEmpty()) { - functions = LamaParser.parseLama(this, source); - } else { - StringBuilder sb = new StringBuilder(); - sb.append("function main("); - String sep = ""; - for (String argumentName : request.getArgumentNames()) { - sb.append(sep); - sb.append(argumentName); - sep = ","; - } - sb.append(") { return "); - sb.append(source.getCharacters()); - sb.append(";}"); - String language = source.getLanguage() == null ? ID : source.getLanguage(); - Source decoratedSource = Source.newBuilder(language, sb.toString(), source.getName()).build(); - functions = LamaParser.parseLama(this, decoratedSource); - } - - // TODO: execute source itself, not main function - - return ; - } - - @Override - protected void initializeMultipleContexts() { - singleContext.invalidate(); - } - - public boolean isSingleContext() { - return singleContext.isValid(); - } - - @Override - protected Object getLanguageView(LamaContext context, Object value) { - return LamaLanguageView.create(value); - } - - @Override - protected boolean isVisible(LamaContext context, Object value) { - return !InteropLibrary.getFactory().getUncached(value).isNull(value); + return new LamaContext(); } @Override protected Object getScope(LamaContext context) { - return context.getFunctionRegistry().getFunctionsObject(); - } - - public Shape getRootShape() { - return rootShape; - } - - /** - * Allocate an empty object. All new objects initially have no properties. Properties are added - * when they are first stored, i.e., the store triggers a shape change of the object. - */ - public LamaObject createObject(AllocationReporter reporter) { - reporter.onEnter(null, 0, AllocationReporter.SIZE_UNKNOWN); - LamaObject object = new LamaObject(rootShape); - reporter.onReturnValue(object, 0, AllocationReporter.SIZE_UNKNOWN); - return object; + return context.globalScopeObject; } // - - public static LamaLanguage get(Node node) { - return REFERENCE.get(node); - } - - // - - public static void installBuiltin(NodeFactory builtin) { - EXTERNAL_BUILTINS.add(builtin); - } - - @Override - protected void exitContext(LamaContext context, ExitMode exitMode, int exitCode) { - /* - * Runs shutdown hooks during explicit exit triggered by TruffleContext#closeExit(Node, int) - * or natural exit triggered during natural context close. - */ - context.runShutdownHooks(); - } +// // +// +// public LamaLanguage() { +//// counter++; +// } +// +// @Override +// protected LamaContext createContext(Env env) { +// return new LamaContext(this, env, new ArrayList<>(EXTERNAL_BUILTINS)); +// } +// +// @Override +// protected boolean patchContext(LamaContext context, Env newEnv) { +// context.patchContext(newEnv); +// return true; +// } +// +// // +// +// public RootCallTarget getOrCreateUndefinedFunction(TruffleString name) { +// RootCallTarget target = undefinedFunctions.get(name); +// if (target == null) { +// target = new LamaUndefinedFunctionRootNode(this, name).getCallTarget(); +// RootCallTarget other = undefinedFunctions.putIfAbsent(name, target); +// if (other != null) { +// target = other; +// } +// } +// return target; +// } +// +// public RootCallTarget lookupBuiltin(NodeFactory factory) { +// RootCallTarget target = builtinTargets.get(factory); +// if (target != null) { +// return target; +// } +// +// /* +// * The builtin node factory is a class that is automatically generated by the Truffle DSL. +// * The signature returned by the factory reflects the signature of the @Specialization +// * +// * methods in the builtin classes. +// */ +// int argumentCount = factory.getExecutionSignature().size(); +// LamaExpressionNode[] argumentNodes = new LamaExpressionNode[argumentCount]; +// /* +// * Builtin functions are like normal functions, i.e., the arguments are passed in as an +// * Object[] array encapsulated in SLArguments. A SLReadArgumentNode extracts a parameter +// * from this array. +// */ +// for (int i = 0; i < argumentCount; i++) { +// argumentNodes[i] = new LamaReadArgumentNode(i); +// } +// /* Instantiate the builtin node. This node performs the actual functionality. */ +// LamaBuiltinNode builtinBodyNode = factory.createNode((Object) argumentNodes); +// builtinBodyNode.addRootTag(); +// /* The name of the builtin function is specified via an annotation on the node class. */ +// TruffleString name = LamaStrings.fromJavaString(lookupNodeInfo(builtinBodyNode.getClass()).shortName()); +// builtinBodyNode.setUnavailableSourceSection(); +// +// /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */ +// LamaRootNode rootNode = new LamaRootNode(this, new FrameDescriptor(), builtinBodyNode, BUILTIN_SOURCE.createUnavailableSection(), name); +// +// /* +// * Register the builtin function in the builtin registry. Call targets for builtins may be +// * reused across multiple contexts. +// */ +// RootCallTarget newTarget = rootNode.getCallTarget(); +// RootCallTarget oldTarget = builtinTargets.putIfAbsent(factory, newTarget); +// if (oldTarget != null) { +// return oldTarget; +// } +// return newTarget; +// } +// +// public static NodeInfo lookupNodeInfo(Class c) { +// if (c == null) { +// return null; +// } +// NodeInfo info = c.getAnnotation(NodeInfo.class); +// if (info != null) { +// return info; +// } else { +// return lookupNodeInfo(c.getSuperclass()); +// } +// } +// +// +// @Override +// protected void initializeMultipleContexts() { +// singleContext.invalidate(); +// } +// +// public boolean isSingleContext() { +// return singleContext.isValid(); +// } +// +// @Override +// protected Object getLanguageView(LamaContext context, Object value) { +// return LamaLanguageView.create(value); +// } +// +// @Override +// protected boolean isVisible(LamaContext context, Object value) { +// return !InteropLibrary.getFactory().getUncached(value).isNull(value); +// } +// +// @Override +// protected Object getScope(LamaContext context) { +// return context.getFunctionRegistry().getFunctionsObject(); +// } +// +// public Shape getRootShape() { +// return rootShape; +// } +// +// /** +// * Allocate an empty object. All new objects initially have no properties. Properties are added +// * when they are first stored, i.e., the store triggers a shape change of the object. +// */ +// public LamaObject createObject(AllocationReporter reporter) { +// reporter.onEnter(null, 0, AllocationReporter.SIZE_UNKNOWN); +// LamaObject object = new LamaObject(rootShape); +// reporter.onReturnValue(object, 0, AllocationReporter.SIZE_UNKNOWN); +// return object; +// } +// +// // +// +// public static LamaLanguage get(Node node) { +// return REFERENCE.get(node); +// } +// +// // +// +// public static void installBuiltin(NodeFactory builtin) { +// EXTERNAL_BUILTINS.add(builtin); +// } +// +// @Override +// protected void exitContext(LamaContext context, ExitMode exitMode, int exitCode) { +// /* +// * Runs shutdown hooks during explicit exit triggered by TruffleContext#closeExit(Node, int) +// * or natural exit triggered during natural context close. +// */ +// context.runShutdownHooks(); +// } } diff --git a/src/main/java/org/programsnail/truffle_lama/LamaTypes.java b/src/main/java/org/programsnail/truffle_lama/LamaTypes.java deleted file mode 100644 index b01afab..0000000 --- a/src/main/java/org/programsnail/truffle_lama/LamaTypes.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.programsnail.truffle_lama; - -import com.oracle.truffle.api.dsl.ImplicitCast; -import com.oracle.truffle.api.dsl.TypeSystem; - -@TypeSystem({long.class, boolean.class, String.class}) -public class LamaTypes {} diff --git a/src/main/java/org/programsnail/truffle_lama/builtins/LamaBuiltinNode.java b/src/main/java/org/programsnail/truffle_lama/builtins/LamaBuiltinNode.java index d508dca..a312450 100644 --- a/src/main/java/org/programsnail/truffle_lama/builtins/LamaBuiltinNode.java +++ b/src/main/java/org/programsnail/truffle_lama/builtins/LamaBuiltinNode.java @@ -6,6 +6,9 @@ import com.oracle.truffle.api.dsl.UnsupportedSpecializationException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; + + @NodeChild(value = "arguments", type = LamaExpressionNode[].class) @GenerateNodeFactory public abstract class LamaBuiltinNode extends LamaExpressionNode { diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/FunctionDispatchNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/FunctionDispatchNode.java new file mode 100644 index 0000000..868286d --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/FunctionDispatchNode.java @@ -0,0 +1,34 @@ +package org.programsnail.truffle_lama.nodes; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.IndirectCallNode; +import com.oracle.truffle.api.nodes.Node; +import org.programsnail.truffle_lama.FunctionObject; +import org.programsnail.truffle_lama.runtime.LamaException; + +public abstract class FunctionDispatchNode extends Node { + public abstract Object executeDispatch(Object function, Object[] arguments); + + @Specialization(guards = "function.callTarget == directCallNode.getCallTarget()", limit = "2") + protected static Object dispatchDirectly(FunctionObject function, + Object[] arguments, + @Cached("create(function.callTarget)") + DirectCallNode directCallNode) { + return directCallNode.call(arguments); // TODO: check arguments count ?? + } + + @Specialization(replaces = "dispatchDirectly") + protected static Object dispatchIndirectly(FunctionObject function, + Object[] arguments, + IndirectCallNode indirectCallNode) { + return indirectCallNode.call(function.callTarget, arguments); // TODO: check arguments count ?? + } + + @Fallback + protected static Object targetIsNotAFunction(Object object, Object[] arguments) { + throw new LamaException("Called '" + object + "' is not a function"); + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/LamaDeclNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/LamaDeclNode.java new file mode 100644 index 0000000..5f79a3a --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/LamaDeclNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes; + +public class LamaDeclNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/LamaExpressionNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/LamaExpressionNode.java index fb3af8e..3fcb13b 100644 --- a/src/main/java/org/programsnail/truffle_lama/nodes/LamaExpressionNode.java +++ b/src/main/java/org/programsnail/truffle_lama/nodes/LamaExpressionNode.java @@ -3,13 +3,13 @@ package org.programsnail.truffle_lama.nodes; import com.oracle.truffle.api.dsl.TypeSystemReference; 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.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; -@TypeSystemReference(SLTypes.class) +@TypeSystemReference(LamaTypes.class) @NodeInfo(description = "The abstract base node for all expressions") -@GenerateWrapper -public abstract class LamaExpressionNode extends LamaStatementNode { +public abstract class LamaExpressionNode extends Node { private boolean hasExpressionTag; @@ -17,29 +17,21 @@ public abstract class LamaExpressionNode extends LamaStatementNode { * The execute method when no specialization is possible. This is the most general case, * therefore it must be provided by all subclasses. */ - public abstract Object executeGeneric(VirtualFrame frame); + public abstract Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException; /** - * When we use an expression at places where a {@link LamaStatementNode statement} is already - * sufficient, the return value is just discarded. + * The return value is just discarded. */ - @Override public void executeVoid(VirtualFrame frame) { executeGeneric(frame); } - // LamaExpressionNodeWrapper is generated (?) - @Override - public InstrumentableNode.WrapperNode createWrapper(ProbeNode probe) { - return new LamaExpressionNodeWrapper(this, probe); - } - @Override public boolean hasTag(Class tag) { if (tag == StandardTags.ExpressionTag.class) { return hasExpressionTag; } - return super.hasTag(tag); + return false; // no super tags } /** @@ -57,6 +49,7 @@ public abstract class LamaExpressionNode extends LamaStatementNode { // LamaTypesGen is generated from LamaTypes + // TODO public long executeLong(VirtualFrame frame) throws UnexpectedResultException { return LamaTypesGen.expectLong(executeGeneric(frame)); } diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/LamaRootNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/LamaRootNode.java new file mode 100644 index 0000000..2ef0b58 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/LamaRootNode.java @@ -0,0 +1,21 @@ +package org.programsnail.truffle_lama.nodes; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.RootNode; + +public class LamaRootNode extends RootNode { + @SuppressWarnings("FieldMayBeFinal") + @Child + private LamaExpressionNode exprNode; + + public LamaRootNode(LamaExpressionNode exprNode) { + super(null); + + this.exprNode = exprNode; + } + + @Override + public Object execute(VirtualFrame frame) { + return this.exprNode.executeGeneric(frame); + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/LamaTypes.java b/src/main/java/org/programsnail/truffle_lama/nodes/LamaTypes.java new file mode 100644 index 0000000..e069173 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/LamaTypes.java @@ -0,0 +1,6 @@ +package org.programsnail.truffle_lama.nodes; + +import com.oracle.truffle.api.dsl.TypeSystem; + +@TypeSystem({long.class, boolean.class, String.class}) +public abstract class LamaTypes {} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaCaseNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaCaseNode.java new file mode 100644 index 0000000..9d7250d --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaCaseNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.controlflow; + +public class LamaCaseNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaControlNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaControlNode.java new file mode 100644 index 0000000..f0bc727 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaControlNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.controlflow; + +public class LamaControlNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaDoWhileNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaDoWhileNode.java new file mode 100644 index 0000000..554da11 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaDoWhileNode.java @@ -0,0 +1,52 @@ +package org.programsnail.truffle_lama.nodes.controlflow; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RepeatingNode; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.runtime.LamaUnit; + +public final class LamaDoWhileNode extends LamaExpressionNode { + @SuppressWarnings("FieldMayBeFinal") + @Child + private LoopNode loopNode; + + public LamaDoWhileNode(LamaExpressionNode conditionExpr, LamaExpressionNode bodyExpr) { + this.loopNode = Truffle.getRuntime().createLoopNode( + new WhileRepeatingNode(conditionExpr, bodyExpr)); + } + + @Override + public Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException { + this.loopNode.execute(frame); + return LamaUnit.INSTANCE; + } + + private static final class WhileRepeatingNode extends Node implements RepeatingNode { + @SuppressWarnings("FieldMayBeFinal") + @Child + private LamaExpressionNode conditionExpr, bodyExpr; + + public WhileRepeatingNode(LamaExpressionNode conditionExpr, LamaExpressionNode bodyExpr) { + this.conditionExpr = conditionExpr; + this.bodyExpr = bodyExpr; + } + + @Override + public boolean executeRepeating(VirtualFrame frame) { + try { + this.bodyExpr.executeGeneric(frame); + // NOTE: try/catch for break/continue + if (!this.conditionExpr.executeBoolean(frame)) { + return false; + } + return false; + } catch (UnexpectedResultException e) { // TODO: handle in proper way + return false; + } + } + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaIfNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaIfNode.java new file mode 100644 index 0000000..0d620b9 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaIfNode.java @@ -0,0 +1,27 @@ +package org.programsnail.truffle_lama.nodes.controlflow; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import com.oracle.truffle.api.profiles.ConditionProfile; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; + +public final class LamaIfNode extends LamaExpressionNode { + @Child + private LamaExpressionNode conditionExpr; + + @Child + private LamaExpressionNode thenExpr; + + @Child + private LamaExpressionNode elseExpr; + + private final ConditionProfile condition = ConditionProfile.create(); + + @Override + public Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException { + if (this.condition.profile(this.conditionExpr.executeBoolean(frame))) { + return this.thenExpr.executeGeneric(frame); + } + return this.elseExpr; // TODO: cases with no else + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaWhileNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaWhileNode.java new file mode 100644 index 0000000..a5cbb9c --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/controlflow/LamaWhileNode.java @@ -0,0 +1,52 @@ +package org.programsnail.truffle_lama.nodes.controlflow; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RepeatingNode; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.runtime.LamaUnit; + +public final class LamaWhileNode extends LamaExpressionNode { + @SuppressWarnings("FieldMayBeFinal") + @Child + private LoopNode loopNode; + + public LamaWhileNode(LamaExpressionNode conditionExpr, LamaExpressionNode bodyExpr) { + this.loopNode = Truffle.getRuntime().createLoopNode( + new WhileRepeatingNode(conditionExpr, bodyExpr)); + } + + @Override + public Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException { + this.loopNode.execute(frame); + return LamaUnit.INSTANCE; + } + + private static final class WhileRepeatingNode extends Node implements RepeatingNode { + @SuppressWarnings("FieldMayBeFinal") + @Child + private LamaExpressionNode conditionExpr, bodyExpr; + + public WhileRepeatingNode(LamaExpressionNode conditionExpr, LamaExpressionNode bodyExpr) { + this.conditionExpr = conditionExpr; + this.bodyExpr = bodyExpr; + } + + @Override + public boolean executeRepeating(VirtualFrame frame) { + try { + if (!this.conditionExpr.executeBoolean(frame)) { + return false; + } + this.bodyExpr.executeGeneric(frame); + // NOTE: try/catch for break/continue + return false; + } catch (UnexpectedResultException e) { // TODO: handle in proper way + return false; + } + } + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaArrayNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaArrayNode.java new file mode 100644 index 0000000..49aebba --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaArrayNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaArrayNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaAssignNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaAssignNode.java new file mode 100644 index 0000000..fd4f635 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaAssignNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaAssignNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaBinopNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaBinopNode.java new file mode 100644 index 0000000..9f4b6fc --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaBinopNode.java @@ -0,0 +1,52 @@ +package org.programsnail.truffle_lama.nodes.expression; + +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.NodeField; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; + +@NodeChild("leftNode") +@NodeChild("rightNode") +@NodeField(name = "op", type = String.class) +public abstract class LamaBinopNode extends LamaExpressionNode { + @Child + LamaExpressionNode leftNode, rightNode; + + @Specialization(rewriteOn = IllegalStateException.class) + protected long numOp(long leftValue, long rightValue) { + return switch (op) { + case "+" -> leftValue + rightValue; + case "-" -> leftValue - rightValue; + case "/" -> leftValue / rightValue; + case "%" -> leftValue % rightValue; + default -> throw new IllegalStateException(); + }; + } + + @Specialization(replaces = "numOp") + protected boolean compOp(long leftValue, long rightValue) { + return switch (op) { + case "<" -> leftValue < rightValue; + case "<=" -> leftValue <= rightValue; + case ">" -> leftValue > rightValue; + case ">=" -> leftValue >= rightValue; + case "==" -> leftValue == rightValue; + case "!=" -> leftValue != rightValue; + default -> throw new IllegalStateException(); + }; + } + + @Specialization + protected boolean boolOp(boolean leftValue, boolean rightValue) { + return switch (op) { + case "&&" -> leftValue && rightValue; + case "!!" -> leftValue || rightValue; + default -> throw new IllegalStateException(); + }; + } + + String op; + +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaCallNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaCallNode.java new file mode 100644 index 0000000..5b08c22 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaCallNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaCallNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaConstNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaConstNode.java new file mode 100644 index 0000000..a78528d --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaConstNode.java @@ -0,0 +1,28 @@ +package org.programsnail.truffle_lama.nodes.expression; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; + +public final class LamaConstNode extends LamaExpressionNode { + private final int value; + + public LamaConstNode(int value) { + this.value = value; + } + + @Override + public Object executeGeneric(VirtualFrame frame) { + return this.executeLong(frame); + } + + @Override + public long executeLong(VirtualFrame frame) { + return value; + } + + @Override + public boolean executeBoolean(VirtualFrame frame) { + return value != 0; + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemNode.java new file mode 100644 index 0000000..d66c187 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaElemNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemRefNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemRefNode.java new file mode 100644 index 0000000..f1ea2af --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaElemRefNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaElemRefNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIgnoreNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIgnoreNode.java new file mode 100644 index 0000000..24d3d2f --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIgnoreNode.java @@ -0,0 +1,16 @@ +package org.programsnail.truffle_lama.nodes.expression; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.runtime.LamaUnit; + +public final class LamaIgnoreNode extends LamaExpressionNode { + @Child + LamaExpressionNode node; + + @Override + public Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException { + return LamaUnit.INSTANCE; + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIntrinsicNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIntrinsicNode.java new file mode 100644 index 0000000..c238188 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaIntrinsicNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaIntrinsicNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLambdaNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLambdaNode.java new file mode 100644 index 0000000..e0ab19d --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLambdaNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaLambdaNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLeaveNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLeaveNode.java new file mode 100644 index 0000000..1e67942 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaLeaveNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaLeaveNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaRefNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaRefNode.java new file mode 100644 index 0000000..be1db4b --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaRefNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaRefNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaScopeNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaScopeNode.java new file mode 100644 index 0000000..82c3ddb --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaScopeNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaScopeNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSeqNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSeqNode.java new file mode 100644 index 0000000..8ca6cec --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSeqNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaSeqNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSexpNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSexpNode.java new file mode 100644 index 0000000..d34765b --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSexpNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaSexpNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSkipNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSkipNode.java new file mode 100644 index 0000000..84b54bd --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaSkipNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaSkipNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaStringNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaStringNode.java new file mode 100644 index 0000000..a105695 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaStringNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaStringNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaUnitNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaUnitNode.java new file mode 100644 index 0000000..18205b1 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaUnitNode.java @@ -0,0 +1,13 @@ +package org.programsnail.truffle_lama.nodes.expression; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.UnexpectedResultException; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.runtime.LamaUnit; + +public final class LamaUnitNode extends LamaExpressionNode { + @Override + public Object executeGeneric(VirtualFrame frame) throws UnexpectedResultException { + return LamaUnit.INSTANCE; + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaVarNode.java b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaVarNode.java new file mode 100644 index 0000000..9955e13 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/nodes/expression/LamaVarNode.java @@ -0,0 +1,4 @@ +package org.programsnail.truffle_lama.nodes.expression; + +public class LamaVarNode { +} diff --git a/src/main/java/org/programsnail/truffle_lama/parser/Lama.g4 b/src/main/java/org/programsnail/truffle_lama/parser/Lama.g4 index 3b912d2..15fcdd8 100644 --- a/src/main/java/org/programsnail/truffle_lama/parser/Lama.g4 +++ b/src/main/java/org/programsnail/truffle_lama/parser/Lama.g4 @@ -40,7 +40,7 @@ */ /* - * The parser and lexer need to be generated using "mx create-sl-parser". + * The parser and lexer need to be generated using "mx create-lama-parser". ??? */ grammar Lama; @@ -58,7 +58,6 @@ import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import org.programsnail.truffle_lama.LamaLanguage; import org.programsnail.truffle_lama.nodes.LamaExpressionNode; -import org.programsnail.truffle_lama.nodes.LamaStatementNode; } @lexer::header @@ -91,11 +90,11 @@ private static void throwParseError(Source source, int line, int charPositionInL int col = charPositionInLine + 1; String location = "-- line " + line + " col " + col + ": "; int length = token == null ? 1 : Math.max(token.getStopIndex() - token.getStartIndex(), 0); - throw new SLParseError(source, line, col, length, String.format("Error(s) parsing script:%n" + location + message)); + throw new LamaParseError(source, line, col, length, String.format("Error(s) parsing script:%n" + location + message)); } -public static Map parseLama(LamaLanguage language, Source source) { - LamaLexer lexer = new LamamLexer(CharStreams.fromString(source.getCharacters().toString())); +public static LamaExpressionNode parseLama(LamaLanguage language, Source source) { + LamaLexer lexer = new LamaLexer(CharStreams.fromString(source.getCharacters().toString())); LamaParser parser = new LamaParser(new CommonTokenStream(lexer)); lexer.removeErrorListeners(); parser.removeErrorListeners(); @@ -105,7 +104,7 @@ public static Map parseLama(LamaLanguage language parser.factory = new LamaNodeFactory(language, source); parser.source = source; parser.lama(); - return parser.factory.getAllFunctions(); + return parser.factory.getRootExpr(); } } @@ -142,15 +141,15 @@ level : ('at' | 'before' | 'after') INFIX; // -expression returns [SLExpressionNode result]: basic_expression (';' expression)?; -basic_expression returns [SLExpressionNode result]: binary_expression; -binary_expression returns [SLExpressionNode result]: postfix_expression (INFIX postfix_expression)*; -postfix_expression returns [SLExpressionNode result]: ('-')? primary (postfix)*; +expression returns [LamaExpressionNode result]: basic_expression (';' expression)?; +basic_expression returns [LamaExpressionNode result]: binary_expression; +binary_expression returns [LamaExpressionNode result]: postfix_expression (INFIX postfix_expression)*; +postfix_expression returns [LamaExpressionNode result]: ('-')? primary (postfix)*; postfix : '(' expression (',' expression)* ')' | '[' expression ']'; -primary returns [SLExpressionNode result]: +primary returns [LamaExpressionNode result]: DECIMAL_LITERAL | STRING_LITERAL | CHAR_LITERAL diff --git a/src/main/java/org/programsnail/truffle_lama/parser/LamaLexer.java b/src/main/java/org/programsnail/truffle_lama/parser/LamaLexer.java index 54c19db..80bd59a 100644 --- a/src/main/java/org/programsnail/truffle_lama/parser/LamaLexer.java +++ b/src/main/java/org/programsnail/truffle_lama/parser/LamaLexer.java @@ -5,9 +5,12 @@ package org.programsnail.truffle_lama.parser; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class LamaLexer extends Lexer { diff --git a/src/main/java/org/programsnail/truffle_lama/parser/LamaNodeFactory.java b/src/main/java/org/programsnail/truffle_lama/parser/LamaNodeFactory.java new file mode 100644 index 0000000..44b43ec --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/parser/LamaNodeFactory.java @@ -0,0 +1,19 @@ +package org.programsnail.truffle_lama.parser; + +import com.oracle.truffle.api.source.Source; +import org.programsnail.truffle_lama.LamaLanguage; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; + +public class LamaNodeFactory { + public LamaNodeFactory(LamaLanguage language, Source source) { + // TODO + } + + public LamaExpressionNode getRootExpr() { + // TODO + return null; + } + + + // TODO: build expr tree from parsed tokens +} diff --git a/src/main/java/org/programsnail/truffle_lama/parser/LamaParseError.java b/src/main/java/org/programsnail/truffle_lama/parser/LamaParseError.java new file mode 100644 index 0000000..7356e93 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/parser/LamaParseError.java @@ -0,0 +1,54 @@ +package org.programsnail.truffle_lama.parser; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.exception.AbstractTruffleException; +import com.oracle.truffle.api.interop.ExceptionType; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; + +@ExportLibrary(InteropLibrary.class) +public class LamaParseError extends AbstractTruffleException { + + public static final long serialVersionUID = 1L; + private final Source source; + private final int line; + private final int column; + private final int length; + + public LamaParseError(Source source, int line, int column, int length, String message) { + super(message); + this.source = source; + this.line = line; + this.column = column; + this.length = length; + } + + /** + * Note that any subclass of {@link AbstractTruffleException} must always return + * true for {@link InteropLibrary#isException(Object)}. That is why it is correct + * to export {@link #getExceptionType()} without implementing + * {@link InteropLibrary#isException(Object)}. + */ + @ExportMessage + ExceptionType getExceptionType() { + return ExceptionType.PARSE_ERROR; + } + + @ExportMessage + boolean hasSourceLocation() { + return source != null; + } + + @ExportMessage(name = "getSourceLocation") + @CompilerDirectives.TruffleBoundary + SourceSection getSourceSection() throws UnsupportedMessageException { + if (source == null) { + throw UnsupportedMessageException.create(); + } + return source.createSection(line, column, length); + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/parser/LamaParser.java b/src/main/java/org/programsnail/truffle_lama/parser/LamaParser.java index 38a0a1d..a97dffc 100644 --- a/src/main/java/org/programsnail/truffle_lama/parser/LamaParser.java +++ b/src/main/java/org/programsnail/truffle_lama/parser/LamaParser.java @@ -3,6 +3,7 @@ package org.programsnail.truffle_lama.parser; // DO NOT MODIFY - generated from Lama.g4 +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -11,12 +12,15 @@ import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import org.programsnail.truffle_lama.LamaLanguage; import org.programsnail.truffle_lama.nodes.LamaExpressionNode; -import org.programsnail.truffle_lama.nodes.LamaStatementNode; import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; import org.antlr.v4.runtime.tree.*; +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) public class LamaParser extends Parser { @@ -153,11 +157,11 @@ public class LamaParser extends Parser { int col = charPositionInLine + 1; String location = "-- line " + line + " col " + col + ": "; int length = token == null ? 1 : Math.max(token.getStopIndex() - token.getStartIndex(), 0); - throw new SLParseError(source, line, col, length, String.format("Error(s) parsing script:%n" + location + message)); + throw new LamaParseError(source, line, col, length, String.format("Error(s) parsing script:%n" + location + message)); } - public static Map parseLama(LamaLanguage language, Source source) { - LamaLexer lexer = new LamamLexer(CharStreams.fromString(source.getCharacters().toString())); + public static LamaExpressionNode parseLama(LamaLanguage language, Source source) { + LamaLexer lexer = new LamaLexer(CharStreams.fromString(source.getCharacters().toString())); LamaParser parser = new LamaParser(new CommonTokenStream(lexer)); lexer.removeErrorListeners(); parser.removeErrorListeners(); @@ -167,7 +171,7 @@ public class LamaParser extends Parser { parser.factory = new LamaNodeFactory(language, source); parser.source = source; parser.lama(); - return parser.factory.getAllFunctions(); + return parser.factory.getRootExpr(); } public LamaParser(TokenStream input) { @@ -351,7 +355,7 @@ public class LamaParser extends Parser { setState(92); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,1,_ctx); - } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); + } while ( _alt!=2 && _alt!= ATN.INVALID_ALT_NUMBER ); setState(95); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { @@ -1057,7 +1061,7 @@ public class LamaParser extends Parser { @SuppressWarnings("CheckReturnValue") public static class ExpressionContext extends ParserRuleContext { - public SLExpressionNode result; + public LamaExpressionNode result; public Basic_expressionContext basic_expression() { return getRuleContext(Basic_expressionContext.class,0); } @@ -1119,7 +1123,7 @@ public class LamaParser extends Parser { @SuppressWarnings("CheckReturnValue") public static class Basic_expressionContext extends ParserRuleContext { - public SLExpressionNode result; + public LamaExpressionNode result; public Binary_expressionContext binary_expression() { return getRuleContext(Binary_expressionContext.class,0); } @@ -1165,7 +1169,7 @@ public class LamaParser extends Parser { @SuppressWarnings("CheckReturnValue") public static class Binary_expressionContext extends ParserRuleContext { - public SLExpressionNode result; + public LamaExpressionNode result; public List postfix_expression() { return getRuleContexts(Postfix_expressionContext.class); } @@ -1235,7 +1239,7 @@ public class LamaParser extends Parser { @SuppressWarnings("CheckReturnValue") public static class Postfix_expressionContext extends ParserRuleContext { - public SLExpressionNode result; + public LamaExpressionNode result; public PrimaryContext primary() { return getRuleContext(PrimaryContext.class,0); } @@ -1400,7 +1404,7 @@ public class LamaParser extends Parser { @SuppressWarnings("CheckReturnValue") public static class PrimaryContext extends ParserRuleContext { - public SLExpressionNode result; + public LamaExpressionNode result; public TerminalNode DECIMAL_LITERAL() { return getToken(LamaParser.DECIMAL_LITERAL, 0); } public TerminalNode STRING_LITERAL() { return getToken(LamaParser.STRING_LITERAL, 0); } public TerminalNode CHAR_LITERAL() { return getToken(LamaParser.CHAR_LITERAL, 0); } diff --git a/src/main/java/org/programsnail/truffle_lama/runtime/LamaException.java b/src/main/java/org/programsnail/truffle_lama/runtime/LamaException.java new file mode 100644 index 0000000..e9c94dc --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/runtime/LamaException.java @@ -0,0 +1,14 @@ +package org.programsnail.truffle_lama.runtime; + +import com.oracle.truffle.api.exception.AbstractTruffleException; +import com.oracle.truffle.api.nodes.Node; + +public class LamaException extends AbstractTruffleException { + public LamaException(String message) { + this(message, null); + } + + public LamaException(String message, Node location) { + super(message, location); + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/runtime/LamaSExp.java b/src/main/java/org/programsnail/truffle_lama/runtime/LamaSExp.java new file mode 100644 index 0000000..5e74c3d --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/runtime/LamaSExp.java @@ -0,0 +1,13 @@ +package org.programsnail.truffle_lama.runtime; + +import java.util.List; + +public final class LamaSExp { + public String name; + public List elements; + + LamaSExp(String name, List elements) { + this.name = name; + this.elements = elements; + } +} diff --git a/src/main/java/org/programsnail/truffle_lama/runtime/LamaUnit.java b/src/main/java/org/programsnail/truffle_lama/runtime/LamaUnit.java new file mode 100644 index 0000000..f29be38 --- /dev/null +++ b/src/main/java/org/programsnail/truffle_lama/runtime/LamaUnit.java @@ -0,0 +1,8 @@ +package org.programsnail.truffle_lama.runtime; + +// TODO: truffle object +public final class LamaUnit { + public static final LamaUnit INSTANCE = new LamaUnit(); + + private LamaUnit() { } +} diff --git a/src/test/java/BasicNodesTest.java b/src/test/java/BasicNodesTest.java new file mode 100644 index 0000000..c965872 --- /dev/null +++ b/src/test/java/BasicNodesTest.java @@ -0,0 +1,17 @@ +import com.oracle.truffle.api.CallTarget; + +import org.junit.Test; +import org.programsnail.truffle_lama.nodes.LamaExpressionNode; +import org.programsnail.truffle_lama.nodes.LamaRootNode; + +public class BasicNodesTest { + @Test + public void basic_test() { + LamaExpressionNode exprNode = null; // TODO + var rootNode = new LamaRootNode(exprNode); + CallTarget callTarget = rootNode.getCallTarget(); + var result = callTarget.call(); + + // TODO: check + } +}