| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | package parser | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	"github.com/goccy/go-yaml/ast" | 
					
						
							| 
									
										
										
										
											2019-10-24 11:07:40 +09:00
										 |  |  | 	"github.com/goccy/go-yaml/internal/errors" | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	"github.com/goccy/go-yaml/token" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 12:53:30 +09:00
										 |  |  | // Parser convert from token instances to ast | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | type Parser struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 12:53:30 +09:00
										 |  |  | // Context context at parsing | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | type Context struct { | 
					
						
							|  |  |  | 	idx    int | 
					
						
							|  |  |  | 	size   int | 
					
						
							|  |  |  | 	tokens token.Tokens | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) next() bool { | 
					
						
							|  |  |  | 	return ctx.idx < ctx.size | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) previousToken() *token.Token { | 
					
						
							|  |  |  | 	if ctx.idx > 0 { | 
					
						
							|  |  |  | 		return ctx.tokens[ctx.idx-1] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) currentToken() *token.Token { | 
					
						
							|  |  |  | 	if ctx.idx >= ctx.size { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ctx.tokens[ctx.idx] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) nextToken() *token.Token { | 
					
						
							|  |  |  | 	if ctx.size > ctx.idx+1 { | 
					
						
							|  |  |  | 		return ctx.tokens[ctx.idx+1] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) afterNextToken() *token.Token { | 
					
						
							|  |  |  | 	if ctx.size > ctx.idx+2 { | 
					
						
							|  |  |  | 		return ctx.tokens[ctx.idx+2] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ctx *Context) progress(num int) { | 
					
						
							|  |  |  | 	if ctx.size <= ctx.idx+num { | 
					
						
							|  |  |  | 		ctx.idx = ctx.size | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ctx.idx += num | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 12:53:30 +09:00
										 |  |  | func newContext(tokens token.Tokens) *Context { | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	removedCommentTokens := token.Tokens{} | 
					
						
							|  |  |  | 	for _, tk := range tokens { | 
					
						
							|  |  |  | 		if tk.Type == token.CommentType { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		removedCommentTokens.Add(tk) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &Context{ | 
					
						
							|  |  |  | 		idx:    0, | 
					
						
							|  |  |  | 		size:   len(removedCommentTokens), | 
					
						
							|  |  |  | 		tokens: removedCommentTokens, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseMapping(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	node := &ast.FlowMappingNode{ | 
					
						
							|  |  |  | 		Start:  ctx.currentToken(), | 
					
						
							|  |  |  | 		Values: []*ast.MappingValueNode{}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip MappingStart token | 
					
						
							|  |  |  | 	for ctx.next() { | 
					
						
							|  |  |  | 		tk := ctx.currentToken() | 
					
						
							|  |  |  | 		if tk.Type == token.MappingEndType { | 
					
						
							|  |  |  | 			node.End = tk | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} else if tk.Type == token.CollectEntryType { | 
					
						
							|  |  |  | 			ctx.progress(1) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value, err := p.parseToken(ctx, tk) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 			return nil, errors.Wrapf(err, "failed to parse mapping value in mapping node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		mvnode, ok := value.(*ast.MappingValueNode) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 			return nil, errors.ErrSyntax("failed to parse flow mapping value node", value.GetToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		node.Values = append(node.Values, mvnode) | 
					
						
							|  |  |  | 		ctx.progress(1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseSequence(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	node := &ast.FlowSequenceNode{ | 
					
						
							|  |  |  | 		Start:  ctx.currentToken(), | 
					
						
							|  |  |  | 		Values: []ast.Node{}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip SequenceStart token | 
					
						
							|  |  |  | 	for ctx.next() { | 
					
						
							|  |  |  | 		tk := ctx.currentToken() | 
					
						
							|  |  |  | 		if tk.Type == token.SequenceEndType { | 
					
						
							|  |  |  | 			node.End = tk | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} else if tk.Type == token.CollectEntryType { | 
					
						
							|  |  |  | 			ctx.progress(1) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value, err := p.parseToken(ctx, tk) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 			return nil, errors.Wrapf(err, "failed to parse sequence value in flow sequence node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		node.Values = append(node.Values, value) | 
					
						
							|  |  |  | 		ctx.progress(1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseTag(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	node := &ast.TagNode{Start: ctx.currentToken()} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip tag token | 
					
						
							|  |  |  | 	value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parse tag value") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	node.Value = value | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) isMapNode(node ast.Node) bool { | 
					
						
							|  |  |  | 	if _, ok := node.(*ast.MappingValueNode); ok { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | func (p *Parser) validateMapKey(tk *token.Token) error { | 
					
						
							|  |  |  | 	if tk.Type != token.StringType { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	origin := strings.TrimLeft(tk.Origin, "\n") | 
					
						
							|  |  |  | 	if strings.Index(origin, "\n") > 0 { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return errors.ErrSyntax("unexpected key name", tk) | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | func (p *Parser) parseMappingValue(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	key := p.parseMapKey(ctx.currentToken()) | 
					
						
							|  |  |  | 	if key == nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected mapping 'key'. key is undefined", ctx.currentToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 	if err := p.validateMapKey(key.GetToken()); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "validate mapping key error") | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	if _, ok := key.(ast.ScalarNode); !ok { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected mapping 'key', key is not scalar value", key.GetToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1)          // progress to mapping value token | 
					
						
							|  |  |  | 	tk := ctx.currentToken() // get mapping value token | 
					
						
							|  |  |  | 	ctx.progress(1)          // progress to value token | 
					
						
							|  |  |  | 	value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parse mapping 'value' node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-21 15:58:46 +09:00
										 |  |  | 	keyColumn := key.GetToken().Position.Column | 
					
						
							|  |  |  | 	valueColumn := value.GetToken().Position.Column | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 	if keyColumn == valueColumn { | 
					
						
							|  |  |  | 		if value.Type() == ast.StringType { | 
					
						
							|  |  |  | 			ntk := ctx.nextToken() | 
					
						
							|  |  |  | 			if ntk == nil || (ntk.Type != token.MappingValueType && ntk.Type != token.SequenceEntryType) { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 				return nil, errors.ErrSyntax("could not found expected ':' token", value.GetToken()) | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	mvnode := &ast.MappingValueNode{ | 
					
						
							|  |  |  | 		Start: tk, | 
					
						
							|  |  |  | 		Key:   key, | 
					
						
							|  |  |  | 		Value: value, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ntk := ctx.nextToken() | 
					
						
							|  |  |  | 	antk := ctx.afterNextToken() | 
					
						
							| 
									
										
										
										
											2019-10-23 20:22:14 +09:00
										 |  |  | 	node := &ast.MappingCollectionNode{ | 
					
						
							|  |  |  | 		Start:  tk, | 
					
						
							|  |  |  | 		Values: []ast.Node{mvnode}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	for antk != nil && antk.Type == token.MappingValueType && | 
					
						
							| 
									
										
										
										
											2019-10-21 15:58:46 +09:00
										 |  |  | 		ntk.Position.Column == key.GetToken().Position.Column { | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		ctx.progress(1) | 
					
						
							|  |  |  | 		value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 			return nil, errors.Wrapf(err, "failed to parse mapping collection node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 		if c, ok := value.(*ast.MappingCollectionNode); ok { | 
					
						
							|  |  |  | 			for _, v := range c.Values { | 
					
						
							|  |  |  | 				node.Values = append(node.Values, v) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			node.Values = append(node.Values, value) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		ntk = ctx.nextToken() | 
					
						
							|  |  |  | 		antk = ctx.afterNextToken() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 20:22:14 +09:00
										 |  |  | 	if len(node.Values) == 1 { | 
					
						
							|  |  |  | 		return mvnode, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseSequenceEntry(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	tk := ctx.currentToken() | 
					
						
							|  |  |  | 	sequenceNode := &ast.SequenceNode{ | 
					
						
							|  |  |  | 		Start:  tk, | 
					
						
							|  |  |  | 		Values: []ast.Node{}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 20:22:14 +09:00
										 |  |  | 	curColumn := tk.Position.Column | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	for tk.Type == token.SequenceEntryType { | 
					
						
							|  |  |  | 		ctx.progress(1) // skip sequence token | 
					
						
							|  |  |  | 		value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 			return nil, errors.Wrapf(err, "failed to parse sequence") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		sequenceNode.Values = append(sequenceNode.Values, value) | 
					
						
							|  |  |  | 		tk = ctx.nextToken() | 
					
						
							|  |  |  | 		if tk == nil { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tk.Type != token.SequenceEntryType { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-23 20:22:14 +09:00
										 |  |  | 		if tk.Position.Column != curColumn { | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ctx.progress(1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return sequenceNode, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseAnchor(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	tk := ctx.currentToken() | 
					
						
							|  |  |  | 	anchor := &ast.AnchorNode{Start: tk} | 
					
						
							|  |  |  | 	ntk := ctx.nextToken() | 
					
						
							|  |  |  | 	if ntk == nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected anchor. anchor name is undefined", tk) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip anchor token | 
					
						
							|  |  |  | 	name, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parser anchor name node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	anchor.Name = name | 
					
						
							|  |  |  | 	ntk = ctx.nextToken() | 
					
						
							|  |  |  | 	if ntk == nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected anchor. anchor value is undefined", ctx.currentToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1) | 
					
						
							|  |  |  | 	value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parser anchor name node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	anchor.Value = value | 
					
						
							|  |  |  | 	return anchor, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseAlias(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	tk := ctx.currentToken() | 
					
						
							|  |  |  | 	alias := &ast.AliasNode{Start: tk} | 
					
						
							|  |  |  | 	ntk := ctx.nextToken() | 
					
						
							|  |  |  | 	if ntk == nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected alias. alias name is undefined", tk) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip alias token | 
					
						
							|  |  |  | 	name, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parser alias name node") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	alias.Value = name | 
					
						
							|  |  |  | 	return alias, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseMapKey(tk *token.Token) ast.Node { | 
					
						
							|  |  |  | 	if node := p.parseStringValue(tk); node != nil { | 
					
						
							|  |  |  | 		return node | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if tk.Type == token.MergeKeyType { | 
					
						
							|  |  |  | 		return ast.MergeKey(tk) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseStringValue(tk *token.Token) ast.Node { | 
					
						
							|  |  |  | 	switch tk.Type { | 
					
						
							|  |  |  | 	case token.StringType, | 
					
						
							|  |  |  | 		token.SingleQuoteType, | 
					
						
							|  |  |  | 		token.DoubleQuoteType: | 
					
						
							|  |  |  | 		return ast.String(tk) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseScalarValue(tk *token.Token) ast.Node { | 
					
						
							|  |  |  | 	if node := p.parseStringValue(tk); node != nil { | 
					
						
							|  |  |  | 		return node | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch tk.Type { | 
					
						
							|  |  |  | 	case token.NullType: | 
					
						
							|  |  |  | 		return ast.Null(tk) | 
					
						
							|  |  |  | 	case token.BoolType: | 
					
						
							|  |  |  | 		return ast.Bool(tk) | 
					
						
							| 
									
										
										
										
											2019-10-29 19:08:02 +09:00
										 |  |  | 	case token.IntegerType, | 
					
						
							|  |  |  | 		token.BinaryIntegerType, | 
					
						
							|  |  |  | 		token.OctetIntegerType, | 
					
						
							|  |  |  | 		token.HexIntegerType: | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		return ast.Integer(tk) | 
					
						
							|  |  |  | 	case token.FloatType: | 
					
						
							|  |  |  | 		return ast.Float(tk) | 
					
						
							|  |  |  | 	case token.InfinityType: | 
					
						
							|  |  |  | 		return ast.Infinity(tk) | 
					
						
							|  |  |  | 	case token.NanType: | 
					
						
							|  |  |  | 		return ast.Nan(tk) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseDirective(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	node := &ast.DirectiveNode{Start: ctx.currentToken()} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip directive token | 
					
						
							|  |  |  | 	value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parse directive value") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	node.Value = value | 
					
						
							|  |  |  | 	ctx.progress(1) | 
					
						
							|  |  |  | 	if ctx.currentToken().Type != token.DocumentHeaderType { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected directive value. document not started", ctx.currentToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseLiteral(ctx *Context) (ast.Node, error) { | 
					
						
							|  |  |  | 	node := &ast.LiteralNode{Start: ctx.currentToken()} | 
					
						
							|  |  |  | 	ctx.progress(1) // skip literal/folded token | 
					
						
							|  |  |  | 	value, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.Wrapf(err, "failed to parse literal/folded value") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	snode, ok := value.(*ast.StringNode) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:30:22 +09:00
										 |  |  | 		return nil, errors.ErrSyntax("unexpected token. required string token", value.GetToken()) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	node.Value = snode | 
					
						
							|  |  |  | 	return node, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Parser) parseToken(ctx *Context, tk *token.Token) (ast.Node, error) { | 
					
						
							|  |  |  | 	if tk.NextType() == token.MappingValueType { | 
					
						
							|  |  |  | 		return p.parseMappingValue(ctx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if node := p.parseScalarValue(tk); node != nil { | 
					
						
							|  |  |  | 		return node, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch tk.Type { | 
					
						
							|  |  |  | 	case token.MappingStartType: | 
					
						
							|  |  |  | 		return p.parseMapping(ctx) | 
					
						
							|  |  |  | 	case token.SequenceStartType: | 
					
						
							|  |  |  | 		return p.parseSequence(ctx) | 
					
						
							|  |  |  | 	case token.SequenceEntryType: | 
					
						
							|  |  |  | 		return p.parseSequenceEntry(ctx) | 
					
						
							|  |  |  | 	case token.AnchorType: | 
					
						
							|  |  |  | 		return p.parseAnchor(ctx) | 
					
						
							|  |  |  | 	case token.AliasType: | 
					
						
							|  |  |  | 		return p.parseAlias(ctx) | 
					
						
							|  |  |  | 	case token.DirectiveType: | 
					
						
							|  |  |  | 		return p.parseDirective(ctx) | 
					
						
							|  |  |  | 	case token.TagType: | 
					
						
							|  |  |  | 		return p.parseTag(ctx) | 
					
						
							|  |  |  | 	case token.LiteralType, token.FoldedType: | 
					
						
							|  |  |  | 		return p.parseLiteral(ctx) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 12:53:30 +09:00
										 |  |  | // Parse parse from token instances, and returns ast.Document | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | func (p *Parser) Parse(tokens token.Tokens) (*ast.Document, error) { | 
					
						
							| 
									
										
										
										
											2019-10-21 12:53:30 +09:00
										 |  |  | 	ctx := newContext(tokens) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 	doc := &ast.Document{Nodes: []ast.Node{}} | 
					
						
							|  |  |  | 	for ctx.next() { | 
					
						
							|  |  |  | 		node, err := p.parseToken(ctx, ctx.currentToken()) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 03:21:42 +09:00
										 |  |  | 			return nil, errors.Wrapf(err, "failed to parse") | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-18 14:27:49 +09:00
										 |  |  | 		ctx.progress(1) | 
					
						
							|  |  |  | 		if node == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(doc.Nodes) == 0 { | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 			doc.Nodes = append(doc.Nodes, node) | 
					
						
							| 
									
										
										
										
											2019-10-18 14:27:49 +09:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, ok := node.(*ast.MappingValueNode); !ok { | 
					
						
							|  |  |  | 			doc.Nodes = append(doc.Nodes, node) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		lastNode := doc.Nodes[len(doc.Nodes)-1] | 
					
						
							|  |  |  | 		switch n := lastNode.(type) { | 
					
						
							|  |  |  | 		case *ast.MappingValueNode: | 
					
						
							|  |  |  | 			doc.Nodes[len(doc.Nodes)-1] = &ast.MappingCollectionNode{ | 
					
						
							|  |  |  | 				Start:  n.GetToken(), | 
					
						
							|  |  |  | 				Values: []ast.Node{lastNode, node}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case *ast.MappingCollectionNode: | 
					
						
							|  |  |  | 			n.Values = append(n.Values, node) | 
					
						
							| 
									
										
										
										
											2019-10-16 18:21:20 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return doc, nil | 
					
						
							|  |  |  | } |