mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-10-26 14:00:14 +00:00
Mangle bytecode method names according to declaration scope
This commit is contained in:
1 parent
0a46e9050d
commit
defb31e309
6 files changed
+49
-17
No files matched your search
@@ -176,7 +176,7 @@ tasks.register("genTerrascriptAstClasses") {
|
|||||||
listOf(
|
listOf(
|
||||||
ASTNode("Expression", listOf("expression" to "Expr")),
|
ASTNode("Expression", listOf("expression" to "Expr")),
|
||||||
ASTNode("Block", listOf("statements" to "List<Stmt>")),
|
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("VariableDeclaration", listOf("type" to "Type", "identifier" to "String", "value" to "Expr")),
|
||||||
ASTNode("Return", listOf("value" to "Expr"), listOf("type" to "Type")),
|
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>")),
|
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("Grouping", listOf("expression" to "TypedExpr")),
|
||||||
ASTNode("Literal", listOf("value" to "Object")),
|
ASTNode("Literal", listOf("value" to "Object")),
|
||||||
ASTNode("Unary", listOf("operator" to "UnaryOperator", "operand" to "TypedExpr")),
|
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("Variable", listOf("identifier" to "String")),
|
||||||
ASTNode("Assignment", listOf("lValue" to "Variable", "rValue" to "TypedExpr")),
|
ASTNode("Assignment", listOf("lValue" to "Variable", "rValue" to "TypedExpr")),
|
||||||
ASTNode("Void", listOf()),
|
ASTNode("Void", listOf()),
|
||||||
@@ -219,7 +219,7 @@ tasks.register("genTerrascriptAstClasses") {
|
|||||||
listOf(
|
listOf(
|
||||||
ASTNode("Expression", listOf("expression" to "TypedExpr")),
|
ASTNode("Expression", listOf("expression" to "TypedExpr")),
|
||||||
ASTNode("Block", listOf("statements" to "List<TypedStmt>")),
|
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("VariableDeclaration", listOf("type" to "Type", "identifier" to "String", "value" to "TypedExpr")),
|
||||||
ASTNode("Return", listOf("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>")),
|
ASTNode("If", listOf("condition" to "TypedExpr", "trueBody" to "Block", "elseIfClauses" to "List<Pair<TypedExpr, Block>>", "elseBody" to "Optional<Block>")),
|
||||||
|
|||||||
+28
-7
@@ -3,6 +3,7 @@ package com.dfsek.terra.addons.terrascript;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -31,33 +32,50 @@ public class Environment {
|
|||||||
|
|
||||||
private final boolean inLoop;
|
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.outer = outer;
|
||||||
this.canAccessOuterVariables = canAccessOuterVariables;
|
this.canAccessOuterVariables = canAccessOuterVariables;
|
||||||
this.inLoop = inLoop;
|
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
|
// Populate symbol tables with built-in Java implemented methods
|
||||||
TerraScript.BUILTIN_FUNCTIONS.forEach((name, method) -> symbolTable
|
TerraScript.BUILTIN_FUNCTIONS.forEach((name, method) -> symbolTable
|
||||||
.put(name,
|
.put(name,
|
||||||
new Function(
|
new Function(
|
||||||
Type.from(method.getReturnType()).orElseThrow(() -> new RuntimeException("")),
|
Type.from(method.getReturnType()).orElseThrow(() -> new RuntimeException("")),
|
||||||
// Map Java classes to TerraScript types
|
// 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() {
|
public static Environment global() {
|
||||||
return new Environment(null, false, false);
|
return new Environment(null, false, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment lexicalInner() {
|
public Environment lexicalInner() {
|
||||||
return new Environment(this, true, inLoop);
|
return new Environment(this, true, inLoop, innerCount++);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment loopInner() {
|
public Environment loopInner() {
|
||||||
return new Environment(this, true, true);
|
return new Environment(this, true, true, innerCount++);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment functionalInner() {
|
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() {
|
public Environment outer() {
|
||||||
@@ -117,9 +135,12 @@ public class Environment {
|
|||||||
|
|
||||||
public final List<Pair<String, Type>> parameters;
|
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.type = type;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -228,7 +228,7 @@ public class TerraScriptClassGenerator {
|
|||||||
}
|
}
|
||||||
expr.arguments.forEach(a -> a.accept(this));
|
expr.arguments.forEach(a -> a.accept(this));
|
||||||
List<Type> parameters = expr.arguments.stream().map(e -> e.type).toList();
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,8 +284,8 @@ public class TerraScriptClassGenerator {
|
|||||||
List<Type> parameterTypes = stmt.parameters.stream().map(Pair::getRight).toList();
|
List<Type> parameterTypes = stmt.parameters.stream().map(Pair::getRight).toList();
|
||||||
|
|
||||||
int access = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
|
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
|
method.visitCode(); // Start method body
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -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;
|
||||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.NonexistentSymbolException;
|
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.ScopeException.SymbolTypeMismatchException;
|
||||||
|
import com.dfsek.terra.addons.terrascript.Environment.Symbol;
|
||||||
import com.dfsek.terra.addons.terrascript.ErrorHandler;
|
import com.dfsek.terra.addons.terrascript.ErrorHandler;
|
||||||
import com.dfsek.terra.addons.terrascript.Type;
|
import com.dfsek.terra.addons.terrascript.Type;
|
||||||
import com.dfsek.terra.addons.terrascript.ast.Expr;
|
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);
|
stmt.body.accept(this);
|
||||||
currentScope = currentScope.outer();
|
currentScope = currentScope.outer();
|
||||||
try {
|
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) {
|
} catch(Environment.ScopeException.SymbolAlreadyExistsException e) {
|
||||||
errorHandler.add(new IdentifierAlreadyDeclaredException("Name '" + stmt.identifier + "' is already defined in this scope",
|
errorHandler.add(new IdentifierAlreadyDeclaredException("Name '" + stmt.identifier + "' is already defined in this scope",
|
||||||
stmt.position));
|
stmt.position));
|
||||||
|
|||||||
+7
-2
@@ -5,6 +5,7 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import com.dfsek.terra.addons.terrascript.Environment;
|
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.ErrorHandler;
|
||||||
import com.dfsek.terra.addons.terrascript.Type;
|
import com.dfsek.terra.addons.terrascript.Type;
|
||||||
import com.dfsek.terra.addons.terrascript.ast.Expr.Assignment;
|
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; }
|
TypeChecker(ErrorHandler errorHandler) { this.errorHandler = errorHandler; }
|
||||||
|
|
||||||
|
private static String scopedIdentifier(String identifier, Symbol.Function symbol) {
|
||||||
|
return identifier + "$" + symbol.scope.name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypedExpr visitBinaryExpr(Binary expr) {
|
public TypedExpr visitBinaryExpr(Binary expr) {
|
||||||
TypedExpr left = expr.left.accept(this);
|
TypedExpr left = expr.left.accept(this);
|
||||||
@@ -124,7 +129,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
|
|||||||
providedType + " instead", expr.position));
|
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
|
@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",
|
new InvalidFunctionDeclarationException("Function body for '" + stmt.identifier + "' does not contain return statement",
|
||||||
stmt.position));
|
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
|
@Override
|
||||||
|
|||||||
@@ -73,7 +73,10 @@ public class CodeGenTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun concatThree(a: str, b: str, c: str): str {
|
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 {
|
fun retStr(): str {
|
||||||
|
|||||||
Reference in new issue
Block a user