diff --git a/parser/context.go b/parser/context.go index 42cc4f8f..78dc7538 100644 --- a/parser/context.go +++ b/parser/context.go @@ -9,11 +9,12 @@ import ( // context context at parsing type context struct { - parent *context - idx int - size int - tokens token.Tokens - path string + parent *context + idx int + size int + tokens token.Tokens + path string + pathStack []string } var pathSpecialChars = []string{ @@ -37,26 +38,32 @@ func normalizePath(path string) string { } func (c *context) withChild(path string) *context { - ctx := c.copy() + // store current path in the stack for later retrieval + c.pathStack = append(c.pathStack, c.path) + c.path = c.createPathForChild(path) + return c +} + +func (c *context) createPathForChild(path string) string { path = normalizePath(path) - ctx.path += fmt.Sprintf(".%s", path) - return ctx + return fmt.Sprintf("%s.%s", c.path, path) } func (c *context) withIndex(idx uint) *context { - ctx := c.copy() - ctx.path += fmt.Sprintf("[%d]", idx) - return ctx + // store current path in the stack for later retrieval + c.pathStack = append(c.pathStack, c.path) + c.path = c.createPathForIndex(idx) + return c } -func (c *context) copy() *context { - return &context{ - parent: c, - idx: c.idx, - size: c.size, - tokens: append(token.Tokens{}, c.tokens...), - path: c.path, - } +func (c *context) createPathForIndex(idx uint) string { + return fmt.Sprintf("%s[%d]", c.path, idx) +} + +func (c *context) popPath() { + // restore previous path from top element in stack and remove it from stack + c.path = c.pathStack[len(c.pathStack)-1] + c.pathStack = c.pathStack[:len(c.pathStack)-1] } func (c *context) next() bool { @@ -184,9 +191,10 @@ func newContext(tokens token.Tokens, mode Mode) *context { } } return &context{ - idx: 0, - size: len(filteredTokens), - tokens: token.Tokens(filteredTokens), - path: "$", + idx: 0, + size: len(filteredTokens), + tokens: token.Tokens(filteredTokens), + path: "$", + pathStack: []string{}, } } diff --git a/parser/parser.go b/parser/parser.go index 2bec5fea..c3f30878 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -58,6 +58,7 @@ func (p *parser) parseSequence(ctx *context) (*ast.SequenceNode, error) { } value, err := p.parseToken(ctx.withIndex(uint(len(node.Values))), tk) + ctx.popPath() if err != nil { return nil, errors.Wrapf(err, "failed to parse sequence value in flow sequence node") } @@ -160,7 +161,7 @@ func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken if tk.Type == token.CommentType { comment = p.parseCommentOnly(ctx) if comment != nil { - comment.SetPath(ctx.withChild(key.GetToken().Value).path) + comment.SetPath(ctx.createPathForChild(key.GetToken().Value)) } tk = ctx.currentToken() } @@ -236,7 +237,7 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) { return nil, errors.Wrapf(err, "failed to parse map key") } keyText := key.GetToken().Value - key.SetPath(ctx.withChild(keyText).path) + key.SetPath(ctx.createPathForChild(keyText)) if err := p.validateMapKey(key.GetToken()); err != nil { return nil, errors.Wrapf(err, "validate mapping key error") } @@ -246,7 +247,9 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) { return nil, errors.ErrSyntax("unexpected map", key.GetToken()) } ctx.progress(1) // progress to value token - if err := p.setSameLineCommentIfExists(ctx.withChild(keyText), key); err != nil { + err = p.setSameLineCommentIfExists(ctx.withChild(keyText), key) + ctx.popPath() + if err != nil { return nil, errors.Wrapf(err, "failed to set same line comment to node") } if key.GetComment() != nil { @@ -256,6 +259,7 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) { } value, err := p.parseMapValue(ctx.withChild(keyText), key, tk) + ctx.popPath() if err != nil { return nil, errors.Wrapf(err, "failed to parse map value") } @@ -264,9 +268,9 @@ func (p *parser) parseMappingValue(ctx *context) (ast.Node, error) { } mvnode := ast.MappingValue(tk, key, value) - mvnode.SetPath(ctx.withChild(keyText).path) + mvnode.SetPath(ctx.createPathForChild(keyText)) node := ast.Mapping(tk, false, mvnode) - node.SetPath(ctx.withChild(keyText).path) + node.SetPath(ctx.createPathForChild(keyText)) ntk := ctx.nextNotCommentToken() antk := ctx.afterNextNotCommentToken() @@ -339,11 +343,12 @@ func (p *parser) parseSequenceEntry(ctx *context) (*ast.SequenceNode, error) { } } value, err := p.parseToken(ctx.withIndex(uint(len(sequenceNode.Values))), ctx.currentToken()) + ctx.popPath() if err != nil { return nil, errors.Wrapf(err, "failed to parse sequence") } if comment != nil { - comment.SetPath(ctx.withIndex(uint(len(sequenceNode.Values))).path) + comment.SetPath(ctx.createPathForIndex(uint(len(sequenceNode.Values)))) sequenceNode.ValueHeadComments = append(sequenceNode.ValueHeadComments, comment) } else { sequenceNode.ValueHeadComments = append(sequenceNode.ValueHeadComments, nil) @@ -621,6 +626,7 @@ func (p *parser) parseMappingKey(ctx *context) (*ast.MappingKeyNode, error) { node.SetPath(ctx.path) ctx.progress(1) // skip mapping key token value, err := p.parseToken(ctx.withChild(keyTk.Value), ctx.currentToken()) + ctx.popPath() if err != nil { return nil, errors.Wrapf(err, "failed to parse map key") }