Our "parser" here is actually not doing any parsing of its own. Instead, it leans on the native parser in hclsyntax, and then uses the source ranges from the AST to partition the raw token sequence to match the raw tokens up to AST nodes. This strategy feels somewhat counter-intuitive, since most o
(src []byte, filename string, start hcl.Pos)
| 30 | // we can't reliably extract tokens from the partial AST produced by an |
| 31 | // erroneous parse. |
| 32 | func parse(src []byte, filename string, start hcl.Pos) (*File, hcl.Diagnostics) { |
| 33 | file, diags := hclsyntax.ParseConfig(src, filename, start) |
| 34 | if diags.HasErrors() { |
| 35 | return nil, diags |
| 36 | } |
| 37 | |
| 38 | // To do our work here, we use the "native" tokens (those from hclsyntax) |
| 39 | // to match against source ranges in the AST, but ultimately produce |
| 40 | // slices from our sequence of "writer" tokens, which contain only |
| 41 | // *relative* position information that is more appropriate for |
| 42 | // transformation/writing use-cases. |
| 43 | nativeTokens, diags := hclsyntax.LexConfig(src, filename, start) |
| 44 | if diags.HasErrors() { |
| 45 | // should never happen, since we would've caught these diags in |
| 46 | // the first call above. |
| 47 | return nil, diags |
| 48 | } |
| 49 | writerTokens := writerTokens(nativeTokens) |
| 50 | |
| 51 | from := inputTokens{ |
| 52 | nativeTokens: nativeTokens, |
| 53 | writerTokens: writerTokens, |
| 54 | } |
| 55 | |
| 56 | before, root, after := parseBody(file.Body.(*hclsyntax.Body), from) |
| 57 | ret := &File{ |
| 58 | inTree: newInTree(), |
| 59 | |
| 60 | srcBytes: src, |
| 61 | body: root, |
| 62 | } |
| 63 | |
| 64 | nodes := ret.children |
| 65 | nodes.Append(before.Tokens()) |
| 66 | nodes.AppendNode(root) |
| 67 | nodes.Append(after.Tokens()) |
| 68 | |
| 69 | return ret, diags |
| 70 | } |
| 71 | |
| 72 | type inputTokens struct { |
| 73 | nativeTokens hclsyntax.Tokens |