package parser import ( "strings" "testing" "usebox.net/lang/ast" "usebox.net/lang/errors" "usebox.net/lang/tokenizer" ) func parse(input string) ([]ast.Expr, error) { tr := tokenizer.NewTokenizer("-", strings.NewReader(input)) toks, err := tr.Scan() if err != nil { return nil, err } p := NewParser(nil) return p.Parse(toks) } func expectError(t *testing.T, input string, code errors.ErrCode) { _, errs := parse(input) if errs == nil { t.Errorf("expected error and it didn't happen (input: %s)", input) } el, ok := errs.(errors.ErrorList) if !ok { t.Errorf("error list expected (input: %s)", input) } else if len(el.Errors) == 0 { t.Errorf("error list is empty (input: %s)", input) } else { if first, ok := el.Errors[0].(errors.Error); !ok { t.Errorf("error in error list not an Error (input: %s)", input) } else { if first.Code != code { t.Errorf("error %d expected, got %d -> %s (input: %s)", code, first.Code, first, input) } } } } func TestErrorFailedNumeric(t *testing.T) { expectError(t, "var n number = 18446744073709551616;", errors.FailedNumeric) } func TestErrorExpectedRParen(t *testing.T) { expectError(t, "var n number = (1 + 2 ;", errors.ExpectedRParen) } func TestErrorExpectedExpr(t *testing.T) { expectError(t, ";", errors.ExpectedExpr) } func TestErrorExpectedVarName(t *testing.T) { expectError(t, "var number = 1;", errors.ExpectedIdent) expectError(t, "const false;", errors.ExpectedIdent) } func TestErrorExpectedType(t *testing.T) { expectError(t, "var n = 1;", errors.ExpectedType) expectError(t, "const n = 1;", errors.ExpectedType) expectError(t, "def fn(n) { }", errors.ExpectedType) expectError(t, "def fn() { }\nvar a number = fn();", errors.TypeMismatch) } func TestErrorDeclareUndefined(t *testing.T) { expectError(t, "var a number = a;", errors.UndefinedIdent) } func TestErrorExpectedSemiColon(t *testing.T) { expectError(t, "var n number = 1", errors.ExpectedSemicolon) expectError(t, "1 + 1", errors.ExpectedSemicolon) } func TestErrorExpectedFunc(t *testing.T) { expectError(t, "def ;", errors.ExpectedIdent) expectError(t, "def fn;", errors.ExpectedLParen) expectError(t, "def fn(number);", errors.ExpectedIdent) expectError(t, "def fn(a number, number);", errors.ExpectedIdent) expectError(t, "def fn(a, b);", errors.ExpectedType) expectError(t, "def fn(a bool, b);", errors.ExpectedType) expectError(t, "def fn() id;", errors.ExpectedType) expectError(t, "def fn(a number) id;", errors.ExpectedType) expectError(t, "def fn()", errors.ExpectedType) expectError(t, "def fn() {", errors.ExpectedRBrace) expectError(t, "def fn() number {", errors.ExpectedRBrace) expectError(t, "fn(;", errors.UndefinedIdent) expectError(t, "fn(0;", errors.UndefinedIdent) expectError(t, "fn()", errors.UndefinedIdent) expectError(t, "def fn() bool { return 1; }", errors.TypeMismatch) expectError(t, "def fn() { }\ndef fn() { }", errors.AlreadyDeclared) } func TestErrorReturn(t *testing.T) { expectError(t, "return", errors.InvalidOperation) expectError(t, "return true", errors.InvalidOperation) expectError(t, "def fn() { return }", errors.ExpectedExpr) expectError(t, "def fn() { return true }", errors.ExpectedSemicolon) expectError(t, ` def fn() [5]number { var local [5]number; return local; } `, errors.InvalidOperation) expectError(t, ` def A { var p number; } def fn() A { var local A; return local; } `, errors.InvalidOperation) expectError(t, ` def A { var p number; } var g A; def fn() A { var local A; local = g; return local; } "OK"; `, errors.TypeMismatch) expectError(t, ` var g [3]bool; def fn() [3]bool { var local [3]bool; local = g; return local; } "OK"; `, errors.TypeMismatch) expectError(t, ` const a [3]number = [1, 2, 3]; var b [3]number = a; `, errors.TypeMismatch) expectError(t, ` const a [3]number = [1, 2, 3]; var b [3]number; var c [3]number = b; c = a; `, errors.TypeMismatch) } func TestErrorExpectedAssign(t *testing.T) { expectError(t, "a = ", errors.UndefinedIdent) expectError(t, "1 = 1;", errors.InvalidTarget) expectError(t, "const a number = 0; a = 1;", errors.AssignConst) expectError(t, "const a [2]number = [0, 1]; a[0] = 1;", errors.AssignConst) expectError(t, ` def fn() { } const a func () = fn; a = fn; `, errors.AssignConst) } func TestErrorLoops(t *testing.T) { expectError(t, "continue;", errors.InvalidOperation) expectError(t, "break;", errors.InvalidOperation) } func TestErrorArray(t *testing.T) { expectError(t, "var a [false]number;", errors.InvalidValue) expectError(t, "var a [1]number = 1;", errors.TypeMismatch) expectError(t, "var a []number = [1, 2, 3];", errors.ExpectedExpr) expectError(t, "var a [2]number; var b [5]number = a;", errors.TypeMismatch) } func TestErrorExprList(t *testing.T) { expectError(t, "var a number = [1];", errors.InvalidValue) expectError(t, "var a [1]number = [];", errors.InvalidValue) expectError(t, "var a [2]number = [1, false];", errors.TypeMismatch) expectError(t, "var a [2]number = [1, 2, 3];", errors.InvalidValue) expectError(t, "var a [1]number = [false];", errors.TypeMismatch) expectError(t, "const a number = [1];", errors.InvalidValue) expectError(t, "const a [1]number = [];", errors.InvalidValue) expectError(t, "const a [2]number = [1, false];", errors.TypeMismatch) expectError(t, "const a [2]number = [1, 2, 3];", errors.InvalidValue) expectError(t, "const a [1]number = [false];", errors.TypeMismatch) } func TestErrorIndex(t *testing.T) { expectError(t, "var a [10]number; a[false];", errors.InvalidValue) expectError(t, "var a [10]number; a[\"bad\"];", errors.InvalidValue) expectError(t, "var i bool; var a [10]number; a[i];", errors.InvalidValue) expectError(t, "def fn() { } var a [10]number; a[fn];", errors.InvalidValue) expectError(t, "def fn() bool { return false; } var a [10]number; a[fn()];", errors.InvalidValue) expectError(t, "false[0];", errors.NotIndexable) expectError(t, "10[0];", errors.NotIndexable) expectError(t, "false[0] = 10;", errors.NotIndexable) } func TestErrorFor(t *testing.T) { expectError(t, "for a { }", errors.UndefinedIdent) expectError(t, "for a != 0 { }", errors.UndefinedIdent) expectError(t, "for a in { }", errors.ExpectedExpr) expectError(t, "for a in a { }", errors.UndefinedIdent) expectError(t, "var a number; for i in a { }", errors.TypeMismatch) } func TestErrorStruct(t *testing.T) { expectError(t, "def A { }", errors.InvalidValue) expectError(t, "var a number; a.b;", errors.NotStruct) expectError(t, "def A { var a number; }\nvar a A; a.1;", errors.ExpectedIdent) expectError(t, "def A { var a number; }\ndef A { }", errors.AlreadyDeclared) expectError(t, "def A { var a A; }", errors.RecursiveStruct) expectError(t, "def A { var a number; }\nvar a A;\na.x;", errors.UndefinedIdent) expectError(t, "def A { var a number; }\nA.a;", errors.InvalidValue) expectError(t, "def A { var a number; }\nvar a number; a = A;", errors.InvalidValue) expectError(t, "def A { var a number; }\nvar a A; var b number = a;", errors.TypeMismatch) expectError(t, "def A { var a number; }\nvar a A; var b a;", errors.ExpectedType) expectError(t, ` def A { var a number; } def B { var a number; } var a A; var b B = a; `, errors.TypeMismatch) expectError(t, ` def fn() { def A { return; } } `, errors.ExpectedDefinition) expectError(t, ` for { def A { break; } } `, errors.ExpectedDefinition) expectError(t, ` for { def A { continue; } } `, errors.ExpectedDefinition) expectError(t, ` def A { var p number; p = 10; } `, errors.ExpectedDefinition) expectError(t, ` def A { var p number; println("error"); } `, errors.ExpectedDefinition) }