func BuildHclNode()

in internal/parser/hcl_node.go [99:368]


func BuildHclNode(tokens hclsyntax.Tokens) *HclNode {
	stack := make([]State, 0)
	stack = append(stack, State{
		CurrentHclNode: &HclNode{
			KeyValueFormat: KeyEqualValue,
			Children:       make(map[string]*HclNode),
		},
		Key:         utils.String("dummy"),
		Index:       nil,
		Value:       nil,
		ExpectKey:   false,
		ExpectEqual: false,
	})

	for _, token := range tokens {
		switch token.Type {
		case hclsyntax.TokenOBrace: // {
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			key := state.GetCurrentKey()
			if state.ExpectKey {
				log.Printf("[WARN] expect key but got {")
			}
			hclNode := &HclNode{
				Key:            key,
				KeyRange:       state.KeyRange,
				ValueRange:     token.Range,
				EqualRange:     state.EqualRange,
				Children:       make(map[string]*HclNode),
				KeyValueFormat: stack[top].CurrentHclNode.KeyValueFormat,
			}
			stack[top].CurrentHclNode.Children[key] = hclNode
			if stack[top].Index == nil {
				stack[top].ExpectKey = true
				stack[top].ExpectEqual = true
			} else {
				// if there's an index, then expect value because p = [{}]
				stack[top].ExpectKey = false
				stack[top].ExpectEqual = false
				// the hclNode is an object in an array, so use the range of "{" as the key range
				hclNode.KeyRange = token.Range
			}
			stack = append(stack, State{
				ExpectKey:      true,
				ExpectEqual:    true,
				CurrentHclNode: hclNode,
			})
		case hclsyntax.TokenCBrace: // }
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			if !state.ExpectKey {
				log.Printf("[WARN] expect value but got }")
				key := state.GetCurrentKey()
				stack[top].CurrentHclNode.Children[key] = &HclNode{
					Key:        key,
					Value:      state.Value,
					KeyRange:   state.KeyRange,
					ValueRange: state.ValueRange,
					EqualRange: state.EqualRange,
				}
			}
			stack[top].CurrentHclNode.ValueRange = RangeOver(stack[top].CurrentHclNode.ValueRange, token.Range)
			stack = stack[0:top]
		case hclsyntax.TokenOBrack: // [
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			if state.ExpectKey {
				log.Printf("[WARN] expect key but got [")
			}
			if state.Value != nil && *state.Value != "" {
				updateStateValue(&stack[top], token)
				break
			}
			key := state.GetCurrentKey()
			hclNode := &HclNode{
				Key:            key,
				KeyRange:       state.KeyRange,
				EqualRange:     state.EqualRange,
				ValueRange:     token.Range,
				KeyValueFormat: state.CurrentHclNode.KeyValueFormat,
				Children:       make(map[string]*HclNode),
			}
			stack[top].CurrentHclNode.Children[key] = hclNode
			stack[top].ExpectKey = true
			stack[top].ExpectEqual = stack[top].ExpectKey
			stack = append(stack, State{
				ExpectKey:      false,
				ExpectEqual:    false,
				Key:            state.Key,
				Index:          utils.Int(0),
				CurrentHclNode: hclNode,
			})
		case hclsyntax.TokenCBrack: // ]
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			if state.Value != nil && *state.Value != "" && strings.Contains(*state.Value, "[") {
				updateStateValue(&stack[top], token)
				break
			}
			if _, ok := state.CurrentHclNode.Children[state.GetCurrentKey()]; !ok {
				log.Printf("[WARN] expect value but got }")
				// avoid adding an empty element
				if !state.ValueRange.Empty() {
					key := state.GetCurrentKey()
					stack[top].CurrentHclNode.Children[key] = &HclNode{
						Key:        key,
						Value:      state.Value,
						ValueRange: state.ValueRange,
					}
				}
			}
			stack[top].CurrentHclNode.ValueRange = RangeOver(stack[top].CurrentHclNode.ValueRange, token.Range)
			stack = stack[0:top]
		case hclsyntax.TokenQuotedLit:
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			if stack[top].ExpectKey {
				foundKey(&stack[top], token)
				stack[top].CurrentHclNode.KeyValueFormat = QuotedKeyEqualValue
			} else {
				updateStateValue(&stack[top], token)
			}
		case hclsyntax.TokenIdent:
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			if stack[top].ExpectKey {
				foundKey(&stack[top], token)
			} else {
				updateStateValue(&stack[top], token)
			}
		case hclsyntax.TokenColon: // :
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			if stack[top].ExpectEqual {
				if stack[top].ExpectKey {
					log.Printf("[WARN] expect key but got =")
					stack[top].ExpectKey = false
				}

				stack[top].CurrentHclNode.KeyValueFormat = QuotedKeyColonValue
				stack[top].EqualRange = token.Range
				stack[top].ExpectEqual = false
			} else {
				updateStateValue(&stack[top], token)
			}
		case hclsyntax.TokenEqual: // =
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			if stack[top].ExpectEqual {
				if stack[top].ExpectKey {
					log.Printf("[WARN] expect key but got =")
					stack[top].ExpectKey = false
				}
				stack[top].EqualRange = token.Range
				stack[top].ExpectEqual = false
			} else {
				updateStateValue(&stack[top], token)
			}
		case hclsyntax.TokenNewline:
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			if !state.ExpectKey {
				if stack[top].Index == nil {
					key := state.GetCurrentKey()
					stack[top].CurrentHclNode.Children[key] = &HclNode{
						Key:        key,
						Value:      state.Value,
						KeyRange:   state.KeyRange,
						ValueRange: state.ValueRange,
						EqualRange: state.EqualRange,
					}
					stack[top].Key = nil
					stack[top].Value = nil
					stack[top].ExpectKey = true
					stack[top].ExpectEqual = stack[top].ExpectKey
				}
			}
		case hclsyntax.TokenComma:
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			state := stack[top]
			if !state.ExpectKey {
				if state.Index == nil {
					log.Printf("[WARN] unexpected symbol: ,")
					break
				}
				if state.Value != nil {
					key := state.GetCurrentKey()
					stack[top].CurrentHclNode.Children[key] = &HclNode{
						Key:        key,
						Value:      state.Value,
						ValueRange: state.ValueRange,
					}
				}
				*stack[top].Index++
				stack[top].Value = nil
				stack[top].ValueRange = hcl.Range{}
			} else {
				log.Printf("[WARN] expect key but got ,")
			}
		case hclsyntax.TokenComment:
			comment := string(token.Bytes)
			if strings.HasSuffix(comment, "\n") {
				top := len(stack) - 1
				if top < 0 {
					return nil
				}
				state := stack[top]
				if !state.ExpectKey {
					if stack[top].Index == nil {
						key := state.GetCurrentKey()
						stack[top].CurrentHclNode.Children[key] = &HclNode{
							Key:        key,
							Value:      state.Value,
							KeyRange:   state.KeyRange,
							ValueRange: state.ValueRange,
							EqualRange: state.EqualRange,
						}
						stack[top].Key = nil
						stack[top].Value = nil
						stack[top].ExpectKey = true
						stack[top].ExpectEqual = stack[top].ExpectKey
					}
				}
			}
		default:
			top := len(stack) - 1
			if top < 0 {
				return nil
			}
			if !stack[top].ExpectEqual {
				updateStateValue(&stack[top], token)
			}
		}
	}

	if len(stack) == 0 {
		return nil
	}

	root := stack[0].CurrentHclNode
	updateValueRange(root)
	fixEmptyValueRange(root)
	return root
}