diff --git a/analysis/common_test.go b/analysis/common_test.go index 3e6dfd27..940f15f8 100644 --- a/analysis/common_test.go +++ b/analysis/common_test.go @@ -144,7 +144,7 @@ func visitExprs(env *esc.Environment, visitor func(path string, x esc.Expr)) { } } - for _, key := range sortedKeys(env.Exprs) { - visit(env.Exprs[key], key) + for _, key := range sortedKeys(env.Exprs.Object) { + visit(env.Exprs.Object[key], key) } } diff --git a/analysis/traversal.go b/analysis/traversal.go index bad2b507..1a2299a5 100644 --- a/analysis/traversal.go +++ b/analysis/traversal.go @@ -46,7 +46,7 @@ func (a *Analysis) ExpressionAtPos(pos esc.Pos) (*esc.Expr, bool) { // (nil, nil, false). The returned expression is the "smallest" expression that contains pos. The path to the given // expression is also returned. func (a *Analysis) expressionAtPos(pos esc.Pos) (*esc.Expr, []traverser, bool) { - for key, x := range a.env.Exprs { + for key, x := range a.env.Exprs.Object { if x, where, ok := expressionAtPos(x, []traverser{newRootTraverser(key)}, pos); ok { return x, where, true } diff --git a/ast/environment.go b/ast/environment.go index 73f7bda6..37e2e0c6 100644 --- a/ast/environment.go +++ b/ast/environment.go @@ -196,7 +196,7 @@ type EnvironmentDecl struct { Description *StringExpr Imports ImportListDecl - Values PropertyMapDecl + Values *ObjectExpr } func (d *EnvironmentDecl) Syntax() syntax.Node { @@ -222,7 +222,7 @@ func (d *EnvironmentDecl) NewDiagnosticWriter(w io.Writer, width uint, color boo return newDiagnosticWriter(w, fileMap, width, color) } -func EnvironmentSyntax(node *syntax.ObjectNode, description *StringExpr, imports ImportListDecl, values PropertyMapDecl) *EnvironmentDecl { +func EnvironmentSyntax(node *syntax.ObjectNode, description *StringExpr, imports ImportListDecl, values *ObjectExpr) *EnvironmentDecl { return &EnvironmentDecl{ syntax: node, Description: description, @@ -231,7 +231,7 @@ func EnvironmentSyntax(node *syntax.ObjectNode, description *StringExpr, imports } } -func Environment(description *StringExpr, imports ImportListDecl, values PropertyMapDecl) *EnvironmentDecl { +func Environment(description *StringExpr, imports ImportListDecl, values *ObjectExpr) *EnvironmentDecl { return EnvironmentSyntax(nil, description, imports, values) } diff --git a/ast/expr.go b/ast/expr.go index ef5155e3..7e0950b0 100644 --- a/ast/expr.go +++ b/ast/expr.go @@ -266,6 +266,13 @@ type ObjectExpr struct { Entries []ObjectProperty } +func (o *ObjectExpr) GetEntries() []ObjectProperty { + if o == nil { + return nil + } + return o.Entries +} + // An ObjectProperty represents an object property. Key must be a string. type ObjectProperty struct { syntax syntax.ObjectPropertyDef diff --git a/cmd/esc/cli/client/client_test.go b/cmd/esc/cli/client/client_test.go index 368adfba..bda10a99 100644 --- a/cmd/esc/cli/client/client_test.go +++ b/cmd/esc/cli/client/client_test.go @@ -758,7 +758,9 @@ func TestCheckYAMLEnvironment(t *testing.T) { yaml := []byte(`{"values":{"foo":"bar"}}`) expected := &esc.Environment{ - Exprs: map[string]esc.Expr{"foo": {Literal: "bar"}}, + Exprs: &esc.Expr{ + Object: map[string]esc.Expr{"foo": {Literal: "bar"}}, + }, Properties: map[string]esc.Value{"foo": esc.NewValue("bar")}, Schema: schema.Record(schema.BuilderMap{"foo": schema.String().Const("bar")}).Schema(), } @@ -884,7 +886,9 @@ func TestOpenYAMLEnvironment(t *testing.T) { func TestGetOpenEnvironment(t *testing.T) { t.Run("OK", func(t *testing.T) { expected := &esc.Environment{ - Exprs: map[string]esc.Expr{"foo": {Literal: "bar"}}, + Exprs: &esc.Expr{ + Object: map[string]esc.Expr{"foo": {Literal: "bar"}}, + }, Properties: map[string]esc.Value{"foo": esc.NewValue("bar")}, Schema: schema.Record(schema.BuilderMap{"foo": schema.String().Const("bar")}).Schema(), } @@ -918,7 +922,9 @@ func TestGetOpenEnvironment(t *testing.T) { func TestGetAnonymousOpenEnvironment(t *testing.T) { t.Run("OK", func(t *testing.T) { expected := &esc.Environment{ - Exprs: map[string]esc.Expr{"foo": {Literal: "bar"}}, + Exprs: &esc.Expr{ + Object: map[string]esc.Expr{"foo": {Literal: "bar"}}, + }, Properties: map[string]esc.Value{"foo": esc.NewValue("bar")}, Schema: schema.Record(schema.BuilderMap{"foo": schema.String().Const("bar")}).Schema(), } diff --git a/cmd/esc/cli/env_get.go b/cmd/esc/cli/env_get.go index 125d4e91..54c1559e 100644 --- a/cmd/esc/cli/env_get.go +++ b/cmd/esc/cli/env_get.go @@ -329,7 +329,7 @@ func (get *envGetCommand) getEnvironmentMember( definitionYAML := "" if valuesNode, ok := (encoding.YAMLSyntax{Node: &docNode}.Get(resource.PropertyPath{"values"})); ok { if node, _ := (encoding.YAMLSyntax{Node: valuesNode}.Get(path)); node != nil { - expr, ok := getEnvExpr(esc.Expr{Object: env.Exprs}, path) + expr, ok := getEnvExpr(*env.Exprs, path) if !ok { return nil, fmt.Errorf("internal error: no expr for path %v", path) } diff --git a/environment.go b/environment.go index 551314ab..1b0f7d5c 100644 --- a/environment.go +++ b/environment.go @@ -164,8 +164,8 @@ type EvaluatedExecutionContext struct { // An Environment contains the result of evaluating an environment definition. type Environment struct { - // Exprs contains the AST for each expression in the environment definition. - Exprs map[string]Expr `json:"exprs,omitempty"` + // Exprs contains the AST for the root object expression. + Exprs *Expr `json:"exprs,omitempty"` // Properties contains the detailed values produced by the environment. Properties map[string]Value `json:"properties,omitempty"` diff --git a/eval/eval.go b/eval/eval.go index e6372ebf..6a864546 100644 --- a/eval/eval.go +++ b/eval/eval.go @@ -163,8 +163,9 @@ func evalEnvironment( envProperties, exportDiags := v.export(name) diags.Extend(exportDiags...) + rootExpr := ec.root.export(name) return &esc.Environment{ - Exprs: ec.root.export(name).Object, + Exprs: &rootExpr, Properties: envProperties.Value.(map[string]esc.Value), Schema: s, ExecutionContext: executionContext, @@ -437,7 +438,7 @@ func (e *evalContext) evaluate() (*value, syntax.Diagnostics) { e.root = &expr{ path: "<" + e.name + ">", repr: &objectExpr{ - node: ast.Object(), + node: e.env.Values, properties: properties, }, base: e.base,