Compare commits
	
		
			No commits in common. "539a4b44e934ffd09460d8f80cdfec5bd7940c20" and "c977e82d9ec2424680b14749737a0dfde4720f62" have entirely different histories.
		
	
	
		
			539a4b44e9
			...
			c977e82d9e
		
	
		
| @ -20,7 +20,7 @@ func importFunc(ctx ExprContext, name string, args []any) (result any, err error | |||||||
| 	return importGeneral(ctx, name, args) | 	return importGeneral(ctx, name, args) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func importAllFunc(ctx ExprContext, name string, args []any) (result any, err error) { | func includeFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||||
| 	enable(ctx, control_export_all) | 	enable(ctx, control_export_all) | ||||||
| 	return importGeneral(ctx, name, args) | 	return importGeneral(ctx, name, args) | ||||||
| } | } | ||||||
| @ -138,7 +138,7 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu | |||||||
| 
 | 
 | ||||||
| func ImportImportFuncs(ctx ExprContext) { | func ImportImportFuncs(ctx ExprContext) { | ||||||
| 	ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1) | 	ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1) | ||||||
| 	ctx.RegisterFunc("importAll", &simpleFunctor{f: importAllFunc}, 1, -1) | 	ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
|  | |||||||
| @ -6,10 +6,17 @@ package expr | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestFuncs(t *testing.T) { | func TestFuncs(t *testing.T) { | ||||||
|  | 	type inputType struct { | ||||||
|  | 		source     string | ||||||
|  | 		wantResult any | ||||||
|  | 		wantErr    error | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	inputs := []inputType{ | 	inputs := []inputType{ | ||||||
| 		/*   1 */ {`isNil(nil)`, true, nil}, | 		/*   1 */ {`isNil(nil)`, true, nil}, | ||||||
| 		/*   2 */ {`v=nil; isNil(v)`, true, nil}, | 		/*   2 */ {`v=nil; isNil(v)`, true, nil}, | ||||||
| @ -22,24 +29,53 @@ func TestFuncs(t *testing.T) { | |||||||
| 		/*   9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)}, | 		/*   9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)}, | ||||||
| 		/*  10 */ {`int("432", 4)`, nil, errors.New(`int() requires exactly one param`)}, | 		/*  10 */ {`int("432", 4)`, nil, errors.New(`int() requires exactly one param`)}, | ||||||
| 		/*  11 */ {`int(nil)`, nil, errors.New(`int() can't convert <nil> to int`)}, | 		/*  11 */ {`int(nil)`, nil, errors.New(`int() can't convert <nil> to int`)}, | ||||||
| 		/*  12 */ {`two=func(){2}; two()`, int64(2), nil}, |  | ||||||
| 		/*  13 */ {`double=func(x) {2*x}; (double(3))`, int64(6), nil}, |  | ||||||
| 		/*  14 */ {`double=func(x){2*x}; double(3)`, int64(6), nil}, |  | ||||||
| 		/*  15 */ {`double=func(x){2*x}; a=5; double(3+a) + 1`, int64(17), nil}, |  | ||||||
| 		/*  16 */ {`double=func(x){2*x}; a=5; two=func() {2}; (double(3+a) + 1) * two()`, int64(34), nil}, |  | ||||||
| 		/*  17 */ {`builtin "import"; import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil}, |  | ||||||
| 		/*  18 */ {`builtin "import"; import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil}, |  | ||||||
| 		/*  19 */ {`@x="hello"; @x`, nil, errors.New(`[1:3] variable references are not allowed in top level expressions: "@x"`)}, |  | ||||||
| 		/*  20 */ {`f=func(){@x="hello"}; f(); x`, "hello", nil}, |  | ||||||
| 		/*  21 */ {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil}, |  | ||||||
| 		/*  22 */ {`f=func(@y){g=func(){@x=5}; @y=@y+g()}; f(2); y+x`, nil, errors.New(`undefined variable or function "x"`)}, |  | ||||||
| 		/*  23 */ {`f=func(@y){g=func(){@x=5}; @z=g(); @y=@y+@z}; f(2); y+z`, int64(12), nil}, |  | ||||||
| 		/*  24 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @y=@y+@z}; f(2); y+z`, int64(12), nil}, |  | ||||||
| 		/*  25 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @x=@y+@z}; f(2); y+x`, int64(9), nil}, |  | ||||||
| 		/*  26 */ {`builtin "import"; importAll("./test-funcs.expr"); six()`, int64(6), nil}, |  | ||||||
| 		/*  27 */ {`builtin "import"; import("./sample-export-all.expr"); six()`, int64(6), nil}, |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// parserTest(t, "Func", inputs[25:26])
 | 	succeeded := 0 | ||||||
| 	parserTest(t, "Func", inputs) | 	failed := 0 | ||||||
|  | 
 | ||||||
|  | 	// inputs1 := []inputType{
 | ||||||
|  | 	// 	/*   1 */ {`0?{}`, nil, nil},
 | ||||||
|  | 	// }
 | ||||||
|  | 
 | ||||||
|  | 	for i, input := range inputs { | ||||||
|  | 		var expr Expr | ||||||
|  | 		var gotResult any | ||||||
|  | 		var gotErr error | ||||||
|  | 
 | ||||||
|  | 		ctx := NewSimpleFuncStore() | ||||||
|  | 		// ImportMathFuncs(ctx)
 | ||||||
|  | 		// ImportImportFunc(ctx)
 | ||||||
|  | 		// ImportOsFuncs(ctx)
 | ||||||
|  | 		parser := NewParser(ctx) | ||||||
|  | 
 | ||||||
|  | 		logTest(t, i+1, "Funcs", input.source, input.wantResult, input.wantErr) | ||||||
|  | 
 | ||||||
|  | 		r := strings.NewReader(input.source) | ||||||
|  | 		scanner := NewScanner(r, DefaultTranslations()) | ||||||
|  | 
 | ||||||
|  | 		good := true | ||||||
|  | 		if expr, gotErr = parser.Parse(scanner); gotErr == nil { | ||||||
|  | 			gotResult, gotErr = expr.Eval(ctx) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if gotResult != input.wantResult { | ||||||
|  | 			t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) | ||||||
|  | 			good = false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if gotErr != input.wantErr { | ||||||
|  | 			if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) { | ||||||
|  | 				t.Errorf("%d: %q -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr) | ||||||
|  | 				good = false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if good { | ||||||
|  | 			succeeded++ | ||||||
|  | 		} else { | ||||||
|  | 			failed++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	t.Logf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,26 +0,0 @@ | |||||||
| // Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 |  | ||||||
| // All rights reserved.
 |  | ||||||
| 
 |  | ||||||
| // iterator_test.go
 |  | ||||||
| package expr |  | ||||||
| 
 |  | ||||||
| import "testing" |  | ||||||
| 
 |  | ||||||
| func TestIteratorParser(t *testing.T) { |  | ||||||
| 	inputs := []inputType{ |  | ||||||
| 		/*   1 */ {`include "iterator.expr"; it=$(ds,3); ()it`, int64(0), nil}, |  | ||||||
| 		/*   2 */ {`include "iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil}, |  | ||||||
| 		/*   3 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(2), nil}, |  | ||||||
| 		/*   4 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil}, |  | ||||||
| 		/*   5 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil}, |  | ||||||
| 		/*   6 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil}, |  | ||||||
| 		/*   7 */ {`builtin "math.arith"; include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil}, |  | ||||||
| 		/*   8 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it++; it.index`, int64(0), nil}, |  | ||||||
| 		/*  10 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it.clean`, true, nil}, |  | ||||||
| 		/*  11 */ {`it=$(1,2,3); it++`, int64(1), nil}, |  | ||||||
| 	} |  | ||||||
| 	// inputs1 := []inputType{
 |  | ||||||
| 	// 	/*   1 */ {`0?{}`, nil, nil},
 |  | ||||||
| 	// }
 |  | ||||||
| 	parserTest(t, "Iterator", inputs) |  | ||||||
| } |  | ||||||
							
								
								
									
										112
									
								
								list_test.go
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								list_test.go
									
									
									
									
									
								
							| @ -1,112 +0,0 @@ | |||||||
| // Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 |  | ||||||
| // All rights reserved.
 |  | ||||||
| 
 |  | ||||||
| // list_test.go
 |  | ||||||
| package expr |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestListParser(t *testing.T) { |  | ||||||
| 	section := "List" |  | ||||||
| 
 |  | ||||||
| 	type inputType struct { |  | ||||||
| 		source     string |  | ||||||
| 		wantResult any |  | ||||||
| 		wantErr    error |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	inputs := []inputType{ |  | ||||||
| 		/*  1 */ {`[]`, []any{}, nil}, |  | ||||||
| 		/*  2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil}, |  | ||||||
| 		/*  3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil}, |  | ||||||
| 		/*  4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil}, |  | ||||||
| 		/*  5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil}, |  | ||||||
| 		/*  6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil}, |  | ||||||
| 		/*  7 */ {`add([1,4,3,2])`, int64(10), nil}, |  | ||||||
| 		/*  8 */ {`add([1,[2,2],3,2])`, int64(10), nil}, |  | ||||||
| 		/*  9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil}, |  | ||||||
| 		/* 10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)}, |  | ||||||
| 		/* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil}, |  | ||||||
| 		/* 12 */ {`[1,2,3] << 2+2`, []any{int64(1), int64(2), int64(3), int64(4)}, nil}, |  | ||||||
| 		/* 13 */ {`2-1 >> [2,3]`, []any{int64(1), int64(2), int64(3)}, nil}, |  | ||||||
| 
 |  | ||||||
| 		// /*  8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
 |  | ||||||
| 		// /*  9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	succeeded := 0 |  | ||||||
| 	failed := 0 |  | ||||||
| 
 |  | ||||||
| 	// inputs1 := []inputType{
 |  | ||||||
| 	// 	/*  7 */ {`add([1,4,3,2])`, int64(10), nil},
 |  | ||||||
| 	// }
 |  | ||||||
| 
 |  | ||||||
| 	for i, input := range inputs { |  | ||||||
| 		var expr *ast |  | ||||||
| 		var gotResult any |  | ||||||
| 		var gotErr error |  | ||||||
| 
 |  | ||||||
| 		ctx := NewSimpleFuncStore() |  | ||||||
| 		ctx.SetVar("var1", int64(123)) |  | ||||||
| 		ctx.SetVar("var2", "abc") |  | ||||||
| 		ImportMathFuncs(ctx) |  | ||||||
| 		parser := NewParser(ctx) |  | ||||||
| 
 |  | ||||||
| 		logTest(t, i+1, "List", input.source, input.wantResult, input.wantErr) |  | ||||||
| 
 |  | ||||||
| 		r := strings.NewReader(input.source) |  | ||||||
| 		scanner := NewScanner(r, DefaultTranslations()) |  | ||||||
| 
 |  | ||||||
| 		good := true |  | ||||||
| 		if expr, gotErr = parser.Parse(scanner); gotErr == nil { |  | ||||||
| 			gotResult, gotErr = expr.Eval(ctx) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (gotResult == nil && input.wantResult != nil) || (gotResult != nil && input.wantResult == nil) { |  | ||||||
| 			t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) |  | ||||||
| 			good = false |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if gotList, okGot := gotResult.([]any); okGot { |  | ||||||
| 			if wantList, okWant := input.wantResult.([]any); okWant { |  | ||||||
| 				if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) { |  | ||||||
| 					t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) |  | ||||||
| 					good = false |  | ||||||
| 				} else { |  | ||||||
| 					equal := len(gotList) == len(wantList) |  | ||||||
| 					if equal { |  | ||||||
| 						for i, gotItem := range gotList { |  | ||||||
| 							wantItem := wantList[i] |  | ||||||
| 							equal = gotItem == wantItem |  | ||||||
| 							if !equal { |  | ||||||
| 								break |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					if !equal { |  | ||||||
| 						t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) |  | ||||||
| 						good = false |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if gotErr != input.wantErr { |  | ||||||
| 			if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) { |  | ||||||
| 				t.Errorf("%d: %q  -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr) |  | ||||||
| 				good = false |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if good { |  | ||||||
| 			succeeded++ |  | ||||||
| 		} else { |  | ||||||
| 			failed++ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed) |  | ||||||
| } |  | ||||||
| @ -34,9 +34,8 @@ func evalInsert(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if isList(rightValue) { | 	if isList(rightValue) { | ||||||
| 		list, _ := rightValue.(*ListType) | 		list, _ := rightValue.([]any) | ||||||
| 		newList := append(ListType{leftValue}, *list...) | 		v = append([]any{leftValue}, list...) | ||||||
| 		v = &newList |  | ||||||
| 	} else { | 	} else { | ||||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||||
| 	} | 	} | ||||||
| @ -51,9 +50,8 @@ func evalAppend(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if isList(leftValue) { | 	if isList(leftValue) { | ||||||
| 		list, _ := leftValue.(*ListType) | 		list, _ := leftValue.([]any) | ||||||
| 		newList := append(*list, rightValue) | 		v = append(list, rightValue) | ||||||
| 		v = &newList |  | ||||||
| 	} else { | 	} else { | ||||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										313
									
								
								parser_test.go
									
									
									
									
									
								
							
							
						
						
									
										313
									
								
								parser_test.go
									
									
									
									
									
								
							| @ -11,7 +11,13 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestGeneralParser(t *testing.T) { | func TestParser(t *testing.T) { | ||||||
|  | 	type inputType struct { | ||||||
|  | 		source     string | ||||||
|  | 		wantResult any | ||||||
|  | 		wantErr    error | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	inputs := []inputType{ | 	inputs := []inputType{ | ||||||
| 		/*   1 */ {`1+/*5*/2`, int64(3), nil}, | 		/*   1 */ {`1+/*5*/2`, int64(3), nil}, | ||||||
| 		/*   2 */ {`3 == 4`, false, nil}, | 		/*   2 */ {`3 == 4`, false, nil}, | ||||||
| @ -45,111 +51,137 @@ func TestGeneralParser(t *testing.T) { | |||||||
| 		/*  30 */ {"-(-2+1)", int64(1), nil}, | 		/*  30 */ {"-(-2+1)", int64(1), nil}, | ||||||
| 		/*  31 */ {"(1+1)*5", int64(10), nil}, | 		/*  31 */ {"(1+1)*5", int64(10), nil}, | ||||||
| 		/*  32 */ {"200 / (1+1) - 1", int64(99), nil}, | 		/*  32 */ {"200 / (1+1) - 1", int64(99), nil}, | ||||||
| 		/*  33 */ {`1+(1+(1+(1)+1)+1)+1`, int64(7), nil}, | 		/*  33 */ {`add(1,2,3)`, int64(6), nil}, | ||||||
| 		/*  34 */ {`(((1)))`, int64(1), nil}, | 		/*  34 */ {`mulX(1,2,3)`, nil, errors.New(`unknown function mulX()`)}, | ||||||
| 		/*  35 */ {`var2="abc"; "uno_" + var2`, `uno_abc`, nil}, | 		/*  35 */ {`add(1+4,3+2,5*(3-2))`, int64(15), nil}, | ||||||
| 		/*  36 */ {`0 || 0.0 && "hello"`, false, nil}, | 		/*  36 */ {`add(add(1+4),3+2,5*(3-2))`, int64(15), nil}, | ||||||
| 		/*  37 */ {`"s" + true`, nil, errors.New(`[1:6] left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)}, | 		/*  37 */ {`add(add(1,4),/*3+2,*/5*(3-2))`, int64(10), nil}, | ||||||
| 		/*  38 */ {`+false`, nil, errors.New(`[1:2] prefix/postfix operator "+" do not support operand 'false' [bool]`)}, | 		/*  38 */ {`1+(1+(1+(1)+1)+1)+1`, int64(7), nil}, | ||||||
| 		/*  39 */ {`false // very simple expression`, false, nil}, | 		/*  39 */ {`(((1)))`, int64(1), nil}, | ||||||
| 		/*  40 */ {`1 + // Missing right operator`, nil, errors.New(`[1:4] infix operator "+" requires two non-nil operands, got 1`)}, | 		/*  40 */ {`"uno_" + var2`, `uno_abc`, nil}, | ||||||
| 		/*  41 */ {"", nil, nil}, | 		/*  41 */ {`0 || 0.0 && "hello"`, false, nil}, | ||||||
| 		/*  42 */ {"4!", int64(24), nil}, | 		/*  42 */ {`"s" + true`, nil, errors.New(`[1:6] left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)}, | ||||||
| 		/*  43 */ {"(-4)!", nil, errors.New(`factorial of a negative integer (-4) is not allowed`)}, | 		/*  43 */ {`+false`, nil, errors.New(`[1:2] prefix/postfix operator "+" do not support operand 'false' [bool]`)}, | ||||||
| 		/*  44 */ {"-4!", int64(-24), nil}, | 		/*  44 */ {`false // very simple expression`, false, nil}, | ||||||
| 		/*  45 */ {"1.5 < 7", true, nil}, | 		/*  45 */ {`1 + // Missing right operator`, nil, errors.New(`[1:4] infix operator "+" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  46 */ {"1.5 > 7", false, nil}, | 		/*  46 */ {"", nil, nil}, | ||||||
| 		/*  47 */ {"1.5 <= 7", true, nil}, | 		/*  47 */ {"4!", int64(24), nil}, | ||||||
| 		/*  48 */ {"1.5 >= 7", false, nil}, | 		/*  48 */ {"(-4)!", nil, errors.New(`factorial of a negative integer (-4) is not allowed`)}, | ||||||
| 		/*  49 */ {"1.5 != 7", true, nil}, | 		/*  49 */ {"-4!", int64(-24), nil}, | ||||||
| 		/*  50 */ {"1.5 == 7", false, nil}, | 		/*  50 */ {"1.5 < 7", true, nil}, | ||||||
| 		/*  51 */ {`"1.5" < "7"`, true, nil}, | 		/*  51 */ {"1.5 > 7", false, nil}, | ||||||
| 		/*  52 */ {`"1.5" > "7"`, false, nil}, | 		/*  52 */ {"1.5 <= 7", true, nil}, | ||||||
| 		/*  53 */ {`"1.5" == "7"`, false, nil}, | 		/*  53 */ {"1.5 >= 7", false, nil}, | ||||||
| 		/*  54 */ {`"1.5" != "7"`, true, nil}, | 		/*  54 */ {"1.5 != 7", true, nil}, | ||||||
| 		/*  55 */ {"1.5 < ", nil, errors.New(`[1:6] infix operator "<" requires two non-nil operands, got 1`)}, | 		/*  55 */ {"1.5 == 7", false, nil}, | ||||||
| 		/*  56 */ {"1.5 > ", nil, errors.New(`[1:6] infix operator ">" requires two non-nil operands, got 1`)}, | 		/*  56 */ {`"1.5" < "7"`, true, nil}, | ||||||
| 		/*  57 */ {"1.5 <= ", nil, errors.New(`[1:6] infix operator "<=" requires two non-nil operands, got 1`)}, | 		/*  57 */ {`"1.5" > "7"`, false, nil}, | ||||||
| 		/*  58 */ {"1.5 >= ", nil, errors.New(`[1:6] infix operator ">=" requires two non-nil operands, got 1`)}, | 		/*  58 */ {`"1.5" == "7"`, false, nil}, | ||||||
| 		/*  59 */ {"1.5 != ", nil, errors.New(`[1:6] infix operator "!=" requires two non-nil operands, got 1`)}, | 		/*  59 */ {`"1.5" != "7"`, true, nil}, | ||||||
| 		/*  60 */ {"1.5 == ", nil, errors.New(`[1:6] infix operator "==" requires two non-nil operands, got 1`)}, | 		/*  60 */ {"1.5 < ", nil, errors.New(`[1:6] infix operator "<" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  61 */ {`"1.5" < `, nil, errors.New(`[1:8] infix operator "<" requires two non-nil operands, got 1`)}, | 		/*  61 */ {"1.5 > ", nil, errors.New(`[1:6] infix operator ">" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  62 */ {`"1.5" > `, nil, errors.New(`[1:8] infix operator ">" requires two non-nil operands, got 1`)}, | 		/*  62 */ {"1.5 <= ", nil, errors.New(`[1:6] infix operator "<=" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  63 */ {`"1.5" == `, nil, errors.New(`[1:8] infix operator "==" requires two non-nil operands, got 1`)}, | 		/*  63 */ {"1.5 >= ", nil, errors.New(`[1:6] infix operator ">=" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  64 */ {`"1.5" != `, nil, errors.New(`[1:8] infix operator "!=" requires two non-nil operands, got 1`)}, | 		/*  64 */ {"1.5 != ", nil, errors.New(`[1:6] infix operator "!=" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  65 */ {"+1.5", float64(1.5), nil}, | 		/*  65 */ {"1.5 == ", nil, errors.New(`[1:6] infix operator "==" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  66 */ {"+", nil, errors.New(`[1:2] prefix operator "+" requires one not nil operand`)}, | 		/*  66 */ {`"1.5" < `, nil, errors.New(`[1:8] infix operator "<" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  67 */ {"4 / 0", nil, errors.New(`division by zero`)}, | 		/*  67 */ {`"1.5" > `, nil, errors.New(`[1:8] infix operator ">" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  68 */ {"4.0 / 0", nil, errors.New(`division by zero`)}, | 		/*  68 */ {`"1.5" == `, nil, errors.New(`[1:8] infix operator "==" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  69 */ {"4.0 / \n2", float64(2.0), nil}, | 		/*  69 */ {`"1.5" != `, nil, errors.New(`[1:8] infix operator "!=" requires two non-nil operands, got 1`)}, | ||||||
| 		/*  70 */ {`123`, int64(123), nil}, | 		/*  70 */ {"+1.5", float64(1.5), nil}, | ||||||
| 		/*  71 */ {`1.`, float64(1.0), nil}, | 		/*  71 */ {"+", nil, errors.New(`[1:2] prefix operator "+" requires one not nil operand`)}, | ||||||
| 		/*  72 */ {`1.E-2`, float64(0.01), nil}, | 		/*  72 */ {"4 / 0", nil, errors.New(`division by zero`)}, | ||||||
| 		/*  73 */ {`1E2`, float64(100), nil}, | 		/*  73 */ {"4.0 / 0", nil, errors.New(`division by zero`)}, | ||||||
| 		/*  74 */ {`1 / 2`, int64(0), nil}, | 		/*  74 */ {"4.0 / \n2", float64(2.0), nil}, | ||||||
| 		/*  75 */ {`1.0 / 2`, float64(0.5), nil}, | 		/*  75 */ {`123`, int64(123), nil}, | ||||||
| 		/*  76 */ {`1 ./ 2`, float64(0.5), nil}, | 		/*  76 */ {`1.`, float64(1.0), nil}, | ||||||
| 		/*  77 */ {`5 % 2`, int64(1), nil}, | 		/*  77 */ {`1.E-2`, float64(0.01), nil}, | ||||||
| 		/*  78 */ {`5 % (-2)`, int64(1), nil}, | 		/*  78 */ {`1E2`, float64(100), nil}, | ||||||
| 		/*  79 */ {`-5 % 2`, int64(-1), nil}, | 		/*  79 */ {`1 / 2`, int64(0), nil}, | ||||||
| 		/*  80 */ {`5 % 2.0`, nil, errors.New(`[1:4] left operand '5' [int64] and right operand '2' [float64] are not compatible with operator "%"`)}, | 		/*  80 */ {`1.0 / 2`, float64(0.5), nil}, | ||||||
| 		/*  81 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil}, | 		/*  81 */ {`1 ./ 2`, float64(0.5), nil}, | ||||||
| 		/*  82 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil}, | 		/*  82 */ {`5 % 2`, int64(1), nil}, | ||||||
| 		/*  83 */ {`"a" < "b" AND ~ 2 == 1`, true, nil}, | 		/*  83 */ {`5 % (-2)`, int64(1), nil}, | ||||||
| 		/*  84 */ {`~ 2 > 1`, false, nil}, | 		/*  84 */ {`-5 % 2`, int64(-1), nil}, | ||||||
| 		/*  85 */ {`~ true && true`, false, nil}, | 		/*  85 */ {`5 % 2.0`, nil, errors.New(`[1:4] left operand '5' [int64] and right operand '2' [float64] are not compatible with operator "%"`)}, | ||||||
| 		/*  86 */ {`~ false || true`, true, nil}, | 		/*  86 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil}, | ||||||
| 		/*  87 */ {`false but true`, true, nil}, | 		/*  87 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil}, | ||||||
| 		/*  88 */ {`2+3 but 5*2`, int64(10), nil}, | 		/*  88 */ {`"a" < "b" AND ~ 2 == 1`, true, nil}, | ||||||
| 		/*  89 */ {`x=2`, int64(2), nil}, | 		/*  89 */ {`~ 2 > 1`, false, nil}, | ||||||
| 		/*  90 */ {`x=2 but x*10`, int64(20), nil}, | 		/*  90 */ {`~ true && true`, false, nil}, | ||||||
| 		/*  91 */ {`false and true`, false, nil}, | 		/*  91 */ {`~ false || true`, true, nil}, | ||||||
| 		/*  92 */ {`false and (x==2)`, false, nil}, | 		/*  92 */ {`false but true`, true, nil}, | ||||||
| 		/*  93 */ {`false and (x=2 but x==2) or x==2`, nil, errors.New(`undefined variable or function "x"`)}, | 		/*  93 */ {`2+3 but 5*2`, int64(10), nil}, | ||||||
| 		/*  94 */ {`false or true`, true, nil}, | 		/*  94 */ {`add(1,2) but var2`, "abc", nil}, | ||||||
| 		/*  95 */ {`false or (x==2)`, nil, errors.New(`undefined variable or function "x"`)}, | 		/*  95 */ {`x=2`, int64(2), nil}, | ||||||
| 		/*  96 */ {`a=5; a`, int64(5), nil}, | 		/*  96 */ {`x=2 but x*10`, int64(20), nil}, | ||||||
| 		/*  97 */ {`2=5`, nil, errors.New(`assign operator ("=") must be preceded by a variable`)}, | 		/*  97 */ {`false and true`, false, nil}, | ||||||
| 		/*  98 */ {`2+a=5`, nil, errors.New(`[1:3] left operand of "=" must be a variable`)}, | 		/*  98 */ {`false and (x==2)`, false, nil}, | ||||||
| 		/*  99 */ {`2+(a=5)`, int64(7), nil}, | 		/*  99 */ {`false and (x=2 but x==2) or x==2`, nil, errors.New(`undefined variable or function "x"`)}, | ||||||
| 		/* 100 */ {`x ?? "default"`, "default", nil}, | 		/* 100 */ {`false or true`, true, nil}, | ||||||
| 		/* 101 */ {`x="hello"; x ?? "default"`, "hello", nil}, | 		/* 101 */ {`false or (x==2)`, nil, errors.New(`undefined variable or function "x"`)}, | ||||||
| 		/* 102 */ {`y=x ?? func(){4}; y()`, int64(4), nil}, | 		/* 102 */ {`a=5; a`, int64(5), nil}, | ||||||
| 		/* 103 */ {`x ?= "default"; x`, "default", nil}, | 		/* 103 */ {`a=5; b=2; add(a, b*3)`, int64(11), nil}, | ||||||
| 		/* 104 */ {`x="hello"; x ?= "default"; x`, "hello", nil}, | 		/* 104 */ {`2=5`, nil, errors.New(`assign operator ("=") must be preceded by a variable`)}, | ||||||
| 		/* 105 */ {`1 ? {"a"} : {"b"}`, "b", nil}, | 		/* 105 */ {`2+a=5`, nil, errors.New(`[1:3] left operand of "=" must be a variable`)}, | ||||||
| 		/* 106 */ {`10 ? {"a"} : {"b"} :: {"c"}`, "c", nil}, | 		/* 106 */ {`2+(a=5)`, int64(7), nil}, | ||||||
| 		/* 107 */ {`10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}`, "b", nil}, | 		/* 107 */ {`two=func(){2}; two()`, int64(2), nil}, | ||||||
| 		/* 108 */ {`10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}`, nil, errors.New(`[1:34] case list in default clause`)}, | 		/* 108 */ {`double=func(x) {2*x}; (double(3))`, int64(6), nil}, | ||||||
| 		/* 109 */ {`10 ? {"a"} :[10] {x="b" but x} :: {"c"}`, "b", nil}, | 		/* 109 */ {`double=func(x){2*x}; double(3)`, int64(6), nil}, | ||||||
| 		/* 110 */ {`10 ? {"a"} :[10] {x="b"; x} :: {"c"}`, "b", nil}, | 		/* 110 */ {`double=func(x){2*x}; a=5; double(3+a) + 1`, int64(17), nil}, | ||||||
| 		/* 111 */ {`10 ? {"a"} : {"b"}`, nil, errors.New(`[1:3] no case catches the value (10) of the selection expression`)}, | 		/* 111 */ {`double=func(x){2*x}; a=5; two=func() {2}; (double(3+a) + 1) * two()`, int64(34), nil}, | ||||||
| 		/* 112 */ {`10 ? {"a"} :: {"b"} : {"c"}`, nil, errors.New(`[1:22] selector-case outside of a selector context`)}, | 		/* 112 */ {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil}, | ||||||
| 		/* 113 */ {`1 ? {"a"} : {"b"} ? ["a"] {"A"} :["b"] {"B"}`, "B", nil}, | 		//		/* 113 */ {`import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
 | ||||||
| 		/* 114 */ {`2 + 1 ? {"a"} : {"b"} * 3`, "2bbb", nil}, | 		/* 114 */ {`x ?? "default"`, "default", nil}, | ||||||
| 		/* 115 */ {`nil`, nil, nil}, | 		/* 115 */ {`x="hello"; x ?? "default"`, "hello", nil}, | ||||||
| 		/* 116 */ {`null`, nil, errors.New(`undefined variable or function "null"`)}, | 		/* 116 */ {`y=x ?? func(){4}; y()`, int64(4), nil}, | ||||||
| 		/* 117 */ {`{"key"}`, nil, errors.New(`[1:8] expected ":", got "}"`)}, | 		/* 117 */ {`x ?= "default"; x`, "default", nil}, | ||||||
| 		/* 118 */ {`{"key":}`, nil, errors.New(`[1:9] expected "dictionary-value", got "}"`)}, | 		/* 118 */ {`x="hello"; x ?= "default"; x`, "hello", nil}, | ||||||
| 		/* 119 */ {`{}`, map[any]any{}, nil}, | 		/* 119 */ {`@x="hello"; @x`, nil, errors.New(`[1:3] variable references are not allowed in top level expressions: "@x"`)}, | ||||||
| 		/* 120 */ {`1|2`, newFraction(1, 2), nil}, | 		/* 120 */ {`f=func(){@x="hello"}; f(); x`, "hello", nil}, | ||||||
| 		/* 121 */ {`1|2 + 1`, newFraction(3, 2), nil}, | 		/* 121 */ {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil}, | ||||||
| 		/* 122 */ {`1|2 - 1`, newFraction(-1, 2), nil}, | 		/* 122 */ {`f=func(@y){g=func(){@x=5}; @y=@y+g()}; f(2); y+x`, nil, errors.New(`undefined variable or function "x"`)}, | ||||||
| 		/* 123 */ {`1|2 * 1`, newFraction(1, 2), nil}, | 		/* 123 */ {`f=func(@y){g=func(){@x=5}; @z=g(); @y=@y+@z}; f(2); y+z`, int64(12), nil}, | ||||||
| 		/* 124 */ {`1|2 * 2|3`, newFraction(2, 6), nil}, | 		/* 124 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @y=@y+@z}; f(2); y+z`, int64(12), nil}, | ||||||
| 		/* 125 */ {`1|2 / 2|3`, newFraction(3, 4), nil}, | 		/* 125 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @x=@y+@z}; f(2); y+x`, int64(9), nil}, | ||||||
| 		/* 126 */ {`builtin "math.arith"; add(1,2,3)`, int64(6), nil}, | 		//		/* 126 */ {`include("./test-funcs.expr"); six()`, int64(6), nil},
 | ||||||
| 		/* 127 */ {`builtin "math.arith"; mulX(1,2,3)`, nil, errors.New(`unknown function mulX()`)}, | 		/* 127 */ {`import("./sample-export-all.expr"); six()`, int64(6), nil}, | ||||||
| 		/* 128 */ {`builtin "math.arith"; add(1+4,3+2,5*(3-2))`, int64(15), nil}, | 		/* 128 */ {`1 ? {"a"} : {"b"}`, "b", nil}, | ||||||
| 		/* 129 */ {`builtin "math.arith"; add(add(1+4),3+2,5*(3-2))`, int64(15), nil}, | 		/* 129 */ {`10 ? {"a"} : {"b"} :: {"c"}`, "c", nil}, | ||||||
| 		/* 130 */ {`builtin "math.arith"; add(add(1,4),/*3+2,*/5*(3-2))`, int64(10), nil}, | 		/* 130 */ {`10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}`, "b", nil}, | ||||||
| 		/* 131 */ {`builtin "math.arith"; a=5; b=2; add(a, b*3)`, int64(11), nil}, | 		/* 131 */ {`10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}`, nil, errors.New(`[1:34] case list in default clause`)}, | ||||||
| 		/* 132 */ {`builtin "math.arith"; var2="abc"; add(1,2) but var2`, "abc", nil}, | 		/* 132 */ {`10 ? {"a"} :[10] {x="b" but x} :: {"c"}`, "b", nil}, | ||||||
| 		/* 133 */ {`builtin "math.arith"; add(1|2, 2|3)`, newFraction(7, 6), nil}, | 		/* 133 */ {`10 ? {"a"} :[10] {x="b"; x} :: {"c"}`, "b", nil}, | ||||||
| 		/* 134 */ {`builtin "math.arith"; add(1|2, 1.0, 2)`, float64(3.5), nil}, | 		/* 134 */ {`10 ? {"a"} : {"b"}`, nil, errors.New(`[1:3] no case catches the value (10) of the selection expression`)}, | ||||||
| 		/* 135 */ {`builtin "math.arith"; mul(1|2, 2|3)`, newFraction(2, 6), nil}, | 		/* 135 */ {`10 ? {"a"} :: {"b"} : {"c"}`, nil, errors.New(`[1:22] selector-case outside of a selector context`)}, | ||||||
| 		/* 136 */ {`builtin "math.arith"; mul(1|2, 1.0, 2)`, float64(1.0), nil}, | 		/* 136 */ {`1 ? {"a"} : {"b"} ? ["a"] {"A"} :["b"] {"B"}`, "B", nil}, | ||||||
| 		/* 137 */ {`builtin "os.file"`, int64(1), nil}, | 		/* 137 */ {`2 + 1 ? {"a"} : {"b"} * 3`, "2bbb", nil}, | ||||||
|  | 		/* 138 */ {`nil`, nil, nil}, | ||||||
|  | 		/* 139 */ {`null`, nil, errors.New(`undefined variable or function "null"`)}, | ||||||
|  | 		/* 140 */ {`{"key"}`, nil, errors.New(`[1:8] expected ":", got "}"`)}, | ||||||
|  | 		/* 141 */ {`{"key":}`, nil, errors.New(`[1:9] expected "dictionary-value", got "}"`)}, | ||||||
|  | 		/* 142 */ {`{}`, map[any]any{}, nil}, | ||||||
|  | 		/* 143 */ {`1|2`, newFraction(1, 2), nil}, | ||||||
|  | 		/* 144 */ {`1|2 + 1`, newFraction(3, 2), nil}, | ||||||
|  | 		/* 145 */ {`1|2 - 1`, newFraction(-1, 2), nil}, | ||||||
|  | 		/* 146 */ {`1|2 * 1`, newFraction(1, 2), nil}, | ||||||
|  | 		/* 147 */ {`1|2 * 2|3`, newFraction(2, 6), nil}, | ||||||
|  | 		/* 148 */ {`1|2 / 2|3`, newFraction(3, 4), nil}, | ||||||
|  | 		/* 149 */ {`builtin "math.arith"; add(1|2, 2|3)`, newFraction(7, 6), nil}, | ||||||
|  | 		/* 150 */ {`builtin "math.arith"; add(1|2, 1.0, 2)`, float64(3.5), nil}, | ||||||
|  | 		/* 151 */ {`builtin "math.arith"; mul(1|2, 2|3)`, newFraction(2, 6), nil}, | ||||||
|  | 		/* 152 */ {`builtin "math.arith"; mul(1|2, 1.0, 2)`, float64(1.0), nil}, | ||||||
|  | 		/* 153 */ {`include "iterator.expr"; it=$(ds,3); ()it`, int64(0), nil}, | ||||||
|  | 		/* 154 */ {`include "iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil}, | ||||||
|  | 		/* 155 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(2), nil}, | ||||||
|  | 		/* 156 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil}, | ||||||
|  | 		/* 157 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil}, | ||||||
|  | 		/* 158 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil}, | ||||||
|  | 		/* 159 */ {`include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil}, | ||||||
|  | 		/* 160 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it++; it.index`, int64(0), nil}, | ||||||
|  | 		/* 161 */ {`include "file-reader.expr"; it=$(ds,"int.list"); it.clean`, true, nil}, | ||||||
|  | 		/* 162 */ {`builtin "os.file"`, int64(1), nil}, | ||||||
|  | 		/* 163 */ {`it=$(1,2,3); it++`, int64(1), nil}, | ||||||
| 	} | 	} | ||||||
| 	check_env_expr_path := 113 | 	check_env_expr_path := 113 | ||||||
| 
 | 
 | ||||||
| @ -166,10 +198,10 @@ func TestGeneralParser(t *testing.T) { | |||||||
| 		var gotErr error | 		var gotErr error | ||||||
| 
 | 
 | ||||||
| 		ctx := NewSimpleFuncStore() | 		ctx := NewSimpleFuncStore() | ||||||
| 		// ctx.SetVar("var1", int64(123))
 | 		ctx.SetVar("var1", int64(123)) | ||||||
| 		// ctx.SetVar("var2", "abc")
 | 		ctx.SetVar("var2", "abc") | ||||||
| 		// ImportMathFuncs(ctx)
 | 		ImportMathFuncs(ctx) | ||||||
| 		// ImportImportFuncs(ctx)
 | 		ImportImportFuncs(ctx) | ||||||
| 		parser := NewParser(ctx) | 		parser := NewParser(ctx) | ||||||
| 
 | 
 | ||||||
| 		logTest(t, i+1, "General", input.source, input.wantResult, input.wantErr) | 		logTest(t, i+1, "General", input.source, input.wantResult, input.wantErr) | ||||||
| @ -208,34 +240,49 @@ func TestGeneralParser(t *testing.T) { | |||||||
| 	t.Logf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed) | 	t.Logf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestListParser(t *testing.T) { | ||||||
| 	type inputType struct { | 	type inputType struct { | ||||||
| 		source     string | 		source     string | ||||||
| 		wantResult any | 		wantResult any | ||||||
| 		wantErr    error | 		wantErr    error | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| func parserTest(t *testing.T, section string, inputs []inputType) { | 	inputs := []inputType{ | ||||||
|  | 		/*  1 */ {`[]`, []any{}, nil}, | ||||||
|  | 		/*  2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil}, | ||||||
|  | 		/*  3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil}, | ||||||
|  | 		/*  4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil}, | ||||||
|  | 		/*  5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil}, | ||||||
|  | 		/*  6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil}, | ||||||
|  | 		/*  7 */ {`add([1,4,3,2])`, int64(10), nil}, | ||||||
|  | 		/*  8 */ {`add([1,[2,2],3,2])`, int64(10), nil}, | ||||||
|  | 		/*  9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil}, | ||||||
|  | 		/* 10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 (2 in 1) has wrong type string, number expected`)}, | ||||||
|  | 		/* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil}, | ||||||
|  | 
 | ||||||
|  | 		// /*  8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
 | ||||||
|  | 		// /*  9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
 | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	succeeded := 0 | 	succeeded := 0 | ||||||
| 	failed := 0 | 	failed := 0 | ||||||
| 
 | 
 | ||||||
| 	// inputs1 := []inputType{
 | 	// inputs1 := []inputType{
 | ||||||
| 	// 	/* 159 */ {`include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil},
 | 	// 	/*  7 */ {`add([1,4,3,2])`, int64(10), nil},
 | ||||||
| 	// }
 | 	// }
 | ||||||
| 
 | 
 | ||||||
| 	for i, input := range inputs { | 	for i, input := range inputs { | ||||||
| 		var expr Expr | 		var expr *ast | ||||||
| 		var gotResult any | 		var gotResult any | ||||||
| 		var gotErr error | 		var gotErr error | ||||||
| 
 | 
 | ||||||
| 		ctx := NewSimpleFuncStore() | 		ctx := NewSimpleFuncStore() | ||||||
| 		// ctx.SetVar("var1", int64(123))
 | 		ctx.SetVar("var1", int64(123)) | ||||||
| 		// ctx.SetVar("var2", "abc")
 | 		ctx.SetVar("var2", "abc") | ||||||
| 		// ImportMathFuncs(ctx)
 | 		ImportMathFuncs(ctx) | ||||||
| 		// ImportImportFuncs(ctx)
 |  | ||||||
| 		parser := NewParser(ctx) | 		parser := NewParser(ctx) | ||||||
| 
 | 
 | ||||||
| 		logTest(t, i+1, "Iterator", input.source, input.wantResult, input.wantErr) | 		logTest(t, i+1, "List", input.source, input.wantResult, input.wantErr) | ||||||
| 
 | 
 | ||||||
| 		r := strings.NewReader(input.source) | 		r := strings.NewReader(input.source) | ||||||
| 		scanner := NewScanner(r, DefaultTranslations()) | 		scanner := NewScanner(r, DefaultTranslations()) | ||||||
| @ -245,13 +292,35 @@ func parserTest(t *testing.T, section string, inputs []inputType) { | |||||||
| 			gotResult, gotErr = expr.Eval(ctx) | 			gotResult, gotErr = expr.Eval(ctx) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		eq := reflect.DeepEqual(gotResult, input.wantResult) | 		if (gotResult == nil && input.wantResult != nil) || (gotResult != nil && input.wantResult == nil) { | ||||||
| 
 |  | ||||||
| 		if !eq /*gotResult != input.wantResult*/ { |  | ||||||
| 			t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) | 			t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) | ||||||
| 			good = false | 			good = false | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if gotList, okGot := gotResult.([]any); okGot { | ||||||
|  | 			if wantList, okWant := input.wantResult.([]any); okWant { | ||||||
|  | 				if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) { | ||||||
|  | 					t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) | ||||||
|  | 					good = false | ||||||
|  | 				} else { | ||||||
|  | 					equal := len(gotList) == len(wantList) | ||||||
|  | 					if equal { | ||||||
|  | 						for i, gotItem := range gotList { | ||||||
|  | 							wantItem := wantList[i] | ||||||
|  | 							equal = gotItem == wantItem | ||||||
|  | 							if !equal { | ||||||
|  | 								break | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					if !equal { | ||||||
|  | 						t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) | ||||||
|  | 						good = false | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if gotErr != input.wantErr { | 		if gotErr != input.wantErr { | ||||||
| 			if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) { | 			if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) { | ||||||
| 				t.Errorf("%d: %q  -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr) | 				t.Errorf("%d: %q  -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr) | ||||||
| @ -265,7 +334,7 @@ func parserTest(t *testing.T, section string, inputs []inputType) { | |||||||
| 			failed++ | 			failed++ | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed) | 	t.Logf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func logTest(t *testing.T, n int, section, source string, wantResult any, wantErr error) { | func logTest(t *testing.T, n int, section, source string, wantResult any, wantErr error) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user