diff options
author | geno <gabriele.genovese2@studio.unibo.it> | 2024-06-27 18:20:34 +0200 |
---|---|---|
committer | geno <gabriele.genovese2@studio.unibo.it> | 2024-06-27 18:20:34 +0200 |
commit | eb7fb04d2dfadd004fa86f28da42681e0038df06 (patch) | |
tree | 1bba3962300083017673c5d689a5d2bf1652109d | |
parent | 095a2cb4e9abb88805aac3271874bc512108ff96 (diff) |
left, right = 1, 2 assignment covered
sfaccimm ho fatto refactoring dell exprlist
-rw-r--r-- | src/ast/Python3VisitorImpl.java | 192 | ||||
-rw-r--r-- | src/ast/nodes/AssignmentNode.java | 21 | ||||
-rw-r--r-- | src/ast/nodes/AtomNode.java | 22 | ||||
-rw-r--r-- | src/ast/nodes/ExprListNode.java | 61 | ||||
-rw-r--r-- | src/ast/nodes/ForStmtNode.java | 12 | ||||
-rw-r--r-- | src/ast/nodes/ParamdefNode.java | 2 | ||||
-rw-r--r-- | src/ast/nodes/TestlistCompNode.java | 61 | ||||
-rw-r--r-- | test/trailers.py | 13 |
8 files changed, 262 insertions, 122 deletions
diff --git a/src/ast/Python3VisitorImpl.java b/src/ast/Python3VisitorImpl.java index d4b4fbf..5b812ea 100644 --- a/src/ast/Python3VisitorImpl.java +++ b/src/ast/Python3VisitorImpl.java @@ -12,20 +12,19 @@ import org.antlr.v4.runtime.tree.TerminalNode; * Overrides each `visitNODE` method from the base class. */ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { + /** * Since a root can be a simple_stmts or a compound_stmt, this method * returns a new `RootNode` with a list of them. * - * ``` - * root : NEWLINE* (simple_stmts | compound_stmt)* EOF; - * ``` + * ``` root : NEWLINE* (simple_stmts | compound_stmt)* EOF; ``` */ public Node visitRoot(RootContext ctx) { ArrayList<Node> childs = new ArrayList<Node>(); - - for (int i = 0; i < ctx.getChildCount(); i++){ + + for (int i = 0; i < ctx.getChildCount(); i++) { var child = ctx.getChild(i); - + if (child instanceof Simple_stmtsContext) { childs.add(visit((Simple_stmtsContext) child)); } else if (child instanceof Compound_stmtContext) { @@ -39,9 +38,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `SimpleStmtsNode`, made by an array of SimpleStmtNode * - * ``` - * simple_stmts : simple_stmt (';' simple_stmt)* ';'? NEWLINE ; - * ``` + * ``` simple_stmts : simple_stmt (';' simple_stmt)* ';'? NEWLINE ; ``` */ public Node visitSimple_stmts(Simple_stmtsContext ctx) { ArrayList<Node> stmts = new ArrayList<Node>(); @@ -57,9 +54,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `CompoundNode`. It can be built by a different kind of * statements, so only one of theme won't be null. * - * ``` - * compound_stmt : if_stmt | while_stmt | for_stmt | funcdef ; - * ``` + * ``` compound_stmt : if_stmt | while_stmt | for_stmt | funcdef ; ``` */ public Node visitCompound_stmt(Compound_stmtContext ctx) { Node ifStmt = null; @@ -90,9 +85,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `SimpleStmtNode`. It can be built by a different kind of * statements, so only one of theme won't be null. * - * ``` - * simple_stmt : assignment | expr | return_stmt | import_stm ; - * ``` + * ``` simple_stmt : assignment | expr | return_stmt | import_stm ; ``` */ public Node visitSimple_stmt(Simple_stmtContext ctx) { Node assignment = null; @@ -122,10 +115,8 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns an `AssignmentNode`. It's made by left side, an assignment and a * right side. - * - * ``` - * assignment : exprlist augassign exprlist ; - * ``` + * + * ``` assignment : exprlist augassign exprlist ; ``` */ public Node visitAssignment(AssignmentContext ctx) { Node lhr = visit(ctx.exprlist(0)); @@ -138,9 +129,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `ReturnStmtNode`. The returned exprlist can be null. * - * ``` - * return_stmt : 'return' exprlist? ; - * ``` + * ``` return_stmt : 'return' exprlist? ; ``` */ public Node visitReturn_stmt(Return_stmtContext ctx) { Node exprList = null; @@ -155,10 +144,8 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `ImportNode`. An import can be made in different ways so we * check the way in a module is imported (by from, by alias or by star). * - * ``` - * import_stm : 'import' dotted_name ('as' NAME)? - * | 'from' dotted_name 'import' (NAME (',' NAME)* | '*') ; - * ``` + * ``` import_stm : 'import' dotted_name ('as' NAME)? | 'from' dotted_name + * 'import' (NAME (',' NAME)* | '*') ; ``` */ public Node visitImport_stm(Import_stmContext ctx) { boolean isFrom = ctx.FROM() != null; @@ -179,9 +166,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `DottedNameNode` used in `import_stm`. * - * ``` - * dotted_name : NAME ('.' NAME)* ; - * ``` + * ``` dotted_name : NAME ('.' NAME)* ; ``` */ public Node visitDotted_name(Dotted_nameContext ctx) { ArrayList<TerminalNode> names = new ArrayList<TerminalNode>(); @@ -196,9 +181,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `FuncdefNode`. A paramlist can be null. * - * ``` - * funcdef : 'def' NAME '(' paramlist? ')' ':' block ; - * ``` + * ``` funcdef : 'def' NAME '(' paramlist? ')' ':' block ; ``` */ public Node visitFuncdef(FuncdefContext ctx) { Node paramlist = null; @@ -216,9 +199,8 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `ParamlistNode`. We ignore the paramdef with default values * (eg: is_used=False) because there is no test which uses this feature. * - * ``` - * paramlist : paramdef ('=' expr)? (',' paramdef ('=' expr)?)* ; - * + * ``` paramlist : paramdef ('=' expr)? (',' paramdef ('=' expr)?)* ; + * * ``` */ public Node visitParamlist(ParamlistContext ctx) { @@ -235,9 +217,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `ParamdefNode`. We ignore the paramdef with type annotation * (eg: x : int) because there is no test which uses this feature. * - * ``` - * paramdef : NAME (':' expr)? ; - * ``` + * ``` paramdef : NAME (':' expr)? ; ``` */ public Node visitParamdef(ParamdefContext ctx) { return new ParamdefNode(ctx.NAME().toString()); @@ -247,11 +227,8 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns an `AugassignNode`. We don't provide all kinds of assignment * below. * - * ``` - * augassign : '=' | '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | - * '^=' | '<<=' | '>>=' | '**=' | '//=' - * ; - * ``` + * ``` augassign : '=' | '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | + * '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' ; ``` */ public Node visitAugassign(AugassignContext ctx) { Node x = null; @@ -285,17 +262,15 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { } else if (ctx.IDIV_ASSIGN() != null) { x = new AugassignNode(ctx.IDIV_ASSIGN()); } - + return x; } /** - * Returns a `IfNode`. - * FIXME: add support for elif statement. + * Returns a `IfNode`. FIXME: add support for elif statement. * - * ``` - * if_stmt : 'if' expr ':' block ('elif' expr ':' block)* ('else' ':' block)? ; - * ``` + * ``` if_stmt : 'if' expr ':' block ('elif' expr ':' block)* ('else' ':' + * block)? ; ``` */ public Node visitIf_stmt(If_stmtContext ctx) { var blocks = ctx.block(); @@ -312,9 +287,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `WhileStmtNode`. We do not provide 'else' branch. * - * ``` - * while_stmt : 'while' expr ':' block ('else' ':' block)? ; - * ``` + * ``` while_stmt : 'while' expr ':' block ('else' ':' block)? ; ``` */ public Node visitWhile_stmt(While_stmtContext ctx) { Node expr = visit(ctx.expr()); @@ -328,9 +301,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `ForSmtNode`. We do not provide 'else' branch. * - * ``` - * for_stmt : 'for' exprlist ':' block ('else' ':' block)? ; - * ``` + * ``` for_stmt : 'for' exprlist ':' block ('else' ':' block)? ; ``` */ public Node visitFor_stmt(For_stmtContext ctx) { Node exprList = visit(ctx.exprlist()); @@ -345,17 +316,15 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns a `BlockNode`. A block can be be a simple_stmts or a list of * simple_stms and/or compound_stmt, so we just use a list for each kind. * - * ``` - * block : simple_stmts - * | NEWLINE INDENT (simple_stmts | compound_stmt)+ DEDENT ; - * ``` + * ``` block : simple_stmts | NEWLINE INDENT (simple_stmts | compound_stmt)+ + * DEDENT ; ``` */ public Node visitBlock(BlockContext ctx) { ArrayList<Node> childs = new ArrayList<Node>(); - for (int i = 0; i < ctx.getChildCount(); i++){ + for (int i = 0; i < ctx.getChildCount(); i++) { var child = ctx.getChild(i); - + if (child instanceof Simple_stmtsContext) { childs.add(visit((Simple_stmtsContext) child)); } else if (child instanceof Compound_stmtContext) { @@ -369,10 +338,8 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { /** * Returns a `CompNode`. It should never be null. * - * ``` - * comp_op : '<' | '>' | '==' | '>=' | '<=' | '<>' | '!=' | 'in' | 'not' 'in' | - * 'is' | 'is' 'not' ; - * ``` + * ``` comp_op : '<' | '>' | '==' | '>=' | '<=' | '<>' | '!=' | 'in' | 'not' + * 'in' | 'is' | 'is' 'not' ; ``` */ public Node visitComp_op(Comp_opContext ctx) { Node comp = null; @@ -404,13 +371,11 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { * Returns an `ExprNode`. An expession can be a different kind of * sub-expression. We do not provide all kinds of expr(s). * - * ``` - * expr : atom trailer* | expr '**' expr | ('+' | '-' | '~')+ expr | expr ('*' | - * '@' | '/' | '%' | '//') expr | expr ('+' | '-') expr | expr ('<<' | '>>') - * expr | expr '&' expr | expr '^' expr | expr '|' expr | 'not' expr | expr - * comp_op expr | expr 'and' expr | expr 'or' expr | expr 'if' expr 'else' expr - * ; - * ``` + * ``` expr : atom trailer* | expr '**' expr | ('+' | '-' | '~')+ expr | + * expr ('*' | '@' | '/' | '%' | '//') expr | expr ('+' | '-') expr | expr + * ('<<' | '>>') expr | expr '&' expr | expr '^' expr | expr '|' expr | + * 'not' expr | expr comp_op expr | expr 'and' expr | expr 'or' expr | expr + * 'if' expr 'else' expr ; ``` */ public Node visitExpr(ExprContext ctx) { Node atom = null; @@ -459,42 +424,52 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { } /** - * Returns an `AtomNode`. - * FIXME: add support for testlist_comp + * Returns an `AtomNode`. FIXME: add support for testlist_comp * - * ``` - * atom : '(' testlist_comp? ')' | '[' testlist_comp? ']' | '{' testlist_comp? - * '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' ; - * ``` + * ``` atom : '(' testlist_comp? ')' | '[' testlist_comp? ']' | '{' + * testlist_comp? '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | + * 'False' ; ``` */ public Node visitAtom(AtomContext ctx) { + Testlist_compContext tlc = ctx.testlist_comp(); if (ctx.NUMBER() != null) { - return new AtomNode(ctx.NUMBER().toString()); + return new AtomNode(ctx.NUMBER().toString(), null); } else if (ctx.TRUE() != null) { - return new AtomNode(ctx.TRUE().toString()); + return new AtomNode(ctx.TRUE().toString(), null); } else if (ctx.FALSE() != null) { - return new AtomNode(ctx.FALSE().toString()); + return new AtomNode(ctx.FALSE().toString(), null); } else if (ctx.NAME() != null) { - return new AtomNode(ctx.NAME().toString()); - } else if (ctx.STRING() != null) { - + return new AtomNode(ctx.NAME().toString(), null); + } else if (!ctx.STRING().isEmpty()) { var varName = ""; for (var x : ctx.STRING()) { varName += x; } + return new AtomNode(varName, null); + } else if (ctx.OPEN_BRACE() != null && ctx.CLOSE_BRACE() != null) { + return manageTlc(tlc); + } else if (ctx.OPEN_BRACK() != null && ctx.CLOSE_BRACK() != null) { + return manageTlc(tlc); + } else if (ctx.OPEN_PAREN() != null && ctx.CLOSE_PAREN() != null) { + return manageTlc(tlc); + } + return new AtomNode(ctx.NONE().toString(), null); + } - return new AtomNode(varName); + public AtomNode manageTlc(Testlist_compContext tlc) { + if (tlc != null) { + Node testlist_comp = visit(tlc); + return new AtomNode(null, testlist_comp); + } else { + return new AtomNode(null, null); } - return new AtomNode(ctx.NONE().toString()); } /** * Returns an `TrailerNode`. * - * ``` - * trailer : '(' arglist? ')' | '[' expr (',' expr)* ','? ']' | '.' NAME | '[' - * expr? ':' expr? (':' expr? )? ']' ; - * ``` + * ``` trailer : '(' arglist? ')' | '[' expr (',' expr)* ','? ']' | '.' NAME + * | '[' expr? ':' expr? (':' expr? )? ']' ; ``` */ public Node visitTrailer(TrailerContext ctx) { Node arglist = null; @@ -517,31 +492,24 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { } /** - * Returns a `Node`. - * FIXME: what to do in case of list?? + * Returns a `Node`. FIXME: what to do in case of list?? * - * ``` - * exprlist : expr (',' expr )* ','? ; - * ``` + * ``` exprlist : expr (',' expr )* ','? ; ``` */ public Node visitExprlist(ExprlistContext ctx) { - Node exp; + ArrayList<Node> exprlist = new ArrayList<Node>(); - if (ctx.expr(0).expr(0) != null){ - exp = visit(ctx.expr(0).expr(0)); - } else { - exp = visit(ctx.expr(0)); + for (ExprContext c : ctx.expr()) { + exprlist.add(visit(c)); } - return exp; + return new ExprListNode(exprlist); } /** * Returns a `ArglistNode`. * - * ``` - * arglist : argument (',' argument)* ','? ; - * ``` + * ``` arglist : argument (',' argument)* ','? ; ``` */ public Node visitArglist(ArglistContext ctx) { ArrayList<Node> arguments = new ArrayList<Node>(); @@ -552,4 +520,20 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> { return new ArglistNode(arguments); } + + /** + * Returns a `TestlistCompNode`. + * + * ``` testlist_comp : expr (comp_for | (',' expr)* ','?) ; ``` + */ + public Node visitTestlist_comp(Testlist_compContext ctx) { + // TODO: implement comp_for + ArrayList<Node> exprlist = new ArrayList<Node>(); + + for (ExprContext c : ctx.expr()) { + exprlist.add(visit(c)); + } + + return new TestlistCompNode(exprlist); + } } diff --git a/src/ast/nodes/AssignmentNode.java b/src/ast/nodes/AssignmentNode.java index 3d597ef..07966c3 100644 --- a/src/ast/nodes/AssignmentNode.java +++ b/src/ast/nodes/AssignmentNode.java @@ -10,14 +10,14 @@ import semanticanalysis.SymbolTable; */ public class AssignmentNode implements Node { - private ExprNode lhr; + private ExprListNode lhr; private Node assign; - private ExprNode rhr; + private ExprListNode rhr; public AssignmentNode(Node lhr, Node assign, Node rhr) { - this.lhr = (ExprNode) lhr; + this.lhr = (ExprListNode) lhr; this.assign = assign; - this.rhr = (ExprNode) rhr; + this.rhr = (ExprListNode) rhr; } @Override @@ -28,7 +28,18 @@ public class AssignmentNode implements Node { errors.addAll(assign.checkSemantics(ST, _nesting)); errors.addAll(rhr.checkSemantics(ST, _nesting)); - ST.insert(lhr.getId(), rhr.typeCheck(), _nesting, ""); + int lsize = lhr.getSize(); + int rsize = rhr.getSize(); + + if (lsize == rsize) { + for (int i = 0; i < lsize; i++) { + ExprNode latom = (ExprNode) lhr.getElem(i); + ExprNode ratom = (ExprNode) rhr.getElem(i); + ST.insert(latom.getId(), ratom.typeCheck(), _nesting, ""); + } + } else { + errors.add(new SemanticError("ValueError: different size of left or right side assignment")); + } return errors; } diff --git a/src/ast/nodes/AtomNode.java b/src/ast/nodes/AtomNode.java index 3c2b1eb..592aac4 100644 --- a/src/ast/nodes/AtomNode.java +++ b/src/ast/nodes/AtomNode.java @@ -13,9 +13,11 @@ import semanticanalysis.SymbolTable; public class AtomNode implements Node { protected String val; + protected TestlistCompNode exprlist; - public AtomNode(String val) { + public AtomNode(String val, Node exprlist) { this.val = val; + this.exprlist = (TestlistCompNode) exprlist; } public String getId() { @@ -26,10 +28,16 @@ public class AtomNode implements Node { public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) { var errors = new ArrayList<SemanticError>(); - if ((this.typeCheck() instanceof AtomType) && ST.nslookup(this.getId()) < 0) { - errors.add(new SemanticError("name '" + this.getId() + "' is not defined.")); - } else { - // System.out.println("exist " + this.getId()); + if (val != null) { + if ((this.typeCheck() instanceof AtomType) && ST.nslookup(this.getId()) < 0) { + errors.add(new SemanticError("name '" + this.getId() + "' is not defined.")); + } else { + // System.out.println("exist " + this.typeCheck()); + } + } + + if (exprlist != null) { + errors.addAll(exprlist.checkSemantics(ST, _nesting)); } return errors; @@ -38,6 +46,10 @@ public class AtomNode implements Node { // ENHANCE: return more specific types @Override public Type typeCheck() { + if (this.val == null) { + return new VoidType(); + } + Pattern booleanVariable = Pattern.compile("^(True|False)$"); Pattern continueBreakVariable = Pattern.compile("^(continue|break)$"); // this regex should match every possible atom name written in this format: CHAR (CHAR | DIGIT)* diff --git a/src/ast/nodes/ExprListNode.java b/src/ast/nodes/ExprListNode.java new file mode 100644 index 0000000..c1a2ebc --- /dev/null +++ b/src/ast/nodes/ExprListNode.java @@ -0,0 +1,61 @@ +package ast.nodes; + +import ast.types.*; +import java.util.ArrayList; +import semanticanalysis.SemanticError; +import semanticanalysis.SymbolTable; + +/** + * Node for the `expr_list` statement of the grammar. + */ +public class ExprListNode implements Node { + + private final ArrayList<Node> exprs; + + public ExprListNode(ArrayList<Node> _exprs) { + this.exprs = _exprs; + } + + @Override + public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) { + ArrayList<SemanticError> errors = new ArrayList(); + + for (var param : exprs) { + errors.addAll(param.checkSemantics(ST, _nesting)); + } + + return errors; + } + + public int getSize() { + return exprs.size(); + } + + public Node getElem(int i) { + return exprs.get(i); + } + + @Override + public Type typeCheck() { + return new VoidType(); + } + + // TODO: code generation for expr list + @Override + public String codeGeneration() { + return ""; + } + + @Override + public String toPrint(String prefix) { + String str = prefix + "Paramlist\n"; + + prefix += " "; + for (var param : exprs) { + str += param.toPrint(prefix); + } + + return str; + } + +} diff --git a/src/ast/nodes/ForStmtNode.java b/src/ast/nodes/ForStmtNode.java index 28fe783..610d0a0 100644 --- a/src/ast/nodes/ForStmtNode.java +++ b/src/ast/nodes/ForStmtNode.java @@ -1,20 +1,20 @@ package ast.nodes; +import ast.types.*; import java.util.ArrayList; - import semanticanalysis.SemanticError; import semanticanalysis.SymbolTable; -import ast.types.*; /** * Node for the `for_stmt` statement of the grammar. */ public class ForStmtNode implements Node { - private Node exprList; + + private ExprListNode exprList; private Node block; public ForStmtNode(Node exprList, Node block) { - this.exprList = exprList; + this.exprList = (ExprListNode) exprList; this.block = block; } @@ -22,9 +22,7 @@ public class ForStmtNode implements Node { public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) { ArrayList<SemanticError> errors = new ArrayList<SemanticError>(); - ExprNode expr = (ExprNode) exprList; - - ST.insert(expr.getId(), expr.typeCheck(), _nesting, ""); + // ST.insert(expr.getId(), expr.typeCheck(s), _nesting, ""); errors.addAll(exprList.checkSemantics(ST, _nesting)); errors.addAll(block.checkSemantics(ST, _nesting)); diff --git a/src/ast/nodes/ParamdefNode.java b/src/ast/nodes/ParamdefNode.java index 5164537..adadf72 100644 --- a/src/ast/nodes/ParamdefNode.java +++ b/src/ast/nodes/ParamdefNode.java @@ -12,7 +12,7 @@ import semanticanalysis.SymbolTable; public class ParamdefNode extends AtomNode { public ParamdefNode(String val) { - super(val); + super(val, null); } @Override diff --git a/src/ast/nodes/TestlistCompNode.java b/src/ast/nodes/TestlistCompNode.java new file mode 100644 index 0000000..070b1a1 --- /dev/null +++ b/src/ast/nodes/TestlistCompNode.java @@ -0,0 +1,61 @@ +package ast.nodes; + +import ast.types.*; +import java.util.ArrayList; +import semanticanalysis.SemanticError; +import semanticanalysis.SymbolTable; + +/** + * Node for the `testlist_comp` statement of the grammar. + */ +public class TestlistCompNode implements Node { + + private final ArrayList<Node> exprs; + + public TestlistCompNode(ArrayList<Node> _exprs) { + this.exprs = _exprs; + } + + @Override + public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) { + ArrayList<SemanticError> errors = new ArrayList(); + + for (var param : exprs) { + errors.addAll(param.checkSemantics(ST, _nesting)); + } + + return errors; + } + + public int getSize() { + return exprs.size(); + } + + public Node getElem(int i) { + return exprs.get(i); + } + + @Override + public Type typeCheck() { + return new VoidType(); + } + + // TODO: code generation for expr list + @Override + public String codeGeneration() { + return ""; + } + + @Override + public String toPrint(String prefix) { + String str = prefix + "Testlist_comp\n"; + + prefix += " "; + for (var param : exprs) { + str += param.toPrint(prefix); + } + + return str; + } + +} diff --git a/test/trailers.py b/test/trailers.py new file mode 100644 index 0000000..278a2d4 --- /dev/null +++ b/test/trailers.py @@ -0,0 +1,13 @@ + +def mult(nums): + ret = [] + for a, b in nums: + ret.append(a * b) + return ret + +print(mult([(2, 4), (5, 2)])) + + +# left, right = 1, 2 +# print(left) +# print(right) |