Checkpoint ongoing work
authorNot Zed <notzed@gmail.com>
Tue, 11 Apr 2023 10:40:53 +0000 (20:10 +0930)
committerNot Zed <notzed@gmail.com>
Tue, 11 Apr 2023 10:40:53 +0000 (20:10 +0930)
 - Rejigged grammar to support:
  + Chained function calls
  + field references
  + multiple variables in declarations
  + assignments to calculated fields
  + more correct operator precedence
 - fixed instance field/method resolution

src/notzed.scripta/classes/au/notzed/scripta/AST.java
src/notzed.scripta/classes/au/notzed/scripta/ASTBuilder.java
src/notzed.scripta/classes/au/notzed/scripta/ASTPrinter.java
src/notzed.scripta/classes/au/notzed/scripta/ASTVisitor.java
src/notzed.scripta/classes/au/notzed/scripta/Compiler.java
src/notzed.scripta/classes/au/notzed/scripta/Generator.java
src/notzed.scripta/classes/au/notzed/scripta/Imports.java
src/notzed.scripta/gen/ScriptA.g4

index 264c782..8c07d50 100644 (file)
@@ -206,14 +206,12 @@ public abstract class AST {
 
        public static class SDeclare extends Statement {
                final DType type;
-               final String name;
-               final Optional<Expression> value;
+               final List<DInitialiser> list;
 
-               public SDeclare(int lineNo, DType type, String id, Optional<Expression> value) {
+               public SDeclare(int lineNo, DType type, List<DInitialiser> list) {
                        super(lineNo);
                        this.type = type;
-                       this.name = id;
-                       this.value = value;
+                       this.list = list;
                }
 
                @Override
@@ -223,15 +221,15 @@ public abstract class AST {
 
                @Override
                public void visitChildren(ASTVisitor av) {
-                       value.ifPresent(x -> x.accept(av));
+                       accept(list, av);
                }
        }
 
        public static class SAssign extends Statement {
-               final XReference ref;
+               final Expression ref;
                final Expression value;
 
-               public SAssign(int lineNo, AST.XReference ref, AST.Expression value) {
+               public SAssign(int lineNo, AST.Expression ref, AST.Expression value) {
                        super(lineNo);
                        this.ref = ref;
                        this.value = value;
@@ -318,12 +316,59 @@ public abstract class AST {
        /* **** metadata */
        public static class DType extends AST {
                final XType type;
-               final Optional<XReference> typeName;
+               final Optional<XReference> name;
+
+               public DType(int lineNo, XType type, Optional<XReference> name) {
+                       super(lineNo);
+                       this.type = type;
+                       this.name = name;
+               }
+
+               @Override
+               public void accept(ASTVisitor av) {
+                       av.visit(this);
+               }
+
+               @Override
+               public String toString() {
+                       return name.orElse(new XReference(lineNo, type.name())).name();
+               }
+       }
+
+       public static class DInitialiser extends AST {
+               final String name;
+               final Optional<Expression> value;
+
+               public DInitialiser(int lineNo, String name, Optional<Expression> value) {
+                       super(lineNo);
+                       this.name = name;
+                       this.value = value;
+               }
+
+               @Override
+               public void accept(ASTVisitor av) {
+                       av.visit(this);
+               }
+
+               @Override
+               public void visitChildren(ASTVisitor av) {
+                       value.ifPresent(x -> x.accept(av));
+               }
 
-               public DType(int lineNo, XType type, Optional<XReference> typeName) {
+               @Override
+               public String toString() {
+                       return name + (value.isPresent() ? (" = " + value.get().toString()) : "");
+               }
+       }
+
+       public static class DParameter extends AST {
+               DType type;
+               DInitialiser param;
+
+               public DParameter(int lineNo, DType type, DInitialiser param) {
                        super(lineNo);
                        this.type = type;
-                       this.typeName = typeName;
+                       this.param = param;
                }
 
                @Override
@@ -331,9 +376,15 @@ public abstract class AST {
                        av.visit(this);
                }
 
+               @Override
+               public void visitChildren(ASTVisitor av) {
+                       type.accept(av);
+                       param.accept(av);
+               }
+
                @Override
                public String toString() {
-                       return typeName.orElse(new XReference(lineNo, type.name())).name();
+                       return type.toString() + " " + param.toString();
                }
        }
 
@@ -431,20 +482,39 @@ public abstract class AST {
                }
        }
 
+       public static class XField extends Expression {
+               Expression ref;
+               String field;
+
+               public XField(int lineNo, Expression ref, String field) {
+                       super(lineNo);
+                       this.ref = ref;
+                       this.field = field;
+               }
+
+               @Override
+               public void accept(ASTVisitor av) {
+                       av.visit(this);
+               }
+
+               @Override
+               public void visitChildren(ASTVisitor av) {
+                       ref.accept(av);
+               }
+       }
+
        public static class XCall extends Expression {
                boolean constructor;
-               XReference ref;
-               List<Expression> params;
+               Optional<Expression> ref;
+               String name;
+               List<Expression> args;
 
-               public XCall(int lineNo, boolean constructor, XReference ref, List<Expression> params) {
+               public XCall(int lineNo, boolean constructor, Optional<Expression> ref, String name, List<Expression> args) {
                        super(lineNo);
                        this.constructor = constructor;
                        this.ref = ref;
-                       this.params = params;
-
-                       System.out.printf("call: %s%s ", constructor ? "new " : "", ref.name());
-                       params.forEach(p -> System.out.printf(" %s", p));
-                       System.out.println();
+                       this.name = name;
+                       this.args = args;
                }
 
                @Override
@@ -454,33 +524,31 @@ public abstract class AST {
 
                @Override
                public void visitChildren(ASTVisitor av) {
-                       ref.accept(av);
-                       accept(params, av);
+                       ref.ifPresent(r -> r.accept(av));
+                       accept(args, av);
                }
 
                @Override
                public String toString() {
                        StringBuilder sb = new StringBuilder("[call ");
                        sb.append(ref);
-                       sb.append(" ");
-                       sb.append(String.join(", ", params.stream().map(x -> x.toString()).toArray(String[]::new)));
-                       sb.append("]");
+                       sb.append("(");
+                       sb.append(String.join(", ", args.stream().map(x -> x.toString()).toArray(String[]::new)));
+                       sb.append(")]");
                        return sb.toString();
                }
        }
 
-       // return type?
+       // how do i know the return type?
        public static class XFunction extends Expression {
                final DType rval;
-               final List<DType> types;
-               final List<String> params;
+               final List<DParameter> params;
                final Statements statements;
 
-               public XFunction(int lineNo, DType rval, List<DType> types, List<String> params, Statements statements) {
+               public XFunction(int lineNo, DType rval, List<DParameter> params, Statements statements) {
                        super(lineNo);
-                       this.params = params;
                        this.rval = rval;
-                       this.types = types;
+                       this.params = params;
                        this.statements = statements;
                }
 
index 2ccc03b..41590cc 100644 (file)
@@ -35,7 +35,9 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
 
        @Override
        public AST.Statements visitStatements(StatementsContext ctx) {
-               return new AST.Statements(ctx.start.getLine(), ctx.statement().stream().map(this::visitStatement).toList());
+               return ctx != null
+                       ? new AST.Statements(ctx.start.getLine(), ctx.statement().stream().map(this::visitStatement).toList())
+                       : new AST.Statements(0, List.of());
        }
 
        public AST.Statement visitStatement(StatementContext ctx) {
@@ -46,6 +48,10 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                return label != null ? Optional.of(label.getText()) : Optional.empty();
        }
 
+       Optional<Expression> expression(ValueExprContext expr) {
+               return expr != null ? Optional.of(visitValueExpr(expr)) : Optional.empty();
+       }
+
        @Override
        public AST.SIf visitIfStatement(IfStatementContext ctx) {
                ValueExprContext valX = ctx.valueExpr();
@@ -102,28 +108,24 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                        type == XType.OBJECT ? Optional.of(visitReference(ctx.reference())) : Optional.empty());
        }
 
+       List<DInitialiser> visitInitialisers(DeclExprContext ctx, List<DInitialiser> list) {
+               if (ctx.declExpr() != null)
+                       list = visitInitialisers(ctx.declExpr(), list);
+               list.add(new DInitialiser(ctx.id.getLine(), ctx.id.getText(), expression(ctx.val)));
+               return list;
+       }
+
        @Override
        public AST visitDeclStatement(DeclStatementContext ctx) {
-               System.out.printf("type\n");
-               Compiler.dump("", ctx.type());
-               if (ctx.valueExpr() == null) {
-                       return new SDeclare(
-                               ctx.start.getLine(),
-                               visitType(ctx.type()),
-                               ctx.ID().getText(),
-                               Optional.empty());
-               } else {
-                       return new SDeclare(
-                               ctx.start.getLine(),
-                               visitType(ctx.type()),
-                               ctx.ID().getText(),
-                               Optional.of(visitValueExpr(ctx.valueExpr())));
-               }
+               return new SDeclare(
+                       ctx.start.getLine(),
+                       visitType(ctx.type()),
+                       visitInitialisers(ctx.declExpr(), new ArrayList<>()));
        }
 
        @Override
        public AST.SAssign visitAssignStatement(AssignStatementContext ctx) {
-               return new AST.SAssign(ctx.start.getLine(), visitReference(ctx.reference()), visitValueExpr(ctx.valueExpr()));
+               return new AST.SAssign(ctx.start.getLine(), visitValueExpr(ctx.valueExpr(0)), visitValueExpr(ctx.valueExpr(1)));
        }
 
        public AST.Expression visitValueExpr(ValueExprContext ctx) {
@@ -132,7 +134,20 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
 
        @Override
        public AST visitCallStatement(CallStatementContext ctx) {
-               return new SCall(ctx.start.getLine(), visitCallExpr(ctx.callExpr()));
+               return new SCall(ctx.start.getLine(),
+                       new XCall(
+                               ctx.start.getLine(),
+                               false,
+                               expression(ctx.left),
+                               ctx.ID().getText(),
+                               ctx.args.valueExpr().stream().map(v -> (AST.Expression)v.accept(this)).toList()));
+       }
+
+       List<DParameter> visitParams(ParamExprContext ctx, List<DParameter> list) {
+               if (ctx.paramExpr() != null)
+                       list = visitParams(ctx.paramExpr(), list);
+               list.add(new DParameter(ctx.id.getLine(), visitType(ctx.type()), new DInitialiser(ctx.id.getLine(), ctx.id.getText(), expression(ctx.val))));
+               return list;
        }
 
        @Override
@@ -140,23 +155,13 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                return new XFunction(
                        ctx.start.getLine(),
                        visitType(ctx.rval),
-                       ctx.type().stream().map(a -> visitType(a)).toList(),
-                       ctx.ID().stream().map(a -> a.getText()).toList(),
+                       visitParams(ctx.paramExpr(), new ArrayList<>()),
                        ctx.statements() != null
                        ? visitStatements(ctx.statements())
                        : AST.Statements.EMPTY
                );
        }
 
-       @Override
-       public AST.XCall visitCallExpr(CallExprContext ctx) {
-               return new XCall(
-                       ctx.start.getLine(),
-                       ctx.NEW() != null,
-                       visitReference(ctx.reference()),
-                       ctx.valueExpr().stream().map(v -> (AST.Expression)v.accept(this)).toList());
-       }
-
        private SBreakType breakType(Token tok) {
                switch (tok.getType()) {
                case BREAK:
@@ -188,6 +193,34 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                return visitValueExpr(ctx.valueExpr());
        }
 
+       @Override
+       public AST.XField visitValueFieldExpr(ValueFieldExprContext ctx) {
+               return new AST.XField(
+                       ctx.start.getLine(),
+                       visitValueExpr(ctx.left),
+                       ctx.ID().getText());
+       }
+
+       @Override
+       public AST visitValueCallExpr(ValueCallExprContext ctx) {
+               return new XCall(
+                       ctx.start.getLine(),
+                       false,
+                       expression(ctx.left),
+                       ctx.ID().getText(),
+                       ctx.args.valueExpr().stream().map(v -> (AST.Expression)v.accept(this)).toList());
+       }
+
+       @Override
+       public AST visitValueNewExpr(ValueNewExprContext ctx) {
+               return new XCall(
+                       ctx.start.getLine(),
+                       true,
+                       Optional.of(visitReference(ctx.ref)),
+                       "<init>",
+                       ctx.args.valueExpr().stream().map(v -> (AST.Expression)v.accept(this)).toList());
+       }
+
        XUnaryOp valueUnaryOp(Token op) {
                switch (op.getType()) {
                case ADD:
@@ -208,7 +241,7 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                return new AST.XUnary(
                        ctx.start.getLine(),
                        valueUnaryOp(ctx.op),
-                       (Expression)visit(ctx.rightValue));
+                       (Expression)visit(ctx.right));
        }
 
        XBinaryOp valueBinaryOp(Token op) {
@@ -257,14 +290,14 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                XBinary xb = new XBinary(
                        ctx.op.getLine(),
                        valueBinaryOp(ctx.op),
-                       (Expression)visit(ctx.leftValue),
-                       (Expression)visit(ctx.rightValue));
+                       (Expression)visit(ctx.left),
+                       (Expression)visit(ctx.right));
                System.out.printf("visit binary %s %s %s\n", xb.left, xb.op, xb.right);
                return new XBinary(
                        ctx.op.getLine(),
                        valueBinaryOp(ctx.op),
-                       (Expression)visit(ctx.leftValue),
-                       (Expression)visit(ctx.rightValue));
+                       (Expression)visit(ctx.left),
+                       (Expression)visit(ctx.right));
        }
 
        @Override
@@ -272,10 +305,12 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                switch (ctx.start.getType()) {
                case INTEGER: {
                        try {
-                               if (ctx.size != null && ctx.size.getText().equals("L"))
-                                       return new XLong(ctx.start.getLine(), Long.parseLong(ctx.start.getText()));
+                               String txt = ctx.start.getText();
+                               //if (ctx.size != null && ctx.size.getText().equals("L"))
+                               if (txt.endsWith("L"))
+                                       return new XLong(ctx.start.getLine(), Long.parseLong(txt.substring(0, txt.length() - 1)));
                                else
-                                       return new XInteger(ctx.start.getLine(), Integer.parseInt(ctx.start.getText()));
+                                       return new XInteger(ctx.start.getLine(), Integer.parseInt(txt));
                        } catch (NumberFormatException x) {
                                errors.add("Invalid INTEGER: " + ctx.start.getText());
                                return new XInteger(ctx.start.getLine(), Integer.MAX_VALUE);
@@ -283,10 +318,12 @@ public class ASTBuilder extends ScriptABaseVisitor<AST> {
                }
                case FLOAT: {
                        try {
-                               if (ctx.size != null && ctx.size.getText().equals("f"))
-                                       return new XFloat(ctx.start.getLine(), Float.parseFloat(ctx.start.getText()));
+                               String txt = ctx.start.getText();
+                               //if (ctx.size != null && ctx.size.getText().equals("f"))
+                               if (txt.endsWith("f"))
+                                       return new XFloat(ctx.start.getLine(), Float.parseFloat(txt));
                                else
-                                       return new XDouble(ctx.start.getLine(), Double.parseDouble(ctx.start.getText()));
+                                       return new XDouble(ctx.start.getLine(), Double.parseDouble(txt));
                        } catch (NumberFormatException x) {
                                errors.add("Invalid REAL: " + ctx.start.getText());
                                return new XFloat(ctx.start.getLine(), Float.NaN);
index d983fce..aa13f6c 100644 (file)
@@ -76,20 +76,28 @@ public class ASTPrinter implements ASTVisitor {
 
        @Override
        public void visitDecl(AST.SDeclare s) {
-               String type = s.type.typeName.orElse(new AST.XReference(s.lineNo, s.type.type.name())).name();
-               s.value.ifPresentOrElse(
-                       v -> {
-                               System.out.printf("%s%s %s = ", d, type, s.name);
-                               v.accept(this);
-                               System.out.println();
-                       },
-                       ()
-                       -> System.out.printf("%s%s %s\n", d, type, s.name));
+               String type = s.type.name.orElse(new AST.XReference(s.lineNo, s.type.type.name())).name();
+
+               System.out.print(d);
+               System.out.print(type);
+
+               for (int i = 0; i < s.list.size(); i++) {
+                       var v = s.list.get(i);
+
+                       if (i != 0)
+                               System.out.print(", ");
+
+                       System.out.print(v.name);
+                       v.value.ifPresent(x -> x.accept(this));
+               }
+               System.out.println();
        }
 
        @Override
        public void visitAssign(AST.SAssign s) {
-               System.out.printf("%s%s = ", d, s.ref.name());
+               System.out.print(d);
+               s.ref.accept(this);
+               System.out.print(" = ");
                s.value.accept(this);
                System.out.println();
        }
@@ -141,10 +149,26 @@ public class ASTPrinter implements ASTVisitor {
        }
 
        @Override
-       public void visit(AST.XCall e) {
+       public void visit(AST.XField e) {
                e.ref.accept(this);
+               System.out.print("[" + e.ref.getClass().getSimpleName() + "]");
+               System.out.println();
+               System.out.print(d);
+               System.out.print(".[!");
+               System.out.print(e.field);
+               System.out.print("]");
+       }
+
+       @Override
+       public void visit(AST.XCall e) {
+               e.ref.ifPresent(x -> {
+                       System.out.print("{");
+                       x.accept(this);
+                       System.out.print("}.");
+               });
+               System.out.print(e.name);
                System.out.print("(");
-               Iterator<AST.Expression> it = e.params.iterator();
+               Iterator<AST.Expression> it = e.args.iterator();
                if (it.hasNext())
                        it.next().accept(this);
                while (it.hasNext()) {
@@ -157,18 +181,19 @@ public class ASTPrinter implements ASTVisitor {
        @Override
        public void visit(AST.XFunction e) {
                System.out.print("function (");
-               Iterator<String> ip = e.params.iterator();
-               Iterator<AST.DType> it = e.types.iterator();
+               Iterator<AST.DParameter> ip = e.params.iterator();
                if (ip.hasNext()) {
-                       System.out.print(it.next().toString());
+                       AST.DParameter p = ip.next();
+                       System.out.print(p.type.toString());
                        System.out.print(" ");
-                       System.out.print(ip.next());
+                       System.out.print(p.param.toString());
                }
                while (ip.hasNext()) {
+                       AST.DParameter p = ip.next();
                        System.out.print(", ");
-                       System.out.print(it.next().toString());
+                       System.out.print(p.type.toString());
                        System.out.print(" ");
-                       System.out.print(ip.next());
+                       System.out.print(p.param.toString());
                }
                System.out.print(") = {\n");
                down();
@@ -179,7 +204,9 @@ public class ASTPrinter implements ASTVisitor {
 
        @Override
        public void visit(AST.XReference e) {
+               System.out.print("<");
                System.out.print(e.name());
+               System.out.print(">");
        }
 
        @Override
index f238a51..b097da1 100644 (file)
@@ -68,6 +68,12 @@ public interface ASTVisitor {
        public default void visit(DType d) {
        }
 
+       public default void visit(DInitialiser d) {
+       }
+
+       public default void visit(DParameter d) {
+       }
+
        // expressions
        public default void visit(Expression e) {
                e.visitChildren(this);
@@ -85,6 +91,10 @@ public interface ASTVisitor {
                e.visitChildren(this);
        }
 
+       public default void visit(XField e) {
+               e.visitChildren(this);
+       }
+
        public default void visit(XCall e) {
                e.visitChildren(this);
        }
index e5705e9..1c7e6bc 100644 (file)
@@ -127,6 +127,7 @@ public class Compiler {
 
                AST.ScriptA script = new ASTBuilder().visitScript(cst);
 
+               System.out.println("printed -->");
                new ASTPrinter().visitScript(script);
                Generator gen = new Generator(name);
                gen.visitScript(script);
index bd35e73..0201287 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.function.Consumer;
 import org.objectweb.asm.ClassWriter;
@@ -46,7 +47,7 @@ import org.objectweb.asm.Type;
  *
  */
 public class Generator implements ASTVisitor {
-       boolean valid = true;
+       boolean valid = false;
        ClassWriter cw;
        MethodVisitor mw;
        int variableID = 1;
@@ -239,6 +240,8 @@ public class Generator implements ASTVisitor {
                                return this;
                        } else {
                                switch (type.getSort()) {
+                               case Type.BOOLEAN:
+                                       return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "toString", "(Z)Ljava/lang/String;", false));
                                case Type.INT:
                                        return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "toString", "(I)Ljava/lang/String;", false));
                                case Type.LONG:
@@ -246,7 +249,7 @@ public class Generator implements ASTVisitor {
                                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));
+                                       return then(mv -> mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "toString", "(D)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));
@@ -287,8 +290,9 @@ public class Generator implements ASTVisitor {
        public Generator(String file) {
                this.file = file;
 
+               imports.importClass(String.class, f -> false, m -> true);
                imports.importClass(System.class, f -> f.getName().matches("out|error"), m -> false);
-               imports.importClass(PrintStream.class, f -> false, m -> m.getName().matches("^print.*"));
+               imports.importClass(PrintStream.class, f -> false, m -> m.getName().matches("^(print|append).*"));
                imports.importClass(Math.class, f -> true, m -> true);
                List<Imports.Import> list = imports.importInstance[Imports.IMPORT_METHODS].getOrDefault(Type.getType(PrintStream.class), Map.of()).entrySet().stream()
                        .filter(e -> e.getKey().matches("^print.*"))
@@ -304,6 +308,7 @@ public class Generator implements ASTVisitor {
                                mv.visitMethodInsn(INVOKEVIRTUAL, m.recv().getInternalName(), m.name(), m.type().getDescriptor(), false);
                        }));
                }
+
        }
 
        @Override
@@ -429,44 +434,47 @@ public class Generator implements ASTVisitor {
 
        @Override
        public void visitDecl(AST.SDeclare s) {
-               System.out.printf("define var %s%s\n", d, s.name);
-               Variable var;
-               Optional<Value> val;
+               for (AST.DInitialiser i: s.list) {
+                       System.out.printf("define var %s%s\n", d, i.name);
+                       Variable var;
+                       Optional<Value> val;
 
-               if (variables.containsKey(s.name)) {
-                       throw new java.lang.IllegalArgumentException(s.lineNo + ": Variable redefined: " + s.name);
-               }
+                       if (variables.containsKey(i.name)) {
+                               throw new java.lang.IllegalArgumentException(s.lineNo + ": Variable redefined: " + i.name);
+                       }
 
-               val = s.value.map(x -> visitExpression(x));
+                       val = i.value.map(x -> visitExpression(x));
 
-               if (s.type.type == AST.XType.OBJECT) {
-                       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 = 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(var.type().getOpcode(ISTORE), var.id);
-                       });
+                       if (s.type.type == AST.XType.OBJECT) {
+                               var = addVariable(i.name, Type.getObjectType(s.type.name.get().name()));
+                               val.ifPresent(v -> {
+                                       v.insert.accept(mw);
+                                       mw.visitVarInsn(ASTORE, var.id);
+                               });
+                       } else {
+                               var = addVariable(i.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(var.type().getOpcode(ISTORE), var.id);
+                               });
+                       }
+                       variables.put(var.name, var);
                }
-               variables.put(var.name, var);
        }
 
        @Override
        public void visitAssign(AST.SAssign s) {
-               System.out.printf("%s%s = ", d, s.ref.name());
+               //System.out.printf("%s%s = ", d, s.ref.name());
 
-               Variable var = variables.get(s.ref.name());
+               Value var = visitExpression(s.ref);
+               //      Variable var = variables.get(s.ref.name());
                Value val = visitExpression(s.value);
 
                val = val.promote(var.type);
                val.insert.accept(mw);
-               mw.visitVarInsn(var.type.getOpcode(ISTORE), var.id);
+               //mw.visitVarInsn(var.type.getOpcode(ISTORE), var.id);
        }
 
        @Override
@@ -643,7 +651,7 @@ public class Generator implements ASTVisitor {
                                stack.addFirst(new Value(STRING_TYPE, 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);
+                                       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;", false);
                                }));
                                return;
                        }
@@ -730,15 +738,26 @@ public class Generator implements ASTVisitor {
 
        @Override
        public void visit(AST.XCall e) {
-               System.out.println(e);
-               // TODO: how to resolve parts of expression
-               List<Value> args = e.params.stream().map(this::visitExpression).toList();
+               List<Value> args = e.args.stream().map(this::visitExpression).toList();
+
+               //imports.dump();
+               if (e.ref.isPresent()) {
+                       Value recv = visitExpression(e.ref.get());
+
+                       System.out.printf("receiver: %s\n", recv);
+                       Optional<Value> im = imports.findImport(recv.type(), e.name, args);
 
-               if (e.ref.part.length == 1) {
-                       stack.push(imports.findImport(e.ref.name(), args).orElseThrow());
-                       // or func variable
+                       if (im.isPresent()) {
+                               Value call = im.get();
+                               stack.push(new Value(call.type(), mv -> {
+                                       recv.insert.accept(mv);
+                                       call.insert.accept(mv);
+                               }));
+                       } else {
+                               throw new NoSuchElementException();
+                       }
                } else {
-                       throw new UnsupportedOperationException("namespace dereferencing unimplemented");
+                       stack.push(imports.findImport(e.name, args).orElseThrow());
                }
        }
 
@@ -746,7 +765,7 @@ public class Generator implements ASTVisitor {
        public void visit(AST.XFunction e) {
                // unimplemented
                System.out.print("function (");
-               Iterator<String> it = e.params.iterator();
+               Iterator<AST.DParameter> it = e.params.iterator();
                if (it.hasNext())
                        System.out.print(it.next());
                while (it.hasNext()) {
@@ -760,6 +779,11 @@ public class Generator implements ASTVisitor {
                System.out.printf("%s}\n", d);
        }
 
+       @Override
+       public void visit(AST.XField e) {
+               System.exit(2);
+       }
+
        @Override
        public void visit(AST.XReference e) {
                Variable var = variables.get(e.name());
index 122344f..eccc21e 100644 (file)
@@ -75,6 +75,10 @@ public class Imports {
        static final int IMPORT_FIELDS = 0;
        static final int IMPORT_METHODS = 1;
        static final int IMPORT_CONSTRUCTORS = 2;
+       /**
+        * Link types to their parents.
+        */
+       Map<Type, Type> parentClass = new HashMap<>();
        Map<Type, Map<String, List<Import>>> importInstance[] = IntStream.range(0, 3).mapToObj(i -> new HashMap<>()).toArray(Map[]::new);
        Map<Type, Map<String, List<Import>>> importStatic[] = IntStream.range(0, 3).mapToObj(i -> new LinkedHashMap<>()).toArray(Map[]::new);
 
@@ -109,6 +113,14 @@ public class Imports {
        // TODO: primitive constants are fully resolved at compile time in java, without the GETSTATIC
        public void importClass(Class<?> itype, Predicate<Field> fields, Predicate<Method> methods) {
                Type irecv = Type.getType(itype);
+
+               Class<?> ptype = itype;
+               while (ptype != Object.class) {
+                       Class<?> ntype = ptype.getSuperclass();
+                       parentClass.put(Type.getType(ptype), Type.getType(ntype));
+                       ptype = ntype;
+               }
+
                for (Field f: itype.getFields()) {
                        if (fields.test(f)) {
                                Type recv = Type.getType(f.getDeclaringClass());
@@ -190,9 +202,9 @@ public class Imports {
                        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)),
-                               String.join(", ", Stream.of(argb).map(Object::toString).toArray(String[]::new)));
+                       //System.out.printf("match arguments:\n %s\n %s\n",
+                       //      String.join(", ", Stream.of(arga).map(Object::toString).toArray(String[]::new)),
+                       //      String.join(", ", Stream.of(argb).map(Object::toString).toArray(String[]::new)));
 
                        if (arga.length == argb.length) {
                                for (int i = 0; i < arga.length; i++) {
@@ -211,12 +223,12 @@ public class Imports {
                                                // anything can be converted to string
                                                score += 6;
                                        } else {
-                                               System.out.printf(" -> no match\n");
+                                               //System.out.printf(" -> no match\n");
                                                return new Match(im, -1);
                                        }
                                }
                        }
-                       System.out.printf(" -> score %d\n", score);
+                       //System.out.printf(" -> score %d\n", score);
                        return new Match(im, score);
                };
        }
@@ -255,14 +267,37 @@ public class Imports {
                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);
-                       }
-               }
+       //      for (var map: importInstance[IMPORT_METHODS].entrySet()) {
+       //              System.out.println(map.getKey());
+       //              for (var im: map.getValue().getOrDefault(name, List.of())) {
+       //                      System.out.printf(" ? %s\n", im);
+       //              }
+       //      }
 
-               return importStatic[IMPORT_METHODS].values().stream()
+               var table = importInstance[IMPORT_METHODS];
+               List<Type> list = new ArrayList<>();
+               Type ptype = recv;
+               do {
+                       list.add(ptype);
+                       ptype = parentClass.get(ptype);
+               } while (ptype != null);
+
+               return list.stream()
+                       .peek(m-> System.out.println("c " + m))
+                       .map(m -> table.getOrDefault(m, Map.of()))
+                       .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));
+               /*
+               return importInstance[IMPORT_METHODS].values().stream()
                        .flatMap(m -> m.getOrDefault(name, List.of()).stream())
                        .peek(m -> System.out.println("? " + m))
                        .map(match(arga))
@@ -274,6 +309,7 @@ public class Imports {
                                return m;
                        })
                        .map(m -> m.im.value(args));
+*/
        }
 
        void dump() {
index cd0e702..d6735f6 100644 (file)
@@ -21,9 +21,10 @@ statement
                ( ELSE '{' rest=statements? '}' )?                              # ifStatement
        | (label=ID ':')? WHILE '(' valueExpr ')' '{' when=statements? '}'      # whileStatement
        | (label=ID ':')? '{' when=statements '}'                               # blockStatement
-       | type ID ( '=' valueExpr ) ?                                           # declStatement
-       | reference '=' valueExpr                                               # assignStatement
-       | callExpr                                                              # callStatement
+       | type declExpr                                                         # declStatement
+       | valueExpr '=' valueExpr                                               # assignStatement
+       | left=valueExpr '.' ID args=argsExpr                                   # callStatement
+       | ID args=argsExpr                                                      # callStatement
        | CONTINUE (label=ID) ?                                                 # breakStatement
        | BREAK (label=ID) ?                                                    # breakStatement
        | RETURN valueExpr ?                                                    # returnStatement
@@ -32,21 +33,37 @@ statement
 // This more or less follows c operator precedence
 valueExpr
        : '(' valueExpr ')'                                                     # valueGroupExpr
-       | op=('!'|'-'|'+'|'~') rightValue=valueExpr                             # valueUnaryExpr
-       | leftValue=valueExpr op=('*'|'/'|'%') rightValue=valueExpr             # valueBinaryExpr
-       | leftValue=valueExpr op=('+'|'-') rightValue=valueExpr                 # valueBinaryExpr
-       | leftValue=valueExpr op=('<<'|'<<<'|'>>') rightValue=valueExpr         # valueBinaryExpr
-       | leftValue=valueExpr op=('&'|'|') rightValue=valueExpr                 # valueBinaryExpr
-       | leftValue=valueExpr op=('&&'|'||'|'^^') rightValue=valueExpr          # valueBinaryExpr
-       | leftValue=valueExpr op=(LT|LE|GT|GE|EQ|NE) rightValue=valueExpr       # valueBinaryExpr
+       | func=funcExpr                                                         # valueFunctionExpr
+       | left=valueExpr '.' ID args=argsExpr                                   # valueCallExpr
+       | ID args=argsExpr                                                      # valueCallExpr
+       | NEW ref=reference args=argsExpr                                       # valueNewExpr
+       | left=valueExpr '.' ID                                                 # valueFieldExpr
+       | op=('!'|'-'|'+'|'~') right=valueExpr                                  # valueUnaryExpr
+       | left=valueExpr op=('*'|'/'|'%') right=valueExpr                       # valueBinaryExpr
+       | left=valueExpr op=('+'|'-') right=valueExpr                           # valueBinaryExpr
+       | left=valueExpr op=('<<'|'<<<'|'>>') right=valueExpr                   # valueBinaryExpr
+       | left=valueExpr op=('&'|'|') right=valueExpr                           # valueBinaryExpr
+       | left=valueExpr op=(LT|LE|GT|GE|EQ|NE) right=valueExpr                 # valueBinaryExpr
+       | left=valueExpr op=('&&'|'||'|'^^') right=valueExpr                    # valueBinaryExpr
        | lit=literal                                                           # valueLiteralExpr
        | ref=reference                                                         # valueReferenceExpr
-       | call=callExpr                                                         # valueCallExpr
-       | func=funcExpr                                                         # valueFunctionExpr
        ;
 
-callExpr       : NEW ? reference '(' (valueExpr (',' valueExpr)*)? ')';
-funcExpr       : FUNC rval=type '(' (type ID (',' type ID) *) ? ')' '{' statements? '}';
+funcExpr       : FUNC rval=type '(' paramExpr? ')' '{' statements? '}';
+
+argsExpr
+       : '(' (valueExpr (',' valueExpr)*)? ')'
+       ;
+
+declExpr
+       : id=ID ('=' val=valueExpr)?
+       | declExpr ',' id=ID ('=' val=valueExpr)?
+        ;
+
+paramExpr
+       : type id=ID ('=' val=valueExpr) ?
+       | paramExpr ',' type id=ID ('=' val=valueExpr) ?
+       ;
 
 IF             : 'if';
 ELSE           : 'else';
@@ -68,7 +85,7 @@ DBL           : 'double';
 LNG            : 'long';
 
 type           : INT | LNG | FLT | DBL | STR | BLN | reference;
-literal                : INTEGER size='L'? | FLOAT size='f'? | STRING | TRUE | FALSE;
+literal                : INTEGER | FLOAT | STRING | TRUE | FALSE;
 reference      : ID ('.' ID)*;
 
 TRUE           : 'true';
@@ -100,11 +117,11 @@ AAND              : '&&';
 OOR            : '||';
 XXOR           : '^^';
 
-INTEGER                : [0-9]+;
-FLOAT          : [0-9]+ '.' ([0-9]+)? ([eE] [+-]? [0-9]+)?;
-STRING         : '"' (~[\\"] | '\\' [\\"])* '"'
-                       | '\'' (~[\\'] | '\\' [\\'])* '\'';
 ID             : [a-zA-Z_][0-9a-zA-Z_$]*;
+INTEGER                : [0-9]+ 'L'?;
+FLOAT          : [0-9]+ '.' ([0-9]+)? ([eE] [+-]? [0-9]+)? ('f'|'d')?;
+STRING         : '"' (~[\\"] | '\\' [\\"])* '"'
+               | '\'' (~[\\'] | '\\' [\\'])* '\'';
 
 NL             : ( '\n' | '\r\n' | '\r' ) -> channel(HIDDEN);
 COMMENT                : '#' ~[\r\n]* -> channel(HIDDEN);