4
4
"fmt"
5
5
"os"
6
6
"path/filepath"
7
- "strings"
8
7
9
8
"github.com/agext/levenshtein"
10
9
"github.com/hashicorp/hcl/v2"
@@ -21,64 +20,11 @@ type ContextMeta struct {
21
20
OriginalWorkingDir string
22
21
}
23
22
24
- type CallStack struct {
25
- addrs map [string ]addrs.Reference
26
- stack []string
27
- }
28
-
29
- func NewCallStack () * CallStack {
30
- return & CallStack {
31
- addrs : make (map [string ]addrs.Reference ),
32
- stack : make ([]string , 0 ),
33
- }
34
- }
35
-
36
- func (g * CallStack ) Push (addr addrs.Reference ) hcl.Diagnostics {
37
- g .stack = append (g .stack , addr .Subject .String ())
38
-
39
- if _ , exists := g .addrs [addr .Subject .String ()]; exists {
40
- return hcl.Diagnostics {
41
- {
42
- Severity : hcl .DiagError ,
43
- Summary : "circular reference found" ,
44
- Detail : g .String (),
45
- Subject : addr .SourceRange .Ptr (),
46
- },
47
- }
48
- }
49
- g .addrs [addr .Subject .String ()] = addr
50
- return hcl.Diagnostics {}
51
- }
52
-
53
- func (g * CallStack ) Pop () {
54
- if g .Empty () {
55
- panic ("cannot pop from empty stack" )
56
- }
57
-
58
- addr := g .stack [len (g .stack )- 1 ]
59
- g .stack = g .stack [:len (g .stack )- 1 ]
60
- delete (g .addrs , addr )
61
- }
62
-
63
- func (g * CallStack ) String () string {
64
- return strings .Join (g .stack , " -> " )
65
- }
66
-
67
- func (g * CallStack ) Empty () bool {
68
- return len (g .stack ) == 0
69
- }
70
-
71
- func (g * CallStack ) Clear () {
72
- g .addrs = make (map [string ]addrs.Reference )
73
- g .stack = make ([]string , 0 )
74
- }
75
-
76
23
type Evaluator struct {
77
24
Meta * ContextMeta
78
25
ModulePath addrs.ModuleInstance
79
26
Config * Config
80
27
VariableValues map [string ]map [string ]cty.Value
81
- CallStack * CallStack
82
28
}
83
29
84
30
// EvaluateExpr takes the given HCL expression and evaluates it to produce a value.
@@ -101,18 +47,27 @@ func (e *Evaluator) ExpandBlock(body hcl.Body, schema *hclext.BodySchema) (hcl.B
101
47
return e .scope ().ExpandBlock (body , schema )
102
48
}
103
49
50
+ // scope creates a new evaluation scope.
51
+ // The difference with Evaluator is that each evaluation is independent
52
+ // and is not shared between goroutines.
104
53
func (e * Evaluator ) scope () * lang.Scope {
105
- return & lang.Scope {
106
- Data : & evaluationData {
107
- Evaluator : e ,
108
- ModulePath : e .ModulePath ,
109
- },
54
+ scope := & lang.Scope {CallStack : lang .NewCallStack ()}
55
+ scope .Data = & evaluationData {
56
+ Scope : scope ,
57
+ Meta : e .Meta ,
58
+ ModulePath : e .ModulePath ,
59
+ Config : e .Config ,
60
+ VariableValues : e .VariableValues ,
110
61
}
62
+ return scope
111
63
}
112
64
113
65
type evaluationData struct {
114
- Evaluator * Evaluator
115
- ModulePath addrs.ModuleInstance
66
+ Scope * lang.Scope
67
+ Meta * ContextMeta
68
+ ModulePath addrs.ModuleInstance
69
+ Config * Config
70
+ VariableValues map [string ]map [string ]cty.Value
116
71
}
117
72
118
73
var _ lang.Data = (* evaluationData )(nil )
@@ -142,7 +97,7 @@ func (d *evaluationData) GetForEachAttr(addr addrs.ForEachAttr, rng hcl.Range) (
142
97
func (d * evaluationData ) GetInputVariable (addr addrs.InputVariable , rng hcl.Range ) (cty.Value , hcl.Diagnostics ) {
143
98
var diags hcl.Diagnostics
144
99
145
- moduleConfig := d .Evaluator . Config .DescendentForInstance (d .ModulePath )
100
+ moduleConfig := d .Config .DescendentForInstance (d .ModulePath )
146
101
if moduleConfig == nil {
147
102
// should never happen, since we can't be evaluating in a module
148
103
// that wasn't mentioned in configuration.
@@ -172,7 +127,7 @@ func (d *evaluationData) GetInputVariable(addr addrs.InputVariable, rng hcl.Rang
172
127
}
173
128
174
129
moduleAddrStr := d .ModulePath .String ()
175
- vals := d .Evaluator . VariableValues [moduleAddrStr ]
130
+ vals := d .VariableValues [moduleAddrStr ]
176
131
if vals == nil {
177
132
return cty .UnknownVal (config .Type ), diags
178
133
}
@@ -229,7 +184,7 @@ func (d *evaluationData) GetLocalValue(addr addrs.LocalValue, rng hcl.Range) (ct
229
184
230
185
// First we'll make sure the requested value is declared in configuration,
231
186
// so we can produce a nice message if not.
232
- moduleConfig := d .Evaluator . Config .DescendentForInstance (d .ModulePath )
187
+ moduleConfig := d .Config .DescendentForInstance (d .ModulePath )
233
188
if moduleConfig == nil {
234
189
// should never happen, since we can't be evaluating in a module
235
190
// that wasn't mentioned in configuration.
@@ -257,13 +212,13 @@ func (d *evaluationData) GetLocalValue(addr addrs.LocalValue, rng hcl.Range) (ct
257
212
}
258
213
259
214
// Build a call stack for circular reference detection only when getting a local value.
260
- if diags := d .Evaluator .CallStack .Push (addrs.Reference {Subject : addr , SourceRange : rng }); diags .HasErrors () {
215
+ if diags := d .Scope .CallStack .Push (addrs.Reference {Subject : addr , SourceRange : rng }); diags .HasErrors () {
261
216
return cty .UnknownVal (cty .DynamicPseudoType ), diags
262
217
}
263
218
264
- val , diags := d .Evaluator . EvaluateExpr (config .Expr , cty .DynamicPseudoType )
219
+ val , diags := d .Scope . EvalExpr (config .Expr , cty .DynamicPseudoType )
265
220
266
- d .Evaluator .CallStack .Pop ()
221
+ d .Scope .CallStack .Pop ()
267
222
return val , diags
268
223
}
269
224
@@ -274,10 +229,10 @@ func (d *evaluationData) GetPathAttr(addr addrs.PathAttr, rng hcl.Range) (cty.Va
274
229
case "cwd" :
275
230
var err error
276
231
var wd string
277
- if d .Evaluator . Meta != nil {
232
+ if d .Meta != nil {
278
233
// Meta is always non-nil in the normal case, but some test cases
279
234
// are not so realistic.
280
- wd = d .Evaluator . Meta .OriginalWorkingDir
235
+ wd = d .Meta .OriginalWorkingDir
281
236
}
282
237
if wd == "" {
283
238
wd , err = os .Getwd ()
@@ -308,7 +263,7 @@ func (d *evaluationData) GetPathAttr(addr addrs.PathAttr, rng hcl.Range) (cty.Va
308
263
return cty .StringVal (filepath .ToSlash (wd )), diags
309
264
310
265
case "module" :
311
- moduleConfig := d .Evaluator . Config .DescendentForInstance (d .ModulePath )
266
+ moduleConfig := d .Config .DescendentForInstance (d .ModulePath )
312
267
if moduleConfig == nil {
313
268
// should never happen, since we can't be evaluating in a module
314
269
// that wasn't mentioned in configuration.
@@ -318,7 +273,7 @@ func (d *evaluationData) GetPathAttr(addr addrs.PathAttr, rng hcl.Range) (cty.Va
318
273
return cty .StringVal (filepath .ToSlash (sourceDir )), diags
319
274
320
275
case "root" :
321
- sourceDir := d .Evaluator . Config .Module .SourceDir
276
+ sourceDir := d .Config .Module .SourceDir
322
277
return cty .StringVal (filepath .ToSlash (sourceDir )), diags
323
278
324
279
default :
@@ -341,7 +296,7 @@ func (d *evaluationData) GetTerraformAttr(addr addrs.TerraformAttr, rng hcl.Rang
341
296
switch addr .Name {
342
297
343
298
case "workspace" :
344
- workspaceName := d .Evaluator . Meta .Env
299
+ workspaceName := d .Meta .Env
345
300
return cty .StringVal (workspaceName ), diags
346
301
347
302
case "env" :
0 commit comments