Compare commits
	
		
			No commits in common. "8346e283405370654d99a9c369e0f226db5904d3" and "dce49fd2b7f369c884e4689b8f6d70096fea8207" have entirely different histories.
		
	
	
		
			8346e28340
			...
			dce49fd2b7
		
	
		
							
								
								
									
										1
									
								
								ast.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								ast.go
									
									
									
									
									
								
							| @ -128,7 +128,6 @@ func (self *ast) eval(ctx ExprContext, preset bool) (result any, err error) { | ||||
| 		} | ||||
| 		if err == nil { | ||||
| 			result, err = self.root.compute(ctx) | ||||
| 			ctx.setVar(ControlLastResult, result) | ||||
| 		} | ||||
| 		// } else {
 | ||||
| 		// 	err = errors.New("empty expression")
 | ||||
|  | ||||
| @ -141,7 +141,7 @@ Numbers can be integers (GO int64) or float (GO float64). In mixed operations in | ||||
| |===  | ||||
| 
 | ||||
| === Fractions | ||||
| _Expr_ also supports fractions. Fraction literals are made with two integers separated by a vertical bar `|`. | ||||
| _Expr_ also suports fractions. Fraction literals are made with tow integers separated by a vertical bar `|`. | ||||
| 
 | ||||
| .Examples | ||||
| // [source,go] | ||||
| @ -149,7 +149,7 @@ _Expr_ also supports fractions. Fraction literals are made with two integers sep | ||||
| `>>>` [blue]`1 | 2` + | ||||
| [green]`1|2` + | ||||
| `>>>` [blue]`4|6` + | ||||
| [green]`2|3` [gray]_Fractions are always reduced to their lowest terms_ + | ||||
| [green]`2|3` [gray]_Fractions are always reduced to theri lowest terms_ + | ||||
| `>>>` [blue]`1|2 + 2|3` + | ||||
| [green]`7|6` + | ||||
| `>>>` [blue]`1|2 * 2|3` + | ||||
| @ -245,7 +245,7 @@ Currently, boolean operations are evaluated using _short cut evaluation_. This m | ||||
| <1> This multi-expression returns _1_ because in the first expression the left value of [blue]`or` is _true_ and as a conseguence its right value is not computed. Therefore the _a_ variable only receives the integer _1_. | ||||
| ==== | ||||
| 
 | ||||
| === Lists | ||||
| === List | ||||
| _Expr_ supports list of mixed-type values, also specified by normal expressions. | ||||
| 
 | ||||
| .List examples | ||||
| @ -258,6 +258,7 @@ _Expr_ supports list of mixed-type values, also specified by normal expressions. | ||||
| [ [1,"one"], [2,"two"]]     // List of lists | ||||
| ---- | ||||
| 
 | ||||
| 
 | ||||
| .List operators | ||||
| [cols="^2,^2,5,4"] | ||||
| |=== | ||||
| @ -268,34 +269,6 @@ _Expr_ supports list of mixed-type values, also specified by normal expressions. | ||||
| | [blue]`-` | _Difference_ | Left list without elements in the right list  | [blue]`[1,2,3] - [2]` _[ [1,3] ]_ | ||||
| |=== | ||||
| 
 | ||||
| The items of array can be accessed using the dot `.` operator. | ||||
| 
 | ||||
| .Item access syntax | ||||
| [source,bnf] | ||||
| ---- | ||||
| <item> ::= <list-expr>"."<index-expr> | ||||
| ---- | ||||
| 
 | ||||
