func parseEscapedRune(s []byte) (rune, int) {
	switch s[1] {
	case 'a':
		return '\a', 1
	case 'b':
		return '\b', 1
	case 'f':
		return '\f', 1
	case 'n':
		return '\n', 1
	case 'r':
		return '\r', 1
	case 't':
		return '\t', 1
	case 'v':
		return '\v', 1
	case '\\':
		return '\\', 1
	case '\'':
		return '\'', 1
	case '"':
		return '"', 1
	case 'x', 'u', 'U':
		var n = 2
		switch s[1] {
		case 'u':
			n = 4
		case 'U':
			n = 8
		}
		var r rune
		for j := 2; j < n+2; j++ {
			r = r * 16
			c := s[j]
			switch {
			case '0' <= c && c <= '9':
				r += rune(c - '0')
			case 'a' <= c && c <= 'f':
				r += rune(c - 'a' + 10)
			case 'A' <= c && c <= 'F':
				r += rune(c - 'A' + 10)
			}
		}
		return r, n + 1
	case '0', '1', '2', '3', '4', '5', '6', '7':
		r := (s[1]-'0')*64 + (s[2]-'0')*8 + (s[3] - '0')
		return rune(r), 3
	}
	panic("unexpected escaped rune")
}
parseEscapedRune parses an escaped rune sequence starting with '\\' and
returns the rune and the length of the parsed sequence.
package compiler
import (
	"bytes"
	"unicode/utf8"
	"github.com/open2b/scriggo/ast"
)
func (p *parsing) parseExpr(tok token, canBeSwitchGuard, canElideType, mustBeType, nextIsBlockBrace bool) (ast.Expression, token) {
	canCompositeLiteral := false
	var path []ast.Operator
	var mustBeSwitchGuard bool
	for {
		var operand ast.Expression
		var operator ast.Operator
		switch tok.typ {
		case tokenLeftParenthesis:  
			pos := tok.pos
			var expr ast.Expression
			expr, tok = p.parseExpr(p.next(), false, false, mustBeType, false)
			if expr == nil {
				panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
			}
			if tok.typ != tokenRightParenthesis {
				panic(syntaxError(tok.pos, "unexpected %s, expecting )", tok))
			}
			expr.SetParenthesis(expr.Parenthesis() + 1)
			operand = expr
			operand.Pos().Start = pos.Start
			operand.Pos().End = tok.pos.End
			tok = p.next()
		case tokenMap:  
			canCompositeLiteral = true
			mapType := ast.NewMapType(tok.pos, nil, nil)
			tok = p.next()
			if tok.typ != tokenLeftBracket {
				panic(syntaxError(tok.pos, "unexpected %s, expecting [", tok))
			}
			var typ ast.Expression
			typ, tok = p.parseExpr(p.next(), false, false, true, false)
			if tok.typ != tokenRightBracket {
				panic(syntaxError(tok.pos, "unexpected %s, expecting %s", tok, tokenRightBrace))
			}
			mapType.KeyType = typ
			typ, tok = p.parseExpr(p.next(), false, false, true, false)
			if typ == nil {
				panic(syntaxError(tok.pos, "unexpected %s, expecting type", tok))
			}
			mapType.Position.End = typ.Pos().End
			mapType.ValueType = typ
			operand = mapType
		case tokenStruct:  
			canCompositeLiteral = true
			pos := tok.pos
			tok = p.next()
			if tok.typ != tokenLeftBrace {
				panic(syntaxError(tok.pos, "unexpected %s, expecting {", tok))
			}
			tok = p.next()
			var fields []*ast.Field
			for tok.typ != tokenRightBrace {
				var field *ast.Field
				field, tok = p.parseField(tok)
				fields = append(fields, field)
			}
			operand = ast.NewStructType(pos.WithEnd(tok.pos.End), fields)
			tok = p.next()
		case tokenInterface:  
			pos := tok.pos
			tok = p.next()
			if tok.typ != tokenLeftBrace {
				panic(syntaxError(tok.pos, "unexpected %s, expecting {", tok))
			}
			tok = p.next()
			if tok.typ != tokenRightBrace {
				if tok.typ == tokenIdentifier {
					panic(syntaxError(tok.pos, "non-empty interfaces are not supported in this release of Scriggo"))
				}
				panic(syntaxError(tok.pos, "unexpected %s, expecting }", tok))
			}
			pos.End = tok.pos.End
			operand = ast.NewInterface(pos)
			tok = p.next()
		case tokenFunc:  
			var node ast.Node
			if mustBeType {
				node, tok = p.parseFunc(tok, parseFuncType)
			} else {
				node, tok = p.parseFunc(tok, parseFuncType|parseFuncLit)
			}
			operand = node.(ast.Expression)
		case tokenMacro:  
			var node ast.Node
			node, tok = p.parseFunc(tok, parseFuncType)
			operand = node.(ast.Expression)
		case
			tokenArrow,  
			tokenChan:   
			pos := tok.pos
			direction := ast.NoDirection
			if tok.typ == tokenArrow {
				tok = p.next()
				if tok.typ == tokenChan {
					direction = ast.ReceiveDirection
				} else {
					operator = ast.NewUnaryOperator(pos, ast.OperatorReceive, nil)
					if mustBeType {
						panic(syntaxError(tok.pos, "unexpected %s, expecting type", operator))
					}
				}
			}
			if operator == nil {
				tok = p.next()
				if direction == ast.NoDirection && tok.typ == tokenArrow {
					direction = ast.SendDirection
					tok = p.next()
				}
				var elemType ast.Expression
				elemType, tok = p.parseExpr(tok, false, false, true, false)
				if elemType == nil {
					panic(syntaxError(tok.pos, "missing channel element type"))
				}
				pos.End = elemType.Pos().End
				operand = ast.NewChanType(pos, direction, elemType)
			}
		case
			tokenAddition,        
			tokenSubtraction,     
			tokenNot,             
			tokenExtendedNot,     
			tokenXor,             
			tokenMultiplication,  
			tokenAmpersand:       
			operator = ast.NewUnaryOperator(tok.pos, operatorFromTokenType(tok.typ, false), nil)
			if mustBeType && tok.typ != tokenMultiplication {
				panic(syntaxError(tok.pos, "unexpected %s, expecting type", tok.txt))
			}
			tok = p.next()
		case tokenDollar:  
			pos := tok.pos
			tok = p.next()
			if tok.typ != tokenIdentifier {
				panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok.txt))
			}
			if len(tok.txt) == 1 && tok.txt[0] == '_' {
				panic(syntaxError(tok.pos, "cannot use _ as value"))
			}
			ident := p.parseIdentifierNode(tok)
			operand = ast.NewDollarIdentifier(pos.WithEnd(tok.pos.End), ident)
			tok = p.next()
		case
			tokenRune,       
			tokenInt,        
			tokenFloat,      
			tokenImaginary:  
			if mustBeType {
				panic(syntaxError(tok.pos, "unexpected literal %s, expecting type", tok.txt))
			}
			operand = ast.NewBasicLiteral(tok.pos, literalType(tok.typ), string(tok.txt))
			tok = p.next()
		case
			tokenInterpretedString,  
			tokenRawString:          
			if mustBeType {
				panic(syntaxError(tok.pos, "unexpected literal %s, expecting type", tok.txt))
			}
			operand = ast.NewBasicLiteral(tok.pos, literalType(tok.typ), string(tok.txt))
			tok = p.next()
		case tokenIdentifier:  
			ident := p.parseIdentifierNode(tok)
			operand = ident
			tok = p.next()
			if mustBeType {
				if tok.typ == tokenPeriod {
					tok = p.next()
					if tok.typ != tokenIdentifier {
						panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok.txt))
					}
					ident := p.parseIdentifierNode(tok)
					operand = ast.NewSelector(tok.pos, operand, ident.Name)
					tok = p.next()
				}
			}
		case tokenLeftBracket:  
			canCompositeLiteral = true
			var expr, length ast.Expression
			pos := tok.pos
			isEllipsis := false
			tok = p.next()
			switch tok.typ {
			case tokenEllipsis:
				isEllipsis = true
				tok = p.next()
			case tokenRightBracket:
			default:
				oldTok := tok
				expr, tok = p.parseExpr(tok, false, false, false, false)
				if expr == nil {
					panic(syntaxError(tok.pos, "unexpected %s, expecting expression", oldTok))
				}
				length = expr
			}
			if tok.typ != tokenRightBracket {
				panic(syntaxError(tok.pos, "unexpected %s, expecting ]", tok))
			}
			var typ ast.Expression
			typ, tok = p.parseExpr(p.next(), false, false, true, false)
			if typ == nil {
				panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
			}
			pos.End = typ.Pos().End
			switch {
			case isEllipsis:
				operand = ast.NewArrayType(pos, nil, typ)
			case length == nil:
				operand = ast.NewSliceType(pos, typ)
			default:
				operand = ast.NewArrayType(pos, length, typ)
			}
		case tokenRender:
			pos := tok.pos
			tok = p.next()
			if tok.typ != tokenInterpretedString && tok.typ != tokenRawString {
				panic(syntaxError(tok.pos, "unexpected %s, expecting string", tok))
			}
			var path = unquoteString(tok.txt)
			if !ValidTemplatePath(path) {
				panic(syntaxError(tok.pos, "invalid file path: %q", path))
			}
			pos.End = tok.pos.End
			operand = ast.NewRender(pos, path)
			p.unexpanded = append(p.unexpanded, operand)
			tok = p.next()
		default:
			if tok.typ == tokenLeftBrace && canElideType {  
				break
			}
			if len(path) > 0 {
				if mustBeType {
					panic(syntaxError(tok.pos, "unexpected %s, expecting type", tok))
				}
				panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
			}
			return nil, tok
		}
		for operator == nil {
			dontEatLeftBraces := tok.typ == tokenLeftBrace && nextIsBlockBrace && !canCompositeLiteral
			if dontEatLeftBraces || mustBeType {
				if len(path) > 0 {
					if operand == nil {
						panic(syntaxError(tok.pos, "unexpected {, expecting expression"))
					}
					operand = addLastOperand(operand, path)
				}
				return operand, tok
			}
			switch tok.typ {
			case tokenLeftBrace:  
				canCompositeLiteral = false
				if operand != nil && operand.Parenthesis() > 0 {
					panic(syntaxError(tok.pos, "cannot parenthesize type in composite literal"))
				}
				pos := &ast.Position{Line: tok.pos.Line, Column: tok.pos.Column, Start: tok.pos.Start, End: tok.pos.End}
				if operand != nil {
					pos.Start = operand.Pos().Start
				}
				var keyValues []ast.KeyValue
				var expr ast.Expression
				for {
					expr, tok = p.parseExpr(p.next(), false, true, false, false)
					if expr == nil {
						break
					}
					switch tok.typ {
					case tokenColon:
						var value ast.Expression
						value, tok = p.parseExpr(p.next(), false, true, false, false)
						if value == nil {
							panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
						}
						keyValues = append(keyValues, ast.KeyValue{Key: expr, Value: value})
					case tokenComma, tokenRightBrace:
						keyValues = append(keyValues, ast.KeyValue{Key: nil, Value: expr})
					default:
						panic(syntaxError(tok.pos, "unexpected %s, expecting comma or }", tok))
					}
					if tok.typ == tokenRightBrace {
						break
					}
				}
				if tok.typ != tokenRightBrace {
					panic(syntaxError(tok.pos, "unexpected %s, expecting expression or }", tok))
				}
				pos.End = tok.pos.End
				operand = ast.NewCompositeLiteral(pos, operand, keyValues)
				tok = p.next()
			case tokenLeftParenthesis:  
				pos := tok.pos
				pos.Start = operand.Pos().Start
				var args []ast.Expression
				args, tok = p.parseExprListInParenthesis(p.next())
				var isVariadic bool
				if tok.typ == tokenEllipsis {
					if args == nil {
						panic(syntaxError(tok.pos, "unexpected ..., expecting expression"))
					}
					isVariadic = true
					tok = p.next()
				}
				if tok.typ != tokenRightParenthesis {
					panic(syntaxError(tok.pos, "unexpected %s, expecting expression or )", tok))
				}
				pos.End = tok.pos.End
				operand = ast.NewCall(pos, operand, args, isVariadic)
				canCompositeLiteral = false
				tok = p.next()
			case tokenLeftBracket:  
				pos := tok.pos
				pos.Start = operand.Pos().Start
				var index ast.Expression
				index, tok = p.parseExpr(p.next(), false, false, false, false)
				if tok.typ == tokenColon {
					low := index
					isFull := false
					var high, max ast.Expression
					high, tok = p.parseExpr(p.next(), false, false, false, false)
					if tok.typ == tokenColon {
						isFull = true
						max, tok = p.parseExpr(p.next(), false, false, false, false)
					}
					if tok.typ != tokenRightBracket {
						panic(syntaxError(tok.pos, "unexpected %s, expecting ]", tok))
					}
					pos.End = tok.pos.End
					operand = ast.NewSlicing(pos, operand, low, high, max, isFull)
				} else {
					if tok.typ != tokenRightBracket {
						panic(syntaxError(tok.pos, "unexpected %s, expecting ]", tok))
					}
					if index == nil {
						panic(syntaxError(tok.pos, "unexpected ], expecting expression"))
					}
					pos.End = tok.pos.End
					operand = ast.NewIndex(pos, operand, index)
				}
				tok = p.next()
			case tokenPeriod:  
				pos := tok.pos
				pos.Start = operand.Pos().Start
				tok = p.next()
				switch tok.typ {
				case tokenIdentifier:
					ident := string(tok.txt)
					pos.End = tok.pos.End
					operand = ast.NewSelector(pos, operand, ident)
				case tokenLeftParenthesis:
					tok = p.next()
					var typ ast.Expression
					switch tok.typ {
					case tokenType:
						if !canBeSwitchGuard {
							panic(syntaxError(tok.pos, "use of .(type) outside type switch"))
						}
						mustBeSwitchGuard = true
						tok = p.next()
					case tokenIdentifier:
						if len(tok.txt) == 1 && tok.txt[0] == '_' {
							panic(syntaxError(tok.pos, "cannot use _ as value"))
						}
						fallthrough
					default:
						typ, tok = p.parseExpr(tok, true, false, true, false)
						if typ == nil {
							panic(syntaxError(tok.pos, "unexpected %s, expecting type", tok))
						}
					}
					if tok.typ != tokenRightParenthesis {
						panic(syntaxError(tok.pos, "unexpected %s, expecting )", tok))
					}
					pos.End = tok.pos.End
					operand = ast.NewTypeAssertion(pos, operand, typ)
				default:
					panic(syntaxError(tok.pos, "unexpected %s, expecting name or (", tok))
				}
				tok = p.next()
			case
				tokenEqual,           
				tokenNotEqual,        
				tokenLess,            
				tokenLessOrEqual,     
				tokenGreater,         
				tokenGreaterOrEqual,  
				tokenAnd,             
				tokenOr,              
				tokenExtendedAnd,     
				tokenExtendedOr,      
				tokenAddition,        
				tokenSubtraction,     
				tokenMultiplication,  
				tokenDivision,        
				tokenModulo,          
				tokenAmpersand,       
				tokenVerticalBar,     
				tokenXor,             
				tokenAndNot,          
				tokenLeftShift,       
				tokenRightShift,      
				tokenContains:        
				operator = ast.NewBinaryOperator(tok.pos, operatorFromTokenType(tok.typ, true), nil, nil)
				tok = p.next()
			case tokenDefault,  
				tokenExtendedNot:  
				if tok.typ == tokenDefault && p.lex.extendedSyntax {
					pos := tok.pos
					pos.Start = operand.Pos().Start
					node := ast.NewDefault(pos, operand, nil)
					if _, ok := operand.(*ast.Render); ok {
						p.unexpanded[len(p.unexpanded)-1] = node
					}
					node.Expr2, tok = p.parseExpr(p.next(), false, false, false, nextIsBlockBrace)
					if node.Expr2 == nil {
						panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
					}
					node.Pos().End = node.Expr2.Pos().End
					operand = node
					break
				} else if tok.typ == tokenExtendedNot {
					next := p.next()
					if next.typ == tokenContains {
						pos := tok.pos.WithEnd(next.pos.End)
						operator = ast.NewBinaryOperator(pos, ast.OperatorNotContains, nil, nil)
						tok = p.next()
						break
					}
				}
				fallthrough
			default:
				if mustBeSwitchGuard && !isTypeGuard(operand) {
					panic(syntaxError(tok.pos, "use of .(type) outside type switch"))
				}
				if len(path) > 0 {
					operand = addLastOperand(operand, path)
				}
				return operand, tok
			}
		}
		canBeSwitchGuard = false
		switch op := operator.(type) {
		case *ast.UnaryOperator:
			if len(path) > 0 {
				switch leaf := path[len(path)-1].(type) {
				case *ast.UnaryOperator:
					leaf.Expr = op
				case *ast.BinaryOperator:
					leaf.Expr2 = op
				}
			}
			path = append(path, op)
		case *ast.BinaryOperator:
			start := operand.Pos().Start
			for i := len(path) - 1; i >= 0; i-- {
				if o, ok := path[i].(*ast.UnaryOperator); ok {
					o.Position.Start = start
				} else {
					break
				}
			}
			var p = len(path)
			for p > 0 && op.Precedence() <= path[p-1].Precedence() {
				p--
			}
			if p > 0 {
				switch o := path[p-1].(type) {
				case *ast.UnaryOperator:
					o.Expr = op
				case *ast.BinaryOperator:
					o.Expr2 = op
				}
			}
			if p < len(path) {
				switch o := path[len(path)-1].(type) {
				case *ast.UnaryOperator:
					o.Expr = operand
				case *ast.BinaryOperator:
					o.Expr2 = operand
				}
				for i := p; i < len(path); i++ {
					switch o := path[i].(type) {
					case *ast.UnaryOperator:
						o.Position.End = operand.Pos().End
					case *ast.BinaryOperator:
						o.Position.End = operand.Pos().End
					}
				}
				op.Expr1 = path[p]
				op.Position.Start = path[p].Pos().Start
				path[p] = op
				path = path[0 : p+1]
			} else {
				op.Expr1 = operand
				op.Position.Start = operand.Pos().Start
				path = append(path, op)
			}
		}
	}
}
func addLastOperand(op ast.Expression, path []ast.Operator) ast.Expression {
	switch leaf := path[len(path)-1].(type) {
	case *ast.UnaryOperator:
		leaf.Expr = op
	case *ast.BinaryOperator:
		leaf.Expr2 = op
	}
	end := op.Pos().End
	for _, op := range path {
		switch o := op.(type) {
		case *ast.UnaryOperator:
			o.Position.End = end
		case *ast.BinaryOperator:
			o.Position.End = end
		}
	}
	return path[0]
}
func (p *parsing) parseExprList(tok token, allowSwitchGuard, allMustBeTypes, nextIsBlockBrace bool) ([]ast.Expression, token) {
	var element ast.Expression
	var elements []ast.Expression
	for {
		element, tok = p.parseExpr(tok, allowSwitchGuard, false, allMustBeTypes, nextIsBlockBrace)
		if element == nil {
			if elements != nil {
				panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
			}
			return elements, tok
		}
		if elements == nil {
			elements = []ast.Expression{element}
		} else {
			elements = append(elements, element)
		}
		if tok.typ != tokenComma {
			return elements, tok
		}
		tok = p.next()
	}
}
func (p *parsing) parseExprListInParenthesis(tok token) ([]ast.Expression, token) {
	var element ast.Expression
	var elements []ast.Expression
	for {
		element, tok = p.parseExpr(tok, false, false, false, false)
		if element == nil {
			if elements != nil && tok.typ != tokenRightParenthesis {
				panic(syntaxError(tok.pos, "unexpected %s, expecting expression", tok))
			}
			return elements, tok
		}
		if elements == nil {
			elements = []ast.Expression{element}
		} else {
			elements = append(elements, element)
		}
		if tok.typ != tokenComma {
			return elements, tok
		}
		tok = p.next()
	}
}
func (p *parsing) parseField(tok token) (*ast.Field, token) {
	pos := tok.pos
	field := ast.NewField(nil, nil, "")
	switch tok.typ {
	case tokenMultiplication:
		tok = p.next()
		if tok.typ != tokenIdentifier {
			if tok.typ == tokenLeftParenthesis {
				panic(syntaxError(tok.pos, "cannot parenthesize embedded type"))
			}
			panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok))
		}
		var expr ast.Expression = ast.NewIdentifier(tok.pos, string(tok.txt))
		tok = p.next()
		if tok.typ == tokenPeriod {
			tok = p.next()
			if tok.typ != tokenIdentifier {
				panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok))
			}
			expr = ast.NewSelector(tok.pos, expr, string(tok.txt))
			tok = p.next()
		}
		pos = pos.WithEnd(expr.Pos().End)
		field.Type = ast.NewUnaryOperator(pos, ast.OperatorPointer, expr)
	case tokenIdentifier:
		ident := ast.NewIdentifier(pos, string(tok.txt))
		tok = p.next()
		switch tok.typ {
		case tokenPeriod:
			tok = p.next()
			if tok.typ != tokenIdentifier {
				panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok))
			}
			pos = pos.WithEnd(tok.pos.End)
			field.Type = ast.NewSelector(pos, ident, string(tok.txt))
			tok = p.next()
		case tokenComma:
			field.Idents = make([]*ast.Identifier, 1, 2)
			field.Idents[0] = ident
			for tok.typ == tokenComma {
				tok = p.next()
				if tok.typ != tokenIdentifier {
					panic(syntaxError(tok.pos, "unexpected %s, expecting name", tok))
				}
				field.Idents = append(field.Idents, ast.NewIdentifier(tok.pos, string(tok.txt)))
				tok = p.next()
			}
			field.Type, tok = p.parseExpr(tok, false, false, true, false)
			if field.Type == nil {
				panic(syntaxError(tok.pos, "unexpected %s, expecting type", tok))
			}
		case tokenRawString, tokenInterpretedString:
			field.Type = ident
		default:
			field.Type, tok = p.parseExpr(tok, false, false, true, false)
			if field.Type == nil {
				field.Type = ident
			} else {
				field.Idents = []*ast.Identifier{ident}
			}
		}
	case tokenLeftParenthesis:
		panic(syntaxError(tok.pos, "cannot parenthesize embedded type"))
	default:
		panic(syntaxError(tok.pos, "unexpected %s, expecting field name or embedded type", tok))
	}
	switch tok.typ {
	case tokenRawString, tokenInterpretedString:
		field.Tag = unquoteString(tok.txt)
		tok = p.next()
	}
	switch tok.typ {
	case tokenSemicolon:
		tok = p.next()
	case tokenRightBrace:
	default:
		panic(syntaxError(tok.pos, "unexpected %s, expecting semicolon or newline or }", tok))
	}
	return field, tok
}
func literalType(typ tokenTyp) ast.LiteralType {
	switch typ {
	case tokenRawString, tokenInterpretedString:
		return ast.StringLiteral
	case tokenRune:
		return ast.RuneLiteral
	case tokenInt:
		return ast.IntLiteral
	case tokenFloat:
		return ast.FloatLiteral
	case tokenImaginary:
		return ast.ImaginaryLiteral
	default:
		panic("invalid token type")
	}
}
func operatorFromTokenType(typ tokenTyp, binary bool) ast.OperatorType {
	switch typ {
	case tokenEqual:
		return ast.OperatorEqual
	case tokenNotEqual:
		return ast.OperatorNotEqual
	case tokenNot:
		return ast.OperatorNot
	case tokenAmpersand:
		if binary {
			return ast.OperatorBitAnd
		}
		return ast.OperatorAddress
	case tokenVerticalBar:
		return ast.OperatorBitOr
	case tokenLess:
		return ast.OperatorLess
	case tokenLessOrEqual:
		return ast.OperatorLessEqual
	case tokenGreater:
		return ast.OperatorGreater
	case tokenGreaterOrEqual:
		return ast.OperatorGreaterEqual
	case tokenAnd:
		return ast.OperatorAnd
	case tokenOr:
		return ast.OperatorOr
	case tokenExtendedAnd:
		return ast.OperatorExtendedAnd
	case tokenExtendedOr:
		return ast.OperatorExtendedOr
	case tokenExtendedNot:
		return ast.OperatorExtendedNot
	case tokenContains:
		return ast.OperatorContains
	case tokenAddition:
		return ast.OperatorAddition
	case tokenSubtraction:
		return ast.OperatorSubtraction
	case tokenMultiplication:
		if binary {
			return ast.OperatorMultiplication
		}
		return ast.OperatorPointer
	case tokenDivision:
		return ast.OperatorDivision
	case tokenModulo:
		return ast.OperatorModulo
	case tokenArrow:
		return ast.OperatorReceive
	case tokenXor:
		return ast.OperatorXor
	case tokenAndNot:
		return ast.OperatorAndNot
	case tokenLeftShift:
		return ast.OperatorLeftShift
	case tokenRightShift:
		return ast.OperatorRightShift
	default:
		panic("invalid token type")
	}
}
func (p *parsing) parseIdentifierNode(tok token) *ast.Identifier {
	ident := ast.NewIdentifier(tok.pos, string(tok.txt))
	return ident
}
func unquoteString(s []byte) string {
	if len(s) == 2 {
		return ""
	}
	if len(s) == 3 {
		return string(s[1])
	}
	if s[0] == '`' || bytes.IndexByte(s, '\\') == -1 {
		return string(s[1 : len(s)-1])
	}
	var cc = make([]byte, 0, len(s))
	for i := 1; i < len(s)-1; i++ {
		if s[i] == '\\' {
			r, n := parseEscapedRune(s[i:])
			if n == 3 || r < utf8.RuneSelf {
				cc = append(cc, byte(r))
			} else {
				p := [4]byte{}
				j := utf8.EncodeRune(p[:], r)
				cc = append(cc, p[:j]...)
			}
			i += n
		} else {
			cc = append(cc, s[i])
		}
	}
	return string(cc)
}