From e1bf92f4aac178009ea8664295d3b7f8c87946da Mon Sep 17 00:00:00 2001 From: Marvin Blum Date: Wed, 6 Jan 2016 22:37:59 +0100 Subject: [PATCH] Unary buildin functions, need to fix test! --- src/parser/parser.go | 93 +++++++++++++++++++++++---------- src/parser/parser_test.go | 48 ++++++++--------- src/tokenizer/tokenizer_test.go | 25 +++++---- src/types/loader.go | 8 +-- test/parser_buildin_func.asl | 2 +- 5 files changed, 107 insertions(+), 69 deletions(-) diff --git a/src/parser/parser.go b/src/parser/parser.go index 12f9b37..f4b0fca 100644 --- a/src/parser/parser.go +++ b/src/parser/parser.go @@ -2,7 +2,6 @@ package parser import ( "errors" - "fmt" "strconv" "tokenizer" "types" @@ -221,7 +220,7 @@ func (c *Compiler) parseFunction() { c.expect("func") // check for build in function - if buildin, _ := types.GetFunction(c.get().Token); buildin == true { + if buildin := types.GetFunction(c.get().Token); buildin != nil { panic(errors.New(c.get().Token + " is a build in function, choose a different name")) } @@ -369,42 +368,27 @@ func (c *Compiler) parseFunctionCall(out bool, name string) string { output := "" c.expect("(") - params, paramCount := c.parseParameter(false) + paramsStr, params, paramCount := c.parseParameter(false) c.expect(")") // buildin function - exists, buildin := types.GetFunction(name) + buildin := types.GetFunction(name) - if exists { + if buildin != nil { // check parameter count - if exists && paramCount < buildin.ArgsCount { + if paramCount < buildin.ArgsCount { panic(errors.New("Function expected " + strconv.Itoa(buildin.ArgsCount) + " parameter but found " + strconv.Itoa(paramCount))) } if buildin.Type == types.NULL { output = name } else if buildin.Type == types.UNARY { - if paramCount == 1 { - output = name + " " + params - } else { - output = "[" + params + "] call " + name - } + output = c.parseUnaryFunction(name, paramsStr, paramCount) } else { - // TODO + output = c.parseBinaryFunction(name, params, buildin) } - - fmt.Println(name) - /*if leftParamCount > 1 { - leftParams = "[" + leftParams + "]" - } - - if leftParamCount > 0 { - output = leftParams + " " + name + " " + rightParams - } else { - output = name + " " + rightParams - }*/ } else { - output = "[" + params + "] call " + name + output = "[" + paramsStr + "] call " + name } if out { @@ -414,12 +398,67 @@ func (c *Compiler) parseFunctionCall(out bool, name string) string { return output } -func (c *Compiler) parseParameter(out bool) (string, int) { +func (c *Compiler) parseUnaryFunction(name, paramsStr string, paramCount int) string { output := "" + + if paramCount == 1 { + output = name + " " + paramsStr + } else { + output = "[" + paramsStr + "] call " + name + } + + return output +} + +func (c *Compiler) parseBinaryFunction(name string, params []string, buildin *types.FunctionType) string { + output := "" + + if buildin.ArgsLeft == 1 { + output = params[0] + " " + } else { + output = "[" + + for i := 0; i < buildin.ArgsLeft; i++ { + output += params[i] + + if i != buildin.ArgsLeft-1 { + output += "," + } + } + + output += "] " + } + + output += name + + if buildin.ArgsCount-buildin.ArgsLeft == 1 { + output += " " + params[1] + } else { + output += " [" + + for i := buildin.ArgsLeft; i < buildin.ArgsCount; i++ { + output += params[i] + + if i != buildin.ArgsCount-1 { + output += "," + } + } + + output += "]" + } + + return output +} + +func (c *Compiler) parseParameter(out bool) (string, []string, int) { + output := "" + params := make([]string, 0) count := 0 for !c.accept(")") { - output += c.parseExpression(out) + expr := c.parseExpression(out) + output += expr + params = append(params, expr) count++ if !c.accept(")") { @@ -432,7 +471,7 @@ func (c *Compiler) parseParameter(out bool) (string, int) { c.appendOut(output, false) } - return output, count + return output, params, count } func (c *Compiler) parseExpression(out bool) string { diff --git a/src/parser/parser_test.go b/src/parser/parser_test.go index 43b6c87..4a3378d 100644 --- a/src/parser/parser_test.go +++ b/src/parser/parser_test.go @@ -8,161 +8,161 @@ import ( ) func TestParserDeclaration(t *testing.T) { - got := getCompiled(t, "test/tokenizer_var.asl") + got := getCompiled(t, "../../test/tokenizer_var.asl") want := "x = 1;\r\narray = [1,2,3];\r\n" equal(t, got, want) } func TestParserAssignment(t *testing.T) { - got := getCompiled(t, "test/parser_assignment.asl") + got := getCompiled(t, "../../test/parser_assignment.asl") want := "x = 1;\r\n" equal(t, got, want) } func TestParserIf(t *testing.T) { - got := getCompiled(t, "test/tokenizer_if.asl") + got := getCompiled(t, "../../test/tokenizer_if.asl") want := "if (ab;\r\n};\r\n[1+3/4, 2-(66*22)/3-((123))] call myFunc;\r\n" equal(t, got, want) } func TestParserBuildinFunctionCall(t *testing.T) { - got := getCompiled(t, "test/parser_buildin_func.asl") + got := getCompiled(t, "../../test/parser_buildin_func.asl") want := "_x = (([player, foo] getVar bar) setHit [\"head\", \"tail\"]);\r\n" equal(t, got, want) } func TestParserOperator(t *testing.T) { - got := getCompiled(t, "test/parser_operator.asl") + got := getCompiled(t, "../../test/parser_operator.asl") want := "if (x==y&&x!=y&&x<=y&&x>=y&&xy) then {\r\n};\r\n" equal(t, got, want) } func TestParserTryCatch(t *testing.T) { - got := getCompiled(t, "test/parser_try_catch.asl") + got := getCompiled(t, "../../test/parser_try_catch.asl") want := "try {\r\n} catch {\r\n};\r\n" equal(t, got, want) } func TestParserNegationFunctionCall(t *testing.T) { - got := getCompiled(t, "test/parser_negation.asl") + got := getCompiled(t, "../../test/parser_negation.asl") want := "x = !([] call foo);\r\n" equal(t, got, want) } func TestParserExitWith(t *testing.T) { - got := getCompiled(t, "test/parser_exitwith.asl") + got := getCompiled(t, "../../test/parser_exitwith.asl") want := "if (true) exitWith {\r\n};\r\n" equal(t, got, want) } func TestParserWaitUntil(t *testing.T) { - got := getCompiled(t, "test/parser_waituntil.asl") + got := getCompiled(t, "../../test/parser_waituntil.asl") want := "waitUntil {x=x+1;x<100};\r\n" equal(t, got, want) } func TestParserArray(t *testing.T) { - got := getCompiled(t, "test/parser_array.asl") + got := getCompiled(t, "../../test/parser_array.asl") want := "x = [1,2,3];\r\ny = (x select (1));\r\n" equal(t, got, want) } func TestParserFunctionParams(t *testing.T) { - got := getCompiled(t, "test/parser_func_params.asl") + got := getCompiled(t, "../../test/parser_func_params.asl") want := "myFunc = {\r\nparams [[\"a\",1],[\"b\",2]];\r\nreturn a+b;\r\n};\r\n" equal(t, got, want) } func TestParserInlineCode(t *testing.T) { - got := getCompiled(t, "test/parser_code.asl") + got := getCompiled(t, "../../test/parser_code.asl") want := "inline_code = {a = 1;b = 2;if (a", "allUnits", "{", "}"} compareLength(t, &got, &want) @@ -47,7 +47,7 @@ func TestTokenizerForach(t *testing.T) { } func TestTokenizerSwitch(t *testing.T) { - got := getTokens(t, "test/tokenizer_switch.asl") + got := getTokens(t, "../../test/tokenizer_switch.asl") want := []string{"switch", "x", "{", "case", "1", ":", "x", "=", "1", ";", "case", "2", ":", "x", "=", "2", ";", "default", ":", "x", "=", "3", ";", "}"} compareLength(t, &got, &want) @@ -55,7 +55,7 @@ func TestTokenizerSwitch(t *testing.T) { } func TestTokenizerFunction(t *testing.T) { - got := getTokens(t, "test/tokenizer_func.asl") + got := getTokens(t, "../../test/tokenizer_func.asl") want := []string{"func", "TestFunction", "(", "param0", ",", "param1", ")", "{", "return", "true", ";", "}"} compareLength(t, &got, &want) @@ -63,7 +63,7 @@ func TestTokenizerFunction(t *testing.T) { } func TestTokenizerExpression(t *testing.T) { - got := getTokens(t, "test/tokenizer_expr.asl") + got := getTokens(t, "../../test/tokenizer_expr.asl") want := []string{"x", "=", "(", "(", "1", "+", "2", "+", "3", ")", "*", "4", "/", "2", ")", "+", "foo", "(", "1", ",", "2", ",", "3", ")", ";"} compareLength(t, &got, &want) @@ -71,7 +71,7 @@ func TestTokenizerExpression(t *testing.T) { } func TestTokenizerIdentifier(t *testing.T) { - got := getTokens(t, "test/tokenizer_identifier.asl") + got := getTokens(t, "../../test/tokenizer_identifier.asl") want := []string{"var", "format", "=", "\"should not be for mat!\"", ";"} compareLength(t, &got, &want) @@ -79,7 +79,7 @@ func TestTokenizerIdentifier(t *testing.T) { } func TestTokenizerInlineCode(t *testing.T) { - got := getTokens(t, "test/tokenizer_code.asl") + got := getTokens(t, "../../test/tokenizer_code.asl") want := []string{"var", "x", "=", "code", "(", "\"var x = 5;\"", ")", ";"} compareLength(t, &got, &want) @@ -87,7 +87,7 @@ func TestTokenizerInlineCode(t *testing.T) { } func TestTokenizerPreprocessor(t *testing.T) { - got := getTokens(t, "test/tokenizer_preprocessor.asl") + got := getTokens(t, "../../test/tokenizer_preprocessor.asl") want := []string{"#define HELLO_WORLD \"Hello World!\"", "hint", "(", ")", "(", "HELLO_WORLD", ")", ";"} compareLength(t, &got, &want) @@ -95,8 +95,7 @@ func TestTokenizerPreprocessor(t *testing.T) { } func TestTokenizerMask(t *testing.T) { - got := getTokens(t, "test/tokenizer_mask.asl") - //var y = code("var z = \"Hello \\"World\\"\";"); + got := getTokens(t, "../../test/tokenizer_mask.asl") want := []string{"var", "x", "=", "\"Hello \\\"World\\\"\"", ";", "var", "y", "=", "code", "(", "\"var z = \\\"Hello \\\\\"World\\\\\"\\\";\"", ")", ";"} diff --git a/src/types/loader.go b/src/types/loader.go index 3f230d3..0c3d904 100644 --- a/src/types/loader.go +++ b/src/types/loader.go @@ -29,17 +29,17 @@ type FunctionType struct { var functions []FunctionType // Returns function type information by name. -// If not found, the first parameter will be false. -func GetFunction(name string) (bool, FunctionType) { +// If not found, the parameter will be nil. +func GetFunction(name string) *FunctionType { name = strings.ToLower(name) for _, function := range functions { if function.Name == name { - return true, function + return &function } } - return false, FunctionType{} + return nil } // Loads type information from file. diff --git a/test/parser_buildin_func.asl b/test/parser_buildin_func.asl index 0b36daa..d64aeba 100644 --- a/test/parser_buildin_func.asl +++ b/test/parser_buildin_func.asl @@ -1 +1 @@ -var _x = setHit(getVar(player, foo)(bar))("head", "tail"); +var _x = setHit(getVar(player, foo, bar), "head", "tail");