From 1e4797071ff6d969ba15dfc0c5aa37415fe6d260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Barzowski?= Date: Thu, 7 Sep 2017 15:46:22 -0400 Subject: [PATCH] Even more builtins Fix a bunch of bugs: - Reverse meaning of boolean argument to objectFieldsEx and objectHasEx - Slice desugaring using `std.slice` instead of `slice` as a field name. Support + on string and something else. Support + on arrays assertEqual should now work properly --- builtins.go | 43 ++++++++++++++----- desugarer.go | 2 +- testdata/assert_equal.golden | 1 + testdata/assert_equal.input | 1 + testdata/assert_equal2.golden | 1 + testdata/assert_equal2.input | 1 + testdata/assert_equal3.golden | 1 + testdata/assert_equal3.input | 1 + testdata/assert_equal4.golden | 1 + testdata/assert_equal4.input | 1 + testdata/builtinObjectFieldsEx.golden | 1 - .../builtinObjectFieldsExWithHidden.golden | 5 +++ .../builtinObjectFieldsExWithHidden.input | 1 + testdata/plus.golden | 1 + testdata/plus.input | 1 + testdata/plus2.golden | 1 + testdata/plus2.input | 1 + testdata/plus3.golden | 8 ++++ testdata/plus3.input | 1 + testdata/plus4.golden | 5 +++ testdata/plus4.input | 1 + testdata/plus5.golden | 1 + testdata/plus5.input | 1 + testdata/plus6.golden | 1 + testdata/plus6.input | 1 + testdata/plus7.golden | 1 + testdata/plus7.input | 1 + testdata/plus8.golden | 1 + testdata/plus8.input | 1 + testdata/plus9.golden | 1 + testdata/plus9.input | 1 + testdata/slice.golden | 4 ++ testdata/slice.input | 1 + testdata/slice2.golden | 3 ++ testdata/slice2.input | 1 + testdata/slice3.golden | 3 ++ testdata/slice3.input | 1 + testdata/slice4.golden | 5 +++ testdata/slice4.input | 1 + testdata/slice5.golden | 5 +++ testdata/slice5.input | 1 + testdata/slice6.golden | 5 +++ testdata/slice6.input | 1 + testdata/slice7.golden | 4 ++ testdata/slice7.input | 1 + testdata/std.objectFields.golden | 4 ++ testdata/std.objectFields.input | 1 + testdata/std.objectHasEx.golden | 1 + testdata/std.objectHasEx.input | 1 + testdata/std.objectHasEx2.golden | 1 + testdata/std.objectHasEx2.input | 1 + testdata/std.objectHasEx3.golden | 1 + testdata/std.objectHasEx3.input | 1 + testdata/std.objectHasEx4.golden | 1 + testdata/std.objectHasEx4.input | 1 + testdata/std.slice.golden | 4 ++ testdata/std.slice.input | 1 + testdata/std.toString.golden | 2 +- value.go | 11 +++++ 59 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 testdata/assert_equal.golden create mode 100644 testdata/assert_equal.input create mode 100644 testdata/assert_equal2.golden create mode 100644 testdata/assert_equal2.input create mode 100644 testdata/assert_equal3.golden create mode 100644 testdata/assert_equal3.input create mode 100644 testdata/assert_equal4.golden create mode 100644 testdata/assert_equal4.input create mode 100644 testdata/builtinObjectFieldsExWithHidden.golden create mode 100644 testdata/builtinObjectFieldsExWithHidden.input create mode 100644 testdata/plus.golden create mode 100644 testdata/plus.input create mode 100644 testdata/plus2.golden create mode 100644 testdata/plus2.input create mode 100644 testdata/plus3.golden create mode 100644 testdata/plus3.input create mode 100644 testdata/plus4.golden create mode 100644 testdata/plus4.input create mode 100644 testdata/plus5.golden create mode 100644 testdata/plus5.input create mode 100644 testdata/plus6.golden create mode 100644 testdata/plus6.input create mode 100644 testdata/plus7.golden create mode 100644 testdata/plus7.input create mode 100644 testdata/plus8.golden create mode 100644 testdata/plus8.input create mode 100644 testdata/plus9.golden create mode 100644 testdata/plus9.input create mode 100644 testdata/slice.golden create mode 100644 testdata/slice.input create mode 100644 testdata/slice2.golden create mode 100644 testdata/slice2.input create mode 100644 testdata/slice3.golden create mode 100644 testdata/slice3.input create mode 100644 testdata/slice4.golden create mode 100644 testdata/slice4.input create mode 100644 testdata/slice5.golden create mode 100644 testdata/slice5.input create mode 100644 testdata/slice6.golden create mode 100644 testdata/slice6.input create mode 100644 testdata/slice7.golden create mode 100644 testdata/slice7.input create mode 100644 testdata/std.objectFields.golden create mode 100644 testdata/std.objectFields.input create mode 100644 testdata/std.objectHasEx.golden create mode 100644 testdata/std.objectHasEx.input create mode 100644 testdata/std.objectHasEx2.golden create mode 100644 testdata/std.objectHasEx2.input create mode 100644 testdata/std.objectHasEx3.golden create mode 100644 testdata/std.objectHasEx3.input create mode 100644 testdata/std.objectHasEx4.golden create mode 100644 testdata/std.objectHasEx4.input create mode 100644 testdata/std.slice.golden create mode 100644 testdata/std.slice.input diff --git a/builtins.go b/builtins.go index 7e4521e..be30d6e 100644 --- a/builtins.go +++ b/builtins.go @@ -38,25 +38,44 @@ func builtinPlus(e *evaluator, xp, yp potentialValue) (value, error) { if err != nil { return nil, err } + y, err := e.evaluate(yp) + if err != nil { + return nil, err + } + switch right := y.(type) { + case *valueString: + left, err := builtinToString(e, xp) + if err != nil { + return nil, err + } + return concatStrings(left.(*valueString), right), nil + + } switch left := x.(type) { case *valueNumber: - right, err := e.evaluateNumber(yp) + right, err := e.getNumber(y) if err != nil { return nil, err } return makeValueNumber(left.value + right.value), nil case *valueString: - right, err := e.evaluateString(yp) + right, err := builtinToString(e, yp) if err != nil { return nil, err } - return concatStrings(left, right), nil + return concatStrings(left, right.(*valueString)), nil case valueObject: - right, err := e.evaluateObject(yp) + right, err := e.getObject(y) if err != nil { return nil, err } return makeValueExtendedObject(left, right), nil + case *valueArray: + right, err := e.getArray(y) + if err != nil { + return nil, err + } + return concatArrays(left, right), nil default: return nil, e.typeErrorGeneral(x) } @@ -215,6 +234,10 @@ func builtinToString(e *evaluator, xp potentialValue) (value, error) { if err != nil { return nil, err } + switch x := x.(type) { + case *valueString: + return x, nil + } var buf bytes.Buffer err = e.i.manifestJSON(e.trace, x, false, "", &buf) if err != nil { @@ -405,16 +428,16 @@ var builtinBitwiseAnd = liftBitwise(func(x, y int64) int64 { return x & y }) var builtinBitwiseOr = liftBitwise(func(x, y int64) int64 { return x | y }) var builtinBitwiseXor = liftBitwise(func(x, y int64) int64 { return x ^ y }) -func builtinObjectFieldsEx(e *evaluator, objp potentialValue, hiddenp potentialValue) (value, error) { +func builtinObjectFieldsEx(e *evaluator, objp potentialValue, includeHiddenP potentialValue) (value, error) { obj, err := e.evaluateObject(objp) if err != nil { return nil, err } - hidden, err := e.evaluateBoolean(hiddenp) + includeHidden, err := e.evaluateBoolean(includeHiddenP) if err != nil { return nil, err } - fields := objectFields(obj, hidden.value) + fields := objectFields(obj, !includeHidden.value) sort.Strings(fields) elems := []potentialValue{} for _, fieldname := range fields { @@ -423,7 +446,7 @@ func builtinObjectFieldsEx(e *evaluator, objp potentialValue, hiddenp potentialV return makeValueArray(elems), nil } -func builtinObjectHasEx(e *evaluator, objp potentialValue, fnamep potentialValue, hiddenp potentialValue) (value, error) { +func builtinObjectHasEx(e *evaluator, objp potentialValue, fnamep potentialValue, includeHiddenP potentialValue) (value, error) { obj, err := e.evaluateObject(objp) if err != nil { return nil, err @@ -432,11 +455,11 @@ func builtinObjectHasEx(e *evaluator, objp potentialValue, fnamep potentialValue if err != nil { return nil, err } - hidden, err := e.evaluateBoolean(hiddenp) + includeHidden, err := e.evaluateBoolean(includeHiddenP) if err != nil { return nil, err } - for _, fieldname := range objectFields(obj, hidden.value) { + for _, fieldname := range objectFields(obj, !includeHidden.value) { if fieldname == string(fname.value) { return makeValueBoolean(true), nil } diff --git a/desugarer.go b/desugarer.go index 7d35e57..1d91f71 100644 --- a/desugarer.go +++ b/desugarer.go @@ -427,7 +427,7 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) { if node.Step == nil { node.Step = &ast.LiteralNull{} } - *astPtr = buildStdCall("std.slice", node.Target, node.BeginIndex, node.EndIndex, node.Step) + *astPtr = buildStdCall("slice", node.Target, node.BeginIndex, node.EndIndex, node.Step) desugar(astPtr, objLevel) case *ast.Local: diff --git a/testdata/assert_equal.golden b/testdata/assert_equal.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/assert_equal.golden @@ -0,0 +1 @@ +true diff --git a/testdata/assert_equal.input b/testdata/assert_equal.input new file mode 100644 index 0000000..07576bc --- /dev/null +++ b/testdata/assert_equal.input @@ -0,0 +1 @@ +std.assertEqual([], []) diff --git a/testdata/assert_equal2.golden b/testdata/assert_equal2.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/assert_equal2.golden @@ -0,0 +1 @@ +true diff --git a/testdata/assert_equal2.input b/testdata/assert_equal2.input new file mode 100644 index 0000000..78e26f9 --- /dev/null +++ b/testdata/assert_equal2.input @@ -0,0 +1 @@ +std.assertEqual({}, {}) diff --git a/testdata/assert_equal3.golden b/testdata/assert_equal3.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/assert_equal3.golden @@ -0,0 +1 @@ +true diff --git a/testdata/assert_equal3.input b/testdata/assert_equal3.input new file mode 100644 index 0000000..cfbc6f0 --- /dev/null +++ b/testdata/assert_equal3.input @@ -0,0 +1 @@ +std.assertEqual({x:: 42}, {}) diff --git a/testdata/assert_equal4.golden b/testdata/assert_equal4.golden new file mode 100644 index 0000000..58b72ac --- /dev/null +++ b/testdata/assert_equal4.golden @@ -0,0 +1 @@ +RUNTIME ERROR: Assertion failed. {"x": 1} != {"x": 2} diff --git a/testdata/assert_equal4.input b/testdata/assert_equal4.input new file mode 100644 index 0000000..789e156 --- /dev/null +++ b/testdata/assert_equal4.input @@ -0,0 +1 @@ +std.assertEqual({x: 1}, {x: 2}) diff --git a/testdata/builtinObjectFieldsEx.golden b/testdata/builtinObjectFieldsEx.golden index 7ca3561..5ed05ba 100644 --- a/testdata/builtinObjectFieldsEx.golden +++ b/testdata/builtinObjectFieldsEx.golden @@ -1,5 +1,4 @@ [ "x", - "y", "z" ] diff --git a/testdata/builtinObjectFieldsExWithHidden.golden b/testdata/builtinObjectFieldsExWithHidden.golden new file mode 100644 index 0000000..7ca3561 --- /dev/null +++ b/testdata/builtinObjectFieldsExWithHidden.golden @@ -0,0 +1,5 @@ +[ + "x", + "y", + "z" +] diff --git a/testdata/builtinObjectFieldsExWithHidden.input b/testdata/builtinObjectFieldsExWithHidden.input new file mode 100644 index 0000000..150ae31 --- /dev/null +++ b/testdata/builtinObjectFieldsExWithHidden.input @@ -0,0 +1 @@ +std.objectFieldsEx({x: 1, y:: 1, z::: 2}, true) diff --git a/testdata/plus.golden b/testdata/plus.golden new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/testdata/plus.golden @@ -0,0 +1 @@ +3 diff --git a/testdata/plus.input b/testdata/plus.input new file mode 100644 index 0000000..e0ef584 --- /dev/null +++ b/testdata/plus.input @@ -0,0 +1 @@ +1 + 2 diff --git a/testdata/plus2.golden b/testdata/plus2.golden new file mode 100644 index 0000000..cb5537d --- /dev/null +++ b/testdata/plus2.golden @@ -0,0 +1 @@ +"ab" diff --git a/testdata/plus2.input b/testdata/plus2.input new file mode 100644 index 0000000..2a0e65a --- /dev/null +++ b/testdata/plus2.input @@ -0,0 +1 @@ +"a" + "b" diff --git a/testdata/plus3.golden b/testdata/plus3.golden new file mode 100644 index 0000000..60ac81f --- /dev/null +++ b/testdata/plus3.golden @@ -0,0 +1,8 @@ +[ + 1, + 2, + 3, + 4, + 5, + 6 +] diff --git a/testdata/plus3.input b/testdata/plus3.input new file mode 100644 index 0000000..a7dfcb8 --- /dev/null +++ b/testdata/plus3.input @@ -0,0 +1 @@ +[1, 2, 3] + [4, 5, 6] diff --git a/testdata/plus4.golden b/testdata/plus4.golden new file mode 100644 index 0000000..1f3f798 --- /dev/null +++ b/testdata/plus4.golden @@ -0,0 +1,5 @@ +{ + "a": 3, + "b": 2, + "c": 4 +} diff --git a/testdata/plus4.input b/testdata/plus4.input new file mode 100644 index 0000000..1ec7515 --- /dev/null +++ b/testdata/plus4.input @@ -0,0 +1 @@ +{"a": 1, "b": 2} + {"a": 3, "c": 4} diff --git a/testdata/plus5.golden b/testdata/plus5.golden new file mode 100644 index 0000000..392356b --- /dev/null +++ b/testdata/plus5.golden @@ -0,0 +1 @@ +RUNTIME ERROR: Unexpected type function, expected number diff --git a/testdata/plus5.input b/testdata/plus5.input new file mode 100644 index 0000000..28ba667 --- /dev/null +++ b/testdata/plus5.input @@ -0,0 +1 @@ +42 + function() 42 diff --git a/testdata/plus6.golden b/testdata/plus6.golden new file mode 100644 index 0000000..6eb548c --- /dev/null +++ b/testdata/plus6.golden @@ -0,0 +1 @@ +"a42" diff --git a/testdata/plus6.input b/testdata/plus6.input new file mode 100644 index 0000000..75e7703 --- /dev/null +++ b/testdata/plus6.input @@ -0,0 +1 @@ +"a" + 42 diff --git a/testdata/plus7.golden b/testdata/plus7.golden new file mode 100644 index 0000000..ffe90b7 --- /dev/null +++ b/testdata/plus7.golden @@ -0,0 +1 @@ +"42a" diff --git a/testdata/plus7.input b/testdata/plus7.input new file mode 100644 index 0000000..5a19603 --- /dev/null +++ b/testdata/plus7.input @@ -0,0 +1 @@ +42 + "a" diff --git a/testdata/plus8.golden b/testdata/plus8.golden new file mode 100644 index 0000000..981f487 --- /dev/null +++ b/testdata/plus8.golden @@ -0,0 +1 @@ +"{\"x\": 42}a" diff --git a/testdata/plus8.input b/testdata/plus8.input new file mode 100644 index 0000000..3bcd58c --- /dev/null +++ b/testdata/plus8.input @@ -0,0 +1 @@ +{"x": 42} + "a" diff --git a/testdata/plus9.golden b/testdata/plus9.golden new file mode 100644 index 0000000..1c23e23 --- /dev/null +++ b/testdata/plus9.golden @@ -0,0 +1 @@ +"a[1, 2, 3]" diff --git a/testdata/plus9.input b/testdata/plus9.input new file mode 100644 index 0000000..bd4a404 --- /dev/null +++ b/testdata/plus9.input @@ -0,0 +1 @@ +"a" + [1, 2, 3] diff --git a/testdata/slice.golden b/testdata/slice.golden new file mode 100644 index 0000000..0970d4d --- /dev/null +++ b/testdata/slice.golden @@ -0,0 +1,4 @@ +[ + 2, + 4 +] diff --git a/testdata/slice.input b/testdata/slice.input new file mode 100644 index 0000000..7c44713 --- /dev/null +++ b/testdata/slice.input @@ -0,0 +1 @@ +[1,2,3,4][1:4:2] diff --git a/testdata/slice2.golden b/testdata/slice2.golden new file mode 100644 index 0000000..b18b6c3 --- /dev/null +++ b/testdata/slice2.golden @@ -0,0 +1,3 @@ +[ + 2 +] diff --git a/testdata/slice2.input b/testdata/slice2.input new file mode 100644 index 0000000..5abb264 --- /dev/null +++ b/testdata/slice2.input @@ -0,0 +1 @@ +[1,2,3,4][1:3:2] diff --git a/testdata/slice3.golden b/testdata/slice3.golden new file mode 100644 index 0000000..b18b6c3 --- /dev/null +++ b/testdata/slice3.golden @@ -0,0 +1,3 @@ +[ + 2 +] diff --git a/testdata/slice3.input b/testdata/slice3.input new file mode 100644 index 0000000..8d99bd7 --- /dev/null +++ b/testdata/slice3.input @@ -0,0 +1 @@ +[1,2,3,4][1:2] diff --git a/testdata/slice4.golden b/testdata/slice4.golden new file mode 100644 index 0000000..a238abc --- /dev/null +++ b/testdata/slice4.golden @@ -0,0 +1,5 @@ +[ + 1, + 2, + 3 +] diff --git a/testdata/slice4.input b/testdata/slice4.input new file mode 100644 index 0000000..58d8447 --- /dev/null +++ b/testdata/slice4.input @@ -0,0 +1 @@ +[1,2,3,4][:3:] diff --git a/testdata/slice5.golden b/testdata/slice5.golden new file mode 100644 index 0000000..2d3b8ef --- /dev/null +++ b/testdata/slice5.golden @@ -0,0 +1,5 @@ +[ + 2, + 3, + 4 +] diff --git a/testdata/slice5.input b/testdata/slice5.input new file mode 100644 index 0000000..d68588e --- /dev/null +++ b/testdata/slice5.input @@ -0,0 +1 @@ +[1,2,3,4][1:] diff --git a/testdata/slice6.golden b/testdata/slice6.golden new file mode 100644 index 0000000..2d3b8ef --- /dev/null +++ b/testdata/slice6.golden @@ -0,0 +1,5 @@ +[ + 2, + 3, + 4 +] diff --git a/testdata/slice6.input b/testdata/slice6.input new file mode 100644 index 0000000..91f4c53 --- /dev/null +++ b/testdata/slice6.input @@ -0,0 +1 @@ +[1,2,3,4][1::] diff --git a/testdata/slice7.golden b/testdata/slice7.golden new file mode 100644 index 0000000..7ccaaf6 --- /dev/null +++ b/testdata/slice7.golden @@ -0,0 +1,4 @@ +[ + 1, + 3 +] diff --git a/testdata/slice7.input b/testdata/slice7.input new file mode 100644 index 0000000..287b4ee --- /dev/null +++ b/testdata/slice7.input @@ -0,0 +1 @@ +[1,2,3,4][::2] diff --git a/testdata/std.objectFields.golden b/testdata/std.objectFields.golden new file mode 100644 index 0000000..5ed05ba --- /dev/null +++ b/testdata/std.objectFields.golden @@ -0,0 +1,4 @@ +[ + "x", + "z" +] diff --git a/testdata/std.objectFields.input b/testdata/std.objectFields.input new file mode 100644 index 0000000..47858aa --- /dev/null +++ b/testdata/std.objectFields.input @@ -0,0 +1 @@ +std.objectFields({x: 1, y:: 2, z::: 3}) diff --git a/testdata/std.objectHasEx.golden b/testdata/std.objectHasEx.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/std.objectHasEx.golden @@ -0,0 +1 @@ +true diff --git a/testdata/std.objectHasEx.input b/testdata/std.objectHasEx.input new file mode 100644 index 0000000..2667c52 --- /dev/null +++ b/testdata/std.objectHasEx.input @@ -0,0 +1 @@ +std.objectHasEx({"x": null}, "x", false) diff --git a/testdata/std.objectHasEx2.golden b/testdata/std.objectHasEx2.golden new file mode 100644 index 0000000..c508d53 --- /dev/null +++ b/testdata/std.objectHasEx2.golden @@ -0,0 +1 @@ +false diff --git a/testdata/std.objectHasEx2.input b/testdata/std.objectHasEx2.input new file mode 100644 index 0000000..5a03f66 --- /dev/null +++ b/testdata/std.objectHasEx2.input @@ -0,0 +1 @@ +std.objectHasEx({"x":: null}, "x", false) diff --git a/testdata/std.objectHasEx3.golden b/testdata/std.objectHasEx3.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/std.objectHasEx3.golden @@ -0,0 +1 @@ +true diff --git a/testdata/std.objectHasEx3.input b/testdata/std.objectHasEx3.input new file mode 100644 index 0000000..cd51339 --- /dev/null +++ b/testdata/std.objectHasEx3.input @@ -0,0 +1 @@ +std.objectHasEx({"x": null}, "x", true) diff --git a/testdata/std.objectHasEx4.golden b/testdata/std.objectHasEx4.golden new file mode 100644 index 0000000..27ba77d --- /dev/null +++ b/testdata/std.objectHasEx4.golden @@ -0,0 +1 @@ +true diff --git a/testdata/std.objectHasEx4.input b/testdata/std.objectHasEx4.input new file mode 100644 index 0000000..7ce8306 --- /dev/null +++ b/testdata/std.objectHasEx4.input @@ -0,0 +1 @@ +std.objectHasEx({"x":: null}, "x", true) diff --git a/testdata/std.slice.golden b/testdata/std.slice.golden new file mode 100644 index 0000000..0970d4d --- /dev/null +++ b/testdata/std.slice.golden @@ -0,0 +1,4 @@ +[ + 2, + 4 +] diff --git a/testdata/std.slice.input b/testdata/std.slice.input new file mode 100644 index 0000000..126a78a --- /dev/null +++ b/testdata/std.slice.input @@ -0,0 +1 @@ +std.slice([1,2,3,4], 1, 4, 2) diff --git a/testdata/std.toString.golden b/testdata/std.toString.golden index 9458e0f..93a8e1f 100644 --- a/testdata/std.toString.golden +++ b/testdata/std.toString.golden @@ -1 +1 @@ -"\"xxx\"" +"xxx" diff --git a/value.go b/value.go index 59eb31f..fa2d5fd 100644 --- a/value.go +++ b/value.go @@ -206,6 +206,17 @@ func makeValueArray(elements []potentialValue) *valueArray { } } +func concatArrays(a, b *valueArray) *valueArray { + result := make([]potentialValue, 0, len(a.elements)+len(b.elements)) + for _, r := range a.elements { + result = append(result, r) + } + for _, r := range b.elements { + result = append(result, r) + } + return &valueArray{elements: result} +} + func (*valueArray) typename() string { return "array" }