| 25 | } |
| 26 | |
| 27 | func (p *parser) ParseBody(end TokenType) (*Body, hcl.Diagnostics) { |
| 28 | attrs := Attributes{} |
| 29 | blocks := Blocks{} |
| 30 | var diags hcl.Diagnostics |
| 31 | |
| 32 | startRange := p.PrevRange() |
| 33 | var endRange hcl.Range |
| 34 | |
| 35 | Token: |
| 36 | for { |
| 37 | next := p.Peek() |
| 38 | if next.Type == end { |
| 39 | endRange = p.NextRange() |
| 40 | p.Read() |
| 41 | break Token |
| 42 | } |
| 43 | |
| 44 | switch next.Type { |
| 45 | case TokenNewline: |
| 46 | p.Read() |
| 47 | continue |
| 48 | case TokenIdent: |
| 49 | item, itemDiags := p.ParseBodyItem() |
| 50 | diags = append(diags, itemDiags...) |
| 51 | switch titem := item.(type) { |
| 52 | case *Block: |
| 53 | blocks = append(blocks, titem) |
| 54 | case *Attribute: |
| 55 | if existing, exists := attrs[titem.Name]; exists { |
| 56 | diags = append(diags, &hcl.Diagnostic{ |
| 57 | Severity: hcl.DiagError, |
| 58 | Summary: "Attribute redefined", |
| 59 | Detail: fmt.Sprintf( |
| 60 | "The argument %q was already set at %s. Each argument may be set only once.", |
| 61 | titem.Name, existing.NameRange.String(), |
| 62 | ), |
| 63 | Subject: &titem.NameRange, |
| 64 | }) |
| 65 | } else { |
| 66 | attrs[titem.Name] = titem |
| 67 | } |
| 68 | default: |
| 69 | // This should never happen for valid input, but may if a |
| 70 | // syntax error was detected in ParseBodyItem that prevented |
| 71 | // it from even producing a partially-broken item. In that |
| 72 | // case, it would've left at least one error in the diagnostics |
| 73 | // slice we already dealt with above. |
| 74 | // |
| 75 | // We'll assume ParseBodyItem attempted recovery to leave |
| 76 | // us in a reasonable position to try parsing the next item. |
| 77 | continue |
| 78 | } |
| 79 | default: |
| 80 | bad := p.Read() |
| 81 | if !p.recovery { |
| 82 | switch bad.Type { |
| 83 | case TokenOQuote: |
| 84 | diags = append(diags, &hcl.Diagnostic{ |