*
*/
public class Generator implements ASTVisitor {
+ boolean valid = true;
ClassWriter cw;
MethodVisitor mw;
int variableID = 1;
static final Type STRING_TYPE = Type.getType(String.class);
static final Type BOOLEAN_OBJECT_TYPE = Type.getType(Boolean.class);
+ static final Type BYTE_OBJECT_TYPE = Type.getType(Byte.class);
static final Type INTEGER_OBJECT_TYPE = Type.getType(Integer.class);
+ static final Type LONG_OBJECT_TYPE = Type.getType(Long.class);
static final Type FLOAT_OBJECT_TYPE = Type.getType(Float.class);
+ static final Type DOUBLE_OBJECT_TYPE = Type.getType(Double.class);
record Variable(String name, int id, Type type) {
}
return new Value(Type.FLOAT_TYPE, mv -> mv.visitLdcInsn(v));
}
+ static public Value constant(double v) {
+ return new Value(Type.DOUBLE_TYPE, mv -> mv.visitLdcInsn(v));
+ }
+
+ static public Value constant(byte v) {
+ return new Value(Type.BYTE_TYPE, mv -> mv.visitLdcInsn(v));
+ }
+
+ static public Value constant(short v) {
+ return new Value(Type.SHORT_TYPE, mv -> mv.visitLdcInsn(v));
+ }
+
static public Value constant(int v) {
return new Value(Type.INT_TYPE, mv -> mv.visitLdcInsn(v));
}
+ static public Value constant(long v) {
+ return new Value(Type.LONG_TYPE, mv -> mv.visitLdcInsn(v));
+ }
+
static public Value constant(boolean v) {
return new Value(Type.BOOLEAN_TYPE, mv -> mv.visitLdcInsn(v));
}
static public Value constant(Object v) {
return new Value(Type.getType(v.getClass()), mv -> mv.visitLdcInsn(v));
}
+
+ public boolean isNumber() {
+ return type.equals(INTEGER_OBJECT_TYPE)
+ || type.equals(FLOAT_OBJECT_TYPE)
+ || type.equals(LONG_OBJECT_TYPE)
+ || type.equals(DOUBLE_OBJECT_TYPE)
+ || type.equals(BYTE_OBJECT_TYPE);
+ }
+
+ public boolean isBoolean() {
+ return type.equals(BOOLEAN_OBJECT_TYPE);
+ }
+
+ public Value promote(Type to) {
+ switch (to.getSort()) {
+ case Type.BOOLEAN:
+ return promoteBoolean();
+ case Type.INT:
+ return promoteInt();
+ case Type.LONG:
+ return promoteLong();
+ case Type.FLOAT:
+ return promoteFloat();
+ case Type.DOUBLE:
+ return promoteDouble();
+ case Type.OBJECT:
+ if (to.equals(STRING_TYPE))
+ return promoteString();
+ else if (to.equals(INTEGER_OBJECT_TYPE))
+ return promoteInt().then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false));
+ else if (to.equals(FLOAT_OBJECT_TYPE))
+ return promoteFloat().then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false));
+ else if (to.equals(BOOLEAN_OBJECT_TYPE))
+ return promoteBoolean().then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false));
+ else if (to.equals(LONG_OBJECT_TYPE))
+ return promoteLong().then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false));
+ else if (to.equals(DOUBLE_OBJECT_TYPE))
+ return promoteDouble().then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false));
+ default:
+ throw new IllegalArgumentException("expecting " + to + ": " + this);
+ }
+ }
+
+ Value promoteBoolean() {
+ if (type == Type.BOOLEAN_TYPE) {
+ return this;
+ } else if (isBoolean()) {
+ return then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Boolean", "booleanValue", "()Z", false));
+ } else if (type.equals(STRING_TYPE)) {
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false));
+ } else {
+ throw new IllegalArgumentException("expecting boolean or boolean string: " + this);
+ }
+ }
+
+ Value promoteInt() {
+ if (type == Type.INT_TYPE) {
+ return this;
+ } else if (type == Type.FLOAT_TYPE) {
+ return then(mv -> mv.visitInsn(F2I));
+ } else if (type == Type.LONG_TYPE) {
+ return then(mv -> mv.visitInsn(L2I));
+ } else if (type == Type.DOUBLE_TYPE) {
+ return then(mv -> mv.visitInsn(D2I));
+ } else if (isNumber()) {
+ return then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "intValue", "()I", true));
+ } else if (type.equals(STRING_TYPE)) {
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I", false));
+ } else {
+ throw new IllegalArgumentException("expecting number or numerical string " + this);
+ }
+ }
+
+ Value promoteLong() {
+ if (type == Type.LONG_TYPE) {
+ return this;
+ } else if (type == Type.FLOAT_TYPE) {
+ return then(mv -> mv.visitInsn(F2L));
+ } else if (type == Type.INT_TYPE) {
+ return then(mv -> mv.visitInsn(I2L));
+ } else if (type == Type.DOUBLE_TYPE) {
+ return then(mv -> mv.visitInsn(D2L));
+ } else if (isNumber()) {
+ return then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "longValue", "()J", true));
+ } else if (type.equals(STRING_TYPE)) {
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;)J", false));
+ } else {
+ throw new IllegalArgumentException("expecting number or numerical string");
+ }
+ }
+
+ public Value promoteFloat() {
+ if (type == Type.FLOAT_TYPE) {
+ return this;
+ } else if (type == Type.INT_TYPE) {
+ return then(mv -> mv.visitInsn(I2F));
+ } else if (type == Type.DOUBLE_TYPE) {
+ return then(mv -> mv.visitInsn(D2F));
+ } else if (type == Type.LONG_TYPE) {
+ return then(mv -> mv.visitInsn(L2F));
+ } else if (isNumber()) {
+ return then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "floatValue", "()F", false));
+ } else if (type.equals(STRING_TYPE)) {
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false));
+ } else {
+ throw new IllegalArgumentException("expecting number or numerical string " + this);
+ }
+ }
+
+ Value promoteDouble() {
+ if (type == Type.DOUBLE_TYPE) {
+ return this;
+ } else if (type == Type.INT_TYPE) {
+ return then(mv -> mv.visitInsn(I2D));
+ } else if (type == Type.FLOAT_TYPE) {
+ return then(mv -> mv.visitInsn(F2D));
+ } else if (type == Type.LONG_TYPE) {
+ return then(mv -> mv.visitInsn(L2D));
+ } else if (isNumber()) {
+ return then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "doubleValue", "()D", true));
+ } else if (type.equals(STRING_TYPE)) {
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false));
+ } else {
+ throw new IllegalArgumentException("expecting number or numerical string");
+ }
+ }
+
+ Value promoteString() {
+ if (type.equals(STRING_TYPE)) {
+ return this;
+ } else {
+ switch (type.getSort()) {
+ case Type.INT:
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "toString", "(I)Ljava/lang/String;", false));
+ case Type.LONG:
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "toString", "(J)Ljava/lang/String;", false));
+ case Type.FLOAT:
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "toString", "(F)Ljava/lang/String;", false));
+ case Type.DOUBLE:
+ return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "toString", "(Z)Ljava/lang/String;", false));
+ case Type.OBJECT:
+ default:
+ return then(mv -> mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "(Ljava/lang/Object;)Ljava/lang/String;", false));
+ }
+ }
+ }
}
// maybe other shit like locals here too
LinkedList<Block> blocks = new LinkedList<>();
- Variable addVariable(String name, Type type) {
+ public Variable addVariable(String name, Type type) {
Variable var;
if (type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE) {
variableID = (variableID + 1) & ~1;
@Override
public void visitScript(AST.ScriptA script) {
- boolean valid = true;
-
if (valid)
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
else
mw.visitLabel(test);
Value testX = visitExpression(s.test);
- promoteBoolean(testX).insert.accept(mw);
+ testX.promoteBoolean().insert.accept(mw);
mw.visitJumpInsn(IFNE, loop);
mw.visitLabel(exit);
blocks.pop();
}
- static final Type typeMap[] = {Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.FLOAT_TYPE, STRING_TYPE};
+ static final Type typeMap[] = {Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.LONG_TYPE, Type.FLOAT_TYPE, Type.DOUBLE_TYPE, STRING_TYPE};
@Override
public void visitDecl(AST.SDeclare s) {
val = s.value.map(x -> visitExpression(x));
if (s.type.type == AST.XType.OBJECT) {
- var = new Variable(s.name, variableID++, Type.getObjectType(s.type.typeName.get().name()));
+ var = addVariable(s.name, Type.getObjectType(s.type.typeName.get().name()));
val.ifPresent(v -> {
v.insert.accept(mw);
mw.visitVarInsn(ASTORE, var.id);
});
} else {
- var = new Variable(s.name, variableID++, typeMap[s.type.type.ordinal()]);
- val = val.map(v -> promote(v, s.type.type));
+ var = addVariable(s.name, typeMap[s.type.type.ordinal()]);
+ val = val.map(v -> v.promote(var.type));
+ System.out.printf(" var: %s = %s\n", var, val);
val.ifPresent(v -> {
v.insert.accept(mw);
- mw.visitVarInsn(v.type().getOpcode(ISTORE), var.id);
+ mw.visitVarInsn(var.type().getOpcode(ISTORE), var.id);
});
}
variables.put(var.name, var);
Variable var = variables.get(s.ref.name());
Value val = visitExpression(s.value);
- val = promote(val, var.type);
+ val = val.promote(var.type);
val.insert.accept(mw);
mw.visitVarInsn(var.type.getOpcode(ISTORE), var.id);
}
stack.push(a.then(mv -> mv.visitInsn(a.type.getOpcode(INEG))));
break;
case NOT:
- Value b = promoteBoolean(a);
+ Value b = a.promoteBoolean();
stack.push(new Value(Type.BOOLEAN_TYPE, mv -> {
b.insert.accept(mv);
mw.visitInsn(ICONST_1);
}));
break;
case INV:
- Value i = promoteInt(a);
+ Value i = a.promoteInt();
stack.push(new Value(Type.INT_TYPE, mv -> {
i.insert.accept(mv);
mw.visitInsn(ICONST_M1);
}
static final int intOp[] = {
- IADD, ISUB, IMUL, IDIV, IUSHR, ISHL, ISHR, IAND, IOR, IXOR
+ IADD, ISUB, IMUL, IDIV, 0, ISHR, ISHL, IUSHR, IAND, IOR, IXOR
};
// CLT, CLE, CGT, CGE, CEQ, CNE,
static final int cmpFloat[] = {
IAND, IOR, IXOR
};
- boolean isAssignable(Class<?> target, Type type) {
- try {
- Class<?> klass = Class.forName(type.getClassName(), false, classLoader);
- return target.isAssignableFrom(klass);
- } catch (ClassNotFoundException ex) {
- return false;
- }
- }
-
- Value promote(Value val, AST.XType to) {
- switch (to) {
- case BOOLEAN:
- return promoteBoolean(val);
- case INTEGER:
- return promoteInt(val);
- case FLOAT:
- return promoteFloat(val);
- case STRING:
- return promoteString(val);
- default:
- return val;
- }
- }
-
- Value promote(Value val, Type to) {
- switch (to.getSort()) {
- case Type.BOOLEAN:
- return promoteBoolean(val);
- case Type.INT:
- return promoteInt(val);
- case Type.FLOAT:
- return promoteFloat(val);
- default:
- if (to.equals(STRING_TYPE))
- return promoteString(val);
- }
- throw new IllegalArgumentException("expecting " + to + ": " + val);
- }
-
- Value promoteBoolean(Value a) {
- if (a.type == Type.BOOLEAN_TYPE) {
- return a;
- } else if (isAssignable(Boolean.class, a.type)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Boolean", "booleanValue", "()Z", false));
- } else if (a.type.equals(STRING_TYPE)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z", false));
- } else {
- throw new IllegalArgumentException("expecting boolean or boolean string: " + a);
- }
- }
-
- Value promoteDouble(Value a) {
- if (a.type == Type.DOUBLE_TYPE) {
- return a;
- } else if (a.type == Type.INT_TYPE) {
- return a.then(mv -> mv.visitInsn(I2D));
- } else if (a.type == Type.FLOAT_TYPE) {
- return a.then(mv -> mv.visitInsn(F2D));
- } else if (a.type == Type.LONG_TYPE) {
- return a.then(mv -> mv.visitInsn(L2D));
- } else if (isAssignable(Number.class, a.type)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "doubleValue", "()D", true));
- } else if (a.type.equals(STRING_TYPE)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D", false));
- } else {
- throw new IllegalArgumentException("expecting number or numerical string");
- }
- }
-
- Value promoteFloat(Value a) {
- if (a.type == Type.FLOAT_TYPE) {
- return a;
- } else if (a.type == Type.INT_TYPE) {
- return a.then(mv -> mv.visitInsn(I2F));
- } else if (a.type == Type.DOUBLE_TYPE) {
- return a.then(mv -> mv.visitInsn(D2F));
- } else if (a.type == Type.LONG_TYPE) {
- return a.then(mv -> mv.visitInsn(L2F));
- } else if (isAssignable(Number.class, a.type)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "floatValue", "()F", true));
- } else if (a.type.equals(STRING_TYPE)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F", false));
- } else {
- throw new IllegalArgumentException("expecting number or numerical string");
- }
- }
-
- Value promoteLong(Value a) {
- if (a.type == Type.LONG_TYPE) {
- return a;
- } else if (a.type == Type.FLOAT_TYPE) {
- return a.then(mv -> mv.visitInsn(F2L));
- } else if (a.type == Type.INT_TYPE) {
- return a.then(mv -> mv.visitInsn(I2L));
- } else if (a.type == Type.DOUBLE_TYPE) {
- return a.then(mv -> mv.visitInsn(D2L));
- } else if (isAssignable(Number.class, a.type)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "longValue", "()J", true));
- } else if (a.type.equals(STRING_TYPE)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;)J", false));
- } else {
- throw new IllegalArgumentException("expecting number or numerical string");
- }
- }
-
- Value promoteInt(Value a) {
- if (a.type == Type.INT_TYPE) {
- return a;
- } else if (a.type == Type.FLOAT_TYPE) {
- return a.then(mv -> mv.visitInsn(F2I));
- } else if (a.type == Type.LONG_TYPE) {
- return a.then(mv -> mv.visitInsn(L2I));
- } else if (a.type == Type.DOUBLE_TYPE) {
- return a.then(mv -> mv.visitInsn(D2I));
- } else if (isAssignable(Number.class, a.type)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/Number", "intValue", "()I", true));
- } else if (a.type.equals(STRING_TYPE)) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I", false));
- } else {
- throw new IllegalArgumentException("expecting number or numerical string");
- }
- }
-
- Value promoteString(Value a) {
- if (a.type.equals(STRING_TYPE)) {
- return a;
- } else if (a.type == Type.INT_TYPE) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "toString", "(I)Ljava/lang/String;", false));
- } else if (a.type == Type.FLOAT_TYPE) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "toString", "(F)Ljava/lang/String;", false));
- } else if (a.type == Type.DOUBLE_TYPE) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "toString", "(D)Ljava/lang/String;", false));
- } else if (a.type == Type.LONG_TYPE) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "toString", "(J)Ljava/lang/String;", false));
- } else if (a.type == Type.BOOLEAN_TYPE) {
- return a.then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "toString", "(Z)Ljava/lang/String;", false));
- } else {
- return a.then(mv -> mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "(Ljava/lang/Object;)Ljava/lang/String;", false));
- }
- }
-
static Value compareFloat(Value c, Value d, int fcmp, int cmp) {
return new Value(Type.BOOLEAN_TYPE, mv -> {
Label t = new Label();
case ADD:
if (a.type == STRING_TYPE || b.type == STRING_TYPE) {
stack.addFirst(new Value(STRING_TYPE, mv -> {
- promoteString(a).insert.accept(mv);
- promoteString(b).insert.accept(mv);
+ a.promoteString().insert.accept(mv);
+ b.promoteString().insert.accept(mv);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
}));
return;
case SUB, MUL, DIV:
if (a.type == Type.DOUBLE_TYPE || b.type == Type.DOUBLE_TYPE) {
type = Type.DOUBLE_TYPE;
- c = promoteDouble(a);
- d = promoteDouble(b);
+ c = a.promoteDouble();
+ d = b.promoteDouble();
} else if (a.type == Type.FLOAT_TYPE || b.type == Type.FLOAT_TYPE) {
type = Type.FLOAT_TYPE;
- c = promoteFloat(a);
- d = promoteFloat(b);
+ c = a.promoteFloat();
+ d = b.promoteFloat();
} else if (a.type == Type.LONG_TYPE || b.type == Type.LONG_TYPE) {
type = Type.LONG_TYPE;
- c = promoteLong(a);
- d = promoteLong(b);
+ c = a.promoteLong();
+ d = b.promoteLong();
} else if (a.type == Type.INT_TYPE || b.type == Type.INT_TYPE) {
type = Type.INT_TYPE;
- c = promoteInt(a);
- d = promoteInt(b);
+ c = a.promoteInt();
+ d = b.promoteInt();
} else {
- type = Type.DOUBLE_TYPE;
- c = promoteDouble(a);
- d = promoteDouble(b);
+ type = Type.FLOAT_TYPE;
+ c = a.promoteFloat();
+ d = b.promoteFloat();
}
opcode = type.getOpcode(intOp[e.op.ordinal()]);
System.out.printf("%s: %d -> %d\n", e.op, intOp[e.op.ordinal()], opcode);
case LSR, LSL, ASR, AND, ORR, XOR:
if (a.type == Type.LONG_TYPE) {
type = a.type;
- c = promoteLong(a);
- d = promoteInt(b);
+ c = a.promoteLong();
+ d = b.promoteInt();
} else if (a.type == Type.INT_TYPE) {
type = a.type;
- c = promoteInt(a);
- d = promoteInt(b);
+ c = a.promoteInt();
+ d = b.promoteInt();
} else {
type = Type.LONG_TYPE;
- c = promoteLong(a);
- d = promoteInt(b);
+ c = a.promoteLong();
+ d = b.promoteInt();
}
opcode = type.getOpcode(intOp[e.op.ordinal()]);
stack.addFirst(new Value(type, mv -> {
int index = e.op.ordinal() - AST.XBinaryOp.CLT.ordinal();
if (a.type == Type.DOUBLE_TYPE || b.type == Type.DOUBLE_TYPE) {
- stack.addFirst(compareFloat(promoteDouble(a), promoteDouble(b), cmpFloat[index] + 2, cmpOp[index]));
+ stack.addFirst(compareFloat(a.promoteDouble(), b.promoteDouble(), cmpFloat[index] + 2, cmpOp[index]));
} else if (a.type == Type.FLOAT_TYPE || b.type == Type.FLOAT_TYPE) {
- stack.addFirst(compareFloat(promoteFloat(a), promoteFloat(b), cmpFloat[index], cmpOp[index]));
+ stack.addFirst(compareFloat(a.promoteFloat(), b.promoteFloat(), cmpFloat[index], cmpOp[index]));
} else if (a.type == Type.LONG_TYPE || b.type == Type.LONG_TYPE) {
- stack.addFirst(compareInt(promoteLong(a), promoteLong(b), LCMP, cmpJump[index]));
+ stack.addFirst(compareInt(a.promoteLong(), b.promoteLong(), LCMP, cmpJump[index]));
} else if (a.type == Type.INT_TYPE || b.type == Type.INT_TYPE) {
- stack.addFirst(compareInt(promoteInt(a), promoteInt(b), 0, cmpJump[index]));
+ stack.addFirst(compareInt(a.promoteInt(), b.promoteInt(), 0, cmpJump[index]));
} else {
- stack.addFirst(compareInt(promoteLong(a), promoteLong(b), LCMP, cmpJump[index]));
+ stack.addFirst(compareInt(a.promoteInt(), b.promoteInt(), 0, cmpJump[index]));
}
break;
case AAND, OOR, XXOR:
- c = promoteBoolean(a);
- d = promoteBoolean(b);
+ c = a.promoteBoolean();
+ d = b.promoteBoolean();
opcode = boolOp[e.op.ordinal() - AST.XBinaryOp.AAND.ordinal()];
stack.addFirst(new Value(Type.BOOLEAN_TYPE, mv -> {
c.insert.accept(mv);
public void visit(AST.XCall e) {
System.out.println(e);
// TODO: how to resolve parts of expression
- // TODO: how to promote?
List<Value> args = e.params.stream().map(this::visitExpression).toList();
- stack.push(imports.findImport(e.ref.name(), args).orElseThrow());
+
+ if (e.ref.part.length == 1) {
+ stack.push(imports.findImport(e.ref.name(), args).orElseThrow());
+ // or func variable
+ } else {
+ throw new UnsupportedOperationException("namespace dereferencing unimplemented");
+ }
}
@Override
public void visit(AST.XFunction e) {
+ // unimplemented
System.out.print("function (");
Iterator<String> it = e.params.iterator();
if (it.hasNext())
@Override
public void visit(AST.XInteger e) {
+ System.out.printf("%d\n", e.value);
+ stack.push(Value.constant(e.value));
+ }
+
+ @Override
+ public void visit(AST.XLong e) {
System.out.printf("%dL\n", e.value);
stack.push(Value.constant(e.value));
}
@Override
- public void visit(AST.XReal e) {
- System.out.printf("%fD", e.value);
+ public void visit(AST.XFloat e) {
+ System.out.printf("%ff", e.value);
+ stack.push(Value.constant(e.value));
+ }
+
+ @Override
+ public void visit(AST.XDouble e) {
+ System.out.printf("%f", e.value);
stack.push(Value.constant(e.value));
}
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static org.objectweb.asm.Opcodes.*;
import org.objectweb.asm.Type;
+/**
+ * TODO: might need a Lookup
+ * TODO: namespaces
+ */
public class Imports {
/*
Need to be able to find fields and methods based on:
Type type = Type.getType(m);
String name = m.getName();
+ // TODO: interface
if (Modifier.isStatic(m.getModifiers())) {
importStatic(new Import(recv, name, type, (im, mv, args) -> {
- // receive must already be present
- // TODO: interface
- // TODO: promote args
- for (var a: args) {
- a.insert().accept(mv);
+ Type[] argb = im.type.getArgumentTypes();
+ for (int i = 0; i < argb.length; i++) {
+ args.get(i).promote(argb[i]).insert().accept(mv);
}
mv.visitMethodInsn(INVOKESTATIC, im.recv.getInternalName(), im.name, im.type.getDescriptor(), false);
}));
} else {
+ // receiver must already be present
importInstance(new Import(recv, name, type, (im, mv, args) -> {
- for (var a: args) {
- a.insert().accept(mv);
+ Type[] argb = im.type.getArgumentTypes();
+ for (int i = 0; i < argb.length; i++) {
+ args.get(i).promote(argb[i]).insert().accept(mv);
}
mv.visitMethodInsn(INVOKEVIRTUAL, im.recv.getInternalName(), im.name, im.type.getDescriptor(), false);
}));
}
}
- // TODO: match promotable types as well
- // MethodType has some stuff but it's private
- static Predicate<Import> matchArguments(Type type) {
- Type[] arga = type.getArgumentTypes();
- return im -> {
- Type[] argb = im.type.getArgumentTypes();
+ static Type[] toArgumentTypes(List<Generator.Value> arga) {
+ return arga.stream().map(Generator.Value::type).toArray(Type[]::new);
+ }
- System.out.printf("match %s %s\n", type, im.type);
- if (arga.length == argb.length) {
- for (int i = 0; i < arga.length; i++) {
- if (!im.type().equals(type))
- return false;
- }
- return true;
- }
- return false;
- };
+ public Optional<Generator.Value> findStaticField(String name) {
+ return importStatic[IMPORT_FIELDS].values().stream()
+ .flatMap(m -> m.getOrDefault(name, List.of()).stream())
+ .findFirst()
+ .map(m -> m.value());
}
- // void boolean char byte short int float long double
- static boolean matchArgument(Type a, Type b) {
- return a.equals(b);
- // || (a.getSort() >= Type.CHAR && a.getSort() <= Type.DOUBLE
- // && b.getSort() >= Type.CHAR && b.getSort() <= Type.DOUBLE);
+ record Match(Import im, int score) implements Comparable<Match> {
+ @Override
+ public int compareTo(Match o) {
+ return Integer.compare(o.score, score);
+ }
}
- static Predicate<Import> matchArguments(Type arga[]) {
+ Function<Import, Match> match(Type[] arga) {
return im -> {
Type[] argb = im.type.getArgumentTypes();
+ int score = 0;
System.out.printf("match arguments:\n %s\n %s\n",
String.join(", ", Stream.of(arga).map(Object::toString).toArray(String[]::new)),
if (arga.length == argb.length) {
for (int i = 0; i < arga.length; i++) {
- if (!matchArgument(arga[i], argb[i])) {
- System.out.println(" -> false");
- return false;
+ Type a = arga[i], b = argb[i];
+ int sa = a.getSort(), sb = b.getSort();
+
+ if (a.equals(b)) {
+ score += 10;
+ } else if ((sa == Type.FLOAT || sa == Type.DOUBLE) && (sb == Type.FLOAT || sb == Type.DOUBLE)) {
+ score += 8;
+ } else if ((sa == Type.INT || sa == Type.LONG) && (sb == Type.INT || sb == Type.LONG)) {
+ score += 8;
+ } else if (new Generator.Value(a, null).isNumber() && sb >= Type.CHAR && sb <= Type.DOUBLE) {
+ score += 6;
+ } else if (b.equals(Generator.STRING_TYPE)) {
+ // anything can be converted to string
+ score += 6;
+ } else {
+ System.out.printf(" -> no match\n");
+ return new Match(im, -1);
}
}
- System.out.println(" -> true");
- return true;
}
- System.out.println(" -> false");
- return false;
- };
- }
-
- static Type[] toArgumentTypes(List<Generator.Value> arga) {
- return arga.stream().map(Generator.Value::type).toArray(Type[]::new);
- }
-
- static Predicate<Import> matchType(Type type) {
- return im -> {
- return im.type().equals(type);
+ System.out.printf(" -> score %d\n", score);
+ return new Match(im, score);
};
}
- public Optional<Generator.Value> findStaticField(String name) {
- return importStatic[IMPORT_FIELDS].values().stream()
- .flatMap(m -> m.getOrDefault(name, List.of()).stream())
- .findFirst()
- .map(m -> m.value());
- }
-
- // Find a method.
+ // Find a static method.
public Optional<Generator.Value> findImport(String name, List<Generator.Value> args) {
Type[] arga = toArgumentTypes(args);
System.out.printf("find method: %s", name);
return importStatic[IMPORT_METHODS].values().stream()
.flatMap(m -> m.getOrDefault(name, List.of()).stream())
.peek(m -> System.out.println("? " + m))
- .filter(matchArguments(arga))
+ .map(match(arga))
+ .filter(m -> m.score >= 0)
+ .sorted()
.findFirst()
- .map(m -> m.value(args));
+ .map(m -> {
+ System.out.println("> " + m);
+ return m;
+ })
+ .map(m -> m.im.value(args));
}
- /**
- *
- * @param name
- * @param type
- * @return
- * @deprecated not finished
- */
- @Deprecated
- public Optional<Import> findImport(String name, Type type) {
- if (type.getSort() == Type.METHOD) {
- System.out.printf("find method: %s\n", name);
- System.out.println(importStatic[IMPORT_METHODS].toString());
- for (var map: importStatic[IMPORT_METHODS].values()) {
- System.out.println(map.getClass());
- System.out.println(map);
- for (var im: map.get(name)) {
- System.out.printf(" ? %s\n", im);
- }
+ // find non-static method
+ // ?? may have to search fields
+ public Optional<Generator.Value> findImport(Type recv, String name, List<Generator.Value> args) {
+ Type[] arga = toArgumentTypes(args);
+ System.out.printf("find method: %s", name);
+ args.stream().forEach(a -> System.out.printf(" %s", a.type()));
+ System.out.println();
+ for (var map: importStatic[IMPORT_METHODS].entrySet()) {
+ System.out.println(map.getKey());
+ for (var im: map.getValue().getOrDefault(name, List.of())) {
+ System.out.printf(" ? %s\n", im);
}
- System.out.println("----");
- return importStatic[IMPORT_METHODS].values().stream()
- .peek(x -> System.out.print(" > "))
- .peek(System.out::println)
- .flatMap(m -> m.get(name).stream())
- .peek(System.out::println)
- .filter(matchArguments(type))
- .findFirst();
- } else {
- System.out.printf("find field: %s\n", name);
- importStatic[IMPORT_FIELDS].values().stream()
- .flatMap(m -> m.get(name).stream())
- .filter(matchType(type));
}
- return null;
- }
-
- @Deprecated
- public Optional<Import> findImport(Type recv, String name, Type type) {
- if (type.getSort() == Type.METHOD) {
- return importInstance[IMPORT_METHODS].values().stream()
- .flatMap(m -> m.get(name).stream())
- .filter(matchArguments(type))
- .findFirst();
- } else {
- }
-
- return null;
+ return importStatic[IMPORT_METHODS].values().stream()
+ .flatMap(m -> m.getOrDefault(name, List.of()).stream())
+ .peek(m -> System.out.println("? " + m))
+ .map(match(arga))
+ .filter(m -> m.score >= 0)
+ .sorted()
+ .findFirst()
+ .map(m -> {
+ System.out.println("> " + m);
+ return m;
+ })
+ .map(m -> m.im.value(args));
}
void dump() {