The Truffle Framework is an open-source library for building programming language implementations as interpreters for self-modifying Abstract Syntax Trees (ASTs). When combined with the GraalVM compiler, Truffle can provide high-performance execution of guest languages on the Java Virtual Machine.
Truffle Architecture Overview
Guest Language → Truffle Parser → AST Interpreter → Graal JIT → Native Code ↓ Language Implementation ↓ Polyglot Programming
Core Dependencies
<!-- pom.xml --> <properties> <graalvm.version>23.0.0</graalvm.version> <truffle.version>23.0.0</truffle.version> </properties> <dependencies> <!-- Truffle API --> <dependency> <groupId>org.graalvm.truffle</groupId> <artifactId>truffle-api</artifactId> <version>${truffle.version}</version> </dependency> <dependency> <groupId>org.graalvm.truffle</groupId> <artifactId>truffle-dsl-processor</artifactId> <version>${truffle.version}</version> <scope>provided</scope> </dependency> <!-- GraalVM SDK --> <dependency> <groupId>org.graalvm.sdk</groupId> <artifactId>graal-sdk</artifactId> <version>${graalvm.version}</version> </dependency> <!-- JSON for configuration --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.0</version> </dependency> </dependencies> Basic Language Implementation Structure
Language Registration
package com.example.tinylang; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; @TruffleLanguage.Registration( id = "tinylang", name = "Tiny Language", defaultMimeType = TinyLanguage.MIME_TYPE, characterMimeTypes = TinyLanguage.MIME_TYPE, contextPolicy = TruffleLanguage.ContextPolicy.SHARED ) public class TinyLanguage extends TruffleLanguage<TinyLanguageContext> { public static final String MIME_TYPE = "application/x-tinylang"; @Override protected TinyLanguageContext createContext(Env env) { return new TinyLanguageContext(env); } @Override protected CallTarget parse(ParsingRequest request) throws Exception { Source source = request.getSource(); Node rootNode = new TinyLanguageParser().parse(this, source); return Truffle.getRuntime().createCallTarget(rootNode); } @Override protected boolean isObjectOfLanguage(Object object) { return false; } } // Language Context class TinyLanguageContext { private final Env env; private final GlobalScope globalScope; public TinyLanguageContext(Env env) { this.env = env; this.globalScope = new GlobalScope(); } public Env getEnv() { return env; } public GlobalScope getGlobalScope() { return globalScope; } } // Global Scope for variables class GlobalScope { private final Map<String, Object> variables = new HashMap<>(); public void defineVariable(String name, Object value) { variables.put(name, value); } public Object getVariable(String name) { return variables.get(name); } public boolean hasVariable(String name) { return variables.containsKey(name); } } AST Node Foundation
Base Node Classes
package com.example.tinylang.nodes; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; // Base class for all expression nodes public abstract class ExpressionNode extends Node { public abstract Object executeGeneric(VirtualFrame frame); public long executeLong(VirtualFrame frame) throws UnexpectedResultException { Object value = executeGeneric(frame); if (value instanceof Long) { return (Long) value; } throw new UnexpectedResultException(value); } public double executeDouble(VirtualFrame frame) throws UnexpectedResultException { Object value = executeGeneric(frame); if (value instanceof Double) { return (Double) value; } throw new UnexpectedResultException(value); } public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException { Object value = executeGeneric(frame); if (value instanceof Boolean) { return (Boolean) value; } throw new UnexpectedResultException(value); } } // Base class for statement nodes public abstract class StatementNode extends Node { public abstract void executeVoid(VirtualFrame frame); } // Root node of the AST @NodeInfo(language = "Tiny Language", description = "The root of Tiny Language AST") public class TinyLanguageRootNode extends ExpressionNode { @Child private ExpressionNode body; private final TinyLanguage language; public TinyLanguageRootNode(TinyLanguage language, ExpressionNode body) { this.language = language; this.body = body; } @Override public Object executeGeneric(VirtualFrame frame) { return body.executeGeneric(frame); } } Expression Nodes
Literal Nodes
package com.example.tinylang.nodes.expressions; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; // Integer literal node @NodeInfo(description = "Integer literal") public abstract class IntLiteralNode extends ExpressionNode { private final long value; public IntLiteralNode(long value) { this.value = value; } @Specialization public long executeLong() { return value; } @Override public Object executeGeneric(VirtualFrame frame) { return executeLong(frame); } } // Double literal node @NodeInfo(description = "Double literal") public abstract class DoubleLiteralNode extends ExpressionNode { private final double value; public DoubleLiteralNode(double value) { this.value = value; } @Specialization public double executeDouble() { return value; } @Override public Object executeGeneric(VirtualFrame frame) { return executeDouble(frame); } } // String literal node @NodeInfo(description = "String literal") public abstract class StringLiteralNode extends ExpressionNode { private final String value; public StringLiteralNode(String value) { this.value = value; } @Specialization public String executeString() { return value; } @Override public Object executeGeneric(VirtualFrame frame) { return executeString(); } } // Boolean literal node @NodeInfo(description = "Boolean literal") public abstract class BooleanLiteralNode extends ExpressionNode { private final boolean value; public BooleanLiteralNode(boolean value) { this.value = value; } @Specialization public boolean executeBoolean() { return value; } @Override public Object executeGeneric(VirtualFrame frame) { return executeBoolean(); } } Arithmetic Operation Nodes
package com.example.tinylang.nodes.expressions; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChildren; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; // Addition node @NodeInfo(description = "Addition operation") @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class AddNode extends ExpressionNode { @Specialization(rewriteOn = ArithmeticException.class) protected long addLong(long left, long right) { return Math.addExact(left, right); } @Specialization protected double addDouble(double left, double right) { return left + right; } @Specialization protected String addString(String left, String right) { return left + right; } @Fallback protected Object addGeneric(Object left, Object right) { return left.toString() + right.toString(); } } // Subtraction node @NodeInfo(description = "Subtraction operation") @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class SubtractNode extends ExpressionNode { @Specialization(rewriteOn = ArithmeticException.class) protected long subtractLong(long left, long right) { return Math.subtractExact(left, right); } @Specialization protected double subtractDouble(double left, double right) { return left - right; } @Fallback protected Object subtractGeneric(Object left, Object right) { throw new UnsupportedOperationException("Cannot subtract non-numeric values"); } } // Multiplication node @NodeInfo(description = "Multiplication operation") @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class MultiplyNode extends ExpressionNode { @Specialization(rewriteOn = ArithmeticException.class) protected long multiplyLong(long left, long right) { return Math.multiplyExact(left, right); } @Specialization protected double multiplyDouble(double left, double right) { return left * right; } @Fallback protected Object multiplyGeneric(Object left, Object right) { throw new UnsupportedOperationException("Cannot multiply non-numeric values"); } } // Division node @NodeInfo(description = "Division operation") @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class DivideNode extends ExpressionNode { @Specialization protected long divideLong(long left, long right) { return left / right; } @Specialization protected double divideDouble(double left, double right) { return left / right; } @Fallback protected Object divideGeneric(Object left, Object right) { throw new UnsupportedOperationException("Cannot divide non-numeric values"); } } Comparison and Logical Nodes
package com.example.tinylang.nodes.expressions; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChildren; import com.oracle.truffle.api.dsl.Specialization; // Equal comparison @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class EqualNode extends ExpressionNode { @Specialization protected boolean equalLong(long left, long right) { return left == right; } @Specialization protected boolean equalDouble(double left, double right) { return left == right; } @Specialization protected boolean equalBoolean(boolean left, boolean right) { return left == right; } @Specialization protected boolean equalString(String left, String right) { return left.equals(right); } @Specialization protected boolean equalObject(Object left, Object right) { return left.equals(right); } } // Less than comparison @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class LessThanNode extends ExpressionNode { @Specialization protected boolean lessThanLong(long left, long right) { return left < right; } @Specialization protected boolean lessThanDouble(double left, double right) { return left < right; } @Specialization protected boolean lessThanString(String left, String right) { return left.compareTo(right) < 0; } } // Logical AND node @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class LogicalAndNode extends ExpressionNode { @Specialization protected boolean logicalAnd(boolean left, boolean right) { return left && right; } } // Logical OR node @NodeChildren({@NodeChild("left"), @NodeChild("right")}) public abstract class LogicalOrNode extends ExpressionNode { @Specialization protected boolean logicalOr(boolean left, boolean right) { return left || right; } } // Logical NOT node @NodeChild("operand") public abstract class LogicalNotNode extends ExpressionNode { @Specialization protected boolean logicalNot(boolean operand) { return !operand; } } Variable and Scope Nodes
package com.example.tinylang.nodes; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.NodeField; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.VirtualFrame; // Read variable node @NodeInfo(description = "Read variable") @NodeField(name = "slot", type = FrameSlot.class) public abstract class ReadVariableNode extends ExpressionNode { protected abstract FrameSlot getSlot(); @Specialization(guards = "isLong(frame)") protected long readLong(VirtualFrame frame) { return frame.getLong(getSlot()); } @Specialization(guards = "isDouble(frame)") protected double readDouble(VirtualFrame frame) { return frame.getDouble(getSlot()); } @Specialization(guards = "isBoolean(frame)") protected boolean readBoolean(VirtualFrame frame) { return frame.getBoolean(getSlot()); } @Specialization(replaces = {"readLong", "readDouble", "readBoolean"}) protected Object readObject(VirtualFrame frame) { if (!frame.isObject(getSlot())) { CompilerDirectives.transferToInterpreter(); Object result = frame.getValue(getSlot()); frame.setObject(getSlot(), result); return result; } return frame.getObject(getSlot()); } protected boolean isLong(VirtualFrame frame) { return frame.getFrameDescriptor().getFrameSlotKind(getSlot()) == FrameSlotKind.Long; } protected boolean isDouble(VirtualFrame frame) { return frame.getFrameDescriptor().getFrameSlotKind(getSlot()) == FrameSlotKind.Double; } protected boolean isBoolean(VirtualFrame frame) { return frame.getFrameDescriptor().getFrameSlotKind(getSlot()) == FrameSlotKind.Boolean; } } // Write variable node @NodeInfo(description = "Write variable") @NodeField(name = "slot", type = FrameSlot.class) public abstract class WriteVariableNode extends StatementNode { @Child private ExpressionNode valueNode; protected abstract FrameSlot getSlot(); public WriteVariableNode(ExpressionNode valueNode) { this.valueNode = valueNode; } @Specialization(guards = "isLong(value)") protected void writeLong(VirtualFrame frame, long value) { frame.setLong(getSlot(), value); updateSlotKind(frame, FrameSlotKind.Long); } @Specialization(guards = "isDouble(value)") protected void writeDouble(VirtualFrame frame, double value) { frame.setDouble(getSlot(), value); updateSlotKind(frame, FrameSlotKind.Double); } @Specialization(guards = "isBoolean(value)") protected void writeBoolean(VirtualFrame frame, boolean value) { frame.setBoolean(getSlot(), value); updateSlotKind(frame, FrameSlotKind.Boolean); } @Specialization(replaces = {"writeLong", "writeDouble", "writeBoolean"}) protected void writeObject(VirtualFrame frame, Object value) { frame.setObject(getSlot(), value); updateSlotKind(frame, FrameSlotKind.Object); } private void updateSlotKind(VirtualFrame frame, FrameSlotKind kind) { if (frame.getFrameDescriptor().getFrameSlotKind(getSlot()) != kind) { CompilerDirectives.transferToInterpreter(); frame.getFrameDescriptor().setFrameSlotKind(getSlot(), kind); } } protected boolean isLong(Object value) { return value instanceof Long; } protected boolean isDouble(Object value) { return value instanceof Double; } protected boolean isBoolean(Object value) { return value instanceof Boolean; } @Override public void executeVoid(VirtualFrame frame) { Object value = valueNode.executeGeneric(frame); executeWrite(frame, value); } protected abstract void executeWrite(VirtualFrame frame, Object value); } Control Flow Nodes
package com.example.tinylang.nodes.control; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.NodeChildren; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; // If-Then-Else node @NodeInfo(description = "If-then-else statement") @NodeChildren({ @NodeChild("condition"), @NodeChild("thenBranch"), @NodeChild("elseBranch") }) public abstract class IfNode extends ExpressionNode { @Specialization protected Object executeIf(boolean condition, Object thenValue, Object elseValue) { return condition ? thenValue : elseValue; } } // While loop node @NodeInfo(description = "While loop") @NodeChildren({ @NodeChild("condition"), @NodeChild("body") }) public abstract class WhileNode extends StatementNode { @Specialization protected void executeWhile(VirtualFrame frame, boolean condition, StatementNode body) { while (condition) { body.executeVoid(frame); // Re-evaluate condition condition = ((ExpressionNode) getCondition()).executeBoolean(frame); } } protected abstract Node getCondition(); protected abstract Node getBody(); } // Block node for statement sequences @NodeInfo(description = "Block of statements") public class BlockNode extends StatementNode { @Children private final StatementNode[] statements; public BlockNode(StatementNode[] statements) { this.statements = statements; } @Override public void executeVoid(VirtualFrame frame) { for (StatementNode statement : statements) { statement.executeVoid(frame); } } } // Function call node @NodeInfo(description = "Function call") public abstract class FunctionCallNode extends ExpressionNode { private final String functionName; @Children private final ExpressionNode[] argumentNodes; public FunctionCallNode(String functionName, ExpressionNode[] argumentNodes) { this.functionName = functionName; this.argumentNodes = argumentNodes; } @Specialization protected Object executeCall(VirtualFrame frame) { // Look up function in global scope Object function = getContext().getGlobalScope().getVariable(functionName); if (function instanceof Callable) { Object[] arguments = new Object[argumentNodes.length]; for (int i = 0; i < argumentNodes.length; i++) { arguments[i] = argumentNodes[i].executeGeneric(frame); } return ((Callable) function).call(arguments); } throw new RuntimeException("Function not found: " + functionName); } private TinyLanguageContext getContext() { return lookupContextReference(TinyLanguageContext.class).get(); } } Built-in Functions
package com.example.tinylang.builtins; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.NodeInfo; // Print function @NodeInfo(description = "Print built-in function") public abstract class PrintFunction extends BuiltinFunction { @Specialization public Object print(Object value) { System.out.println(value); return value; } } // Length function for strings and arrays @NodeInfo(description = "Length built-in function") public abstract class LengthFunction extends BuiltinFunction { @Specialization public long length(String str) { return str.length(); } @Specialization public long length(Object[] array) { return array.length; } } // Type conversion functions @NodeInfo(description = "To string built-in function") public abstract class ToStringFunction extends BuiltinFunction { @Specialization public String toString(Object value) { return String.valueOf(value); } } @NodeInfo(description = "To number built-in function") public abstract class ToNumberFunction extends BuiltinFunction { @Specialization public double toNumber(String str) { try { return Double.parseDouble(str); } catch (NumberFormatException e) { return 0.0; } } @Specialization public double toNumber(boolean bool) { return bool ? 1.0 : 0.0; } @Specialization public double toNumber(Object obj) { return 0.0; } } // Base class for built-in functions public abstract class BuiltinFunction { public abstract Object call(Object[] arguments); protected void checkArgumentCount(Object[] arguments, int expected) { if (arguments.length != expected) { throw new RuntimeException("Expected " + expected + " arguments, got " + arguments.length); } } } Parser Implementation
package com.example.tinylang.parser; import com.example.tinylang.TinyLanguage; import com.example.tinylang.nodes.*; import com.example.tinylang.nodes.expressions.*; import com.example.tinylang.nodes.control.*; import com.oracle.truffle.api.source.Source; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTree; import java.util.ArrayList; import java.util.List; public class TinyLanguageParser { public ExpressionNode parse(TinyLanguage language, Source source) { try { String code = source.getCharacters().toString(); TinyLanguageLexer lexer = new TinyLanguageLexer(CharStreams.fromString(code)); TinyLanguageParser parser = new TinyLanguageParser(new CommonTokenStream(lexer)); ParseTree tree = parser.program(); TinyLanguageVisitor visitor = new TinyLanguageVisitor(language); return visitor.visit(tree); } catch (Exception e) { throw new RuntimeException("Parse error: " + e.getMessage(), e); } } } // ANTLR Visitor for AST construction class TinyLanguageVisitor extends TinyLanguageBaseVisitor<ExpressionNode> { private final TinyLanguage language; public TinyLanguageVisitor(TinyLanguage language) { this.language = language; } @Override public ExpressionNode visitIntLiteral(TinyLanguageParser.IntLiteralContext ctx) { long value = Long.parseLong(ctx.INT().getText()); return new IntLiteralNode(value); } @Override public ExpressionNode visitDoubleLiteral(TinyLanguageParser.DoubleLiteralContext ctx) { double value = Double.parseDouble(ctx.DOUBLE().getText()); return new DoubleLiteralNode(value); } @Override public ExpressionNode visitStringLiteral(TinyLanguageParser.StringLiteralContext ctx) { String text = ctx.STRING().getText(); // Remove quotes String value = text.substring(1, text.length() - 1); return new StringLiteralNode(value); } @Override public ExpressionNode visitAddSub(TinyLanguageParser.AddSubContext ctx) { ExpressionNode left = visit(ctx.expression(0)); ExpressionNode right = visit(ctx.expression(1)); if (ctx.op.getType() == TinyLanguageParser.ADD) { return AddNodeGen.create(left, right); } else { return SubtractNodeGen.create(left, right); } } @Override public ExpressionNode visitMulDiv(TinyLanguageParser.MulDivContext ctx) { ExpressionNode left = visit(ctx.expression(0)); ExpressionNode right = visit(ctx.expression(1)); if (ctx.op.getType() == TinyLanguageParser.MUL) { return MultiplyNodeGen.create(left, right); } else { return DivideNodeGen.create(left, right); } } @Override public ExpressionNode visitParens(TinyLanguageParser.ParensContext ctx) { return visit(ctx.expression()); } @Override public ExpressionNode visitComparison(TinyLanguageParser.ComparisonContext ctx) { ExpressionNode left = visit(ctx.expression(0)); ExpressionNode right = visit(ctx.expression(1)); switch (ctx.op.getType()) { case TinyLanguageParser.EQUAL: return EqualNodeGen.create(left, right); case TinyLanguageParser.LESS: return LessThanNodeGen.create(left, right); default: throw new UnsupportedOperationException("Unknown comparison operator"); } } @Override public ExpressionNode visitLogicalAnd(TinyLanguageParser.LogicalAndContext ctx) { ExpressionNode left = visit(ctx.expression(0)); ExpressionNode right = visit(ctx.expression(1)); return LogicalAndNodeGen.create(left, right); } @Override public ExpressionNode visitLogicalOr(TinyLanguageParser.LogicalOrContext ctx) { ExpressionNode left = visit(ctx.expression(0)); ExpressionNode right = visit(ctx.expression(1)); return LogicalOrNodeGen.create(left, right); } @Override public ExpressionNode visitIfExpression(TinyLanguageParser.IfExpressionContext ctx) { ExpressionNode condition = visit(ctx.expression(0)); ExpressionNode thenBranch = visit(ctx.expression(1)); ExpressionNode elseBranch = visit(ctx.expression(2)); return IfNodeGen.create(condition, thenBranch, elseBranch); } @Override public ExpressionNode visitFunctionCall(TinyLanguageParser.FunctionCallContext ctx) { String functionName = ctx.ID().getText(); List<ExpressionNode> arguments = new ArrayList<>(); if (ctx.expressionList() != null) { for (TinyLanguageParser.ExpressionContext argCtx : ctx.expressionList().expression()) { arguments.add(visit(argCtx)); } } return new FunctionCallNode(functionName, arguments.toArray(new ExpressionNode[0])); } } Language Interoperability
Polyglot Integration
package com.example.tinylang.interop; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; // Tiny Language array for interop @ExportLibrary(InteropLibrary.class) public class TinyLanguageArray implements TruffleObject { private final Object[] elements; public TinyLanguageArray(Object[] elements) { this.elements = elements; } @ExportMessage boolean hasArrayElements() { return true; } @ExportMessage long getArraySize() { return elements.length; } @ExportMessage boolean isArrayElementReadable(long index) { return index >= 0 && index < elements.length; } @ExportMessage Object readArrayElement(long index) throws UnsupportedMessageException { if (!isArrayElementReadable(index)) { throw UnsupportedMessageException.create(); } return elements[(int) index]; } } // Foreign function interface public class TinyLanguageFFI { private final InteropLibrary interop = InteropLibrary.getFactory().createDispatched(3); public Object callForeignFunction(Object function, Object... arguments) { try { if (interop.isExecutable(function)) { return interop.execute(function, arguments); } throw new RuntimeException("Object is not executable"); } catch (UnsupportedMessageException e) { throw new RuntimeException("Failed to execute foreign function", e); } } public Object importFromJS(String code) { try { Context context = Context.getCurrent(); return context.eval("js", code); } catch (Exception e) { throw new RuntimeException("Failed to import from JavaScript", e); } } public Object importFromPython(String code) { try { Context context = Context.getCurrent(); return context.eval("python", code); } catch (Exception e) { throw new RuntimeException("Failed to import from Python", e); } } } Performance Optimization
Specialization and Caching
package com.example.tinylang.nodes.optimized; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; // Optimized function call with caching public abstract class OptimizedFunctionCallNode extends ExpressionNode { private final String functionName; @Children private final ExpressionNode[] argumentNodes; public OptimizedFunctionCallNode(String functionName, ExpressionNode[] argumentNodes) { this.functionName = functionName; this.argumentNodes = argumentNodes; } @Specialization(limit = "3") protected Object executeCached(VirtualFrame frame, @Cached("createBinaryProfile()") ConditionProfile profile) { Object function = lookupFunction(); if (profile.profile(function instanceof BuiltinFunction)) { Object[] arguments = evaluateArguments(frame); return ((BuiltinFunction) function).call(arguments); } CompilerDirectives.transferToInterpreter(); throw new RuntimeException("Function not found: " + functionName); } private Object lookupFunction() { return getContext().getGlobalScope().getVariable(functionName); } private Object[] evaluateArguments(VirtualFrame frame) { Object[] arguments = new Object[argumentNodes.length]; for (int i = 0; i < argumentNodes.length; i++) { arguments[i] = argumentNodes[i].executeGeneric(frame); } return arguments; } private TinyLanguageContext getContext() { return lookupContextReference(TinyLanguageContext.class).get(); } } Testing Framework
package com.example.tinylang.test; import com.example.tinylang.TinyLanguage; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; class TinyLanguageTest { @Test void testArithmeticOperations() { String code = """ 2 + 3 * 4 """; Object result = execute(code); assertEquals(14L, result); } @Test void testStringConcatenation() { String code = """ "Hello, " + "World!" """; Object result = execute(code); assertEquals("Hello, World!", result); } @Test void testIfExpression() { String code = """ if (5 > 3) then "yes" else "no" """; Object result = execute(code); assertEquals("yes", result); } @Test void testFunctionCalls() { String code = """ print("Testing") length("hello") """; Object result = execute(code); assertEquals(5L, result); } private Object execute(String code) { try (Context context = Context.newBuilder() .allowAllAccess(true) .build()) { Value result = context.eval("tinylang", code); return result.as(Object.class); } } } // Benchmark tests class TinyLanguageBenchmark { @Test void benchmarkFibonacci() { String fibonacciCode = """ let fib = fn(n) { if (n < 2) then n else fib(n - 1) + fib(n - 2) }; fib(20) """; long startTime = System.nanoTime(); Object result = execute(fibonacciCode); long endTime = System.nanoTime(); assertEquals(6765L, result); System.out.printf("Fibonacci(20) executed in: %.2f ms%n", (endTime - startTime) / 1_000_000.0); } private Object execute(String code) { // Implementation same as above return null; } } Deployment and Integration
Maven Build Configuration
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> <compilerArgs> <arg>-Agraal.Dump=</arg> <arg>-Agraal.PrintGraph=Network</arg> </compilerArgs> </configuration> </plugin> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>0.9.22</version> <extensions>true</extensions> <executions> <execution> <id>build-native</id> <goals> <goal>build</goal> </goals> <phase>package</phase> </execution> </executions> </plugin> </plugins> </build>
Language Distribution
// Service provider configuration // META-INF/services/com.oracle.truffle.api.TruffleLanguage com.example.tinylang.TinyLanguage // Language configuration public class TinyLanguageConfig { public static void main(String[] args) { try (Context context = Context.newBuilder() .allowAllAccess(true) .option("tinylang.Home", System.getProperty("user.dir")) .build()) { // Execute Tiny Language code Value result = context.eval("tinylang", "1 + 2 * 3"); System.out.println("Result: " + result.asInt()); } } } This comprehensive Truffle Framework implementation demonstrates how to build a complete language from scratch, including parsing, AST construction, node specialization, built-in functions, interoperability, and performance optimization. The framework enables high-performance language implementations that can leverage GraalVM's JIT compilation for near-native performance.