func parse()

in cluster-autoscaler/cloudprovider/aws/aws-sdk-go/internal/ini/ini_parser.go [143:325]


func parse(tokens []Token) ([]AST, error) {
	start := Start
	stack := newParseStack(3, len(tokens))

	stack.Push(start)
	s := newSkipper()

loop:
	for stack.Len() > 0 {
		k := stack.Pop()

		var tok Token
		if len(tokens) == 0 {
			// this occurs when all the tokens have been processed
			// but reduction of what's left on the stack needs to
			// occur.
			tok = emptyToken
		} else {
			tok = tokens[0]
		}

		step := parseTable[k.Kind][tok.Type()]
		if s.ShouldSkip(tok) {
			// being in a skip state with no tokens will break out of
			// the parse loop since there is nothing left to process.
			if len(tokens) == 0 {
				break loop
			}
			// if should skip is true, we skip the tokens until should skip is set to false.
			step = SkipTokenState
		}

		switch step {
		case TerminalState:
			// Finished parsing. Push what should be the last
			// statement to the stack. If there is anything left
			// on the stack, an error in parsing has occurred.
			if k.Kind != ASTKindStart {
				stack.MarkComplete(k)
			}
			break loop
		case SkipTokenState:
			// When skipping a token, the previous state was popped off the stack.
			// To maintain the correct state, the previous state will be pushed
			// onto the stack.
			stack.Push(k)
		case StatementState:
			if k.Kind != ASTKindStart {
				stack.MarkComplete(k)
			}
			expr := newExpression(tok)
			stack.Push(expr)
		case StatementPrimeState:
			if tok.Type() != TokenOp {
				stack.MarkComplete(k)
				continue
			}

			if k.Kind != ASTKindExpr {
				return nil, NewParseError(
					fmt.Sprintf("invalid expression: expected Expr type, but found %T type", k),
				)
			}

			k = trimSpaces(k)
			expr := newEqualExpr(k, tok)
			stack.Push(expr)
		case ValueState:
			// ValueState requires the previous state to either be an equal expression
			// or an expression statement.
			switch k.Kind {
			case ASTKindEqualExpr:
				// assigning a value to some key
				k.AppendChild(newExpression(tok))
				stack.Push(newExprStatement(k))
			case ASTKindExpr:
				k.Root.raw = append(k.Root.raw, tok.Raw()...)
				stack.Push(k)
			case ASTKindExprStatement:
				root := k.GetRoot()
				children := root.GetChildren()
				if len(children) == 0 {
					return nil, NewParseError(
						fmt.Sprintf("invalid expression: AST contains no children %s", k.Kind),
					)
				}

				rhs := children[len(children)-1]

				if rhs.Root.ValueType != QuotedStringType {
					rhs.Root.ValueType = StringType
					rhs.Root.raw = append(rhs.Root.raw, tok.Raw()...)

				}

				children[len(children)-1] = rhs
				root.SetChildren(children)

				stack.Push(k)
			}
		case OpenScopeState:
			if !runeCompare(tok.Raw(), openBrace) {
				return nil, NewParseError("expected '['")
			}
			// If OpenScopeState is not at the start, we must mark the previous ast as complete
			//
			// for example: if previous ast was a skip statement;
			// we should mark it as complete before we create a new statement
			if k.Kind != ASTKindStart {
				stack.MarkComplete(k)
			}

			stmt := newStatement()
			stack.Push(stmt)
		case CloseScopeState:
			if !runeCompare(tok.Raw(), closeBrace) {
				return nil, NewParseError("expected ']'")
			}

			k = trimSpaces(k)
			stack.Push(newCompletedSectionStatement(k))
		case SectionState:
			var stmt AST

			switch k.Kind {
			case ASTKindStatement:
				// If there are multiple literals inside of a scope declaration,
				// then the current token's raw value will be appended to the Name.
				//
				// This handles cases like [ profile default ]
				//
				// k will represent a SectionStatement with the children representing
				// the label of the section
				stmt = newSectionStatement(tok)
			case ASTKindSectionStatement:
				k.Root.raw = append(k.Root.raw, tok.Raw()...)
				stmt = k
			default:
				return nil, NewParseError(
					fmt.Sprintf("invalid statement: expected statement: %v", k.Kind),
				)
			}

			stack.Push(stmt)
		case MarkCompleteState:
			if k.Kind != ASTKindStart {
				stack.MarkComplete(k)
			}

			if stack.Len() == 0 {
				stack.Push(start)
			}
		case SkipState:
			stack.Push(newSkipStatement(k))
			s.Skip()
		case CommentState:
			if k.Kind == ASTKindStart {
				stack.Push(k)
			} else {
				stack.MarkComplete(k)
			}

			stmt := newCommentStatement(tok)
			stack.Push(stmt)
		default:
			return nil, NewParseError(
				fmt.Sprintf("invalid state with ASTKind %v and TokenType %v",
					k, tok.Type()))
		}

		if len(tokens) > 0 {
			tokens = tokens[1:]
		}
	}

	// this occurs when a statement has not been completed
	if stack.top > 1 {
		return nil, NewParseError(fmt.Sprintf("incomplete ini expression"))
	}

	// returns a sublist which excludes the start symbol
	return stack.List(), nil
}