diff --git a/tests/transpiler/options_test.go b/tests/transpiler/options_test.go index 84e54f5..481ae7c 100644 --- a/tests/transpiler/options_test.go +++ b/tests/transpiler/options_test.go @@ -32,23 +32,24 @@ func foo(x int) int { options: transpiler.Options{ Numbers: true, }, - output: `jump 5 always # 0 -set _foo_x @funcArg_foo_0 # 1 -op add _foo_0 _foo_x 20 # 2 -set @return_0 _foo_0 # 3 -set @counter @funcTramp_foo # 4 -set _main_i 0 # 5 -jump 8 lessThan _main_i 10 # 6 -jump 16 always # 7 -set @funcArg_foo_0 _main_i # 8 -set @funcTramp_foo 11 # 9 -jump 1 always # 10 -set _main_0 @return_0 # 11 -print _main_0 # 12 -print "\n" # 13 -op add _main_i _main_i 1 # 14 -jump 8 lessThan _main_i 10 # 15 -end # 16 `, + output: `jump 5 always # 0 +set _foo_x @funcArg_foo_0 # 1 +op add _foo_0 _foo_x 20 # 2 +set @return_0 _foo_0 # 3 +set @counter @funcTramp_foo # 4 +set _main_i 0 # 5 +op lessThan _main_0 _main_i 10 # 6 +jump 9 equal _main_0 true # 7 +jump 17 always # 8 +set @funcArg_foo_0 _main_i # 9 +set @funcTramp_foo 12 # 10 +jump 1 always # 11 +set _main_1 @return_0 # 12 +print _main_1 # 13 +print "\n" # 14 +op add _main_i _main_i 1 # 15 +jump 6 always # 16 +end # 17 `, }, { name: "Comments", @@ -57,29 +58,30 @@ end # 16 `, Comments: true, CommentOffset: 45, }, - output: `jump 5 always # Jump to start of main -# -# Function: foo # -# -set _foo_x @funcArg_foo_0 # Read parameter into variable -op add _foo_0 _foo_x 20 # Execute operation -set @return_0 _foo_0 # Set return data -set @counter @funcTramp_foo # Trampoline back -# -# Function: main # -# -set _main_i 0 # Assign value to variable -jump 8 lessThan _main_i 10 # Jump into the loop -jump 16 always # Jump to end of loop -set @funcArg_foo_0 _main_i # Set foo argument: 0 -set @funcTramp_foo 11 # Set Trampoline Address -jump 1 always # Jump to function: foo -set _main_0 @return_0 # Set variable to returned value -print _main_0 # Call to native function -print "\n" # Call to native function -op add _main_i _main_i 1 # Execute increment/decrement -jump 8 lessThan _main_i 10 # Jump to start of loop -end # Trampoline back `, + output: `jump 5 always # Jump to start of main +# +# Function: foo # +# +set _foo_x @funcArg_foo_0 # Read parameter into variable +op add _foo_0 _foo_x 20 # Execute operation +set @return_0 _foo_0 # Set return data +set @counter @funcTramp_foo # Trampoline back +# +# Function: main # +# +set _main_i 0 # Assign value to variable +op lessThan _main_0 _main_i 10 # Execute operation +jump 9 equal _main_0 true # Jump into the loop +jump 17 always # Jump to end of loop +set @funcArg_foo_0 _main_i # Set foo argument: 0 +set @funcTramp_foo 12 # Set Trampoline Address +jump 1 always # Jump to function: foo +set _main_1 @return_0 # Set variable to returned value +print _main_1 # Call to native function +print "\n" # Call to native function +op add _main_i _main_i 1 # Execute increment/decrement +jump 6 always # Jump to start of loop +end # Trampoline back `, }, { name: "Comments", @@ -88,23 +90,24 @@ end # Trampoline back `, Source: true, CommentOffset: 45, }, - output: `jump 5 always -set _foo_x @funcArg_foo_0 -op add _foo_0 _foo_x 20 # x + 20 -set @return_0 _foo_0 # return x + 20 -set @counter @funcTramp_foo -set _main_i 0 # i := 0 -jump 8 lessThan _main_i 10 -jump 16 always -set @funcArg_foo_0 _main_i -set @funcTramp_foo 11 -jump 1 always # foo(i) -set _main_0 @return_0 -print _main_0 # println(foo(i)) -print "\n" # println(foo(i)) -op add _main_i _main_i 1 # i++ -jump 8 lessThan _main_i 10 -end `, + output: `jump 5 always +set _foo_x @funcArg_foo_0 +op add _foo_0 _foo_x 20 # x + 20 +set @return_0 _foo_0 # return x + 20 +set @counter @funcTramp_foo +set _main_i 0 # i := 0 +op lessThan _main_0 _main_i 10 # i < 10 +jump 9 equal _main_0 true +jump 17 always +set @funcArg_foo_0 _main_i +set @funcTramp_foo 12 +jump 1 always # foo(i) +set _main_1 @return_0 +print _main_1 # println(foo(i)) +print "\n" # println(foo(i)) +op add _main_i _main_i 1 # i++ +jump 6 always +end `, }, { name: "All", @@ -115,29 +118,30 @@ end `, Source: true, CommentOffset: 45, }, - output: `jump 5 always # 0 # Jump to start of main -# -# Function: foo # -# -set _foo_x @funcArg_foo_0 # 1 # Read parameter into variable -op add _foo_0 _foo_x 20 # 2 # Execute operation # x + 20 -set @return_0 _foo_0 # 3 # Set return data # return x + 20 -set @counter @funcTramp_foo # 4 # Trampoline back -# -# Function: main # -# -set _main_i 0 # 5 # Assign value to variable # i := 0 -jump 8 lessThan _main_i 10 # 6 # Jump into the loop -jump 16 always # 7 # Jump to end of loop -set @funcArg_foo_0 _main_i # 8 # Set foo argument: 0 -set @funcTramp_foo 11 # 9 # Set Trampoline Address -jump 1 always # 10 # Jump to function: foo # foo(i) -set _main_0 @return_0 # 11 # Set variable to returned value -print _main_0 # 12 # Call to native function # println(foo(i)) -print "\n" # 13 # Call to native function # println(foo(i)) -op add _main_i _main_i 1 # 14 # Execute increment/decrement # i++ -jump 8 lessThan _main_i 10 # 15 # Jump to start of loop -end # 16 # Trampoline back `, + output: `jump 5 always # 0 # Jump to start of main +# +# Function: foo # +# +set _foo_x @funcArg_foo_0 # 1 # Read parameter into variable +op add _foo_0 _foo_x 20 # 2 # Execute operation # x + 20 +set @return_0 _foo_0 # 3 # Set return data # return x + 20 +set @counter @funcTramp_foo # 4 # Trampoline back +# +# Function: main # +# +set _main_i 0 # 5 # Assign value to variable # i := 0 +op lessThan _main_0 _main_i 10 # 6 # Execute operation # i < 10 +jump 9 equal _main_0 true # 7 # Jump into the loop +jump 17 always # 8 # Jump to end of loop +set @funcArg_foo_0 _main_i # 9 # Set foo argument: 0 +set @funcTramp_foo 12 # 10 # Set Trampoline Address +jump 1 always # 11 # Jump to function: foo # foo(i) +set _main_1 @return_0 # 12 # Set variable to returned value +print _main_1 # 13 # Call to native function # println(foo(i)) +print "\n" # 14 # Call to native function # println(foo(i)) +op add _main_i _main_i 1 # 15 # Execute increment/decrement # i++ +jump 6 always # 16 # Jump to start of loop +end # 17 # Trampoline back `, }, } for _, test := range tests { diff --git a/tests/transpiler/statement_test.go b/tests/transpiler/statement_test.go index 1be8566..e057e81 100644 --- a/tests/transpiler/statement_test.go +++ b/tests/transpiler/statement_test.go @@ -32,11 +32,12 @@ print 6`, name: "ForLoop", input: TestMain(`for i := 0; i < 10; i++ { print(i) }`, false, false), output: `set _main_i 0 -jump 3 lessThan _main_i 10 -jump 6 always +op lessThan _main_0 _main_i 10 +jump 4 equal _main_0 true +jump 7 always print _main_i op add _main_i _main_i 1 -jump 3 lessThan _main_i 10`, +jump 1 always`, }, { name: "ForLoop2", @@ -62,8 +63,10 @@ for s.IsEnabled() && a < b { set _main_a 1 set _main_b 2 sensor _main_0 _main_s @enabled -jump 6 equal _main_0 true -jump 8 always +op lessThan _main_1 _main_a _main_b +op land _main_2 _main_0 _main_1 +jump 8 equal _main_2 true +jump 10 always print 1 jump 3 always`, }, @@ -94,31 +97,33 @@ print _main_x`, name: "Break", input: TestMain(`for i := 0; i < 10; i++ { if i == 5 { break; }; println(i); }`, false, false), output: `set _main_i 0 -jump 3 lessThan _main_i 10 -jump 11 always -op equal _main_0 _main_i 5 -jump 6 equal _main_0 1 -jump 7 always -jump 11 always +op lessThan _main_0 _main_i 10 +jump 4 equal _main_0 true +jump 12 always +op equal _main_1 _main_i 5 +jump 7 equal _main_1 1 +jump 8 always +jump 12 always print _main_i print "\n" op add _main_i _main_i 1 -jump 3 lessThan _main_i 10`, +jump 1 always`, }, { name: "Continue", input: TestMain(`for i := 0; i < 10; i++ { if i == 5 { continue; }; println(i); }`, false, false), output: `set _main_i 0 -jump 3 lessThan _main_i 10 -jump 11 always -op equal _main_0 _main_i 5 -jump 6 equal _main_0 1 -jump 7 always -jump 9 always +op lessThan _main_0 _main_i 10 +jump 4 equal _main_0 true +jump 12 always +op equal _main_1 _main_i 5 +jump 7 equal _main_1 1 +jump 8 always +jump 10 always print _main_i print "\n" op add _main_i _main_i 1 -jump 3 lessThan _main_i 10`, +jump 1 always`, }, { name: "Switch", @@ -233,11 +238,12 @@ print 2 jump end loop: set _main_i 0 -jump 7 lessThan _main_i 10 -jump 10 always +op lessThan _main_0 _main_i 10 +jump 8 equal _main_0 true +jump 11 always print 3 op add _main_i _main_i 1 -jump 7 lessThan _main_i 10 +jump 5 always print 4 jump test end: diff --git a/transpiler/statement.go b/transpiler/statement.go index 6f9de09..4a2452d 100644 --- a/transpiler/statement.go +++ b/transpiler/statement.go @@ -335,62 +335,30 @@ func forStmtToMLOG(ctx context.Context, statement *ast.ForStmt) ([]MLOGStatement } if binaryExpr, ok := statement.Cond.(*ast.BinaryExpr); ok { - if translatedOp, ok := jumpOperators[binaryExpr.Op]; ok { - leftSide, leftExprInstructions, err := exprToResolvable(ctx, binaryExpr.X) - if err != nil { - return nil, err - } - results = append(results, leftExprInstructions...) - - if len(leftSide) != 1 { - return nil, Err(ctx, "unknown error") - } - - rightSide, rightExprInstructions, err := exprToResolvable(ctx, binaryExpr.Y) - if err != nil { - return nil, err - } - results = append(results, rightExprInstructions...) - - if len(rightSide) != 1 { - return nil, Err(ctx, "unknown error") - } - - loopStartJump.Condition = []Resolvable{ - &Value{Value: translatedOp}, - leftSide[0], - rightSide[0], - } - - intoLoopJump.Condition = []Resolvable{ - &Value{Value: translatedOp}, - leftSide[0], - rightSide[0], - } - } else { - expr, exprInstructions, err := exprToResolvable(ctx, binaryExpr.X) - if err != nil { - return nil, err - } + // TODO Optimize jump instruction if possible - results = append(results, exprInstructions...) + expr, exprInstructions, err := exprToResolvable(ctx, binaryExpr) + if err != nil { + return nil, err + } - if len(expr) != 1 { - return nil, Err(ctx, "unknown error") - } + results = append(results, exprInstructions...) - loopStartJump.Condition = []Resolvable{ - &Value{Value: "always"}, - } + if len(expr) != 1 { + return nil, Err(ctx, "unknown error") + } - intoLoopJump.Condition = []Resolvable{ - &Value{Value: jumpOperators[token.EQL]}, - expr[0], - &Value{Value: "true"}, - } + loopStartJump.Condition = []Resolvable{ + &Value{Value: "always"}, + } - loopStartOverride = &exprInstructions[0] + intoLoopJump.Condition = []Resolvable{ + &Value{Value: jumpOperators[token.EQL]}, + expr[0], + &Value{Value: "true"}, } + + loopStartOverride = &exprInstructions[0] } else if unaryExpr, ok := statement.Cond.(*ast.UnaryExpr); ok { if unaryExpr.Op != token.NOT { return nil, Err(ctx, fmt.Sprintf("loop unary expresion cannot use this operation: %T", binaryExpr.Op))