| // Package ast declares the types used to represent syntax trees for HCL |
| // (HashiCorp Configuration Language) |
| package ast |
| |
| import ( |
| "fmt" |
| "strings" |
| |
| "google3/third_party/golang/hashicorp/hcl/hcl/token/token" |
| ) |
| |
| // Node is an element in the abstract syntax tree. |
| type Node interface { |
| node() |
| Pos() token.Pos |
| } |
| |
| func (File) node() {} |
| func (ObjectList) node() {} |
| func (ObjectKey) node() {} |
| func (ObjectItem) node() {} |
| func (Comment) node() {} |
| func (CommentGroup) node() {} |
| func (ObjectType) node() {} |
| func (LiteralType) node() {} |
| func (ListType) node() {} |
| |
| // File represents a single HCL file |
| type File struct { |
| Node Node // usually a *ObjectList |
| Comments []*CommentGroup // list of all comments in the source |
| } |
| |
| func (f *File) Pos() token.Pos { |
| return f.Node.Pos() |
| } |
| |
| // ObjectList represents a list of ObjectItems. An HCL file itself is an |
| // ObjectList. |
| type ObjectList struct { |
| Items []*ObjectItem |
| } |
| |
| func (o *ObjectList) Add(item *ObjectItem) { |
| o.Items = append(o.Items, item) |
| } |
| |
| // Filter filters out the objects with the given key list as a prefix. |
| // |
| // The returned list of objects contain ObjectItems where the keys have |
| // this prefix already stripped off. This might result in objects with |
| // zero-length key lists if they have no children. |
| // |
| // If no matches are found, an empty ObjectList (non-nil) is returned. |
| func (o *ObjectList) Filter(keys ...string) *ObjectList { |
| var result ObjectList |
| for _, item := range o.Items { |
| // If there aren't enough keys, then ignore this |
| if len(item.Keys) < len(keys) { |
| continue |
| } |
| |
| match := true |
| for i, key := range item.Keys[:len(keys)] { |
| key := key.Token.Value().(string) |
| if key != keys[i] && !strings.EqualFold(key, keys[i]) { |
| match = false |
| break |
| } |
| } |
| if !match { |
| continue |
| } |
| |
| // Strip off the prefix from the children |
| newItem := *item |
| newItem.Keys = newItem.Keys[len(keys):] |
| result.Add(&newItem) |
| } |
| |
| return &result |
| } |
| |
| // Children returns further nested objects (key length > 0) within this |
| // ObjectList. This should be used with Filter to get at child items. |
| func (o *ObjectList) Children() *ObjectList { |
| var result ObjectList |
| for _, item := range o.Items { |
| if len(item.Keys) > 0 { |
| result.Add(item) |
| } |
| } |
| |
| return &result |
| } |
| |
| // Elem returns items in the list that are direct element assignments |
| // (key length == 0). This should be used with Filter to get at elements. |
| func (o *ObjectList) Elem() *ObjectList { |
| var result ObjectList |
| for _, item := range o.Items { |
| if len(item.Keys) == 0 { |
| result.Add(item) |
| } |
| } |
| |
| return &result |
| } |
| |
| func (o *ObjectList) Pos() token.Pos { |
| // always returns the uninitiliazed position |
| return o.Items[0].Pos() |
| } |
| |
| // ObjectItem represents a HCL Object Item. An item is represented with a key |
| // (or keys). It can be an assignment or an object (both normal and nested) |
| type ObjectItem struct { |
| // keys is only one length long if it's of type assignment. If it's a |
| // nested object it can be larger than one. In that case "assign" is |
| // invalid as there is no assignments for a nested object. |
| Keys []*ObjectKey |
| |
| // assign contains the position of "=", if any |
| Assign token.Pos |
| |
| // val is the item itself. It can be an object,list, number, bool or a |
| // string. If key length is larger than one, val can be only of type |
| // Object. |
| Val Node |
| |
| LeadComment *CommentGroup // associated lead comment |
| LineComment *CommentGroup // associated line comment |
| } |
| |
| func (o *ObjectItem) Pos() token.Pos { |
| // I'm not entirely sure what causes this, but removing this causes |
| // a test failure. We should investigate at some point. |
| if len(o.Keys) == 0 { |
| return token.Pos{} |
| } |
| |
| return o.Keys[0].Pos() |
| } |
| |
| // ObjectKeys are either an identifier or of type string. |
| type ObjectKey struct { |
| Token token.Token |
| } |
| |
| func (o *ObjectKey) Pos() token.Pos { |
| return o.Token.Pos |
| } |
| |
| // LiteralType represents a literal of basic type. Valid types are: |
| // token.NUMBER, token.FLOAT, token.BOOL and token.STRING |
| type LiteralType struct { |
| Token token.Token |
| |
| // comment types, only used when in a list |
| LeadComment *CommentGroup |
| LineComment *CommentGroup |
| } |
| |
| func (l *LiteralType) Pos() token.Pos { |
| return l.Token.Pos |
| } |
| |
| // ListStatement represents a HCL List type |
| type ListType struct { |
| Lbrack token.Pos // position of "[" |
| Rbrack token.Pos // position of "]" |
| List []Node // the elements in lexical order |
| } |
| |
| func (l *ListType) Pos() token.Pos { |
| return l.Lbrack |
| } |
| |
| func (l *ListType) Add(node Node) { |
| l.List = append(l.List, node) |
| } |
| |
| // ObjectType represents a HCL Object Type |
| type ObjectType struct { |
| Lbrace token.Pos // position of "{" |
| Rbrace token.Pos // position of "}" |
| List *ObjectList // the nodes in lexical order |
| } |
| |
| func (o *ObjectType) Pos() token.Pos { |
| return o.Lbrace |
| } |
| |
| // Comment node represents a single //, # style or /*- style commment |
| type Comment struct { |
| Start token.Pos // position of / or # |
| Text string |
| } |
| |
| func (c *Comment) Pos() token.Pos { |
| return c.Start |
| } |
| |
| // CommentGroup node represents a sequence of comments with no other tokens and |
| // no empty lines between. |
| type CommentGroup struct { |
| List []*Comment // len(List) > 0 |
| } |
| |
| func (c *CommentGroup) Pos() token.Pos { |
| return c.List[0].Pos() |
| } |
| |
| //------------------------------------------------------------------- |
| // GoStringer |
| //------------------------------------------------------------------- |
| |
| func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } |
| func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } |