From a6646f1ff2c769037d090c3199bb2283289b7fa2 Mon Sep 17 00:00:00 2001 From: xrstf Date: Sun, 26 Nov 2023 19:46:11 +0100 Subject: [PATCH] embrace native types: evaluate objects/vectors with native child values instead of wrapped ones --- README.md | 4 +- pkg/deepcopy/deepcopy.go | 8 +- pkg/eval/builtin/comparisons.go | 28 ++- pkg/eval/builtin/comparisons_test.go | 111 +++++------ pkg/eval/builtin/core.go | 14 +- pkg/eval/builtin/core_test.go | 287 ++++++++++++++------------- pkg/eval/builtin/dates.go | 2 +- pkg/eval/builtin/encoding.go | 4 +- pkg/eval/builtin/encoding_test.go | 24 +-- pkg/eval/builtin/funcs.go | 17 +- pkg/eval/builtin/hashing.go | 2 +- pkg/eval/builtin/hashing_test.go | 25 ++- pkg/eval/builtin/lists.go | 126 +++++------- pkg/eval/builtin/lists_test.go | 101 +++++----- pkg/eval/builtin/logic.go | 6 +- pkg/eval/builtin/logic_test.go | 33 ++- pkg/eval/builtin/math.go | 14 +- pkg/eval/builtin/math_test.go | 39 ++-- pkg/eval/builtin/strings.go | 22 +- pkg/eval/builtin/strings_test.go | 43 ++-- pkg/eval/builtin/types.go | 35 +--- pkg/eval/builtin/types_test.go | 97 +++++---- pkg/eval/builtin/util.go | 10 + pkg/eval/eval.go | 12 +- pkg/eval/eval_bool.go | 2 +- pkg/eval/eval_null.go | 2 +- pkg/eval/eval_number.go | 2 +- pkg/eval/eval_object.go | 8 +- pkg/eval/eval_path_expression.go | 33 +-- pkg/eval/eval_program.go | 2 +- pkg/eval/eval_statement.go | 7 +- pkg/eval/eval_string.go | 2 +- pkg/eval/eval_symbol.go | 7 +- pkg/eval/eval_tuple.go | 11 +- pkg/eval/eval_vector.go | 8 +- pkg/eval/test/bool_test.go | 4 +- pkg/eval/test/expression_test.go | 16 +- pkg/eval/test/funcs.go | 5 +- pkg/eval/test/null_test.go | 2 +- pkg/eval/test/number_test.go | 10 +- pkg/eval/test/object_test.go | 28 +-- pkg/eval/test/program_test.go | 8 +- pkg/eval/test/statement_test.go | 12 +- pkg/eval/test/string_test.go | 4 +- pkg/eval/test/symbol_test.go | 34 +--- pkg/eval/test/tuple_test.go | 18 +- pkg/eval/test/vector_test.go | 14 +- pkg/eval/types/context.go | 7 +- pkg/pathexpr/delete.go | 23 +-- pkg/testutil/testcase.go | 7 +- 50 files changed, 614 insertions(+), 726 deletions(-) diff --git a/README.md b/README.md index e63251b..0e5d633 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ from GitHub. Examples: * `rudi '.foo' myfile.json` - * `rudi '(set .foo "bar") (set .users 42) .' myfile.json` + * `rudi '(set! .foo "bar") (set! .users 42) .' myfile.json` * `rudi --script convert.rudi myfile.json` `rudi` has extensive help built right into it, try running `rudi help` to get started. @@ -118,7 +118,7 @@ func main() { // functions like "if" and "and", so running with an empty function set // is generally not advisable). rudi.NewBuiltInFunctions(), - // decide what kind of type strictness you would like; pedantic, strict + // Decide what kind of type strictness you would like; pedantic, strict // or humane; choose your own adventure (strict is default if you use nil // here; humane allows conversions like 1 == "1"). coalescing.NewStrict(), diff --git a/pkg/deepcopy/deepcopy.go b/pkg/deepcopy/deepcopy.go index 75c2c4b..fdfea43 100644 --- a/pkg/deepcopy/deepcopy.go +++ b/pkg/deepcopy/deepcopy.go @@ -61,9 +61,9 @@ func clone(val any) (any, error) { case string: return asserted, nil case map[string]any: - return cloneObject(asserted) + return cloneMap(asserted) case []any: - return cloneVector(asserted) + return cloneSlice(asserted) // pointer to Go types @@ -129,7 +129,7 @@ func clone(val any) (any, error) { } } -func cloneVector(obj []any) ([]any, error) { +func cloneSlice(obj []any) ([]any, error) { result := make([]any, len(obj)) for i, item := range obj { cloned, err := clone(item) @@ -143,7 +143,7 @@ func cloneVector(obj []any) ([]any, error) { return result, nil } -func cloneObject(obj map[string]any) (map[string]any, error) { +func cloneMap(obj map[string]any) (map[string]any, error) { result := map[string]any{} for key, value := range obj { cloned, err := clone(value) diff --git a/pkg/eval/builtin/comparisons.go b/pkg/eval/builtin/comparisons.go index 646abf2..708f706 100644 --- a/pkg/eval/builtin/comparisons.go +++ b/pkg/eval/builtin/comparisons.go @@ -23,6 +23,11 @@ func eqFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #0: %w", err) } + leftData, err = types.WrapNative(leftData) + if err != nil { + return nil, fmt.Errorf("argument #0: %w", err) + } + leftValue, ok := leftData.(ast.Literal) if !ok { return nil, fmt.Errorf("argument #0 is not a literal, but %T", leftData) @@ -33,6 +38,11 @@ func eqFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #1: %w", err) } + rightData, err = types.WrapNative(rightData) + if err != nil { + return nil, fmt.Errorf("argument #1: %w", err) + } + rightValue, ok := rightData.(ast.Literal) if !ok { return nil, fmt.Errorf("argument #1 is not a literal, but %T", rightData) @@ -43,7 +53,7 @@ func eqFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } - return ast.Bool(equal), nil + return equal, nil } func likeFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -56,6 +66,11 @@ func likeFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #0: %w", err) } + leftData, err = types.WrapNative(leftData) + if err != nil { + return nil, fmt.Errorf("argument #0: %w", err) + } + leftValue, ok := leftData.(ast.Literal) if !ok { return nil, fmt.Errorf("argument #0 is not a literal, but %T", leftData) @@ -66,6 +81,11 @@ func likeFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #1: %w", err) } + rightData, err = types.WrapNative(rightData) + if err != nil { + return nil, fmt.Errorf("argument #1: %w", err) + } + rightValue, ok := rightData.(ast.Literal) if !ok { return nil, fmt.Errorf("argument #1 is not a literal, but %T", rightData) @@ -76,11 +96,11 @@ func likeFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } - return ast.Bool(equal), nil + return equal, nil } -type intProcessor func(left, right int64) (ast.Bool, error) -type floatProcessor func(left, right float64) (ast.Bool, error) +type intProcessor func(left, right int64) (bool, error) +type floatProcessor func(left, right float64) (bool, error) func makeNumberComparatorFunc(inter intProcessor, floater floatProcessor, desc string) types.Function { return types.BasicFunction(func(ctx types.Context, args []ast.Expression) (any, error) { diff --git a/pkg/eval/builtin/comparisons_test.go b/pkg/eval/builtin/comparisons_test.go index ea01ae8..17ab7c2 100644 --- a/pkg/eval/builtin/comparisons_test.go +++ b/pkg/eval/builtin/comparisons_test.go @@ -7,7 +7,6 @@ import ( "fmt" "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -85,39 +84,39 @@ func TestEqFunction(t *testing.T) { { left: `true`, right: `true`, - expected: ast.Bool(true), + expected: true, }, { left: `true`, right: `false`, - expected: ast.Bool(false), + expected: false, }, { left: `true`, right: `.bool`, - expected: ast.Bool(true), + expected: true, document: testDoc, }, { left: `1`, right: `1`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `2`, - expected: ast.Bool(false), + expected: false, }, { left: `.int`, right: `4`, - expected: ast.Bool(true), + expected: true, document: testDoc, }, { left: `1`, right: `1.0`, - expected: ast.Bool(false), + expected: false, }, { left: `1`, @@ -132,78 +131,78 @@ func TestEqFunction(t *testing.T) { { left: `"foo"`, right: `"foo"`, - expected: ast.Bool(true), + expected: true, }, { left: `.string`, right: `"foo"`, - expected: ast.Bool(true), + expected: true, document: testDoc, }, { left: `"foo"`, right: `"bar"`, - expected: ast.Bool(false), + expected: false, }, { left: `"foo"`, right: `"Foo"`, - expected: ast.Bool(false), + expected: false, }, { left: `"foo"`, right: `" foo"`, - expected: ast.Bool(false), + expected: false, }, { left: `[]`, right: `[]`, - expected: ast.Bool(true), + expected: true, }, { left: `[]`, right: `[1]`, - expected: ast.Bool(false), + expected: false, }, { left: `[1]`, right: `[1]`, - expected: ast.Bool(true), + expected: true, }, { left: `[1 [2] {foo "bar"}]`, right: `[1 [2] {foo "bar"}]`, - expected: ast.Bool(true), + expected: true, }, { left: `[1 [2] {foo "bar"}]`, right: `[1 [2] {foo "baz"}]`, - expected: ast.Bool(false), + expected: false, }, { left: `{}`, right: `{}`, - expected: ast.Bool(true), + expected: true, }, { left: `{}`, right: `{foo "bar"}`, - expected: ast.Bool(false), + expected: false, }, { left: `{foo "bar"}`, right: `{foo "bar"}`, - expected: ast.Bool(true), + expected: true, }, { left: `{foo "bar"}`, right: `{foo "baz"}`, - expected: ast.Bool(false), + expected: false, }, { left: `{foo "bar" l [1 2]}`, right: `{foo "bar" l [1 2]}`, - expected: ast.Bool(true), + expected: true, }, }) @@ -241,117 +240,117 @@ func TestLikeFunction(t *testing.T) { { left: `1`, right: `1`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `"1"`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `1.0`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `"1.0"`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `"2.0"`, - expected: ast.Bool(false), + expected: false, }, { left: `1`, right: `true`, - expected: ast.Bool(true), + expected: true, }, { left: `1`, right: `2`, - expected: ast.Bool(false), + expected: false, }, { left: `false`, right: `null`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `"null"`, - expected: ast.Bool(false), + expected: false, }, { left: `0`, right: `null`, - expected: ast.Bool(true), + expected: true, }, { left: `0.0`, right: `null`, - expected: ast.Bool(true), + expected: true, }, { left: `""`, right: `null`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `0`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `""`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `[]`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `{}`, - expected: ast.Bool(true), + expected: true, }, { left: `false`, right: `"false"`, - expected: ast.Bool(true), + expected: true, }, { left: `true`, right: `{foo "bar"}`, - expected: ast.Bool(true), + expected: true, }, { left: `"foo"`, right: `"bar"`, - expected: ast.Bool(false), + expected: false, }, { left: `true`, right: `[""]`, - expected: ast.Bool(true), + expected: true, }, { left: `{}`, right: `[]`, - expected: ast.Bool(true), + expected: true, }, { left: `{}`, right: `[1]`, - expected: ast.Bool(false), + expected: false, }, { left: `{foo "bar"}`, right: `[]`, - expected: ast.Bool(false), + expected: false, }, }) @@ -401,43 +400,43 @@ func TestLtFunction(t *testing.T) { }, { Expression: `(lt? 3 3)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(lt? 2 (+ 1 2))`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? 2 3)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? -3 2)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? -3 -5)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(lt? 3.4 3.4)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(lt? 2.4 (+ 1.4 2))`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? 2.4 3.4)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? -3.4 2.4)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(lt? -3.4 -5.4)`, - Expected: ast.Bool(false), + Expected: false, }, } diff --git a/pkg/eval/builtin/core.go b/pkg/eval/builtin/core.go index 56e728a..effc758 100644 --- a/pkg/eval/builtin/core.go +++ b/pkg/eval/builtin/core.go @@ -7,9 +7,9 @@ import ( "errors" "fmt" + "go.xrstf.de/rudi/pkg/coalescing" "go.xrstf.de/rudi/pkg/deepcopy" "go.xrstf.de/rudi/pkg/eval" - "go.xrstf.de/rudi/pkg/coalescing" "go.xrstf.de/rudi/pkg/eval/types" "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/pathexpr" @@ -44,7 +44,7 @@ func ifFunction(ctx types.Context, args []ast.Expression) (any, error) { return result, err } - return ast.Null{}, nil + return nil, nil } // (do STEP:Expr+) @@ -137,10 +137,10 @@ func hasFunction(ctx types.Context, args []ast.Expression) (any, error) { _, err = eval.TraverseEvaluatedPathExpression(value, *evaluatedPath) if err != nil { - return ast.Bool(false), nil + return false, nil } - return ast.Bool(true), nil + return true, nil } // (default TEST:Expression FALLBACK:any) @@ -181,7 +181,7 @@ func tryFunction(ctx types.Context, args []ast.Expression) (any, error) { _, result, err := eval.EvalExpression(ctx, args[0]) if err != nil { if len(args) == 1 { - return ast.Null{}, nil + return nil, nil } _, result, err = eval.EvalExpression(ctx, args[1]) @@ -277,7 +277,7 @@ func (deleteFunction) Evaluate(ctx types.Context, args []ast.Expression) (any, e return nil, fmt.Errorf("cannot delete %s in %T: %w", pathExpr, currentValue, err) } - return types.Must(types.WrapNative(updatedValue)), nil + return updatedValue, nil } func (deleteFunction) BangHandler(ctx types.Context, sym ast.Symbol, value any) (types.Context, any, error) { @@ -337,5 +337,5 @@ func isEmptyFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #0: %w", err) } - return ast.Bool(!boolified), nil + return !boolified, nil } diff --git a/pkg/eval/builtin/core_test.go b/pkg/eval/builtin/core_test.go index 7e6a2db..fecb026 100644 --- a/pkg/eval/builtin/core_test.go +++ b/pkg/eval/builtin/core_test.go @@ -51,23 +51,23 @@ func TestIfFunction(t *testing.T) { }, { Expression: `(if true 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { Expression: `(if (eq? 1 1) 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { Expression: `(if (eq? 1 2) 3)`, - Expected: ast.Null{}, + Expected: nil, }, { Expression: `(if (eq? 1 2) "yes" "else")`, - Expected: ast.String("else"), + Expected: "else", }, { Expression: `(if false "yes" (+ 1 4))`, - Expected: ast.Number{Value: int64(5)}, + Expected: int64(5), }, } @@ -81,26 +81,26 @@ func TestSetFunction(t *testing.T) { testObjDocument := func() any { return map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, } } testVecDocument := func() any { - return []any{int64(1), int64(2), map[string]any{"foo": "bar"}} + return []any{1, 2, map[string]any{"foo": "bar"}} } testVariables := func() types.Variables { return types.Variables{ - "myvar": int64(42), + "myvar": 42, "obj": testObjDocument(), "vec": testVecDocument(), - "astVec": ast.Vector{Data: []any{ast.String("foo")}}, + "astVec": []any{"foo"}, } } @@ -140,7 +140,7 @@ func TestSetFunction(t *testing.T) { // return the value that was set (without a bang modifier, this doesn't actually modify anything) { Expression: `(set $var "foo")`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(set $var "foo") $var`, @@ -148,68 +148,71 @@ func TestSetFunction(t *testing.T) { }, { Expression: `(set $var 1)`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, // with bang it works as expected { Expression: `(set! $var 1)`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, { Expression: `(set! $var 1) $var`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, // can overwrite variables on the top level { Expression: `(set! $myvar 12) $myvar`, Variables: testVariables(), - Expected: ast.Number{Value: int64(12)}, + Expected: int64(12), + ExpectedVariables: types.Variables{ + "myvar": int64(12), + }, }, // can change the type { Expression: `(set! $myvar "new value") $myvar`, Variables: testVariables(), - Expected: ast.String("new value"), + Expected: "new value", }, { Expression: `(set! $obj.aList[1] "new value")`, Variables: testVariables(), - Expected: ast.String("new value"), + Expected: "new value", }, { Expression: `(set! $obj.aList[1] "new value") $obj`, Variables: testVariables(), - Expected: ast.Object{Data: map[string]any{ + Expected: map[string]any{ "aString": "foo", "aList": []any{"first", "new value", "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, - }}, + }, }, // set itself does not change the first argument { Expression: `(set $myvar "new value") $myvar`, Variables: testVariables(), - Expected: ast.Number{Value: int64(42)}, + Expected: 42, }, { Expression: `(set $obj.aString "new value") $obj.aString`, Variables: testVariables(), - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(set $obj.aList[1] "new value") $obj.aList`, Variables: testVariables(), - Expected: ast.Vector{Data: []any{"first", int64(2), "third"}}, + Expected: []any{"first", 2, "third"}, }, // ...but not leak into upper scopes { Expression: `(set! $a 1) (if true (set! $a 2)) $a`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, { Expression: `(set! $a 1) (if true (set! $b 2)) $b`, @@ -218,11 +221,11 @@ func TestSetFunction(t *testing.T) { // do not accidentally set a key without creating a new context { Expression: `(set! $a {foo "bar"}) (if true (set! $a.foo "updated"))`, - Expected: ast.String("updated"), + Expected: "updated", }, { Expression: `(set! $a {foo "bar"}) (if true (set! $a.foo "updated")) $a.foo`, - Expected: ast.String("bar"), + Expected: "bar", }, // handle bad paths { @@ -241,50 +244,50 @@ func TestSetFunction(t *testing.T) { // update a key within an object variable { Expression: `(set! $obj.aString "new value")`, - Expected: ast.String("new value"), + Expected: "new value", Variables: testVariables(), }, { Expression: `(set! $obj.aString "new value") $obj.aString`, - Expected: ast.String("new value"), + Expected: "new value", Variables: testVariables(), }, // add a new sub key { Expression: `(set! $obj.newKey "new value")`, - Expected: ast.String("new value"), + Expected: "new value", Variables: testVariables(), }, { Expression: `(set! $obj.newKey "new value") $obj.newKey`, - Expected: ast.String("new value"), + Expected: "new value", Variables: testVariables(), }, // runtime variables { Expression: `(set! $vec [1]) (set! $vec[0] 2) $vec[0]`, - Expected: ast.Number{Value: int64(2)}, + Expected: int64(2), }, // replace the global document { Expression: `(set! . 1) .`, Document: testObjDocument(), - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), ExpectedDocument: int64(1), }, // update keys in the global document { Expression: `(set! .aString "new-value") .aString`, Document: testObjDocument(), - Expected: ast.String("new-value"), + Expected: "new-value", ExpectedDocument: map[string]any{ "aString": "new-value", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, }, }, @@ -292,15 +295,15 @@ func TestSetFunction(t *testing.T) { { Expression: `(set! .newKey "new-value") .newKey`, Document: testObjDocument(), - Expected: ast.String("new-value"), + Expected: "new-value", ExpectedDocument: map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, "newKey": "new-value", }, @@ -309,7 +312,7 @@ func TestSetFunction(t *testing.T) { { Expression: `(set! .aList[1] "new-value") .aList[1]`, Document: testObjDocument(), - Expected: ast.String("new-value"), + Expected: "new-value", ExpectedDocument: map[string]any{ "aString": "foo", "aList": []any{"first", "new-value", "third"}, @@ -317,7 +320,7 @@ func TestSetFunction(t *testing.T) { "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, }, }, @@ -333,12 +336,12 @@ func TestDeleteFunction(t *testing.T) { testObjDocument := func() map[string]any { return map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, } } @@ -370,45 +373,45 @@ func TestDeleteFunction(t *testing.T) { { Expression: `(delete .)`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Null{}, + Expected: nil, ExpectedDocument: map[string]any{"foo": "bar"}, }, { Expression: `(delete! .) .`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Null{}, + Expected: nil, }, // delete does not update the target { Expression: `(delete .) .`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, ExpectedDocument: map[string]any{"foo": "bar"}, }, // can remove a key { Expression: `(delete .foo)`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Object{Data: map[string]any{}}, + Expected: map[string]any{}, ExpectedDocument: map[string]any{"foo": "bar"}, }, { Expression: `(delete .foo) .`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, ExpectedDocument: map[string]any{"foo": "bar"}, }, { Expression: `(delete! .foo) .`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Object{Data: map[string]any{}}, + Expected: map[string]any{}, ExpectedDocument: map[string]any{}, }, // non-existent key is okay { Expression: `(delete .bar)`, Document: map[string]any{"foo": "bar"}, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, ExpectedDocument: map[string]any{"foo": "bar"}, }, // path must be sane though @@ -421,19 +424,19 @@ func TestDeleteFunction(t *testing.T) { { Expression: `(delete .[1])`, Document: []any{"a", "b", "c"}, - Expected: ast.Vector{Data: []any{"a", "c"}}, + Expected: []any{"a", "c"}, ExpectedDocument: []any{"a", "b", "c"}, }, { Expression: `(delete .[1]) .`, Document: []any{"a", "b", "c"}, - Expected: ast.Vector{Data: []any{"a", "b", "c"}}, + Expected: []any{"a", "b", "c"}, ExpectedDocument: []any{"a", "b", "c"}, }, { Expression: `(delete! .[1]) .`, Document: []any{"a", "b", "c"}, - Expected: ast.Vector{Data: []any{"a", "c"}}, + Expected: []any{"a", "c"}, ExpectedDocument: []any{"a", "c"}, }, // vector bounds are checked @@ -451,37 +454,37 @@ func TestDeleteFunction(t *testing.T) { { Expression: `(delete .aList[1])`, Document: testObjDocument(), - Expected: ast.Object{Data: map[string]any{ + Expected: map[string]any{ "aString": "foo", "aList": []any{"first", "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, - }}, + }, ExpectedDocument: testObjDocument(), }, { Expression: `(delete .aList[1]) .`, Document: testObjDocument(), - Expected: ast.Object{Data: testObjDocument()}, + Expected: testObjDocument(), ExpectedDocument: testObjDocument(), }, { Expression: `(delete! .aList[1]) .`, Document: testObjDocument(), - Expected: ast.Object{Data: map[string]any{ + Expected: map[string]any{ "aString": "foo", "aList": []any{"first", "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, - }}, + }, ExpectedDocument: map[string]any{ "aString": "foo", "aList": []any{"first", "third"}, @@ -489,52 +492,52 @@ func TestDeleteFunction(t *testing.T) { "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 7}, }, }, }, { Expression: `(delete .anObject.key3[1].foo)`, Document: testObjDocument(), - Expected: ast.Object{Data: map[string]any{ + Expected: map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{}, int64(7)}, + "key3": []any{9, map[string]any{}, 7}, }, - }}, + }, ExpectedDocument: testObjDocument(), }, { Expression: `(delete .anObject.key3[1].foo) .`, Document: testObjDocument(), - Expected: ast.Object{Data: testObjDocument()}, + Expected: testObjDocument(), ExpectedDocument: testObjDocument(), }, { Expression: `(delete! .anObject.key3[1].foo) .`, Document: testObjDocument(), - Expected: ast.Object{Data: map[string]any{ + Expected: map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{}, int64(7)}, + "key3": []any{9, map[string]any{}, 7}, }, - }}, + }, ExpectedDocument: map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{}, int64(7)}, + "key3": []any{9, map[string]any{}, 7}, }, }, }, @@ -558,23 +561,23 @@ func TestDoFunction(t *testing.T) { }, { Expression: `(do 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, // test that the runtime context is inherited from one step to another { Expression: `(do (set! $var "foo") $var)`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(do (set! $var "foo") $var (set! $var "new") $var)`, - Expected: ast.String("new"), + Expected: "new", }, // test that the runtime context doesn't leak { Expression: `(set! $var "outer") (do (set! $var "inner")) (concat $var ["1" "2"])`, - Expected: ast.String("1outer2"), + Expected: "1outer2", }, { Expression: `(do (set! $var "inner")) (concat $var ["1" "2"])`, @@ -600,18 +603,18 @@ func TestDefaultFunction(t *testing.T) { }, { Expression: `(default null 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, // coalescing should be applied { Expression: `(default false 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { Expression: `(default [] 3)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, // errors are not swallowed @@ -641,33 +644,33 @@ func TestTryFunction(t *testing.T) { }, { Expression: `(try (+ 1 2))`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, // coalescing should be not applied { Expression: `(try false)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(try null)`, - Expected: ast.Null{}, + Expected: nil, }, { Expression: `(try null "fallback")`, - Expected: ast.Null{}, + Expected: nil, }, // swallow errors { Expression: `(try (eq? 3 "foo"))`, - Expected: ast.Null{}, + Expected: nil, }, { Expression: `(try (eq? 3 "foo") "fallback")`, - Expected: ast.String("fallback"), + Expected: "fallback", }, // not in the fallback though @@ -700,47 +703,47 @@ func TestIsEmptyFunction(t *testing.T) { }, { Expression: `(empty? null)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? true)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(empty? false)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? 0)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? 0.0)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? (+ 0 0.0))`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? (+ 1 0.0))`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(empty? [])`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? [""])`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(empty? {})`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(empty? {foo "bar"})`, - Expected: ast.Bool(false), + Expected: false, }, } @@ -753,24 +756,24 @@ func TestIsEmptyFunction(t *testing.T) { func TestHasFunction(t *testing.T) { testObjDocument := map[string]any{ "aString": "foo", - "aList": []any{"first", int64(2), "third"}, + "aList": []any{"first", 2, "third"}, "aBool": true, "anObject": map[string]any{ "key1": true, "key2": nil, - "key3": []any{int64(9), map[string]any{"foo": "bar"}, int64(7)}, + "key3": []any{9, map[string]any{"foo": "bar"}, 77}, }, } - testVecDocument := []any{int64(1), int64(2), map[string]any{"foo": "bar"}} + testVecDocument := []any{1, 2, map[string]any{"foo": "bar"}} testVariables := types.Variables{ // value does not matter here, but this testcase is still meant // to ensure the missing path is detected, not detect an unknown variable - "myvar": int64(42), + "myvar": 42, "obj": testObjDocument, "vec": testVecDocument, - "astVec": ast.Vector{Data: []any{ast.String("foo")}}, + "astVec": ast.Vector{Data: []any{"foo"}}, } testcases := []testutil.Testcase{ @@ -807,108 +810,108 @@ func TestHasFunction(t *testing.T) { { Expression: `(has? .)`, - Expected: ast.Bool(true), + Expected: true, Document: nil, // the . always matches, no matter what the document is }, { Expression: `(has? .)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .nonexistingKey)`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .[0])`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aString)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .["aString"])`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .[(concat "" "a" "String")])`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aBool)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aList)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aList[0])`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aList[99])`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .aList.invalidObjKey)`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject[99])`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject.key1)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject.key99)`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject.key3[1].foo)`, - Expected: ast.Bool(true), + Expected: true, Document: testObjDocument, ExpectedDocument: testObjDocument, }, { Expression: `(has? .anObject.key3[1].bar)`, - Expected: ast.Bool(false), + Expected: false, Document: testObjDocument, ExpectedDocument: testObjDocument, }, @@ -917,19 +920,19 @@ func TestHasFunction(t *testing.T) { { Expression: `(has? .[1])`, - Expected: ast.Bool(true), + Expected: true, Document: testVecDocument, ExpectedDocument: testVecDocument, }, { Expression: `(has? .key)`, - Expected: ast.Bool(false), + Expected: false, Document: testVecDocument, ExpectedDocument: testVecDocument, }, { Expression: `(has? .[2].foo)`, - Expected: ast.Bool(true), + Expected: true, Document: testVecDocument, ExpectedDocument: testVecDocument, }, @@ -938,32 +941,32 @@ func TestHasFunction(t *testing.T) { { Expression: `(has? .)`, - Expected: ast.Bool(true), + Expected: true, Document: "testdata", ExpectedDocument: "testdata", }, { Expression: `(has? .)`, - Expected: ast.Bool(true), + Expected: true, Document: nil, ExpectedDocument: nil, }, { Expression: `(has? .foo)`, - Expected: ast.Bool(false), + Expected: false, Document: "testdata", ExpectedDocument: "testdata", }, { Expression: `(has? .)`, - Expected: ast.Bool(true), + Expected: true, Document: 64, - ExpectedDocument: int64(64), + ExpectedDocument: 64, }, { Expression: `(has? .)`, - Expected: ast.Bool(true), - Document: ast.String("foo"), + Expected: true, + Document: "foo", ExpectedDocument: "foo", }, @@ -981,32 +984,32 @@ func TestHasFunction(t *testing.T) { }, { Expression: `(has? $myvar.foo)`, - Expected: ast.Bool(false), + Expected: false, Variables: testVariables, }, { Expression: `(has? $myvar[0])`, - Expected: ast.Bool(false), + Expected: false, Variables: testVariables, }, { Expression: `(has? $obj.aString)`, - Expected: ast.Bool(true), + Expected: true, Variables: testVariables, }, { Expression: `(has? $obj.aList[1])`, - Expected: ast.Bool(true), + Expected: true, Variables: testVariables, }, { Expression: `(has? $vec[1])`, - Expected: ast.Bool(true), + Expected: true, Variables: testVariables, }, { Expression: `(has? $astVec[0])`, - Expected: ast.Bool(true), + Expected: true, Variables: testVariables, }, @@ -1014,22 +1017,22 @@ func TestHasFunction(t *testing.T) { { Expression: `(has? [1 2 3][1])`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(has? [1 2 3][4])`, - Expected: ast.Bool(false), + Expected: false, }, // follow a path expression on an object node { Expression: `(has? {foo "bar"}.foo)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(has? {foo "bar"}.bar)`, - Expected: ast.Bool(false), + Expected: false, }, // follow a path expression on a tuple node @@ -1037,19 +1040,19 @@ func TestHasFunction(t *testing.T) { { Expression: `(has? (set $foo {foo "bar"}).foo)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(has? (set $foo {foo "bar"}).bar)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(has? (set $foo [1])[0])`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(has? (set $foo {foo "bar"})[0])`, - Expected: ast.Bool(false), + Expected: false, }, } diff --git a/pkg/eval/builtin/dates.go b/pkg/eval/builtin/dates.go index c5e3f15..2068fc6 100644 --- a/pkg/eval/builtin/dates.go +++ b/pkg/eval/builtin/dates.go @@ -29,5 +29,5 @@ func nowFunction(ctx types.Context, args []ast.Expression) (any, error) { formatted := time.Now().Format(string(formatString)) - return ast.String(formatted), nil + return formatted, nil } diff --git a/pkg/eval/builtin/encoding.go b/pkg/eval/builtin/encoding.go index 35aa136..3709adc 100644 --- a/pkg/eval/builtin/encoding.go +++ b/pkg/eval/builtin/encoding.go @@ -30,7 +30,7 @@ func toBase64Function(ctx types.Context, args []ast.Expression) (any, error) { encoded := base64.StdEncoding.EncodeToString([]byte(str)) - return ast.String(encoded), nil + return encoded, nil } // (from-base64 VAL:string) @@ -54,5 +54,5 @@ func fromBase64Function(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("not valid base64: %w", err) } - return ast.String(string(decoded)), nil + return string(decoded), nil } diff --git a/pkg/eval/builtin/encoding_test.go b/pkg/eval/builtin/encoding_test.go index b7b4c45..c038263 100644 --- a/pkg/eval/builtin/encoding_test.go +++ b/pkg/eval/builtin/encoding_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -31,23 +30,23 @@ func TestToBase64Function(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(to-base64 null)`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(to-base64 "")`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(to-base64 " ")`, - Expected: ast.String("IA=="), + Expected: "IA==", }, { Expression: `(to-base64 (concat "" "f" "o" "o"))`, - Expected: ast.String("Zm9v"), + Expected: "Zm9v", }, { Expression: `(to-base64 "test")`, - Expected: ast.String("dGVzdA=="), + Expected: "dGVzdA==", }, } @@ -82,29 +81,28 @@ func TestFromBase64Function(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(from-base64 null)`, - Expected: ast.String(""), - + Expected: "", }, { // should be able to recover Expression: `(try (from-base64 "definitely-not-base64") "fallback")`, - Expected: ast.String("fallback"), + Expected: "fallback", }, { Expression: `(from-base64 "")`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(from-base64 "IA==")`, - Expected: ast.String(" "), + Expected: " ", }, { Expression: `(from-base64 (concat "" "Z" "m" "9" "v"))`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(from-base64 "dGVzdA==")`, - Expected: ast.String("test"), + Expected: "test", }, } diff --git a/pkg/eval/builtin/funcs.go b/pkg/eval/builtin/funcs.go index 447d62c..bd33806 100644 --- a/pkg/eval/builtin/funcs.go +++ b/pkg/eval/builtin/funcs.go @@ -5,7 +5,6 @@ package builtin import ( "go.xrstf.de/rudi/pkg/eval/types" - "go.xrstf.de/rudi/pkg/lang/ast" ) var Functions = types.Functions{ @@ -64,23 +63,23 @@ var Functions = types.Functions{ "like?": types.BasicFunction(likeFunction, `like eq?, but does lossless type conversions so 1 == "1"`), "lt?": makeNumberComparatorFunc( - func(a, b int64) (ast.Bool, error) { return ast.Bool(a < b), nil }, - func(a, b float64) (ast.Bool, error) { return ast.Bool(a < b), nil }, + func(a, b int64) (bool, error) { return a < b, nil }, + func(a, b float64) (bool, error) { return a < b, nil }, "returns a < b", ), "lte?": makeNumberComparatorFunc( - func(a, b int64) (ast.Bool, error) { return ast.Bool(a <= b), nil }, - func(a, b float64) (ast.Bool, error) { return ast.Bool(a <= b), nil }, + func(a, b int64) (bool, error) { return a <= b, nil }, + func(a, b float64) (bool, error) { return a <= b, nil }, "return a <= b", ), "gt?": makeNumberComparatorFunc( - func(a, b int64) (ast.Bool, error) { return ast.Bool(a > b), nil }, - func(a, b float64) (ast.Bool, error) { return ast.Bool(a > b), nil }, + func(a, b int64) (bool, error) { return a > b, nil }, + func(a, b float64) (bool, error) { return a > b, nil }, "returns a > b", ), "gte?": makeNumberComparatorFunc( - func(a, b int64) (ast.Bool, error) { return ast.Bool(a >= b), nil }, - func(a, b float64) (ast.Bool, error) { return ast.Bool(a >= b), nil }, + func(a, b int64) (bool, error) { return a >= b, nil }, + func(a, b float64) (bool, error) { return a >= b, nil }, "returns a >= b", ), diff --git a/pkg/eval/builtin/hashing.go b/pkg/eval/builtin/hashing.go index 2cad871..cc32089 100644 --- a/pkg/eval/builtin/hashing.go +++ b/pkg/eval/builtin/hashing.go @@ -38,7 +38,7 @@ func hashFunc(ctx types.Context, args []ast.Expression, h hash.Hash) (any, error encoded := hex.EncodeToString(h.Sum(nil)) - return ast.String(encoded), nil + return encoded, nil } // (sha1 VAL:string) diff --git a/pkg/eval/builtin/hashing_test.go b/pkg/eval/builtin/hashing_test.go index 5d538b3..f79c090 100644 --- a/pkg/eval/builtin/hashing_test.go +++ b/pkg/eval/builtin/hashing_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -31,19 +30,19 @@ func TestSha1Function(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(sha1 null)`, - Expected: ast.String("da39a3ee5e6b4b0d3255bfef95601890afd80709"), + Expected: "da39a3ee5e6b4b0d3255bfef95601890afd80709", }, { Expression: `(sha1 "")`, - Expected: ast.String("da39a3ee5e6b4b0d3255bfef95601890afd80709"), + Expected: "da39a3ee5e6b4b0d3255bfef95601890afd80709", }, { Expression: `(sha1 " ")`, - Expected: ast.String("b858cb282617fb0956d960215c8e84d1ccf909c6"), + Expected: "b858cb282617fb0956d960215c8e84d1ccf909c6", }, { Expression: `(sha1 (concat "" "f" "o" "o"))`, - Expected: ast.String("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), + Expected: "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", }, } @@ -74,19 +73,19 @@ func TestSha256Function(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(sha256 null)`, - Expected: ast.String("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), + Expected: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }, { Expression: `(sha256 "")`, - Expected: ast.String("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), + Expected: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }, { Expression: `(sha256 " ")`, - Expected: ast.String("36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068"), + Expected: "36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068", }, { Expression: `(sha256 (concat "" "f" "o" "o"))`, - Expected: ast.String("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"), + Expected: "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", }, } @@ -117,19 +116,19 @@ func TestSha512Function(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(sha512 null)`, - Expected: ast.String("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"), + Expected: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", }, { Expression: `(sha512 "")`, - Expected: ast.String("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"), + Expected: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", }, { Expression: `(sha512 " ")`, - Expected: ast.String("f90ddd77e400dfe6a3fcf479b00b1ee29e7015c5bb8cd70f5f15b4886cc339275ff553fc8a053f8ddc7324f45168cffaf81f8c3ac93996f6536eef38e5e40768"), + Expected: "f90ddd77e400dfe6a3fcf479b00b1ee29e7015c5bb8cd70f5f15b4886cc339275ff553fc8a053f8ddc7324f45168cffaf81f8c3ac93996f6536eef38e5e40768", }, { Expression: `(sha512 (concat "" "f" "o" "o"))`, - Expected: ast.String("f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"), + Expected: "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7", }, } diff --git a/pkg/eval/builtin/lists.go b/pkg/eval/builtin/lists.go index 859c9eb..926b00f 100644 --- a/pkg/eval/builtin/lists.go +++ b/pkg/eval/builtin/lists.go @@ -25,15 +25,15 @@ func lenFunction(ctx types.Context, args []ast.Expression) (any, error) { } if vector, err := ctx.Coalesce().ToVector(list); err == nil { - return ast.Number{Value: int64(len(vector))}, nil + return len(vector), nil } if obj, err := ctx.Coalesce().ToObject(list); err == nil { - return ast.Number{Value: int64(len(obj))}, nil + return len(obj), nil } if str, err := ctx.Coalesce().ToString(list); err == nil { - return ast.Number{Value: int64(len(str))}, nil + return len(str), nil } return nil, errors.New("argument is neither a string, vector nor object") @@ -55,9 +55,9 @@ func appendFunction(ctx types.Context, args []ast.Expression) (any, error) { } if vector, err := ctx.Coalesce().ToVector(acc); err == nil { - result := ast.Vector{} - result.Data = append(result.Data, vector...) - result.Data = append(result.Data, evaluated...) + result := []any{} + result = append(result, vector...) + result = append(result, evaluated...) return result, nil } @@ -77,7 +77,7 @@ func appendFunction(ctx types.Context, args []ast.Expression) (any, error) { suffix += string(argString) } - return ast.String(string(str) + suffix), nil + return string(str) + suffix, nil } func prependFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -96,10 +96,7 @@ func prependFunction(ctx types.Context, args []ast.Expression) (any, error) { } if vector, err := ctx.Coalesce().ToVector(acc); err == nil { - result := ast.Vector{Data: evaluated} - result.Data = append(result.Data, vector...) - - return result, nil + return append(evaluated, vector...), nil } str, err := ctx.Coalesce().ToString(acc) @@ -117,7 +114,7 @@ func prependFunction(ctx types.Context, args []ast.Expression) (any, error) { prefix += string(argString) } - return ast.String(prefix + string(str)), nil + return prefix + string(str), nil } func reverseFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -137,17 +134,15 @@ func reverseFunction(ctx types.Context, args []ast.Expression) (any, error) { result[i], result[j] = result[j], result[i] } - return ast.String(result), nil + return string(result), nil } if vector, err := ctx.Coalesce().ToVector(value); err == nil { - result := ast.Vector{ - // clone original data - Data: append([]any{}, vector...), - } + // clone original data + result := append([]any{}, vector...) - for i, j := 0, len(result.Data)-1; i < j; i, j = i+1, j-1 { - result.Data[i], result.Data[j] = result.Data[j], result.Data[i] + for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 { + result[i], result[j] = result[j], result[i] } return result, nil @@ -182,7 +177,6 @@ func rangeFunction(ctx types.Context, args []ast.Expression) (any, error) { } var result any - result = ast.Null{} // list over vector elements if sourceVector, err := ctx.Coalesce().ToVector(source); err == nil { @@ -190,7 +184,7 @@ func rangeFunction(ctx types.Context, args []ast.Expression) (any, error) { // do not use separate contexts for each loop iteration, as the loop might build up a counter innerCtx = innerCtx.WithVariable(loopVarName, item) if loopIndexName != "" { - innerCtx = innerCtx.WithVariable(loopIndexName, ast.Number{Value: int64(i)}) + innerCtx = innerCtx.WithVariable(loopIndexName, i) } for _, expr := range args[2:] { @@ -210,7 +204,7 @@ func rangeFunction(ctx types.Context, args []ast.Expression) (any, error) { // do not use separate contexts for each loop iteration, as the loop might build up a counter innerCtx = innerCtx.WithVariable(loopVarName, value) if loopIndexName != "" { - innerCtx = innerCtx.WithVariable(loopIndexName, ast.String(key)) + innerCtx = innerCtx.WithVariable(loopIndexName, key) } for _, expr := range args[2:] { @@ -246,22 +240,15 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #0: %w", err) } - var lit ast.Literal - if vec, err := ctx.Coalesce().ToVector(source); err == nil { - lit = ast.Vector{Data: vec} - } else if obj, err := ctx.Coalesce().ToObject(source); err == nil { - lit = ast.Object{Data: obj} - } - - if lit == nil { - return nil, fmt.Errorf("argument #0: expected vector or object, got %T", source) + if err := checkIterable(ctx, source); err != nil { + return nil, fmt.Errorf("argument #0: %w", err) } // handle plain function calls // (map VECTOR identifier) // (map OBJECT identifier) if len(args) == 2 { - return anonymousMapFunction(innerCtx, lit, args[1]) + return anonymousMapFunction(innerCtx, source, args[1]) } // all further forms are (map THING NAMING_VEC EXPR+) @@ -287,15 +274,13 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { // list over vector elements if sourceVector, err := ctx.Coalesce().ToVector(source); err == nil { - output := ast.Vector{ - Data: make([]any, len(sourceVector)), - } + output := make([]any, len(sourceVector)) for i, item := range sourceVector { // do not use separate contexts for each loop iteration, as the loop might build up a counter innerCtx = innerCtx.WithVariable(valueVarName, item) if indexVarName != "" { - innerCtx = innerCtx.WithVariable(indexVarName, ast.Number{Value: int64(i)}) + innerCtx = innerCtx.WithVariable(indexVarName, i) } var result any @@ -304,7 +289,7 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } - output.Data[i] = result + output[i] = result } return output, nil @@ -312,9 +297,7 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { // list over object elements if sourceObject, err := ctx.Coalesce().ToObject(source); err == nil { - output := ast.Object{ - Data: map[string]any{}, - } + output := map[string]any{} for key, value := range sourceObject { // do not use separate contexts for each loop iteration, as the loop might build up a counter @@ -329,7 +312,7 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } - output.Data[key] = result + output[key] = result } return output, nil @@ -340,7 +323,7 @@ func mapFunction(ctx types.Context, args []ast.Expression) (any, error) { // (map VECTOR identifier) // (map OBJECT identifier) -func anonymousMapFunction(ctx types.Context, source ast.Literal, expr ast.Expression) (any, error) { +func anonymousMapFunction(ctx types.Context, source any, expr ast.Expression) (any, error) { identifier, ok := expr.(ast.Identifier) if !ok { return nil, fmt.Errorf("argument #1: expected identifier, got %T", expr) @@ -359,9 +342,7 @@ func anonymousMapFunction(ctx types.Context, source ast.Literal, expr ast.Expres } if vector, err := ctx.Coalesce().ToVector(source); err == nil { - output := ast.Vector{ - Data: make([]any, len(vector)), - } + output := make([]any, len(vector)) for i, item := range vector { var ( @@ -374,16 +355,14 @@ func anonymousMapFunction(ctx types.Context, source ast.Literal, expr ast.Expres return nil, err } - output.Data[i] = result + output[i] = result } return output, nil } if object, err := ctx.Coalesce().ToObject(source); err == nil { - output := ast.Object{ - Data: map[string]any{}, - } + output := map[string]any{} for key, value := range object { var ( @@ -396,7 +375,7 @@ func anonymousMapFunction(ctx types.Context, source ast.Literal, expr ast.Expres return nil, err } - output.Data[key] = result + output[key] = result } return output, nil @@ -425,22 +404,15 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, fmt.Errorf("argument #0: %w", err) } - var lit ast.Literal - if vec, err := ctx.Coalesce().ToVector(source); err == nil { - lit = ast.Vector{Data: vec} - } else if obj, err := ctx.Coalesce().ToObject(source); err == nil { - lit = ast.Object{Data: obj} - } - - if lit == nil { - return nil, fmt.Errorf("argument #0: expected Vector or Object, got %T", source) + if err := checkIterable(ctx, source); err != nil { + return nil, fmt.Errorf("argument #0: %w", err) } // handle plain function calls // (filter VECTOR identifier) // (filter OBJECT identifier) if len(args) == 2 { - return anonymousFilterFunction(innerCtx, lit, args[1]) + return anonymousFilterFunction(innerCtx, source, args[1]) } // all further forms are (map THING NAMING_VEC EXPR+) @@ -471,15 +443,13 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { // list over vector elements if sourceVector, err := ctx.Coalesce().ToVector(source); err == nil { - output := ast.Vector{ - Data: []any{}, - } + output := []any{} for i, item := range sourceVector { // do not use separate contexts for each loop iteration, as the loop might build up a counter innerCtx = innerCtx.WithVariable(valueVarName, item) if indexVarName != "" { - innerCtx = innerCtx.WithVariable(indexVarName, ast.Number{Value: int64(i)}) + innerCtx = innerCtx.WithVariable(indexVarName, i) } var result bool @@ -489,7 +459,7 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { } if result { - output.Data = append(output.Data, sourceVector[i]) + output = append(output, sourceVector[i]) } } @@ -498,9 +468,7 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { // list over object elements if sourceObject, err := ctx.Coalesce().ToObject(source); err == nil { - output := ast.Object{ - Data: map[string]any{}, - } + output := map[string]any{} for key, value := range sourceObject { // do not use separate contexts for each loop iteration, as the loop might build up a counter @@ -516,7 +484,7 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { } if result { - output.Data[key] = result + output[key] = result } } @@ -528,7 +496,7 @@ func filterFunction(ctx types.Context, args []ast.Expression) (any, error) { // (filter VECTOR identifier) // (filter OBJECT identifier) -func anonymousFilterFunction(ctx types.Context, source ast.Literal, expr ast.Expression) (any, error) { +func anonymousFilterFunction(ctx types.Context, source any, expr ast.Expression) (any, error) { identifier, ok := expr.(ast.Identifier) if !ok { return nil, fmt.Errorf("argument #1: expected identifier, got %T", expr) @@ -558,9 +526,7 @@ func anonymousFilterFunction(ctx types.Context, source ast.Literal, expr ast.Exp } if vector, err := ctx.Coalesce().ToVector(source); err == nil { - output := ast.Vector{ - Data: []any{}, - } + output := []any{} for i, item := range vector { var ( @@ -574,7 +540,7 @@ func anonymousFilterFunction(ctx types.Context, source ast.Literal, expr ast.Exp } if result { - output.Data = append(output.Data, vector[i]) + output = append(output, vector[i]) } } @@ -582,9 +548,7 @@ func anonymousFilterFunction(ctx types.Context, source ast.Literal, expr ast.Exp } if object, err := ctx.Coalesce().ToObject(source); err == nil { - output := ast.Object{ - Data: map[string]any{}, - } + output := map[string]any{} for key, value := range object { var ( @@ -598,7 +562,7 @@ func anonymousFilterFunction(ctx types.Context, source ast.Literal, expr ast.Exp } if result { - output.Data[key] = result + output[key] = result } } @@ -666,7 +630,7 @@ func containsFunction(ctx types.Context, args []ast.Expression) (any, error) { if strNeedle, err := ctx.Coalesce().ToString(needle); err == nil { contains := strings.Contains(strHaystack, strNeedle) - return ast.Bool(contains), nil + return contains, nil } return nil, fmt.Errorf("argument #1: expected string, got %T", needle) @@ -686,10 +650,10 @@ func containsFunction(ctx types.Context, args []ast.Expression) (any, error) { equal, err := equality.StrictEqual(valLiteral, needleLiteral) if err == nil && equal { - return ast.Bool(true), nil + return true, nil } } } - return ast.Bool(false), nil + return false, nil } diff --git a/pkg/eval/builtin/lists_test.go b/pkg/eval/builtin/lists_test.go index d501840..4078293 100644 --- a/pkg/eval/builtin/lists_test.go +++ b/pkg/eval/builtin/lists_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -31,31 +30,31 @@ func TestLenFunction(t *testing.T) { { // strict coalescing allows null to turn into [] or "", both have len=0 Expression: `(len null)`, - Expected: ast.Number{Value: int64(0)}, + Expected: 0, }, { Expression: `(len "")`, - Expected: ast.Number{Value: int64(0)}, + Expected: 0, }, { Expression: `(len " foo ")`, - Expected: ast.Number{Value: int64(5)}, + Expected: 5, }, { Expression: `(len [])`, - Expected: ast.Number{Value: int64(0)}, + Expected: 0, }, { Expression: `(len [1 2 3])`, - Expected: ast.Number{Value: int64(3)}, + Expected: 3, }, { Expression: `(len {})`, - Expected: ast.Number{Value: int64(0)}, + Expected: 0, }, { Expression: `(len {foo "bar" hello "world"})`, - Expected: ast.Number{Value: int64(2)}, + Expected: 2, }, } @@ -92,23 +91,23 @@ func TestAppendFunction(t *testing.T) { // which would result in "1", but append/prepend prefer the first arg // to be a vector) Expression: `(append null 1)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}}}, + Expected: []any{int64(1)}, }, { Expression: `(append [] 1)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}}}, + Expected: []any{int64(1)}, }, { Expression: `(append [1 2] 3 "foo")`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}, ast.Number{Value: 2}, ast.Number{Value: 3}, ast.String("foo")}}, + Expected: []any{int64(1), int64(2), int64(3), "foo"}, }, { Expression: `(append [] [])`, - Expected: ast.Vector{Data: []any{ast.Vector{Data: []any{}}}}, + Expected: []any{[]any{}}, }, { Expression: `(append [] "foo")`, - Expected: ast.Vector{Data: []any{ast.String("foo")}}, + Expected: []any{"foo"}, }, { Expression: `(append "foo" [])`, @@ -120,7 +119,7 @@ func TestAppendFunction(t *testing.T) { }, { Expression: `(append "foo" "bar" "test")`, - Expected: ast.String("foobartest"), + Expected: "foobartest", }, } @@ -157,27 +156,27 @@ func TestPrependFunction(t *testing.T) { // which would result in "1", but append/prepend prefer the first arg // to be a vector) Expression: `(prepend null 1)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}}}, + Expected: []any{int64(1)}, }, { Expression: `(prepend [] 1)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}}}, + Expected: []any{int64(1)}, }, { Expression: `(prepend [1] 2)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 2}, ast.Number{Value: 1}}}, + Expected: []any{int64(2), int64(1)}, }, { Expression: `(prepend [1 2] 3 "foo")`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 3}, ast.String("foo"), ast.Number{Value: 1}, ast.Number{Value: 2}}}, + Expected: []any{int64(3), "foo", int64(1), int64(2)}, }, { Expression: `(prepend [] [])`, - Expected: ast.Vector{Data: []any{ast.Vector{Data: []any{}}}}, + Expected: []any{[]any{}}, }, { Expression: `(prepend [] "foo")`, - Expected: ast.Vector{Data: []any{ast.String("foo")}}, + Expected: []any{"foo"}, }, { Expression: `(prepend "foo" [])`, @@ -189,7 +188,7 @@ func TestPrependFunction(t *testing.T) { }, { Expression: `(prepend "foo" "bar" "test")`, - Expected: ast.String("bartestfoo"), + Expected: "bartestfoo", }, } @@ -224,35 +223,35 @@ func TestReverseFunction(t *testing.T) { { // strict coalescing allows null to turn into "" Expression: `(reverse null)`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(reverse "")`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(reverse (concat "" "f" "oo"))`, - Expected: ast.String("oof"), + Expected: "oof", }, { Expression: `(reverse "abcd")`, - Expected: ast.String("dcba"), + Expected: "dcba", }, { Expression: `(reverse (reverse "abcd"))`, - Expected: ast.String("abcd"), + Expected: "abcd", }, { Expression: `(reverse [])`, - Expected: ast.Vector{Data: []any{}}, + Expected: []any{}, }, { Expression: `(reverse [1])`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}}}, + Expected: []any{int64(1)}, }, { Expression: `(reverse [1 2 3])`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 3}, ast.Number{Value: 2}, ast.Number{Value: 1}}}, + Expected: []any{int64(3), int64(2), int64(1)}, }, } @@ -312,32 +311,32 @@ func TestRangeFunction(t *testing.T) { { // single simple expression Expression: `(range [1 2 3] [a] (+ 1 2))`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { // multiple expressions that use a common context Expression: `(range [1 2 3] [a] (set! $foo $a) (+ $foo 3))`, - Expected: ast.Number{Value: int64(6)}, + Expected: int64(6), }, { // count iterations Expression: `(range [1 2 3] [loop-var] (set! $counter (+ (default (try $counter) 0) 1)))`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { // value is bound to desired variable Expression: `(range [1 2 3] [a] $a)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { // support loop index variable Expression: `(range [1 2 3] [idx var] $idx)`, - Expected: ast.Number{Value: int64(2)}, + Expected: 2, }, { // support loop index variable Expression: `(range [1 2 3] [idx var] $var)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { // variables do not leak outside the range @@ -352,15 +351,15 @@ func TestRangeFunction(t *testing.T) { { // support ranging over objects Expression: `(range {} [key value] $key)`, - Expected: ast.Null{}, + Expected: nil, }, { Expression: `(range {foo "bar"} [key value] $key)`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(range {foo "bar"} [key value] $value)`, - Expected: ast.String("bar"), + Expected: "bar", }, } @@ -420,11 +419,11 @@ func TestMapFunction(t *testing.T) { { // single simple expression Expression: `(map ["foo" "bar"] to-upper)`, - Expected: ast.Vector{Data: []any{ast.String("FOO"), ast.String("BAR")}}, + Expected: []any{"FOO", "BAR"}, }, { Expression: `(map {foo "bar"} to-upper)`, - Expected: ast.Object{Data: map[string]any{"foo": ast.String("BAR")}}, + Expected: map[string]any{"foo": "BAR"}, }, { // type safety still applies @@ -434,27 +433,27 @@ func TestMapFunction(t *testing.T) { { // eval expression with variable Expression: `(map [1 2 3] [val] (+ $val 3))`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 4}, ast.Number{Value: 5}, ast.Number{Value: 6}}}, + Expected: []any{int64(4), int64(5), int64(6)}, }, { // eval with loop index Expression: `(map ["foo" "bar"] [idx _] $idx)`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 0}, ast.Number{Value: 1}}}, + Expected: []any{0, 1}, }, { // last expression controls the result Expression: `(map [1 2 3] [val] (+ $val 3) "foo")`, - Expected: ast.Vector{Data: []any{ast.String("foo"), ast.String("foo"), ast.String("foo")}}, + Expected: []any{"foo", "foo", "foo"}, }, { // multiple expressions that use a common context Expression: `(map [1 2 3] [val] (set! $foo $val) (+ $foo 3))`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 4}, ast.Number{Value: 5}, ast.Number{Value: 6}}}, + Expected: []any{int64(4), int64(5), int64(6)}, }, { // context is even shared across elements Expression: `(map ["foo" "bar"] [_] (set! $counter (+ (try $counter 0) 1)))`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}, ast.Number{Value: 2}}}, + Expected: []any{int64(1), int64(2)}, }, { // variables do not leak outside the range @@ -469,27 +468,27 @@ func TestMapFunction(t *testing.T) { // do not modify the source { Expression: `(set! $foo [1 2 3]) (map $foo [_ __] "bar")`, - Expected: ast.Vector{Data: []any{ast.String("bar"), ast.String("bar"), ast.String("bar")}}, + Expected: []any{"bar", "bar", "bar"}, }, { Expression: `(set! $foo [1 2 3]) (map $foo [_ __] "bar") $foo`, - Expected: ast.Vector{Data: []any{ast.Number{Value: 1}, ast.Number{Value: 2}, ast.Number{Value: 3}}}, + Expected: []any{int64(1), int64(2), int64(3)}, }, { Expression: `(set! $foo {foo "bar"}) (map $foo [_ __] "new-value") $foo`, - Expected: ast.Object{Data: map[string]any{"foo": ast.String("bar")}}, + Expected: map[string]any{"foo": "bar"}, }, { Expression: `(set! $foo ["foo" "bar"]) (map $foo to-upper)`, - Expected: ast.Vector{Data: []any{ast.String("FOO"), ast.String("BAR")}}, + Expected: []any{"FOO", "BAR"}, }, { Expression: `(set! $foo ["foo" "bar"]) (map $foo to-upper) $foo`, - Expected: ast.Vector{Data: []any{ast.String("foo"), ast.String("bar")}}, + Expected: []any{"foo", "bar"}, }, { Expression: `(set! $foo {foo "bar"}) (map $foo to-upper) $foo`, - Expected: ast.Object{Data: map[string]any{"foo": ast.String("bar")}}, + Expected: map[string]any{"foo": "bar"}, }, } diff --git a/pkg/eval/builtin/logic.go b/pkg/eval/builtin/logic.go index b5a3f88..7896022 100644 --- a/pkg/eval/builtin/logic.go +++ b/pkg/eval/builtin/logic.go @@ -31,7 +31,7 @@ func andFunction(ctx types.Context, args []ast.Expression) (any, error) { result = result && bool(part) } - return ast.Bool(result), nil + return result, nil } func orFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -54,7 +54,7 @@ func orFunction(ctx types.Context, args []ast.Expression) (any, error) { result = result || bool(part) } - return ast.Bool(result), nil + return result, nil } func notFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -72,5 +72,5 @@ func notFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } - return ast.Bool(!arg), nil + return !arg, nil } diff --git a/pkg/eval/builtin/logic_test.go b/pkg/eval/builtin/logic_test.go index 9751f0a..19e8aa2 100644 --- a/pkg/eval/builtin/logic_test.go +++ b/pkg/eval/builtin/logic_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -50,27 +49,27 @@ func TestAndFunction(t *testing.T) { }, { Expression: `(and true)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(and false)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(and null)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(and true false)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(and true true)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(and (eq? 1 1) true)`, - Expected: ast.Bool(true), + Expected: true, }, } @@ -120,27 +119,27 @@ func TestOrFunction(t *testing.T) { }, { Expression: `(or true)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(or false)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(or null)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(or true false)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(or true true)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(or (eq? 1 1) true)`, - Expected: ast.Bool(true), + Expected: true, }, } @@ -194,19 +193,19 @@ func TestNotFunction(t *testing.T) { }, { Expression: `(not false)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(not true)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(not null)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(not (not (not (not true))))`, - Expected: ast.Bool(true), + Expected: true, }, } diff --git a/pkg/eval/builtin/math.go b/pkg/eval/builtin/math.go index e229c36..0265bd8 100644 --- a/pkg/eval/builtin/math.go +++ b/pkg/eval/builtin/math.go @@ -54,7 +54,7 @@ func sumFunction(ctx types.Context, args []ast.Expression) (any, error) { sum += val } - return ast.Number{Value: sum}, nil + return sum, nil } sum := float64(0) @@ -62,7 +62,7 @@ func sumFunction(ctx types.Context, args []ast.Expression) (any, error) { sum += num.ToFloat() } - return ast.Number{Value: sum}, nil + return sum, nil } func subFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -82,7 +82,7 @@ func subFunction(ctx types.Context, args []ast.Expression) (any, error) { difference -= val } - return ast.Number{Value: difference}, nil + return difference, nil } difference := values[0].ToFloat() @@ -90,7 +90,7 @@ func subFunction(ctx types.Context, args []ast.Expression) (any, error) { difference -= num.ToFloat() } - return ast.Number{Value: difference}, nil + return difference, nil } func multiplyFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -110,7 +110,7 @@ func multiplyFunction(ctx types.Context, args []ast.Expression) (any, error) { product *= factor } - return ast.Number{Value: product}, nil + return product, nil } product := float64(1) @@ -118,7 +118,7 @@ func multiplyFunction(ctx types.Context, args []ast.Expression) (any, error) { product *= num.ToFloat() } - return ast.Number{Value: product}, nil + return product, nil } func divideFunction(ctx types.Context, args []ast.Expression) (any, error) { @@ -141,5 +141,5 @@ func divideFunction(ctx types.Context, args []ast.Expression) (any, error) { result /= divisor } - return ast.Number{Value: result}, nil + return result, nil } diff --git a/pkg/eval/builtin/math_test.go b/pkg/eval/builtin/math_test.go index 826f1ce..050a38a 100644 --- a/pkg/eval/builtin/math_test.go +++ b/pkg/eval/builtin/math_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -38,23 +37,23 @@ func TestSumFunction(t *testing.T) { }, { Expression: `(+ 1 2)`, - Expected: ast.Number{Value: int64(3)}, + Expected: int64(3), }, { Expression: `(+ 1 -2 5)`, - Expected: ast.Number{Value: int64(4)}, + Expected: int64(4), }, { Expression: `(+ 1 1.5)`, - Expected: ast.Number{Value: float64(2.5)}, + Expected: float64(2.5), }, { Expression: `(+ 1 1.5 (+ 1 2))`, - Expected: ast.Number{Value: float64(5.5)}, + Expected: float64(5.5), }, { Expression: `(+ 0 0.0 -5.6)`, - Expected: ast.Number{Value: float64(-5.6)}, + Expected: float64(-5.6), }, } @@ -88,23 +87,23 @@ func TestMinusFunction(t *testing.T) { }, { Expression: `(- 1 2)`, - Expected: ast.Number{Value: int64(-1)}, + Expected: int64(-1), }, { Expression: `(- 1 -2 5)`, - Expected: ast.Number{Value: int64(-2)}, + Expected: int64(-2), }, { Expression: `(- 1 1.5)`, - Expected: ast.Number{Value: float64(-0.5)}, + Expected: float64(-0.5), }, { Expression: `(- 1 1.5 (- 1 2))`, - Expected: ast.Number{Value: float64(0.5)}, + Expected: float64(0.5), }, { Expression: `(- 0 0.0 -5.6)`, - Expected: ast.Number{Value: float64(5.6)}, + Expected: float64(5.6), }, } @@ -138,23 +137,23 @@ func TestMultiplyFunction(t *testing.T) { }, { Expression: `(* 1 2)`, - Expected: ast.Number{Value: int64(2)}, + Expected: int64(2), }, { Expression: `(* 1 -2 5)`, - Expected: ast.Number{Value: int64(-10)}, + Expected: int64(-10), }, { Expression: `(* 2 -1.5)`, - Expected: ast.Number{Value: float64(-3.0)}, + Expected: float64(-3.0), }, { Expression: `(* 1 1.5 (* 1 2))`, - Expected: ast.Number{Value: float64(3.0)}, + Expected: float64(3.0), }, { Expression: `(* 0 0.0 -5.6)`, - Expected: ast.Number{Value: float64(0)}, + Expected: float64(0), }, } @@ -188,19 +187,19 @@ func TestDivideFunction(t *testing.T) { }, { Expression: `(/ 1 2)`, - Expected: ast.Number{Value: float64(0.5)}, + Expected: float64(0.5), }, { Expression: `(/ 1 -2 5)`, - Expected: ast.Number{Value: float64(-0.1)}, + Expected: float64(-0.1), }, { Expression: `(/ 2 -1.5)`, - Expected: ast.Number{Value: float64(-1.33333333333333333333)}, + Expected: float64(-1.33333333333333333333), }, { Expression: `(/ 1 1.5 (/ 1 2))`, - Expected: ast.Number{Value: float64(1.33333333333333333333)}, + Expected: float64(1.33333333333333333333), }, { Expression: `(/ 0 0.0 -5.6)`, diff --git a/pkg/eval/builtin/strings.go b/pkg/eval/builtin/strings.go index 42da9c9..26033da 100644 --- a/pkg/eval/builtin/strings.go +++ b/pkg/eval/builtin/strings.go @@ -56,7 +56,7 @@ func concatFunction(ctx types.Context, args []ast.Expression) (any, error) { } } - return ast.String(strings.Join(parts, string(glueString))), nil + return strings.Join(parts, string(glueString)), nil } type genericStringFunc func(ctx types.Context, args []string) (any, error) @@ -89,59 +89,61 @@ func fromStringFunc(f genericStringFunc, expectedArgs int, desc string) types.Fu // (split SEP:String SOURCE:String) func splitFunction(ctx types.Context, args []string) (any, error) { parts := strings.Split(args[1], args[0]) + + // to []any result := make([]any, len(parts)) for i, part := range parts { - result[i] = ast.String(part) + result[i] = part } - return ast.Vector{Data: result}, nil + return result, nil } // (has-suffix SOURCE:String SUFFIX:String) func hasSuffixFunction(ctx types.Context, args []string) (any, error) { result := strings.HasSuffix(args[0], args[1]) - return ast.Bool(result), nil + return result, nil } // (has-prefix SOURCE:String PREFIX:String) func hasPrefixFunction(ctx types.Context, args []string) (any, error) { result := strings.HasPrefix(args[0], args[1]) - return ast.Bool(result), nil + return result, nil } // (trim-suffix SOURCE:String SUFFIX:String) func trimSuffixFunction(ctx types.Context, args []string) (any, error) { result := strings.TrimSuffix(args[0], args[1]) - return ast.String(result), nil + return result, nil } // (trim-prefix SOURCE:String PREFIX:String) func trimPrefixFunction(ctx types.Context, args []string) (any, error) { result := strings.TrimPrefix(args[0], args[1]) - return ast.String(result), nil + return result, nil } // (to-lower SOURCE:String) func toLowerFunction(ctx types.Context, args []string) (any, error) { result := strings.ToLower(args[0]) - return ast.String(result), nil + return result, nil } // (to-upper SOURCE:String) func toUpperFunction(ctx types.Context, args []string) (any, error) { result := strings.ToUpper(args[0]) - return ast.String(result), nil + return result, nil } // (trim SOURCE:String) func trimFunction(ctx types.Context, args []string) (any, error) { result := strings.TrimSpace(args[0]) - return ast.String(result), nil + return result, nil } diff --git a/pkg/eval/builtin/strings_test.go b/pkg/eval/builtin/strings_test.go index da9840a..f85c709 100644 --- a/pkg/eval/builtin/strings_test.go +++ b/pkg/eval/builtin/strings_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -50,23 +49,23 @@ func TestConcatFunction(t *testing.T) { }, { Expression: `(concat "g" "foo")`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(concat "-" "foo" "bar" "test")`, - Expected: ast.String("foo-bar-test"), + Expected: "foo-bar-test", }, { Expression: `(concat "" "foo" "bar")`, - Expected: ast.String("foobar"), + Expected: "foobar", }, { Expression: `(concat "" ["foo" "bar"])`, - Expected: ast.String("foobar"), + Expected: "foobar", }, { Expression: `(concat "-" ["foo" "bar"] "test" ["suffix"])`, - Expected: ast.String("foo-bar-test-suffix"), + Expected: "foo-bar-test-suffix", }, } @@ -104,33 +103,23 @@ func TestSplitFunction(t *testing.T) { }, { Expression: `(split "" "")`, - Expected: ast.Vector{ - Data: []any{}, - }, + Expected: []any{}, }, { Expression: `(split "g" "")`, - Expected: ast.Vector{ - Data: []any{ast.String("")}, - }, + Expected: []any{""}, }, { Expression: `(split "g" "foo")`, - Expected: ast.Vector{ - Data: []any{ast.String("foo")}, - }, + Expected: []any{"foo"}, }, { Expression: `(split "-" "foo-bar-test-")`, - Expected: ast.Vector{ - Data: []any{ast.String("foo"), ast.String("bar"), ast.String("test"), ast.String("")}, - }, + Expected: []any{"foo", "bar", "test", ""}, }, { Expression: `(split "" "foobar")`, - Expected: ast.Vector{ - Data: []any{ast.String("f"), ast.String("o"), ast.String("o"), ast.String("b"), ast.String("a"), ast.String("r")}, - }, + Expected: []any{"f", "o", "o", "b", "a", "r"}, }, } @@ -164,15 +153,15 @@ func TestToUpperFunction(t *testing.T) { }, { Expression: `(to-upper "")`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(to-upper " TeSt ")`, - Expected: ast.String(" TEST "), + Expected: " TEST ", }, { Expression: `(to-upper " test ")`, - Expected: ast.String(" TEST "), + Expected: " TEST ", }, } @@ -206,15 +195,15 @@ func TestToLowerFunction(t *testing.T) { }, { Expression: `(to-lower "")`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(to-lower " TeSt ")`, - Expected: ast.String(" test "), + Expected: " test ", }, { Expression: `(to-lower " TEST ")`, - Expected: ast.String(" test "), + Expected: " test ", }, } diff --git a/pkg/eval/builtin/types.go b/pkg/eval/builtin/types.go index 2f590df..8009a15 100644 --- a/pkg/eval/builtin/types.go +++ b/pkg/eval/builtin/types.go @@ -25,12 +25,7 @@ func toStringFunction(ctx types.Context, args []ast.Expression) (any, error) { } // this function purposefully always uses humane coalescing - coalesced, err := coalescing.NewHumane().ToString(value) - if err != nil { - return nil, err - } - - return ast.String(coalesced), nil + return coalescing.NewHumane().ToString(value) } // (to-int VAL:any) @@ -45,12 +40,7 @@ func toIntFunction(ctx types.Context, args []ast.Expression) (any, error) { } // this function purposefully always uses humane coalescing - coalesced, err := coalescing.NewHumane().ToInt64(value) - if err != nil { - return nil, err - } - - return ast.Number{Value: coalesced}, nil + return coalescing.NewHumane().ToInt64(value) } // (to-float VAL:any) @@ -65,12 +55,7 @@ func toFloatFunction(ctx types.Context, args []ast.Expression) (any, error) { } // this function purposefully always uses humane coalescing - coalesced, err := coalescing.NewHumane().ToFloat64(value) - if err != nil { - return nil, err - } - - return ast.Number{Value: coalesced}, nil + return coalescing.NewHumane().ToFloat64(value) } // (to-bool VAL:any) @@ -85,12 +70,7 @@ func toBoolFunction(ctx types.Context, args []ast.Expression) (any, error) { } // this function purposefully always uses humane coalescing - coalesced, err := coalescing.NewHumane().ToBool(value) - if err != nil { - return nil, err - } - - return ast.Bool(coalesced), nil + return coalescing.NewHumane().ToBool(value) } // (type-of VAL:any) @@ -104,6 +84,11 @@ func typeOfFunction(ctx types.Context, args []ast.Expression) (any, error) { return nil, err } + value, err = types.WrapNative(value) + if err != nil { + return nil, err + } + expr, ok := value.(ast.Literal) if !ok { return nil, fmt.Errorf("expected expression, but got %T", value) @@ -111,5 +96,5 @@ func typeOfFunction(ctx types.Context, args []ast.Expression) (any, error) { name := strings.ToLower(expr.ExpressionName()) - return ast.String(name), nil + return name, nil } diff --git a/pkg/eval/builtin/types_test.go b/pkg/eval/builtin/types_test.go index 8bde9e6..156254b 100644 --- a/pkg/eval/builtin/types_test.go +++ b/pkg/eval/builtin/types_test.go @@ -6,7 +6,6 @@ package builtin import ( "testing" - "go.xrstf.de/rudi/pkg/lang/ast" "go.xrstf.de/rudi/pkg/testutil" ) @@ -22,31 +21,31 @@ func TestToStringFunction(t *testing.T) { }, { Expression: `(to-string "foo")`, - Expected: ast.String("foo"), + Expected: "foo", }, { Expression: `(to-string 1)`, - Expected: ast.String("1"), + Expected: "1", }, { Expression: `(to-string (+ 1 3))`, - Expected: ast.String("4"), + Expected: "4", }, { Expression: `(to-string 1.5)`, - Expected: ast.String("1.5"), + Expected: "1.5", }, { Expression: `(to-string 1e3)`, - Expected: ast.String("1000"), + Expected: "1000", }, { Expression: `(to-string true)`, - Expected: ast.String("true"), + Expected: "true", }, { Expression: `(to-string null)`, - Expected: ast.String(""), + Expected: "", }, { Expression: `(to-string [])`, @@ -76,15 +75,15 @@ func TestToIntFunction(t *testing.T) { }, { Expression: `(to-int 1)`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, { Expression: `(to-int "42")`, - Expected: ast.Number{Value: int64(42)}, + Expected: int64(42), }, { Expression: `(to-int (+ 1 3))`, - Expected: ast.Number{Value: int64(4)}, + Expected: int64(4), }, { Expression: `(to-int 1.5)`, @@ -96,15 +95,15 @@ func TestToIntFunction(t *testing.T) { }, { Expression: `(to-int true)`, - Expected: ast.Number{Value: int64(1)}, + Expected: int64(1), }, { Expression: `(to-int false)`, - Expected: ast.Number{Value: int64(0)}, + Expected: int64(0), }, { Expression: `(to-int null)`, - Expected: ast.Number{Value: int64(0)}, + Expected: int64(0), }, { Expression: `(to-int [])`, @@ -134,35 +133,35 @@ func TestToFloatFunction(t *testing.T) { }, { Expression: `(to-float 1)`, - Expected: ast.Number{Value: float64(1)}, + Expected: float64(1), }, { Expression: `(to-float (+ 1 3))`, - Expected: ast.Number{Value: float64(4)}, + Expected: float64(4), }, { Expression: `(to-float 1.5)`, - Expected: ast.Number{Value: float64(1.5)}, + Expected: float64(1.5), }, { Expression: `(to-float "3")`, - Expected: ast.Number{Value: float64(3)}, + Expected: float64(3), }, { Expression: `(to-float "1.5")`, - Expected: ast.Number{Value: float64(1.5)}, + Expected: float64(1.5), }, { Expression: `(to-float true)`, - Expected: ast.Number{Value: float64(1)}, + Expected: float64(1), }, { Expression: `(to-float false)`, - Expected: ast.Number{Value: float64(0)}, + Expected: float64(0), }, { Expression: `(to-float null)`, - Expected: ast.Number{Value: float64(0)}, + Expected: float64(0), }, { Expression: `(to-float [])`, @@ -192,55 +191,55 @@ func TestToBoolFunction(t *testing.T) { }, { Expression: `(to-bool 1)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool 0)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool (+ 1 3))`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool 1.5)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool 0.0)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool "3")`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool true)`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool false)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool null)`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool [])`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool [0])`, - Expected: ast.Bool(true), + Expected: true, }, { Expression: `(to-bool {})`, - Expected: ast.Bool(false), + Expected: false, }, { Expression: `(to-bool {foo "bar"})`, - Expected: ast.Bool(true), + Expected: true, }, } @@ -262,59 +261,59 @@ func TestTypeOfFunction(t *testing.T) { }, { Expression: `(type-of 1)`, - Expected: ast.String("number"), + Expected: "number", }, { Expression: `(type-of 0)`, - Expected: ast.String("number"), + Expected: "number", }, { Expression: `(type-of (+ 1 3))`, - Expected: ast.String("number"), + Expected: "number", }, { Expression: `(type-of 1.5)`, - Expected: ast.String("number"), + Expected: "number", }, { Expression: `(type-of 0.0)`, - Expected: ast.String("number"), + Expected: "number", }, { Expression: `(type-of "3")`, - Expected: ast.String("string"), + Expected: "string", }, { Expression: `(type-of true)`, - Expected: ast.String("bool"), + Expected: "bool", }, { Expression: `(type-of false)`, - Expected: ast.String("bool"), + Expected: "bool", }, { Expression: `(type-of null)`, - Expected: ast.String("null"), + Expected: "null", }, { Expression: `(type-of [])`, - Expected: ast.String("vector"), + Expected: "vector", }, { Expression: `(type-of (append [] "test"))`, - Expected: ast.String("vector"), + Expected: "vector", }, { Expression: `(type-of [0])`, - Expected: ast.String("vector"), + Expected: "vector", }, { Expression: `(type-of {})`, - Expected: ast.String("object"), + Expected: "object", }, { Expression: `(type-of {foo "bar"})`, - Expected: ast.String("object"), + Expected: "object", }, } diff --git a/pkg/eval/builtin/util.go b/pkg/eval/builtin/util.go index 86ea018..cfa9e04 100644 --- a/pkg/eval/builtin/util.go +++ b/pkg/eval/builtin/util.go @@ -24,3 +24,13 @@ func evalArgs(ctx types.Context, args []ast.Expression, argShift int) ([]any, er return values, nil } + +func checkIterable(ctx types.Context, val any) error { + if _, err := ctx.Coalesce().ToVector(val); err != nil { + if _, err := ctx.Coalesce().ToObject(val); err != nil { + return fmt.Errorf("expected vector or object, got %T", val) + } + } + + return nil +} diff --git a/pkg/eval/eval.go b/pkg/eval/eval.go index f853b73..6e11efc 100644 --- a/pkg/eval/eval.go +++ b/pkg/eval/eval.go @@ -9,15 +9,5 @@ import ( ) func Run(ctx types.Context, p *ast.Program) (types.Context, any, error) { - newCtx, result, err := EvalProgram(ctx, p) - if err != nil { - return ctx, nil, err - } - - unwrapped, err := types.UnwrapType(result) - if err != nil { - return ctx, nil, err - } - - return newCtx, unwrapped, nil + return EvalProgram(ctx, p) } diff --git a/pkg/eval/eval_bool.go b/pkg/eval/eval_bool.go index 8a34a75..ba1176a 100644 --- a/pkg/eval/eval_bool.go +++ b/pkg/eval/eval_bool.go @@ -9,5 +9,5 @@ import ( ) func EvalBool(ctx types.Context, b ast.Bool) (types.Context, any, error) { - return ctx, b, nil + return ctx, b.LiteralValue(), nil } diff --git a/pkg/eval/eval_null.go b/pkg/eval/eval_null.go index 6919f84..7a8ac22 100644 --- a/pkg/eval/eval_null.go +++ b/pkg/eval/eval_null.go @@ -9,5 +9,5 @@ import ( ) func EvalNull(ctx types.Context, n ast.Null) (types.Context, any, error) { - return ctx, n, nil + return ctx, nil, nil } diff --git a/pkg/eval/eval_number.go b/pkg/eval/eval_number.go index ae484f3..0114f98 100644 --- a/pkg/eval/eval_number.go +++ b/pkg/eval/eval_number.go @@ -9,5 +9,5 @@ import ( ) func EvalNumber(ctx types.Context, n ast.Number) (types.Context, any, error) { - return ctx, n, nil + return ctx, n.LiteralValue(), nil } diff --git a/pkg/eval/eval_object.go b/pkg/eval/eval_object.go index 5082ae2..fa4cee0 100644 --- a/pkg/eval/eval_object.go +++ b/pkg/eval/eval_object.go @@ -13,14 +13,12 @@ import ( // evaluated objects are technically considered expressions. func EvalObject(ctx types.Context, obj ast.Object) (types.Context, any, error) { - return ctx, obj, nil + return ctx, obj.LiteralValue(), nil } func EvalObjectNode(ctx types.Context, obj ast.ObjectNode) (types.Context, any, error) { innerCtx := ctx - result := ast.Object{ - Data: map[string]any{}, - } + result := map[string]any{} var ( key any @@ -56,7 +54,7 @@ func EvalObjectNode(ctx types.Context, obj ast.ObjectNode) (types.Context, any, return ctx, nil, fmt.Errorf("failed to evaluate object value %s: %w", pair.Value.String(), err) } - result.Data[keyString] = value + result[keyString] = value } if obj.PathExpression != nil { diff --git a/pkg/eval/eval_path_expression.go b/pkg/eval/eval_path_expression.go index 15746c2..b4d8997 100644 --- a/pkg/eval/eval_path_expression.go +++ b/pkg/eval/eval_path_expression.go @@ -4,7 +4,6 @@ package eval import ( - "errors" "fmt" "go.xrstf.de/rudi/pkg/eval/types" @@ -35,7 +34,7 @@ func EvalPathExpression(ctx types.Context, path *ast.PathExpression) (*ast.Evalu // $var[(set $bla 2)][(add $bla 2)] <-- would be $var[2][4] switch asserted := step.(type) { case ast.Identifier: - evaluated = asserted + evaluated = asserted.Name default: innerCtx, evaluated, err = EvalExpression(innerCtx, step) if err != nil { @@ -60,21 +59,14 @@ func ptrTo[T any](s T) *T { func convertToAccessor(evaluated any) (*ast.EvaluatedPathStep, error) { switch asserted := evaluated.(type) { - case ast.String: - return &ast.EvaluatedPathStep{StringValue: ptrTo(string(asserted))}, nil - case ast.Identifier: - if asserted.Bang { - return nil, errors.New("cannot use bang modifier in path expression") - } - - return &ast.EvaluatedPathStep{StringValue: &asserted.Name}, nil - case ast.Number: - intVal, ok := asserted.ToInteger() - if !ok { - return nil, fmt.Errorf("cannot use floats as indices: %v", asserted.ToFloat()) - } - - return &ast.EvaluatedPathStep{IntegerValue: &intVal}, nil + case string: + return &ast.EvaluatedPathStep{StringValue: &asserted}, nil + case int: + return &ast.EvaluatedPathStep{IntegerValue: ptrTo(int64(asserted))}, nil + case int32: + return &ast.EvaluatedPathStep{IntegerValue: ptrTo(int64(asserted))}, nil + case int64: + return &ast.EvaluatedPathStep{IntegerValue: &asserted}, nil default: return nil, fmt.Errorf("cannot use %T in path expression", asserted) } @@ -90,10 +82,5 @@ func TraversePathExpression(ctx types.Context, value any, path *ast.PathExpressi } func TraverseEvaluatedPathExpression(value any, path ast.EvaluatedPathExpression) (any, error) { - result, err := pathexpr.Get(value, pathexpr.FromEvaluatedPath(path)) - if err != nil { - return nil, err - } - - return types.WrapNative(result) + return pathexpr.Get(value, pathexpr.FromEvaluatedPath(path)) } diff --git a/pkg/eval/eval_program.go b/pkg/eval/eval_program.go index 694951c..f7fae6f 100644 --- a/pkg/eval/eval_program.go +++ b/pkg/eval/eval_program.go @@ -17,7 +17,7 @@ func EvalProgram(ctx types.Context, p *ast.Program) (types.Context, any, error) } if len(p.Statements) == 0 { - return ctx, ast.Null{}, nil + return ctx, nil, nil } innerCtx := ctx diff --git a/pkg/eval/eval_statement.go b/pkg/eval/eval_statement.go index 265a0c9..ad85c09 100644 --- a/pkg/eval/eval_statement.go +++ b/pkg/eval/eval_statement.go @@ -9,10 +9,5 @@ import ( ) func EvalStatement(ctx types.Context, stmt ast.Statement) (types.Context, any, error) { - newContext, result, err := EvalExpression(ctx, stmt.Expression) - if err != nil { - return ctx, nil, err - } - - return newContext, result, nil + return EvalExpression(ctx, stmt.Expression) } diff --git a/pkg/eval/eval_string.go b/pkg/eval/eval_string.go index 191f48c..c5a670e 100644 --- a/pkg/eval/eval_string.go +++ b/pkg/eval/eval_string.go @@ -9,5 +9,5 @@ import ( ) func EvalString(ctx types.Context, str ast.String) (types.Context, any, error) { - return ctx, str, nil + return ctx, str.LiteralValue(), nil } diff --git a/pkg/eval/eval_symbol.go b/pkg/eval/eval_symbol.go index 19f2cb3..9a12ee0 100644 --- a/pkg/eval/eval_symbol.go +++ b/pkg/eval/eval_symbol.go @@ -36,12 +36,7 @@ func EvalSymbolWithEvaluatedPath(ctx types.Context, sym ast.Symbol, path ast.Eva // . always returns the root document if sym.IsDot() { - wrapped, err := types.WrapNative(rootValue) - if err != nil { - return ctx, nil, err - } - - return ctx, wrapped, nil + return ctx, rootValue, nil } // if this symbol is a variable, replace the root value with the variable's value diff --git a/pkg/eval/eval_tuple.go b/pkg/eval/eval_tuple.go index f25c158..0f54176 100644 --- a/pkg/eval/eval_tuple.go +++ b/pkg/eval/eval_tuple.go @@ -87,10 +87,7 @@ func EvalFunctionCall(ctx types.Context, fun ast.Identifier, args []ast.Expressi // We always return the computed value, no matter how deep we inject it into the symbol; // but for setting the new variable/document, we need the _whole_ new value, which might be // the result of combining the current + setting a value deep somewhere. - // We store unwrapped, native Go types in variables, assuming that they and especially the - // global document are later post-processed outside of Rudi and keeping the data "clean" is - // being a good neighbour. - unwrappedResult := types.Must(types.UnwrapType(result)) + updatedValue := result // if the symbol has a path to traverse, do so if updateSymbol.PathExpression != nil { @@ -118,7 +115,7 @@ func EvalFunctionCall(ctx types.Context, fun ast.Identifier, args []ast.Expressi } // apply the path expression - unwrappedResult, err = pathexpr.Set(currentValue, pathexpr.FromEvaluatedPath(*pathExpr), unwrappedResult) + updatedValue, err = pathexpr.Set(currentValue, pathexpr.FromEvaluatedPath(*pathExpr), updatedValue) if err != nil { return ctx, nil, fmt.Errorf("cannot set value in %T at %s: %w", currentValue, pathExpr, err) } @@ -126,9 +123,9 @@ func EvalFunctionCall(ctx types.Context, fun ast.Identifier, args []ast.Expressi if updateSymbol.Variable != nil { varName := string(*updateSymbol.Variable) - resultCtx = resultCtx.WithVariable(varName, unwrappedResult) + resultCtx = resultCtx.WithVariable(varName, updatedValue) } else { - ctx.GetDocument().Set(unwrappedResult) + ctx.GetDocument().Set(updatedValue) } } diff --git a/pkg/eval/eval_vector.go b/pkg/eval/eval_vector.go index a16b18e..08d3a72 100644 --- a/pkg/eval/eval_vector.go +++ b/pkg/eval/eval_vector.go @@ -12,14 +12,12 @@ import ( // evaluated vectors are technically considered expressions. func EvalVector(ctx types.Context, vec ast.Vector) (types.Context, any, error) { - return ctx, vec, nil + return ctx, vec.LiteralValue(), nil } func EvalVectorNode(ctx types.Context, vec ast.VectorNode) (types.Context, any, error) { innerCtx := ctx - result := ast.Vector{ - Data: make([]any, len(vec.Expressions)), - } + result := make([]any, len(vec.Expressions)) var ( data any @@ -35,7 +33,7 @@ func EvalVectorNode(ctx types.Context, vec ast.VectorNode) (types.Context, any, return ctx, nil, fmt.Errorf("failed to eval expression %s: %w", expr.String(), err) } - result.Data[i] = data + result[i] = data } if vec.PathExpression != nil { diff --git a/pkg/eval/test/bool_test.go b/pkg/eval/test/bool_test.go index 90afba9..2d1004b 100644 --- a/pkg/eval/test/bool_test.go +++ b/pkg/eval/test/bool_test.go @@ -14,11 +14,11 @@ func TestEvalBool(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.Bool(true), - Expected: ast.Bool(true), + Expected: true, }, { AST: ast.Bool(false), - Expected: ast.Bool(false), + Expected: false, }, } diff --git a/pkg/eval/test/expression_test.go b/pkg/eval/test/expression_test.go index d26ac0a..e55c365 100644 --- a/pkg/eval/test/expression_test.go +++ b/pkg/eval/test/expression_test.go @@ -14,23 +14,23 @@ func TestEvalExpression(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.Null{}, - Expected: ast.Null{}, + Expected: nil, }, { AST: ast.Bool(true), - Expected: ast.Bool(true), + Expected: true, }, { AST: ast.String("foo"), - Expected: ast.String("foo"), + Expected: "foo", }, { AST: ast.Number{Value: 1}, - Expected: ast.Number{Value: 1}, + Expected: 1, }, { AST: ast.Object{Data: map[string]any{"foo": "bar"}}, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, }, { AST: ast.ObjectNode{ @@ -41,11 +41,11 @@ func TestEvalExpression(t *testing.T) { }, }, }, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, }, { AST: ast.Vector{Data: []any{"foo", 1}}, - Expected: ast.Vector{Data: []any{"foo", 1}}, + Expected: []any{"foo", 1}, }, { AST: ast.VectorNode{ @@ -54,7 +54,7 @@ func TestEvalExpression(t *testing.T) { ast.Number{Value: 1}, }, }, - Expected: ast.Vector{Data: []any{"foo", 1}}, + Expected: []any{"foo", 1}, }, } diff --git a/pkg/eval/test/funcs.go b/pkg/eval/test/funcs.go index 5a445ec..71bf156 100644 --- a/pkg/eval/test/funcs.go +++ b/pkg/eval/test/funcs.go @@ -31,11 +31,8 @@ var ( } _, value, err := eval.EvalExpression(ctx, args[1]) - if err != nil { - return nil, err - } - return value, nil + return value, err }, ""), } ) diff --git a/pkg/eval/test/null_test.go b/pkg/eval/test/null_test.go index 49876f0..e154673 100644 --- a/pkg/eval/test/null_test.go +++ b/pkg/eval/test/null_test.go @@ -14,7 +14,7 @@ func TestEvalNull(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.Null{}, - Expected: ast.Null{}, + Expected: nil, }, } diff --git a/pkg/eval/test/number_test.go b/pkg/eval/test/number_test.go index a321784..635a29e 100644 --- a/pkg/eval/test/number_test.go +++ b/pkg/eval/test/number_test.go @@ -14,15 +14,19 @@ func TestEvalNumber(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.Number{Value: 0}, - Expected: ast.Number{Value: 0}, + Expected: 0, }, { AST: ast.Number{Value: 1}, - Expected: ast.Number{Value: 1}, + Expected: 1, + }, + { + AST: ast.Number{Value: -1}, + Expected: -1, }, { AST: ast.Number{Value: 3.14}, - Expected: ast.Number{Value: 3.14}, + Expected: 3.14, }, } diff --git a/pkg/eval/test/object_test.go b/pkg/eval/test/object_test.go index 2d06f84..98b12fb 100644 --- a/pkg/eval/test/object_test.go +++ b/pkg/eval/test/object_test.go @@ -15,7 +15,7 @@ func TestEvalObjectNode(t *testing.T) { // {} { AST: ast.ObjectNode{}, - Expected: ast.Object{}, + Expected: map[string]any{}, }, // {foo "bar"} { @@ -27,10 +27,8 @@ func TestEvalObjectNode(t *testing.T) { }, }, }, - Expected: ast.Object{ - Data: map[string]any{ - "foo": ast.String("bar"), - }, + Expected: map[string]any{ + "foo": "bar", }, }, // {null "bar"} @@ -43,10 +41,8 @@ func TestEvalObjectNode(t *testing.T) { }, }, }, - Expected: ast.Object{ - Data: map[string]any{ - "": ast.String("bar"), - }, + Expected: map[string]any{ + "": "bar", }, }, // {(eval "evaled") (eval "also evaled")} @@ -69,10 +65,8 @@ func TestEvalObjectNode(t *testing.T) { }, }, }, - Expected: ast.Object{ - Data: map[string]any{ - "evaled": ast.String("also evaled"), - }, + Expected: map[string]any{ + "evaled": "also evaled", }, }, // {{foo "bar"} "test"} @@ -116,10 +110,8 @@ func TestEvalObjectNode(t *testing.T) { }, }, }, - Expected: ast.Object{ - Data: map[string]any{ - "bar": ast.String("test"), - }, + Expected: map[string]any{ + "bar": "test", }, }, // {foo "bar"}.foo @@ -137,7 +129,7 @@ func TestEvalObjectNode(t *testing.T) { }, }, }, - Expected: ast.String("bar"), + Expected: "bar", }, // {foo bar} { diff --git a/pkg/eval/test/program_test.go b/pkg/eval/test/program_test.go index 6eb1371..5601574 100644 --- a/pkg/eval/test/program_test.go +++ b/pkg/eval/test/program_test.go @@ -42,7 +42,7 @@ func TestEvalProgram(t *testing.T) { // (empty program) { AST: makeProgram(), - Expected: ast.Null{}, + Expected: nil, }, // single statement // "foo" @@ -50,7 +50,7 @@ func TestEvalProgram(t *testing.T) { AST: makeProgram( ast.String("foo"), ), - Expected: ast.String("foo"), + Expected: "foo", }, // program result should be the result from the last statement // "foo" "bar" @@ -59,7 +59,7 @@ func TestEvalProgram(t *testing.T) { ast.String("foo"), ast.String("bar"), ), - Expected: ast.String("bar"), + Expected: "bar", }, // context changes from one statement should affect the next // (set! $foo 1) $foo (set! $bar $foo) $bar @@ -78,7 +78,7 @@ func TestEvalProgram(t *testing.T) { ), makeVar("bar", nil), ), - Expected: ast.Number{Value: 1}, + Expected: 1, }, // context changes from inner statements should not leak // (set! $foo (set! $bar 1)) $bar diff --git a/pkg/eval/test/statement_test.go b/pkg/eval/test/statement_test.go index 2c33e2b..74d584c 100644 --- a/pkg/eval/test/statement_test.go +++ b/pkg/eval/test/statement_test.go @@ -14,27 +14,27 @@ func TestEvalStatement(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.Statement{Expression: ast.Null{}}, - Expected: ast.Null{}, + Expected: nil, }, { AST: ast.Statement{Expression: ast.Bool(true)}, - Expected: ast.Bool(true), + Expected: true, }, { AST: ast.Statement{Expression: ast.String("foo")}, - Expected: ast.String("foo"), + Expected: "foo", }, { AST: ast.Statement{Expression: ast.Number{Value: 1}}, - Expected: ast.Number{Value: 1}, + Expected: 1, }, { AST: ast.Statement{Expression: ast.Object{Data: map[string]any{"foo": "bar"}}}, - Expected: ast.Object{Data: map[string]any{"foo": "bar"}}, + Expected: map[string]any{"foo": "bar"}, }, { AST: ast.Statement{Expression: ast.Vector{Data: []any{"foo", 1}}}, - Expected: ast.Vector{Data: []any{"foo", 1}}, + Expected: []any{"foo", 1}, }, } diff --git a/pkg/eval/test/string_test.go b/pkg/eval/test/string_test.go index f00d624..74b7042 100644 --- a/pkg/eval/test/string_test.go +++ b/pkg/eval/test/string_test.go @@ -14,11 +14,11 @@ func TestEvalString(t *testing.T) { testcases := []testutil.Testcase{ { AST: ast.String(""), - Expected: ast.String(""), + Expected: "", }, { AST: ast.String("foo"), - Expected: ast.String("foo"), + Expected: "foo", }, } diff --git a/pkg/eval/test/symbol_test.go b/pkg/eval/test/symbol_test.go index f62ea7a..33b9e8e 100644 --- a/pkg/eval/test/symbol_test.go +++ b/pkg/eval/test/symbol_test.go @@ -40,35 +40,25 @@ func TestEvalSymbol(t *testing.T) { { AST: makeSymbol("var", nil), Variables: types.Variables{ - "var": ast.String("foo"), + "var": "foo", }, - Expected: ast.String("foo"), - }, - // $native - { - AST: makeSymbol("native", nil), - Variables: types.Variables{ - "native": "foo", - }, - Expected: ast.String("foo"), + Expected: "foo", }, // $var.foo { AST: makeSymbol("var", &ast.PathExpression{Steps: []ast.Expression{ast.Identifier{Name: "foo"}}}), Variables: types.Variables{ "var": map[string]any{ - "foo": ast.String("foobar"), + "foo": "foobar", }, }, - Expected: ast.String("foobar"), + Expected: "foobar", }, // $aVector.foo { AST: makeSymbol("aVector", &ast.PathExpression{Steps: []ast.Expression{ast.Identifier{Name: "foo"}}}), Variables: types.Variables{ - "var": ast.Vector{ - Data: []any{ast.String("first")}, - }, + "aVector": []any{"first"}, }, Invalid: true, }, @@ -76,27 +66,25 @@ func TestEvalSymbol(t *testing.T) { { AST: makeSymbol("var", &ast.PathExpression{Steps: []ast.Expression{ast.Number{Value: 1}}}), Variables: types.Variables{ - "var": ast.Vector{ - Data: []any{ - ast.String("first"), - ast.String("second"), - }, + "var": []any{ + "first", + "second", }, }, - Expected: ast.String("second"), + Expected: "second", }, // $aString[1] { AST: makeSymbol("aString", &ast.PathExpression{Steps: []ast.Expression{ast.Number{Value: 1}}}), Variables: types.Variables{ - "var": ast.String("bar"), + "aString": "bar", }, Invalid: true, }, // . { AST: makeSymbol("", &ast.PathExpression{}), - Expected: ast.Null{}, + Expected: nil, }, } diff --git a/pkg/eval/test/tuple_test.go b/pkg/eval/test/tuple_test.go index 5e854de..65cb371 100644 --- a/pkg/eval/test/tuple_test.go +++ b/pkg/eval/test/tuple_test.go @@ -81,7 +81,7 @@ func TestEvalTuple(t *testing.T) { ast.String("foo"), }, }, - Expected: ast.String("foo"), + Expected: "foo", }, // (eval {foo "bar"}).foo { @@ -103,7 +103,7 @@ func TestEvalTuple(t *testing.T) { }, }, }, - Expected: ast.String("bar"), + Expected: "bar", }, // (eval {foo "bar"})[1] { @@ -145,7 +145,7 @@ func TestEvalTuple(t *testing.T) { }, }, }, - Expected: ast.Number{Value: 2}, + Expected: 2, }, // (eval [1 2]).invalid { @@ -251,7 +251,7 @@ func TestEvalTupleBangModifier(t *testing.T) { ast.String("value"), }, }, - Expected: ast.String("value"), + Expected: "value", ExpectedDocument: "value", }, // (set! . "value") @@ -263,7 +263,7 @@ func TestEvalTupleBangModifier(t *testing.T) { ast.String("value"), }, }, - Expected: ast.String("value"), + Expected: "value", ExpectedDocument: "value", }, // (set! $val "value") @@ -275,7 +275,7 @@ func TestEvalTupleBangModifier(t *testing.T) { ast.String("value"), }, }, - Expected: ast.String("value"), + Expected: "value", ExpectedVariables: types.Variables{ "myvar": "value", }, @@ -294,7 +294,7 @@ func TestEvalTupleBangModifier(t *testing.T) { }, }, Document: map[string]any{"hello": "world", "hei": "verden"}, - Expected: ast.String("value"), + Expected: "value", ExpectedDocument: map[string]any{"hello": "value", "hei": "verden"}, }, // (set! $val.key "value") @@ -313,7 +313,7 @@ func TestEvalTupleBangModifier(t *testing.T) { Variables: types.Variables{ "val": map[string]any{"foo": "bar", "key": 42}, }, - Expected: ast.String("value"), + Expected: "value", ExpectedVariables: types.Variables{ "val": map[string]any{"foo": "bar", "key": "value"}, }, @@ -342,7 +342,7 @@ func TestEvalTupleBangModifier(t *testing.T) { }, }, Document: map[string]any{"hello": "world", "hei": "verden"}, - Expected: ast.String("value"), + Expected: "value", ExpectedDocument: map[string]any{"hello": "value", "hei": "value"}, }, } diff --git a/pkg/eval/test/vector_test.go b/pkg/eval/test/vector_test.go index 00aa61f..e2e0a2c 100644 --- a/pkg/eval/test/vector_test.go +++ b/pkg/eval/test/vector_test.go @@ -15,7 +15,7 @@ func TestEvalVectorNode(t *testing.T) { // [] { AST: ast.VectorNode{}, - Expected: ast.Vector{}, + Expected: []any{}, }, // [identifier] { @@ -40,12 +40,10 @@ func TestEvalVectorNode(t *testing.T) { }, }, }, - Expected: ast.Vector{ - Data: []any{ - true, - ast.String("foo"), - ast.String("evaled"), - }, + Expected: []any{ + true, + "foo", + "evaled", }, }, // [true "foo"][1] @@ -61,7 +59,7 @@ func TestEvalVectorNode(t *testing.T) { }, }, }, - Expected: ast.String("foo"), + Expected: "foo", }, // ["foo"][1] { diff --git a/pkg/eval/types/context.go b/pkg/eval/types/context.go index 92213ae..6cdaed1 100644 --- a/pkg/eval/types/context.go +++ b/pkg/eval/types/context.go @@ -15,13 +15,8 @@ type Document struct { } func NewDocument(data any) (Document, error) { - wrapped, err := WrapNative(data) - if err != nil { - return Document{}, fmt.Errorf("invalid document data: %w", err) - } - return Document{ - data: wrapped, + data: data, }, nil } diff --git a/pkg/pathexpr/delete.go b/pkg/pathexpr/delete.go index fa588da..6f0c996 100644 --- a/pkg/pathexpr/delete.go +++ b/pkg/pathexpr/delete.go @@ -6,8 +6,6 @@ package pathexpr import ( "errors" "fmt" - - "go.xrstf.de/rudi/pkg/eval/types" ) func removeSliceItem(slice []any, index int) []any { @@ -19,11 +17,6 @@ func Delete(dest any, path Path) (any, error) { return nil, nil } - target, err := types.UnwrapType(dest) - if err != nil { - return nil, fmt.Errorf("cannot descend into %T", dest) - } - thisStep := path[0] remainingSteps := path[1:] @@ -35,7 +28,7 @@ func Delete(dest any, path Path) (any, error) { return nil, fmt.Errorf("index %d out of bounds", index) } - if slice, ok := target.([]any); ok { + if slice, ok := dest.([]any); ok { if index >= len(slice) { return nil, fmt.Errorf("index %d out of bounds", index) } @@ -43,17 +36,17 @@ func Delete(dest any, path Path) (any, error) { return removeSliceItem(slice, index), nil } - return nil, fmt.Errorf("cannot delete index from %T", target) + return nil, fmt.Errorf("cannot delete index from %T", dest) } // .key if key, ok := toStringStep(thisStep); ok { - if object, ok := target.(map[string]any); ok { + if object, ok := dest.(map[string]any); ok { delete(object, key) return object, nil } - return nil, fmt.Errorf("cannot delete key from %T", target) + return nil, fmt.Errorf("cannot delete key from %T", dest) } return nil, fmt.Errorf("can only remove object keys or slice items, not %T", thisStep) @@ -65,7 +58,7 @@ func Delete(dest any, path Path) (any, error) { return nil, fmt.Errorf("index %d out of bounds", index) } - if slice, ok := target.([]any); ok { + if slice, ok := dest.([]any); ok { if index >= len(slice) { return nil, fmt.Errorf("index %d out of bounds", index) } @@ -82,12 +75,12 @@ func Delete(dest any, path Path) (any, error) { return slice, nil } - return nil, fmt.Errorf("cannot descend with [%d] into %T", index, target) + return nil, fmt.Errorf("cannot descend with [%d] into %T", index, dest) } // .key if key, ok := toStringStep(thisStep); ok { - if object, ok := target.(map[string]any); ok { + if object, ok := dest.(map[string]any); ok { // getting the empty value for non-existing keys is fine existingValue := object[key] @@ -101,7 +94,7 @@ func Delete(dest any, path Path) (any, error) { return object, nil } - return nil, fmt.Errorf("cannot descend with [%s] into %T", key, target) + return nil, fmt.Errorf("cannot descend with [%s] into %T", key, dest) } return nil, errors.New("invalid path step: neither key nor index") diff --git a/pkg/testutil/testcase.go b/pkg/testutil/testcase.go index 716298f..b10aa48 100644 --- a/pkg/testutil/testcase.go +++ b/pkg/testutil/testcase.go @@ -143,11 +143,8 @@ func assertResultValue(t *testing.T, expected any, actual any) { func assertDocument(t *testing.T, expected any, ctx types.Context) { resultDoc := ctx.GetDocument().Data() - unwrappedDoc, err := types.UnwrapType(resultDoc) - if err != nil { - t.Errorf("Failed to unwrap document: %v", err) - } else if !cmp.Equal(expected, unwrappedDoc) { - t.Errorf("Resulting document does not match expectation:\n\n%s\n", renderDiff(expected, unwrappedDoc)) + if !cmp.Equal(expected, resultDoc) { + t.Errorf("Resulting document does not match expectation:\n\n%s\n", renderDiff(expected, resultDoc)) } }