lexerClass, String source) {
+ CharStream input = new ANTLRInputStream(source);
+ L lexer;
+ try {
+ lexer = lexerClass.getConstructor(CharStream.class).newInstance(input);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("couldn't invoke lexer constructor", e);
+ }
+ lexer.addErrorListener(new AntlrFailureListener());
+ return lexer;
+ }
+
+ public static P getParser(Class extends Lexer> lexerClass, Class
parserClass, String source) {
+ Lexer lexer = getLexer(lexerClass, source);
+ TokenStream tokens = new CommonTokenStream(lexer);
+
+ P parser;
+ try {
+ parser = parserClass.getConstructor(TokenStream.class).newInstance(tokens);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("couldn't invoke parser constructor", e);
+ }
+ parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
+ parser.removeErrorListeners(); // don't spit to stderr
+ parser.addErrorListener(new DiagnosticErrorListener());
+ parser.addErrorListener(new AntlrFailureListener());
+
+ return parser;
+ }
+
+ private static class AntlrFailureListener extends BaseErrorListener {
+ @Override
+ public void syntaxError(Recognizer, ?> recognizer, @Nullable Object offendingSymbol, int line,
+ int charPositionInLine, String msg, @Nullable RecognitionException e) {
+ throw new AntlrParseException(line, charPositionInLine, msg, e);
+ }
+ }
+
+ public static class AntlrParseException extends RuntimeException {
+ public AntlrParseException(int line, int posInLine, String msg, Throwable cause) {
+ // posInLine comes in 0-indexed, but we want to 1-index it so it lines up with what editors say (they
+ // tend to 1-index)
+ super(String.format("at line %d column %d: %s", line, posInLine+1, msg), cause);
+ }
+ }
+}
diff --git a/ethereumj-core/src/main/java/org/ethereum/serpent/Serpent.g4 b/ethereumj-core/src/main/java/org/ethereum/serpent/Serpent.g4
new file mode 100644
index 00000000..6c17e79d
--- /dev/null
+++ b/ethereumj-core/src/main/java/org/ethereum/serpent/Serpent.g4
@@ -0,0 +1,196 @@
+grammar Serpent;
+
+tokens {
+INDENT, DEDENT }
+@lexer::header {
+ import com.yuvalshavit.antlr4.DenterHelper;
+}
+
+
+@lexer::members {
+ private final DenterHelper denter = new DenterHelper(NL, SerpentParser.INDENT, SerpentParser.DEDENT) {
+ @Override
+ public Token pullToken() {
+ return SerpentLexer.super.nextToken(); // must be to super.nextToken, or we'll recurse forever!
+ }
+
+
+ };
+
+ @Override
+ public Token nextToken() {
+ return denter.nextToken();
+ }
+}
+
+
+parse: block EOF
+ ;
+
+
+block: (assign | special_func | if_elif_else_stmt | while_stmt | ret_func)* ;
+
+
+if_elif_else_stmt: 'if' condition ':' INDENT block DEDENT
+ ('elif' condition ':' INDENT block DEDENT)*
+ ('else:' INDENT block DEDENT)?
+ ;
+
+while_stmt: 'while' condition ':' INDENT block DEDENT;
+
+
+/* special functions */
+
+special_func :
+ msg_datasize |
+ msg_sender |
+ msg_value |
+ tx_gasprice |
+ tx_origin |
+ tx_gas |
+ contract_balance |
+ block_prevhash |
+ block_coinbase |
+ block_timestamp |
+ block_number |
+ block_difficulty |
+ block_gaslimit
+ ;
+
+msg_datasize
+ : 'msg.datasize' ;
+
+msg_sender
+ : 'msg.sender' ;
+
+msg_value
+ : 'msg.value' ;
+
+tx_gasprice
+ : 'tx.gasprice' ;
+
+tx_origin
+ : 'tx.origin' ;
+
+tx_gas
+ : 'tx.gas' ;
+
+contract_balance
+ : 'contract.balance' ;
+
+block_prevhash
+ : 'block.prevhash' ;
+
+block_coinbase
+ : 'block.coinbase' ;
+
+block_timestamp
+ : 'block.timestamp' ;
+
+block_number
+ : 'block.number' ;
+
+block_difficulty
+ : 'block.difficulty' ;
+
+block_gaslimit
+ : 'block.gaslimit' ;
+
+
+
+assign: VAR EQ_OP expression NL;
+
+
+mul_expr
+ : int_val
+ | mul_expr OP_MUL int_val
+ ;
+
+add_expr
+ : mul_expr
+ | add_expr OP_ADD mul_expr
+ ;
+
+rel_exp
+ : add_expr
+ | rel_exp OP_REL add_expr
+ ;
+
+eq_exp
+ : rel_exp
+ | eq_exp OP_EQ rel_exp
+ ;
+
+and_exp
+ : eq_exp
+ | and_exp OP_AND eq_exp
+ ;
+
+ex_or_exp
+ : and_exp
+ | ex_or_exp OP_EX_OR and_exp
+ ;
+
+in_or_exp
+ : ex_or_exp
+ | in_or_exp OP_IN_OR ex_or_exp
+ ;
+
+log_and_exp
+ : in_or_exp
+ | log_and_exp OP_LOG_AND in_or_exp
+ ;
+
+log_or_exp
+ : log_and_exp
+ | log_or_exp OP_LOG_OR log_and_exp
+ ;
+
+
+expression : log_or_exp ;
+
+condition: expression ;
+
+
+int_val : INT | hex_num | get_var | special_func | '(' expression ')' | OP_NOT '(' expression ')' ;
+// todo: here the val should include also retrieve a variable
+
+hex_num
+ : HEX_NUMBER
+ ;
+
+ret_func: 'return' '(' INT ')' NL;
+
+get_var: VAR;
+
+
+/* 'xor', 'and', 'or', 'not' operands should be defined
+ first among lexer rules because it
+ can be mismatched as a var lexa */
+OP_EX_OR: 'xor';
+OP_LOG_AND: '&&' | 'and';
+OP_LOG_OR: '||' | 'or';
+OP_NOT: '!' | 'not';
+
+
+EQ_OP: '=' ;
+
+NL: ('\r'? '\n' ' '*); // note the ' '*;
+WS: [ \t]+ -> skip;
+LINE_COMMENT: '//' ~[\r\n]* -> skip;
+
+INT: [0-9]+;
+VAR: [a-zA-Z][a-zA-Z0-9]* ;
+
+
+OP_ADD : '+' | '-';
+OP_MUL : '*' | '/' | '^' | '%' ;
+
+OP_REL : '<' | '>' | '<=' | '>=';
+OP_EQ : '==' | '!=';
+OP_AND: '&';
+OP_IN_OR: '|';
+
+
+HEX_DIGIT : [0-9a-fA-F];
+HEX_NUMBER : ('0x' | '0X' )HEX_DIGIT+;
diff --git a/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java
new file mode 100644
index 00000000..dfdc77d2
--- /dev/null
+++ b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentCompiler.java
@@ -0,0 +1,23 @@
+package org.ethereum.serpent;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+
+/**
+ * www.ethereumJ.com
+ * User: Roman Mandeleil
+ * Created on: 13/05/14 19:37
+ */
+public class SerpentCompiler {
+
+ public static String compile(String code){
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ return result;
+ }
+}
diff --git a/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentToAssemblyCompiler.java b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentToAssemblyCompiler.java
new file mode 100644
index 00000000..2e3d4f45
--- /dev/null
+++ b/ethereumj-core/src/main/java/org/ethereum/serpent/SerpentToAssemblyCompiler.java
@@ -0,0 +1,434 @@
+package org.ethereum.serpent;
+
+import org.antlr.v4.runtime.misc.NotNull;
+import org.spongycastle.util.encoders.Hex;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+
+/**
+ * www.ethereumJ.com
+ * User: Roman Mandeleil
+ * Created on: 05/05/14 13:41
+ */
+public class SerpentToAssemblyCompiler extends SerpentBaseVisitor {
+
+ int labelIndex = 0;
+ private ArrayList vars = new ArrayList();
+
+
+
+ @Override
+ public String visitParse(@NotNull SerpentParser.ParseContext ctx) {
+
+ StringBuffer result = new StringBuffer();
+
+ result.append( super.visitParse(ctx) );
+
+ // todo: calc the wrapping with memory usage data
+
+ return result.toString();
+ }
+
+
+ @Override
+ public String visitIf_elif_else_stmt(@NotNull SerpentParser.If_elif_else_stmtContext ctx) {
+
+ //todo: when you find some error throw expectation exception
+ StringBuffer retCode = new StringBuffer();
+
+ int endOfStmtLabel = labelIndex++ ;
+
+ // if body
+ SerpentParser.BlockContext ifBlock = (SerpentParser.BlockContext) ctx.getChild(4);
+ String blockCode = visitBlock(ifBlock);
+ String ifCond = visitCondition(ctx.condition(0));
+
+ int nextLabel = labelIndex++;
+
+
+ // if_cond [NOT REF_X JUMPI] if_body [REF_Y JUMP LABEL_X] Y=total_end
+ retCode.append(ifCond).
+ append(" NOT REF_").append(nextLabel).append(" JUMPI ").
+ append(blockCode).
+ append("REF_").append(endOfStmtLabel).
+ append(" JUMP LABEL_").append(nextLabel).append(" ");
+
+ // traverse the children and find out all [elif] and [else] that exist
+ int count = ctx.condition().size();
+
+ // traverse all 'elif' statements
+ int i = 1; // define i here for 'else' option
+ for (; i < count; ++i){
+
+
+ // if the condition much at the end jump out of the main if
+ // append to general retCode
+ // todo: [NOT REF_X JUMPI] elif_body [REF_Y JUMP LABEL_X] Y=total_end
+ // todo extract the condition and the body
+ nextLabel = labelIndex++;
+
+ // elif condition
+ String elifCond = visitCondition(ctx.condition(i));
+
+ // elif body
+ String elifBlockCode = visitBlock(ctx.block(i));
+
+ retCode.append(elifCond).
+ append(" NOT REF_").append(nextLabel).append(" JUMPI ").
+ append(elifBlockCode).
+ append("REF_").append(endOfStmtLabel).append(" JUMP LABEL_").
+ append(nextLabel).append(" ");
+ }
+
+
+ // check if there is 'else'
+ if (ctx.block(i) != null) {
+
+ // body
+ String elseBlockCode = visitBlock(ctx.block(i));
+
+ // append to general retCode
+ retCode.append(elseBlockCode);
+ }
+
+ // [LABEL_Y] Y = end of statement
+ retCode.append("LABEL_").append(endOfStmtLabel).append(" ");
+
+ return retCode.toString();
+ }
+
+
+ @Override
+ public String visitWhile_stmt(@NotNull SerpentParser.While_stmtContext ctx) {
+
+ int whileStartRef = labelIndex++;
+ int whileEndRef = labelIndex++;
+
+ // elif condition
+ SerpentParser.ConditionContext whileCondition = (SerpentParser.ConditionContext)
+ ctx.getChild(1);
+
+ // elif body
+ SerpentParser.BlockContext whileBlock = (SerpentParser.BlockContext)
+ ctx.getChild(4);
+
+ String retCode =
+ String.format("LABEL_%d %s EQ NOT REF_%d JUMPI %s REF_%d JUMP LABEL_%d",
+ whileStartRef, visitCondition(whileCondition), whileEndRef, visitBlock(whileBlock), whileStartRef, whileEndRef);
+
+ return retCode;
+ }
+
+ @Override
+ public String visitBlock(@NotNull SerpentParser.BlockContext ctx) {
+
+ String blockStmt = super.visitBlock(ctx);
+
+ return blockStmt;
+ }
+
+
+ @Override
+ public String visitCondition(@NotNull SerpentParser.ConditionContext ctx) {
+ return super.visitCondition(ctx);
+ }
+
+ @Override
+ public String visitGet_var(@NotNull SerpentParser.Get_varContext ctx) {
+
+ String varName = ctx.VAR().toString();
+ int addr;
+
+ addr = vars.indexOf(varName);
+ if (addr == -1){
+ throw new UnassignVarException(varName);
+ }
+
+ return String.format(" %d MLOAD ", addr * 32);
+ }
+
+
+ @Override
+ public String visitAssign(@NotNull SerpentParser.AssignContext ctx) {
+
+ String varName = ctx.VAR().toString();
+ int addr = 0;
+
+ addr = vars.indexOf(varName);
+ if (addr == -1){
+ addr = vars.size();
+ vars.add(varName);
+ }
+
+ String expression = visitExpression(ctx.expression());
+
+ return String.format(" %s %d MSTORE ", expression, addr * 32);
+ }
+
+
+ @Override
+ public String visitInt_val(@NotNull SerpentParser.Int_valContext ctx) {
+
+ if (ctx.OP_NOT() != null)
+ return visitExpression(ctx.expression()) + " NOT";
+
+ if (ctx.expression() != null)
+ return visitExpression(ctx.expression());
+
+ if (ctx.get_var() != null)
+ return visitGet_var(ctx.get_var());
+
+ if (ctx.hex_num() != null)
+ return hexStringToDecimalString(ctx.hex_num().getText());
+
+ if (ctx.special_func() != null)
+ return visitSpecial_func(ctx.special_func());
+
+ return ctx.INT().toString();
+ }
+
+
+ @Override
+ public String visitMul_expr(@NotNull SerpentParser.Mul_exprContext ctx) {
+ if (ctx.mul_expr() == null) return visit(ctx.int_val());
+
+ String operand0 = visit(ctx.mul_expr());
+ String operand1 = visit(ctx.int_val());
+
+ switch (ctx.OP_MUL().getText().toLowerCase()) {
+ case "*": return operand0 + " " + operand1 + " MUL";
+ case "/": return operand0 + " " + operand1 + " DIV";
+ case "^": return operand0 + " " + operand1 + " EXP";
+ case "%": return operand0 + " " + operand1 + " MOD";
+ default: throw new UnknownOperandException(ctx.OP_MUL().getText());
+ }
+ }
+
+
+ @Override
+ public String visitAdd_expr(@NotNull SerpentParser.Add_exprContext ctx) {
+
+ if (ctx.add_expr() == null) return visit(ctx.mul_expr());
+
+ String operand0 = visit(ctx.add_expr());
+ String operand1 = visit(ctx.mul_expr());
+
+ switch (ctx.OP_ADD().getText().toLowerCase()) {
+ case "+": return operand0 + " " + operand1 + " ADD";
+ case "-": return operand0 + " " + operand1 + " SUB";
+ default: throw new UnknownOperandException(ctx.OP_ADD().getText());
+ }
+ }
+
+ @Override
+ public String visitRel_exp(@NotNull SerpentParser.Rel_expContext ctx) {
+
+ if (ctx.rel_exp() == null) return visit(ctx.add_expr());
+
+ String operand0 = visit(ctx.rel_exp());
+ String operand1 = visit(ctx.add_expr());
+
+ switch (ctx.OP_REL().getText().toLowerCase()) {
+ case "<": return operand0 + " " + operand1 + " LT";
+ case ">": return operand0 + " " + operand1 + " GT";
+ case ">=": return operand0 + " " + operand1 + " LT NOT";
+ case "<=": return operand0 + " " + operand1 + " GT NOT";
+ default: throw new UnknownOperandException(ctx.OP_REL().getText());
+ }
+ }
+
+ @Override
+ public String visitEq_exp(@NotNull SerpentParser.Eq_expContext ctx) {
+
+ if (ctx.eq_exp() == null) return visit(ctx.rel_exp());
+
+ String operand0 = visit(ctx.eq_exp());
+ String operand1 = visit(ctx.rel_exp());
+
+ switch (ctx.OP_EQ().getText().toLowerCase()) {
+ case "==": return operand0 + " " + operand1 + " EQ";
+ case "!=": return operand0 + " " + operand1 + " EQ NOT";
+ default: throw new UnknownOperandException(ctx.OP_EQ().getText());
+ }
+ }
+
+ @Override
+ public String visitAnd_exp(@NotNull SerpentParser.And_expContext ctx) {
+
+ if (ctx.and_exp() == null) return visit(ctx.eq_exp());
+
+ String operand0 = visit(ctx.and_exp());
+ String operand1 = visit(ctx.eq_exp());
+
+ switch (ctx.OP_AND().getText().toLowerCase()) {
+ case "&": return operand0 + " " + operand1 + " AND";
+ default: throw new UnknownOperandException(ctx.OP_AND().getText());
+ }
+ }
+
+ @Override
+ public String visitEx_or_exp(@NotNull SerpentParser.Ex_or_expContext ctx) {
+
+ if (ctx.ex_or_exp() == null) return visit(ctx.and_exp());
+
+ String operand0 = visit(ctx.ex_or_exp());
+ String operand1 = visit(ctx.and_exp());
+
+ switch (ctx.OP_EX_OR().getText().toLowerCase()) {
+ case "xor": return operand0 + " " + operand1 + " XOR";
+ default: throw new UnknownOperandException(ctx.OP_EX_OR().getText());
+ }
+ }
+
+ @Override
+ public String visitIn_or_exp(@NotNull SerpentParser.In_or_expContext ctx) {
+
+ if (ctx.in_or_exp() == null) return visit(ctx.ex_or_exp());
+
+ String operand0 = visit(ctx.in_or_exp());
+ String operand1 = visit(ctx.ex_or_exp());
+
+ switch (ctx.OP_IN_OR().getText().toLowerCase()) {
+ case "|": return operand0 + " " + operand1 + " OR";
+ default: throw new UnknownOperandException(ctx.OP_IN_OR().getText());
+ }
+ }
+
+ @Override
+ public String visitLog_and_exp(@NotNull SerpentParser.Log_and_expContext ctx) {
+
+ if (ctx.log_and_exp() == null) return visit(ctx.in_or_exp());
+
+ String operand0 = visit(ctx.log_and_exp());
+ String operand1 = visit(ctx.in_or_exp());
+
+ switch (ctx.OP_LOG_AND().getText().toLowerCase()) {
+ case "and": return operand0 + " " + operand1 + " NOT NOT MUL";
+ case "&&": return operand0 + " " + operand1 + " NOT NOT MUL";
+ default: throw new UnknownOperandException(ctx.OP_LOG_AND().getText());
+ }
+ }
+
+ @Override
+ public String visitLog_or_exp(@NotNull SerpentParser.Log_or_expContext ctx) {
+
+ if (ctx.log_or_exp() == null) return visit(ctx.log_and_exp());
+
+ String operand0 = visit(ctx.log_or_exp());
+ String operand1 = visit(ctx.log_and_exp());
+
+ switch (ctx.OP_LOG_OR().getText().toLowerCase()) {
+ case "||": return operand0 + " " + operand1 + " DUP 4 PC ADD JUMPI POP SWAP POP";
+ case "or": return operand0 + " " + operand1 + " DUP 4 PC ADD JUMPI POP SWAP POP";
+ default: throw new UnknownOperandException(ctx.OP_LOG_OR().getText());
+ }
+ }
+
+
+
+ @Override
+ public String visitMsg_sender(@NotNull SerpentParser.Msg_senderContext ctx) {
+ return "CALLER";
+ }
+
+ @Override
+ public String visitMsg_datasize(@NotNull SerpentParser.Msg_datasizeContext ctx) {
+ return "32 CALLDATASIZE DIV ";
+ }
+
+
+ @Override
+ public String visitMsg_value(@NotNull SerpentParser.Msg_valueContext ctx) {
+ return " CALLVALUE ";
+ }
+
+ @Override
+ public String visitContract_balance(@NotNull SerpentParser.Contract_balanceContext ctx) {
+ return " BALANCE ";
+ }
+
+ @Override
+ public String visitTx_origin(@NotNull SerpentParser.Tx_originContext ctx) {
+ return " ORIGIN ";
+ }
+
+ @Override
+ public String visitBlock_timestamp(@NotNull SerpentParser.Block_timestampContext ctx) {
+ return " TIMESTAMP ";
+ }
+
+ @Override
+ public String visitBlock_number(@NotNull SerpentParser.Block_numberContext ctx) {
+ return " NUMBER ";
+ }
+
+ @Override
+ public String visitTx_gas(@NotNull SerpentParser.Tx_gasContext ctx) {
+ return " GAS ";
+ }
+
+ @Override
+ public String visitBlock_difficulty(@NotNull SerpentParser.Block_difficultyContext ctx) {
+ return " DIFFICULTY ";
+ }
+
+ @Override
+ public String visitBlock_coinbase(@NotNull SerpentParser.Block_coinbaseContext ctx) {
+ return " COINBASE ";
+ }
+
+ @Override
+ public String visitTx_gasprice(@NotNull SerpentParser.Tx_gaspriceContext ctx) {
+ return " GASPRICE ";
+ }
+
+ @Override
+ public String visitBlock_prevhash(@NotNull SerpentParser.Block_prevhashContext ctx) {
+ return " PREVHASH ";
+ }
+
+ @Override
+ public String visitBlock_gaslimit(@NotNull SerpentParser.Block_gaslimitContext ctx) {
+ return " GASLIMIT ";
+ }
+
+
+
+ @Override
+ protected String aggregateResult(String aggregate, String nextResult) {
+ return aggregate + nextResult;
+ }
+
+ @Override
+ protected String defaultResult() {
+ return "";
+ }
+
+
+ /**
+ * @param hexNum should be in form '0x34fabd34....'
+ * @return
+ */
+ private String hexStringToDecimalString(String hexNum){
+ String digits = hexNum.substring(2);
+ if (digits.length() % 2 != 0) digits = "0" + digits;
+ byte[] numberBytes = Hex.decode(digits);
+ return (new BigInteger(1, numberBytes)).toString();
+ }
+
+
+
+ public static class UnknownOperandException extends RuntimeException {
+ public UnknownOperandException(String name) {
+ super("unknown operand: " + name);
+ }
+ }
+
+ public static class UnassignVarException extends RuntimeException {
+ public UnassignVarException(String name) {
+ super("attempt to access not assigned variable: " + name);
+ }
+ }
+
+}
diff --git a/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java b/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java
new file mode 100644
index 00000000..e5861c60
--- /dev/null
+++ b/ethereumj-core/src/test/java/org/ethereum/serpent/SerpentCompileTest.java
@@ -0,0 +1,856 @@
+package org.ethereum.serpent;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * www.ethereumJ.com
+ * User: Roman Mandeleil
+ * Created on: 13/05/14 10:07
+ */
+public class SerpentCompileTest {
+
+
+ @Test // assign test 1
+ public void test1(){
+
+ String code = "a=2";
+ String expected = "2 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // assign test 2
+ public void test2(){
+
+ String code = "a=2\n" +
+ "b=6";
+ String expected = "2 0 MSTORE 6 32 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // assign test 3
+ public void test3(){
+
+ String code = "a=2\n" +
+ "b=6\n" +
+ "c=b";
+ String expected = "2 0 MSTORE 6 32 MSTORE 32 MLOAD 64 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+
+ @Test // assign test 4
+ public void test4(){
+
+ String code = "a=2\n" +
+ "b=6\n" +
+ "c=b\n" +
+ "a=c";
+ String expected = "2 0 MSTORE 6 32 MSTORE 32 MLOAD 64 MSTORE 64 MLOAD 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // assign test 5
+ public void test5(){
+
+ String code = "a=2\n" +
+ "b=6\n" +
+ "c=b\n" +
+ "a=c\n" +
+ "a=d";
+ String expected = "exception";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = null;
+
+ try {
+ result = new SerpentToAssemblyCompiler().visit(tree);
+ } catch (Exception e) {
+
+ Assert.assertTrue(e instanceof SerpentToAssemblyCompiler.UnassignVarException);
+ return;
+ }
+
+ // No exception was thrown
+ Assert.fail();
+ }
+
+
+ @Test // expression test 1
+ public void test6(){
+
+ String code = "a = 2 * 2";
+ String expected = "2 2 MUL 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 2
+ public void test7(){
+
+ String code = "a = 2 * 2 xor 2 * 2";
+ String expected = "2 2 MUL 2 2 MUL XOR 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 3
+ public void test8(){
+
+ String code = "a = 2 | 2 xor 2 * 2";
+ String expected = "2 2 2 2 MUL XOR OR 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 4
+ public void test9(){
+
+ String code = "a = (2 | 2) xor (2 * 2)";
+ String expected = "2 2 OR 2 2 MUL XOR 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+
+ @Test // expression test 5
+ public void test10(){
+
+ String code = "a = !(2 | 2 xor 2 * 2)";
+ String expected = "2 2 2 2 MUL XOR OR NOT 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 6
+ public void test11(){
+
+ String code = "a = 2 + 2 * 2 + 2";
+ String expected = "2 2 2 MUL ADD 2 ADD 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 7
+ public void test12(){
+
+ String code = "a = 2 / 2 * 2 + 2";
+ String expected = "2 2 DIV 2 MUL 2 ADD 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 8
+ public void test13(){
+
+ String code = "a = 2 - 0x1a * 5 + 0xA";
+ String expected = "2 26 5 MUL SUB 10 ADD 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 9
+ public void test14(){
+
+ String code = "a = 1 > 2 > 3 > 4";
+ String expected = "1 2 GT 3 GT 4 GT 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // expression test 10
+ public void test15(){
+
+ String code = "a = not ( 1 + 2 * 9 | 8 == 2)";
+ String expected = "1 2 9 MUL ADD 8 2 EQ OR NOT 0 MSTORE";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 1
+ public void test16(){
+
+ String code = "if 1>2: \n" +
+ " a=2";
+ String expected = "1 2 GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 LABEL_0";
+
+ /**
+ 1 2 GT NOT REF_1 JUMPI
+ 2 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ LABEL_0
+ */
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 2
+ public void test17(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 LABEL_0";
+
+ /**
+
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ LABEL_0
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 3
+ public void test18(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2\n" +
+ "else: \n" +
+ " c=3\n";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 3 32 MSTORE LABEL_0";
+
+ /**
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE REF_0 JUMP
+ LABEL_1
+ 3 32 MSTORE
+ LABEL_0
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 4
+ public void test19(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2\n" +
+ "else: \n" +
+ " c=123\n" +
+ " d=0xFFAA";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 123 32 MSTORE 65450 64 MSTORE LABEL_0";
+
+ /**
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE REF_0 JUMP
+ LABEL_1
+ 123 32 MSTORE
+ 65450 64 MSTORE
+ LABEL_0
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 5
+ public void test20(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2\n" +
+ "elif 2*2==4: \n" +
+ " a=3\n" +
+ "else: \n" +
+ " c=123\n" +
+ " d=0xFFAA";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 2 2 MUL 4 EQ NOT REF_2 JUMPI 3 0 MSTORE REF_0 JUMP LABEL_2 123 32 MSTORE 65450 64 MSTORE LABEL_0";
+
+ /**
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE REF_0 JUMP
+ LABEL_1
+ 2 2 MUL 4 EQ NOT REF_2 JUMPI
+ 3 0 MSTORE REF_0 JUMP
+ LABEL_2
+ 123 32 MSTORE
+ 65450 64 MSTORE
+ LABEL_0
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 6
+ public void test21(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2\n" +
+ "elif 2*2==4: \n" +
+ " a=3\n" +
+ "elif 2*2+10==40: \n" +
+ " a=3\n" +
+ " a=9\n" +
+ " a=21\n" +
+ "else: \n" +
+ " c=123\n" +
+ " d=0xFFAA";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 2 2 MUL 4 EQ NOT REF_2 JUMPI 3 0 MSTORE REF_0 JUMP LABEL_2 2 2 MUL 10 ADD 40 EQ NOT REF_3 JUMPI 3 0 MSTORE 9 0 MSTORE 21 0 MSTORE REF_0 JUMP LABEL_3 123 32 MSTORE 65450 64 MSTORE LABEL_0";
+
+ /**
+
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE REF_0 JUMP
+ LABEL_1
+ 2 2 MUL 4 EQ NOT REF_2 JUMPI
+ 3 0 MSTORE
+ REF_0 JUMP
+ LABEL_2
+ 2 2 MUL 10 ADD 40 EQ NOT REF_3 JUMPI
+ 3 0 MSTORE
+ 9 0 MSTORE
+ 21 0 MSTORE
+ REF_0 JUMP
+ LABEL_3
+ 123 32 MSTORE
+ 65450 64 MSTORE
+ LABEL_0 */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+
+ @Test // if elif else test 7
+ public void test22(){
+
+ String code = "if 10 > 2 + 5: \n" +
+ " a=2\n" +
+ "elif 2*2==4: \n" +
+ " a=3\n" +
+ " if a==3:\n" +
+ " q=123\n" +
+ "elif 2*2+10==40: \n" +
+ " a=3\n" +
+ " a=9\n" +
+ " a=21\n" +
+ "else: \n" +
+ " c=123\n" +
+ " d=0xFFAA";
+ String expected = "10 2 5 ADD GT NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 2 2 MUL 4 EQ NOT REF_2 JUMPI 3 0 MSTORE 0 MLOAD 3 EQ NOT REF_4 JUMPI 123 32 MSTORE REF_3 JUMP LABEL_4 LABEL_3 REF_0 JUMP LABEL_2 2 2 MUL 10 ADD 40 EQ NOT REF_5 JUMPI 3 0 MSTORE 9 0 MSTORE 21 0 MSTORE REF_0 JUMP LABEL_5 123 64 MSTORE 65450 96 MSTORE LABEL_0";
+
+ /**
+ 10 2 5 ADD GT NOT REF_1 JUMPI
+ 2 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ 2 2 MUL 4 EQ NOT REF_2 JUMPI
+ 3 0 MSTORE
+ 0 MLOAD 3 EQ NOT REF_4 JUMPI
+ 123 32 MSTORE
+ REF_3 JUMP
+ LABEL_4
+ LABEL_3
+ REF_0 JUMP
+ LABEL_2
+ 2 2 MUL 10 ADD 40 EQ NOT REF_5 JUMPI
+ 3 0 MSTORE
+ 9 0 MSTORE
+ 21 0 MSTORE
+ REF_0 JUMP
+ LABEL_5
+ 123 64 MSTORE
+ 65450 96 MSTORE
+ LABEL_0
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 8
+ public void test23(){
+
+ String code = "if (10 > 2 + 5) && (2 * 7 > 96): \n" +
+ " a=2\n" +
+ "elif 2*2==4: \n" +
+ " a=3\n" +
+ " if a==3:\n" +
+ " q=123\n" +
+ "elif 2*2+10==40: \n" +
+ " a=3\n" +
+ " a=9\n" +
+ " a=21\n" +
+ "else: \n" +
+ " c=123\n" +
+ " d=0xFFAA";
+ String expected = "10 2 5 ADD GT 2 7 MUL 96 GT NOT NOT MUL NOT REF_1 JUMPI 2 0 MSTORE REF_0 JUMP LABEL_1 2 2 MUL 4 EQ NOT REF_2 JUMPI 3 0 MSTORE 0 MLOAD 3 EQ NOT REF_4 JUMPI 123 32 MSTORE REF_3 JUMP LABEL_4 LABEL_3 REF_0 JUMP LABEL_2 2 2 MUL 10 ADD 40 EQ NOT REF_5 JUMPI 3 0 MSTORE 9 0 MSTORE 21 0 MSTORE REF_0 JUMP LABEL_5 123 64 MSTORE 65450 96 MSTORE LABEL_0";
+
+ /**
+ 10 2 5 ADD GT 2 7 MUL 96 GT NOT NOT MUL NOT REF_1 JUMPI
+ 2 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ 2 2 MUL 4 EQ NOT REF_2 JUMPI
+ 3 0 MSTORE
+ 0 MLOAD 3 EQ NOT REF_4 JUMPI
+ 123 32 MSTORE REF_3 JUMP
+ LABEL_4
+ LABEL_3
+ REF_0 JUMP
+ LABEL_2
+ 2 2 MUL 10 ADD 40 EQ NOT REF_5 JUMPI
+ 3 0 MSTORE
+ 9 0 MSTORE
+ 21 0 MSTORE
+ REF_0 JUMP
+ LABEL_5
+ 123 64 MSTORE
+ 65450 96 MSTORE
+
+ LABEL_0
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 9
+ public void test24(){
+
+ String code = "a = 20\n" +
+ "b = 40\n" +
+ "if a == 20: \n" +
+ " a = 30\n" +
+ "if b == 40: \n" +
+ " b = 50\n";
+ String expected = "20 0 MSTORE 40 32 MSTORE 0 MLOAD 20 EQ NOT REF_1 JUMPI 30 0 MSTORE REF_0 JUMP LABEL_1 LABEL_0 32 MLOAD 40 EQ NOT REF_3 JUMPI 50 32 MSTORE REF_2 JUMP LABEL_3 LABEL_2";
+
+ /**
+
+ 20 0 MSTORE
+ 40 32 MSTORE
+ 0 MLOAD 20 EQ NOT REF_1 JUMPI
+ 30 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ LABEL_0
+ 32 MLOAD 40 EQ NOT REF_3 JUMPI
+ 50 32 MSTORE
+ REF_2 JUMP
+ LABEL_3
+ LABEL_2
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 10
+ public void test25(){
+
+ String code = "a = 20\n" +
+ "b = 40\n" +
+ "if a == 20: \n" +
+ " a = 30\n" +
+ "a = 70\n" +
+ "if b == 40: \n" +
+ " b = 50\n";
+ String expected = "20 0 MSTORE 40 32 MSTORE 0 MLOAD 20 EQ NOT REF_1 JUMPI 30 0 MSTORE REF_0 JUMP LABEL_1 LABEL_0 70 0 MSTORE 32 MLOAD 40 EQ NOT REF_3 JUMPI 50 32 MSTORE REF_2 JUMP LABEL_3 LABEL_2";
+
+ /**
+
+ 20 0 MSTORE
+ 40 32 MSTORE
+ 0 MLOAD 20 EQ NOT REF_1 JUMPI
+ 30 0 MSTORE
+ REF_0 JUMP
+ LABEL_1
+ LABEL_0
+ 70 0 MSTORE
+ 32 MLOAD 40 EQ NOT REF_3 JUMPI
+ 50 32 MSTORE
+ REF_2 JUMP
+ LABEL_3
+ LABEL_2
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 11
+ public void test26(){
+
+ String code = "if 2>1: \n" +
+ " if 3>2: \n" +
+ " if 4>3:\n" +
+ " if 5>4:\n" +
+ " a = 10\n";
+ String expected = "2 1 GT NOT REF_7 JUMPI 3 2 GT NOT REF_6 JUMPI 4 3 GT NOT REF_5 JUMPI 5 4 GT NOT REF_4 JUMPI 10 0 MSTORE REF_3 JUMP LABEL_4 LABEL_3 REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0";
+
+ /**
+
+ 2 1 GT NOT REF_7 JUMPI
+ 3 2 GT NOT REF_6 JUMPI
+ 4 3 GT NOT REF_5 JUMPI
+ 5 4 GT NOT REF_4 JUMPI
+ 10 0 MSTORE
+ REF_3 JUMP
+ LABEL_4 LABEL_3 REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+ @Test // if elif else test 12
+ public void test27(){
+
+ String code = "if 2>1: \n" +
+ " if 3>2: \n" +
+ " if 4>3:\n" +
+ " if 5>4:\n" +
+ " a = 10\n";
+ String expected = "2 1 GT NOT REF_7 JUMPI 3 2 GT NOT REF_6 JUMPI 4 3 GT NOT REF_5 JUMPI 5 4 GT NOT REF_4 JUMPI 10 0 MSTORE REF_3 JUMP LABEL_4 LABEL_3 REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0";
+
+ /**
+
+ 2 1 GT NOT REF_7 JUMPI
+ 3 2 GT NOT REF_6 JUMPI
+ 4 3 GT NOT REF_5 JUMPI
+ 5 4 GT NOT REF_4 JUMPI
+ 10 0 MSTORE
+ REF_3 JUMP
+ LABEL_4 LABEL_3 REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0
+
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+
+ @Test // if elif else test 13
+ public void test28(){
+
+ String code = "if 2>1: \n" +
+ " if 3>2: \n" +
+ " if 4>3:\n" +
+ " if 5>4:\n" +
+ " a = 10\n" +
+ " else:\n" +
+ " b = 20\n";
+ String expected = "2 1 GT NOT REF_7 JUMPI 3 2 GT NOT REF_6 JUMPI 4 3 GT NOT REF_5 JUMPI 5 4 GT NOT REF_4 JUMPI 10 0 MSTORE REF_3 JUMP LABEL_4 20 32 MSTORE LABEL_3 REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0";
+
+ /**
+
+ 2 1 GT NOT REF_7 JUMPI
+ 3 2 GT NOT REF_6 JUMPI
+ 4 3 GT NOT REF_5 JUMPI
+ 5 4 GT NOT REF_4 JUMPI
+ 10 0 MSTORE REF_3 JUMP
+ LABEL_4
+ 20 32 MSTORE
+ LABEL_3
+ REF_2 JUMP LABEL_5 LABEL_2 REF_1 JUMP LABEL_6 LABEL_1 REF_0 JUMP LABEL_7 LABEL_0
+ */
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+ ParseTree tree = parser.parse();
+
+ String result = new SerpentToAssemblyCompiler().visit(tree);
+ result = result.replaceAll("\\s+", " ");
+ result = result.trim();
+
+ Assert.assertEquals(result, expected);
+ }
+
+
+ @Test // if elif else test 14
+ public void test29(){
+
+ String code = " if 2>4: \n" +
+ " a=20 \n" +
+ " \n" +
+ " \n";
+ String expected = "";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+
+ ParseTree tree = null;
+ try {
+ tree = parser.parse();
+ } catch (Throwable e) {
+
+ Assert.assertTrue(e instanceof ParserUtils.AntlrParseException);
+ return;
+ }
+
+ Assert.fail("Should be indent error thrown");
+ }
+
+ @Test // if elif else test 15
+ public void test30(){
+
+ String code = "if 2>4: \n" +
+ " a=20 \n" +
+ " else: \n" +
+ " a=40 \n";
+ String expected = "";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+
+ ParseTree tree = null;
+ try {
+ tree = parser.parse();
+ } catch (Throwable e) {
+
+ Assert.assertTrue(e instanceof ParserUtils.AntlrParseException);
+ return;
+ }
+
+ Assert.fail("Should be indent error thrown");
+ }
+
+
+ @Test // if elif else test 16
+ public void test31(){
+
+ String code = "if 2>4: \n" +
+ " a=20 \n" +
+ " elif 2<9: \n" +
+ " a=40 \n" +
+ "else: \n" +
+ " a=40 \n";
+ String expected = "";
+
+ SerpentParser parser = ParserUtils.getParser(SerpentLexer.class, SerpentParser.class,
+ code);
+
+ ParseTree tree = null;
+ try {
+ tree = parser.parse();
+ } catch (Throwable e) {
+
+ Assert.assertTrue(e instanceof ParserUtils.AntlrParseException);
+ return;
+ }
+
+ Assert.fail("Should be indent error thrown");
+ }
+
+ /**
+ * todo: more testing for if-elif-else 4 tests
+ * todo: more testing for special functions 10
+ * todo: more testing for while function 10
+ */
+}