mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-04 06:46:21 +00:00
Mangle bytecode method names according to declaration scope
This commit is contained in:
@@ -176,7 +176,7 @@ tasks.register("genTerrascriptAstClasses") {
|
||||
listOf(
|
||||
ASTNode("Expression", listOf("expression" to "Expr")),
|
||||
ASTNode("Block", listOf("statements" to "List<Stmt>")),
|
||||
ASTNode("FunctionDeclaration", listOf("identifier" to "String", "parameters" to "List<Pair<String, Type>>", "returnType" to "Type", "body" to "Block")),
|
||||
ASTNode("FunctionDeclaration", listOf("identifier" to "String", "parameters" to "List<Pair<String, Type>>", "returnType" to "Type", "body" to "Block"), listOf("symbol" to "Symbol.Function")),
|
||||
ASTNode("VariableDeclaration", listOf("type" to "Type", "identifier" to "String", "value" to "Expr")),
|
||||
ASTNode("Return", listOf("value" to "Expr"), listOf("type" to "Type")),
|
||||
ASTNode("If", listOf("condition" to "Expr", "trueBody" to "Block", "elseIfClauses" to "List<Pair<Expr, Block>>", "elseBody" to "Optional<Block>")),
|
||||
@@ -201,7 +201,7 @@ tasks.register("genTerrascriptAstClasses") {
|
||||
ASTNode("Grouping", listOf("expression" to "TypedExpr")),
|
||||
ASTNode("Literal", listOf("value" to "Object")),
|
||||
ASTNode("Unary", listOf("operator" to "UnaryOperator", "operand" to "TypedExpr")),
|
||||
ASTNode("Call", listOf("identifier" to "String", "arguments" to "List<TypedExpr>")),
|
||||
ASTNode("Call", listOf("identifier" to "String", "arguments" to "List<TypedExpr>", "scopedIdentifier" to "String")),
|
||||
ASTNode("Variable", listOf("identifier" to "String")),
|
||||
ASTNode("Assignment", listOf("lValue" to "Variable", "rValue" to "TypedExpr")),
|
||||
ASTNode("Void", listOf()),
|
||||
@@ -219,7 +219,7 @@ tasks.register("genTerrascriptAstClasses") {
|
||||
listOf(
|
||||
ASTNode("Expression", listOf("expression" to "TypedExpr")),
|
||||
ASTNode("Block", listOf("statements" to "List<TypedStmt>")),
|
||||
ASTNode("FunctionDeclaration", listOf("identifier" to "String", "parameters" to "List<Pair<String, Type>>", "returnType" to "Type", "body" to "Block")),
|
||||
ASTNode("FunctionDeclaration", listOf("identifier" to "String", "parameters" to "List<Pair<String, Type>>", "returnType" to "Type", "body" to "Block", "scopedIdentifier" to "String")),
|
||||
ASTNode("VariableDeclaration", listOf("type" to "Type", "identifier" to "String", "value" to "TypedExpr")),
|
||||
ASTNode("Return", listOf("value" to "TypedExpr")),
|
||||
ASTNode("If", listOf("condition" to "TypedExpr", "trueBody" to "Block", "elseIfClauses" to "List<Pair<TypedExpr, Block>>", "elseBody" to "Optional<Block>")),
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.dfsek.terra.addons.terrascript;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -31,33 +32,50 @@ public class Environment {
|
||||
|
||||
private final boolean inLoop;
|
||||
|
||||
private Environment(@Nullable Environment outer, boolean canAccessOuterVariables, boolean inLoop) {
|
||||
private final int index;
|
||||
|
||||
private int innerCount = 0;
|
||||
|
||||
public final String name;
|
||||
|
||||
private Environment(@Nullable Environment outer, boolean canAccessOuterVariables, boolean inLoop, int index) {
|
||||
this.outer = outer;
|
||||
this.canAccessOuterVariables = canAccessOuterVariables;
|
||||
this.inLoop = inLoop;
|
||||
this.index = index;
|
||||
this.name = String.join("_", getNestedIndexes().stream().map(Object::toString).toList());
|
||||
// Populate symbol tables with built-in Java implemented methods
|
||||
TerraScript.BUILTIN_FUNCTIONS.forEach((name, method) -> symbolTable
|
||||
.put(name,
|
||||
new Function(
|
||||
Type.from(method.getReturnType()).orElseThrow(() -> new RuntimeException("")),
|
||||
// Map Java classes to TerraScript types
|
||||
IntStream.range(0, method.getParameterCount()).mapToObj(i -> Pair.of("param" + i, Type.from(method.getParameterTypes()[i]).orElseThrow(() -> new RuntimeException("")))).toList())));
|
||||
IntStream.range(0, method.getParameterCount()).mapToObj(i -> Pair.of("param" + i, Type.from(method.getParameterTypes()[i]).orElseThrow(() -> new RuntimeException("")))).toList(),
|
||||
this)));
|
||||
}
|
||||
|
||||
public static Environment global() {
|
||||
return new Environment(null, false, false);
|
||||
return new Environment(null, false, false, 0);
|
||||
}
|
||||
|
||||
public Environment lexicalInner() {
|
||||
return new Environment(this, true, inLoop);
|
||||
return new Environment(this, true, inLoop, innerCount++);
|
||||
}
|
||||
|
||||
public Environment loopInner() {
|
||||
return new Environment(this, true, true);
|
||||
return new Environment(this, true, true, innerCount++);
|
||||
}
|
||||
|
||||
public Environment functionalInner() {
|
||||
return new Environment(this, false, inLoop);
|
||||
return new Environment(this, false, inLoop, innerCount++);
|
||||
}
|
||||
|
||||
private List<Integer> getNestedIndexes() {
|
||||
List<Integer> idxs = new ArrayList<>();
|
||||
for (Environment env = this; env.outer != null; env = env.outer) {
|
||||
idxs.add(0, env.index);
|
||||
}
|
||||
return idxs;
|
||||
}
|
||||
|
||||
public Environment outer() {
|
||||
@@ -117,9 +135,12 @@ public class Environment {
|
||||
|
||||
public final List<Pair<String, Type>> parameters;
|
||||
|
||||
public Function(Type type, List<Pair<String, Type>> parameters) {
|
||||
public final Environment scope;
|
||||
|
||||
public Function(Type type, List<Pair<String, Type>> parameters, Environment scope) {
|
||||
this.type = type;
|
||||
this.parameters = parameters;
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ public class TerraScriptClassGenerator {
|
||||
}
|
||||
expr.arguments.forEach(a -> a.accept(this));
|
||||
List<Type> parameters = expr.arguments.stream().map(e -> e.type).toList();
|
||||
method.visitMethodInsn(Opcodes.INVOKESTATIC, className, expr.identifier, getFunctionDescriptor(parameters, expr.type), false);
|
||||
method.visitMethodInsn(Opcodes.INVOKESTATIC, className, expr.scopedIdentifier, getFunctionDescriptor(parameters, expr.type), false);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -284,8 +284,8 @@ public class TerraScriptClassGenerator {
|
||||
List<Type> parameterTypes = stmt.parameters.stream().map(Pair::getRight).toList();
|
||||
|
||||
int access = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
|
||||
// TODO - Mangle identifier based on scope to avoid issues with using the same identifier in different scopes
|
||||
MethodVisitor method = classWriter.visitMethod(access, stmt.identifier, getFunctionDescriptor(parameterTypes, stmt.returnType), null, null);
|
||||
|
||||
MethodVisitor method = classWriter.visitMethod(access, stmt.scopedIdentifier, getFunctionDescriptor(parameterTypes, stmt.returnType), null, null);
|
||||
|
||||
method.visitCode(); // Start method body
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.dfsek.terra.addons.terrascript.semanticanalysis;
|
||||
import com.dfsek.terra.addons.terrascript.Environment;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.NonexistentSymbolException;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.SymbolTypeMismatchException;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.Symbol;
|
||||
import com.dfsek.terra.addons.terrascript.ErrorHandler;
|
||||
import com.dfsek.terra.addons.terrascript.Type;
|
||||
import com.dfsek.terra.addons.terrascript.ast.Expr;
|
||||
@@ -119,7 +120,9 @@ public class ScopeAnalyzer implements Visitor<Void>, Stmt.Visitor<Void> {
|
||||
stmt.body.accept(this);
|
||||
currentScope = currentScope.outer();
|
||||
try {
|
||||
currentScope.put(stmt.identifier, new Environment.Symbol.Function(stmt.returnType, stmt.parameters));
|
||||
Symbol.Function symbol = new Symbol.Function(stmt.returnType, stmt.parameters, currentScope);
|
||||
stmt.setSymbol(symbol);
|
||||
currentScope.put(stmt.identifier, symbol);
|
||||
} catch(Environment.ScopeException.SymbolAlreadyExistsException e) {
|
||||
errorHandler.add(new IdentifierAlreadyDeclaredException("Name '" + stmt.identifier + "' is already defined in this scope",
|
||||
stmt.position));
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.Environment;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.Symbol;
|
||||
import com.dfsek.terra.addons.terrascript.ErrorHandler;
|
||||
import com.dfsek.terra.addons.terrascript.Type;
|
||||
import com.dfsek.terra.addons.terrascript.ast.Expr.Assignment;
|
||||
@@ -33,6 +34,10 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
|
||||
|
||||
TypeChecker(ErrorHandler errorHandler) { this.errorHandler = errorHandler; }
|
||||
|
||||
private static String scopedIdentifier(String identifier, Symbol.Function symbol) {
|
||||
return identifier + "$" + symbol.scope.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedExpr visitBinaryExpr(Binary expr) {
|
||||
TypedExpr left = expr.left.accept(this);
|
||||
@@ -124,7 +129,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
|
||||
providedType + " instead", expr.position));
|
||||
}
|
||||
|
||||
return new TypedExpr.Call(expr.identifier, arguments, signature.type);
|
||||
return new TypedExpr.Call(expr.identifier, arguments, scopedIdentifier(expr.identifier, expr.getSymbol()), signature.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -179,7 +184,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
|
||||
new InvalidFunctionDeclarationException("Function body for '" + stmt.identifier + "' does not contain return statement",
|
||||
stmt.position));
|
||||
}
|
||||
return new TypedStmt.FunctionDeclaration(stmt.identifier, stmt.parameters, stmt.returnType, body);
|
||||
return new TypedStmt.FunctionDeclaration(stmt.identifier, stmt.parameters, stmt.returnType, body, scopedIdentifier(stmt.identifier, stmt.getSymbol()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -73,7 +73,10 @@ public class CodeGenTest {
|
||||
}
|
||||
|
||||
fun concatThree(a: str, b: str, c: str): str {
|
||||
return a + b + c;
|
||||
fun concatTwo(a: str, b: str): str {
|
||||
return a + b;
|
||||
}
|
||||
return concatTwo(a, b) + c;
|
||||
}
|
||||
|
||||
fun retStr(): str {
|
||||
|
||||
Reference in New Issue
Block a user