mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-04 06:46:21 +00:00
Remove hardcoded print native java call
This commit is contained in:
@@ -1,25 +1,17 @@
|
||||
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;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.NonexistentSymbolException;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.SymbolAlreadyExistsException;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.ScopeException.SymbolTypeMismatchException;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.Symbol.Function;
|
||||
import com.dfsek.terra.addons.terrascript.Environment.Symbol.Variable;
|
||||
import com.dfsek.terra.addons.terrascript.codegen.TerraScript;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
import com.dfsek.terra.addons.terrascript.codegen.NativeFunction;
|
||||
|
||||
|
||||
public class Environment {
|
||||
@@ -45,13 +37,7 @@ public class Environment {
|
||||
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(),
|
||||
this)));
|
||||
NativeFunction.BUILTIN_FUNCTIONS.forEach((name, function) -> symbolTable.put(name, new Symbol.Function(function.getReturnType(), function.getParameterTypes(), this)));
|
||||
}
|
||||
|
||||
public static Environment global() {
|
||||
@@ -133,11 +119,11 @@ public class Environment {
|
||||
|
||||
public final Type type;
|
||||
|
||||
public final List<Pair<String, Type>> parameters;
|
||||
public final List<Type> parameters;
|
||||
|
||||
public final Environment scope;
|
||||
|
||||
public Function(Type type, List<Pair<String, Type>> parameters, Environment scope) {
|
||||
public Function(Type type, List<Type> parameters, Environment scope) {
|
||||
this.type = type;
|
||||
this.parameters = parameters;
|
||||
this.scope = scope;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.dfsek.terra.addons.terrascript.codegen;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.Type;
|
||||
|
||||
|
||||
public interface NativeFunction {
|
||||
Map<String, NativeFunction> BUILTIN_FUNCTIONS = new HashMap<>() {{
|
||||
put("print", new StaticMethodOfStaticField(
|
||||
"java/lang/System",
|
||||
"out",
|
||||
"java/io/PrintStream",
|
||||
"println",
|
||||
"(Ljava/lang/String;)V",
|
||||
Type.VOID,
|
||||
List.of(Type.STRING))
|
||||
);
|
||||
put("printNum", new StaticMethodOfStaticField(
|
||||
"java/lang/System",
|
||||
"out",
|
||||
"java/io/PrintStream",
|
||||
"println",
|
||||
"(D)V",
|
||||
Type.VOID,
|
||||
List.of(Type.NUMBER))
|
||||
);
|
||||
}};
|
||||
|
||||
void pushInstance(MethodVisitor method);
|
||||
|
||||
void callMethod(MethodVisitor method);
|
||||
|
||||
Type getReturnType();
|
||||
|
||||
List<Type> getParameterTypes();
|
||||
|
||||
class StaticMethodOfStaticField implements NativeFunction {
|
||||
|
||||
private final String fieldOwner;
|
||||
private final String fieldName;
|
||||
private final String className;
|
||||
private final String methodName;
|
||||
private final String methodDescriptor;
|
||||
private final Type returnType;
|
||||
private final List<Type> parameters;
|
||||
|
||||
// TODO - Use reflection to obtain these automatically
|
||||
public StaticMethodOfStaticField(String fieldOwner, String fieldName, String className, String methodName, String methodDescriptor,
|
||||
Type returnType, List<Type> parameters) {
|
||||
this.fieldOwner = fieldOwner;
|
||||
this.fieldName = fieldName;
|
||||
this.className = className;
|
||||
this.methodName = methodName;
|
||||
this.methodDescriptor = methodDescriptor;
|
||||
this.returnType = returnType;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushInstance(MethodVisitor method) {
|
||||
method.visitFieldInsn(Opcodes.GETSTATIC, fieldOwner, fieldName, "L" + className + ";");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callMethod(MethodVisitor method) {
|
||||
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName, methodDescriptor, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Type> getParameterTypes() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,8 @@
|
||||
package com.dfsek.terra.addons.terrascript.codegen;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public interface TerraScript {
|
||||
|
||||
void execute();
|
||||
|
||||
Map<String, Method> BUILTIN_FUNCTIONS = new HashMap<>() {{
|
||||
try {
|
||||
put("print", System.out.getClass().getMethod("println", String.class));
|
||||
put("printNum", System.out.getClass().getMethod("println", double.class));
|
||||
} catch(NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.dfsek.terra.addons.terrascript.ast.TypedStmt.Return;
|
||||
import com.dfsek.terra.addons.terrascript.ast.TypedStmt.VariableDeclaration;
|
||||
import com.dfsek.terra.addons.terrascript.ast.TypedStmt.While;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.codegen.NativeFunction;
|
||||
import com.dfsek.terra.addons.terrascript.codegen.TerraScript;
|
||||
import com.dfsek.terra.addons.terrascript.exception.CompilerBugException;
|
||||
import com.dfsek.terra.addons.terrascript.util.ASMUtil;
|
||||
@@ -39,7 +40,6 @@ import org.objectweb.asm.commons.LocalVariablesSorter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
@@ -217,13 +217,11 @@ public class TerraScriptClassGenerator {
|
||||
|
||||
@Override
|
||||
public Void visitCallTypedExpr(Call expr) {
|
||||
if (TerraScript.BUILTIN_FUNCTIONS.containsKey(expr.identifier)) {
|
||||
Method m = TerraScript.BUILTIN_FUNCTIONS.get(expr.identifier);
|
||||
if (expr.identifier.equals("print")) { // TODO - remove quick dirty print function call
|
||||
method.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
||||
expr.arguments.get(0).accept(this);
|
||||
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
|
||||
}
|
||||
if (NativeFunction.BUILTIN_FUNCTIONS.containsKey(expr.identifier)) {
|
||||
NativeFunction function = NativeFunction.BUILTIN_FUNCTIONS.get(expr.identifier);
|
||||
function.pushInstance(method);
|
||||
expr.arguments.forEach(a -> a.accept(this));
|
||||
function.callMethod(method);
|
||||
return null;
|
||||
}
|
||||
expr.arguments.forEach(a -> a.accept(this));
|
||||
|
||||
@@ -120,7 +120,7 @@ public class ScopeAnalyzer implements Visitor<Void>, Stmt.Visitor<Void> {
|
||||
stmt.body.accept(this);
|
||||
currentScope = currentScope.outer();
|
||||
try {
|
||||
Symbol.Function symbol = new Symbol.Function(stmt.returnType, stmt.parameters, currentScope);
|
||||
Symbol.Function symbol = new Symbol.Function(stmt.returnType, stmt.parameters.stream().map(Pair::getRight).toList(), currentScope);
|
||||
stmt.setSymbol(symbol);
|
||||
currentScope.put(stmt.identifier, symbol);
|
||||
} catch(Environment.ScopeException.SymbolAlreadyExistsException e) {
|
||||
|
||||
@@ -113,7 +113,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
|
||||
Environment.Symbol.Function signature = expr.getSymbol();
|
||||
|
||||
List<TypedExpr> arguments = expr.arguments.stream().map(a -> a.accept(this)).toList();
|
||||
List<Type> parameters = signature.parameters.stream().map(Pair::getRight).toList();
|
||||
List<Type> parameters = signature.parameters;
|
||||
|
||||
if(arguments.size() != parameters.size())
|
||||
errorHandler.add(new ParseException(
|
||||
|
||||
@@ -19,6 +19,7 @@ public class CodeGenTest {
|
||||
@Test
|
||||
public void test() {
|
||||
testValid("""
|
||||
printNum(12345);
|
||||
|
||||
if (1 == 1) print("Dis is true");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user