]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package ast |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | ) | |
6 | ||
7 | // Node is the interface that all AST nodes must implement. | |
8 | type Node interface { | |
9 | // Accept is called to dispatch to the visitors. It must return the | |
10 | // resulting Node (which might be different in an AST transform). | |
11 | Accept(Visitor) Node | |
12 | ||
13 | // Pos returns the position of this node in some source. | |
14 | Pos() Pos | |
15 | ||
16 | // Type returns the type of this node for the given context. | |
17 | Type(Scope) (Type, error) | |
18 | } | |
19 | ||
20 | // Pos is the starting position of an AST node | |
21 | type Pos struct { | |
22 | Column, Line int // Column/Line number, starting at 1 | |
23 | Filename string // Optional source filename, if known | |
24 | } | |
25 | ||
26 | func (p Pos) String() string { | |
27 | if p.Filename == "" { | |
28 | return fmt.Sprintf("%d:%d", p.Line, p.Column) | |
29 | } else { | |
30 | return fmt.Sprintf("%s:%d:%d", p.Filename, p.Line, p.Column) | |
31 | } | |
32 | } | |
33 | ||
34 | // InitPos is an initiaial position value. This should be used as | |
35 | // the starting position (presets the column and line to 1). | |
36 | var InitPos = Pos{Column: 1, Line: 1} | |
37 | ||
38 | // Visitors are just implementations of this function. | |
39 | // | |
40 | // The function must return the Node to replace this node with. "nil" is | |
41 | // _not_ a valid return value. If there is no replacement, the original node | |
42 | // should be returned. We build this replacement directly into the visitor | |
43 | // pattern since AST transformations are a common and useful tool and | |
44 | // building it into the AST itself makes it required for future Node | |
45 | // implementations and very easy to do. | |
46 | // | |
47 | // Note that this isn't a true implementation of the visitor pattern, which | |
48 | // generally requires proper type dispatch on the function. However, | |
49 | // implementing this basic visitor pattern style is still very useful even | |
50 | // if you have to type switch. | |
51 | type Visitor func(Node) Node | |
52 | ||
53 | //go:generate stringer -type=Type | |
54 | ||
55 | // Type is the type of any value. | |
56 | type Type uint32 | |
57 | ||
58 | const ( | |
59 | TypeInvalid Type = 0 | |
60 | TypeAny Type = 1 << iota | |
61 | TypeBool | |
62 | TypeString | |
63 | TypeInt | |
64 | TypeFloat | |
65 | TypeList | |
66 | TypeMap | |
67 | ||
68 | // This is a special type used by Terraform to mark "unknown" values. | |
69 | // It is impossible for this type to be introduced into your HIL programs | |
70 | // unless you explicitly set a variable to this value. In that case, | |
71 | // any operation including the variable will return "TypeUnknown" as the | |
72 | // type. | |
73 | TypeUnknown | |
74 | ) | |
75 | ||
76 | func (t Type) Printable() string { | |
77 | switch t { | |
78 | case TypeInvalid: | |
79 | return "invalid type" | |
80 | case TypeAny: | |
81 | return "any type" | |
82 | case TypeBool: | |
83 | return "type bool" | |
84 | case TypeString: | |
85 | return "type string" | |
86 | case TypeInt: | |
87 | return "type int" | |
88 | case TypeFloat: | |
89 | return "type float" | |
90 | case TypeList: | |
91 | return "type list" | |
92 | case TypeMap: | |
93 | return "type map" | |
94 | case TypeUnknown: | |
95 | return "type unknown" | |
96 | default: | |
97 | return "unknown type" | |
98 | } | |
99 | } |