// parseExprs parses a comma-separated list of expressions, starting with the comma.
// It is used to parse tuples and list elements.
// expr_list = (',' expr)* ','?
976670
func (p *parser) parseExprs(exprs []Expr, allowTrailingComma bool) []Expr {
	for p.tok == COMMA {
		pos := p.nextToken()
		if terminatesExprList(p.tok) {
			if !allowTrailingComma {
				p.in.error(pos, "unparenthesized tuple with trailing comma")
			}
			break
		}
		exprs = append(exprs, p.parseTest())
	}
	return exprs
}
1181795
func parsePrefix(s string) (string, string) {
	if strings.HasPrefix(s, "P") {
		return "P", s[1:]
	}
	if len(s) < 2 {
		return s, ""
	}
	return s[:2], s[2:]
}
262666
func compileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) {
	regexps := []*regexp.Regexp{}
	for _, regexpStr := range regexpStrings {
		r, err := regexp.Compile(regexpStr)
		if err != nil {
			return []*regexp.Regexp{}, err
		}
		regexps = append(regexps, r)
	}
	return regexps, nil
}
334790
func (m *FuncNode) Expr() *Expr {
	fe := &Expr{Op: lex.TokenUdfExpr.String()}
	if len(m.Args) > 0 {
		fe.Args = []*Expr{{Identity: m.Name}}
		fe.Args = append(fe.Args, ExprsFromNodes(m.Args)...)
	}
	return fe
}
871809
func Expr(expr syntax.Expr, locals []*syntax.Ident) *Funcode {
	stmts := []syntax.Stmt{&syntax.ReturnStmt{Result: expr}}
	return File(stmts, locals, nil).Toplevel
}
194110
func MustParseExpression(in string) threshold.Predicate {
	e, err := ParseExpression(in)
	if err != nil {
		panic(err)
	}
	return e
}
453526
func (p *parser) parseRelationalExpr(n node) node {
	opnd := p.parseAdditiveExpr(n)
Loop:
	for {
		var op string
		switch p.r.typ {
		case itemLt:
			op = "<"
		case itemGt:
			op = ">"
		case itemLe:
			op = "<="
		case itemGe:
			op = ">="
		default:
			break Loop
		}
		p.next()
		opnd = newOperatorNode(op, opnd, p.parseAdditiveExpr(n))
	}
	return opnd
}
751863
func (p *parser) parseExpression(n node) node {
	if p.d = p.d + 1; p.d > 200 {
		panic("the xpath query is too complex(depth > 200)")
	}
	n = p.parseOrExpr(n)
	p.d--
	return n
}
962572
func lexExpr(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
		state: lexInsideTag,
	}
	go l.run()
	return l
}
664158
func (t *tree) parseExpr(prec int) ast.Node {
	n := t.parseExprFirstTerm()
	var tok item
	for {
		tok = t.next()
		q := precedence[tok.typ]
		if !isBinaryOp(tok.typ) || q < prec {
			break
		}
		q++
		n = newBinaryOpNode(tok, n, t.parseExpr(q))
	}
	if prec == 0 && tok.typ == itemTernIf {
		return t.parseTernary(n)
	}
	t.backup()
	return n
}
1062354
func ParseMatchers(regexes, inverseRegexes, globs, inverseGlobs []string) (m Matcher, err error) {
	var matchers multiMatcher
	if len(regexes) == 0 && len(globs) == 0 {
		matchers = multiMatcher{matchAll{}}
	}
	for _, r := range regexes {
		regex, err := regexp.Compile(r)
		if err != nil {
			return nil, err
		}
		matchers = append(matchers, newRegexMatcher(regex, false))
	}
	for _, r := range inverseRegexes {
		regex, err := regexp.Compile(r)
		if err != nil {
			return nil, err
		}
		matchers = append(matchers, newRegexMatcher(regex, true))
	}
	for _, g := range globs {
		matchers = append(matchers, &globMatcher{glob: g})
	}
	for _, g := range inverseGlobs {
		matchers = append(matchers, &globMatcher{
			glob:    g,
			inverse: true,
		})
	}
	return matchers, nil
}
318358
func (p *parser) parseExpression(tok *lexer.Token) *ast.Expression {
	result := ast.NewExpression(tok.Pos, tok.Line)

	// helperName
	result.Path = p.parseHelperName()

	// param* hash?
	result.Params, result.Hash = p.parseExpressionParamsHash()

	return result
}
321203
func Parse(e string) (*expr, string, error) {
	// skip whitespace
	for len(e) > 1 && e[0] == ' ' {
		e = e[1:]
	}

	if len(e) == 0 {
		return nil, "", ErrMissingExpr
	}

	if '0' <= e[0] && e[0] <= '9' || e[0] == '-' || e[0] == '+' {
		return parseConst(e)
	}

	if val, ok := strToBool(e); ok {
		// 'false' is 5 chars, 'true' is 4
		size := 5
		if val {
			size = 4
		}
		return &expr{bool: val, str: e[:size], etype: etBool}, e[size:], nil
	}

	if e[0] == '\'' || e[0] == '"' {
		val, e, err := parseString(e)
		return &expr{str: val, etype: etString}, e, err
	}

	name, e := parseName(e)

	if name == "" {
		return nil, e, ErrMissingArg
	}

	if e != "" && e[0] == '(' {
		for i := range name {
			if !isFnChar(name[i]) {
				return nil, "", ErrIllegalCharacter
			}
		}

		exp := &expr{str: name, etype: etFunc}

		ArgString, posArgs, namedArgs, e, err := parseArgList(e)
		exp.argsStr = ArgString
		exp.args = posArgs
		exp.namedArgs = namedArgs

		return exp, e, err
	}

	return &expr{str: name, etype: etName}, e, nil
}
1270746
func Parse(env []string) ([]Constraint, error) {
	exprs := []Constraint{}
	for _, e := range env {
		found := false
		// each expr is in the form of "key op value"
		for i, op := range operators {
			if !strings.Contains(e, op) {
				continue
			}
			// split with the op
			parts := strings.SplitN(e, op, 2)

			if len(parts) < 2 {
				return nil, fmt.Errorf("invalid expr: %s", e)
			}

			part0 := strings.TrimSpace(parts[0])
			// validate key
			matched := alphaNumeric.MatchString(part0)
			if !matched {
				return nil, fmt.Errorf("key '%s' is invalid", part0)
			}

			part1 := strings.TrimSpace(parts[1])

			// validate Value
			matched = valuePattern.MatchString(part1)
			if !matched {
				return nil, fmt.Errorf("value '%s' is invalid", part1)
			}
			// TODO(dongluochen): revisit requirements to see if globing or regex are useful
			exprs = append(exprs, Constraint{key: part0, operator: i, exp: part1})

			found = true
			break // found an op, move to next entry
		}
		if !found {
			return nil, fmt.Errorf("constraint expected one operator from %s", strings.Join(operators, ", "))
		}
	}
	return exprs, nil
}
908864
func IsValidExpression(expr string) bool {
	_, err := parseExpression(expr)
	return err == nil
}
1186603
func ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) {
	in, err := newScanner(filename, src, mode&RetainComments != 0)
	if err != nil {
		return nil, err
	}
	p := parser{in: in}
	defer p.in.recover(&err)

	p.nextToken() // read first lookahead token
	expr = p.parseTest()

	// A following newline (e.g. "f()\n") appears outside any brackets,
	// on a non-blank line, and thus results in a NEWLINE token.
	if p.tok == NEWLINE {
		p.nextToken()
	}

	if p.tok != EOF {
		p.in.errorf(p.in.pos, "got %#v after expression, want EOF", p.tok)
	}
	p.assignComments(expr)
	return expr, nil
}
626384
func (p *Parser) parseRegex() (*RegexLiteral, error) {
	nextRune := p.peekRune()
	if isWhitespace(nextRune) {
		p.consumeWhitespace()
	}

	// If the next character is not a '/', then return nils.
	nextRune = p.peekRune()
	if nextRune != '/' {
		return nil, nil
	}

	tok, pos, lit := p.s.ScanRegex()

	if tok == BADESCAPE {
		msg := fmt.Sprintf("bad escape: %s", lit)
		return nil, &ParseError{Message: msg, Pos: pos}
	} else if tok == BADREGEX {
		msg := fmt.Sprintf("bad regex: %s", lit)
		return nil, &ParseError{Message: msg, Pos: pos}
	} else if tok != REGEX {
		return nil, newParseError(tokstr(tok, lit), []string{"regex"}, pos)
	}

	re, err := regexp.Compile(lit)
	if err != nil {
		return nil, &ParseError{Message: err.Error(), Pos: pos}
	}

	return &RegexLiteral{Val: re}, nil
}