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
This commit is contained in:
Stanisław Barzowski 2017-09-07 15:46:22 -04:00 committed by Dave Cunningham
parent 6b040a9afe
commit 1e4797071f
59 changed files with 143 additions and 13 deletions

View File

@ -38,25 +38,44 @@ func builtinPlus(e *evaluator, xp, yp potentialValue) (value, error) {
if err != nil { if err != nil {
return nil, err 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) { switch left := x.(type) {
case *valueNumber: case *valueNumber:
right, err := e.evaluateNumber(yp) right, err := e.getNumber(y)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return makeValueNumber(left.value + right.value), nil return makeValueNumber(left.value + right.value), nil
case *valueString: case *valueString:
right, err := e.evaluateString(yp) right, err := builtinToString(e, yp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return concatStrings(left, right), nil return concatStrings(left, right.(*valueString)), nil
case valueObject: case valueObject:
right, err := e.evaluateObject(yp) right, err := e.getObject(y)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return makeValueExtendedObject(left, right), nil return makeValueExtendedObject(left, right), nil
case *valueArray:
right, err := e.getArray(y)
if err != nil {
return nil, err
}
return concatArrays(left, right), nil
default: default:
return nil, e.typeErrorGeneral(x) return nil, e.typeErrorGeneral(x)
} }
@ -215,6 +234,10 @@ func builtinToString(e *evaluator, xp potentialValue) (value, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch x := x.(type) {
case *valueString:
return x, nil
}
var buf bytes.Buffer var buf bytes.Buffer
err = e.i.manifestJSON(e.trace, x, false, "", &buf) err = e.i.manifestJSON(e.trace, x, false, "", &buf)
if err != nil { 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 builtinBitwiseOr = liftBitwise(func(x, y int64) int64 { return x | y })
var builtinBitwiseXor = 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) obj, err := e.evaluateObject(objp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hidden, err := e.evaluateBoolean(hiddenp) includeHidden, err := e.evaluateBoolean(includeHiddenP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fields := objectFields(obj, hidden.value) fields := objectFields(obj, !includeHidden.value)
sort.Strings(fields) sort.Strings(fields)
elems := []potentialValue{} elems := []potentialValue{}
for _, fieldname := range fields { for _, fieldname := range fields {
@ -423,7 +446,7 @@ func builtinObjectFieldsEx(e *evaluator, objp potentialValue, hiddenp potentialV
return makeValueArray(elems), nil 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) obj, err := e.evaluateObject(objp)
if err != nil { if err != nil {
return nil, err return nil, err
@ -432,11 +455,11 @@ func builtinObjectHasEx(e *evaluator, objp potentialValue, fnamep potentialValue
if err != nil { if err != nil {
return nil, err return nil, err
} }
hidden, err := e.evaluateBoolean(hiddenp) includeHidden, err := e.evaluateBoolean(includeHiddenP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, fieldname := range objectFields(obj, hidden.value) { for _, fieldname := range objectFields(obj, !includeHidden.value) {
if fieldname == string(fname.value) { if fieldname == string(fname.value) {
return makeValueBoolean(true), nil return makeValueBoolean(true), nil
} }

View File

@ -427,7 +427,7 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) {
if node.Step == nil { if node.Step == nil {
node.Step = &ast.LiteralNull{} 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) desugar(astPtr, objLevel)
case *ast.Local: case *ast.Local:

1
testdata/assert_equal.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/assert_equal.input vendored Normal file
View File

@ -0,0 +1 @@
std.assertEqual([], [])

1
testdata/assert_equal2.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/assert_equal2.input vendored Normal file
View File

@ -0,0 +1 @@
std.assertEqual({}, {})

1
testdata/assert_equal3.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/assert_equal3.input vendored Normal file
View File

@ -0,0 +1 @@
std.assertEqual({x:: 42}, {})

1
testdata/assert_equal4.golden vendored Normal file
View File

@ -0,0 +1 @@
RUNTIME ERROR: Assertion failed. {"x": 1} != {"x": 2}

1
testdata/assert_equal4.input vendored Normal file
View File

@ -0,0 +1 @@
std.assertEqual({x: 1}, {x: 2})

View File

@ -1,5 +1,4 @@
[ [
"x", "x",
"y",
"z" "z"
] ]

View File

@ -0,0 +1,5 @@
[
"x",
"y",
"z"
]

View File

@ -0,0 +1 @@
std.objectFieldsEx({x: 1, y:: 1, z::: 2}, true)

1
testdata/plus.golden vendored Normal file
View File

@ -0,0 +1 @@
3

1
testdata/plus.input vendored Normal file
View File

@ -0,0 +1 @@
1 + 2

1
testdata/plus2.golden vendored Normal file
View File

@ -0,0 +1 @@
"ab"

1
testdata/plus2.input vendored Normal file
View File

@ -0,0 +1 @@
"a" + "b"

8
testdata/plus3.golden vendored Normal file
View File

@ -0,0 +1,8 @@
[
1,
2,
3,
4,
5,
6
]

1
testdata/plus3.input vendored Normal file
View File

@ -0,0 +1 @@
[1, 2, 3] + [4, 5, 6]

5
testdata/plus4.golden vendored Normal file
View File

@ -0,0 +1,5 @@
{
"a": 3,
"b": 2,
"c": 4
}

1
testdata/plus4.input vendored Normal file
View File

@ -0,0 +1 @@
{"a": 1, "b": 2} + {"a": 3, "c": 4}

1
testdata/plus5.golden vendored Normal file
View File

@ -0,0 +1 @@
RUNTIME ERROR: Unexpected type function, expected number

1
testdata/plus5.input vendored Normal file
View File

@ -0,0 +1 @@
42 + function() 42

1
testdata/plus6.golden vendored Normal file
View File

@ -0,0 +1 @@
"a42"

1
testdata/plus6.input vendored Normal file
View File

@ -0,0 +1 @@
"a" + 42

1
testdata/plus7.golden vendored Normal file
View File

@ -0,0 +1 @@
"42a"

1
testdata/plus7.input vendored Normal file
View File

@ -0,0 +1 @@
42 + "a"

1
testdata/plus8.golden vendored Normal file
View File

@ -0,0 +1 @@
"{\"x\": 42}a"

1
testdata/plus8.input vendored Normal file
View File

@ -0,0 +1 @@
{"x": 42} + "a"

1
testdata/plus9.golden vendored Normal file
View File

@ -0,0 +1 @@
"a[1, 2, 3]"

1
testdata/plus9.input vendored Normal file
View File

@ -0,0 +1 @@
"a" + [1, 2, 3]

4
testdata/slice.golden vendored Normal file
View File

@ -0,0 +1,4 @@
[
2,
4
]

1
testdata/slice.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][1:4:2]

3
testdata/slice2.golden vendored Normal file
View File

@ -0,0 +1,3 @@
[
2
]

1
testdata/slice2.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][1:3:2]

3
testdata/slice3.golden vendored Normal file
View File

@ -0,0 +1,3 @@
[
2
]

1
testdata/slice3.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][1:2]

5
testdata/slice4.golden vendored Normal file
View File

@ -0,0 +1,5 @@
[
1,
2,
3
]

1
testdata/slice4.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][:3:]

5
testdata/slice5.golden vendored Normal file
View File

@ -0,0 +1,5 @@
[
2,
3,
4
]

1
testdata/slice5.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][1:]

5
testdata/slice6.golden vendored Normal file
View File

@ -0,0 +1,5 @@
[
2,
3,
4
]

1
testdata/slice6.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][1::]

4
testdata/slice7.golden vendored Normal file
View File

@ -0,0 +1,4 @@
[
1,
3
]

1
testdata/slice7.input vendored Normal file
View File

@ -0,0 +1 @@
[1,2,3,4][::2]

4
testdata/std.objectFields.golden vendored Normal file
View File

@ -0,0 +1,4 @@
[
"x",
"z"
]

1
testdata/std.objectFields.input vendored Normal file
View File

@ -0,0 +1 @@
std.objectFields({x: 1, y:: 2, z::: 3})

1
testdata/std.objectHasEx.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/std.objectHasEx.input vendored Normal file
View File

@ -0,0 +1 @@
std.objectHasEx({"x": null}, "x", false)

1
testdata/std.objectHasEx2.golden vendored Normal file
View File

@ -0,0 +1 @@
false

1
testdata/std.objectHasEx2.input vendored Normal file
View File

@ -0,0 +1 @@
std.objectHasEx({"x":: null}, "x", false)

1
testdata/std.objectHasEx3.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/std.objectHasEx3.input vendored Normal file
View File

@ -0,0 +1 @@
std.objectHasEx({"x": null}, "x", true)

1
testdata/std.objectHasEx4.golden vendored Normal file
View File

@ -0,0 +1 @@
true

1
testdata/std.objectHasEx4.input vendored Normal file
View File

@ -0,0 +1 @@
std.objectHasEx({"x":: null}, "x", true)

4
testdata/std.slice.golden vendored Normal file
View File

@ -0,0 +1,4 @@
[
2,
4
]

1
testdata/std.slice.input vendored Normal file
View File

@ -0,0 +1 @@
std.slice([1,2,3,4], 1, 4, 2)

View File

@ -1 +1 @@
"\"xxx\"" "xxx"

View File

@ -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 { func (*valueArray) typename() string {
return "array" return "array"
} }