From 6131567bf31701218a5c5b2e88b54943bf0ab874 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Tue, 11 Apr 2023 20:10:53 +0930 Subject: [PATCH] Checkpoint ongoing work - 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 --- .../classes/au/notzed/scripta/AST.java | 130 +++++++++++++----- .../classes/au/notzed/scripta/ASTBuilder.java | 117 ++++++++++------ .../classes/au/notzed/scripta/ASTPrinter.java | 63 ++++++--- .../classes/au/notzed/scripta/ASTVisitor.java | 10 ++ .../classes/au/notzed/scripta/Compiler.java | 1 + .../classes/au/notzed/scripta/Generator.java | 98 ++++++++----- .../classes/au/notzed/scripta/Imports.java | 60 ++++++-- src/notzed.scripta/gen/ScriptA.g4 | 55 +++++--- 8 files changed, 377 insertions(+), 157 deletions(-) diff --git a/src/notzed.scripta/classes/au/notzed/scripta/AST.java b/src/notzed.scripta/classes/au/notzed/scripta/AST.java index 264c782..8c07d50 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/AST.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/AST.java @@ -206,14 +206,12 @@ public abstract class AST { public static class SDeclare extends Statement { final DType type; - final String name; - final Optional value; + final List list; - public SDeclare(int lineNo, DType type, String id, Optional value) { + public SDeclare(int lineNo, DType type, List 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 typeName; + final Optional name; + + public DType(int lineNo, XType type, Optional 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 value; + + public DInitialiser(int lineNo, String name, Optional 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 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 params; + Optional ref; + String name; + List args; - public XCall(int lineNo, boolean constructor, XReference ref, List params) { + public XCall(int lineNo, boolean constructor, Optional ref, String name, List 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 types; - final List params; + final List params; final Statements statements; - public XFunction(int lineNo, DType rval, List types, List params, Statements statements) { + public XFunction(int lineNo, DType rval, List params, Statements statements) { super(lineNo); - this.params = params; this.rval = rval; - this.types = types; + this.params = params; this.statements = statements; } diff --git a/src/notzed.scripta/classes/au/notzed/scripta/ASTBuilder.java b/src/notzed.scripta/classes/au/notzed/scripta/ASTBuilder.java index 2ccc03b..41590cc 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/ASTBuilder.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/ASTBuilder.java @@ -35,7 +35,9 @@ public class ASTBuilder extends ScriptABaseVisitor { @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 { return label != null ? Optional.of(label.getText()) : Optional.empty(); } + Optional 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 { type == XType.OBJECT ? Optional.of(visitReference(ctx.reference())) : Optional.empty()); } + List visitInitialisers(DeclExprContext ctx, List 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 { @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 visitParams(ParamExprContext ctx, List 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 { 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 { 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)), + "", + 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 { 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 { 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 { 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 { } 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); diff --git a/src/notzed.scripta/classes/au/notzed/scripta/ASTPrinter.java b/src/notzed.scripta/classes/au/notzed/scripta/ASTPrinter.java index d983fce..aa13f6c 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/ASTPrinter.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/ASTPrinter.java @@ -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 it = e.params.iterator(); + Iterator 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 ip = e.params.iterator(); - Iterator it = e.types.iterator(); + Iterator 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 diff --git a/src/notzed.scripta/classes/au/notzed/scripta/ASTVisitor.java b/src/notzed.scripta/classes/au/notzed/scripta/ASTVisitor.java index f238a51..b097da1 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/ASTVisitor.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/ASTVisitor.java @@ -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); } diff --git a/src/notzed.scripta/classes/au/notzed/scripta/Compiler.java b/src/notzed.scripta/classes/au/notzed/scripta/Compiler.java index e5705e9..1c7e6bc 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/Compiler.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/Compiler.java @@ -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); diff --git a/src/notzed.scripta/classes/au/notzed/scripta/Generator.java b/src/notzed.scripta/classes/au/notzed/scripta/Generator.java index bd35e73..0201287 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/Generator.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/Generator.java @@ -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 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 val; + for (AST.DInitialiser i: s.list) { + System.out.printf("define var %s%s\n", d, i.name); + Variable var; + Optional 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 args = e.params.stream().map(this::visitExpression).toList(); + List 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 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 it = e.params.iterator(); + Iterator 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()); diff --git a/src/notzed.scripta/classes/au/notzed/scripta/Imports.java b/src/notzed.scripta/classes/au/notzed/scripta/Imports.java index 122344f..eccc21e 100644 --- a/src/notzed.scripta/classes/au/notzed/scripta/Imports.java +++ b/src/notzed.scripta/classes/au/notzed/scripta/Imports.java @@ -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 parentClass = new HashMap<>(); Map>> importInstance[] = IntStream.range(0, 3).mapToObj(i -> new HashMap<>()).toArray(Map[]::new); Map>> 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 fields, Predicate 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 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() { diff --git a/src/notzed.scripta/gen/ScriptA.g4 b/src/notzed.scripta/gen/ScriptA.g4 index cd0e702..d6735f6 100644 --- a/src/notzed.scripta/gen/ScriptA.g4 +++ b/src/notzed.scripta/gen/ScriptA.g4 @@ -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); -- 2.39.2