// Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package parser declares an expression parser with support for macro // expansion. package parser import ( "fmt" "strconv" "strings" "sync" "github.com/antlr/antlr4/runtime/Go/antlr" "github.com/google/cel-go/common" "github.com/google/cel-go/common/operators" "github.com/google/cel-go/common/runes" "github.com/google/cel-go/parser/gen" exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" structpb "google.golang.org/protobuf/types/known/structpb" ) // Parser encapsulates the context necessary to perform parsing for different expressions. type Parser struct { options } // NewParser builds and returns a new Parser using the provided options. func NewParser(opts ...Option) (*Parser, error) { p := &Parser{} for _, opt := range opts { if err := opt(&p.options); err != nil { return nil, err } } if p.maxRecursionDepth == 0 { p.maxRecursionDepth = 250 } if p.maxRecursionDepth == -1 { p.maxRecursionDepth = int((^uint(0)) >> 1) } if p.errorRecoveryTokenLookaheadLimit == 0 { p.errorRecoveryTokenLookaheadLimit = 256 } if p.errorRecoveryLimit == 0 { p.errorRecoveryLimit = 30 } if p.errorRecoveryLimit == -1 { p.errorRecoveryLimit = int((^uint(0)) >> 1) } if p.expressionSizeCodePointLimit == 0 { p.expressionSizeCodePointLimit = 100_000 } if p.expressionSizeCodePointLimit == -1 { p.expressionSizeCodePointLimit = int((^uint(0)) >> 1) } // Bool is false by default, so populateMacroCalls will be false by default return p, nil } // mustNewParser does the work of NewParser and panics if an error occurs. // // This function is only intended for internal use and is for backwards compatibility in Parse and // ParseWithMacros, where we know the options will result in an error. func mustNewParser(opts ...Option) *Parser { p, err := NewParser(opts...) if err != nil { panic(err) } return p } // Parse parses the expression represented by source and returns the result. func (p *Parser) Parse(source common.Source) (*exprpb.ParsedExpr, *common.Errors) { impl := parser{ errors: &parseErrors{common.NewErrors(source)}, helper: newParserHelper(source), macros: p.macros, maxRecursionDepth: p.maxRecursionDepth, errorRecoveryLimit: p.errorRecoveryLimit, errorRecoveryLookaheadTokenLimit: p.errorRecoveryTokenLookaheadLimit, populateMacroCalls: p.populateMacroCalls, } buf, ok := source.(runes.Buffer) if !ok { buf = runes.NewBuffer(source.Content()) } var e *exprpb.Expr if buf.Len() > p.expressionSizeCodePointLimit { e = impl.reportError(common.NoLocation, "expression code point size exceeds limit: size: %d, limit %d", buf.Len(), p.expressionSizeCodePointLimit) } else { e = impl.parse(buf, source.Description()) } return &exprpb.ParsedExpr{ Expr: e, SourceInfo: impl.helper.getSourceInfo(), }, impl.errors.Errors } // reservedIds are not legal to use as variables. We exclude them post-parse, as they *are* valid // field names for protos, and it would complicate the grammar to distinguish the cases. var reservedIds = map[string]struct{}{ "as": {}, "break": {}, "const": {}, "continue": {}, "else": {}, "false": {}, "for": {}, "function": {}, "if": {}, "import": {}, "in": {}, "let": {}, "loop": {}, "package": {}, "namespace": {}, "null": {}, "return": {}, "true": {}, "var": {}, "void": {}, "while": {}, } // Parse converts a source input a parsed expression. // This function calls ParseWithMacros with AllMacros. // // Deprecated: Use NewParser().Parse() instead. func Parse(source common.Source) (*exprpb.ParsedExpr, *common.Errors) { return mustNewParser(Macros(AllMacros...)).Parse(source) } type recursionError struct { message string } // Error implements error. func (re *recursionError) Error() string { return re.message } var _ error = &recursionError{} type recursionListener struct { maxDepth int ruleTypeDepth map[int]*int } func (rl *recursionListener) VisitTerminal(node antlr.TerminalNode) {} func (rl *recursionListener) VisitErrorNode(node antlr.ErrorNode) {} func (rl *recursionListener) EnterEveryRule(ctx antlr.ParserRuleContext) { if ctx == nil { return } ruleIndex := ctx.GetRuleIndex() depth, found := rl.ruleTypeDepth[ruleIndex] if !found { var counter = 1 rl.ruleTypeDepth[ruleIndex] = &counter depth = &counter } else { *depth++ } if *depth >= rl.maxDepth { panic(&recursionError{ message: fmt.Sprintf("expression recursion limit exceeded: %d", rl.maxDepth), }) } } func (rl *recursionListener) ExitEveryRule(ctx antlr.ParserRuleContext) { if ctx == nil { return } ruleIndex := ctx.GetRuleIndex() if depth, found := rl.ruleTypeDepth[ruleIndex]; found && *depth > 0 { *depth-- } } var _ antlr.ParseTreeListener = &recursionListener{} type recoveryLimitError struct { message string } // Error implements error. func (rl *recoveryLimitError) Error() string { return rl.message } type lookaheadLimitError struct { message string } func (ll *lookaheadLimitError) Error() string { return ll.message } var _ error = &recoveryLimitError{} type recoveryLimitErrorStrategy struct { *antlr.DefaultErrorStrategy errorRecoveryLimit int errorRecoveryTokenLookaheadLimit int recoveryAttempts int } type lookaheadConsumer struct { antlr.Parser errorRecoveryTokenLookaheadLimit int lookaheadAttempts int } func (lc *lookaheadConsumer) Consume() antlr.Token { if lc.lookaheadAttempts >= lc.errorRecoveryTokenLookaheadLimit { panic(&lookaheadLimitError{ message: fmt.Sprintf("error recovery token lookahead limit exceeded: %d", lc.errorRecoveryTokenLookaheadLimit), }) } lc.lookaheadAttempts++ return lc.Parser.Consume() } func (rl *recoveryLimitErrorStrategy) Recover(recognizer antlr.Parser, e antlr.RecognitionException) { rl.checkAttempts(recognizer) lc := &lookaheadConsumer{Parser: recognizer, errorRecoveryTokenLookaheadLimit: rl.errorRecoveryTokenLookaheadLimit} rl.DefaultErrorStrategy.Recover(lc, e) } func (rl *recoveryLimitErrorStrategy) RecoverInline(recognizer antlr.Parser) antlr.Token { rl.checkAttempts(recognizer) lc := &lookaheadConsumer{Parser: recognizer, errorRecoveryTokenLookaheadLimit: rl.errorRecoveryTokenLookaheadLimit} return rl.DefaultErrorStrategy.RecoverInline(lc) } func (rl *recoveryLimitErrorStrategy) checkAttempts(recognizer antlr.Parser) { if rl.recoveryAttempts == rl.errorRecoveryLimit { rl.recoveryAttempts++ msg := fmt.Sprintf("error recovery attempt limit exceeded: %d", rl.errorRecoveryLimit) recognizer.NotifyErrorListeners(msg, nil, nil) panic(&recoveryLimitError{ message: msg, }) } rl.recoveryAttempts++ } var _ antlr.ErrorStrategy = &recoveryLimitErrorStrategy{} type parser struct { gen.BaseCELVisitor errors *parseErrors helper *parserHelper macros map[string]Macro recursionDepth int maxRecursionDepth int errorRecoveryLimit int errorRecoveryLookaheadTokenLimit int populateMacroCalls bool } var ( _ gen.CELVisitor = (*parser)(nil) lexerPool *sync.Pool = &sync.Pool{ New: func() interface{} { l := gen.NewCELLexer(nil) l.RemoveErrorListeners() return l }, } parserPool *sync.Pool = &sync.Pool{ New: func() interface{} { p := gen.NewCELParser(nil) p.RemoveErrorListeners() return p }, } ) func (p *parser) parse(expr runes.Buffer, desc string) *exprpb.Expr { // TODO: get rid of these pools once https://github.com/antlr/antlr4/pull/3571 is in a release lexer := lexerPool.Get().(*gen.CELLexer) prsr := parserPool.Get().(*gen.CELParser) // Unfortunately ANTLR Go runtime is missing (*antlr.BaseParser).RemoveParseListeners, so this is // good enough until that is exported. prsrListener := &recursionListener{ maxDepth: p.maxRecursionDepth, ruleTypeDepth: map[int]*int{}, } defer func() { // Reset the lexer and parser before putting them back in the pool. lexer.RemoveErrorListeners() prsr.RemoveParseListener(prsrListener) prsr.RemoveErrorListeners() lexer.SetInputStream(nil) prsr.SetInputStream(nil) lexerPool.Put(lexer) parserPool.Put(prsr) }() lexer.SetInputStream(newCharStream(expr, desc)) prsr.SetInputStream(antlr.NewCommonTokenStream(lexer, 0)) lexer.AddErrorListener(p) prsr.AddErrorListener(p) prsr.AddParseListener(prsrListener) prsr.SetErrorHandler(&recoveryLimitErrorStrategy{ DefaultErrorStrategy: antlr.NewDefaultErrorStrategy(), errorRecoveryLimit: p.errorRecoveryLimit, errorRecoveryTokenLookaheadLimit: p.errorRecoveryLookaheadTokenLimit, }) defer func() { if val := recover(); val != nil { switch err := val.(type) { case *lookaheadLimitError: p.errors.ReportError(common.NoLocation, err.Error()) case *recursionError: p.errors.ReportError(common.NoLocation, err.Error()) case *recoveryLimitError: // do nothing, listeners already notified and error reported. default: panic(val) } } }() return p.Visit(prsr.Start()).(*exprpb.Expr) } // Visitor implementations. func (p *parser) Visit(tree antlr.ParseTree) interface{} { p.recursionDepth++ if p.recursionDepth > p.maxRecursionDepth { panic(&recursionError{message: "max recursion depth exceeded"}) } defer func() { p.recursionDepth-- }() switch tree.(type) { case *gen.StartContext: return p.VisitStart(tree.(*gen.StartContext)) case *gen.ExprContext: return p.VisitExpr(tree.(*gen.ExprContext)) case *gen.ConditionalAndContext: return p.VisitConditionalAnd(tree.(*gen.ConditionalAndContext)) case *gen.ConditionalOrContext: return p.VisitConditionalOr(tree.(*gen.ConditionalOrContext)) case *gen.RelationContext: return p.VisitRelation(tree.(*gen.RelationContext)) case *gen.CalcContext: return p.VisitCalc(tree.(*gen.CalcContext)) case *gen.LogicalNotContext: return p.VisitLogicalNot(tree.(*gen.LogicalNotContext)) case *gen.MemberExprContext: return p.VisitMemberExpr(tree.(*gen.MemberExprContext)) case *gen.PrimaryExprContext: return p.VisitPrimaryExpr(tree.(*gen.PrimaryExprContext)) case *gen.SelectOrCallContext: return p.VisitSelectOrCall(tree.(*gen.SelectOrCallContext)) case *gen.MapInitializerListContext: return p.VisitMapInitializerList(tree.(*gen.MapInitializerListContext)) case *gen.NegateContext: return p.VisitNegate(tree.(*gen.NegateContext)) case *gen.IndexContext: return p.VisitIndex(tree.(*gen.IndexContext)) case *gen.UnaryContext: return p.VisitUnary(tree.(*gen.UnaryContext)) case *gen.CreateListContext: return p.VisitCreateList(tree.(*gen.CreateListContext)) case *gen.CreateMessageContext: return p.VisitCreateMessage(tree.(*gen.CreateMessageContext)) case *gen.CreateStructContext: return p.VisitCreateStruct(tree.(*gen.CreateStructContext)) } // Report at least one error if the parser reaches an unknown parse element. // Typically, this happens if the parser has already encountered a syntax error elsewhere. if len(p.errors.GetErrors()) == 0 { txt := "<>" if tree != nil { txt = fmt.Sprintf("<<%T>>", tree) } return p.reportError(common.NoLocation, "unknown parse element encountered: %s", txt) } return p.helper.newExpr(common.NoLocation) } // Visit a parse tree produced by CELParser#start. func (p *parser) VisitStart(ctx *gen.StartContext) interface{} { return p.Visit(ctx.Expr()) } // Visit a parse tree produced by CELParser#expr. func (p *parser) VisitExpr(ctx *gen.ExprContext) interface{} { result := p.Visit(ctx.GetE()).(*exprpb.Expr) if ctx.GetOp() == nil { return result } opID := p.helper.id(ctx.GetOp()) ifTrue := p.Visit(ctx.GetE1()).(*exprpb.Expr) ifFalse := p.Visit(ctx.GetE2()).(*exprpb.Expr) return p.globalCallOrMacro(opID, operators.Conditional, result, ifTrue, ifFalse) } // Visit a parse tree produced by CELParser#conditionalOr. func (p *parser) VisitConditionalOr(ctx *gen.ConditionalOrContext) interface{} { result := p.Visit(ctx.GetE()).(*exprpb.Expr) if ctx.GetOps() == nil { return result } b := newBalancer(p.helper, operators.LogicalOr, result) rest := ctx.GetE1() for i, op := range ctx.GetOps() { if i >= len(rest) { return p.reportError(ctx, "unexpected character, wanted '||'") } next := p.Visit(rest[i]).(*exprpb.Expr) opID := p.helper.id(op) b.addTerm(opID, next) } return b.balance() } // Visit a parse tree produced by CELParser#conditionalAnd. func (p *parser) VisitConditionalAnd(ctx *gen.ConditionalAndContext) interface{} { result := p.Visit(ctx.GetE()).(*exprpb.Expr) if ctx.GetOps() == nil { return result } b := newBalancer(p.helper, operators.LogicalAnd, result) rest := ctx.GetE1() for i, op := range ctx.GetOps() { if i >= len(rest) { return p.reportError(ctx, "unexpected character, wanted '&&'") } next := p.Visit(rest[i]).(*exprpb.Expr) opID := p.helper.id(op) b.addTerm(opID, next) } return b.balance() } // Visit a parse tree produced by CELParser#relation. func (p *parser) VisitRelation(ctx *gen.RelationContext) interface{} { if ctx.Calc() != nil { return p.Visit(ctx.Calc()) } opText := "" if ctx.GetOp() != nil { opText = ctx.GetOp().GetText() } if op, found := operators.Find(opText); found { lhs := p.Visit(ctx.Relation(0)).(*exprpb.Expr) opID := p.helper.id(ctx.GetOp()) rhs := p.Visit(ctx.Relation(1)).(*exprpb.Expr) return p.globalCallOrMacro(opID, op, lhs, rhs) } return p.reportError(ctx, "operator not found") } // Visit a parse tree produced by CELParser#calc. func (p *parser) VisitCalc(ctx *gen.CalcContext) interface{} { if ctx.Unary() != nil { return p.Visit(ctx.Unary()) } opText := "" if ctx.GetOp() != nil { opText = ctx.GetOp().GetText() } if op, found := operators.Find(opText); found { lhs := p.Visit(ctx.Calc(0)).(*exprpb.Expr) opID := p.helper.id(ctx.GetOp()) rhs := p.Visit(ctx.Calc(1)).(*exprpb.Expr) return p.globalCallOrMacro(opID, op, lhs, rhs) } return p.reportError(ctx, "operator not found") } func (p *parser) VisitUnary(ctx *gen.UnaryContext) interface{} { return p.helper.newLiteralString(ctx, "<>") } // Visit a parse tree produced by CELParser#MemberExpr. func (p *parser) VisitMemberExpr(ctx *gen.MemberExprContext) interface{} { switch ctx.Member().(type) { case *gen.PrimaryExprContext: return p.VisitPrimaryExpr(ctx.Member().(*gen.PrimaryExprContext)) case *gen.SelectOrCallContext: return p.VisitSelectOrCall(ctx.Member().(*gen.SelectOrCallContext)) case *gen.IndexContext: return p.VisitIndex(ctx.Member().(*gen.IndexContext)) case *gen.CreateMessageContext: return p.VisitCreateMessage(ctx.Member().(*gen.CreateMessageContext)) } return p.reportError(ctx, "unsupported simple expression") } // Visit a parse tree produced by CELParser#LogicalNot. func (p *parser) VisitLogicalNot(ctx *gen.LogicalNotContext) interface{} { if len(ctx.GetOps())%2 == 0 { return p.Visit(ctx.Member()) } opID := p.helper.id(ctx.GetOps()[0]) target := p.Visit(ctx.Member()).(*exprpb.Expr) return p.globalCallOrMacro(opID, operators.LogicalNot, target) } func (p *parser) VisitNegate(ctx *gen.NegateContext) interface{} { if len(ctx.GetOps())%2 == 0 { return p.Visit(ctx.Member()) } opID := p.helper.id(ctx.GetOps()[0]) target := p.Visit(ctx.Member()).(*exprpb.Expr) return p.globalCallOrMacro(opID, operators.Negate, target) } // Visit a parse tree produced by CELParser#SelectOrCall. func (p *parser) VisitSelectOrCall(ctx *gen.SelectOrCallContext) interface{} { operand := p.Visit(ctx.Member()).(*exprpb.Expr) // Handle the error case where no valid identifier is specified. if ctx.GetId() == nil { return p.helper.newExpr(ctx) } id := ctx.GetId().GetText() if ctx.GetOpen() != nil { opID := p.helper.id(ctx.GetOpen()) return p.receiverCallOrMacro(opID, id, operand, p.visitList(ctx.GetArgs())...) } return p.helper.newSelect(ctx.GetOp(), operand, id) } // Visit a parse tree produced by CELParser#PrimaryExpr. func (p *parser) VisitPrimaryExpr(ctx *gen.PrimaryExprContext) interface{} { switch ctx.Primary().(type) { case *gen.NestedContext: return p.VisitNested(ctx.Primary().(*gen.NestedContext)) case *gen.IdentOrGlobalCallContext: return p.VisitIdentOrGlobalCall(ctx.Primary().(*gen.IdentOrGlobalCallContext)) case *gen.CreateListContext: return p.VisitCreateList(ctx.Primary().(*gen.CreateListContext)) case *gen.CreateStructContext: return p.VisitCreateStruct(ctx.Primary().(*gen.CreateStructContext)) case *gen.ConstantLiteralContext: return p.VisitConstantLiteral(ctx.Primary().(*gen.ConstantLiteralContext)) } return p.reportError(ctx, "invalid primary expression") } // Visit a parse tree produced by CELParser#Index. func (p *parser) VisitIndex(ctx *gen.IndexContext) interface{} { target := p.Visit(ctx.Member()).(*exprpb.Expr) opID := p.helper.id(ctx.GetOp()) index := p.Visit(ctx.GetIndex()).(*exprpb.Expr) return p.globalCallOrMacro(opID, operators.Index, target, index) } // Visit a parse tree produced by CELParser#CreateMessage. func (p *parser) VisitCreateMessage(ctx *gen.CreateMessageContext) interface{} { target := p.Visit(ctx.Member()).(*exprpb.Expr) objID := p.helper.id(ctx.GetOp()) if messageName, found := p.extractQualifiedName(target); found { entries := p.VisitIFieldInitializerList(ctx.GetEntries()).([]*exprpb.Expr_CreateStruct_Entry) return p.helper.newObject(objID, messageName, entries...) } return p.helper.newExpr(objID) } // Visit a parse tree of field initializers. func (p *parser) VisitIFieldInitializerList(ctx gen.IFieldInitializerListContext) interface{} { if ctx == nil || ctx.GetFields() == nil { // This is the result of a syntax error handled elswhere, return empty. return []*exprpb.Expr_CreateStruct_Entry{} } result := make([]*exprpb.Expr_CreateStruct_Entry, len(ctx.GetFields())) cols := ctx.GetCols() vals := ctx.GetValues() for i, f := range ctx.GetFields() { if i >= len(cols) || i >= len(vals) { // This is the result of a syntax error detected elsewhere. return []*exprpb.Expr_CreateStruct_Entry{} } initID := p.helper.id(cols[i]) value := p.Visit(vals[i]).(*exprpb.Expr) field := p.helper.newObjectField(initID, f.GetText(), value) result[i] = field } return result } // Visit a parse tree produced by CELParser#IdentOrGlobalCall. func (p *parser) VisitIdentOrGlobalCall(ctx *gen.IdentOrGlobalCallContext) interface{} { identName := "" if ctx.GetLeadingDot() != nil { identName = "." } // Handle the error case where no valid identifier is specified. if ctx.GetId() == nil { return p.helper.newExpr(ctx) } // Handle reserved identifiers. id := ctx.GetId().GetText() if _, ok := reservedIds[id]; ok { return p.reportError(ctx, "reserved identifier: %s", id) } identName += id if ctx.GetOp() != nil { opID := p.helper.id(ctx.GetOp()) return p.globalCallOrMacro(opID, identName, p.visitList(ctx.GetArgs())...) } return p.helper.newIdent(ctx.GetId(), identName) } // Visit a parse tree produced by CELParser#Nested. func (p *parser) VisitNested(ctx *gen.NestedContext) interface{} { return p.Visit(ctx.GetE()) } // Visit a parse tree produced by CELParser#CreateList. func (p *parser) VisitCreateList(ctx *gen.CreateListContext) interface{} { listID := p.helper.id(ctx.GetOp()) return p.helper.newList(listID, p.visitList(ctx.GetElems())...) } // Visit a parse tree produced by CELParser#CreateStruct. func (p *parser) VisitCreateStruct(ctx *gen.CreateStructContext) interface{} { structID := p.helper.id(ctx.GetOp()) entries := []*exprpb.Expr_CreateStruct_Entry{} if ctx.GetEntries() != nil { entries = p.Visit(ctx.GetEntries()).([]*exprpb.Expr_CreateStruct_Entry) } return p.helper.newMap(structID, entries...) } // Visit a parse tree produced by CELParser#ConstantLiteral. func (p *parser) VisitConstantLiteral(ctx *gen.ConstantLiteralContext) interface{} { switch ctx.Literal().(type) { case *gen.IntContext: return p.VisitInt(ctx.Literal().(*gen.IntContext)) case *gen.UintContext: return p.VisitUint(ctx.Literal().(*gen.UintContext)) case *gen.DoubleContext: return p.VisitDouble(ctx.Literal().(*gen.DoubleContext)) case *gen.StringContext: return p.VisitString(ctx.Literal().(*gen.StringContext)) case *gen.BytesContext: return p.VisitBytes(ctx.Literal().(*gen.BytesContext)) case *gen.BoolFalseContext: return p.VisitBoolFalse(ctx.Literal().(*gen.BoolFalseContext)) case *gen.BoolTrueContext: return p.VisitBoolTrue(ctx.Literal().(*gen.BoolTrueContext)) case *gen.NullContext: return p.VisitNull(ctx.Literal().(*gen.NullContext)) } return p.reportError(ctx, "invalid literal") } // Visit a parse tree produced by CELParser#mapInitializerList. func (p *parser) VisitMapInitializerList(ctx *gen.MapInitializerListContext) interface{} { if ctx == nil || ctx.GetKeys() == nil { // This is the result of a syntax error handled elswhere, return empty. return []*exprpb.Expr_CreateStruct_Entry{} } result := make([]*exprpb.Expr_CreateStruct_Entry, len(ctx.GetCols())) keys := ctx.GetKeys() vals := ctx.GetValues() for i, col := range ctx.GetCols() { colID := p.helper.id(col) if i >= len(keys) || i >= len(vals) { // This is the result of a syntax error detected elsewhere. return []*exprpb.Expr_CreateStruct_Entry{} } key := p.Visit(keys[i]).(*exprpb.Expr) value := p.Visit(vals[i]).(*exprpb.Expr) entry := p.helper.newMapEntry(colID, key, value) result[i] = entry } return result } // Visit a parse tree produced by CELParser#Int. func (p *parser) VisitInt(ctx *gen.IntContext) interface{} { text := ctx.GetTok().GetText() base := 10 if strings.HasPrefix(text, "0x") { base = 16 text = text[2:] } if ctx.GetSign() != nil { text = ctx.GetSign().GetText() + text } i, err := strconv.ParseInt(text, base, 64) if err != nil { return p.reportError(ctx, "invalid int literal") } return p.helper.newLiteralInt(ctx, i) } // Visit a parse tree produced by CELParser#Uint. func (p *parser) VisitUint(ctx *gen.UintContext) interface{} { text := ctx.GetTok().GetText() // trim the 'u' designator included in the uint literal. text = text[:len(text)-1] base := 10 if strings.HasPrefix(text, "0x") { base = 16 text = text[2:] } i, err := strconv.ParseUint(text, base, 64) if err != nil { return p.reportError(ctx, "invalid uint literal") } return p.helper.newLiteralUint(ctx, i) } // Visit a parse tree produced by CELParser#Double. func (p *parser) VisitDouble(ctx *gen.DoubleContext) interface{} { txt := ctx.GetTok().GetText() if ctx.GetSign() != nil { txt = ctx.GetSign().GetText() + txt } f, err := strconv.ParseFloat(txt, 64) if err != nil { return p.reportError(ctx, "invalid double literal") } return p.helper.newLiteralDouble(ctx, f) } // Visit a parse tree produced by CELParser#String. func (p *parser) VisitString(ctx *gen.StringContext) interface{} { s := p.unquote(ctx, ctx.GetText(), false) return p.helper.newLiteralString(ctx, s) } // Visit a parse tree produced by CELParser#Bytes. func (p *parser) VisitBytes(ctx *gen.BytesContext) interface{} { b := []byte(p.unquote(ctx, ctx.GetTok().GetText()[1:], true)) return p.helper.newLiteralBytes(ctx, b) } // Visit a parse tree produced by CELParser#BoolTrue. func (p *parser) VisitBoolTrue(ctx *gen.BoolTrueContext) interface{} { return p.helper.newLiteralBool(ctx, true) } // Visit a parse tree produced by CELParser#BoolFalse. func (p *parser) VisitBoolFalse(ctx *gen.BoolFalseContext) interface{} { return p.helper.newLiteralBool(ctx, false) } // Visit a parse tree produced by CELParser#Null. func (p *parser) VisitNull(ctx *gen.NullContext) interface{} { return p.helper.newLiteral(ctx, &exprpb.Constant{ ConstantKind: &exprpb.Constant_NullValue{ NullValue: structpb.NullValue_NULL_VALUE}}) } func (p *parser) visitList(ctx gen.IExprListContext) []*exprpb.Expr { if ctx == nil { return []*exprpb.Expr{} } return p.visitSlice(ctx.GetE()) } func (p *parser) visitSlice(expressions []gen.IExprContext) []*exprpb.Expr { if expressions == nil { return []*exprpb.Expr{} } result := make([]*exprpb.Expr, len(expressions)) for i, e := range expressions { ex := p.Visit(e).(*exprpb.Expr) result[i] = ex } return result } func (p *parser) extractQualifiedName(e *exprpb.Expr) (string, bool) { if e == nil { return "", false } switch e.GetExprKind().(type) { case *exprpb.Expr_IdentExpr: return e.GetIdentExpr().GetName(), true case *exprpb.Expr_SelectExpr: s := e.GetSelectExpr() if prefix, found := p.extractQualifiedName(s.GetOperand()); found { return prefix + "." + s.GetField(), true } } // TODO: Add a method to Source to get location from character offset. location := p.helper.getLocation(e.GetId()) p.reportError(location, "expected a qualified name") return "", false } func (p *parser) unquote(ctx interface{}, value string, isBytes bool) string { text, err := unescape(value, isBytes) if err != nil { p.reportError(ctx, "%s", err.Error()) return value } return text } func (p *parser) reportError(ctx interface{}, format string, args ...interface{}) *exprpb.Expr { var location common.Location switch ctx.(type) { case common.Location: location = ctx.(common.Location) case antlr.Token, antlr.ParserRuleContext: err := p.helper.newExpr(ctx) location = p.helper.getLocation(err.GetId()) } err := p.helper.newExpr(ctx) // Provide arguments to the report error. p.errors.ReportError(location, format, args...) return err } // ANTLR Parse listener implementations func (p *parser) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) { // TODO: Snippet l := p.helper.source.NewLocation(line, column) p.errors.syntaxError(l, msg) } func (p *parser) ReportAmbiguity(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex int, exact bool, ambigAlts *antlr.BitSet, configs antlr.ATNConfigSet) { // Intentional } func (p *parser) ReportAttemptingFullContext(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex int, conflictingAlts *antlr.BitSet, configs antlr.ATNConfigSet) { // Intentional } func (p *parser) ReportContextSensitivity(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex, prediction int, configs antlr.ATNConfigSet) { // Intentional } func (p *parser) globalCallOrMacro(exprID int64, function string, args ...*exprpb.Expr) *exprpb.Expr { if expr, found := p.expandMacro(exprID, function, nil, args...); found { return expr } return p.helper.newGlobalCall(exprID, function, args...) } func (p *parser) receiverCallOrMacro(exprID int64, function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr { if expr, found := p.expandMacro(exprID, function, target, args...); found { return expr } return p.helper.newReceiverCall(exprID, function, target, args...) } func (p *parser) expandMacro(exprID int64, function string, target *exprpb.Expr, args ...*exprpb.Expr) (*exprpb.Expr, bool) { macro, found := p.macros[makeMacroKey(function, len(args), target != nil)] if !found { macro, found = p.macros[makeVarArgMacroKey(function, target != nil)] if !found { return nil, false } } eh := exprHelperPool.Get().(*exprHelper) defer exprHelperPool.Put(eh) eh.parserHelper = p.helper eh.id = exprID expr, err := macro.Expander()(eh, target, args) if err != nil { if err.Location != nil { return p.reportError(err.Location, err.Message), true } return p.reportError(p.helper.getLocation(exprID), err.Message), true } if p.populateMacroCalls { p.helper.addMacroCall(expr.GetId(), function, target, args...) } return expr, true }