func (p *parser) parseMustache() *ast.MustacheStatement {
	tok := p.shift()
	closeToken := lexer.TokenClose
	if tok.Kind == lexer.TokenOpenUnescaped {
		closeToken = lexer.TokenCloseUnescaped
	}
	unescaped := false
	if (tok.Kind == lexer.TokenOpenUnescaped) || (rOpenAmp.MatchString(tok.Val)) {
		unescaped = true
	}
	result := ast.NewMustacheStatement(tok.Pos, tok.Line, unescaped)
	result.Expression = p.parseExpression(tok)
	tokClose := p.shift()
	if tokClose.Kind != closeToken {
		errExpected(closeToken, tokClose)
	}
	result.Strip = ast.NewStrip(tok.Val, tokClose.Val)
	return result
}
mustache : OPEN helperName param* hash? CLOSE
| OPEN_UNESCAPED helperName param* hash? CLOSE_UNESCAPED
package parser
import (
	"fmt"
	"regexp"
	"runtime"
	"strconv"
	"github.com/aymerick/raymond/ast"
	"github.com/aymerick/raymond/lexer"
)
type parser struct {
	lex *lexer.Lexer
	root ast.Node
	tokens []*lexer.Token
	lexOver bool
}
var (
	rOpenComment  = regexp.MustCompile(`^\{\{~?!-?-?`)
	rCloseComment = regexp.MustCompile(`-?-?~?\}\}$`)
	rOpenAmp      = regexp.MustCompile(`^\{\{~?&`)
)
func new(input string) *parser {
	return &parser{
		lex: lexer.Scan(input),
	}
}
func Parse(input string) (result *ast.Program, err error) {
	defer errRecover(&err)
	parser := new(input)
	result = parser.parseProgram()
	token := parser.shift()
	if token.Kind != lexer.TokenEOF {
		errToken(token, "Syntax error")
	}
	processWhitespaces(result)
	return
}
func errRecover(errp *error) {
	e := recover()
	if e != nil {
		switch err := e.(type) {
		case runtime.Error:
			panic(e)
		case error:
			*errp = err
		default:
			panic(e)
		}
	}
}
func errPanic(err error, line int) {
	panic(fmt.Errorf("Parse error on line %d:\n%s", line, err))
}
func errNode(node ast.Node, msg string) {
	errPanic(fmt.Errorf("%s\nNode: %s", msg, node), node.Location().Line)
}
func errToken(tok *lexer.Token, msg string) {
	errPanic(fmt.Errorf("%s\nToken: %s", msg, tok), tok.Line)
}
func errExpected(expect lexer.TokenKind, tok *lexer.Token) {
	errPanic(fmt.Errorf("Expecting %s, got: '%s'", expect, tok), tok.Line)
}
func (p *parser) parseProgram() *ast.Program {
	result := ast.NewProgram(p.next().Pos, p.next().Line)
	for p.isStatement() {
		result.AddStatement(p.parseStatement())
	}
	return result
}
func (p *parser) parseStatement() ast.Node {
	var result ast.Node
	tok := p.next()
	switch tok.Kind {
	case lexer.TokenOpen, lexer.TokenOpenUnescaped:
		result = p.parseMustache()
	case lexer.TokenOpenBlock:
		result = p.parseBlock()
	case lexer.TokenOpenInverse:
		result = p.parseInverse()
	case lexer.TokenOpenRawBlock:
		result = p.parseRawBlock()
	case lexer.TokenOpenPartial:
		result = p.parsePartial()
	case lexer.TokenContent:
		result = p.parseContent()
	case lexer.TokenComment:
		result = p.parseComment()
	}
	return result
}
func (p *parser) isStatement() bool {
	if !p.have(1) {
		return false
	}
	switch p.next().Kind {
	case lexer.TokenOpen, lexer.TokenOpenUnescaped, lexer.TokenOpenBlock,
		lexer.TokenOpenInverse, lexer.TokenOpenRawBlock, lexer.TokenOpenPartial,
		lexer.TokenContent, lexer.TokenComment:
		return true
	}
	return false
}
func (p *parser) parseContent() *ast.ContentStatement {
	tok := p.shift()
	if tok.Kind != lexer.TokenContent {
		errExpected(lexer.TokenContent, tok)
	}
	return ast.NewContentStatement(tok.Pos, tok.Line, tok.Val)
}
func (p *parser) parseComment() *ast.CommentStatement {
	tok := p.shift()
	value := rOpenComment.ReplaceAllString(tok.Val, "")
	value = rCloseComment.ReplaceAllString(value, "")
	result := ast.NewCommentStatement(tok.Pos, tok.Line, value)
	result.Strip = ast.NewStripForStr(tok.Val)
	return result
}
func (p *parser) parseExpressionParamsHash() ([]ast.Node, *ast.Hash) {
	var params []ast.Node
	var hash *ast.Hash
	if p.isParam() {
		params = p.parseParams()
	}
	if p.isHashSegment() {
		hash = p.parseHash()
	}
	return params, hash
}
func (p *parser) parseExpression(tok *lexer.Token) *ast.Expression {
	result := ast.NewExpression(tok.Pos, tok.Line)
	result.Path = p.parseHelperName()
	result.Params, result.Hash = p.parseExpressionParamsHash()
	return result
}
func (p *parser) parseRawBlock() *ast.BlockStatement {
	tok := p.shift()
	result := ast.NewBlockStatement(tok.Pos, tok.Line)
	result.Expression = p.parseExpression(tok)
	openName := result.Expression.Canonical()
	tok = p.shift()
	if tok.Kind != lexer.TokenCloseRawBlock {
		errExpected(lexer.TokenCloseRawBlock, tok)
	}
	content := p.parseContent()
	program := ast.NewProgram(tok.Pos, tok.Line)
	program.AddStatement(content)
	result.Program = program
	tok = p.shift()
	if tok.Kind != lexer.TokenOpenEndRawBlock {
		errExpected(lexer.TokenOpenEndRawBlock, tok)
	}
	endID := p.parseHelperName()
	closeName, ok := ast.HelperNameStr(endID)
	if !ok {
		errNode(endID, "Erroneous closing expression")
	}
	if openName != closeName {
		errNode(endID, fmt.Sprintf("%s doesn't match %s", openName, closeName))
	}
	tok = p.shift()
	if tok.Kind != lexer.TokenCloseRawBlock {
		errExpected(lexer.TokenCloseRawBlock, tok)
	}
	return result
}
func (p *parser) parseBlock() *ast.BlockStatement {
	result, blockParams := p.parseOpenBlock()
	program := p.parseProgram()
	program.BlockParams = blockParams
	result.Program = program
	if p.isInverseChain() {
		result.Inverse = p.parseInverseChain()
	}
	p.parseCloseBlock(result)
	setBlockInverseStrip(result)
	return result
}
func setBlockInverseStrip(block *ast.BlockStatement) {
	if block.Inverse == nil {
		return
	}
	if block.Inverse.Chained {
		b, _ := block.Inverse.Body[0].(*ast.BlockStatement)
		b.CloseStrip = block.CloseStrip
	}
	block.InverseStrip = block.Inverse.Strip
}
func (p *parser) parseInverse() *ast.BlockStatement {
	result, blockParams := p.parseOpenBlock()
	program := p.parseProgram()
	program.BlockParams = blockParams
	result.Inverse = program
	if p.isInverse() {
		result.Program = p.parseInverseAndProgram()
	}
	p.parseCloseBlock(result)
	setBlockInverseStrip(result)
	return result
}
func (p *parser) parseOpenBlockExpression(tok *lexer.Token) (*ast.BlockStatement, []string) {
	var blockParams []string
	result := ast.NewBlockStatement(tok.Pos, tok.Line)
	result.Expression = p.parseExpression(tok)
	if p.isBlockParams() {
		blockParams = p.parseBlockParams()
	}
	return result, blockParams
}
func (p *parser) parseInverseChain() *ast.Program {
	if p.isInverse() {
		return p.parseInverseAndProgram()
	}
	result := ast.NewProgram(p.next().Pos, p.next().Line)
	block, blockParams := p.parseOpenBlock()
	program := p.parseProgram()
	program.BlockParams = blockParams
	block.Program = program
	if p.isInverseChain() {
		block.Inverse = p.parseInverseChain()
	}
	setBlockInverseStrip(block)
	result.Chained = true
	result.AddStatement(block)
	return result
}
func (p *parser) isInverseChain() bool {
	return p.isOpenInverseChain() || p.isInverse()
}
func (p *parser) parseInverseAndProgram() *ast.Program {
	tok := p.shift()
	result := p.parseProgram()
	result.Strip = ast.NewStripForStr(tok.Val)
	return result
}
func (p *parser) parseOpenBlock() (*ast.BlockStatement, []string) {
	tok := p.shift()
	result, blockParams := p.parseOpenBlockExpression(tok)
	tokClose := p.shift()
	if tokClose.Kind != lexer.TokenClose {
		errExpected(lexer.TokenClose, tokClose)
	}
	result.OpenStrip = ast.NewStrip(tok.Val, tokClose.Val)
	return result, blockParams
}
func (p *parser) parseCloseBlock(block *ast.BlockStatement) {
	tok := p.shift()
	if tok.Kind != lexer.TokenOpenEndBlock {
		errExpected(lexer.TokenOpenEndBlock, tok)
	}
	endID := p.parseHelperName()
	closeName, ok := ast.HelperNameStr(endID)
	if !ok {
		errNode(endID, "Erroneous closing expression")
	}
	openName := block.Expression.Canonical()
	if openName != closeName {
		errNode(endID, fmt.Sprintf("%s doesn't match %s", openName, closeName))
	}
	tokClose := p.shift()
	if tokClose.Kind != lexer.TokenClose {
		errExpected(lexer.TokenClose, tokClose)
	}
	block.CloseStrip = ast.NewStrip(tok.Val, tokClose.Val)
}