mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-29 01:11:02 +02:00
Object comprehensions
This commit is contained in:
parent
850575cf34
commit
78b4794523
12
ast/ast.go
12
ast/ast.go
@ -482,18 +482,6 @@ type ObjectComp struct {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// ObjectComprehensionSimple represents post-desugaring object
|
|
||||||
// comprehension { [e]: e for x in e }.
|
|
||||||
type ObjectComprehensionSimple struct {
|
|
||||||
NodeBase
|
|
||||||
Field Node
|
|
||||||
Value Node
|
|
||||||
Id Identifier
|
|
||||||
Array Node
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Self represents the self keyword.
|
// Self represents the self keyword.
|
||||||
type Self struct{ NodeBase }
|
type Self struct{ NodeBase }
|
||||||
|
|
||||||
|
39
builtins.go
39
builtins.go
@ -553,6 +553,42 @@ func builtinPow(e *evaluator, basep potentialValue, expp potentialValue) (value,
|
|||||||
return makeDoubleCheck(e, math.Pow(base.value, exp.value))
|
return makeDoubleCheck(e, math.Pow(base.value, exp.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func builtinUglyObjectFlatMerge(e *evaluator, objarrp potentialValue) (value, error) {
|
||||||
|
objarr, err := e.evaluateArray(objarrp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(objarr.elements) == 0 {
|
||||||
|
return &valueSimpleObject{}, nil
|
||||||
|
}
|
||||||
|
newFields := make(valueSimpleObjectFieldMap)
|
||||||
|
for _, elem := range objarr.elements {
|
||||||
|
obj, err := e.evaluateObject(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// starts getting ugly - we mess with object internals
|
||||||
|
simpleObj := obj.(*valueSimpleObject)
|
||||||
|
for fieldName, fieldVal := range simpleObj.fields {
|
||||||
|
if _, alreadyExists := newFields[fieldName]; alreadyExists {
|
||||||
|
return nil, e.Error(duplicateFieldNameErrMsg(fieldName))
|
||||||
|
}
|
||||||
|
newFields[fieldName] = valueSimpleObjectField{
|
||||||
|
hide: fieldVal.hide,
|
||||||
|
field: &bindingsUnboundField{
|
||||||
|
inner: fieldVal.field,
|
||||||
|
bindings: simpleObj.upValues,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return makeValueSimpleObject(
|
||||||
|
nil, // no binding frame
|
||||||
|
newFields,
|
||||||
|
[]unboundField{}, // No asserts allowed
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
type unaryBuiltin func(*evaluator, potentialValue) (value, error)
|
type unaryBuiltin func(*evaluator, potentialValue) (value, error)
|
||||||
type binaryBuiltin func(*evaluator, potentialValue, potentialValue) (value, error)
|
type binaryBuiltin func(*evaluator, potentialValue, potentialValue) (value, error)
|
||||||
type ternaryBuiltin func(*evaluator, potentialValue, potentialValue, potentialValue) (value, error)
|
type ternaryBuiltin func(*evaluator, potentialValue, potentialValue, potentialValue) (value, error)
|
||||||
@ -686,4 +722,7 @@ var funcBuiltins = map[string]evalCallable{
|
|||||||
"pow": &BinaryBuiltin{name: "pow", function: builtinPow, parameters: ast.Identifiers{"base", "exp"}},
|
"pow": &BinaryBuiltin{name: "pow", function: builtinPow, parameters: ast.Identifiers{"base", "exp"}},
|
||||||
"modulo": &BinaryBuiltin{name: "modulo", function: builtinModulo, parameters: ast.Identifiers{"x", "y"}},
|
"modulo": &BinaryBuiltin{name: "modulo", function: builtinModulo, parameters: ast.Identifiers{"x", "y"}},
|
||||||
"md5": &UnaryBuiltin{name: "md5", function: builtinMd5, parameters: ast.Identifiers{"x"}},
|
"md5": &UnaryBuiltin{name: "md5", function: builtinMd5, parameters: ast.Identifiers{"x"}},
|
||||||
|
|
||||||
|
// internal
|
||||||
|
"$objectFlatMerge": &UnaryBuiltin{name: "$objectFlatMerge", function: builtinUglyObjectFlatMerge, parameters: ast.Identifiers{"x"}},
|
||||||
}
|
}
|
||||||
|
69
desugarer.go
69
desugarer.go
@ -249,9 +249,31 @@ func desugarArrayComp(comp *ast.ArrayComp, objLevel int) (ast.Node, error) {
|
|||||||
return desugarForSpec(wrapInArray(comp.Body), &comp.Spec)
|
return desugarForSpec(wrapInArray(comp.Body), &comp.Spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func desugarObjectComp(astComp *ast.ObjectComp, objLevel int) (ast.Node, error) {
|
func desugarObjectComp(comp *ast.ObjectComp, objLevel int) (ast.Node, error) {
|
||||||
return &ast.LiteralNull{}, nil
|
|
||||||
// TODO(sbarzowski) this
|
// TODO(sbarzowski) find a consistent convention to prevent desugaring the same thing twice
|
||||||
|
// here we deeply desugar fields and it will happen again
|
||||||
|
err := desugarFields(*comp.Loc(), &comp.Fields, objLevel+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(comp.Fields) != 1 {
|
||||||
|
panic("Too many fields in object comprehension, it should have been caught during parsing")
|
||||||
|
}
|
||||||
|
|
||||||
|
arrComp := ast.ArrayComp{
|
||||||
|
Body: buildDesugaredObject(comp.NodeBase, comp.Fields),
|
||||||
|
Spec: comp.Spec,
|
||||||
|
}
|
||||||
|
|
||||||
|
desugaredArrayComp, err := desugarArrayComp(&arrComp, objLevel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
desugaredComp := buildStdCall("$objectFlatMerge", desugaredArrayComp)
|
||||||
|
return desugaredComp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildLiteralString(value string) ast.Node {
|
func buildLiteralString(value string) ast.Node {
|
||||||
@ -277,6 +299,23 @@ func buildStdCall(builtinName ast.Identifier, args ...ast.Node) ast.Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildDesugaredObject(nodeBase ast.NodeBase, fields ast.ObjectFields) *ast.DesugaredObject {
|
||||||
|
var newFields ast.DesugaredObjectFields
|
||||||
|
var newAsserts ast.Nodes
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
if field.Kind == ast.ObjectAssert {
|
||||||
|
newAsserts = append(newAsserts, field.Expr2)
|
||||||
|
} else if field.Kind == ast.ObjectFieldExpr {
|
||||||
|
newFields = append(newFields, ast.DesugaredObjectField{field.Hide, field.Expr1, field.Expr2})
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("INTERNAL ERROR: field should have been desugared: %s", field.Kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ast.DesugaredObject{nodeBase, newAsserts, newFields}
|
||||||
|
}
|
||||||
|
|
||||||
// Desugar Jsonnet expressions to reduce the number of constructs the rest of the implementation
|
// Desugar Jsonnet expressions to reduce the number of constructs the rest of the implementation
|
||||||
// needs to understand.
|
// needs to understand.
|
||||||
|
|
||||||
@ -506,34 +545,22 @@ func desugar(astPtr *ast.Node, objLevel int) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var newFields ast.DesugaredObjectFields
|
*astPtr = buildDesugaredObject(node.NodeBase, node.Fields)
|
||||||
var newAsserts ast.Nodes
|
|
||||||
|
|
||||||
for _, field := range node.Fields {
|
|
||||||
if field.Kind == ast.ObjectAssert {
|
|
||||||
newAsserts = append(newAsserts, field.Expr2)
|
|
||||||
} else if field.Kind == ast.ObjectFieldExpr {
|
|
||||||
newFields = append(newFields, ast.DesugaredObjectField{field.Hide, field.Expr1, field.Expr2})
|
|
||||||
} else {
|
|
||||||
panic(fmt.Sprintf("INTERNAL ERROR: field should have been desugared: %s", field.Kind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*astPtr = &ast.DesugaredObject{node.NodeBase, newAsserts, newFields}
|
|
||||||
|
|
||||||
case *ast.DesugaredObject:
|
case *ast.DesugaredObject:
|
||||||
panic("Desugaring desugared object")
|
return nil
|
||||||
|
|
||||||
case *ast.ObjectComp:
|
case *ast.ObjectComp:
|
||||||
comp, err := desugarObjectComp(node, objLevel)
|
comp, err := desugarObjectComp(node, objLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = desugar(&comp, objLevel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
*astPtr = comp
|
*astPtr = comp
|
||||||
|
|
||||||
case *ast.ObjectComprehensionSimple:
|
|
||||||
panic("Desugaring desugared object comprehension")
|
|
||||||
|
|
||||||
case *ast.Self:
|
case *ast.Self:
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
|
|
||||||
|
@ -318,11 +318,11 @@ func (i *interpreter) evaluate(a ast.Node, context *TraceContext) (value, error)
|
|||||||
// Omitted field.
|
// Omitted field.
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
return nil, e.Error("Field name was not a string.")
|
return nil, e.Error(fmt.Sprintf("Field name must be string, got %v", fieldNameValue.typename()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := fields[fieldName]; ok {
|
if _, ok := fields[fieldName]; ok {
|
||||||
return nil, e.Error(fmt.Sprintf("Duplicate field name: \"%s\"", fieldName))
|
return nil, e.Error(duplicateFieldNameErrMsg(fieldName))
|
||||||
}
|
}
|
||||||
fields[fieldName] = valueSimpleObjectField{field.Hide, &codeUnboundField{field.Body}}
|
fields[fieldName] = valueSimpleObjectField{field.Hide, &codeUnboundField{field.Body}}
|
||||||
}
|
}
|
||||||
|
@ -117,9 +117,6 @@ func analyzeVisit(a ast.Node, inObject bool, vars ast.IdentifierSet) error {
|
|||||||
for _, assert := range a.Asserts {
|
for _, assert := range a.Asserts {
|
||||||
visitNext(assert, true, vars, s)
|
visitNext(assert, true, vars, s)
|
||||||
}
|
}
|
||||||
case *ast.ObjectComprehensionSimple:
|
|
||||||
// TODO (sbarzowski) this
|
|
||||||
panic("Comprehensions not supported yet")
|
|
||||||
case *ast.Self:
|
case *ast.Self:
|
||||||
if !inObject {
|
if !inObject {
|
||||||
return parser.MakeStaticError("Can't use self outside of an object.", *a.Loc())
|
return parser.MakeStaticError("Can't use self outside of an object.", *a.Loc())
|
||||||
|
2
testdata/fieldname_not_string.golden
vendored
2
testdata/fieldname_not_string.golden
vendored
@ -1 +1 @@
|
|||||||
RUNTIME ERROR: Field name was not a string.
|
RUNTIME ERROR: Field name must be string, got number
|
||||||
|
5
testdata/object_comp.golden
vendored
Normal file
5
testdata/object_comp.golden
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"a": 42,
|
||||||
|
"b": 42,
|
||||||
|
"c": 42
|
||||||
|
}
|
1
testdata/object_comp.jsonnet
vendored
Normal file
1
testdata/object_comp.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [x]: 42 for x in ["a", "b", "c"] }
|
1
testdata/object_comp2.golden
vendored
Normal file
1
testdata/object_comp2.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ }
|
1
testdata/object_comp2.jsonnet
vendored
Normal file
1
testdata/object_comp2.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [x]: error "xxx" for x in [] }
|
5
testdata/object_comp3.golden
vendored
Normal file
5
testdata/object_comp3.golden
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"x": "x",
|
||||||
|
"y": "y",
|
||||||
|
"z": "z"
|
||||||
|
}
|
1
testdata/object_comp3.jsonnet
vendored
Normal file
1
testdata/object_comp3.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{[v]: v for v in ["x", "y", "z"] }
|
1
testdata/object_comp_assert.golden
vendored
Normal file
1
testdata/object_comp_assert.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
testdata/object_comp_assert:1:32-35 Object comprehension cannot have asserts.
|
1
testdata/object_comp_assert.jsonnet
vendored
Normal file
1
testdata/object_comp_assert.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ assert self.x == 5, ["x"]: 5 for i in [42] }
|
1
testdata/object_comp_bad_field.golden
vendored
Normal file
1
testdata/object_comp_bad_field.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
testdata/object_comp_bad_field:1:9-12 Object comprehensions can only have [e] fields.
|
1
testdata/object_comp_bad_field.jsonnet
vendored
Normal file
1
testdata/object_comp_bad_field.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ x: 42 for _ in [1] }
|
1
testdata/object_comp_bad_field2.golden
vendored
Normal file
1
testdata/object_comp_bad_field2.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
testdata/object_comp_bad_field2:1:11-14 Object comprehensions can only have [e] fields.
|
1
testdata/object_comp_bad_field2.jsonnet
vendored
Normal file
1
testdata/object_comp_bad_field2.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ "x": 42 for _ in [1] }
|
1
testdata/object_comp_duplicate.golden
vendored
Normal file
1
testdata/object_comp_duplicate.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
RUNTIME ERROR: Duplicate field name: "x"
|
1
testdata/object_comp_duplicate.jsonnet
vendored
Normal file
1
testdata/object_comp_duplicate.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [x]: x for x in ["x", "x"] }
|
1
testdata/object_comp_err_elem.golden
vendored
Normal file
1
testdata/object_comp_err_elem.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
RUNTIME ERROR: xxx
|
1
testdata/object_comp_err_elem.jsonnet
vendored
Normal file
1
testdata/object_comp_err_elem.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ ["x"]: error "xxx" for x in [1] }
|
1
testdata/object_comp_err_index.golden
vendored
Normal file
1
testdata/object_comp_err_index.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
RUNTIME ERROR: xxx
|
1
testdata/object_comp_err_index.jsonnet
vendored
Normal file
1
testdata/object_comp_err_index.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [error "xxx"]: 42 for x in [1] }
|
4
testdata/object_comp_if.golden
vendored
Normal file
4
testdata/object_comp_if.golden
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"b": 42,
|
||||||
|
"bb": 42
|
||||||
|
}
|
1
testdata/object_comp_if.jsonnet
vendored
Normal file
1
testdata/object_comp_if.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [x]: 42 for x in ["a", "b", "bb", "c"] if x[0] == "b" }
|
1
testdata/object_comp_illegal.golden
vendored
Normal file
1
testdata/object_comp_illegal.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
testdata/object_comp_illegal:1:15-18 Object comprehension can only have one field.
|
1
testdata/object_comp_illegal.jsonnet
vendored
Normal file
1
testdata/object_comp_illegal.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ local x = 5 for y in [1, 2, 3] }
|
1
testdata/object_comp_int_index.golden
vendored
Normal file
1
testdata/object_comp_int_index.golden
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
RUNTIME ERROR: Field name must be string, got number
|
1
testdata/object_comp_int_index.jsonnet
vendored
Normal file
1
testdata/object_comp_int_index.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ [x]: x for x in [1, 2, 3] }
|
18
testdata/object_comp_super.golden
vendored
Normal file
18
testdata/object_comp_super.golden
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"a": "42a",
|
||||||
|
"b": "42b",
|
||||||
|
"c": "42c",
|
||||||
|
"q": 42,
|
||||||
|
"x": [
|
||||||
|
1,
|
||||||
|
"x"
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
1,
|
||||||
|
"y"
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
1,
|
||||||
|
"z"
|
||||||
|
]
|
||||||
|
}
|
4
testdata/object_comp_super.jsonnet
vendored
Normal file
4
testdata/object_comp_super.jsonnet
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{x: 1, y: 2, z: 3} +
|
||||||
|
{[v]: [super.x, v] for v in ["x", "y", "z"] } +
|
||||||
|
{[v]: self.q + v for v in ["a", "b", "c"]} +
|
||||||
|
{q: 42}
|
11
testdata/proto_object_comp.golden
vendored
Normal file
11
testdata/proto_object_comp.golden
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": "x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"y": "y"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"z": "z"
|
||||||
|
}
|
||||||
|
]
|
1
testdata/proto_object_comp.jsonnet
vendored
Normal file
1
testdata/proto_object_comp.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{[v]: v} for v in ["x", "y", "z"]]
|
4
testdata/string_to_bool.golden
vendored
Normal file
4
testdata/string_to_bool.golden
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
]
|
5
testdata/string_to_bool.jsonnet
vendored
Normal file
5
testdata/string_to_bool.jsonnet
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
local stringToBool(s) =
|
||||||
|
if s == "true" then true
|
||||||
|
else if s == "false" then false
|
||||||
|
else error "invalid boolean: " + std.manifestJson(s);
|
||||||
|
[stringToBool("false"), stringToBool("true")]
|
23
thunks.go
23
thunks.go
@ -131,9 +131,28 @@ type codeUnboundField struct {
|
|||||||
body ast.Node
|
body ast.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *codeUnboundField) bindToObject(sb selfBinding, origBinding bindingFrame) potentialValue {
|
func (f *codeUnboundField) bindToObject(sb selfBinding, origBindings bindingFrame) potentialValue {
|
||||||
// TODO(sbarzowski) better object names (perhaps include a field name too?)
|
// TODO(sbarzowski) better object names (perhaps include a field name too?)
|
||||||
return makeThunk("object_field", makeEnvironment(origBinding, sb), f.body)
|
return makeThunk("object_field", makeEnvironment(origBindings, sb), f.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide additional bindings for a field. It shadows bindings from the object.
|
||||||
|
type bindingsUnboundField struct {
|
||||||
|
inner unboundField
|
||||||
|
// in addition to "generic" binding frame from the object
|
||||||
|
bindings bindingFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *bindingsUnboundField) bindToObject(sb selfBinding, origBindings bindingFrame) potentialValue {
|
||||||
|
var upValues bindingFrame
|
||||||
|
upValues = make(bindingFrame)
|
||||||
|
for variable, pvalue := range origBindings {
|
||||||
|
upValues[variable] = pvalue
|
||||||
|
}
|
||||||
|
for variable, pvalue := range f.bindings {
|
||||||
|
upValues[variable] = pvalue
|
||||||
|
}
|
||||||
|
return f.inner.bindToObject(sb, upValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evalCallables
|
// evalCallables
|
||||||
|
4
value.go
4
value.go
@ -543,3 +543,7 @@ func objectFields(obj valueObject, manifesting bool) []string {
|
|||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func duplicateFieldNameErrMsg(fieldName string) string {
|
||||||
|
return fmt.Sprintf("Duplicate field name: %s", unparseString(fieldName))
|
||||||
|
}
|
||||||
|
15
vm.go
15
vm.go
@ -69,12 +69,17 @@ func (vm *VM) ExtCode(key string, val string) {
|
|||||||
vm.ext[key] = vmExt{value: val, isCode: true}
|
vm.ext[key] = vmExt{value: val, isCode: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VM) evaluateSnippet(filename string, snippet string) (string, error) {
|
func (vm *VM) evaluateSnippet(filename string, snippet string) (output string, err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("(CRASH) %v\n%s", r, debug.Stack())
|
||||||
|
}
|
||||||
|
}()
|
||||||
node, err := snippetToAST(filename, snippet)
|
node, err := snippetToAST(filename, snippet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
output, err := evaluate(node, vm.ext, vm.MaxStack, &FileImporter{})
|
output, err = evaluate(node, vm.ext, vm.MaxStack, &FileImporter{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -86,11 +91,6 @@ func (vm *VM) evaluateSnippet(filename string, snippet string) (string, error) {
|
|||||||
//
|
//
|
||||||
// The filename parameter is only used for error messages.
|
// The filename parameter is only used for error messages.
|
||||||
func (vm *VM) EvaluateSnippet(filename string, snippet string) (json string, formattedErr error) {
|
func (vm *VM) EvaluateSnippet(filename string, snippet string) (json string, formattedErr error) {
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
formattedErr = errors.New(vm.ef.format(fmt.Errorf("(CRASH) %v\n%s", r, debug.Stack())))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
json, err := vm.evaluateSnippet(filename, snippet)
|
json, err := vm.evaluateSnippet(filename, snippet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New(vm.ef.format(err))
|
return "", errors.New(vm.ef.format(err))
|
||||||
@ -107,7 +107,6 @@ func snippetToAST(filename string, snippet string) (ast.Node, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// fmt.Println(ast.(dumpable).dump())
|
|
||||||
err = desugarFile(&node)
|
err = desugarFile(&node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
x
Reference in New Issue
Block a user