diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c6a8b3b..3eabddb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,9 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Warm up pkg.go.dev + uses: andrewslotin/go-proxy-pull-action@master + pages: name: Pages runs-on: ubuntu-latest diff --git a/README.md b/README.md index 6296a11..e0aa27b 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![codecov](https://codecov.io/gh/Vilsol/go-mlog/branch/master/graph/badge.svg?token=LFNKYWS0N2)](https://codecov.io/gh/Vilsol/go-mlog) [![CodeFactor](https://www.codefactor.io/repository/github/vilsol/go-mlog/badge)](https://www.codefactor.io/repository/github/vilsol/go-mlog) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/vilsol/go-mlog) +[![godoc reference](https://img.shields.io/badge/godoc-reference-5272B4)](https://pkg.go.dev/github.com/Vilsol/go-mlog) Go to MLOG transpiler. @@ -34,6 +35,7 @@ A Web IDE is available [here](https://vilsol.github.io/go-mlog-web/?1) * Variable argument count functions * Multiple function return values * Optimize simple jump instructions +* Multi-pass post-processing ## Design Limitations diff --git a/m/base.go b/m/base.go index 110ac1e..698f4c6 100644 --- a/m/base.go +++ b/m/base.go @@ -1,18 +1,20 @@ package m import ( + "errors" "github.com/Vilsol/go-mlog/transpiler" "strings" ) func init() { transpiler.RegisterFuncTranslation("m.Read", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { memoryName := strings.Trim(args[0].GetValue(), "\"") if memoryName == transpiler.StackCellName { - panic("can't read/write to memory cell that is used for the stack: " + transpiler.StackCellName) + return nil, errors.New("can't read/write to memory cell that is used for the stack: " + transpiler.StackCellName) } return []transpiler.MLOGStatement{ @@ -20,22 +22,22 @@ func init() { Statement: [][]transpiler.Resolvable{ { &transpiler.Value{Value: "read"}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], &transpiler.Value{Value: memoryName}, &transpiler.Value{Value: args[1].GetValue()}, }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.Write", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { memoryName := strings.Trim(args[1].GetValue(), "\"") if memoryName == transpiler.StackCellName { - panic("can't read/write to memory cell that is used for the stack: " + transpiler.StackCellName) + return nil, errors.New("can't read/write to memory cell that is used for the stack: " + transpiler.StackCellName) } return []transpiler.MLOGStatement{ @@ -49,12 +51,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.PrintFlush", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -64,28 +66,30 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.GetLink", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ { &transpiler.Value{Value: "getlink"}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], &transpiler.Value{Value: args[0].GetValue()}, }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.Radar", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -97,28 +101,29 @@ func init() { &transpiler.Value{Value: args[5].GetValue()}, &transpiler.Value{Value: args[0].GetValue()}, &transpiler.Value{Value: args[4].GetValue()}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.Sensor", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ { &transpiler.Value{Value: "sensor"}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], &transpiler.Value{Value: args[0].GetValue()}, &transpiler.Value{Value: args[1].GetValue()}, }, }, }, - } + }, nil }, }) } diff --git a/m/control.go b/m/control.go index 0b4440b..75aaf96 100644 --- a/m/control.go +++ b/m/control.go @@ -5,7 +5,7 @@ import "github.com/Vilsol/go-mlog/transpiler" func init() { transpiler.RegisterFuncTranslation("m.ControlEnabled", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -17,12 +17,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.ControlShoot", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -36,12 +36,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.ControlShootP", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -54,12 +54,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.ControlConfigure", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -71,7 +71,7 @@ func init() { }, }, }, - } + }, nil }, }) } diff --git a/m/draw.go b/m/draw.go index 2459c4b..e6346b3 100644 --- a/m/draw.go +++ b/m/draw.go @@ -8,7 +8,7 @@ import ( func init() { transpiler.RegisterFuncTranslation("m.DrawClear", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -21,12 +21,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawColor", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -40,12 +40,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawStroke", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -56,12 +56,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawLine", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -75,12 +75,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawRect", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -94,12 +94,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawLineRect", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -113,12 +113,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawPoly", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -133,12 +133,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawLinePoly", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -153,12 +153,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawTriangle", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -174,12 +174,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawImage", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -194,12 +194,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.DrawFlush", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -209,7 +209,7 @@ func init() { }, }, }, - } + }, nil }, }) } diff --git a/m/operations.go b/m/operations.go index 7cb890e..10c17fb 100644 --- a/m/operations.go +++ b/m/operations.go @@ -4,37 +4,39 @@ import "github.com/Vilsol/go-mlog/transpiler" func init() { transpiler.RegisterFuncTranslation("m.Floor", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ { &transpiler.Value{Value: "op"}, &transpiler.Value{Value: "floor"}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], &transpiler.Value{Value: args[0].GetValue()}, }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.Random", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ { &transpiler.Value{Value: "op"}, &transpiler.Value{Value: "rand"}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], &transpiler.Value{Value: args[0].GetValue()}, }, }, }, - } + }, nil }, }) } diff --git a/m/unit.go b/m/unit.go index 5beac13..de1b6bc 100644 --- a/m/unit.go +++ b/m/unit.go @@ -1,11 +1,14 @@ package m -import "github.com/Vilsol/go-mlog/transpiler" +import ( + "github.com/Vilsol/go-mlog/transpiler" + "strings" +) func init() { transpiler.RegisterFuncTranslation("m.UnitBind", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -15,41 +18,123 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitRadar", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ { - &transpiler.Value{Value: "radar"}, + &transpiler.Value{Value: "uradar"}, &transpiler.Value{Value: args[0].GetValue()}, &transpiler.Value{Value: args[1].GetValue()}, &transpiler.Value{Value: args[2].GetValue()}, &transpiler.Value{Value: args[4].GetValue()}, &transpiler.Value{Value: "turret1"}, // Remove once fixed in game &transpiler.Value{Value: args[3].GetValue()}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], }, }, }, - } + }, nil + }, + }) + transpiler.RegisterFuncTranslation("m.UnitLocateOre", transpiler.Translator{ + Count: 1, + Variables: 3, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { + return []transpiler.MLOGStatement{ + &transpiler.MLOG{ + Statement: [][]transpiler.Resolvable{ + { + &transpiler.Value{Value: "ulocate"}, + &transpiler.Value{Value: "ore"}, + &transpiler.Value{Value: "core"}, // Remove once fixed in game + &transpiler.Value{Value: "true"}, // Remove once fixed in game + &transpiler.Value{Value: strings.Trim(args[0].GetValue(), "\"")}, + vars[0], + vars[1], + vars[2], + &transpiler.Value{Value: "null"}, // Remove once fixed in game + }, + }, + }, + }, nil + }, + }) + transpiler.RegisterFuncTranslation("m.UnitLocateBuilding", transpiler.Translator{ + Count: 1, + Variables: 4, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { + return []transpiler.MLOGStatement{ + &transpiler.MLOG{ + Statement: [][]transpiler.Resolvable{ + { + &transpiler.Value{Value: "ulocate"}, + &transpiler.Value{Value: "building"}, + &transpiler.Value{Value: args[0].GetValue()}, + &transpiler.Value{Value: args[1].GetValue()}, + &transpiler.Value{Value: "@copper"}, // Remove once fixed in game + vars[0], + vars[1], + vars[2], + vars[3], + }, + }, + }, + }, nil + }, + }) + transpiler.RegisterFuncTranslation("m.UnitLocateSpawn", transpiler.Translator{ + Count: 1, + Variables: 4, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { + return []transpiler.MLOGStatement{ + &transpiler.MLOG{ + Statement: [][]transpiler.Resolvable{ + { + &transpiler.Value{Value: "ulocate"}, + &transpiler.Value{Value: "spawn"}, + &transpiler.Value{Value: "core"}, // Remove once fixed in game + &transpiler.Value{Value: "true"}, // Remove once fixed in game + &transpiler.Value{Value: "@copper"}, // Remove once fixed in game + vars[0], + vars[1], + vars[2], + vars[3], + }, + }, + }, + }, nil + }, + }) + transpiler.RegisterFuncTranslation("m.UnitLocateDamaged", transpiler.Translator{ + Count: 1, + Variables: 4, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { + return []transpiler.MLOGStatement{ + &transpiler.MLOG{ + Statement: [][]transpiler.Resolvable{ + { + &transpiler.Value{Value: "ulocate"}, + &transpiler.Value{Value: "damaged"}, + &transpiler.Value{Value: "core"}, // Remove once fixed in game + &transpiler.Value{Value: "true"}, // Remove once fixed in game + &transpiler.Value{Value: "@copper"}, // Remove once fixed in game + vars[0], + vars[1], + vars[2], + vars[3], + }, + }, + }, + }, nil }, }) - // TODO UnitLocateOre - // ulocate ore storage A @copper B C D E - - // TODO UnitLocateBuilding - // ulocate building storage A @copper B C D E - - // TODO UnitLocateSpawn - // ulocate spawn core A @copper B C D E - - // TODO UnitLocateDamaged - // ulocate damaged core A @copper B C D E } // TODO Docs diff --git a/m/unit_control.go b/m/unit_control.go index 6630b35..e912ead 100644 --- a/m/unit_control.go +++ b/m/unit_control.go @@ -5,7 +5,7 @@ import "github.com/Vilsol/go-mlog/transpiler" func init() { transpiler.RegisterFuncTranslation("m.UnitStop", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -15,12 +15,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitMove", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -32,12 +32,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitApproach", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -50,12 +50,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitBoost", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -66,12 +66,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitPathfind", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -81,12 +81,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitTarget", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -99,12 +99,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitTargetP", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -116,12 +116,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitItemDrop", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -133,12 +133,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitItemTake", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -151,12 +151,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitPayloadDrop", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -166,12 +166,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitPayloadTake", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -182,12 +182,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitMine", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -199,12 +199,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitFlag", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -215,12 +215,12 @@ func init() { }, }, }, - } + }, nil }, }) transpiler.RegisterFuncTranslation("m.UnitBuild", transpiler.Translator{ Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -235,14 +235,33 @@ func init() { }, }, }, - } + }, nil + }, + }) + transpiler.RegisterFuncTranslation("m.UnitGetBlock", transpiler.Translator{ + Count: 1, + Variables: 2, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { + return []transpiler.MLOGStatement{ + &transpiler.MLOG{ + Statement: [][]transpiler.Resolvable{ + { + &transpiler.Value{Value: "ucontrol"}, + &transpiler.Value{Value: "getBlock"}, + &transpiler.Value{Value: args[0].GetValue()}, + &transpiler.Value{Value: args[1].GetValue()}, + vars[0], + vars[1], + }, + }, + }, + }, nil }, }) - // TODO UnitGetBlock - // ucontrol getBlock A B C D transpiler.RegisterFuncTranslation("m.UnitWithin", transpiler.Translator{ - Count: 1, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Count: 1, + Variables: 1, + Translate: func(args []transpiler.Resolvable, vars []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { return []transpiler.MLOGStatement{ &transpiler.MLOG{ Statement: [][]transpiler.Resolvable{ @@ -252,11 +271,11 @@ func init() { &transpiler.Value{Value: args[0].GetValue()}, &transpiler.Value{Value: args[1].GetValue()}, &transpiler.Value{Value: args[2].GetValue()}, - &transpiler.Value{Value: transpiler.FunctionReturnVariable}, + vars[0], }, }, }, - } + }, nil }, }) } diff --git a/tests/base_test.go b/tests/base_test.go index 24a56a6..8ad8be0 100644 --- a/tests/base_test.go +++ b/tests/base_test.go @@ -15,8 +15,8 @@ func TestBase(t *testing.T) { }{ { name: "Read", - input: TestMain(`m.Read("cell1", 0)`), - output: `read @return cell1 0`, + input: TestMain(`x := m.Read("cell1", 0)`), + output: `read _main_x cell1 0`, }, { name: "Write", @@ -30,18 +30,18 @@ func TestBase(t *testing.T) { }, { name: "GetLink", - input: TestMain(`m.GetLink(0)`), - output: `getlink @return 0`, + input: TestMain(`x := m.GetLink(0)`), + output: `getlink _main_x 0`, }, { name: "Radar", - input: TestMain(`m.Radar("A", m.RTAlly, m.RTEnemy, m.RTBoss, 0, m.RSArmor)`), - output: `radar ally enemy boss armor "A" 0 @return`, + input: TestMain(`x := m.Radar("A", m.RTAlly, m.RTEnemy, m.RTBoss, 0, m.RSArmor)`), + output: `radar ally enemy boss armor "A" 0 _main_x`, }, { name: "Sensor", - input: TestMain(`m.Sensor("A", "B")`), - output: `sensor @return "A" "B"`, + input: TestMain(`x := m.Sensor("A", "B")`), + output: `sensor _main_x "A" "B"`, }, } for _, test := range tests { diff --git a/tests/errors_test.go b/tests/errors_test.go index 424d874..8a6217f 100644 --- a/tests/errors_test.go +++ b/tests/errors_test.go @@ -120,6 +120,39 @@ func main() { }`, output: `unknown constant type: *ast.BinaryExpr`, }, + { + name: "EmptyPrintlnError", + input: TestMain(`println()`), + output: `println with 0 arguments`, + }, + { + name: "EmptyPrintError", + input: TestMain(`print()`), + output: `print with 0 arguments`, + }, + { + name: "ErrorWriteToStack", + input: TestMain(`m.Write(0, "bank1", 0)`), + output: `can't read/write to memory cell that is used for the stack: bank1`, + }, + { + name: "ErrorReadFromStack", + input: TestMain(`x := m.Read("bank1", 0)`), + output: `can't read/write to memory cell that is used for the stack: bank1`, + }, + { + name: "SingleValueReturns", + input: `package main + +func main() { + sample() +} + +func sample() (int, int) { + return 1, 2 +}`, + output: `only single value returns are supported`, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -140,13 +173,3 @@ func TestRegisterFuncTranslationPanic(t *testing.T) { transpiler.RegisterFuncTranslation("print", transpiler.Translator{}) }) } - -func TestEmptyPrintPanic(t *testing.T) { - assert.Panics(t, func() { - _, _ = transpiler.GolangToMLOG(TestMain(`println()`), transpiler.Options{}) - }) - - assert.Panics(t, func() { - _, _ = transpiler.GolangToMLOG(TestMain(`print()`), transpiler.Options{}) - }) -} diff --git a/tests/function_test.go b/tests/function_test.go index 1a246f9..f92b116 100644 --- a/tests/function_test.go +++ b/tests/function_test.go @@ -42,13 +42,11 @@ op add @stack @stack 1 op add _main_0 1 2 write _main_0 bank1 @stack op add @stack @stack 1 -op rand @return 100 -set _main_1 @return -op floor @return _main_1 -set _main_2 @return +op rand _main_1 100 +op floor _main_2 _main_1 write _main_2 bank1 @stack op add @stack @stack 1 -write 21 bank1 @stack +write 19 bank1 @stack jump 2 always op sub @stack @stack 3 set _main_3 @return diff --git a/tests/unit_control_test.go b/tests/unit_control_test.go index 7e60001..d39b72e 100644 --- a/tests/unit_control_test.go +++ b/tests/unit_control_test.go @@ -83,10 +83,15 @@ func TestUnitControl(t *testing.T) { input: TestMain(`m.UnitBuild(1, 2, "A", 3, 4)`), output: `ucontrol build 1 2 "A" 3 4`, }, + { + name: "UnitGetBlock", + input: TestMain(`x, y := m.UnitGetBlock(1, 2)`), + output: `ucontrol getBlock 1 2 _main_x _main_y`, + }, { name: "UnitWithin", - input: TestMain(`m.UnitWithin(1, 2, 3)`), - output: `ucontrol within 1 2 3 @return`, + input: TestMain(`x := m.UnitWithin(1, 2, 3)`), + output: `ucontrol within 1 2 3 _main_x`, }, } for _, test := range tests { diff --git a/tests/unit_test.go b/tests/unit_test.go index 2338fd5..0e5c85b 100644 --- a/tests/unit_test.go +++ b/tests/unit_test.go @@ -20,8 +20,28 @@ func TestUnit(t *testing.T) { }, { name: "UnitRadar", - input: TestMain(`m.UnitRadar(m.RTAlly, m.RTEnemy, m.RTBoss, 0, m.RSArmor)`), - output: `radar ally enemy boss armor turret1 0 @return`, + input: TestMain(`x := m.UnitRadar(m.RTAlly, m.RTEnemy, m.RTBoss, 0, m.RSArmor)`), + output: `uradar ally enemy boss armor turret1 0 _main_x`, + }, + { + name: "UnitLocateOre", + input: TestMain(`x, y, z := m.UnitLocateOre("@copper")`), + output: `ulocate ore core true @copper _main_x _main_y _main_z null`, + }, + { + name: "UnitLocateBuilding", + input: TestMain(`x, y, z, b := m.UnitLocateBuilding(m.BCore, 1)`), + output: `ulocate building core 1 @copper _main_x _main_y _main_z _main_b`, + }, + { + name: "UnitLocateSpawn", + input: TestMain(`x, y, z, b := m.UnitLocateSpawn()`), + output: `ulocate spawn core true @copper _main_x _main_y _main_z _main_b`, + }, + { + name: "UnitLocateDamaged", + input: TestMain(`x, y, z, b := m.UnitLocateDamaged()`), + output: `ulocate damaged core true @copper _main_x _main_y _main_z _main_b`, }, } for _, test := range tests { diff --git a/transpiler/expression.go b/transpiler/expression.go index f28f733..16a8e3b 100644 --- a/transpiler/expression.go +++ b/transpiler/expression.go @@ -8,7 +8,7 @@ import ( "strings" ) -func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGStatement, error) { +func expressionToMLOG(ident []Resolvable, expr ast.Expr, options Options) ([]MLOGStatement, error) { switch expr.(type) { case *ast.BasicLit: basicExpr := expr.(*ast.BasicLit) @@ -23,7 +23,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS Statement: [][]Resolvable{ { &Value{Value: "set"}, - ident, + ident[0], &Value{Value: value}, }, }, @@ -37,7 +37,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS Statement: [][]Resolvable{ { &Value{Value: "set"}, - ident, + ident[0], &Value{Value: identExpr.Name}, }, }, @@ -49,7 +49,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS Statement: [][]Resolvable{ { &Value{Value: "set"}, - ident, + ident[0], &NormalVariable{Name: identExpr.Name}, }, }, @@ -69,7 +69,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS } else if leftExpr, ok := binaryExpr.X.(ast.Expr); ok { dVar := &DynamicVariable{} - exprInstructions, err := expressionToMLOG(dVar, leftExpr, options) + exprInstructions, err := expressionToMLOG([]Resolvable{dVar}, leftExpr, options) if err != nil { return nil, err } @@ -87,7 +87,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS } else if rightExpr, ok := binaryExpr.Y.(ast.Expr); ok { dVar := &DynamicVariable{} - exprInstructions, err := expressionToMLOG(dVar, rightExpr, options) + exprInstructions, err := expressionToMLOG([]Resolvable{dVar}, rightExpr, options) if err != nil { return nil, err } @@ -104,7 +104,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS { &Value{Value: "op"}, &Value{Value: opTranslated}, - ident, + ident[0], leftSide, rightSide, }, @@ -114,22 +114,10 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS return nil, errors.New(fmt.Sprintf("operator statement cannot use this operation: %s", binaryExpr.Op.String())) } case *ast.CallExpr: - callInstructions, err := callExprToMLOG(expr.(*ast.CallExpr), options) + callInstructions, err := callExprToMLOG(expr.(*ast.CallExpr), ident, options) if err != nil { return nil, err } - - callInstructions = append(callInstructions, &MLOG{ - Comment: "Set the variable to the value", - Statement: [][]Resolvable{ - { - &Value{Value: "set"}, - ident, - &Value{Value: FunctionReturnVariable}, - }, - }, - }) - return callInstructions, err case *ast.UnaryExpr: unaryExpr := expr.(*ast.UnaryExpr) @@ -145,7 +133,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS } else if leftExpr, ok := unaryExpr.X.(ast.Expr); ok { dVar := &DynamicVariable{} - exprInstructions, err := expressionToMLOG(dVar, leftExpr, options) + exprInstructions, err := expressionToMLOG([]Resolvable{dVar}, leftExpr, options) if err != nil { return nil, err } @@ -162,7 +150,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS statement = []Resolvable{ &Value{Value: "op"}, &Value{Value: regularOperators[token.NOT]}, - ident, + ident[0], x, &Value{Value: "-1"}, } @@ -171,7 +159,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS statement = []Resolvable{ &Value{Value: "op"}, &Value{Value: regularOperators[token.MUL]}, - ident, + ident[0], x, &Value{Value: "-1"}, } @@ -197,7 +185,7 @@ func expressionToMLOG(ident Resolvable, expr ast.Expr, options Options) ([]MLOGS } return instructions, nil case *ast.SelectorExpr: - mlog, _, err := selectorExprToMLOG(ident, expr.(*ast.SelectorExpr)) + mlog, _, err := selectorExprToMLOG(ident[0], expr.(*ast.SelectorExpr)) return mlog, err default: return nil, errors.New(fmt.Sprintf("unsupported expression type: %T", expr)) @@ -232,7 +220,7 @@ func selectorExprToMLOG(ident Resolvable, selectorExpr *ast.SelectorExpr) ([]MLO return nil, "", errors.New(fmt.Sprintf("unknown selector: %s", name)) } -func callExprToMLOG(callExpr *ast.CallExpr, options Options) ([]MLOGStatement, error) { +func callExprToMLOG(callExpr *ast.CallExpr, ident []Resolvable, options Options) ([]MLOGStatement, error) { results := make([]MLOGStatement, 0) var funcName string @@ -253,6 +241,7 @@ func callExprToMLOG(callExpr *ast.CallExpr, options Options) ([]MLOGStatement, e results = append(results, &MLOGFunc{ Function: translatedFunc, Arguments: args, + Variables: ident, }) } else { for _, arg := range callExpr.Args { @@ -268,7 +257,7 @@ func callExprToMLOG(callExpr *ast.CallExpr, options Options) ([]MLOGStatement, e } else if argExpr, ok := arg.(ast.Expr); ok { dVar := &DynamicVariable{} - instructions, err := expressionToMLOG(dVar, argExpr, options) + instructions, err := expressionToMLOG([]Resolvable{dVar}, argExpr, options) if err != nil { return nil, err } @@ -322,6 +311,19 @@ func callExprToMLOG(callExpr *ast.CallExpr, options Options) ([]MLOGStatement, e Action: "sub", Extra: len(callExpr.Args), }) + + if len(ident) > 0 { + results = append(results, &MLOG{ + Comment: "Set the variable to the value", + Statement: [][]Resolvable{ + { + &Value{Value: "set"}, + ident[0], + &Value{Value: FunctionReturnVariable}, + }, + }, + }) + } } return results, nil @@ -345,7 +347,7 @@ func argumentsToResolvables(args []ast.Expr, options Options) ([]Resolvable, []M } else if expr, ok := arg.(ast.Expr); ok { dVar := &DynamicVariable{} - exprInstructions, err := expressionToMLOG(dVar, expr, options) + exprInstructions, err := expressionToMLOG([]Resolvable{dVar}, expr, options) if err != nil { return nil, nil, err } diff --git a/transpiler/statement.go b/transpiler/statement.go index cebce95..665f791 100644 --- a/transpiler/statement.go +++ b/transpiler/statement.go @@ -20,15 +20,11 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro break } - if initStmt, ok := forStatement.Init.(ast.Stmt); ok { - initMlog, err := statementToMLOG(initStmt, options) - if err != nil { - return nil, err - } - results = append(results, initMlog...) - } else { - return nil, errors.New("for loop can only have variable assignment initiators") + initMlog, err := statementToMLOG(forStatement.Init, options) + if err != nil { + return nil, err } + results = append(results, initMlog...) var loopStartJump *MLOGJump if binaryExpr, ok := forStatement.Cond.(*ast.BinaryExpr); ok { @@ -77,28 +73,11 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro results = append(results, bodyMLOG...) - // TODO Support more statements - if incDecStatement, ok := forStatement.Post.(*ast.IncDecStmt); ok { - name := &NormalVariable{Name: incDecStatement.X.(*ast.Ident).Name} - op := "add" - if incDecStatement.Tok == token.DEC { - op = "sub" - } - results = append(results, &MLOG{ - Comment: "Execute for loop post condition increment/decrement", - Statement: [][]Resolvable{ - { - &Value{Value: "op"}, - &Value{Value: op}, - name, - name, - &Value{Value: "1"}, - }, - }, - }) - } else { - return nil, errors.New("for loop supports only increment or decrement post statements") + instructions, err := statementToMLOG(forStatement.Post, options) + if err != nil { + return nil, err } + results = append(results, instructions...) loopStartJump.JumpTarget = bodyMLOG[0] results = append(results, loopStartJump) @@ -107,16 +86,12 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro case *ast.ExprStmt: expressionStatement := statement.(*ast.ExprStmt) - if callExpression, ok := expressionStatement.X.(*ast.CallExpr); ok { - instructions, err := callExprToMLOG(callExpression, options) - if err != nil { - return nil, err - } - results = append(results, instructions...) - } else { - return nil, errors.New(fmt.Sprintf("unknown expression statement: %T", expressionStatement.X)) + instructions, err := expressionToMLOG(nil, expressionStatement.X, options) + if err != nil { + return nil, err } + results = append(results, instructions...) break case *ast.IfStmt: ifStmt := statement.(*ast.IfStmt) @@ -131,7 +106,7 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro dVar := &DynamicVariable{} - instructions, err := expressionToMLOG(dVar, ifStmt.Cond, options) + instructions, err := expressionToMLOG([]Resolvable{dVar}, ifStmt.Cond, options) if err != nil { return nil, err } @@ -224,7 +199,7 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro } else if expr, ok := returnValue.(ast.Expr); ok { dVar := &DynamicVariable{} - instructions, err := expressionToMLOG(dVar, expr, options) + instructions, err := expressionToMLOG([]Resolvable{dVar}, expr, options) if err != nil { return nil, err } @@ -259,6 +234,26 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro results = append(results, instructions...) } break + case *ast.IncDecStmt: + incDecStatement := statement.(*ast.IncDecStmt) + name := &NormalVariable{Name: incDecStatement.X.(*ast.Ident).Name} + op := "add" + if incDecStatement.Tok == token.DEC { + op = "sub" + } + results = append(results, &MLOG{ + Comment: "Execute for loop post condition increment/decrement", + Statement: [][]Resolvable{ + { + &Value{Value: "op"}, + &Value{Value: op}, + name, + name, + &Value{Value: "1"}, + }, + }, + }) + break default: return nil, errors.New(fmt.Sprintf("statement type not supported: %T", statement)) } @@ -269,19 +264,37 @@ func statementToMLOG(statement ast.Stmt, options Options) ([]MLOGStatement, erro func assignStmtToMLOG(statement *ast.AssignStmt, options Options) ([]MLOGStatement, error) { mlog := make([]MLOGStatement, 0) - for i, expr := range statement.Lhs { - if ident, ok := expr.(*ast.Ident); ok { - if statement.Tok != token.ASSIGN && statement.Tok != token.DEFINE { - return nil, errors.New("only direct assignment is supported") + if len(statement.Lhs) != len(statement.Rhs) { + if len(statement.Rhs) == 1 { + leftSide := make([]Resolvable, len(statement.Lhs)) + + for i, lhs := range statement.Lhs { + leftSide[i] = &NormalVariable{Name: lhs.(*ast.Ident).Name} } - exprMLOG, err := expressionToMLOG(&NormalVariable{Name: ident.Name}, statement.Rhs[i], options) + exprMLOG, err := expressionToMLOG(leftSide, statement.Rhs[0], options) if err != nil { return nil, err } mlog = append(mlog, exprMLOG...) } else { - return nil, errors.New("left side variable assignment can only contain identifications") + return nil, errors.New("mismatched variable assignment sides") + } + } else { + for i, expr := range statement.Lhs { + if ident, ok := expr.(*ast.Ident); ok { + if statement.Tok != token.ASSIGN && statement.Tok != token.DEFINE { + return nil, errors.New("only direct assignment is supported") + } + + exprMLOG, err := expressionToMLOG([]Resolvable{&NormalVariable{Name: ident.Name}}, statement.Rhs[i], options) + if err != nil { + return nil, err + } + mlog = append(mlog, exprMLOG...) + } else { + return nil, errors.New("left side variable assignment can only contain identifications") + } } } diff --git a/transpiler/translations.go b/transpiler/translations.go index 7e70bc8..51cc0ef 100644 --- a/transpiler/translations.go +++ b/transpiler/translations.go @@ -1,10 +1,10 @@ package transpiler type Translator struct { - Count int + Count int + Variables int - // TODO Pass return variable as argument - Translate func(args []Resolvable) []MLOGStatement + Translate func(args []Resolvable, vars []Resolvable) ([]MLOGStatement, error) } var funcTranslations = map[string]Translator{} diff --git a/transpiler/translations_native.go b/transpiler/translations_native.go index 2322fe6..3b797e8 100644 --- a/transpiler/translations_native.go +++ b/transpiler/translations_native.go @@ -1,11 +1,13 @@ package transpiler +import "errors" + func init() { RegisterFuncTranslation("print", Translator{ Count: 1, - Translate: func(args []Resolvable) []MLOGStatement { + Translate: func(args []Resolvable, _ []Resolvable) ([]MLOGStatement, error) { if len(args) == 0 { - panic("print with 0 arguments") + return nil, errors.New("print with 0 arguments") } return []MLOGStatement{ &MLOG{ @@ -16,14 +18,14 @@ func init() { }, }, }, - } + }, nil }, }) RegisterFuncTranslation("println", Translator{ Count: 2, - Translate: func(args []Resolvable) []MLOGStatement { + Translate: func(args []Resolvable, _ []Resolvable) ([]MLOGStatement, error) { if len(args) == 0 { - panic("println with 0 arguments") + return nil, errors.New("println with 0 arguments") } return []MLOGStatement{ &MLOG{ @@ -42,7 +44,7 @@ func init() { }, }, }, - } + }, nil }, }) } diff --git a/transpiler/types.go b/transpiler/types.go index 792ad5e..afbb88d 100644 --- a/transpiler/types.go +++ b/transpiler/types.go @@ -108,6 +108,7 @@ type MLOGFunc struct { Position int Function Translator Arguments []Resolvable + Variables []Resolvable Unresolved []MLOGStatement } @@ -129,12 +130,22 @@ func (m *MLOGFunc) SetPosition(position int) int { } func (m *MLOGFunc) PostProcess(global *Global, function *Function) error { + if len(m.Variables) != m.Function.Variables { + return errors.New(fmt.Sprintf("function requires %d variables, provided: %d", m.Function.Variables, len(m.Variables))) + } + for _, argument := range m.Arguments { if err := argument.PostProcess(global, function); err != nil { return err } } - m.Unresolved = m.Function.Translate(m.Arguments) + + var err error + m.Unresolved, err = m.Function.Translate(m.Arguments, m.Variables) + if err != nil { + return err + } + for i, statement := range m.Unresolved { statement.SetPosition(m.Position + i) if err := statement.PostProcess(global, function); err != nil { diff --git a/x/main.go b/x/main.go index a67e973..af749e9 100644 --- a/x/main.go +++ b/x/main.go @@ -5,7 +5,7 @@ import "github.com/Vilsol/go-mlog/transpiler" func init() { transpiler.RegisterFuncTranslation("x.Sleep", transpiler.Translator{ Count: 2, - Translate: func(args []transpiler.Resolvable) []transpiler.MLOGStatement { + Translate: func(args []transpiler.Resolvable, _ []transpiler.Resolvable) ([]transpiler.MLOGStatement, error) { dVar := &transpiler.DynamicVariable{} jump := &transpiler.MLOGJump{ @@ -35,7 +35,7 @@ func init() { }, }, jump, - } + }, nil }, }) }