| .Items of list | ||||
| [source,go] | ||||
| ---- | ||||
| `>>>` [blue]`[1,2,3].1` | ||||
| [green]`2` | ||||
| `>>>` [blue]`list=[1,2,3]; list.1` | ||||
| [green]`2` | ||||
| `>>>` [blue]`["one","two","three"].1` | ||||
| [green]`two` | ||||
| `>>>` [blue]`list=["one","two","three"]; list.(2-1)` | ||||
| [green]`two` | ||||
| `>>>` [blue]`list.(-1)` | ||||
| [green]`three` | ||||
| `>>>` [blue]`list.(-1)` | ||||
| [green]`three` | ||||
| `>>>` [blue]`list.(10)` | ||||
| ---- | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| == Dictionaries | ||||
| The _dictionary_ data-type is set of pairs _key/value_. It is also known as _map_ or _associative array_. Dictionary literals are sequences of pairs separated by comma `,`; sequences are enclosed between brace brackets. | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										49
									
								
								func-base.go
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								func-base.go
									
									
									
									
									
								
							| @ -18,42 +18,6 @@ func isNilFunc(ctx ExprContext, name string, args []any) (result any, err error) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isIntFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsInteger(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isFloatFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsFloat(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isBoolFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsBool(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isStringFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsString(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isFractionFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsFract(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isListFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsList(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func isDictionaryFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	result = IsDict(args[0]) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func intFunc(ctx ExprContext, name string, args []any) (result any, err error) { | ||||
| 	if len(args) == 1 { | ||||
| 		switch v := args[0].(type) { | ||||
| @ -86,17 +50,8 @@ func iteratorFunc(ctx ExprContext, name string, args []any) (result any, err err | ||||
| } | ||||
| 
 | ||||
| func ImportBuiltinsFuncs(ctx ExprContext) { | ||||
| 	ctx.RegisterFunc("isNil", &simpleFunctor{f: isNilFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isInt", &simpleFunctor{f: isIntFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isFloat", &simpleFunctor{f: isFloatFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isBool", &simpleFunctor{f: isBoolFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isFract", &simpleFunctor{f: isFractionFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isList", &simpleFunctor{f: isListFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isDict", &simpleFunctor{f: isDictionaryFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("int", &simpleFunctor{f: intFunc}, 1, 1) | ||||
| 	ctx.RegisterFunc("isNil", &simpleFunctor{f: isNilFunc}, 1, -1) | ||||
| 	ctx.RegisterFunc("int", &simpleFunctor{f: intFunc}, 1, -1) | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
|  | ||||
| @ -20,7 +20,7 @@ func TestFuncs(t *testing.T) { | ||||
| 		/*   7 */ {`int(3.9)`, int64(3), nil}, | ||||
| 		/*   8 */ {`int("432")`, int64(432), nil}, | ||||
| 		/*   9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)}, | ||||
| 		/*  10 */ {`int("432", 4)`, nil, errors.New(`too much params -- expected 1, got 2`)}, | ||||
| 		/*  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`)}, | ||||
| 		/*  12 */ {`two=func(){2}; two()`, int64(2), nil}, | ||||
| 		/*  13 */ {`double=func(x) {2*x}; (double(3))`, int64(6), nil}, | ||||
| @ -55,14 +55,8 @@ func TestFuncs(t *testing.T) { | ||||
| 		/*  42 */ {`builtin "string"; endsWithStr("0123456789", "xyz", "0125")`, false, nil}, | ||||
| 		/*  43 */ {`builtin "string"; endsWithStr("0123456789")`, nil, errors.New(`too few params -- expected 2 or more, got 1`)}, | ||||
| 		/*  44 */ {`builtin "string"; splitStr("one-two-three", "-", )`, newListA("one","two","three"), nil}, | ||||
| 		/*  45 */ {`isInt(2+1)`, true, nil}, | ||||
| 		/*  46 */ {`isInt(3.1)`, false, nil}, | ||||
| 		/*  46 */ {`isFloat(3.1)`, true, nil}, | ||||
| 		/*  47 */ {`isString("3.1")`, true, nil}, | ||||
| 		/*  48 */ {`isString("3" + 1)`, true, nil}, | ||||
| 		/*  49 */ {`isList(["3",  1])`, true, nil}, | ||||
| 		/*  50 */ {`isDict({"a":"3",  "b":1})`, true, nil}, | ||||
| 		/*  51 */ {`isFract(3|1)`, true, nil}, | ||||
| 		/*  45 */ {`["a", "b", "c"]`, newListA("a","b","c"), nil}, | ||||
| 		/*  46 */ {`["a", "b", "c"]`, newList([]any{"a","b","c"}), nil}, | ||||
| 	} | ||||
| 
 | ||||
| 	t.Setenv("EXPR_PATH", ".") | ||||
|  | ||||
| @ -36,9 +36,6 @@ func TestListParser(t *testing.T) { | ||||
| 		/* 14 */ {`[1,2,3].1`, int64(2), nil}, | ||||
| 		/* 15 */ {`ls=[1,2,3] but ls.1`, int64(2), nil}, | ||||
| 		/* 16 */ {`ls=[1,2,3] but ls.(-1)`, int64(3), nil}, | ||||
| 		/*  17 */ {`list=["one","two","three"]; list.10`, nil, errors.New(`[1:36] index 10 out of bounds`)}, | ||||
| 		/*  18 */ {`["a", "b", "c"]`, newListA("a", "b", "c"), nil}, | ||||
| 		/*  19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), 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},
 | ||||
|  | ||||
| @ -22,11 +22,10 @@ func verifyIndex(ctx ExprContext, indexTerm *term, maxValue int) (index int, err | ||||
| 	var indexValue any | ||||
| 	if indexValue, err = indexTerm.compute(ctx); err == nil { | ||||
| 		if v, err = indexTerm.toInt(indexValue, "index expression value must be integer"); err == nil { | ||||
| 			if v < 0 && v >= -maxValue { | ||||
| 				v = maxValue + v | ||||
| 			} | ||||
| 			if v >= 0 && v < maxValue { | ||||
| 				index = v | ||||
| 			} else if index >= -maxValue { | ||||
| 				index = maxValue + v | ||||
| 			} else { | ||||
| 				err = indexTerm.Errorf("index %d out of bounds", v) | ||||
| 			} | ||||
|  | ||||
| @ -177,7 +177,7 @@ func parserTest(t *testing.T, section string, inputs []inputType) { | ||||
| 		ctx := NewSimpleFuncStore() | ||||
| 		parser := NewParser(ctx) | ||||
| 
 | ||||
| 		logTest(t, i+1, section, input.source, input.wantResult, input.wantErr) | ||||
| 		logTest(t, i+1, "Iterator", input.source, input.wantResult, input.wantErr) | ||||
| 
 | ||||
| 		r := strings.NewReader(input.source) | ||||
| 		scanner := NewScanner(r, DefaultTranslations()) | ||||
|  | ||||
							
								
								
									
										10
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								utils.go
									
									
									
									
									
								
							| @ -24,11 +24,6 @@ func IsFloat(v any) (ok bool) { | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| func IsBool(v any) (ok bool) { | ||||
| 	_, ok = v.(bool) | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| func IsList(v any) (ok bool) { | ||||
| 	_, ok = v.(*ListType) | ||||
| 	return ok | ||||
| @ -39,11 +34,6 @@ func IsDict(v any) (ok bool) { | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| func IsFract(v any) (ok bool) { | ||||
| 	_, ok = v.(*fraction) | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| func IsNumber(v any) (ok bool) { | ||||
| 	return IsFloat(v) || IsInteger(v) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user