Major redesign of Serpent compiler

This commit is contained in:
romanman 2014-05-13 22:00:08 +03:00
parent f1d292a2b4
commit ea0a0bc754
8 changed files with 1651 additions and 16 deletions

View File

@ -61,18 +61,20 @@
<artifactId>geoip-api</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr</artifactId>
<!-- Using older version for jython compatibility -->
<version>3.1.3</version>
<!-- <version>3.5.2</version> -->
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython</artifactId>
@ -92,7 +94,15 @@
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
<dependency>
<groupId>com.yuvalshavit</groupId>
<artifactId>antlr-denter</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>

View File

@ -1,5 +1,6 @@
package org.ethereum.gui;
import org.ethereum.serpent.SerpentCompiler;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;
@ -20,13 +21,23 @@ import java.awt.event.ActionListener;
public class SerpentEditor extends JFrame {
private String codeSample = "\n\n\n" +
"" +
"" +
"if !contract.storage[msg.data[0]]:\n" +
" contract.storage[msg.data[0]] = msg.data[1]\n" +
" return(1)\n" +
"else:\n" +
" return(0)\n";
private String codeSample2 = "\n\n\n" +
"" +
"a=block.gaslimit\n" +
"b = block.difficulty\n" +
"if 10*2+5 > 15:\n" +
" b = 2\n" +
"\n" +
"return(0)\n";
private static final long serialVersionUID = 1L;
@ -48,7 +59,7 @@ public class SerpentEditor extends JFrame {
codeArea.setSyntaxEditingStyle("text/serpent");
codeArea.setCodeFoldingEnabled(true);
codeArea.setAntiAliasingEnabled(true);
codeArea.setText(codeSample);
codeArea.setText(codeSample2);
RTextScrollPane sp = new RTextScrollPane(codeArea);
@ -84,7 +95,7 @@ public class SerpentEditor extends JFrame {
try {
// todo: integrate new compiler when avail
//asmResult = SerpentCompiler.compile(codeArea.getText());
asmResult = SerpentCompiler.compile(codeArea.getText());
} catch (Throwable th) {th.printStackTrace();}
splitPanel.setDividerLocation(0.7);

View File

@ -0,0 +1,50 @@
package org.ethereum.serpent;
import org.antlr.mojo.antlr4.Antlr4ErrorLog;
import org.antlr.mojo.antlr4.Antlr4Mojo;
import org.antlr.v4.Tool;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.tool.Grammar;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import java.io.*;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 25/04/14 17:06
*/
public class ParserGenerator {
public static void main(String args[]) throws MojoFailureException, MojoExecutionException {
String userDir = System.getProperty("user.dir");
String grammarName = userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\Serpent.g4";
File inputDir = new File(userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\");
String options[] = {grammarName, "-visitor", "-package", "org.ethereum.serpent"};
Tool tool = new Tool(options);
tool.outputDirectory = userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\";
tool.processGrammarsOnCommandLine();
// org.antlr.Tool.main(new String[]{userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\Serpent.g4"});
// org.antlr.Tool.main(new String[]{userDir + "\\src\\main\\java\\samples\\antlr\\PyEsque.g"});
}
}

View File

@ -0,0 +1,55 @@
package org.ethereum.serpent;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.Nullable;
public class ParserUtils {
private ParserUtils() {}
public static <L extends Lexer> L getLexer(Class<L> 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 extends Parser> P getParser(Class<? extends Lexer> lexerClass, Class<P> 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);
}
}
}

View File

@ -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+;

View File

@ -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;
}
}

View File

@ -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<String> {
int labelIndex = 0;
private ArrayList<String> vars = new ArrayList<String>();
@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);
}
}
}

View File

@ -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
*/
}