Pin new dependency: github.com/google/cel-go v0.9.0

This commit is contained in:
Joe Betz
2021-11-01 14:08:09 -04:00
parent 91ff1f9840
commit d73403dc12
304 changed files with 48716 additions and 995 deletions

View File

@@ -0,0 +1,26 @@
Copyright 2021 The ANTLR Project
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

152
vendor/github.com/antlr/antlr4/runtime/Go/antlr/atn.go generated vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
var ATNInvalidAltNumber int
type ATN struct {
// DecisionToState is the decision points for all rules, subrules, optional
// blocks, ()+, ()*, etc. Used to build DFA predictors for them.
DecisionToState []DecisionState
// grammarType is the ATN type and is used for deserializing ATNs from strings.
grammarType int
// lexerActions is referenced by action transitions in the ATN for lexer ATNs.
lexerActions []LexerAction
// maxTokenType is the maximum value for any symbol recognized by a transition in the ATN.
maxTokenType int
modeNameToStartState map[string]*TokensStartState
modeToStartState []*TokensStartState
// ruleToStartState maps from rule index to starting state number.
ruleToStartState []*RuleStartState
// ruleToStopState maps from rule index to stop state number.
ruleToStopState []*RuleStopState
// ruleToTokenType maps the rule index to the resulting token type for lexer
// ATNs. For parser ATNs, it maps the rule index to the generated bypass token
// type if ATNDeserializationOptions.isGenerateRuleBypassTransitions was
// specified, and otherwise is nil.
ruleToTokenType []int
states []ATNState
}
func NewATN(grammarType int, maxTokenType int) *ATN {
return &ATN{
grammarType: grammarType,
maxTokenType: maxTokenType,
modeNameToStartState: make(map[string]*TokensStartState),
}
}
// NextTokensInContext computes the set of valid tokens that can occur starting
// in state s. If ctx is nil, the set of tokens will not include what can follow
// the rule surrounding s. In other words, the set will be restricted to tokens
// reachable staying within the rule of s.
func (a *ATN) NextTokensInContext(s ATNState, ctx RuleContext) *IntervalSet {
return NewLL1Analyzer(a).Look(s, nil, ctx)
}
// NextTokensNoContext computes the set of valid tokens that can occur starting
// in s and staying in same rule. Token.EPSILON is in set if we reach end of
// rule.
func (a *ATN) NextTokensNoContext(s ATNState) *IntervalSet {
if s.GetNextTokenWithinRule() != nil {
return s.GetNextTokenWithinRule()
}
s.SetNextTokenWithinRule(a.NextTokensInContext(s, nil))
s.GetNextTokenWithinRule().readOnly = true
return s.GetNextTokenWithinRule()
}
func (a *ATN) NextTokens(s ATNState, ctx RuleContext) *IntervalSet {
if ctx == nil {
return a.NextTokensNoContext(s)
}
return a.NextTokensInContext(s, ctx)
}
func (a *ATN) addState(state ATNState) {
if state != nil {
state.SetATN(a)
state.SetStateNumber(len(a.states))
}
a.states = append(a.states, state)
}
func (a *ATN) removeState(state ATNState) {
a.states[state.GetStateNumber()] = nil // Just free the memory; don't shift states in the slice
}
func (a *ATN) defineDecisionState(s DecisionState) int {
a.DecisionToState = append(a.DecisionToState, s)
s.setDecision(len(a.DecisionToState) - 1)
return s.getDecision()
}
func (a *ATN) getDecisionState(decision int) DecisionState {
if len(a.DecisionToState) == 0 {
return nil
}
return a.DecisionToState[decision]
}
// getExpectedTokens computes the set of input symbols which could follow ATN
// state number stateNumber in the specified full parse context ctx and returns
// the set of potentially valid input symbols which could follow the specified
// state in the specified context. This method considers the complete parser
// context, but does not evaluate semantic predicates (i.e. all predicates
// encountered during the calculation are assumed true). If a path in the ATN
// exists from the starting state to the RuleStopState of the outermost context
// without Matching any symbols, Token.EOF is added to the returned set.
//
// A nil ctx defaults to ParserRuleContext.EMPTY.
//
// It panics if the ATN does not contain state stateNumber.
func (a *ATN) getExpectedTokens(stateNumber int, ctx RuleContext) *IntervalSet {
if stateNumber < 0 || stateNumber >= len(a.states) {
panic("Invalid state number.")
}
s := a.states[stateNumber]
following := a.NextTokens(s, nil)
if !following.contains(TokenEpsilon) {
return following
}
expected := NewIntervalSet()
expected.addSet(following)
expected.removeOne(TokenEpsilon)
for ctx != nil && ctx.GetInvokingState() >= 0 && following.contains(TokenEpsilon) {
invokingState := a.states[ctx.GetInvokingState()]
rt := invokingState.GetTransitions()[0]
following = a.NextTokens(rt.(*RuleTransition).followState, nil)
expected.addSet(following)
expected.removeOne(TokenEpsilon)
ctx = ctx.GetParent().(RuleContext)
}
if following.contains(TokenEpsilon) {
expected.addOne(TokenEOF)
}
return expected
}

View File

@@ -0,0 +1,295 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
)
type comparable interface {
equals(other interface{}) bool
}
// ATNConfig is a tuple: (ATN state, predicted alt, syntactic, semantic
// context). The syntactic context is a graph-structured stack node whose
// path(s) to the root is the rule invocation(s) chain used to arrive at the
// state. The semantic context is the tree of semantic predicates encountered
// before reaching an ATN state.
type ATNConfig interface {
comparable
hash() int
GetState() ATNState
GetAlt() int
GetSemanticContext() SemanticContext
GetContext() PredictionContext
SetContext(PredictionContext)
GetReachesIntoOuterContext() int
SetReachesIntoOuterContext(int)
String() string
getPrecedenceFilterSuppressed() bool
setPrecedenceFilterSuppressed(bool)
}
type BaseATNConfig struct {
precedenceFilterSuppressed bool
state ATNState
alt int
context PredictionContext
semanticContext SemanticContext
reachesIntoOuterContext int
}
func NewBaseATNConfig7(old *BaseATNConfig) *BaseATNConfig { // TODO: Dup
return &BaseATNConfig{
state: old.state,
alt: old.alt,
context: old.context,
semanticContext: old.semanticContext,
reachesIntoOuterContext: old.reachesIntoOuterContext,
}
}
func NewBaseATNConfig6(state ATNState, alt int, context PredictionContext) *BaseATNConfig {
return NewBaseATNConfig5(state, alt, context, SemanticContextNone)
}
func NewBaseATNConfig5(state ATNState, alt int, context PredictionContext, semanticContext SemanticContext) *BaseATNConfig {
if semanticContext == nil {
panic("semanticContext cannot be nil") // TODO: Necessary?
}
return &BaseATNConfig{state: state, alt: alt, context: context, semanticContext: semanticContext}
}
func NewBaseATNConfig4(c ATNConfig, state ATNState) *BaseATNConfig {
return NewBaseATNConfig(c, state, c.GetContext(), c.GetSemanticContext())
}
func NewBaseATNConfig3(c ATNConfig, state ATNState, semanticContext SemanticContext) *BaseATNConfig {
return NewBaseATNConfig(c, state, c.GetContext(), semanticContext)
}
func NewBaseATNConfig2(c ATNConfig, semanticContext SemanticContext) *BaseATNConfig {
return NewBaseATNConfig(c, c.GetState(), c.GetContext(), semanticContext)
}
func NewBaseATNConfig1(c ATNConfig, state ATNState, context PredictionContext) *BaseATNConfig {
return NewBaseATNConfig(c, state, context, c.GetSemanticContext())
}
func NewBaseATNConfig(c ATNConfig, state ATNState, context PredictionContext, semanticContext SemanticContext) *BaseATNConfig {
if semanticContext == nil {
panic("semanticContext cannot be nil")
}
return &BaseATNConfig{
state: state,
alt: c.GetAlt(),
context: context,
semanticContext: semanticContext,
reachesIntoOuterContext: c.GetReachesIntoOuterContext(),
precedenceFilterSuppressed: c.getPrecedenceFilterSuppressed(),
}
}
func (b *BaseATNConfig) getPrecedenceFilterSuppressed() bool {
return b.precedenceFilterSuppressed
}
func (b *BaseATNConfig) setPrecedenceFilterSuppressed(v bool) {
b.precedenceFilterSuppressed = v
}
func (b *BaseATNConfig) GetState() ATNState {
return b.state
}
func (b *BaseATNConfig) GetAlt() int {
return b.alt
}
func (b *BaseATNConfig) SetContext(v PredictionContext) {
b.context = v
}
func (b *BaseATNConfig) GetContext() PredictionContext {
return b.context
}
func (b *BaseATNConfig) GetSemanticContext() SemanticContext {
return b.semanticContext
}
func (b *BaseATNConfig) GetReachesIntoOuterContext() int {
return b.reachesIntoOuterContext
}
func (b *BaseATNConfig) SetReachesIntoOuterContext(v int) {
b.reachesIntoOuterContext = v
}
// An ATN configuration is equal to another if both have the same state, they
// predict the same alternative, and syntactic/semantic contexts are the same.
func (b *BaseATNConfig) equals(o interface{}) bool {
if b == o {
return true
}
var other, ok = o.(*BaseATNConfig)
if !ok {
return false
}
var equal bool
if b.context == nil {
equal = other.context == nil
} else {
equal = b.context.equals(other.context)
}
var (
nums = b.state.GetStateNumber() == other.state.GetStateNumber()
alts = b.alt == other.alt
cons = b.semanticContext.equals(other.semanticContext)
sups = b.precedenceFilterSuppressed == other.precedenceFilterSuppressed
)
return nums && alts && cons && sups && equal
}
func (b *BaseATNConfig) hash() int {
var c int
if b.context != nil {
c = b.context.hash()
}
h := murmurInit(7)
h = murmurUpdate(h, b.state.GetStateNumber())
h = murmurUpdate(h, b.alt)
h = murmurUpdate(h, c)
h = murmurUpdate(h, b.semanticContext.hash())
return murmurFinish(h, 4)
}
func (b *BaseATNConfig) String() string {
var s1, s2, s3 string
if b.context != nil {
s1 = ",[" + fmt.Sprint(b.context) + "]"
}
if b.semanticContext != SemanticContextNone {
s2 = "," + fmt.Sprint(b.semanticContext)
}
if b.reachesIntoOuterContext > 0 {
s3 = ",up=" + fmt.Sprint(b.reachesIntoOuterContext)
}
return fmt.Sprintf("(%v,%v%v%v%v)", b.state, b.alt, s1, s2, s3)
}
type LexerATNConfig struct {
*BaseATNConfig
lexerActionExecutor *LexerActionExecutor
passedThroughNonGreedyDecision bool
}
func NewLexerATNConfig6(state ATNState, alt int, context PredictionContext) *LexerATNConfig {
return &LexerATNConfig{BaseATNConfig: NewBaseATNConfig5(state, alt, context, SemanticContextNone)}
}
func NewLexerATNConfig5(state ATNState, alt int, context PredictionContext, lexerActionExecutor *LexerActionExecutor) *LexerATNConfig {
return &LexerATNConfig{
BaseATNConfig: NewBaseATNConfig5(state, alt, context, SemanticContextNone),
lexerActionExecutor: lexerActionExecutor,
}
}
func NewLexerATNConfig4(c *LexerATNConfig, state ATNState) *LexerATNConfig {
return &LexerATNConfig{
BaseATNConfig: NewBaseATNConfig(c, state, c.GetContext(), c.GetSemanticContext()),
lexerActionExecutor: c.lexerActionExecutor,
passedThroughNonGreedyDecision: checkNonGreedyDecision(c, state),
}
}
func NewLexerATNConfig3(c *LexerATNConfig, state ATNState, lexerActionExecutor *LexerActionExecutor) *LexerATNConfig {
return &LexerATNConfig{
BaseATNConfig: NewBaseATNConfig(c, state, c.GetContext(), c.GetSemanticContext()),
lexerActionExecutor: lexerActionExecutor,
passedThroughNonGreedyDecision: checkNonGreedyDecision(c, state),
}
}
func NewLexerATNConfig2(c *LexerATNConfig, state ATNState, context PredictionContext) *LexerATNConfig {
return &LexerATNConfig{
BaseATNConfig: NewBaseATNConfig(c, state, context, c.GetSemanticContext()),
lexerActionExecutor: c.lexerActionExecutor,
passedThroughNonGreedyDecision: checkNonGreedyDecision(c, state),
}
}
func NewLexerATNConfig1(state ATNState, alt int, context PredictionContext) *LexerATNConfig {
return &LexerATNConfig{BaseATNConfig: NewBaseATNConfig5(state, alt, context, SemanticContextNone)}
}
func (l *LexerATNConfig) hash() int {
var f int
if l.passedThroughNonGreedyDecision {
f = 1
} else {
f = 0
}
h := murmurInit(7)
h = murmurUpdate(h, l.state.hash())
h = murmurUpdate(h, l.alt)
h = murmurUpdate(h, l.context.hash())
h = murmurUpdate(h, l.semanticContext.hash())
h = murmurUpdate(h, f)
h = murmurUpdate(h, l.lexerActionExecutor.hash())
h = murmurFinish(h, 6)
return h
}
func (l *LexerATNConfig) equals(other interface{}) bool {
var othert, ok = other.(*LexerATNConfig)
if l == other {
return true
} else if !ok {
return false
} else if l.passedThroughNonGreedyDecision != othert.passedThroughNonGreedyDecision {
return false
}
var b bool
if l.lexerActionExecutor != nil {
b = !l.lexerActionExecutor.equals(othert.lexerActionExecutor)
} else {
b = othert.lexerActionExecutor != nil
}
if b {
return false
}
return l.BaseATNConfig.equals(othert.BaseATNConfig)
}
func checkNonGreedyDecision(source *LexerATNConfig, target ATNState) bool {
var ds, ok = target.(DecisionState)
return source.passedThroughNonGreedyDecision || (ok && ds.getNonGreedy())
}

View File

@@ -0,0 +1,387 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import "fmt"
type ATNConfigSet interface {
hash() int
Add(ATNConfig, *DoubleDict) bool
AddAll([]ATNConfig) bool
GetStates() *Set
GetPredicates() []SemanticContext
GetItems() []ATNConfig
OptimizeConfigs(interpreter *BaseATNSimulator)
Equals(other interface{}) bool
Length() int
IsEmpty() bool
Contains(ATNConfig) bool
ContainsFast(ATNConfig) bool
Clear()
String() string
HasSemanticContext() bool
SetHasSemanticContext(v bool)
ReadOnly() bool
SetReadOnly(bool)
GetConflictingAlts() *BitSet
SetConflictingAlts(*BitSet)
FullContext() bool
GetUniqueAlt() int
SetUniqueAlt(int)
GetDipsIntoOuterContext() bool
SetDipsIntoOuterContext(bool)
}
// BaseATNConfigSet is a specialized set of ATNConfig that tracks information
// about its elements and can combine similar configurations using a
// graph-structured stack.
type BaseATNConfigSet struct {
cachedHash int
// configLookup is used to determine whether two BaseATNConfigSets are equal. We
// need all configurations with the same (s, i, _, semctx) to be equal. A key
// effectively doubles the number of objects associated with ATNConfigs. All
// keys are hashed by (s, i, _, pi), not including the context. Wiped out when
// read-only because a set becomes a DFA state.
configLookup *Set
// configs is the added elements.
configs []ATNConfig
// TODO: These fields make me pretty uncomfortable, but it is nice to pack up
// info together because it saves recomputation. Can we track conflicts as they
// are added to save scanning configs later?
conflictingAlts *BitSet
// dipsIntoOuterContext is used by parsers and lexers. In a lexer, it indicates
// we hit a pred while computing a closure operation. Do not make a DFA state
// from the BaseATNConfigSet in this case. TODO: How is this used by parsers?
dipsIntoOuterContext bool
// fullCtx is whether it is part of a full context LL prediction. Used to
// determine how to merge $. It is a wildcard with SLL, but not for an LL
// context merge.
fullCtx bool
// Used in parser and lexer. In lexer, it indicates we hit a pred
// while computing a closure operation. Don't make a DFA state from a.
hasSemanticContext bool
// readOnly is whether it is read-only. Do not
// allow any code to manipulate the set if true because DFA states will point at
// sets and those must not change. It not protect other fields; conflictingAlts
// in particular, which is assigned after readOnly.
readOnly bool
// TODO: These fields make me pretty uncomfortable, but it is nice to pack up
// info together because it saves recomputation. Can we track conflicts as they
// are added to save scanning configs later?
uniqueAlt int
}
func NewBaseATNConfigSet(fullCtx bool) *BaseATNConfigSet {
return &BaseATNConfigSet{
cachedHash: -1,
configLookup: NewSet(nil, equalATNConfigs),
fullCtx: fullCtx,
}
}
// Add merges contexts with existing configs for (s, i, pi, _), where s is the
// ATNConfig.state, i is the ATNConfig.alt, and pi is the
// ATNConfig.semanticContext. We use (s,i,pi) as the key. Updates
// dipsIntoOuterContext and hasSemanticContext when necessary.
func (b *BaseATNConfigSet) Add(config ATNConfig, mergeCache *DoubleDict) bool {
if b.readOnly {
panic("set is read-only")
}
if config.GetSemanticContext() != SemanticContextNone {
b.hasSemanticContext = true
}
if config.GetReachesIntoOuterContext() > 0 {
b.dipsIntoOuterContext = true
}
existing := b.configLookup.add(config).(ATNConfig)
if existing == config {
b.cachedHash = -1
b.configs = append(b.configs, config) // Track order here
return true
}
// Merge a previous (s, i, pi, _) with it and save the result
rootIsWildcard := !b.fullCtx
merged := merge(existing.GetContext(), config.GetContext(), rootIsWildcard, mergeCache)
// No need to check for existing.context because config.context is in the cache,
// since the only way to create new graphs is the "call rule" and here. We cache
// at both places.
existing.SetReachesIntoOuterContext(intMax(existing.GetReachesIntoOuterContext(), config.GetReachesIntoOuterContext()))
// Preserve the precedence filter suppression during the merge
if config.getPrecedenceFilterSuppressed() {
existing.setPrecedenceFilterSuppressed(true)
}
// Replace the context because there is no need to do alt mapping
existing.SetContext(merged)
return true
}
func (b *BaseATNConfigSet) GetStates() *Set {
states := NewSet(nil, nil)
for i := 0; i < len(b.configs); i++ {
states.add(b.configs[i].GetState())
}
return states
}
func (b *BaseATNConfigSet) HasSemanticContext() bool {
return b.hasSemanticContext
}
func (b *BaseATNConfigSet) SetHasSemanticContext(v bool) {
b.hasSemanticContext = v
}
func (b *BaseATNConfigSet) GetPredicates() []SemanticContext {
preds := make([]SemanticContext, 0)
for i := 0; i < len(b.configs); i++ {
c := b.configs[i].GetSemanticContext()
if c != SemanticContextNone {
preds = append(preds, c)
}
}
return preds
}
func (b *BaseATNConfigSet) GetItems() []ATNConfig {
return b.configs
}
func (b *BaseATNConfigSet) OptimizeConfigs(interpreter *BaseATNSimulator) {
if b.readOnly {
panic("set is read-only")
}
if b.configLookup.length() == 0 {
return
}
for i := 0; i < len(b.configs); i++ {
config := b.configs[i]
config.SetContext(interpreter.getCachedContext(config.GetContext()))
}
}
func (b *BaseATNConfigSet) AddAll(coll []ATNConfig) bool {
for i := 0; i < len(coll); i++ {
b.Add(coll[i], nil)
}
return false
}
func (b *BaseATNConfigSet) Equals(other interface{}) bool {
if b == other {
return true
} else if _, ok := other.(*BaseATNConfigSet); !ok {
return false
}
other2 := other.(*BaseATNConfigSet)
return b.configs != nil &&
// TODO: b.configs.equals(other2.configs) && // TODO: Is b necessary?
b.fullCtx == other2.fullCtx &&
b.uniqueAlt == other2.uniqueAlt &&
b.conflictingAlts == other2.conflictingAlts &&
b.hasSemanticContext == other2.hasSemanticContext &&
b.dipsIntoOuterContext == other2.dipsIntoOuterContext
}
func (b *BaseATNConfigSet) hash() int {
if b.readOnly {
if b.cachedHash == -1 {
b.cachedHash = b.hashCodeConfigs()
}
return b.cachedHash
}
return b.hashCodeConfigs()
}
func (b *BaseATNConfigSet) hashCodeConfigs() int {
h := murmurInit(1)
for _, c := range b.configs {
if c != nil {
h = murmurUpdate(h, c.hash())
}
}
return murmurFinish(h, len(b.configs))
}
func (b *BaseATNConfigSet) Length() int {
return len(b.configs)
}
func (b *BaseATNConfigSet) IsEmpty() bool {
return len(b.configs) == 0
}
func (b *BaseATNConfigSet) Contains(item ATNConfig) bool {
if b.configLookup == nil {
panic("not implemented for read-only sets")
}
return b.configLookup.contains(item)
}
func (b *BaseATNConfigSet) ContainsFast(item ATNConfig) bool {
if b.configLookup == nil {
panic("not implemented for read-only sets")
}
return b.configLookup.contains(item) // TODO: containsFast is not implemented for Set
}
func (b *BaseATNConfigSet) Clear() {
if b.readOnly {
panic("set is read-only")
}
b.configs = make([]ATNConfig, 0)
b.cachedHash = -1
b.configLookup = NewSet(nil, equalATNConfigs)
}
func (b *BaseATNConfigSet) FullContext() bool {
return b.fullCtx
}
func (b *BaseATNConfigSet) GetDipsIntoOuterContext() bool {
return b.dipsIntoOuterContext
}
func (b *BaseATNConfigSet) SetDipsIntoOuterContext(v bool) {
b.dipsIntoOuterContext = v
}
func (b *BaseATNConfigSet) GetUniqueAlt() int {
return b.uniqueAlt
}
func (b *BaseATNConfigSet) SetUniqueAlt(v int) {
b.uniqueAlt = v
}
func (b *BaseATNConfigSet) GetConflictingAlts() *BitSet {
return b.conflictingAlts
}
func (b *BaseATNConfigSet) SetConflictingAlts(v *BitSet) {
b.conflictingAlts = v
}
func (b *BaseATNConfigSet) ReadOnly() bool {
return b.readOnly
}
func (b *BaseATNConfigSet) SetReadOnly(readOnly bool) {
b.readOnly = readOnly
if readOnly {
b.configLookup = nil // Read only, so no need for the lookup cache
}
}
func (b *BaseATNConfigSet) String() string {
s := "["
for i, c := range b.configs {
s += c.String()
if i != len(b.configs)-1 {
s += ", "
}
}
s += "]"
if b.hasSemanticContext {
s += ",hasSemanticContext=" + fmt.Sprint(b.hasSemanticContext)
}
if b.uniqueAlt != ATNInvalidAltNumber {
s += ",uniqueAlt=" + fmt.Sprint(b.uniqueAlt)
}
if b.conflictingAlts != nil {
s += ",conflictingAlts=" + b.conflictingAlts.String()
}
if b.dipsIntoOuterContext {
s += ",dipsIntoOuterContext"
}
return s
}
type OrderedATNConfigSet struct {
*BaseATNConfigSet
}
func NewOrderedATNConfigSet() *OrderedATNConfigSet {
b := NewBaseATNConfigSet(false)
b.configLookup = NewSet(nil, nil)
return &OrderedATNConfigSet{BaseATNConfigSet: b}
}
func equalATNConfigs(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
if a == b {
return true
}
var ai, ok = a.(ATNConfig)
var bi, ok1 = b.(ATNConfig)
if !ok || !ok1 {
return false
}
nums := ai.GetState().GetStateNumber() == bi.GetState().GetStateNumber()
alts := ai.GetAlt() == bi.GetAlt()
cons := ai.GetSemanticContext().equals(bi.GetSemanticContext())
return nums && alts && cons
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
var ATNDeserializationOptionsdefaultOptions = &ATNDeserializationOptions{true, false, false}
type ATNDeserializationOptions struct {
readOnly bool
verifyATN bool
generateRuleBypassTransitions bool
}
func NewATNDeserializationOptions(CopyFrom *ATNDeserializationOptions) *ATNDeserializationOptions {
o := new(ATNDeserializationOptions)
if CopyFrom != nil {
o.readOnly = CopyFrom.readOnly
o.verifyATN = CopyFrom.verifyATN
o.generateRuleBypassTransitions = CopyFrom.generateRuleBypassTransitions
}
return o
}

View File

@@ -0,0 +1,828 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"encoding/hex"
"fmt"
"strconv"
"strings"
"unicode/utf16"
)
// This is the earliest supported serialized UUID.
// stick to serialized version for now, we don't need a UUID instance
var BaseSerializedUUID = "AADB8D7E-AEEF-4415-AD2B-8204D6CF042E"
var AddedUnicodeSMP = "59627784-3BE5-417A-B9EB-8131A7286089"
// This list contains all of the currently supported UUIDs, ordered by when
// the feature first appeared in this branch.
var SupportedUUIDs = []string{BaseSerializedUUID, AddedUnicodeSMP}
var SerializedVersion = 3
// This is the current serialized UUID.
var SerializedUUID = AddedUnicodeSMP
type LoopEndStateIntPair struct {
item0 *LoopEndState
item1 int
}
type BlockStartStateIntPair struct {
item0 BlockStartState
item1 int
}
type ATNDeserializer struct {
deserializationOptions *ATNDeserializationOptions
data []rune
pos int
uuid string
}
func NewATNDeserializer(options *ATNDeserializationOptions) *ATNDeserializer {
if options == nil {
options = ATNDeserializationOptionsdefaultOptions
}
return &ATNDeserializer{deserializationOptions: options}
}
func stringInSlice(a string, list []string) int {
for i, b := range list {
if b == a {
return i
}
}
return -1
}
// isFeatureSupported determines if a particular serialized representation of an
// ATN supports a particular feature, identified by the UUID used for
// serializing the ATN at the time the feature was first introduced. Feature is
// the UUID marking the first time the feature was supported in the serialized
// ATN. ActualUuid is the UUID of the actual serialized ATN which is currently
// being deserialized. It returns true if actualUuid represents a serialized ATN
// at or after the feature identified by feature was introduced, and otherwise
// false.
func (a *ATNDeserializer) isFeatureSupported(feature, actualUUID string) bool {
idx1 := stringInSlice(feature, SupportedUUIDs)
if idx1 < 0 {
return false
}
idx2 := stringInSlice(actualUUID, SupportedUUIDs)
return idx2 >= idx1
}
func (a *ATNDeserializer) DeserializeFromUInt16(data []uint16) *ATN {
a.reset(utf16.Decode(data))
a.checkVersion()
a.checkUUID()
atn := a.readATN()
a.readStates(atn)
a.readRules(atn)
a.readModes(atn)
sets := make([]*IntervalSet, 0)
// First, deserialize sets with 16-bit arguments <= U+FFFF.
sets = a.readSets(atn, sets, a.readInt)
// Next, if the ATN was serialized with the Unicode SMP feature,
// deserialize sets with 32-bit arguments <= U+10FFFF.
if (a.isFeatureSupported(AddedUnicodeSMP, a.uuid)) {
sets = a.readSets(atn, sets, a.readInt32)
}
a.readEdges(atn, sets)
a.readDecisions(atn)
a.readLexerActions(atn)
a.markPrecedenceDecisions(atn)
a.verifyATN(atn)
if a.deserializationOptions.generateRuleBypassTransitions && atn.grammarType == ATNTypeParser {
a.generateRuleBypassTransitions(atn)
// Re-verify after modification
a.verifyATN(atn)
}
return atn
}
func (a *ATNDeserializer) reset(data []rune) {
temp := make([]rune, len(data))
for i, c := range data {
// Don't adjust the first value since that's the version number
if i == 0 {
temp[i] = c
} else if c > 1 {
temp[i] = c - 2
} else {
temp[i] = c + 65533
}
}
a.data = temp
a.pos = 0
}
func (a *ATNDeserializer) checkVersion() {
version := a.readInt()
if version != SerializedVersion {
panic("Could not deserialize ATN with version " + strconv.Itoa(version) + " (expected " + strconv.Itoa(SerializedVersion) + ").")
}
}
func (a *ATNDeserializer) checkUUID() {
uuid := a.readUUID()
if stringInSlice(uuid, SupportedUUIDs) < 0 {
panic("Could not deserialize ATN with UUID: " + uuid + " (expected " + SerializedUUID + " or a legacy UUID).")
}
a.uuid = uuid
}
func (a *ATNDeserializer) readATN() *ATN {
grammarType := a.readInt()
maxTokenType := a.readInt()
return NewATN(grammarType, maxTokenType)
}
func (a *ATNDeserializer) readStates(atn *ATN) {
loopBackStateNumbers := make([]LoopEndStateIntPair, 0)
endStateNumbers := make([]BlockStartStateIntPair, 0)
nstates := a.readInt()
for i := 0; i < nstates; i++ {
stype := a.readInt()
// Ignore bad types of states
if stype == ATNStateInvalidType {
atn.addState(nil)
continue
}
ruleIndex := a.readInt()
if ruleIndex == 0xFFFF {
ruleIndex = -1
}
s := a.stateFactory(stype, ruleIndex)
if stype == ATNStateLoopEnd {
loopBackStateNumber := a.readInt()
loopBackStateNumbers = append(loopBackStateNumbers, LoopEndStateIntPair{s.(*LoopEndState), loopBackStateNumber})
} else if s2, ok := s.(BlockStartState); ok {
endStateNumber := a.readInt()
endStateNumbers = append(endStateNumbers, BlockStartStateIntPair{s2, endStateNumber})
}
atn.addState(s)
}
// Delay the assignment of loop back and end states until we know all the state
// instances have been initialized
for j := 0; j < len(loopBackStateNumbers); j++ {
pair := loopBackStateNumbers[j]
pair.item0.loopBackState = atn.states[pair.item1]
}
for j := 0; j < len(endStateNumbers); j++ {
pair := endStateNumbers[j]
pair.item0.setEndState(atn.states[pair.item1].(*BlockEndState))
}
numNonGreedyStates := a.readInt()
for j := 0; j < numNonGreedyStates; j++ {
stateNumber := a.readInt()
atn.states[stateNumber].(DecisionState).setNonGreedy(true)
}
numPrecedenceStates := a.readInt()
for j := 0; j < numPrecedenceStates; j++ {
stateNumber := a.readInt()
atn.states[stateNumber].(*RuleStartState).isPrecedenceRule = true
}
}
func (a *ATNDeserializer) readRules(atn *ATN) {
nrules := a.readInt()
if atn.grammarType == ATNTypeLexer {
atn.ruleToTokenType = make([]int, nrules) // TODO: initIntArray(nrules, 0)
}
atn.ruleToStartState = make([]*RuleStartState, nrules) // TODO: initIntArray(nrules, 0)
for i := 0; i < nrules; i++ {
s := a.readInt()
startState := atn.states[s].(*RuleStartState)
atn.ruleToStartState[i] = startState
if atn.grammarType == ATNTypeLexer {
tokenType := a.readInt()
if tokenType == 0xFFFF {
tokenType = TokenEOF
}
atn.ruleToTokenType[i] = tokenType
}
}
atn.ruleToStopState = make([]*RuleStopState, nrules) //initIntArray(nrules, 0)
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
if s2, ok := state.(*RuleStopState); ok {
atn.ruleToStopState[s2.ruleIndex] = s2
atn.ruleToStartState[s2.ruleIndex].stopState = s2
}
}
}
func (a *ATNDeserializer) readModes(atn *ATN) {
nmodes := a.readInt()
for i := 0; i < nmodes; i++ {
s := a.readInt()
atn.modeToStartState = append(atn.modeToStartState, atn.states[s].(*TokensStartState))
}
}
func (a *ATNDeserializer) readSets(atn *ATN, sets []*IntervalSet, readUnicode func() int) []*IntervalSet {
m := a.readInt()
for i := 0; i < m; i++ {
iset := NewIntervalSet()
sets = append(sets, iset)
n := a.readInt()
containsEOF := a.readInt()
if containsEOF != 0 {
iset.addOne(-1)
}
for j := 0; j < n; j++ {
i1 := readUnicode()
i2 := readUnicode()
iset.addRange(i1, i2)
}
}
return sets
}
func (a *ATNDeserializer) readEdges(atn *ATN, sets []*IntervalSet) {
nedges := a.readInt()
for i := 0; i < nedges; i++ {
var (
src = a.readInt()
trg = a.readInt()
ttype = a.readInt()
arg1 = a.readInt()
arg2 = a.readInt()
arg3 = a.readInt()
trans = a.edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets)
srcState = atn.states[src]
)
srcState.AddTransition(trans, -1)
}
// Edges for rule stop states can be derived, so they are not serialized
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
for j := 0; j < len(state.GetTransitions()); j++ {
var t, ok = state.GetTransitions()[j].(*RuleTransition)
if !ok {
continue
}
outermostPrecedenceReturn := -1
if atn.ruleToStartState[t.getTarget().GetRuleIndex()].isPrecedenceRule {
if t.precedence == 0 {
outermostPrecedenceReturn = t.getTarget().GetRuleIndex()
}
}
trans := NewEpsilonTransition(t.followState, outermostPrecedenceReturn)
atn.ruleToStopState[t.getTarget().GetRuleIndex()].AddTransition(trans, -1)
}
}
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
if s2, ok := state.(*BaseBlockStartState); ok {
// We need to know the end state to set its start state
if s2.endState == nil {
panic("IllegalState")
}
// Block end states can only be associated to a single block start state
if s2.endState.startState != nil {
panic("IllegalState")
}
s2.endState.startState = state
}
if s2, ok := state.(*PlusLoopbackState); ok {
for j := 0; j < len(s2.GetTransitions()); j++ {
target := s2.GetTransitions()[j].getTarget()
if t2, ok := target.(*PlusBlockStartState); ok {
t2.loopBackState = state
}
}
} else if s2, ok := state.(*StarLoopbackState); ok {
for j := 0; j < len(s2.GetTransitions()); j++ {
target := s2.GetTransitions()[j].getTarget()
if t2, ok := target.(*StarLoopEntryState); ok {
t2.loopBackState = state
}
}
}
}
}
func (a *ATNDeserializer) readDecisions(atn *ATN) {
ndecisions := a.readInt()
for i := 0; i < ndecisions; i++ {
s := a.readInt()
decState := atn.states[s].(DecisionState)
atn.DecisionToState = append(atn.DecisionToState, decState)
decState.setDecision(i)
}
}
func (a *ATNDeserializer) readLexerActions(atn *ATN) {
if atn.grammarType == ATNTypeLexer {
count := a.readInt()
atn.lexerActions = make([]LexerAction, count) // initIntArray(count, nil)
for i := 0; i < count; i++ {
actionType := a.readInt()
data1 := a.readInt()
if data1 == 0xFFFF {
data1 = -1
}
data2 := a.readInt()
if data2 == 0xFFFF {
data2 = -1
}
lexerAction := a.lexerActionFactory(actionType, data1, data2)
atn.lexerActions[i] = lexerAction
}
}
}
func (a *ATNDeserializer) generateRuleBypassTransitions(atn *ATN) {
count := len(atn.ruleToStartState)
for i := 0; i < count; i++ {
atn.ruleToTokenType[i] = atn.maxTokenType + i + 1
}
for i := 0; i < count; i++ {
a.generateRuleBypassTransition(atn, i)
}
}
func (a *ATNDeserializer) generateRuleBypassTransition(atn *ATN, idx int) {
bypassStart := NewBasicBlockStartState()
bypassStart.ruleIndex = idx
atn.addState(bypassStart)
bypassStop := NewBlockEndState()
bypassStop.ruleIndex = idx
atn.addState(bypassStop)
bypassStart.endState = bypassStop
atn.defineDecisionState(bypassStart.BaseDecisionState)
bypassStop.startState = bypassStart
var excludeTransition Transition
var endState ATNState
if atn.ruleToStartState[idx].isPrecedenceRule {
// Wrap from the beginning of the rule to the StarLoopEntryState
endState = nil
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
if a.stateIsEndStateFor(state, idx) != nil {
endState = state
excludeTransition = state.(*StarLoopEntryState).loopBackState.GetTransitions()[0]
break
}
}
if excludeTransition == nil {
panic("Couldn't identify final state of the precedence rule prefix section.")
}
} else {
endState = atn.ruleToStopState[idx]
}
// All non-excluded transitions that currently target end state need to target
// blockEnd instead
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
for j := 0; j < len(state.GetTransitions()); j++ {
transition := state.GetTransitions()[j]
if transition == excludeTransition {
continue
}
if transition.getTarget() == endState {
transition.setTarget(bypassStop)
}
}
}
// All transitions leaving the rule start state need to leave blockStart instead
ruleToStartState := atn.ruleToStartState[idx]
count := len(ruleToStartState.GetTransitions())
for count > 0 {
bypassStart.AddTransition(ruleToStartState.GetTransitions()[count-1], -1)
ruleToStartState.SetTransitions([]Transition{ruleToStartState.GetTransitions()[len(ruleToStartState.GetTransitions())-1]})
}
// Link the new states
atn.ruleToStartState[idx].AddTransition(NewEpsilonTransition(bypassStart, -1), -1)
bypassStop.AddTransition(NewEpsilonTransition(endState, -1), -1)
MatchState := NewBasicState()
atn.addState(MatchState)
MatchState.AddTransition(NewAtomTransition(bypassStop, atn.ruleToTokenType[idx]), -1)
bypassStart.AddTransition(NewEpsilonTransition(MatchState, -1), -1)
}
func (a *ATNDeserializer) stateIsEndStateFor(state ATNState, idx int) ATNState {
if state.GetRuleIndex() != idx {
return nil
}
if _, ok := state.(*StarLoopEntryState); !ok {
return nil
}
maybeLoopEndState := state.GetTransitions()[len(state.GetTransitions())-1].getTarget()
if _, ok := maybeLoopEndState.(*LoopEndState); !ok {
return nil
}
var _, ok = maybeLoopEndState.GetTransitions()[0].getTarget().(*RuleStopState)
if maybeLoopEndState.(*LoopEndState).epsilonOnlyTransitions && ok {
return state
}
return nil
}
// markPrecedenceDecisions analyzes the StarLoopEntryState states in the
// specified ATN to set the StarLoopEntryState.precedenceRuleDecision field to
// the correct value.
func (a *ATNDeserializer) markPrecedenceDecisions(atn *ATN) {
for _, state := range atn.states {
if _, ok := state.(*StarLoopEntryState); !ok {
continue
}
// We analyze the ATN to determine if a ATN decision state is the
// decision for the closure block that determines whether a
// precedence rule should continue or complete.
if atn.ruleToStartState[state.GetRuleIndex()].isPrecedenceRule {
maybeLoopEndState := state.GetTransitions()[len(state.GetTransitions())-1].getTarget()
if s3, ok := maybeLoopEndState.(*LoopEndState); ok {
var _, ok2 = maybeLoopEndState.GetTransitions()[0].getTarget().(*RuleStopState)
if s3.epsilonOnlyTransitions && ok2 {
state.(*StarLoopEntryState).precedenceRuleDecision = true
}
}
}
}
}
func (a *ATNDeserializer) verifyATN(atn *ATN) {
if !a.deserializationOptions.verifyATN {
return
}
// Verify assumptions
for i := 0; i < len(atn.states); i++ {
state := atn.states[i]
if state == nil {
continue
}
a.checkCondition(state.GetEpsilonOnlyTransitions() || len(state.GetTransitions()) <= 1, "")
switch s2 := state.(type) {
case *PlusBlockStartState:
a.checkCondition(s2.loopBackState != nil, "")
case *StarLoopEntryState:
a.checkCondition(s2.loopBackState != nil, "")
a.checkCondition(len(s2.GetTransitions()) == 2, "")
switch s2 := state.(type) {
case *StarBlockStartState:
var _, ok2 = s2.GetTransitions()[1].getTarget().(*LoopEndState)
a.checkCondition(ok2, "")
a.checkCondition(!s2.nonGreedy, "")
case *LoopEndState:
var s3, ok2 = s2.GetTransitions()[1].getTarget().(*StarBlockStartState)
a.checkCondition(ok2, "")
a.checkCondition(s3.nonGreedy, "")
default:
panic("IllegalState")
}
case *StarLoopbackState:
a.checkCondition(len(state.GetTransitions()) == 1, "")
var _, ok2 = state.GetTransitions()[0].getTarget().(*StarLoopEntryState)
a.checkCondition(ok2, "")
case *LoopEndState:
a.checkCondition(s2.loopBackState != nil, "")
case *RuleStartState:
a.checkCondition(s2.stopState != nil, "")
case *BaseBlockStartState:
a.checkCondition(s2.endState != nil, "")
case *BlockEndState:
a.checkCondition(s2.startState != nil, "")
case DecisionState:
a.checkCondition(len(s2.GetTransitions()) <= 1 || s2.getDecision() >= 0, "")
default:
var _, ok = s2.(*RuleStopState)
a.checkCondition(len(s2.GetTransitions()) <= 1 || ok, "")
}
}
}
func (a *ATNDeserializer) checkCondition(condition bool, message string) {
if !condition {
if message == "" {
message = "IllegalState"
}
panic(message)
}
}
func (a *ATNDeserializer) readInt() int {
v := a.data[a.pos]
a.pos++
return int(v)
}
func (a *ATNDeserializer) readInt32() int {
var low = a.readInt()
var high = a.readInt()
return low | (high << 16)
}
//TODO
//func (a *ATNDeserializer) readLong() int64 {
// panic("Not implemented")
// var low = a.readInt32()
// var high = a.readInt32()
// return (low & 0x00000000FFFFFFFF) | (high << int32)
//}
func createByteToHex() []string {
bth := make([]string, 256)
for i := 0; i < 256; i++ {
bth[i] = strings.ToUpper(hex.EncodeToString([]byte{byte(i)}))
}
return bth
}
var byteToHex = createByteToHex()
func (a *ATNDeserializer) readUUID() string {
bb := make([]int, 16)
for i := 7; i >= 0; i-- {
integer := a.readInt()
bb[(2*i)+1] = integer & 0xFF
bb[2*i] = (integer >> 8) & 0xFF
}
return byteToHex[bb[0]] + byteToHex[bb[1]] +
byteToHex[bb[2]] + byteToHex[bb[3]] + "-" +
byteToHex[bb[4]] + byteToHex[bb[5]] + "-" +
byteToHex[bb[6]] + byteToHex[bb[7]] + "-" +
byteToHex[bb[8]] + byteToHex[bb[9]] + "-" +
byteToHex[bb[10]] + byteToHex[bb[11]] +
byteToHex[bb[12]] + byteToHex[bb[13]] +
byteToHex[bb[14]] + byteToHex[bb[15]]
}
func (a *ATNDeserializer) edgeFactory(atn *ATN, typeIndex, src, trg, arg1, arg2, arg3 int, sets []*IntervalSet) Transition {
target := atn.states[trg]
switch typeIndex {
case TransitionEPSILON:
return NewEpsilonTransition(target, -1)
case TransitionRANGE:
if arg3 != 0 {
return NewRangeTransition(target, TokenEOF, arg2)
}
return NewRangeTransition(target, arg1, arg2)
case TransitionRULE:
return NewRuleTransition(atn.states[arg1], arg2, arg3, target)
case TransitionPREDICATE:
return NewPredicateTransition(target, arg1, arg2, arg3 != 0)
case TransitionPRECEDENCE:
return NewPrecedencePredicateTransition(target, arg1)
case TransitionATOM:
if arg3 != 0 {
return NewAtomTransition(target, TokenEOF)
}
return NewAtomTransition(target, arg1)
case TransitionACTION:
return NewActionTransition(target, arg1, arg2, arg3 != 0)
case TransitionSET:
return NewSetTransition(target, sets[arg1])
case TransitionNOTSET:
return NewNotSetTransition(target, sets[arg1])
case TransitionWILDCARD:
return NewWildcardTransition(target)
}
panic("The specified transition type is not valid.")
}
func (a *ATNDeserializer) stateFactory(typeIndex, ruleIndex int) ATNState {
var s ATNState
switch typeIndex {
case ATNStateInvalidType:
return nil
case ATNStateBasic:
s = NewBasicState()
case ATNStateRuleStart:
s = NewRuleStartState()
case ATNStateBlockStart:
s = NewBasicBlockStartState()
case ATNStatePlusBlockStart:
s = NewPlusBlockStartState()
case ATNStateStarBlockStart:
s = NewStarBlockStartState()
case ATNStateTokenStart:
s = NewTokensStartState()
case ATNStateRuleStop:
s = NewRuleStopState()
case ATNStateBlockEnd:
s = NewBlockEndState()
case ATNStateStarLoopBack:
s = NewStarLoopbackState()
case ATNStateStarLoopEntry:
s = NewStarLoopEntryState()
case ATNStatePlusLoopBack:
s = NewPlusLoopbackState()
case ATNStateLoopEnd:
s = NewLoopEndState()
default:
panic(fmt.Sprintf("state type %d is invalid", typeIndex))
}
s.SetRuleIndex(ruleIndex)
return s
}
func (a *ATNDeserializer) lexerActionFactory(typeIndex, data1, data2 int) LexerAction {
switch typeIndex {
case LexerActionTypeChannel:
return NewLexerChannelAction(data1)
case LexerActionTypeCustom:
return NewLexerCustomAction(data1, data2)
case LexerActionTypeMode:
return NewLexerModeAction(data1)
case LexerActionTypeMore:
return LexerMoreActionINSTANCE
case LexerActionTypePopMode:
return LexerPopModeActionINSTANCE
case LexerActionTypePushMode:
return NewLexerPushModeAction(data1)
case LexerActionTypeSkip:
return LexerSkipActionINSTANCE
case LexerActionTypeType:
return NewLexerTypeAction(data1)
default:
panic(fmt.Sprintf("lexer action %d is invalid", typeIndex))
}
}

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
var ATNSimulatorError = NewDFAState(0x7FFFFFFF, NewBaseATNConfigSet(false))
type IATNSimulator interface {
SharedContextCache() *PredictionContextCache
ATN() *ATN
DecisionToDFA() []*DFA
}
type BaseATNSimulator struct {
atn *ATN
sharedContextCache *PredictionContextCache
decisionToDFA []*DFA
}
func NewBaseATNSimulator(atn *ATN, sharedContextCache *PredictionContextCache) *BaseATNSimulator {
b := new(BaseATNSimulator)
b.atn = atn
b.sharedContextCache = sharedContextCache
return b
}
func (b *BaseATNSimulator) getCachedContext(context PredictionContext) PredictionContext {
if b.sharedContextCache == nil {
return context
}
visited := make(map[PredictionContext]PredictionContext)
return getCachedBasePredictionContext(context, b.sharedContextCache, visited)
}
func (b *BaseATNSimulator) SharedContextCache() *PredictionContextCache {
return b.sharedContextCache
}
func (b *BaseATNSimulator) ATN() *ATN {
return b.atn
}
func (b *BaseATNSimulator) DecisionToDFA() []*DFA {
return b.decisionToDFA
}

View File

@@ -0,0 +1,386 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import "strconv"
// Constants for serialization.
const (
ATNStateInvalidType = 0
ATNStateBasic = 1
ATNStateRuleStart = 2
ATNStateBlockStart = 3
ATNStatePlusBlockStart = 4
ATNStateStarBlockStart = 5
ATNStateTokenStart = 6
ATNStateRuleStop = 7
ATNStateBlockEnd = 8
ATNStateStarLoopBack = 9
ATNStateStarLoopEntry = 10
ATNStatePlusLoopBack = 11
ATNStateLoopEnd = 12
ATNStateInvalidStateNumber = -1
)
var ATNStateInitialNumTransitions = 4
type ATNState interface {
GetEpsilonOnlyTransitions() bool
GetRuleIndex() int
SetRuleIndex(int)
GetNextTokenWithinRule() *IntervalSet
SetNextTokenWithinRule(*IntervalSet)
GetATN() *ATN
SetATN(*ATN)
GetStateType() int
GetStateNumber() int
SetStateNumber(int)
GetTransitions() []Transition
SetTransitions([]Transition)
AddTransition(Transition, int)
String() string
hash() int
}
type BaseATNState struct {
// NextTokenWithinRule caches lookahead during parsing. Not used during construction.
NextTokenWithinRule *IntervalSet
// atn is the current ATN.
atn *ATN
epsilonOnlyTransitions bool
// ruleIndex tracks the Rule index because there are no Rule objects at runtime.
ruleIndex int
stateNumber int
stateType int
// Track the transitions emanating from this ATN state.
transitions []Transition
}
func NewBaseATNState() *BaseATNState {
return &BaseATNState{stateNumber: ATNStateInvalidStateNumber, stateType: ATNStateInvalidType}
}
func (as *BaseATNState) GetRuleIndex() int {
return as.ruleIndex
}
func (as *BaseATNState) SetRuleIndex(v int) {
as.ruleIndex = v
}
func (as *BaseATNState) GetEpsilonOnlyTransitions() bool {
return as.epsilonOnlyTransitions
}
func (as *BaseATNState) GetATN() *ATN {
return as.atn
}
func (as *BaseATNState) SetATN(atn *ATN) {
as.atn = atn
}
func (as *BaseATNState) GetTransitions() []Transition {
return as.transitions
}
func (as *BaseATNState) SetTransitions(t []Transition) {
as.transitions = t
}
func (as *BaseATNState) GetStateType() int {
return as.stateType
}
func (as *BaseATNState) GetStateNumber() int {
return as.stateNumber
}
func (as *BaseATNState) SetStateNumber(stateNumber int) {
as.stateNumber = stateNumber
}
func (as *BaseATNState) GetNextTokenWithinRule() *IntervalSet {
return as.NextTokenWithinRule
}
func (as *BaseATNState) SetNextTokenWithinRule(v *IntervalSet) {
as.NextTokenWithinRule = v
}
func (as *BaseATNState) hash() int {
return as.stateNumber
}
func (as *BaseATNState) String() string {
return strconv.Itoa(as.stateNumber)
}
func (as *BaseATNState) equals(other interface{}) bool {
if ot, ok := other.(ATNState); ok {
return as.stateNumber == ot.GetStateNumber()
}
return false
}
func (as *BaseATNState) isNonGreedyExitState() bool {
return false
}
func (as *BaseATNState) AddTransition(trans Transition, index int) {
if len(as.transitions) == 0 {
as.epsilonOnlyTransitions = trans.getIsEpsilon()
} else if as.epsilonOnlyTransitions != trans.getIsEpsilon() {
as.epsilonOnlyTransitions = false
}
if index == -1 {
as.transitions = append(as.transitions, trans)
} else {
as.transitions = append(as.transitions[:index], append([]Transition{trans}, as.transitions[index:]...)...)
// TODO: as.transitions.splice(index, 1, trans)
}
}
type BasicState struct {
*BaseATNState
}
func NewBasicState() *BasicState {
b := NewBaseATNState()
b.stateType = ATNStateBasic
return &BasicState{BaseATNState: b}
}
type DecisionState interface {
ATNState
getDecision() int
setDecision(int)
getNonGreedy() bool
setNonGreedy(bool)
}
type BaseDecisionState struct {
*BaseATNState
decision int
nonGreedy bool
}
func NewBaseDecisionState() *BaseDecisionState {
return &BaseDecisionState{BaseATNState: NewBaseATNState(), decision: -1}
}
func (s *BaseDecisionState) getDecision() int {
return s.decision
}
func (s *BaseDecisionState) setDecision(b int) {
s.decision = b
}
func (s *BaseDecisionState) getNonGreedy() bool {
return s.nonGreedy
}
func (s *BaseDecisionState) setNonGreedy(b bool) {
s.nonGreedy = b
}
type BlockStartState interface {
DecisionState
getEndState() *BlockEndState
setEndState(*BlockEndState)
}
// BaseBlockStartState is the start of a regular (...) block.
type BaseBlockStartState struct {
*BaseDecisionState
endState *BlockEndState
}
func NewBlockStartState() *BaseBlockStartState {
return &BaseBlockStartState{BaseDecisionState: NewBaseDecisionState()}
}
func (s *BaseBlockStartState) getEndState() *BlockEndState {
return s.endState
}
func (s *BaseBlockStartState) setEndState(b *BlockEndState) {
s.endState = b
}
type BasicBlockStartState struct {
*BaseBlockStartState
}
func NewBasicBlockStartState() *BasicBlockStartState {
b := NewBlockStartState()
b.stateType = ATNStateBlockStart
return &BasicBlockStartState{BaseBlockStartState: b}
}
// BlockEndState is a terminal node of a simple (a|b|c) block.
type BlockEndState struct {
*BaseATNState
startState ATNState
}
func NewBlockEndState() *BlockEndState {
b := NewBaseATNState()
b.stateType = ATNStateBlockEnd
return &BlockEndState{BaseATNState: b}
}
// RuleStopState is the last node in the ATN for a rule, unless that rule is the
// start symbol. In that case, there is one transition to EOF. Later, we might
// encode references to all calls to this rule to compute FOLLOW sets for error
// handling.
type RuleStopState struct {
*BaseATNState
}
func NewRuleStopState() *RuleStopState {
b := NewBaseATNState()
b.stateType = ATNStateRuleStop
return &RuleStopState{BaseATNState: b}
}
type RuleStartState struct {
*BaseATNState
stopState ATNState
isPrecedenceRule bool
}
func NewRuleStartState() *RuleStartState {
b := NewBaseATNState()
b.stateType = ATNStateRuleStart
return &RuleStartState{BaseATNState: b}
}
// PlusLoopbackState is a decision state for A+ and (A|B)+. It has two
// transitions: one to the loop back to start of the block, and one to exit.
type PlusLoopbackState struct {
*BaseDecisionState
}
func NewPlusLoopbackState() *PlusLoopbackState {
b := NewBaseDecisionState()
b.stateType = ATNStatePlusLoopBack
return &PlusLoopbackState{BaseDecisionState: b}
}
// PlusBlockStartState is the start of a (A|B|...)+ loop. Technically it is a
// decision state; we don't use it for code generation. Somebody might need it,
// it is included for completeness. In reality, PlusLoopbackState is the real
// decision-making node for A+.
type PlusBlockStartState struct {
*BaseBlockStartState
loopBackState ATNState
}
func NewPlusBlockStartState() *PlusBlockStartState {
b := NewBlockStartState()
b.stateType = ATNStatePlusBlockStart
return &PlusBlockStartState{BaseBlockStartState: b}
}
// StarBlockStartState is the block that begins a closure loop.
type StarBlockStartState struct {
*BaseBlockStartState
}
func NewStarBlockStartState() *StarBlockStartState {
b := NewBlockStartState()
b.stateType = ATNStateStarBlockStart
return &StarBlockStartState{BaseBlockStartState: b}
}
type StarLoopbackState struct {
*BaseATNState
}
func NewStarLoopbackState() *StarLoopbackState {
b := NewBaseATNState()
b.stateType = ATNStateStarLoopBack
return &StarLoopbackState{BaseATNState: b}
}
type StarLoopEntryState struct {
*BaseDecisionState
loopBackState ATNState
precedenceRuleDecision bool
}
func NewStarLoopEntryState() *StarLoopEntryState {
b := NewBaseDecisionState()
b.stateType = ATNStateStarLoopEntry
// False precedenceRuleDecision indicates whether s state can benefit from a precedence DFA during SLL decision making.
return &StarLoopEntryState{BaseDecisionState: b}
}
// LoopEndState marks the end of a * or + loop.
type LoopEndState struct {
*BaseATNState
loopBackState ATNState
}
func NewLoopEndState() *LoopEndState {
b := NewBaseATNState()
b.stateType = ATNStateLoopEnd
return &LoopEndState{BaseATNState: b}
}
// TokensStartState is the Tokens rule start state linking to each lexer rule start state.
type TokensStartState struct {
*BaseDecisionState
}
func NewTokensStartState() *TokensStartState {
b := NewBaseDecisionState()
b.stateType = ATNStateTokenStart
return &TokensStartState{BaseDecisionState: b}
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// Represent the type of recognizer an ATN applies to.
const (
ATNTypeLexer = 0
ATNTypeParser = 1
)

View File

@@ -0,0 +1,12 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type CharStream interface {
IntStream
GetText(int, int) string
GetTextFromTokens(start, end Token) string
GetTextFromInterval(*Interval) string
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// TokenFactory creates CommonToken objects.
type TokenFactory interface {
Create(source *TokenSourceCharStreamPair, ttype int, text string, channel, start, stop, line, column int) Token
}
// CommonTokenFactory is the default TokenFactory implementation.
type CommonTokenFactory struct {
// copyText indicates whether CommonToken.setText should be called after
// constructing tokens to explicitly set the text. This is useful for cases
// where the input stream might not be able to provide arbitrary substrings of
// text from the input after the lexer creates a token (e.g. the
// implementation of CharStream.GetText in UnbufferedCharStream panics an
// UnsupportedOperationException). Explicitly setting the token text allows
// Token.GetText to be called at any time regardless of the input stream
// implementation.
//
// The default value is false to avoid the performance and memory overhead of
// copying text for every token unless explicitly requested.
copyText bool
}
func NewCommonTokenFactory(copyText bool) *CommonTokenFactory {
return &CommonTokenFactory{copyText: copyText}
}
// CommonTokenFactoryDEFAULT is the default CommonTokenFactory. It does not
// explicitly copy token text when constructing tokens.
var CommonTokenFactoryDEFAULT = NewCommonTokenFactory(false)
func (c *CommonTokenFactory) Create(source *TokenSourceCharStreamPair, ttype int, text string, channel, start, stop, line, column int) Token {
t := NewCommonToken(source, ttype, channel, start, stop)
t.line = line
t.column = column
if text != "" {
t.SetText(text)
} else if c.copyText && source.charStream != nil {
t.SetText(source.charStream.GetTextFromInterval(NewInterval(start, stop)))
}
return t
}
func (c *CommonTokenFactory) createThin(ttype int, text string) Token {
t := NewCommonToken(nil, ttype, TokenDefaultChannel, -1, -1)
t.SetText(text)
return t
}

View File

@@ -0,0 +1,447 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"strconv"
)
// CommonTokenStream is an implementation of TokenStream that loads tokens from
// a TokenSource on-demand and places the tokens in a buffer to provide access
// to any previous token by index. This token stream ignores the value of
// Token.getChannel. If your parser requires the token stream filter tokens to
// only those on a particular channel, such as Token.DEFAULT_CHANNEL or
// Token.HIDDEN_CHANNEL, use a filtering token stream such a CommonTokenStream.
type CommonTokenStream struct {
channel int
// fetchedEOF indicates whether the Token.EOF token has been fetched from
// tokenSource and added to tokens. This field improves performance for the
// following cases:
//
// consume: The lookahead check in consume to preven consuming the EOF symbol is
// optimized by checking the values of fetchedEOF and p instead of calling LA.
//
// fetch: The check to prevent adding multiple EOF symbols into tokens is
// trivial with bt field.
fetchedEOF bool
// index indexs into tokens of the current token (next token to consume).
// tokens[p] should be LT(1). It is set to -1 when the stream is first
// constructed or when SetTokenSource is called, indicating that the first token
// has not yet been fetched from the token source. For additional information,
// see the documentation of IntStream for a description of initializing methods.
index int
// tokenSource is the TokenSource from which tokens for the bt stream are
// fetched.
tokenSource TokenSource
// tokens is all tokens fetched from the token source. The list is considered a
// complete view of the input once fetchedEOF is set to true.
tokens []Token
}
func NewCommonTokenStream(lexer Lexer, channel int) *CommonTokenStream {
return &CommonTokenStream{
channel: channel,
index: -1,
tokenSource: lexer,
tokens: make([]Token, 0),
}
}
func (c *CommonTokenStream) GetAllTokens() []Token {
return c.tokens
}
func (c *CommonTokenStream) Mark() int {
return 0
}
func (c *CommonTokenStream) Release(marker int) {}
func (c *CommonTokenStream) reset() {
c.Seek(0)
}
func (c *CommonTokenStream) Seek(index int) {
c.lazyInit()
c.index = c.adjustSeekIndex(index)
}
func (c *CommonTokenStream) Get(index int) Token {
c.lazyInit()
return c.tokens[index]
}
func (c *CommonTokenStream) Consume() {
SkipEOFCheck := false
if c.index >= 0 {
if c.fetchedEOF {
// The last token in tokens is EOF. Skip the check if p indexes any fetched.
// token except the last.
SkipEOFCheck = c.index < len(c.tokens)-1
} else {
// No EOF token in tokens. Skip the check if p indexes a fetched token.
SkipEOFCheck = c.index < len(c.tokens)
}
} else {
// Not yet initialized
SkipEOFCheck = false
}
if !SkipEOFCheck && c.LA(1) == TokenEOF {
panic("cannot consume EOF")
}
if c.Sync(c.index + 1) {
c.index = c.adjustSeekIndex(c.index + 1)
}
}
// Sync makes sure index i in tokens has a token and returns true if a token is
// located at index i and otherwise false.
func (c *CommonTokenStream) Sync(i int) bool {
n := i - len(c.tokens) + 1 // TODO: How many more elements do we need?
if n > 0 {
fetched := c.fetch(n)
return fetched >= n
}
return true
}
// fetch adds n elements to buffer and returns the actual number of elements
// added to the buffer.
func (c *CommonTokenStream) fetch(n int) int {
if c.fetchedEOF {
return 0
}
for i := 0; i < n; i++ {
t := c.tokenSource.NextToken()
t.SetTokenIndex(len(c.tokens))
c.tokens = append(c.tokens, t)
if t.GetTokenType() == TokenEOF {
c.fetchedEOF = true
return i + 1
}
}
return n
}
// GetTokens gets all tokens from start to stop inclusive.
func (c *CommonTokenStream) GetTokens(start int, stop int, types *IntervalSet) []Token {
if start < 0 || stop < 0 {
return nil
}
c.lazyInit()
subset := make([]Token, 0)
if stop >= len(c.tokens) {
stop = len(c.tokens) - 1
}
for i := start; i < stop; i++ {
t := c.tokens[i]
if t.GetTokenType() == TokenEOF {
break
}
if types == nil || types.contains(t.GetTokenType()) {
subset = append(subset, t)
}
}
return subset
}
func (c *CommonTokenStream) LA(i int) int {
return c.LT(i).GetTokenType()
}
func (c *CommonTokenStream) lazyInit() {
if c.index == -1 {
c.setup()
}
}
func (c *CommonTokenStream) setup() {
c.Sync(0)
c.index = c.adjustSeekIndex(0)
}
func (c *CommonTokenStream) GetTokenSource() TokenSource {
return c.tokenSource
}
// SetTokenSource resets the c token stream by setting its token source.
func (c *CommonTokenStream) SetTokenSource(tokenSource TokenSource) {
c.tokenSource = tokenSource
c.tokens = make([]Token, 0)
c.index = -1
}
// NextTokenOnChannel returns the index of the next token on channel given a
// starting index. Returns i if tokens[i] is on channel. Returns -1 if there are
// no tokens on channel between i and EOF.
func (c *CommonTokenStream) NextTokenOnChannel(i, channel int) int {
c.Sync(i)
if i >= len(c.tokens) {
return -1
}
token := c.tokens[i]
for token.GetChannel() != c.channel {
if token.GetTokenType() == TokenEOF {
return -1
}
i++
c.Sync(i)
token = c.tokens[i]
}
return i
}
// previousTokenOnChannel returns the index of the previous token on channel
// given a starting index. Returns i if tokens[i] is on channel. Returns -1 if
// there are no tokens on channel between i and 0.
func (c *CommonTokenStream) previousTokenOnChannel(i, channel int) int {
for i >= 0 && c.tokens[i].GetChannel() != channel {
i--
}
return i
}
// GetHiddenTokensToRight collects all tokens on a specified channel to the
// right of the current token up until we see a token on DEFAULT_TOKEN_CHANNEL
// or EOF. If channel is -1, it finds any non-default channel token.
func (c *CommonTokenStream) GetHiddenTokensToRight(tokenIndex, channel int) []Token {
c.lazyInit()
if tokenIndex < 0 || tokenIndex >= len(c.tokens) {
panic(strconv.Itoa(tokenIndex) + " not in 0.." + strconv.Itoa(len(c.tokens)-1))
}
nextOnChannel := c.NextTokenOnChannel(tokenIndex+1, LexerDefaultTokenChannel)
from := tokenIndex + 1
// If no onchannel to the right, then nextOnChannel == -1, so set to to last token
var to int
if nextOnChannel == -1 {
to = len(c.tokens) - 1
} else {
to = nextOnChannel
}
return c.filterForChannel(from, to, channel)
}
// GetHiddenTokensToLeft collects all tokens on channel to the left of the
// current token until we see a token on DEFAULT_TOKEN_CHANNEL. If channel is
// -1, it finds any non default channel token.
func (c *CommonTokenStream) GetHiddenTokensToLeft(tokenIndex, channel int) []Token {
c.lazyInit()
if tokenIndex < 0 || tokenIndex >= len(c.tokens) {
panic(strconv.Itoa(tokenIndex) + " not in 0.." + strconv.Itoa(len(c.tokens)-1))
}
prevOnChannel := c.previousTokenOnChannel(tokenIndex-1, LexerDefaultTokenChannel)
if prevOnChannel == tokenIndex-1 {
return nil
}
// If there are none on channel to the left and prevOnChannel == -1 then from = 0
from := prevOnChannel + 1
to := tokenIndex - 1
return c.filterForChannel(from, to, channel)
}
func (c *CommonTokenStream) filterForChannel(left, right, channel int) []Token {
hidden := make([]Token, 0)
for i := left; i < right+1; i++ {
t := c.tokens[i]
if channel == -1 {
if t.GetChannel() != LexerDefaultTokenChannel {
hidden = append(hidden, t)
}
} else if t.GetChannel() == channel {
hidden = append(hidden, t)
}
}
if len(hidden) == 0 {
return nil
}
return hidden
}
func (c *CommonTokenStream) GetSourceName() string {
return c.tokenSource.GetSourceName()
}
func (c *CommonTokenStream) Size() int {
return len(c.tokens)
}
func (c *CommonTokenStream) Index() int {
return c.index
}
func (c *CommonTokenStream) GetAllText() string {
return c.GetTextFromInterval(nil)
}
func (c *CommonTokenStream) GetTextFromTokens(start, end Token) string {
if start == nil || end == nil {
return ""
}
return c.GetTextFromInterval(NewInterval(start.GetTokenIndex(), end.GetTokenIndex()))
}
func (c *CommonTokenStream) GetTextFromRuleContext(interval RuleContext) string {
return c.GetTextFromInterval(interval.GetSourceInterval())
}
func (c *CommonTokenStream) GetTextFromInterval(interval *Interval) string {
c.lazyInit()
c.Fill()
if interval == nil {
interval = NewInterval(0, len(c.tokens)-1)
}
start := interval.Start
stop := interval.Stop
if start < 0 || stop < 0 {
return ""
}
if stop >= len(c.tokens) {
stop = len(c.tokens) - 1
}
s := ""
for i := start; i < stop+1; i++ {
t := c.tokens[i]
if t.GetTokenType() == TokenEOF {
break
}
s += t.GetText()
}
return s
}
// Fill gets all tokens from the lexer until EOF.
func (c *CommonTokenStream) Fill() {
c.lazyInit()
for c.fetch(1000) == 1000 {
continue
}
}
func (c *CommonTokenStream) adjustSeekIndex(i int) int {
return c.NextTokenOnChannel(i, c.channel)
}
func (c *CommonTokenStream) LB(k int) Token {
if k == 0 || c.index-k < 0 {
return nil
}
i := c.index
n := 1
// Find k good tokens looking backward
for n <= k {
// Skip off-channel tokens
i = c.previousTokenOnChannel(i-1, c.channel)
n++
}
if i < 0 {
return nil
}
return c.tokens[i]
}
func (c *CommonTokenStream) LT(k int) Token {
c.lazyInit()
if k == 0 {
return nil
}
if k < 0 {
return c.LB(-k)
}
i := c.index
n := 1 // We know tokens[n] is valid
// Find k good tokens
for n < k {
// Skip off-channel tokens, but make sure to not look past EOF
if c.Sync(i + 1) {
i = c.NextTokenOnChannel(i+1, c.channel)
}
n++
}
return c.tokens[i]
}
// getNumberOfOnChannelTokens counts EOF once.
func (c *CommonTokenStream) getNumberOfOnChannelTokens() int {
var n int
c.Fill()
for i := 0; i < len(c.tokens); i++ {
t := c.tokens[i]
if t.GetChannel() == c.channel {
n++
}
if t.GetTokenType() == TokenEOF {
break
}
}
return n
}

183
vendor/github.com/antlr/antlr4/runtime/Go/antlr/dfa.go generated vendored Normal file
View File

@@ -0,0 +1,183 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"sort"
"sync"
)
type DFA struct {
// atnStartState is the ATN state in which this was created
atnStartState DecisionState
decision int
// states is all the DFA states. Use Map to get the old state back; Set can only
// indicate whether it is there.
states map[int]*DFAState
statesMu sync.RWMutex
s0 *DFAState
s0Mu sync.RWMutex
// precedenceDfa is the backing field for isPrecedenceDfa and setPrecedenceDfa.
// True if the DFA is for a precedence decision and false otherwise.
precedenceDfa bool
precedenceDfaMu sync.RWMutex
}
func NewDFA(atnStartState DecisionState, decision int) *DFA {
return &DFA{
atnStartState: atnStartState,
decision: decision,
states: make(map[int]*DFAState),
}
}
// getPrecedenceStartState gets the start state for the current precedence and
// returns the start state corresponding to the specified precedence if a start
// state exists for the specified precedence and nil otherwise. d must be a
// precedence DFA. See also isPrecedenceDfa.
func (d *DFA) getPrecedenceStartState(precedence int) *DFAState {
if !d.getPrecedenceDfa() {
panic("only precedence DFAs may contain a precedence start state")
}
// s0.edges is never nil for a precedence DFA
if precedence < 0 || precedence >= len(d.getS0().getEdges()) {
return nil
}
return d.getS0().getIthEdge(precedence)
}
// setPrecedenceStartState sets the start state for the current precedence. d
// must be a precedence DFA. See also isPrecedenceDfa.
func (d *DFA) setPrecedenceStartState(precedence int, startState *DFAState) {
if !d.getPrecedenceDfa() {
panic("only precedence DFAs may contain a precedence start state")
}
if precedence < 0 {
return
}
// Synchronization on s0 here is ok. When the DFA is turned into a
// precedence DFA, s0 will be initialized once and not updated again. s0.edges
// is never nil for a precedence DFA.
s0 := d.getS0()
if precedence >= s0.numEdges() {
edges := append(s0.getEdges(), make([]*DFAState, precedence+1-s0.numEdges())...)
s0.setEdges(edges)
d.setS0(s0)
}
s0.setIthEdge(precedence, startState)
}
func (d *DFA) getPrecedenceDfa() bool {
d.precedenceDfaMu.RLock()
defer d.precedenceDfaMu.RUnlock()
return d.precedenceDfa
}
// setPrecedenceDfa sets whether d is a precedence DFA. If precedenceDfa differs
// from the current DFA configuration, then d.states is cleared, the initial
// state s0 is set to a new DFAState with an empty outgoing DFAState.edges to
// store the start states for individual precedence values if precedenceDfa is
// true or nil otherwise, and d.precedenceDfa is updated.
func (d *DFA) setPrecedenceDfa(precedenceDfa bool) {
if d.getPrecedenceDfa() != precedenceDfa {
d.setStates(make(map[int]*DFAState))
if precedenceDfa {
precedenceState := NewDFAState(-1, NewBaseATNConfigSet(false))
precedenceState.setEdges(make([]*DFAState, 0))
precedenceState.isAcceptState = false
precedenceState.requiresFullContext = false
d.setS0(precedenceState)
} else {
d.setS0(nil)
}
d.precedenceDfaMu.Lock()
defer d.precedenceDfaMu.Unlock()
d.precedenceDfa = precedenceDfa
}
}
func (d *DFA) getS0() *DFAState {
d.s0Mu.RLock()
defer d.s0Mu.RUnlock()
return d.s0
}
func (d *DFA) setS0(s *DFAState) {
d.s0Mu.Lock()
defer d.s0Mu.Unlock()
d.s0 = s
}
func (d *DFA) getState(hash int) (*DFAState, bool) {
d.statesMu.RLock()
defer d.statesMu.RUnlock()
s, ok := d.states[hash]
return s, ok
}
func (d *DFA) setStates(states map[int]*DFAState) {
d.statesMu.Lock()
defer d.statesMu.Unlock()
d.states = states
}
func (d *DFA) setState(hash int, state *DFAState) {
d.statesMu.Lock()
defer d.statesMu.Unlock()
d.states[hash] = state
}
func (d *DFA) numStates() int {
d.statesMu.RLock()
defer d.statesMu.RUnlock()
return len(d.states)
}
type dfaStateList []*DFAState
func (d dfaStateList) Len() int { return len(d) }
func (d dfaStateList) Less(i, j int) bool { return d[i].stateNumber < d[j].stateNumber }
func (d dfaStateList) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
// sortedStates returns the states in d sorted by their state number.
func (d *DFA) sortedStates() []*DFAState {
vs := make([]*DFAState, 0, len(d.states))
for _, v := range d.states {
vs = append(vs, v)
}
sort.Sort(dfaStateList(vs))
return vs
}
func (d *DFA) String(literalNames []string, symbolicNames []string) string {
if d.getS0() == nil {
return ""
}
return NewDFASerializer(d, literalNames, symbolicNames).String()
}
func (d *DFA) ToLexerString() string {
if d.getS0() == nil {
return ""
}
return NewLexerDFASerializer(d).String()
}

View File

@@ -0,0 +1,152 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
// DFASerializer is a DFA walker that knows how to dump them to serialized
// strings.
type DFASerializer struct {
dfa *DFA
literalNames []string
symbolicNames []string
}
func NewDFASerializer(dfa *DFA, literalNames, symbolicNames []string) *DFASerializer {
if literalNames == nil {
literalNames = make([]string, 0)
}
if symbolicNames == nil {
symbolicNames = make([]string, 0)
}
return &DFASerializer{
dfa: dfa,
literalNames: literalNames,
symbolicNames: symbolicNames,
}
}
func (d *DFASerializer) String() string {
if d.dfa.getS0() == nil {
return ""
}
buf := ""
states := d.dfa.sortedStates()
for _, s := range states {
if s.edges != nil {
n := len(s.edges)
for j := 0; j < n; j++ {
t := s.edges[j]
if t != nil && t.stateNumber != 0x7FFFFFFF {
buf += d.GetStateString(s)
buf += "-"
buf += d.getEdgeLabel(j)
buf += "->"
buf += d.GetStateString(t)
buf += "\n"
}
}
}
}
if len(buf) == 0 {
return ""
}
return buf
}
func (d *DFASerializer) getEdgeLabel(i int) string {
if i == 0 {
return "EOF"
} else if d.literalNames != nil && i-1 < len(d.literalNames) {
return d.literalNames[i-1]
} else if d.symbolicNames != nil && i-1 < len(d.symbolicNames) {
return d.symbolicNames[i-1]
}
return strconv.Itoa(i - 1)
}
func (d *DFASerializer) GetStateString(s *DFAState) string {
var a, b string
if s.isAcceptState {
a = ":"
}
if s.requiresFullContext {
b = "^"
}
baseStateStr := a + "s" + strconv.Itoa(s.stateNumber) + b
if s.isAcceptState {
if s.predicates != nil {
return baseStateStr + "=>" + fmt.Sprint(s.predicates)
}
return baseStateStr + "=>" + fmt.Sprint(s.prediction)
}
return baseStateStr
}
type LexerDFASerializer struct {
*DFASerializer
}
func NewLexerDFASerializer(dfa *DFA) *LexerDFASerializer {
return &LexerDFASerializer{DFASerializer: NewDFASerializer(dfa, nil, nil)}
}
func (l *LexerDFASerializer) getEdgeLabel(i int) string {
return "'" + string(i) + "'"
}
func (l *LexerDFASerializer) String() string {
if l.dfa.getS0() == nil {
return ""
}
buf := ""
states := l.dfa.sortedStates()
for i := 0; i < len(states); i++ {
s := states[i]
if s.edges != nil {
n := len(s.edges)
for j := 0; j < n; j++ {
t := s.edges[j]
if t != nil && t.stateNumber != 0x7FFFFFFF {
buf += l.GetStateString(s)
buf += "-"
buf += l.getEdgeLabel(j)
buf += "->"
buf += l.GetStateString(t)
buf += "\n"
}
}
}
}
if len(buf) == 0 {
return ""
}
return buf
}

View File

@@ -0,0 +1,198 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"sync"
)
// PredPrediction maps a predicate to a predicted alternative.
type PredPrediction struct {
alt int
pred SemanticContext
}
func NewPredPrediction(pred SemanticContext, alt int) *PredPrediction {
return &PredPrediction{alt: alt, pred: pred}
}
func (p *PredPrediction) String() string {
return "(" + fmt.Sprint(p.pred) + ", " + fmt.Sprint(p.alt) + ")"
}
// DFAState represents a set of possible ATN configurations. As Aho, Sethi,
// Ullman p. 117 says: "The DFA uses its state to keep track of all possible
// states the ATN can be in after reading each input symbol. That is to say,
// after reading input a1a2..an, the DFA is in a state that represents the
// subset T of the states of the ATN that are reachable from the ATN's start
// state along some path labeled a1a2..an." In conventional NFA-to-DFA
// conversion, therefore, the subset T would be a bitset representing the set of
// states the ATN could be in. We need to track the alt predicted by each state
// as well, however. More importantly, we need to maintain a stack of states,
// tracking the closure operations as they jump from rule to rule, emulating
// rule invocations (method calls). I have to add a stack to simulate the proper
// lookahead sequences for the underlying LL grammar from which the ATN was
// derived.
//
// I use a set of ATNConfig objects, not simple states. An ATNConfig is both a
// state (ala normal conversion) and a RuleContext describing the chain of rules
// (if any) followed to arrive at that state.
//
// A DFAState may have multiple references to a particular state, but with
// different ATN contexts (with same or different alts) meaning that state was
// reached via a different set of rule invocations.
type DFAState struct {
stateNumber int
configs ATNConfigSet
// edges elements point to the target of the symbol. Shift up by 1 so (-1)
// Token.EOF maps to the first element.
edges []*DFAState
edgesMu sync.RWMutex
isAcceptState bool
// prediction is the ttype we match or alt we predict if the state is accept.
// Set to ATN.INVALID_ALT_NUMBER when predicates != nil or
// requiresFullContext.
prediction int
lexerActionExecutor *LexerActionExecutor
// requiresFullContext indicates it was created during an SLL prediction that
// discovered a conflict between the configurations in the state. Future
// ParserATNSimulator.execATN invocations immediately jump doing
// full context prediction if true.
requiresFullContext bool
// predicates is the predicates associated with the ATN configurations of the
// DFA state during SLL parsing. When we have predicates, requiresFullContext
// is false, since full context prediction evaluates predicates on-the-fly. If
// d is
// not nil, then prediction is ATN.INVALID_ALT_NUMBER.
//
// We only use these for non-requiresFullContext but conflicting states. That
// means we know from the context (it's $ or we don't dip into outer context)
// that it's an ambiguity not a conflict.
//
// This list is computed by
// ParserATNSimulator.predicateDFAState.
predicates []*PredPrediction
}
func NewDFAState(stateNumber int, configs ATNConfigSet) *DFAState {
if configs == nil {
configs = NewBaseATNConfigSet(false)
}
return &DFAState{configs: configs, stateNumber: stateNumber}
}
// GetAltSet gets the set of all alts mentioned by all ATN configurations in d.
func (d *DFAState) GetAltSet() *Set {
alts := NewSet(nil, nil)
if d.configs != nil {
for _, c := range d.configs.GetItems() {
alts.add(c.GetAlt())
}
}
if alts.length() == 0 {
return nil
}
return alts
}
func (d *DFAState) getEdges() []*DFAState {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return d.edges
}
func (d *DFAState) numEdges() int {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return len(d.edges)
}
func (d *DFAState) getIthEdge(i int) *DFAState {
d.edgesMu.RLock()
defer d.edgesMu.RUnlock()
return d.edges[i]
}
func (d *DFAState) setEdges(newEdges []*DFAState) {
d.edgesMu.Lock()
defer d.edgesMu.Unlock()
d.edges = newEdges
}
func (d *DFAState) setIthEdge(i int, edge *DFAState) {
d.edgesMu.Lock()
defer d.edgesMu.Unlock()
d.edges[i] = edge
}
func (d *DFAState) setPrediction(v int) {
d.prediction = v
}
// equals returns whether d equals other. Two DFAStates are equal if their ATN
// configuration sets are the same. This method is used to see if a state
// already exists.
//
// Because the number of alternatives and number of ATN configurations are
// finite, there is a finite number of DFA states that can be processed. This is
// necessary to show that the algorithm terminates.
//
// Cannot test the DFA state numbers here because in
// ParserATNSimulator.addDFAState we need to know if any other state exists that
// has d exact set of ATN configurations. The stateNumber is irrelevant.
func (d *DFAState) equals(other interface{}) bool {
if d == other {
return true
} else if _, ok := other.(*DFAState); !ok {
return false
}
return d.configs.Equals(other.(*DFAState).configs)
}
func (d *DFAState) String() string {
var s string
if d.isAcceptState {
if d.predicates != nil {
s = "=>" + fmt.Sprint(d.predicates)
} else {
s = "=>" + fmt.Sprint(d.prediction)
}
}
return fmt.Sprintf("%d:%s%s", fmt.Sprint(d.configs), s)
}
func (d *DFAState) hash() int {
h := murmurInit(11)
c := 1
if d.isAcceptState {
if d.predicates != nil {
for _, p := range d.predicates {
h = murmurUpdate(h, p.alt)
h = murmurUpdate(h, p.pred.hash())
c += 2
}
} else {
h = murmurUpdate(h, d.prediction)
c += 1
}
}
h = murmurUpdate(h, d.configs.hash())
return murmurFinish(h, c)
}

View File

@@ -0,0 +1,111 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"strconv"
)
//
// This implementation of {@link ANTLRErrorListener} can be used to identify
// certain potential correctness and performance problems in grammars. "reports"
// are made by calling {@link Parser//NotifyErrorListeners} with the appropriate
// message.
//
// <ul>
// <li><b>Ambiguities</b>: These are cases where more than one path through the
// grammar can Match the input.</li>
// <li><b>Weak context sensitivity</b>: These are cases where full-context
// prediction resolved an SLL conflict to a unique alternative which equaled the
// minimum alternative of the SLL conflict.</li>
// <li><b>Strong (forced) context sensitivity</b>: These are cases where the
// full-context prediction resolved an SLL conflict to a unique alternative,
// <em>and</em> the minimum alternative of the SLL conflict was found to not be
// a truly viable alternative. Two-stage parsing cannot be used for inputs where
// d situation occurs.</li>
// </ul>
type DiagnosticErrorListener struct {
*DefaultErrorListener
exactOnly bool
}
func NewDiagnosticErrorListener(exactOnly bool) *DiagnosticErrorListener {
n := new(DiagnosticErrorListener)
// whether all ambiguities or only exact ambiguities are Reported.
n.exactOnly = exactOnly
return n
}
func (d *DiagnosticErrorListener) ReportAmbiguity(recognizer Parser, dfa *DFA, startIndex, stopIndex int, exact bool, ambigAlts *BitSet, configs ATNConfigSet) {
if d.exactOnly && !exact {
return
}
msg := "reportAmbiguity d=" +
d.getDecisionDescription(recognizer, dfa) +
": ambigAlts=" +
d.getConflictingAlts(ambigAlts, configs).String() +
", input='" +
recognizer.GetTokenStream().GetTextFromInterval(NewInterval(startIndex, stopIndex)) + "'"
recognizer.NotifyErrorListeners(msg, nil, nil)
}
func (d *DiagnosticErrorListener) ReportAttemptingFullContext(recognizer Parser, dfa *DFA, startIndex, stopIndex int, conflictingAlts *BitSet, configs ATNConfigSet) {
msg := "reportAttemptingFullContext d=" +
d.getDecisionDescription(recognizer, dfa) +
", input='" +
recognizer.GetTokenStream().GetTextFromInterval(NewInterval(startIndex, stopIndex)) + "'"
recognizer.NotifyErrorListeners(msg, nil, nil)
}
func (d *DiagnosticErrorListener) ReportContextSensitivity(recognizer Parser, dfa *DFA, startIndex, stopIndex, prediction int, configs ATNConfigSet) {
msg := "reportContextSensitivity d=" +
d.getDecisionDescription(recognizer, dfa) +
", input='" +
recognizer.GetTokenStream().GetTextFromInterval(NewInterval(startIndex, stopIndex)) + "'"
recognizer.NotifyErrorListeners(msg, nil, nil)
}
func (d *DiagnosticErrorListener) getDecisionDescription(recognizer Parser, dfa *DFA) string {
decision := dfa.decision
ruleIndex := dfa.atnStartState.GetRuleIndex()
ruleNames := recognizer.GetRuleNames()
if ruleIndex < 0 || ruleIndex >= len(ruleNames) {
return strconv.Itoa(decision)
}
ruleName := ruleNames[ruleIndex]
if ruleName == "" {
return strconv.Itoa(decision)
}
return strconv.Itoa(decision) + " (" + ruleName + ")"
}
//
// Computes the set of conflicting or ambiguous alternatives from a
// configuration set, if that information was not already provided by the
// parser.
//
// @param ReportedAlts The set of conflicting or ambiguous alternatives, as
// Reported by the parser.
// @param configs The conflicting or ambiguous configuration set.
// @return Returns {@code ReportedAlts} if it is not {@code nil}, otherwise
// returns the set of alternatives represented in {@code configs}.
//
func (d *DiagnosticErrorListener) getConflictingAlts(ReportedAlts *BitSet, set ATNConfigSet) *BitSet {
if ReportedAlts != nil {
return ReportedAlts
}
result := NewBitSet()
for _, c := range set.GetItems() {
result.add(c.GetAlt())
}
return result
}

View File

@@ -0,0 +1,108 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"os"
"strconv"
)
// Provides an empty default implementation of {@link ANTLRErrorListener}. The
// default implementation of each method does nothing, but can be overridden as
// necessary.
type ErrorListener interface {
SyntaxError(recognizer Recognizer, offendingSymbol interface{}, line, column int, msg string, e RecognitionException)
ReportAmbiguity(recognizer Parser, dfa *DFA, startIndex, stopIndex int, exact bool, ambigAlts *BitSet, configs ATNConfigSet)
ReportAttemptingFullContext(recognizer Parser, dfa *DFA, startIndex, stopIndex int, conflictingAlts *BitSet, configs ATNConfigSet)
ReportContextSensitivity(recognizer Parser, dfa *DFA, startIndex, stopIndex, prediction int, configs ATNConfigSet)
}
type DefaultErrorListener struct {
}
func NewDefaultErrorListener() *DefaultErrorListener {
return new(DefaultErrorListener)
}
func (d *DefaultErrorListener) SyntaxError(recognizer Recognizer, offendingSymbol interface{}, line, column int, msg string, e RecognitionException) {
}
func (d *DefaultErrorListener) ReportAmbiguity(recognizer Parser, dfa *DFA, startIndex, stopIndex int, exact bool, ambigAlts *BitSet, configs ATNConfigSet) {
}
func (d *DefaultErrorListener) ReportAttemptingFullContext(recognizer Parser, dfa *DFA, startIndex, stopIndex int, conflictingAlts *BitSet, configs ATNConfigSet) {
}
func (d *DefaultErrorListener) ReportContextSensitivity(recognizer Parser, dfa *DFA, startIndex, stopIndex, prediction int, configs ATNConfigSet) {
}
type ConsoleErrorListener struct {
*DefaultErrorListener
}
func NewConsoleErrorListener() *ConsoleErrorListener {
return new(ConsoleErrorListener)
}
//
// Provides a default instance of {@link ConsoleErrorListener}.
//
var ConsoleErrorListenerINSTANCE = NewConsoleErrorListener()
//
// {@inheritDoc}
//
// <p>
// This implementation prints messages to {@link System//err} containing the
// values of {@code line}, {@code charPositionInLine}, and {@code msg} using
// the following format.</p>
//
// <pre>
// line <em>line</em>:<em>charPositionInLine</em> <em>msg</em>
// </pre>
//
func (c *ConsoleErrorListener) SyntaxError(recognizer Recognizer, offendingSymbol interface{}, line, column int, msg string, e RecognitionException) {
fmt.Fprintln(os.Stderr, "line "+strconv.Itoa(line)+":"+strconv.Itoa(column)+" "+msg)
}
type ProxyErrorListener struct {
*DefaultErrorListener
delegates []ErrorListener
}
func NewProxyErrorListener(delegates []ErrorListener) *ProxyErrorListener {
if delegates == nil {
panic("delegates is not provided")
}
l := new(ProxyErrorListener)
l.delegates = delegates
return l
}
func (p *ProxyErrorListener) SyntaxError(recognizer Recognizer, offendingSymbol interface{}, line, column int, msg string, e RecognitionException) {
for _, d := range p.delegates {
d.SyntaxError(recognizer, offendingSymbol, line, column, msg, e)
}
}
func (p *ProxyErrorListener) ReportAmbiguity(recognizer Parser, dfa *DFA, startIndex, stopIndex int, exact bool, ambigAlts *BitSet, configs ATNConfigSet) {
for _, d := range p.delegates {
d.ReportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs)
}
}
func (p *ProxyErrorListener) ReportAttemptingFullContext(recognizer Parser, dfa *DFA, startIndex, stopIndex int, conflictingAlts *BitSet, configs ATNConfigSet) {
for _, d := range p.delegates {
d.ReportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs)
}
}
func (p *ProxyErrorListener) ReportContextSensitivity(recognizer Parser, dfa *DFA, startIndex, stopIndex, prediction int, configs ATNConfigSet) {
for _, d := range p.delegates {
d.ReportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs)
}
}

View File

@@ -0,0 +1,758 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"reflect"
"strconv"
"strings"
)
type ErrorStrategy interface {
reset(Parser)
RecoverInline(Parser) Token
Recover(Parser, RecognitionException)
Sync(Parser)
inErrorRecoveryMode(Parser) bool
ReportError(Parser, RecognitionException)
ReportMatch(Parser)
}
// This is the default implementation of {@link ANTLRErrorStrategy} used for
// error Reporting and recovery in ANTLR parsers.
//
type DefaultErrorStrategy struct {
errorRecoveryMode bool
lastErrorIndex int
lastErrorStates *IntervalSet
}
var _ ErrorStrategy = &DefaultErrorStrategy{}
func NewDefaultErrorStrategy() *DefaultErrorStrategy {
d := new(DefaultErrorStrategy)
// Indicates whether the error strategy is currently "recovering from an
// error". This is used to suppress Reporting multiple error messages while
// attempting to recover from a detected syntax error.
//
// @see //inErrorRecoveryMode
//
d.errorRecoveryMode = false
// The index into the input stream where the last error occurred.
// This is used to prevent infinite loops where an error is found
// but no token is consumed during recovery...another error is found,
// ad nauseum. This is a failsafe mechanism to guarantee that at least
// one token/tree node is consumed for two errors.
//
d.lastErrorIndex = -1
d.lastErrorStates = nil
return d
}
// <p>The default implementation simply calls {@link //endErrorCondition} to
// ensure that the handler is not in error recovery mode.</p>
func (d *DefaultErrorStrategy) reset(recognizer Parser) {
d.endErrorCondition(recognizer)
}
//
// This method is called to enter error recovery mode when a recognition
// exception is Reported.
//
// @param recognizer the parser instance
//
func (d *DefaultErrorStrategy) beginErrorCondition(recognizer Parser) {
d.errorRecoveryMode = true
}
func (d *DefaultErrorStrategy) inErrorRecoveryMode(recognizer Parser) bool {
return d.errorRecoveryMode
}
//
// This method is called to leave error recovery mode after recovering from
// a recognition exception.
//
// @param recognizer
//
func (d *DefaultErrorStrategy) endErrorCondition(recognizer Parser) {
d.errorRecoveryMode = false
d.lastErrorStates = nil
d.lastErrorIndex = -1
}
//
// {@inheritDoc}
//
// <p>The default implementation simply calls {@link //endErrorCondition}.</p>
//
func (d *DefaultErrorStrategy) ReportMatch(recognizer Parser) {
d.endErrorCondition(recognizer)
}
//
// {@inheritDoc}
//
// <p>The default implementation returns immediately if the handler is already
// in error recovery mode. Otherwise, it calls {@link //beginErrorCondition}
// and dispatches the Reporting task based on the runtime type of {@code e}
// according to the following table.</p>
//
// <ul>
// <li>{@link NoViableAltException}: Dispatches the call to
// {@link //ReportNoViableAlternative}</li>
// <li>{@link InputMisMatchException}: Dispatches the call to
// {@link //ReportInputMisMatch}</li>
// <li>{@link FailedPredicateException}: Dispatches the call to
// {@link //ReportFailedPredicate}</li>
// <li>All other types: calls {@link Parser//NotifyErrorListeners} to Report
// the exception</li>
// </ul>
//
func (d *DefaultErrorStrategy) ReportError(recognizer Parser, e RecognitionException) {
// if we've already Reported an error and have not Matched a token
// yet successfully, don't Report any errors.
if d.inErrorRecoveryMode(recognizer) {
return // don't Report spurious errors
}
d.beginErrorCondition(recognizer)
switch t := e.(type) {
default:
fmt.Println("unknown recognition error type: " + reflect.TypeOf(e).Name())
// fmt.Println(e.stack)
recognizer.NotifyErrorListeners(e.GetMessage(), e.GetOffendingToken(), e)
case *NoViableAltException:
d.ReportNoViableAlternative(recognizer, t)
case *InputMisMatchException:
d.ReportInputMisMatch(recognizer, t)
case *FailedPredicateException:
d.ReportFailedPredicate(recognizer, t)
}
}
// {@inheritDoc}
//
// <p>The default implementation reSynchronizes the parser by consuming tokens
// until we find one in the reSynchronization set--loosely the set of tokens
// that can follow the current rule.</p>
//
func (d *DefaultErrorStrategy) Recover(recognizer Parser, e RecognitionException) {
if d.lastErrorIndex == recognizer.GetInputStream().Index() &&
d.lastErrorStates != nil && d.lastErrorStates.contains(recognizer.GetState()) {
// uh oh, another error at same token index and previously-Visited
// state in ATN must be a case where LT(1) is in the recovery
// token set so nothing got consumed. Consume a single token
// at least to prevent an infinite loop d is a failsafe.
recognizer.Consume()
}
d.lastErrorIndex = recognizer.GetInputStream().Index()
if d.lastErrorStates == nil {
d.lastErrorStates = NewIntervalSet()
}
d.lastErrorStates.addOne(recognizer.GetState())
followSet := d.getErrorRecoverySet(recognizer)
d.consumeUntil(recognizer, followSet)
}
// The default implementation of {@link ANTLRErrorStrategy//Sync} makes sure
// that the current lookahead symbol is consistent with what were expecting
// at d point in the ATN. You can call d anytime but ANTLR only
// generates code to check before subrules/loops and each iteration.
//
// <p>Implements Jim Idle's magic Sync mechanism in closures and optional
// subrules. E.g.,</p>
//
// <pre>
// a : Sync ( stuff Sync )*
// Sync : {consume to what can follow Sync}
// </pre>
//
// At the start of a sub rule upon error, {@link //Sync} performs single
// token deletion, if possible. If it can't do that, it bails on the current
// rule and uses the default error recovery, which consumes until the
// reSynchronization set of the current rule.
//
// <p>If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block
// with an empty alternative), then the expected set includes what follows
// the subrule.</p>
//
// <p>During loop iteration, it consumes until it sees a token that can start a
// sub rule or what follows loop. Yes, that is pretty aggressive. We opt to
// stay in the loop as long as possible.</p>
//
// <p><strong>ORIGINS</strong></p>
//
// <p>Previous versions of ANTLR did a poor job of their recovery within loops.
// A single mismatch token or missing token would force the parser to bail
// out of the entire rules surrounding the loop. So, for rule</p>
//
// <pre>
// classfunc : 'class' ID '{' member* '}'
// </pre>
//
// input with an extra token between members would force the parser to
// consume until it found the next class definition rather than the next
// member definition of the current class.
//
// <p>This functionality cost a little bit of effort because the parser has to
// compare token set at the start of the loop and at each iteration. If for
// some reason speed is suffering for you, you can turn off d
// functionality by simply overriding d method as a blank { }.</p>
//
func (d *DefaultErrorStrategy) Sync(recognizer Parser) {
// If already recovering, don't try to Sync
if d.inErrorRecoveryMode(recognizer) {
return
}
s := recognizer.GetInterpreter().atn.states[recognizer.GetState()]
la := recognizer.GetTokenStream().LA(1)
// try cheaper subset first might get lucky. seems to shave a wee bit off
nextTokens := recognizer.GetATN().NextTokens(s, nil)
if nextTokens.contains(TokenEpsilon) || nextTokens.contains(la) {
return
}
switch s.GetStateType() {
case ATNStateBlockStart, ATNStateStarBlockStart, ATNStatePlusBlockStart, ATNStateStarLoopEntry:
// Report error and recover if possible
if d.SingleTokenDeletion(recognizer) != nil {
return
}
panic(NewInputMisMatchException(recognizer))
case ATNStatePlusLoopBack, ATNStateStarLoopBack:
d.ReportUnwantedToken(recognizer)
expecting := NewIntervalSet()
expecting.addSet(recognizer.GetExpectedTokens())
whatFollowsLoopIterationOrRule := expecting.addSet(d.getErrorRecoverySet(recognizer))
d.consumeUntil(recognizer, whatFollowsLoopIterationOrRule)
default:
// do nothing if we can't identify the exact kind of ATN state
}
}
// This is called by {@link //ReportError} when the exception is a
// {@link NoViableAltException}.
//
// @see //ReportError
//
// @param recognizer the parser instance
// @param e the recognition exception
//
func (d *DefaultErrorStrategy) ReportNoViableAlternative(recognizer Parser, e *NoViableAltException) {
tokens := recognizer.GetTokenStream()
var input string
if tokens != nil {
if e.startToken.GetTokenType() == TokenEOF {
input = "<EOF>"
} else {
input = tokens.GetTextFromTokens(e.startToken, e.offendingToken)
}
} else {
input = "<unknown input>"
}
msg := "no viable alternative at input " + d.escapeWSAndQuote(input)
recognizer.NotifyErrorListeners(msg, e.offendingToken, e)
}
//
// This is called by {@link //ReportError} when the exception is an
// {@link InputMisMatchException}.
//
// @see //ReportError
//
// @param recognizer the parser instance
// @param e the recognition exception
//
func (this *DefaultErrorStrategy) ReportInputMisMatch(recognizer Parser, e *InputMisMatchException) {
msg := "mismatched input " + this.GetTokenErrorDisplay(e.offendingToken) +
" expecting " + e.getExpectedTokens().StringVerbose(recognizer.GetLiteralNames(), recognizer.GetSymbolicNames(), false)
recognizer.NotifyErrorListeners(msg, e.offendingToken, e)
}
//
// This is called by {@link //ReportError} when the exception is a
// {@link FailedPredicateException}.
//
// @see //ReportError
//
// @param recognizer the parser instance
// @param e the recognition exception
//
func (d *DefaultErrorStrategy) ReportFailedPredicate(recognizer Parser, e *FailedPredicateException) {
ruleName := recognizer.GetRuleNames()[recognizer.GetParserRuleContext().GetRuleIndex()]
msg := "rule " + ruleName + " " + e.message
recognizer.NotifyErrorListeners(msg, e.offendingToken, e)
}
// This method is called to Report a syntax error which requires the removal
// of a token from the input stream. At the time d method is called, the
// erroneous symbol is current {@code LT(1)} symbol and has not yet been
// removed from the input stream. When d method returns,
// {@code recognizer} is in error recovery mode.
//
// <p>This method is called when {@link //singleTokenDeletion} identifies
// single-token deletion as a viable recovery strategy for a mismatched
// input error.</p>
//
// <p>The default implementation simply returns if the handler is already in
// error recovery mode. Otherwise, it calls {@link //beginErrorCondition} to
// enter error recovery mode, followed by calling
// {@link Parser//NotifyErrorListeners}.</p>
//
// @param recognizer the parser instance
//
func (d *DefaultErrorStrategy) ReportUnwantedToken(recognizer Parser) {
if d.inErrorRecoveryMode(recognizer) {
return
}
d.beginErrorCondition(recognizer)
t := recognizer.GetCurrentToken()
tokenName := d.GetTokenErrorDisplay(t)
expecting := d.GetExpectedTokens(recognizer)
msg := "extraneous input " + tokenName + " expecting " +
expecting.StringVerbose(recognizer.GetLiteralNames(), recognizer.GetSymbolicNames(), false)
recognizer.NotifyErrorListeners(msg, t, nil)
}
// This method is called to Report a syntax error which requires the
// insertion of a missing token into the input stream. At the time d
// method is called, the missing token has not yet been inserted. When d
// method returns, {@code recognizer} is in error recovery mode.
//
// <p>This method is called when {@link //singleTokenInsertion} identifies
// single-token insertion as a viable recovery strategy for a mismatched
// input error.</p>
//
// <p>The default implementation simply returns if the handler is already in
// error recovery mode. Otherwise, it calls {@link //beginErrorCondition} to
// enter error recovery mode, followed by calling
// {@link Parser//NotifyErrorListeners}.</p>
//
// @param recognizer the parser instance
//
func (d *DefaultErrorStrategy) ReportMissingToken(recognizer Parser) {
if d.inErrorRecoveryMode(recognizer) {
return
}
d.beginErrorCondition(recognizer)
t := recognizer.GetCurrentToken()
expecting := d.GetExpectedTokens(recognizer)
msg := "missing " + expecting.StringVerbose(recognizer.GetLiteralNames(), recognizer.GetSymbolicNames(), false) +
" at " + d.GetTokenErrorDisplay(t)
recognizer.NotifyErrorListeners(msg, t, nil)
}
// <p>The default implementation attempts to recover from the mismatched input
// by using single token insertion and deletion as described below. If the
// recovery attempt fails, d method panics an
// {@link InputMisMatchException}.</p>
//
// <p><strong>EXTRA TOKEN</strong> (single token deletion)</p>
//
// <p>{@code LA(1)} is not what we are looking for. If {@code LA(2)} has the
// right token, however, then assume {@code LA(1)} is some extra spurious
// token and delete it. Then consume and return the next token (which was
// the {@code LA(2)} token) as the successful result of the Match operation.</p>
//
// <p>This recovery strategy is implemented by {@link
// //singleTokenDeletion}.</p>
//
// <p><strong>MISSING TOKEN</strong> (single token insertion)</p>
//
// <p>If current token (at {@code LA(1)}) is consistent with what could come
// after the expected {@code LA(1)} token, then assume the token is missing
// and use the parser's {@link TokenFactory} to create it on the fly. The
// "insertion" is performed by returning the created token as the successful
// result of the Match operation.</p>
//
// <p>This recovery strategy is implemented by {@link
// //singleTokenInsertion}.</p>
//
// <p><strong>EXAMPLE</strong></p>
//
// <p>For example, Input {@code i=(3} is clearly missing the {@code ')'}. When
// the parser returns from the nested call to {@code expr}, it will have
// call chain:</p>
//
// <pre>
// stat &rarr expr &rarr atom
// </pre>
//
// and it will be trying to Match the {@code ')'} at d point in the
// derivation:
//
// <pre>
// =&gt ID '=' '(' INT ')' ('+' atom)* ''
// ^
// </pre>
//
// The attempt to Match {@code ')'} will fail when it sees {@code ''} and
// call {@link //recoverInline}. To recover, it sees that {@code LA(1)==''}
// is in the set of tokens that can follow the {@code ')'} token reference
// in rule {@code atom}. It can assume that you forgot the {@code ')'}.
//
func (d *DefaultErrorStrategy) RecoverInline(recognizer Parser) Token {
// SINGLE TOKEN DELETION
MatchedSymbol := d.SingleTokenDeletion(recognizer)
if MatchedSymbol != nil {
// we have deleted the extra token.
// now, move past ttype token as if all were ok
recognizer.Consume()
return MatchedSymbol
}
// SINGLE TOKEN INSERTION
if d.SingleTokenInsertion(recognizer) {
return d.GetMissingSymbol(recognizer)
}
// even that didn't work must panic the exception
panic(NewInputMisMatchException(recognizer))
}
//
// This method implements the single-token insertion inline error recovery
// strategy. It is called by {@link //recoverInline} if the single-token
// deletion strategy fails to recover from the mismatched input. If this
// method returns {@code true}, {@code recognizer} will be in error recovery
// mode.
//
// <p>This method determines whether or not single-token insertion is viable by
// checking if the {@code LA(1)} input symbol could be successfully Matched
// if it were instead the {@code LA(2)} symbol. If d method returns
// {@code true}, the caller is responsible for creating and inserting a
// token with the correct type to produce d behavior.</p>
//
// @param recognizer the parser instance
// @return {@code true} if single-token insertion is a viable recovery
// strategy for the current mismatched input, otherwise {@code false}
//
func (d *DefaultErrorStrategy) SingleTokenInsertion(recognizer Parser) bool {
currentSymbolType := recognizer.GetTokenStream().LA(1)
// if current token is consistent with what could come after current
// ATN state, then we know we're missing a token error recovery
// is free to conjure up and insert the missing token
atn := recognizer.GetInterpreter().atn
currentState := atn.states[recognizer.GetState()]
next := currentState.GetTransitions()[0].getTarget()
expectingAtLL2 := atn.NextTokens(next, recognizer.GetParserRuleContext())
if expectingAtLL2.contains(currentSymbolType) {
d.ReportMissingToken(recognizer)
return true
}
return false
}
// This method implements the single-token deletion inline error recovery
// strategy. It is called by {@link //recoverInline} to attempt to recover
// from mismatched input. If this method returns nil, the parser and error
// handler state will not have changed. If this method returns non-nil,
// {@code recognizer} will <em>not</em> be in error recovery mode since the
// returned token was a successful Match.
//
// <p>If the single-token deletion is successful, d method calls
// {@link //ReportUnwantedToken} to Report the error, followed by
// {@link Parser//consume} to actually "delete" the extraneous token. Then,
// before returning {@link //ReportMatch} is called to signal a successful
// Match.</p>
//
// @param recognizer the parser instance
// @return the successfully Matched {@link Token} instance if single-token
// deletion successfully recovers from the mismatched input, otherwise
// {@code nil}
//
func (d *DefaultErrorStrategy) SingleTokenDeletion(recognizer Parser) Token {
NextTokenType := recognizer.GetTokenStream().LA(2)
expecting := d.GetExpectedTokens(recognizer)
if expecting.contains(NextTokenType) {
d.ReportUnwantedToken(recognizer)
// print("recoverFromMisMatchedToken deleting " \
// + str(recognizer.GetTokenStream().LT(1)) \
// + " since " + str(recognizer.GetTokenStream().LT(2)) \
// + " is what we want", file=sys.stderr)
recognizer.Consume() // simply delete extra token
// we want to return the token we're actually Matching
MatchedSymbol := recognizer.GetCurrentToken()
d.ReportMatch(recognizer) // we know current token is correct
return MatchedSymbol
}
return nil
}
// Conjure up a missing token during error recovery.
//
// The recognizer attempts to recover from single missing
// symbols. But, actions might refer to that missing symbol.
// For example, x=ID {f($x)}. The action clearly assumes
// that there has been an identifier Matched previously and that
// $x points at that token. If that token is missing, but
// the next token in the stream is what we want we assume that
// d token is missing and we keep going. Because we
// have to return some token to replace the missing token,
// we have to conjure one up. This method gives the user control
// over the tokens returned for missing tokens. Mostly,
// you will want to create something special for identifier
// tokens. For literals such as '{' and ',', the default
// action in the parser or tree parser works. It simply creates
// a CommonToken of the appropriate type. The text will be the token.
// If you change what tokens must be created by the lexer,
// override d method to create the appropriate tokens.
//
func (d *DefaultErrorStrategy) GetMissingSymbol(recognizer Parser) Token {
currentSymbol := recognizer.GetCurrentToken()
expecting := d.GetExpectedTokens(recognizer)
expectedTokenType := expecting.first()
var tokenText string
if expectedTokenType == TokenEOF {
tokenText = "<missing EOF>"
} else {
ln := recognizer.GetLiteralNames()
if expectedTokenType > 0 && expectedTokenType < len(ln) {
tokenText = "<missing " + recognizer.GetLiteralNames()[expectedTokenType] + ">"
} else {
tokenText = "<missing undefined>" // TODO matches the JS impl
}
}
current := currentSymbol
lookback := recognizer.GetTokenStream().LT(-1)
if current.GetTokenType() == TokenEOF && lookback != nil {
current = lookback
}
tf := recognizer.GetTokenFactory()
return tf.Create(current.GetSource(), expectedTokenType, tokenText, TokenDefaultChannel, -1, -1, current.GetLine(), current.GetColumn())
}
func (d *DefaultErrorStrategy) GetExpectedTokens(recognizer Parser) *IntervalSet {
return recognizer.GetExpectedTokens()
}
// How should a token be displayed in an error message? The default
// is to display just the text, but during development you might
// want to have a lot of information spit out. Override in that case
// to use t.String() (which, for CommonToken, dumps everything about
// the token). This is better than forcing you to override a method in
// your token objects because you don't have to go modify your lexer
// so that it creates a NewJava type.
//
func (d *DefaultErrorStrategy) GetTokenErrorDisplay(t Token) string {
if t == nil {
return "<no token>"
}
s := t.GetText()
if s == "" {
if t.GetTokenType() == TokenEOF {
s = "<EOF>"
} else {
s = "<" + strconv.Itoa(t.GetTokenType()) + ">"
}
}
return d.escapeWSAndQuote(s)
}
func (d *DefaultErrorStrategy) escapeWSAndQuote(s string) string {
s = strings.Replace(s, "\t", "\\t", -1)
s = strings.Replace(s, "\n", "\\n", -1)
s = strings.Replace(s, "\r", "\\r", -1)
return "'" + s + "'"
}
// Compute the error recovery set for the current rule. During
// rule invocation, the parser pushes the set of tokens that can
// follow that rule reference on the stack d amounts to
// computing FIRST of what follows the rule reference in the
// enclosing rule. See LinearApproximator.FIRST().
// This local follow set only includes tokens
// from within the rule i.e., the FIRST computation done by
// ANTLR stops at the end of a rule.
//
// EXAMPLE
//
// When you find a "no viable alt exception", the input is not
// consistent with any of the alternatives for rule r. The best
// thing to do is to consume tokens until you see something that
// can legally follow a call to r//or* any rule that called r.
// You don't want the exact set of viable next tokens because the
// input might just be missing a token--you might consume the
// rest of the input looking for one of the missing tokens.
//
// Consider grammar:
//
// a : '[' b ']'
// | '(' b ')'
//
// b : c '^' INT
// c : ID
// | INT
//
//
// At each rule invocation, the set of tokens that could follow
// that rule is pushed on a stack. Here are the various
// context-sensitive follow sets:
//
// FOLLOW(b1_in_a) = FIRST(']') = ']'
// FOLLOW(b2_in_a) = FIRST(')') = ')'
// FOLLOW(c_in_b) = FIRST('^') = '^'
//
// Upon erroneous input "[]", the call chain is
//
// a -> b -> c
//
// and, hence, the follow context stack is:
//
// depth follow set start of rule execution
// 0 <EOF> a (from main())
// 1 ']' b
// 2 '^' c
//
// Notice that ')' is not included, because b would have to have
// been called from a different context in rule a for ')' to be
// included.
//
// For error recovery, we cannot consider FOLLOW(c)
// (context-sensitive or otherwise). We need the combined set of
// all context-sensitive FOLLOW sets--the set of all tokens that
// could follow any reference in the call chain. We need to
// reSync to one of those tokens. Note that FOLLOW(c)='^' and if
// we reSync'd to that token, we'd consume until EOF. We need to
// Sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
// In this case, for input "[]", LA(1) is ']' and in the set, so we would
// not consume anything. After printing an error, rule c would
// return normally. Rule b would not find the required '^' though.
// At this point, it gets a mismatched token error and panics an
// exception (since LA(1) is not in the viable following token
// set). The rule exception handler tries to recover, but finds
// the same recovery set and doesn't consume anything. Rule b
// exits normally returning to rule a. Now it finds the ']' (and
// with the successful Match exits errorRecovery mode).
//
// So, you can see that the parser walks up the call chain looking
// for the token that was a member of the recovery set.
//
// Errors are not generated in errorRecovery mode.
//
// ANTLR's error recovery mechanism is based upon original ideas:
//
// "Algorithms + Data Structures = Programs" by Niklaus Wirth
//
// and
//
// "A note on error recovery in recursive descent parsers":
// http://portal.acm.org/citation.cfm?id=947902.947905
//
// Later, Josef Grosch had some good ideas:
//
// "Efficient and Comfortable Error Recovery in Recursive Descent
// Parsers":
// ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
//
// Like Grosch I implement context-sensitive FOLLOW sets that are combined
// at run-time upon error to avoid overhead during parsing.
//
func (d *DefaultErrorStrategy) getErrorRecoverySet(recognizer Parser) *IntervalSet {
atn := recognizer.GetInterpreter().atn
ctx := recognizer.GetParserRuleContext()
recoverSet := NewIntervalSet()
for ctx != nil && ctx.GetInvokingState() >= 0 {
// compute what follows who invoked us
invokingState := atn.states[ctx.GetInvokingState()]
rt := invokingState.GetTransitions()[0]
follow := atn.NextTokens(rt.(*RuleTransition).followState, nil)
recoverSet.addSet(follow)
ctx = ctx.GetParent().(ParserRuleContext)
}
recoverSet.removeOne(TokenEpsilon)
return recoverSet
}
// Consume tokens until one Matches the given token set.//
func (d *DefaultErrorStrategy) consumeUntil(recognizer Parser, set *IntervalSet) {
ttype := recognizer.GetTokenStream().LA(1)
for ttype != TokenEOF && !set.contains(ttype) {
recognizer.Consume()
ttype = recognizer.GetTokenStream().LA(1)
}
}
//
// This implementation of {@link ANTLRErrorStrategy} responds to syntax errors
// by immediately canceling the parse operation with a
// {@link ParseCancellationException}. The implementation ensures that the
// {@link ParserRuleContext//exception} field is set for all parse tree nodes
// that were not completed prior to encountering the error.
//
// <p>
// This error strategy is useful in the following scenarios.</p>
//
// <ul>
// <li><strong>Two-stage parsing:</strong> This error strategy allows the first
// stage of two-stage parsing to immediately terminate if an error is
// encountered, and immediately fall back to the second stage. In addition to
// avoiding wasted work by attempting to recover from errors here, the empty
// implementation of {@link BailErrorStrategy//Sync} improves the performance of
// the first stage.</li>
// <li><strong>Silent validation:</strong> When syntax errors are not being
// Reported or logged, and the parse result is simply ignored if errors occur,
// the {@link BailErrorStrategy} avoids wasting work on recovering from errors
// when the result will be ignored either way.</li>
// </ul>
//
// <p>
// {@code myparser.setErrorHandler(NewBailErrorStrategy())}</p>
//
// @see Parser//setErrorHandler(ANTLRErrorStrategy)
type BailErrorStrategy struct {
*DefaultErrorStrategy
}
var _ ErrorStrategy = &BailErrorStrategy{}
func NewBailErrorStrategy() *BailErrorStrategy {
b := new(BailErrorStrategy)
b.DefaultErrorStrategy = NewDefaultErrorStrategy()
return b
}
// Instead of recovering from exception {@code e}, re-panic it wrapped
// in a {@link ParseCancellationException} so it is not caught by the
// rule func catches. Use {@link Exception//getCause()} to get the
// original {@link RecognitionException}.
//
func (b *BailErrorStrategy) Recover(recognizer Parser, e RecognitionException) {
context := recognizer.GetParserRuleContext()
for context != nil {
context.SetException(e)
context = context.GetParent().(ParserRuleContext)
}
panic(NewParseCancellationException()) // TODO we don't emit e properly
}
// Make sure we don't attempt to recover inline if the parser
// successfully recovers, it won't panic an exception.
//
func (b *BailErrorStrategy) RecoverInline(recognizer Parser) Token {
b.Recover(recognizer, NewInputMisMatchException(recognizer))
return nil
}
// Make sure we don't attempt to recover from problems in subrules.//
func (b *BailErrorStrategy) Sync(recognizer Parser) {
// pass
}

View File

@@ -0,0 +1,241 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// The root of the ANTLR exception hierarchy. In general, ANTLR tracks just
// 3 kinds of errors: prediction errors, failed predicate errors, and
// mismatched input errors. In each case, the parser knows where it is
// in the input, where it is in the ATN, the rule invocation stack,
// and what kind of problem occurred.
type RecognitionException interface {
GetOffendingToken() Token
GetMessage() string
GetInputStream() IntStream
}
type BaseRecognitionException struct {
message string
recognizer Recognizer
offendingToken Token
offendingState int
ctx RuleContext
input IntStream
}
func NewBaseRecognitionException(message string, recognizer Recognizer, input IntStream, ctx RuleContext) *BaseRecognitionException {
// todo
// Error.call(this)
//
// if (!!Error.captureStackTrace) {
// Error.captureStackTrace(this, RecognitionException)
// } else {
// stack := NewError().stack
// }
// TODO may be able to use - "runtime" func Stack(buf []byte, all bool) int
t := new(BaseRecognitionException)
t.message = message
t.recognizer = recognizer
t.input = input
t.ctx = ctx
// The current {@link Token} when an error occurred. Since not all streams
// support accessing symbols by index, we have to track the {@link Token}
// instance itself.
t.offendingToken = nil
// Get the ATN state number the parser was in at the time the error
// occurred. For {@link NoViableAltException} and
// {@link LexerNoViableAltException} exceptions, this is the
// {@link DecisionState} number. For others, it is the state whose outgoing
// edge we couldn't Match.
t.offendingState = -1
if t.recognizer != nil {
t.offendingState = t.recognizer.GetState()
}
return t
}
func (b *BaseRecognitionException) GetMessage() string {
return b.message
}
func (b *BaseRecognitionException) GetOffendingToken() Token {
return b.offendingToken
}
func (b *BaseRecognitionException) GetInputStream() IntStream {
return b.input
}
// <p>If the state number is not known, b method returns -1.</p>
//
// Gets the set of input symbols which could potentially follow the
// previously Matched symbol at the time b exception was panicn.
//
// <p>If the set of expected tokens is not known and could not be computed,
// b method returns {@code nil}.</p>
//
// @return The set of token types that could potentially follow the current
// state in the ATN, or {@code nil} if the information is not available.
// /
func (b *BaseRecognitionException) getExpectedTokens() *IntervalSet {
if b.recognizer != nil {
return b.recognizer.GetATN().getExpectedTokens(b.offendingState, b.ctx)
}
return nil
}
func (b *BaseRecognitionException) String() string {
return b.message
}
type LexerNoViableAltException struct {
*BaseRecognitionException
startIndex int
deadEndConfigs ATNConfigSet
}
func NewLexerNoViableAltException(lexer Lexer, input CharStream, startIndex int, deadEndConfigs ATNConfigSet) *LexerNoViableAltException {
l := new(LexerNoViableAltException)
l.BaseRecognitionException = NewBaseRecognitionException("", lexer, input, nil)
l.startIndex = startIndex
l.deadEndConfigs = deadEndConfigs
return l
}
func (l *LexerNoViableAltException) String() string {
symbol := ""
if l.startIndex >= 0 && l.startIndex < l.input.Size() {
symbol = l.input.(CharStream).GetTextFromInterval(NewInterval(l.startIndex, l.startIndex))
}
return "LexerNoViableAltException" + symbol
}
type NoViableAltException struct {
*BaseRecognitionException
startToken Token
offendingToken Token
ctx ParserRuleContext
deadEndConfigs ATNConfigSet
}
// Indicates that the parser could not decide which of two or more paths
// to take based upon the remaining input. It tracks the starting token
// of the offending input and also knows where the parser was
// in the various paths when the error. Reported by ReportNoViableAlternative()
//
func NewNoViableAltException(recognizer Parser, input TokenStream, startToken Token, offendingToken Token, deadEndConfigs ATNConfigSet, ctx ParserRuleContext) *NoViableAltException {
if ctx == nil {
ctx = recognizer.GetParserRuleContext()
}
if offendingToken == nil {
offendingToken = recognizer.GetCurrentToken()
}
if startToken == nil {
startToken = recognizer.GetCurrentToken()
}
if input == nil {
input = recognizer.GetInputStream().(TokenStream)
}
n := new(NoViableAltException)
n.BaseRecognitionException = NewBaseRecognitionException("", recognizer, input, ctx)
// Which configurations did we try at input.Index() that couldn't Match
// input.LT(1)?//
n.deadEndConfigs = deadEndConfigs
// The token object at the start index the input stream might
// not be buffering tokens so get a reference to it. (At the
// time the error occurred, of course the stream needs to keep a
// buffer all of the tokens but later we might not have access to those.)
n.startToken = startToken
n.offendingToken = offendingToken
return n
}
type InputMisMatchException struct {
*BaseRecognitionException
}
// This signifies any kind of mismatched input exceptions such as
// when the current input does not Match the expected token.
//
func NewInputMisMatchException(recognizer Parser) *InputMisMatchException {
i := new(InputMisMatchException)
i.BaseRecognitionException = NewBaseRecognitionException("", recognizer, recognizer.GetInputStream(), recognizer.GetParserRuleContext())
i.offendingToken = recognizer.GetCurrentToken()
return i
}
// A semantic predicate failed during validation. Validation of predicates
// occurs when normally parsing the alternative just like Matching a token.
// Disambiguating predicate evaluation occurs when we test a predicate during
// prediction.
type FailedPredicateException struct {
*BaseRecognitionException
ruleIndex int
predicateIndex int
predicate string
}
func NewFailedPredicateException(recognizer Parser, predicate string, message string) *FailedPredicateException {
f := new(FailedPredicateException)
f.BaseRecognitionException = NewBaseRecognitionException(f.formatMessage(predicate, message), recognizer, recognizer.GetInputStream(), recognizer.GetParserRuleContext())
s := recognizer.GetInterpreter().atn.states[recognizer.GetState()]
trans := s.GetTransitions()[0]
if trans2, ok := trans.(*PredicateTransition); ok {
f.ruleIndex = trans2.ruleIndex
f.predicateIndex = trans2.predIndex
} else {
f.ruleIndex = 0
f.predicateIndex = 0
}
f.predicate = predicate
f.offendingToken = recognizer.GetCurrentToken()
return f
}
func (f *FailedPredicateException) formatMessage(predicate, message string) string {
if message != "" {
return message
}
return "failed predicate: {" + predicate + "}?"
}
type ParseCancellationException struct {
}
func NewParseCancellationException() *ParseCancellationException {
// Error.call(this)
// Error.captureStackTrace(this, ParseCancellationException)
return new(ParseCancellationException)
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"bytes"
"io"
"os"
)
// This is an InputStream that is loaded from a file all at once
// when you construct the object.
type FileStream struct {
*InputStream
filename string
}
func NewFileStream(fileName string) (*FileStream, error) {
buf := bytes.NewBuffer(nil)
f, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer f.Close()
_, err = io.Copy(buf, f)
if err != nil {
return nil, err
}
fs := new(FileStream)
fs.filename = fileName
s := string(buf.Bytes())
fs.InputStream = NewInputStream(s)
return fs, nil
}
func (f *FileStream) GetSourceName() string {
return f.filename
}

View File

@@ -0,0 +1,3 @@
module github.com/antlr/antlr4/runtime/Go/antlr
go 1.16

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type InputStream struct {
name string
index int
data []rune
size int
}
func NewInputStream(data string) *InputStream {
is := new(InputStream)
is.name = "<empty>"
is.index = 0
is.data = []rune(data)
is.size = len(is.data) // number of runes
return is
}
func (is *InputStream) reset() {
is.index = 0
}
func (is *InputStream) Consume() {
if is.index >= is.size {
// assert is.LA(1) == TokenEOF
panic("cannot consume EOF")
}
is.index++
}
func (is *InputStream) LA(offset int) int {
if offset == 0 {
return 0 // nil
}
if offset < 0 {
offset++ // e.g., translate LA(-1) to use offset=0
}
pos := is.index + offset - 1
if pos < 0 || pos >= is.size { // invalid
return TokenEOF
}
return int(is.data[pos])
}
func (is *InputStream) LT(offset int) int {
return is.LA(offset)
}
func (is *InputStream) Index() int {
return is.index
}
func (is *InputStream) Size() int {
return is.size
}
// mark/release do nothing we have entire buffer
func (is *InputStream) Mark() int {
return -1
}
func (is *InputStream) Release(marker int) {
}
func (is *InputStream) Seek(index int) {
if index <= is.index {
is.index = index // just jump don't update stream state (line,...)
return
}
// seek forward
is.index = intMin(index, is.size)
}
func (is *InputStream) GetText(start int, stop int) string {
if stop >= is.size {
stop = is.size - 1
}
if start >= is.size {
return ""
}
return string(is.data[start : stop+1])
}
func (is *InputStream) GetTextFromTokens(start, stop Token) string {
if start != nil && stop != nil {
return is.GetTextFromInterval(NewInterval(start.GetTokenIndex(), stop.GetTokenIndex()))
}
return ""
}
func (is *InputStream) GetTextFromInterval(i *Interval) string {
return is.GetText(i.Start, i.Stop)
}
func (*InputStream) GetSourceName() string {
return "Obtained from string"
}
func (is *InputStream) String() string {
return string(is.data)
}

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type IntStream interface {
Consume()
LA(int) int
Mark() int
Release(marker int)
Index() int
Seek(index int)
Size() int
GetSourceName() string
}

View File

@@ -0,0 +1,296 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"strconv"
"strings"
)
type Interval struct {
Start int
Stop int
}
/* stop is not included! */
func NewInterval(start, stop int) *Interval {
i := new(Interval)
i.Start = start
i.Stop = stop
return i
}
func (i *Interval) Contains(item int) bool {
return item >= i.Start && item < i.Stop
}
func (i *Interval) String() string {
if i.Start == i.Stop-1 {
return strconv.Itoa(i.Start)
}
return strconv.Itoa(i.Start) + ".." + strconv.Itoa(i.Stop-1)
}
func (i *Interval) length() int {
return i.Stop - i.Start
}
type IntervalSet struct {
intervals []*Interval
readOnly bool
}
func NewIntervalSet() *IntervalSet {
i := new(IntervalSet)
i.intervals = nil
i.readOnly = false
return i
}
func (i *IntervalSet) first() int {
if len(i.intervals) == 0 {
return TokenInvalidType
}
return i.intervals[0].Start
}
func (i *IntervalSet) addOne(v int) {
i.addInterval(NewInterval(v, v+1))
}
func (i *IntervalSet) addRange(l, h int) {
i.addInterval(NewInterval(l, h+1))
}
func (i *IntervalSet) addInterval(v *Interval) {
if i.intervals == nil {
i.intervals = make([]*Interval, 0)
i.intervals = append(i.intervals, v)
} else {
// find insert pos
for k, interval := range i.intervals {
// distinct range -> insert
if v.Stop < interval.Start {
i.intervals = append(i.intervals[0:k], append([]*Interval{v}, i.intervals[k:]...)...)
return
} else if v.Stop == interval.Start {
i.intervals[k].Start = v.Start
return
} else if v.Start <= interval.Stop {
i.intervals[k] = NewInterval(intMin(interval.Start, v.Start), intMax(interval.Stop, v.Stop))
// if not applying to end, merge potential overlaps
if k < len(i.intervals)-1 {
l := i.intervals[k]
r := i.intervals[k+1]
// if r contained in l
if l.Stop >= r.Stop {
i.intervals = append(i.intervals[0:k+1], i.intervals[k+2:]...)
} else if l.Stop >= r.Start { // partial overlap
i.intervals[k] = NewInterval(l.Start, r.Stop)
i.intervals = append(i.intervals[0:k+1], i.intervals[k+2:]...)
}
}
return
}
}
// greater than any exiting
i.intervals = append(i.intervals, v)
}
}
func (i *IntervalSet) addSet(other *IntervalSet) *IntervalSet {
if other.intervals != nil {
for k := 0; k < len(other.intervals); k++ {
i2 := other.intervals[k]
i.addInterval(NewInterval(i2.Start, i2.Stop))
}
}
return i
}
func (i *IntervalSet) complement(start int, stop int) *IntervalSet {
result := NewIntervalSet()
result.addInterval(NewInterval(start, stop+1))
for j := 0; j < len(i.intervals); j++ {
result.removeRange(i.intervals[j])
}
return result
}
func (i *IntervalSet) contains(item int) bool {
if i.intervals == nil {
return false
}
for k := 0; k < len(i.intervals); k++ {
if i.intervals[k].Contains(item) {
return true
}
}
return false
}
func (i *IntervalSet) length() int {
len := 0
for _, v := range i.intervals {
len += v.length()
}
return len
}
func (i *IntervalSet) removeRange(v *Interval) {
if v.Start == v.Stop-1 {
i.removeOne(v.Start)
} else if i.intervals != nil {
k := 0
for n := 0; n < len(i.intervals); n++ {
ni := i.intervals[k]
// intervals are ordered
if v.Stop <= ni.Start {
return
} else if v.Start > ni.Start && v.Stop < ni.Stop {
i.intervals[k] = NewInterval(ni.Start, v.Start)
x := NewInterval(v.Stop, ni.Stop)
// i.intervals.splice(k, 0, x)
i.intervals = append(i.intervals[0:k], append([]*Interval{x}, i.intervals[k:]...)...)
return
} else if v.Start <= ni.Start && v.Stop >= ni.Stop {
// i.intervals.splice(k, 1)
i.intervals = append(i.intervals[0:k], i.intervals[k+1:]...)
k = k - 1 // need another pass
} else if v.Start < ni.Stop {
i.intervals[k] = NewInterval(ni.Start, v.Start)
} else if v.Stop < ni.Stop {
i.intervals[k] = NewInterval(v.Stop, ni.Stop)
}
k++
}
}
}
func (i *IntervalSet) removeOne(v int) {
if i.intervals != nil {
for k := 0; k < len(i.intervals); k++ {
ki := i.intervals[k]
// intervals i ordered
if v < ki.Start {
return
} else if v == ki.Start && v == ki.Stop-1 {
// i.intervals.splice(k, 1)
i.intervals = append(i.intervals[0:k], i.intervals[k+1:]...)
return
} else if v == ki.Start {
i.intervals[k] = NewInterval(ki.Start+1, ki.Stop)
return
} else if v == ki.Stop-1 {
i.intervals[k] = NewInterval(ki.Start, ki.Stop-1)
return
} else if v < ki.Stop-1 {
x := NewInterval(ki.Start, v)
ki.Start = v + 1
// i.intervals.splice(k, 0, x)
i.intervals = append(i.intervals[0:k], append([]*Interval{x}, i.intervals[k:]...)...)
return
}
}
}
}
func (i *IntervalSet) String() string {
return i.StringVerbose(nil, nil, false)
}
func (i *IntervalSet) StringVerbose(literalNames []string, symbolicNames []string, elemsAreChar bool) string {
if i.intervals == nil {
return "{}"
} else if literalNames != nil || symbolicNames != nil {
return i.toTokenString(literalNames, symbolicNames)
} else if elemsAreChar {
return i.toCharString()
}
return i.toIndexString()
}
func (i *IntervalSet) toCharString() string {
names := make([]string, len(i.intervals))
for j := 0; j < len(i.intervals); j++ {
v := i.intervals[j]
if v.Stop == v.Start+1 {
if v.Start == TokenEOF {
names = append(names, "<EOF>")
} else {
names = append(names, ("'" + string(v.Start) + "'"))
}
} else {
names = append(names, "'"+string(v.Start)+"'..'"+string(v.Stop-1)+"'")
}
}
if len(names) > 1 {
return "{" + strings.Join(names, ", ") + "}"
}
return names[0]
}
func (i *IntervalSet) toIndexString() string {
names := make([]string, 0)
for j := 0; j < len(i.intervals); j++ {
v := i.intervals[j]
if v.Stop == v.Start+1 {
if v.Start == TokenEOF {
names = append(names, "<EOF>")
} else {
names = append(names, strconv.Itoa(v.Start))
}
} else {
names = append(names, strconv.Itoa(v.Start)+".."+strconv.Itoa(v.Stop-1))
}
}
if len(names) > 1 {
return "{" + strings.Join(names, ", ") + "}"
}
return names[0]
}
func (i *IntervalSet) toTokenString(literalNames []string, symbolicNames []string) string {
names := make([]string, 0)
for _, v := range i.intervals {
for j := v.Start; j < v.Stop; j++ {
names = append(names, i.elementName(literalNames, symbolicNames, j))
}
}
if len(names) > 1 {
return "{" + strings.Join(names, ", ") + "}"
}
return names[0]
}
func (i *IntervalSet) elementName(literalNames []string, symbolicNames []string, a int) string {
if a == TokenEOF {
return "<EOF>"
} else if a == TokenEpsilon {
return "<EPSILON>"
} else {
if a < len(literalNames) && literalNames[a] != "" {
return literalNames[a]
}
return symbolicNames[a]
}
}

View File

@@ -0,0 +1,418 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
// A lexer is recognizer that draws input symbols from a character stream.
// lexer grammars result in a subclass of this object. A Lexer object
// uses simplified Match() and error recovery mechanisms in the interest
// of speed.
///
type Lexer interface {
TokenSource
Recognizer
Emit() Token
SetChannel(int)
PushMode(int)
PopMode() int
SetType(int)
SetMode(int)
}
type BaseLexer struct {
*BaseRecognizer
Interpreter ILexerATNSimulator
TokenStartCharIndex int
TokenStartLine int
TokenStartColumn int
ActionType int
Virt Lexer // The most derived lexer implementation. Allows virtual method calls.
input CharStream
factory TokenFactory
tokenFactorySourcePair *TokenSourceCharStreamPair
token Token
hitEOF bool
channel int
thetype int
modeStack IntStack
mode int
text string
}
func NewBaseLexer(input CharStream) *BaseLexer {
lexer := new(BaseLexer)
lexer.BaseRecognizer = NewBaseRecognizer()
lexer.input = input
lexer.factory = CommonTokenFactoryDEFAULT
lexer.tokenFactorySourcePair = &TokenSourceCharStreamPair{lexer, input}
lexer.Virt = lexer
lexer.Interpreter = nil // child classes must populate it
// The goal of all lexer rules/methods is to create a token object.
// l is an instance variable as multiple rules may collaborate to
// create a single token. NextToken will return l object after
// Matching lexer rule(s). If you subclass to allow multiple token
// emissions, then set l to the last token to be Matched or
// something nonnil so that the auto token emit mechanism will not
// emit another token.
lexer.token = nil
// What character index in the stream did the current token start at?
// Needed, for example, to get the text for current token. Set at
// the start of NextToken.
lexer.TokenStartCharIndex = -1
// The line on which the first character of the token resides///
lexer.TokenStartLine = -1
// The character position of first character within the line///
lexer.TokenStartColumn = -1
// Once we see EOF on char stream, next token will be EOF.
// If you have DONE : EOF then you see DONE EOF.
lexer.hitEOF = false
// The channel number for the current token///
lexer.channel = TokenDefaultChannel
// The token type for the current token///
lexer.thetype = TokenInvalidType
lexer.modeStack = make([]int, 0)
lexer.mode = LexerDefaultMode
// You can set the text for the current token to override what is in
// the input char buffer. Use setText() or can set l instance var.
// /
lexer.text = ""
return lexer
}
const (
LexerDefaultMode = 0
LexerMore = -2
LexerSkip = -3
)
const (
LexerDefaultTokenChannel = TokenDefaultChannel
LexerHidden = TokenHiddenChannel
LexerMinCharValue = 0x0000
LexerMaxCharValue = 0x10FFFF
)
func (b *BaseLexer) reset() {
// wack Lexer state variables
if b.input != nil {
b.input.Seek(0) // rewind the input
}
b.token = nil
b.thetype = TokenInvalidType
b.channel = TokenDefaultChannel
b.TokenStartCharIndex = -1
b.TokenStartColumn = -1
b.TokenStartLine = -1
b.text = ""
b.hitEOF = false
b.mode = LexerDefaultMode
b.modeStack = make([]int, 0)
b.Interpreter.reset()
}
func (b *BaseLexer) GetInterpreter() ILexerATNSimulator {
return b.Interpreter
}
func (b *BaseLexer) GetInputStream() CharStream {
return b.input
}
func (b *BaseLexer) GetSourceName() string {
return b.GrammarFileName
}
func (b *BaseLexer) SetChannel(v int) {
b.channel = v
}
func (b *BaseLexer) GetTokenFactory() TokenFactory {
return b.factory
}
func (b *BaseLexer) setTokenFactory(f TokenFactory) {
b.factory = f
}
func (b *BaseLexer) safeMatch() (ret int) {
defer func() {
if e := recover(); e != nil {
if re, ok := e.(RecognitionException); ok {
b.notifyListeners(re) // Report error
b.Recover(re)
ret = LexerSkip // default
}
}
}()
return b.Interpreter.Match(b.input, b.mode)
}
// Return a token from l source i.e., Match a token on the char stream.
func (b *BaseLexer) NextToken() Token {
if b.input == nil {
panic("NextToken requires a non-nil input stream.")
}
tokenStartMarker := b.input.Mark()
// previously in finally block
defer func() {
// make sure we release marker after Match or
// unbuffered char stream will keep buffering
b.input.Release(tokenStartMarker)
}()
for {
if b.hitEOF {
b.EmitEOF()
return b.token
}
b.token = nil
b.channel = TokenDefaultChannel
b.TokenStartCharIndex = b.input.Index()
b.TokenStartColumn = b.Interpreter.GetCharPositionInLine()
b.TokenStartLine = b.Interpreter.GetLine()
b.text = ""
continueOuter := false
for {
b.thetype = TokenInvalidType
ttype := LexerSkip
ttype = b.safeMatch()
if b.input.LA(1) == TokenEOF {
b.hitEOF = true
}
if b.thetype == TokenInvalidType {
b.thetype = ttype
}
if b.thetype == LexerSkip {
continueOuter = true
break
}
if b.thetype != LexerMore {
break
}
}
if continueOuter {
continue
}
if b.token == nil {
b.Virt.Emit()
}
return b.token
}
return nil
}
// Instruct the lexer to Skip creating a token for current lexer rule
// and look for another token. NextToken() knows to keep looking when
// a lexer rule finishes with token set to SKIPTOKEN. Recall that
// if token==nil at end of any token rule, it creates one for you
// and emits it.
// /
func (b *BaseLexer) Skip() {
b.thetype = LexerSkip
}
func (b *BaseLexer) More() {
b.thetype = LexerMore
}
func (b *BaseLexer) SetMode(m int) {
b.mode = m
}
func (b *BaseLexer) PushMode(m int) {
if LexerATNSimulatorDebug {
fmt.Println("pushMode " + strconv.Itoa(m))
}
b.modeStack.Push(b.mode)
b.mode = m
}
func (b *BaseLexer) PopMode() int {
if len(b.modeStack) == 0 {
panic("Empty Stack")
}
if LexerATNSimulatorDebug {
fmt.Println("popMode back to " + fmt.Sprint(b.modeStack[0:len(b.modeStack)-1]))
}
i, _ := b.modeStack.Pop()
b.mode = i
return b.mode
}
func (b *BaseLexer) inputStream() CharStream {
return b.input
}
// SetInputStream resets the lexer input stream and associated lexer state.
func (b *BaseLexer) SetInputStream(input CharStream) {
b.input = nil
b.tokenFactorySourcePair = &TokenSourceCharStreamPair{b, b.input}
b.reset()
b.input = input
b.tokenFactorySourcePair = &TokenSourceCharStreamPair{b, b.input}
}
func (b *BaseLexer) GetTokenSourceCharStreamPair() *TokenSourceCharStreamPair {
return b.tokenFactorySourcePair
}
// By default does not support multiple emits per NextToken invocation
// for efficiency reasons. Subclass and override l method, NextToken,
// and GetToken (to push tokens into a list and pull from that list
// rather than a single variable as l implementation does).
// /
func (b *BaseLexer) EmitToken(token Token) {
b.token = token
}
// The standard method called to automatically emit a token at the
// outermost lexical rule. The token object should point into the
// char buffer start..stop. If there is a text override in 'text',
// use that to set the token's text. Override l method to emit
// custom Token objects or provide a Newfactory.
// /
func (b *BaseLexer) Emit() Token {
t := b.factory.Create(b.tokenFactorySourcePair, b.thetype, b.text, b.channel, b.TokenStartCharIndex, b.GetCharIndex()-1, b.TokenStartLine, b.TokenStartColumn)
b.EmitToken(t)
return t
}
func (b *BaseLexer) EmitEOF() Token {
cpos := b.GetCharPositionInLine()
lpos := b.GetLine()
eof := b.factory.Create(b.tokenFactorySourcePair, TokenEOF, "", TokenDefaultChannel, b.input.Index(), b.input.Index()-1, lpos, cpos)
b.EmitToken(eof)
return eof
}
func (b *BaseLexer) GetCharPositionInLine() int {
return b.Interpreter.GetCharPositionInLine()
}
func (b *BaseLexer) GetLine() int {
return b.Interpreter.GetLine()
}
func (b *BaseLexer) GetType() int {
return b.thetype
}
func (b *BaseLexer) SetType(t int) {
b.thetype = t
}
// What is the index of the current character of lookahead?///
func (b *BaseLexer) GetCharIndex() int {
return b.input.Index()
}
// Return the text Matched so far for the current token or any text override.
//Set the complete text of l token it wipes any previous changes to the text.
func (b *BaseLexer) GetText() string {
if b.text != "" {
return b.text
}
return b.Interpreter.GetText(b.input)
}
func (b *BaseLexer) SetText(text string) {
b.text = text
}
func (b *BaseLexer) GetATN() *ATN {
return b.Interpreter.ATN()
}
// Return a list of all Token objects in input char stream.
// Forces load of all tokens. Does not include EOF token.
// /
func (b *BaseLexer) GetAllTokens() []Token {
vl := b.Virt
tokens := make([]Token, 0)
t := vl.NextToken()
for t.GetTokenType() != TokenEOF {
tokens = append(tokens, t)
t = vl.NextToken()
}
return tokens
}
func (b *BaseLexer) notifyListeners(e RecognitionException) {
start := b.TokenStartCharIndex
stop := b.input.Index()
text := b.input.GetTextFromInterval(NewInterval(start, stop))
msg := "token recognition error at: '" + text + "'"
listener := b.GetErrorListenerDispatch()
listener.SyntaxError(b, nil, b.TokenStartLine, b.TokenStartColumn, msg, e)
}
func (b *BaseLexer) getErrorDisplayForChar(c rune) string {
if c == TokenEOF {
return "<EOF>"
} else if c == '\n' {
return "\\n"
} else if c == '\t' {
return "\\t"
} else if c == '\r' {
return "\\r"
} else {
return string(c)
}
}
func (b *BaseLexer) getCharErrorDisplay(c rune) string {
return "'" + b.getErrorDisplayForChar(c) + "'"
}
// Lexers can normally Match any char in it's vocabulary after Matching
// a token, so do the easy thing and just kill a character and hope
// it all works out. You can instead use the rule invocation stack
// to do sophisticated error recovery if you are in a fragment rule.
// /
func (b *BaseLexer) Recover(re RecognitionException) {
if b.input.LA(1) != TokenEOF {
if _, ok := re.(*LexerNoViableAltException); ok {
// Skip a char and try again
b.Interpreter.Consume(b.input)
} else {
// TODO: Do we lose character or line position information?
b.input.Consume()
}
}
}

View File

@@ -0,0 +1,431 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import "strconv"
const (
LexerActionTypeChannel = 0 //The type of a {@link LexerChannelAction} action.
LexerActionTypeCustom = 1 //The type of a {@link LexerCustomAction} action.
LexerActionTypeMode = 2 //The type of a {@link LexerModeAction} action.
LexerActionTypeMore = 3 //The type of a {@link LexerMoreAction} action.
LexerActionTypePopMode = 4 //The type of a {@link LexerPopModeAction} action.
LexerActionTypePushMode = 5 //The type of a {@link LexerPushModeAction} action.
LexerActionTypeSkip = 6 //The type of a {@link LexerSkipAction} action.
LexerActionTypeType = 7 //The type of a {@link LexerTypeAction} action.
)
type LexerAction interface {
getActionType() int
getIsPositionDependent() bool
execute(lexer Lexer)
hash() int
equals(other LexerAction) bool
}
type BaseLexerAction struct {
actionType int
isPositionDependent bool
}
func NewBaseLexerAction(action int) *BaseLexerAction {
la := new(BaseLexerAction)
la.actionType = action
la.isPositionDependent = false
return la
}
func (b *BaseLexerAction) execute(lexer Lexer) {
panic("Not implemented")
}
func (b *BaseLexerAction) getActionType() int {
return b.actionType
}
func (b *BaseLexerAction) getIsPositionDependent() bool {
return b.isPositionDependent
}
func (b *BaseLexerAction) hash() int {
return b.actionType
}
func (b *BaseLexerAction) equals(other LexerAction) bool {
return b == other
}
//
// Implements the {@code Skip} lexer action by calling {@link Lexer//Skip}.
//
// <p>The {@code Skip} command does not have any parameters, so l action is
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
type LexerSkipAction struct {
*BaseLexerAction
}
func NewLexerSkipAction() *LexerSkipAction {
la := new(LexerSkipAction)
la.BaseLexerAction = NewBaseLexerAction(LexerActionTypeSkip)
return la
}
// Provides a singleton instance of l parameterless lexer action.
var LexerSkipActionINSTANCE = NewLexerSkipAction()
func (l *LexerSkipAction) execute(lexer Lexer) {
lexer.Skip()
}
func (l *LexerSkipAction) String() string {
return "skip"
}
// Implements the {@code type} lexer action by calling {@link Lexer//setType}
// with the assigned type.
type LexerTypeAction struct {
*BaseLexerAction
thetype int
}
func NewLexerTypeAction(thetype int) *LexerTypeAction {
l := new(LexerTypeAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypeType)
l.thetype = thetype
return l
}
func (l *LexerTypeAction) execute(lexer Lexer) {
lexer.SetType(l.thetype)
}
func (l *LexerTypeAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.thetype)
return murmurFinish(h, 2)
}
func (l *LexerTypeAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerTypeAction); !ok {
return false
} else {
return l.thetype == other.(*LexerTypeAction).thetype
}
}
func (l *LexerTypeAction) String() string {
return "actionType(" + strconv.Itoa(l.thetype) + ")"
}
// Implements the {@code pushMode} lexer action by calling
// {@link Lexer//pushMode} with the assigned mode.
type LexerPushModeAction struct {
*BaseLexerAction
mode int
}
func NewLexerPushModeAction(mode int) *LexerPushModeAction {
l := new(LexerPushModeAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypePushMode)
l.mode = mode
return l
}
// <p>This action is implemented by calling {@link Lexer//pushMode} with the
// value provided by {@link //getMode}.</p>
func (l *LexerPushModeAction) execute(lexer Lexer) {
lexer.PushMode(l.mode)
}
func (l *LexerPushModeAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.mode)
return murmurFinish(h, 2)
}
func (l *LexerPushModeAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerPushModeAction); !ok {
return false
} else {
return l.mode == other.(*LexerPushModeAction).mode
}
}
func (l *LexerPushModeAction) String() string {
return "pushMode(" + strconv.Itoa(l.mode) + ")"
}
// Implements the {@code popMode} lexer action by calling {@link Lexer//popMode}.
//
// <p>The {@code popMode} command does not have any parameters, so l action is
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
type LexerPopModeAction struct {
*BaseLexerAction
}
func NewLexerPopModeAction() *LexerPopModeAction {
l := new(LexerPopModeAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypePopMode)
return l
}
var LexerPopModeActionINSTANCE = NewLexerPopModeAction()
// <p>This action is implemented by calling {@link Lexer//popMode}.</p>
func (l *LexerPopModeAction) execute(lexer Lexer) {
lexer.PopMode()
}
func (l *LexerPopModeAction) String() string {
return "popMode"
}
// Implements the {@code more} lexer action by calling {@link Lexer//more}.
//
// <p>The {@code more} command does not have any parameters, so l action is
// implemented as a singleton instance exposed by {@link //INSTANCE}.</p>
type LexerMoreAction struct {
*BaseLexerAction
}
func NewLexerMoreAction() *LexerMoreAction {
l := new(LexerMoreAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypeMore)
return l
}
var LexerMoreActionINSTANCE = NewLexerMoreAction()
// <p>This action is implemented by calling {@link Lexer//popMode}.</p>
func (l *LexerMoreAction) execute(lexer Lexer) {
lexer.More()
}
func (l *LexerMoreAction) String() string {
return "more"
}
// Implements the {@code mode} lexer action by calling {@link Lexer//mode} with
// the assigned mode.
type LexerModeAction struct {
*BaseLexerAction
mode int
}
func NewLexerModeAction(mode int) *LexerModeAction {
l := new(LexerModeAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypeMode)
l.mode = mode
return l
}
// <p>This action is implemented by calling {@link Lexer//mode} with the
// value provided by {@link //getMode}.</p>
func (l *LexerModeAction) execute(lexer Lexer) {
lexer.SetMode(l.mode)
}
func (l *LexerModeAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.mode)
return murmurFinish(h, 2)
}
func (l *LexerModeAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerModeAction); !ok {
return false
} else {
return l.mode == other.(*LexerModeAction).mode
}
}
func (l *LexerModeAction) String() string {
return "mode(" + strconv.Itoa(l.mode) + ")"
}
// Executes a custom lexer action by calling {@link Recognizer//action} with the
// rule and action indexes assigned to the custom action. The implementation of
// a custom action is added to the generated code for the lexer in an override
// of {@link Recognizer//action} when the grammar is compiled.
//
// <p>This class may represent embedded actions created with the <code>{...}</code>
// syntax in ANTLR 4, as well as actions created for lexer commands where the
// command argument could not be evaluated when the grammar was compiled.</p>
// Constructs a custom lexer action with the specified rule and action
// indexes.
//
// @param ruleIndex The rule index to use for calls to
// {@link Recognizer//action}.
// @param actionIndex The action index to use for calls to
// {@link Recognizer//action}.
type LexerCustomAction struct {
*BaseLexerAction
ruleIndex, actionIndex int
}
func NewLexerCustomAction(ruleIndex, actionIndex int) *LexerCustomAction {
l := new(LexerCustomAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypeCustom)
l.ruleIndex = ruleIndex
l.actionIndex = actionIndex
l.isPositionDependent = true
return l
}
// <p>Custom actions are implemented by calling {@link Lexer//action} with the
// appropriate rule and action indexes.</p>
func (l *LexerCustomAction) execute(lexer Lexer) {
lexer.Action(nil, l.ruleIndex, l.actionIndex)
}
func (l *LexerCustomAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.ruleIndex)
h = murmurUpdate(h, l.actionIndex)
return murmurFinish(h, 3)
}
func (l *LexerCustomAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerCustomAction); !ok {
return false
} else {
return l.ruleIndex == other.(*LexerCustomAction).ruleIndex && l.actionIndex == other.(*LexerCustomAction).actionIndex
}
}
// Implements the {@code channel} lexer action by calling
// {@link Lexer//setChannel} with the assigned channel.
// Constructs a New{@code channel} action with the specified channel value.
// @param channel The channel value to pass to {@link Lexer//setChannel}.
type LexerChannelAction struct {
*BaseLexerAction
channel int
}
func NewLexerChannelAction(channel int) *LexerChannelAction {
l := new(LexerChannelAction)
l.BaseLexerAction = NewBaseLexerAction(LexerActionTypeChannel)
l.channel = channel
return l
}
// <p>This action is implemented by calling {@link Lexer//setChannel} with the
// value provided by {@link //getChannel}.</p>
func (l *LexerChannelAction) execute(lexer Lexer) {
lexer.SetChannel(l.channel)
}
func (l *LexerChannelAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.channel)
return murmurFinish(h, 2)
}
func (l *LexerChannelAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerChannelAction); !ok {
return false
} else {
return l.channel == other.(*LexerChannelAction).channel
}
}
func (l *LexerChannelAction) String() string {
return "channel(" + strconv.Itoa(l.channel) + ")"
}
// This implementation of {@link LexerAction} is used for tracking input offsets
// for position-dependent actions within a {@link LexerActionExecutor}.
//
// <p>This action is not serialized as part of the ATN, and is only required for
// position-dependent lexer actions which appear at a location other than the
// end of a rule. For more information about DFA optimizations employed for
// lexer actions, see {@link LexerActionExecutor//append} and
// {@link LexerActionExecutor//fixOffsetBeforeMatch}.</p>
// Constructs a Newindexed custom action by associating a character offset
// with a {@link LexerAction}.
//
// <p>Note: This class is only required for lexer actions for which
// {@link LexerAction//isPositionDependent} returns {@code true}.</p>
//
// @param offset The offset into the input {@link CharStream}, relative to
// the token start index, at which the specified lexer action should be
// executed.
// @param action The lexer action to execute at a particular offset in the
// input {@link CharStream}.
type LexerIndexedCustomAction struct {
*BaseLexerAction
offset int
lexerAction LexerAction
isPositionDependent bool
}
func NewLexerIndexedCustomAction(offset int, lexerAction LexerAction) *LexerIndexedCustomAction {
l := new(LexerIndexedCustomAction)
l.BaseLexerAction = NewBaseLexerAction(lexerAction.getActionType())
l.offset = offset
l.lexerAction = lexerAction
l.isPositionDependent = true
return l
}
// <p>This method calls {@link //execute} on the result of {@link //getAction}
// using the provided {@code lexer}.</p>
func (l *LexerIndexedCustomAction) execute(lexer Lexer) {
// assume the input stream position was properly set by the calling code
l.lexerAction.execute(lexer)
}
func (l *LexerIndexedCustomAction) hash() int {
h := murmurInit(0)
h = murmurUpdate(h, l.actionType)
h = murmurUpdate(h, l.offset)
h = murmurUpdate(h, l.lexerAction.hash())
return murmurFinish(h, 3)
}
func (l *LexerIndexedCustomAction) equals(other LexerAction) bool {
if l == other {
return true
} else if _, ok := other.(*LexerIndexedCustomAction); !ok {
return false
} else {
return l.offset == other.(*LexerIndexedCustomAction).offset && l.lexerAction == other.(*LexerIndexedCustomAction).lexerAction
}
}

View File

@@ -0,0 +1,170 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// Represents an executor for a sequence of lexer actions which traversed during
// the Matching operation of a lexer rule (token).
//
// <p>The executor tracks position information for position-dependent lexer actions
// efficiently, ensuring that actions appearing only at the end of the rule do
// not cause bloating of the {@link DFA} created for the lexer.</p>
type LexerActionExecutor struct {
lexerActions []LexerAction
cachedHash int
}
func NewLexerActionExecutor(lexerActions []LexerAction) *LexerActionExecutor {
if lexerActions == nil {
lexerActions = make([]LexerAction, 0)
}
l := new(LexerActionExecutor)
l.lexerActions = lexerActions
// Caches the result of {@link //hashCode} since the hash code is an element
// of the performance-critical {@link LexerATNConfig//hashCode} operation.
l.cachedHash = murmurInit(57)
for _, a := range lexerActions {
l.cachedHash = murmurUpdate(l.cachedHash, a.hash())
}
return l
}
// Creates a {@link LexerActionExecutor} which executes the actions for
// the input {@code lexerActionExecutor} followed by a specified
// {@code lexerAction}.
//
// @param lexerActionExecutor The executor for actions already traversed by
// the lexer while Matching a token within a particular
// {@link LexerATNConfig}. If this is {@code nil}, the method behaves as
// though it were an empty executor.
// @param lexerAction The lexer action to execute after the actions
// specified in {@code lexerActionExecutor}.
//
// @return A {@link LexerActionExecutor} for executing the combine actions
// of {@code lexerActionExecutor} and {@code lexerAction}.
func LexerActionExecutorappend(lexerActionExecutor *LexerActionExecutor, lexerAction LexerAction) *LexerActionExecutor {
if lexerActionExecutor == nil {
return NewLexerActionExecutor([]LexerAction{lexerAction})
}
return NewLexerActionExecutor(append(lexerActionExecutor.lexerActions, lexerAction))
}
// Creates a {@link LexerActionExecutor} which encodes the current offset
// for position-dependent lexer actions.
//
// <p>Normally, when the executor encounters lexer actions where
// {@link LexerAction//isPositionDependent} returns {@code true}, it calls
// {@link IntStream//seek} on the input {@link CharStream} to set the input
// position to the <em>end</em> of the current token. This behavior provides
// for efficient DFA representation of lexer actions which appear at the end
// of a lexer rule, even when the lexer rule Matches a variable number of
// characters.</p>
//
// <p>Prior to traversing a Match transition in the ATN, the current offset
// from the token start index is assigned to all position-dependent lexer
// actions which have not already been assigned a fixed offset. By storing
// the offsets relative to the token start index, the DFA representation of
// lexer actions which appear in the middle of tokens remains efficient due
// to sharing among tokens of the same length, regardless of their absolute
// position in the input stream.</p>
//
// <p>If the current executor already has offsets assigned to all
// position-dependent lexer actions, the method returns {@code this}.</p>
//
// @param offset The current offset to assign to all position-dependent
// lexer actions which do not already have offsets assigned.
//
// @return A {@link LexerActionExecutor} which stores input stream offsets
// for all position-dependent lexer actions.
// /
func (l *LexerActionExecutor) fixOffsetBeforeMatch(offset int) *LexerActionExecutor {
var updatedLexerActions []LexerAction
for i := 0; i < len(l.lexerActions); i++ {
_, ok := l.lexerActions[i].(*LexerIndexedCustomAction)
if l.lexerActions[i].getIsPositionDependent() && !ok {
if updatedLexerActions == nil {
updatedLexerActions = make([]LexerAction, 0)
for _, a := range l.lexerActions {
updatedLexerActions = append(updatedLexerActions, a)
}
}
updatedLexerActions[i] = NewLexerIndexedCustomAction(offset, l.lexerActions[i])
}
}
if updatedLexerActions == nil {
return l
}
return NewLexerActionExecutor(updatedLexerActions)
}
// Execute the actions encapsulated by l executor within the context of a
// particular {@link Lexer}.
//
// <p>This method calls {@link IntStream//seek} to set the position of the
// {@code input} {@link CharStream} prior to calling
// {@link LexerAction//execute} on a position-dependent action. Before the
// method returns, the input position will be restored to the same position
// it was in when the method was invoked.</p>
//
// @param lexer The lexer instance.
// @param input The input stream which is the source for the current token.
// When l method is called, the current {@link IntStream//index} for
// {@code input} should be the start of the following token, i.e. 1
// character past the end of the current token.
// @param startIndex The token start index. This value may be passed to
// {@link IntStream//seek} to set the {@code input} position to the beginning
// of the token.
// /
func (l *LexerActionExecutor) execute(lexer Lexer, input CharStream, startIndex int) {
requiresSeek := false
stopIndex := input.Index()
defer func() {
if requiresSeek {
input.Seek(stopIndex)
}
}()
for i := 0; i < len(l.lexerActions); i++ {
lexerAction := l.lexerActions[i]
if la, ok := lexerAction.(*LexerIndexedCustomAction); ok {
offset := la.offset
input.Seek(startIndex + offset)
lexerAction = la.lexerAction
requiresSeek = (startIndex + offset) != stopIndex
} else if lexerAction.getIsPositionDependent() {
input.Seek(stopIndex)
requiresSeek = false
}
lexerAction.execute(lexer)
}
}
func (l *LexerActionExecutor) hash() int {
if l == nil {
return 61
}
return l.cachedHash
}
func (l *LexerActionExecutor) equals(other interface{}) bool {
if l == other {
return true
} else if _, ok := other.(*LexerActionExecutor); !ok {
return false
} else {
return l.cachedHash == other.(*LexerActionExecutor).cachedHash &&
&l.lexerActions == &other.(*LexerActionExecutor).lexerActions
}
}

View File

@@ -0,0 +1,658 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
var (
LexerATNSimulatorDebug = false
LexerATNSimulatorDFADebug = false
LexerATNSimulatorMinDFAEdge = 0
LexerATNSimulatorMaxDFAEdge = 127 // forces unicode to stay in ATN
LexerATNSimulatorMatchCalls = 0
)
type ILexerATNSimulator interface {
IATNSimulator
reset()
Match(input CharStream, mode int) int
GetCharPositionInLine() int
GetLine() int
GetText(input CharStream) string
Consume(input CharStream)
}
type LexerATNSimulator struct {
*BaseATNSimulator
recog Lexer
predictionMode int
mergeCache DoubleDict
startIndex int
Line int
CharPositionInLine int
mode int
prevAccept *SimState
MatchCalls int
}
func NewLexerATNSimulator(recog Lexer, atn *ATN, decisionToDFA []*DFA, sharedContextCache *PredictionContextCache) *LexerATNSimulator {
l := new(LexerATNSimulator)
l.BaseATNSimulator = NewBaseATNSimulator(atn, sharedContextCache)
l.decisionToDFA = decisionToDFA
l.recog = recog
// The current token's starting index into the character stream.
// Shared across DFA to ATN simulation in case the ATN fails and the
// DFA did not have a previous accept state. In l case, we use the
// ATN-generated exception object.
l.startIndex = -1
// line number 1..n within the input///
l.Line = 1
// The index of the character relative to the beginning of the line
// 0..n-1///
l.CharPositionInLine = 0
l.mode = LexerDefaultMode
// Used during DFA/ATN exec to record the most recent accept configuration
// info
l.prevAccept = NewSimState()
// done
return l
}
func (l *LexerATNSimulator) copyState(simulator *LexerATNSimulator) {
l.CharPositionInLine = simulator.CharPositionInLine
l.Line = simulator.Line
l.mode = simulator.mode
l.startIndex = simulator.startIndex
}
func (l *LexerATNSimulator) Match(input CharStream, mode int) int {
l.MatchCalls++
l.mode = mode
mark := input.Mark()
defer func() {
input.Release(mark)
}()
l.startIndex = input.Index()
l.prevAccept.reset()
dfa := l.decisionToDFA[mode]
if dfa.getS0() == nil {
return l.MatchATN(input)
}
return l.execATN(input, dfa.getS0())
}
func (l *LexerATNSimulator) reset() {
l.prevAccept.reset()
l.startIndex = -1
l.Line = 1
l.CharPositionInLine = 0
l.mode = LexerDefaultMode
}
func (l *LexerATNSimulator) MatchATN(input CharStream) int {
startState := l.atn.modeToStartState[l.mode]
if LexerATNSimulatorDebug {
fmt.Println("MatchATN mode " + strconv.Itoa(l.mode) + " start: " + startState.String())
}
oldMode := l.mode
s0Closure := l.computeStartState(input, startState)
suppressEdge := s0Closure.hasSemanticContext
s0Closure.hasSemanticContext = false
next := l.addDFAState(s0Closure)
if !suppressEdge {
l.decisionToDFA[l.mode].setS0(next)
}
predict := l.execATN(input, next)
if LexerATNSimulatorDebug {
fmt.Println("DFA after MatchATN: " + l.decisionToDFA[oldMode].ToLexerString())
}
return predict
}
func (l *LexerATNSimulator) execATN(input CharStream, ds0 *DFAState) int {
if LexerATNSimulatorDebug {
fmt.Println("start state closure=" + ds0.configs.String())
}
if ds0.isAcceptState {
// allow zero-length tokens
l.captureSimState(l.prevAccept, input, ds0)
}
t := input.LA(1)
s := ds0 // s is current/from DFA state
for { // while more work
if LexerATNSimulatorDebug {
fmt.Println("execATN loop starting closure: " + s.configs.String())
}
// As we move src->trg, src->trg, we keep track of the previous trg to
// avoid looking up the DFA state again, which is expensive.
// If the previous target was already part of the DFA, we might
// be able to avoid doing a reach operation upon t. If s!=nil,
// it means that semantic predicates didn't prevent us from
// creating a DFA state. Once we know s!=nil, we check to see if
// the DFA state has an edge already for t. If so, we can just reuse
// it's configuration set there's no point in re-computing it.
// This is kind of like doing DFA simulation within the ATN
// simulation because DFA simulation is really just a way to avoid
// computing reach/closure sets. Technically, once we know that
// we have a previously added DFA state, we could jump over to
// the DFA simulator. But, that would mean popping back and forth
// a lot and making things more complicated algorithmically.
// This optimization makes a lot of sense for loops within DFA.
// A character will take us back to an existing DFA state
// that already has lots of edges out of it. e.g., .* in comments.
target := l.getExistingTargetState(s, t)
if target == nil {
target = l.computeTargetState(input, s, t)
// print("Computed:" + str(target))
}
if target == ATNSimulatorError {
break
}
// If l is a consumable input element, make sure to consume before
// capturing the accept state so the input index, line, and char
// position accurately reflect the state of the interpreter at the
// end of the token.
if t != TokenEOF {
l.Consume(input)
}
if target.isAcceptState {
l.captureSimState(l.prevAccept, input, target)
if t == TokenEOF {
break
}
}
t = input.LA(1)
s = target // flip current DFA target becomes Newsrc/from state
}
return l.failOrAccept(l.prevAccept, input, s.configs, t)
}
// Get an existing target state for an edge in the DFA. If the target state
// for the edge has not yet been computed or is otherwise not available,
// l method returns {@code nil}.
//
// @param s The current DFA state
// @param t The next input symbol
// @return The existing target DFA state for the given input symbol
// {@code t}, or {@code nil} if the target state for l edge is not
// already cached
func (l *LexerATNSimulator) getExistingTargetState(s *DFAState, t int) *DFAState {
if s.getEdges() == nil || t < LexerATNSimulatorMinDFAEdge || t > LexerATNSimulatorMaxDFAEdge {
return nil
}
target := s.getIthEdge(t-LexerATNSimulatorMinDFAEdge)
if LexerATNSimulatorDebug && target != nil {
fmt.Println("reuse state " + strconv.Itoa(s.stateNumber) + " edge to " + strconv.Itoa(target.stateNumber))
}
return target
}
// Compute a target state for an edge in the DFA, and attempt to add the
// computed state and corresponding edge to the DFA.
//
// @param input The input stream
// @param s The current DFA state
// @param t The next input symbol
//
// @return The computed target DFA state for the given input symbol
// {@code t}. If {@code t} does not lead to a valid DFA state, l method
// returns {@link //ERROR}.
func (l *LexerATNSimulator) computeTargetState(input CharStream, s *DFAState, t int) *DFAState {
reach := NewOrderedATNConfigSet()
// if we don't find an existing DFA state
// Fill reach starting from closure, following t transitions
l.getReachableConfigSet(input, s.configs, reach.BaseATNConfigSet, t)
if len(reach.configs) == 0 { // we got nowhere on t from s
if !reach.hasSemanticContext {
// we got nowhere on t, don't panic out l knowledge it'd
// cause a failover from DFA later.
l.addDFAEdge(s, t, ATNSimulatorError, nil)
}
// stop when we can't Match any more char
return ATNSimulatorError
}
// Add an edge from s to target DFA found/created for reach
return l.addDFAEdge(s, t, nil, reach.BaseATNConfigSet)
}
func (l *LexerATNSimulator) failOrAccept(prevAccept *SimState, input CharStream, reach ATNConfigSet, t int) int {
if l.prevAccept.dfaState != nil {
lexerActionExecutor := prevAccept.dfaState.lexerActionExecutor
l.accept(input, lexerActionExecutor, l.startIndex, prevAccept.index, prevAccept.line, prevAccept.column)
return prevAccept.dfaState.prediction
}
// if no accept and EOF is first char, return EOF
if t == TokenEOF && input.Index() == l.startIndex {
return TokenEOF
}
panic(NewLexerNoViableAltException(l.recog, input, l.startIndex, reach))
}
// Given a starting configuration set, figure out all ATN configurations
// we can reach upon input {@code t}. Parameter {@code reach} is a return
// parameter.
func (l *LexerATNSimulator) getReachableConfigSet(input CharStream, closure ATNConfigSet, reach ATNConfigSet, t int) {
// l is used to Skip processing for configs which have a lower priority
// than a config that already reached an accept state for the same rule
SkipAlt := ATNInvalidAltNumber
for _, cfg := range closure.GetItems() {
currentAltReachedAcceptState := (cfg.GetAlt() == SkipAlt)
if currentAltReachedAcceptState && cfg.(*LexerATNConfig).passedThroughNonGreedyDecision {
continue
}
if LexerATNSimulatorDebug {
fmt.Printf("testing %s at %s\n", l.GetTokenName(t), cfg.String()) // l.recog, true))
}
for _, trans := range cfg.GetState().GetTransitions() {
target := l.getReachableTarget(trans, t)
if target != nil {
lexerActionExecutor := cfg.(*LexerATNConfig).lexerActionExecutor
if lexerActionExecutor != nil {
lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.Index() - l.startIndex)
}
treatEOFAsEpsilon := (t == TokenEOF)
config := NewLexerATNConfig3(cfg.(*LexerATNConfig), target, lexerActionExecutor)
if l.closure(input, config, reach,
currentAltReachedAcceptState, true, treatEOFAsEpsilon) {
// any remaining configs for l alt have a lower priority
// than the one that just reached an accept state.
SkipAlt = cfg.GetAlt()
}
}
}
}
}
func (l *LexerATNSimulator) accept(input CharStream, lexerActionExecutor *LexerActionExecutor, startIndex, index, line, charPos int) {
if LexerATNSimulatorDebug {
fmt.Printf("ACTION %s\n", lexerActionExecutor)
}
// seek to after last char in token
input.Seek(index)
l.Line = line
l.CharPositionInLine = charPos
if lexerActionExecutor != nil && l.recog != nil {
lexerActionExecutor.execute(l.recog, input, startIndex)
}
}
func (l *LexerATNSimulator) getReachableTarget(trans Transition, t int) ATNState {
if trans.Matches(t, 0, LexerMaxCharValue) {
return trans.getTarget()
}
return nil
}
func (l *LexerATNSimulator) computeStartState(input CharStream, p ATNState) *OrderedATNConfigSet {
configs := NewOrderedATNConfigSet()
for i := 0; i < len(p.GetTransitions()); i++ {
target := p.GetTransitions()[i].getTarget()
cfg := NewLexerATNConfig6(target, i+1, BasePredictionContextEMPTY)
l.closure(input, cfg, configs, false, false, false)
}
return configs
}
// Since the alternatives within any lexer decision are ordered by
// preference, l method stops pursuing the closure as soon as an accept
// state is reached. After the first accept state is reached by depth-first
// search from {@code config}, all other (potentially reachable) states for
// l rule would have a lower priority.
//
// @return {@code true} if an accept state is reached, otherwise
// {@code false}.
func (l *LexerATNSimulator) closure(input CharStream, config *LexerATNConfig, configs ATNConfigSet,
currentAltReachedAcceptState, speculative, treatEOFAsEpsilon bool) bool {
if LexerATNSimulatorDebug {
fmt.Println("closure(" + config.String() + ")") // config.String(l.recog, true) + ")")
}
_, ok := config.state.(*RuleStopState)
if ok {
if LexerATNSimulatorDebug {
if l.recog != nil {
fmt.Printf("closure at %s rule stop %s\n", l.recog.GetRuleNames()[config.state.GetRuleIndex()], config)
} else {
fmt.Printf("closure at rule stop %s\n", config)
}
}
if config.context == nil || config.context.hasEmptyPath() {
if config.context == nil || config.context.isEmpty() {
configs.Add(config, nil)
return true
}
configs.Add(NewLexerATNConfig2(config, config.state, BasePredictionContextEMPTY), nil)
currentAltReachedAcceptState = true
}
if config.context != nil && !config.context.isEmpty() {
for i := 0; i < config.context.length(); i++ {
if config.context.getReturnState(i) != BasePredictionContextEmptyReturnState {
newContext := config.context.GetParent(i) // "pop" return state
returnState := l.atn.states[config.context.getReturnState(i)]
cfg := NewLexerATNConfig2(config, returnState, newContext)
currentAltReachedAcceptState = l.closure(input, cfg, configs, currentAltReachedAcceptState, speculative, treatEOFAsEpsilon)
}
}
}
return currentAltReachedAcceptState
}
// optimization
if !config.state.GetEpsilonOnlyTransitions() {
if !currentAltReachedAcceptState || !config.passedThroughNonGreedyDecision {
configs.Add(config, nil)
}
}
for j := 0; j < len(config.state.GetTransitions()); j++ {
trans := config.state.GetTransitions()[j]
cfg := l.getEpsilonTarget(input, config, trans, configs, speculative, treatEOFAsEpsilon)
if cfg != nil {
currentAltReachedAcceptState = l.closure(input, cfg, configs,
currentAltReachedAcceptState, speculative, treatEOFAsEpsilon)
}
}
return currentAltReachedAcceptState
}
// side-effect: can alter configs.hasSemanticContext
func (l *LexerATNSimulator) getEpsilonTarget(input CharStream, config *LexerATNConfig, trans Transition,
configs ATNConfigSet, speculative, treatEOFAsEpsilon bool) *LexerATNConfig {
var cfg *LexerATNConfig
if trans.getSerializationType() == TransitionRULE {
rt := trans.(*RuleTransition)
newContext := SingletonBasePredictionContextCreate(config.context, rt.followState.GetStateNumber())
cfg = NewLexerATNConfig2(config, trans.getTarget(), newContext)
} else if trans.getSerializationType() == TransitionPRECEDENCE {
panic("Precedence predicates are not supported in lexers.")
} else if trans.getSerializationType() == TransitionPREDICATE {
// Track traversing semantic predicates. If we traverse,
// we cannot add a DFA state for l "reach" computation
// because the DFA would not test the predicate again in the
// future. Rather than creating collections of semantic predicates
// like v3 and testing them on prediction, v4 will test them on the
// fly all the time using the ATN not the DFA. This is slower but
// semantically it's not used that often. One of the key elements to
// l predicate mechanism is not adding DFA states that see
// predicates immediately afterwards in the ATN. For example,
// a : ID {p1}? | ID {p2}?
// should create the start state for rule 'a' (to save start state
// competition), but should not create target of ID state. The
// collection of ATN states the following ID references includes
// states reached by traversing predicates. Since l is when we
// test them, we cannot cash the DFA state target of ID.
pt := trans.(*PredicateTransition)
if LexerATNSimulatorDebug {
fmt.Println("EVAL rule " + strconv.Itoa(trans.(*PredicateTransition).ruleIndex) + ":" + strconv.Itoa(pt.predIndex))
}
configs.SetHasSemanticContext(true)
if l.evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative) {
cfg = NewLexerATNConfig4(config, trans.getTarget())
}
} else if trans.getSerializationType() == TransitionACTION {
if config.context == nil || config.context.hasEmptyPath() {
// execute actions anywhere in the start rule for a token.
//
// TODO: if the entry rule is invoked recursively, some
// actions may be executed during the recursive call. The
// problem can appear when hasEmptyPath() is true but
// isEmpty() is false. In l case, the config needs to be
// split into two contexts - one with just the empty path
// and another with everything but the empty path.
// Unfortunately, the current algorithm does not allow
// getEpsilonTarget to return two configurations, so
// additional modifications are needed before we can support
// the split operation.
lexerActionExecutor := LexerActionExecutorappend(config.lexerActionExecutor, l.atn.lexerActions[trans.(*ActionTransition).actionIndex])
cfg = NewLexerATNConfig3(config, trans.getTarget(), lexerActionExecutor)
} else {
// ignore actions in referenced rules
cfg = NewLexerATNConfig4(config, trans.getTarget())
}
} else if trans.getSerializationType() == TransitionEPSILON {
cfg = NewLexerATNConfig4(config, trans.getTarget())
} else if trans.getSerializationType() == TransitionATOM ||
trans.getSerializationType() == TransitionRANGE ||
trans.getSerializationType() == TransitionSET {
if treatEOFAsEpsilon {
if trans.Matches(TokenEOF, 0, LexerMaxCharValue) {
cfg = NewLexerATNConfig4(config, trans.getTarget())
}
}
}
return cfg
}
// Evaluate a predicate specified in the lexer.
//
// <p>If {@code speculative} is {@code true}, l method was called before
// {@link //consume} for the Matched character. This method should call
// {@link //consume} before evaluating the predicate to ensure position
// sensitive values, including {@link Lexer//GetText}, {@link Lexer//GetLine},
// and {@link Lexer//getcolumn}, properly reflect the current
// lexer state. This method should restore {@code input} and the simulator
// to the original state before returning (i.e. undo the actions made by the
// call to {@link //consume}.</p>
//
// @param input The input stream.
// @param ruleIndex The rule containing the predicate.
// @param predIndex The index of the predicate within the rule.
// @param speculative {@code true} if the current index in {@code input} is
// one character before the predicate's location.
//
// @return {@code true} if the specified predicate evaluates to
// {@code true}.
// /
func (l *LexerATNSimulator) evaluatePredicate(input CharStream, ruleIndex, predIndex int, speculative bool) bool {
// assume true if no recognizer was provided
if l.recog == nil {
return true
}
if !speculative {
return l.recog.Sempred(nil, ruleIndex, predIndex)
}
savedcolumn := l.CharPositionInLine
savedLine := l.Line
index := input.Index()
marker := input.Mark()
defer func() {
l.CharPositionInLine = savedcolumn
l.Line = savedLine
input.Seek(index)
input.Release(marker)
}()
l.Consume(input)
return l.recog.Sempred(nil, ruleIndex, predIndex)
}
func (l *LexerATNSimulator) captureSimState(settings *SimState, input CharStream, dfaState *DFAState) {
settings.index = input.Index()
settings.line = l.Line
settings.column = l.CharPositionInLine
settings.dfaState = dfaState
}
func (l *LexerATNSimulator) addDFAEdge(from *DFAState, tk int, to *DFAState, cfgs ATNConfigSet) *DFAState {
if to == nil && cfgs != nil {
// leading to l call, ATNConfigSet.hasSemanticContext is used as a
// marker indicating dynamic predicate evaluation makes l edge
// dependent on the specific input sequence, so the static edge in the
// DFA should be omitted. The target DFAState is still created since
// execATN has the ability to reSynchronize with the DFA state cache
// following the predicate evaluation step.
//
// TJP notes: next time through the DFA, we see a pred again and eval.
// If that gets us to a previously created (but dangling) DFA
// state, we can continue in pure DFA mode from there.
// /
suppressEdge := cfgs.HasSemanticContext()
cfgs.SetHasSemanticContext(false)
to = l.addDFAState(cfgs)
if suppressEdge {
return to
}
}
// add the edge
if tk < LexerATNSimulatorMinDFAEdge || tk > LexerATNSimulatorMaxDFAEdge {
// Only track edges within the DFA bounds
return to
}
if LexerATNSimulatorDebug {
fmt.Println("EDGE " + from.String() + " -> " + to.String() + " upon " + strconv.Itoa(tk))
}
if from.getEdges() == nil {
// make room for tokens 1..n and -1 masquerading as index 0
from.setEdges(make([]*DFAState, LexerATNSimulatorMaxDFAEdge-LexerATNSimulatorMinDFAEdge+1))
}
from.setIthEdge(tk-LexerATNSimulatorMinDFAEdge, to) // connect
return to
}
// Add a NewDFA state if there isn't one with l set of
// configurations already. This method also detects the first
// configuration containing an ATN rule stop state. Later, when
// traversing the DFA, we will know which rule to accept.
func (l *LexerATNSimulator) addDFAState(configs ATNConfigSet) *DFAState {
proposed := NewDFAState(-1, configs)
var firstConfigWithRuleStopState ATNConfig
for _, cfg := range configs.GetItems() {
_, ok := cfg.GetState().(*RuleStopState)
if ok {
firstConfigWithRuleStopState = cfg
break
}
}
if firstConfigWithRuleStopState != nil {
proposed.isAcceptState = true
proposed.lexerActionExecutor = firstConfigWithRuleStopState.(*LexerATNConfig).lexerActionExecutor
proposed.setPrediction(l.atn.ruleToTokenType[firstConfigWithRuleStopState.GetState().GetRuleIndex()])
}
hash := proposed.hash()
dfa := l.decisionToDFA[l.mode]
existing, ok := dfa.getState(hash)
if ok {
return existing
}
newState := proposed
newState.stateNumber = dfa.numStates()
configs.SetReadOnly(true)
newState.configs = configs
dfa.setState(hash, newState)
return newState
}
func (l *LexerATNSimulator) getDFA(mode int) *DFA {
return l.decisionToDFA[mode]
}
// Get the text Matched so far for the current token.
func (l *LexerATNSimulator) GetText(input CharStream) string {
// index is first lookahead char, don't include.
return input.GetTextFromInterval(NewInterval(l.startIndex, input.Index()-1))
}
func (l *LexerATNSimulator) Consume(input CharStream) {
curChar := input.LA(1)
if curChar == int('\n') {
l.Line++
l.CharPositionInLine = 0
} else {
l.CharPositionInLine++
}
input.Consume()
}
func (l *LexerATNSimulator) GetCharPositionInLine() int {
return l.CharPositionInLine
}
func (l *LexerATNSimulator) GetLine() int {
return l.Line
}
func (l *LexerATNSimulator) GetTokenName(tt int) string {
if tt == -1 {
return "EOF"
}
return "'" + string(tt) + "'"
}
func resetSimState(sim *SimState) {
sim.index = -1
sim.line = 0
sim.column = -1
sim.dfaState = nil
}
type SimState struct {
index int
line int
column int
dfaState *DFAState
}
func NewSimState() *SimState {
s := new(SimState)
resetSimState(s)
return s
}
func (s *SimState) reset() {
resetSimState(s)
}

View File

@@ -0,0 +1,212 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type LL1Analyzer struct {
atn *ATN
}
func NewLL1Analyzer(atn *ATN) *LL1Analyzer {
la := new(LL1Analyzer)
la.atn = atn
return la
}
//* Special value added to the lookahead sets to indicate that we hit
// a predicate during analysis if {@code seeThruPreds==false}.
///
const (
LL1AnalyzerHitPred = TokenInvalidType
)
//*
// Calculates the SLL(1) expected lookahead set for each outgoing transition
// of an {@link ATNState}. The returned array has one element for each
// outgoing transition in {@code s}. If the closure from transition
// <em>i</em> leads to a semantic predicate before Matching a symbol, the
// element at index <em>i</em> of the result will be {@code nil}.
//
// @param s the ATN state
// @return the expected symbols for each outgoing transition of {@code s}.
func (la *LL1Analyzer) getDecisionLookahead(s ATNState) []*IntervalSet {
if s == nil {
return nil
}
count := len(s.GetTransitions())
look := make([]*IntervalSet, count)
for alt := 0; alt < count; alt++ {
look[alt] = NewIntervalSet()
lookBusy := NewSet(nil, nil)
seeThruPreds := false // fail to get lookahead upon pred
la.look1(s.GetTransitions()[alt].getTarget(), nil, BasePredictionContextEMPTY, look[alt], lookBusy, NewBitSet(), seeThruPreds, false)
// Wipe out lookahead for la alternative if we found nothing
// or we had a predicate when we !seeThruPreds
if look[alt].length() == 0 || look[alt].contains(LL1AnalyzerHitPred) {
look[alt] = nil
}
}
return look
}
//*
// Compute set of tokens that can follow {@code s} in the ATN in the
// specified {@code ctx}.
//
// <p>If {@code ctx} is {@code nil} and the end of the rule containing
// {@code s} is reached, {@link Token//EPSILON} is added to the result set.
// If {@code ctx} is not {@code nil} and the end of the outermost rule is
// reached, {@link Token//EOF} is added to the result set.</p>
//
// @param s the ATN state
// @param stopState the ATN state to stop at. This can be a
// {@link BlockEndState} to detect epsilon paths through a closure.
// @param ctx the complete parser context, or {@code nil} if the context
// should be ignored
//
// @return The set of tokens that can follow {@code s} in the ATN in the
// specified {@code ctx}.
///
func (la *LL1Analyzer) Look(s, stopState ATNState, ctx RuleContext) *IntervalSet {
r := NewIntervalSet()
seeThruPreds := true // ignore preds get all lookahead
var lookContext PredictionContext
if ctx != nil {
lookContext = predictionContextFromRuleContext(s.GetATN(), ctx)
}
la.look1(s, stopState, lookContext, r, NewSet(nil, nil), NewBitSet(), seeThruPreds, true)
return r
}
//*
// Compute set of tokens that can follow {@code s} in the ATN in the
// specified {@code ctx}.
//
// <p>If {@code ctx} is {@code nil} and {@code stopState} or the end of the
// rule containing {@code s} is reached, {@link Token//EPSILON} is added to
// the result set. If {@code ctx} is not {@code nil} and {@code addEOF} is
// {@code true} and {@code stopState} or the end of the outermost rule is
// reached, {@link Token//EOF} is added to the result set.</p>
//
// @param s the ATN state.
// @param stopState the ATN state to stop at. This can be a
// {@link BlockEndState} to detect epsilon paths through a closure.
// @param ctx The outer context, or {@code nil} if the outer context should
// not be used.
// @param look The result lookahead set.
// @param lookBusy A set used for preventing epsilon closures in the ATN
// from causing a stack overflow. Outside code should pass
// {@code NewSet<ATNConfig>} for la argument.
// @param calledRuleStack A set used for preventing left recursion in the
// ATN from causing a stack overflow. Outside code should pass
// {@code NewBitSet()} for la argument.
// @param seeThruPreds {@code true} to true semantic predicates as
// implicitly {@code true} and "see through them", otherwise {@code false}
// to treat semantic predicates as opaque and add {@link //HitPred} to the
// result if one is encountered.
// @param addEOF Add {@link Token//EOF} to the result if the end of the
// outermost context is reached. This parameter has no effect if {@code ctx}
// is {@code nil}.
func (la *LL1Analyzer) look2(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, i int) {
returnState := la.atn.states[ctx.getReturnState(i)]
la.look1(returnState, stopState, ctx.GetParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
}
func (la *LL1Analyzer) look1(s, stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool) {
c := NewBaseATNConfig6(s, 0, ctx)
if lookBusy.contains(c) {
return
}
lookBusy.add(c)
if s == stopState {
if ctx == nil {
look.addOne(TokenEpsilon)
return
} else if ctx.isEmpty() && addEOF {
look.addOne(TokenEOF)
return
}
}
_, ok := s.(*RuleStopState)
if ok {
if ctx == nil {
look.addOne(TokenEpsilon)
return
} else if ctx.isEmpty() && addEOF {
look.addOne(TokenEOF)
return
}
if ctx != BasePredictionContextEMPTY {
removed := calledRuleStack.contains(s.GetRuleIndex())
defer func() {
if removed {
calledRuleStack.add(s.GetRuleIndex())
}
}()
calledRuleStack.remove(s.GetRuleIndex())
// run thru all possible stack tops in ctx
for i := 0; i < ctx.length(); i++ {
returnState := la.atn.states[ctx.getReturnState(i)]
la.look2(returnState, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF, i)
}
return
}
}
n := len(s.GetTransitions())
for i := 0; i < n; i++ {
t := s.GetTransitions()[i]
if t1, ok := t.(*RuleTransition); ok {
if calledRuleStack.contains(t1.getTarget().GetRuleIndex()) {
continue
}
newContext := SingletonBasePredictionContextCreate(ctx, t1.followState.GetStateNumber())
la.look3(stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF, t1)
} else if t2, ok := t.(AbstractPredicateTransition); ok {
if seeThruPreds {
la.look1(t2.getTarget(), stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
} else {
look.addOne(LL1AnalyzerHitPred)
}
} else if t.getIsEpsilon() {
la.look1(t.getTarget(), stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
} else if _, ok := t.(*WildcardTransition); ok {
look.addRange(TokenMinUserTokenType, la.atn.maxTokenType)
} else {
set := t.getLabel()
if set != nil {
if _, ok := t.(*NotSetTransition); ok {
set = set.complement(TokenMinUserTokenType, la.atn.maxTokenType)
}
look.addSet(set)
}
}
}
}
func (la *LL1Analyzer) look3(stopState ATNState, ctx PredictionContext, look *IntervalSet, lookBusy *Set, calledRuleStack *BitSet, seeThruPreds, addEOF bool, t1 *RuleTransition) {
newContext := SingletonBasePredictionContextCreate(ctx, t1.followState.GetStateNumber())
defer func() {
calledRuleStack.remove(t1.getTarget().GetRuleIndex())
}()
calledRuleStack.add(t1.getTarget().GetRuleIndex())
la.look1(t1.getTarget(), stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
}

View File

@@ -0,0 +1,718 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
type Parser interface {
Recognizer
GetInterpreter() *ParserATNSimulator
GetTokenStream() TokenStream
GetTokenFactory() TokenFactory
GetParserRuleContext() ParserRuleContext
SetParserRuleContext(ParserRuleContext)
Consume() Token
GetParseListeners() []ParseTreeListener
GetErrorHandler() ErrorStrategy
SetErrorHandler(ErrorStrategy)
GetInputStream() IntStream
GetCurrentToken() Token
GetExpectedTokens() *IntervalSet
NotifyErrorListeners(string, Token, RecognitionException)
IsExpectedToken(int) bool
GetPrecedence() int
GetRuleInvocationStack(ParserRuleContext) []string
}
type BaseParser struct {
*BaseRecognizer
Interpreter *ParserATNSimulator
BuildParseTrees bool
input TokenStream
errHandler ErrorStrategy
precedenceStack IntStack
ctx ParserRuleContext
tracer *TraceListener
parseListeners []ParseTreeListener
_SyntaxErrors int
}
// p.is all the parsing support code essentially most of it is error
// recovery stuff.//
func NewBaseParser(input TokenStream) *BaseParser {
p := new(BaseParser)
p.BaseRecognizer = NewBaseRecognizer()
// The input stream.
p.input = nil
// The error handling strategy for the parser. The default value is a new
// instance of {@link DefaultErrorStrategy}.
p.errHandler = NewDefaultErrorStrategy()
p.precedenceStack = make([]int, 0)
p.precedenceStack.Push(0)
// The {@link ParserRuleContext} object for the currently executing rule.
// p.is always non-nil during the parsing process.
p.ctx = nil
// Specifies whether or not the parser should construct a parse tree during
// the parsing process. The default value is {@code true}.
p.BuildParseTrees = true
// When {@link //setTrace}{@code (true)} is called, a reference to the
// {@link TraceListener} is stored here so it can be easily removed in a
// later call to {@link //setTrace}{@code (false)}. The listener itself is
// implemented as a parser listener so p.field is not directly used by
// other parser methods.
p.tracer = nil
// The list of {@link ParseTreeListener} listeners registered to receive
// events during the parse.
p.parseListeners = nil
// The number of syntax errors Reported during parsing. p.value is
// incremented each time {@link //NotifyErrorListeners} is called.
p._SyntaxErrors = 0
p.SetInputStream(input)
return p
}
// p.field maps from the serialized ATN string to the deserialized {@link
// ATN} with
// bypass alternatives.
//
// @see ATNDeserializationOptions//isGenerateRuleBypassTransitions()
//
var bypassAltsAtnCache = make(map[string]int)
// reset the parser's state//
func (p *BaseParser) reset() {
if p.input != nil {
p.input.Seek(0)
}
p.errHandler.reset(p)
p.ctx = nil
p._SyntaxErrors = 0
p.SetTrace(nil)
p.precedenceStack = make([]int, 0)
p.precedenceStack.Push(0)
if p.Interpreter != nil {
p.Interpreter.reset()
}
}
func (p *BaseParser) GetErrorHandler() ErrorStrategy {
return p.errHandler
}
func (p *BaseParser) SetErrorHandler(e ErrorStrategy) {
p.errHandler = e
}
// Match current input symbol against {@code ttype}. If the symbol type
// Matches, {@link ANTLRErrorStrategy//ReportMatch} and {@link //consume} are
// called to complete the Match process.
//
// <p>If the symbol type does not Match,
// {@link ANTLRErrorStrategy//recoverInline} is called on the current error
// strategy to attempt recovery. If {@link //getBuildParseTree} is
// {@code true} and the token index of the symbol returned by
// {@link ANTLRErrorStrategy//recoverInline} is -1, the symbol is added to
// the parse tree by calling {@link ParserRuleContext//addErrorNode}.</p>
//
// @param ttype the token type to Match
// @return the Matched symbol
// @panics RecognitionException if the current input symbol did not Match
// {@code ttype} and the error strategy could not recover from the
// mismatched symbol
func (p *BaseParser) Match(ttype int) Token {
t := p.GetCurrentToken()
if t.GetTokenType() == ttype {
p.errHandler.ReportMatch(p)
p.Consume()
} else {
t = p.errHandler.RecoverInline(p)
if p.BuildParseTrees && t.GetTokenIndex() == -1 {
// we must have conjured up a Newtoken during single token
// insertion
// if it's not the current symbol
p.ctx.AddErrorNode(t)
}
}
return t
}
// Match current input symbol as a wildcard. If the symbol type Matches
// (i.e. has a value greater than 0), {@link ANTLRErrorStrategy//ReportMatch}
// and {@link //consume} are called to complete the Match process.
//
// <p>If the symbol type does not Match,
// {@link ANTLRErrorStrategy//recoverInline} is called on the current error
// strategy to attempt recovery. If {@link //getBuildParseTree} is
// {@code true} and the token index of the symbol returned by
// {@link ANTLRErrorStrategy//recoverInline} is -1, the symbol is added to
// the parse tree by calling {@link ParserRuleContext//addErrorNode}.</p>
//
// @return the Matched symbol
// @panics RecognitionException if the current input symbol did not Match
// a wildcard and the error strategy could not recover from the mismatched
// symbol
func (p *BaseParser) MatchWildcard() Token {
t := p.GetCurrentToken()
if t.GetTokenType() > 0 {
p.errHandler.ReportMatch(p)
p.Consume()
} else {
t = p.errHandler.RecoverInline(p)
if p.BuildParseTrees && t.GetTokenIndex() == -1 {
// we must have conjured up a Newtoken during single token
// insertion
// if it's not the current symbol
p.ctx.AddErrorNode(t)
}
}
return t
}
func (p *BaseParser) GetParserRuleContext() ParserRuleContext {
return p.ctx
}
func (p *BaseParser) SetParserRuleContext(v ParserRuleContext) {
p.ctx = v
}
func (p *BaseParser) GetParseListeners() []ParseTreeListener {
if p.parseListeners == nil {
return make([]ParseTreeListener, 0)
}
return p.parseListeners
}
// Registers {@code listener} to receive events during the parsing process.
//
// <p>To support output-preserving grammar transformations (including but not
// limited to left-recursion removal, automated left-factoring, and
// optimized code generation), calls to listener methods during the parse
// may differ substantially from calls made by
// {@link ParseTreeWalker//DEFAULT} used after the parse is complete. In
// particular, rule entry and exit events may occur in a different order
// during the parse than after the parser. In addition, calls to certain
// rule entry methods may be omitted.</p>
//
// <p>With the following specific exceptions, calls to listener events are
// <em>deterministic</em>, i.e. for identical input the calls to listener
// methods will be the same.</p>
//
// <ul>
// <li>Alterations to the grammar used to generate code may change the
// behavior of the listener calls.</li>
// <li>Alterations to the command line options passed to ANTLR 4 when
// generating the parser may change the behavior of the listener calls.</li>
// <li>Changing the version of the ANTLR Tool used to generate the parser
// may change the behavior of the listener calls.</li>
// </ul>
//
// @param listener the listener to add
//
// @panics nilPointerException if {@code} listener is {@code nil}
//
func (p *BaseParser) AddParseListener(listener ParseTreeListener) {
if listener == nil {
panic("listener")
}
if p.parseListeners == nil {
p.parseListeners = make([]ParseTreeListener, 0)
}
p.parseListeners = append(p.parseListeners, listener)
}
//
// Remove {@code listener} from the list of parse listeners.
//
// <p>If {@code listener} is {@code nil} or has not been added as a parse
// listener, p.method does nothing.</p>
// @param listener the listener to remove
//
func (p *BaseParser) RemoveParseListener(listener ParseTreeListener) {
if p.parseListeners != nil {
idx := -1
for i, v := range p.parseListeners {
if v == listener {
idx = i
break
}
}
if idx == -1 {
return
}
// remove the listener from the slice
p.parseListeners = append(p.parseListeners[0:idx], p.parseListeners[idx+1:]...)
if len(p.parseListeners) == 0 {
p.parseListeners = nil
}
}
}
// Remove all parse listeners.
func (p *BaseParser) removeParseListeners() {
p.parseListeners = nil
}
// Notify any parse listeners of an enter rule event.
func (p *BaseParser) TriggerEnterRuleEvent() {
if p.parseListeners != nil {
ctx := p.ctx
for _, listener := range p.parseListeners {
listener.EnterEveryRule(ctx)
ctx.EnterRule(listener)
}
}
}
//
// Notify any parse listeners of an exit rule event.
//
// @see //addParseListener
//
func (p *BaseParser) TriggerExitRuleEvent() {
if p.parseListeners != nil {
// reverse order walk of listeners
ctx := p.ctx
l := len(p.parseListeners) - 1
for i := range p.parseListeners {
listener := p.parseListeners[l-i]
ctx.ExitRule(listener)
listener.ExitEveryRule(ctx)
}
}
}
func (p *BaseParser) GetInterpreter() *ParserATNSimulator {
return p.Interpreter
}
func (p *BaseParser) GetATN() *ATN {
return p.Interpreter.atn
}
func (p *BaseParser) GetTokenFactory() TokenFactory {
return p.input.GetTokenSource().GetTokenFactory()
}
// Tell our token source and error strategy about a Newway to create tokens.//
func (p *BaseParser) setTokenFactory(factory TokenFactory) {
p.input.GetTokenSource().setTokenFactory(factory)
}
// The ATN with bypass alternatives is expensive to create so we create it
// lazily.
//
// @panics UnsupportedOperationException if the current parser does not
// implement the {@link //getSerializedATN()} method.
//
func (p *BaseParser) GetATNWithBypassAlts() {
// TODO
panic("Not implemented!")
// serializedAtn := p.getSerializedATN()
// if (serializedAtn == nil) {
// panic("The current parser does not support an ATN with bypass alternatives.")
// }
// result := p.bypassAltsAtnCache[serializedAtn]
// if (result == nil) {
// deserializationOptions := NewATNDeserializationOptions(nil)
// deserializationOptions.generateRuleBypassTransitions = true
// result = NewATNDeserializer(deserializationOptions).deserialize(serializedAtn)
// p.bypassAltsAtnCache[serializedAtn] = result
// }
// return result
}
// The preferred method of getting a tree pattern. For example, here's a
// sample use:
//
// <pre>
// ParseTree t = parser.expr()
// ParseTreePattern p = parser.compileParseTreePattern("&ltID&gt+0",
// MyParser.RULE_expr)
// ParseTreeMatch m = p.Match(t)
// String id = m.Get("ID")
// </pre>
func (p *BaseParser) compileParseTreePattern(pattern, patternRuleIndex, lexer Lexer) {
panic("NewParseTreePatternMatcher not implemented!")
//
// if (lexer == nil) {
// if (p.GetTokenStream() != nil) {
// tokenSource := p.GetTokenStream().GetTokenSource()
// if _, ok := tokenSource.(ILexer); ok {
// lexer = tokenSource
// }
// }
// }
// if (lexer == nil) {
// panic("Parser can't discover a lexer to use")
// }
// m := NewParseTreePatternMatcher(lexer, p)
// return m.compile(pattern, patternRuleIndex)
}
func (p *BaseParser) GetInputStream() IntStream {
return p.GetTokenStream()
}
func (p *BaseParser) SetInputStream(input TokenStream) {
p.SetTokenStream(input)
}
func (p *BaseParser) GetTokenStream() TokenStream {
return p.input
}
// Set the token stream and reset the parser.//
func (p *BaseParser) SetTokenStream(input TokenStream) {
p.input = nil
p.reset()
p.input = input
}
// Match needs to return the current input symbol, which gets put
// into the label for the associated token ref e.g., x=ID.
//
func (p *BaseParser) GetCurrentToken() Token {
return p.input.LT(1)
}
func (p *BaseParser) NotifyErrorListeners(msg string, offendingToken Token, err RecognitionException) {
if offendingToken == nil {
offendingToken = p.GetCurrentToken()
}
p._SyntaxErrors++
line := offendingToken.GetLine()
column := offendingToken.GetColumn()
listener := p.GetErrorListenerDispatch()
listener.SyntaxError(p, offendingToken, line, column, msg, err)
}
func (p *BaseParser) Consume() Token {
o := p.GetCurrentToken()
if o.GetTokenType() != TokenEOF {
p.GetInputStream().Consume()
}
hasListener := p.parseListeners != nil && len(p.parseListeners) > 0
if p.BuildParseTrees || hasListener {
if p.errHandler.inErrorRecoveryMode(p) {
node := p.ctx.AddErrorNode(o)
if p.parseListeners != nil {
for _, l := range p.parseListeners {
l.VisitErrorNode(node)
}
}
} else {
node := p.ctx.AddTokenNode(o)
if p.parseListeners != nil {
for _, l := range p.parseListeners {
l.VisitTerminal(node)
}
}
}
// node.invokingState = p.state
}
return o
}
func (p *BaseParser) addContextToParseTree() {
// add current context to parent if we have a parent
if p.ctx.GetParent() != nil {
p.ctx.GetParent().(ParserRuleContext).AddChild(p.ctx)
}
}
func (p *BaseParser) EnterRule(localctx ParserRuleContext, state, ruleIndex int) {
p.SetState(state)
p.ctx = localctx
p.ctx.SetStart(p.input.LT(1))
if p.BuildParseTrees {
p.addContextToParseTree()
}
if p.parseListeners != nil {
p.TriggerEnterRuleEvent()
}
}
func (p *BaseParser) ExitRule() {
p.ctx.SetStop(p.input.LT(-1))
// trigger event on ctx, before it reverts to parent
if p.parseListeners != nil {
p.TriggerExitRuleEvent()
}
p.SetState(p.ctx.GetInvokingState())
if p.ctx.GetParent() != nil {
p.ctx = p.ctx.GetParent().(ParserRuleContext)
} else {
p.ctx = nil
}
}
func (p *BaseParser) EnterOuterAlt(localctx ParserRuleContext, altNum int) {
localctx.SetAltNumber(altNum)
// if we have Newlocalctx, make sure we replace existing ctx
// that is previous child of parse tree
if p.BuildParseTrees && p.ctx != localctx {
if p.ctx.GetParent() != nil {
p.ctx.GetParent().(ParserRuleContext).RemoveLastChild()
p.ctx.GetParent().(ParserRuleContext).AddChild(localctx)
}
}
p.ctx = localctx
}
// Get the precedence level for the top-most precedence rule.
//
// @return The precedence level for the top-most precedence rule, or -1 if
// the parser context is not nested within a precedence rule.
func (p *BaseParser) GetPrecedence() int {
if len(p.precedenceStack) == 0 {
return -1
}
return p.precedenceStack[len(p.precedenceStack)-1]
}
func (p *BaseParser) EnterRecursionRule(localctx ParserRuleContext, state, ruleIndex, precedence int) {
p.SetState(state)
p.precedenceStack.Push(precedence)
p.ctx = localctx
p.ctx.SetStart(p.input.LT(1))
if p.parseListeners != nil {
p.TriggerEnterRuleEvent() // simulates rule entry for
// left-recursive rules
}
}
//
// Like {@link //EnterRule} but for recursive rules.
func (p *BaseParser) PushNewRecursionContext(localctx ParserRuleContext, state, ruleIndex int) {
previous := p.ctx
previous.SetParent(localctx)
previous.SetInvokingState(state)
previous.SetStop(p.input.LT(-1))
p.ctx = localctx
p.ctx.SetStart(previous.GetStart())
if p.BuildParseTrees {
p.ctx.AddChild(previous)
}
if p.parseListeners != nil {
p.TriggerEnterRuleEvent() // simulates rule entry for
// left-recursive rules
}
}
func (p *BaseParser) UnrollRecursionContexts(parentCtx ParserRuleContext) {
p.precedenceStack.Pop()
p.ctx.SetStop(p.input.LT(-1))
retCtx := p.ctx // save current ctx (return value)
// unroll so ctx is as it was before call to recursive method
if p.parseListeners != nil {
for p.ctx != parentCtx {
p.TriggerExitRuleEvent()
p.ctx = p.ctx.GetParent().(ParserRuleContext)
}
} else {
p.ctx = parentCtx
}
// hook into tree
retCtx.SetParent(parentCtx)
if p.BuildParseTrees && parentCtx != nil {
// add return ctx into invoking rule's tree
parentCtx.AddChild(retCtx)
}
}
func (p *BaseParser) GetInvokingContext(ruleIndex int) ParserRuleContext {
ctx := p.ctx
for ctx != nil {
if ctx.GetRuleIndex() == ruleIndex {
return ctx
}
ctx = ctx.GetParent().(ParserRuleContext)
}
return nil
}
func (p *BaseParser) Precpred(localctx RuleContext, precedence int) bool {
return precedence >= p.precedenceStack[len(p.precedenceStack)-1]
}
func (p *BaseParser) inContext(context ParserRuleContext) bool {
// TODO: useful in parser?
return false
}
//
// Checks whether or not {@code symbol} can follow the current state in the
// ATN. The behavior of p.method is equivalent to the following, but is
// implemented such that the complete context-sensitive follow set does not
// need to be explicitly constructed.
//
// <pre>
// return getExpectedTokens().contains(symbol)
// </pre>
//
// @param symbol the symbol type to check
// @return {@code true} if {@code symbol} can follow the current state in
// the ATN, otherwise {@code false}.
func (p *BaseParser) IsExpectedToken(symbol int) bool {
atn := p.Interpreter.atn
ctx := p.ctx
s := atn.states[p.state]
following := atn.NextTokens(s, nil)
if following.contains(symbol) {
return true
}
if !following.contains(TokenEpsilon) {
return false
}
for ctx != nil && ctx.GetInvokingState() >= 0 && following.contains(TokenEpsilon) {
invokingState := atn.states[ctx.GetInvokingState()]
rt := invokingState.GetTransitions()[0]
following = atn.NextTokens(rt.(*RuleTransition).followState, nil)
if following.contains(symbol) {
return true
}
ctx = ctx.GetParent().(ParserRuleContext)
}
if following.contains(TokenEpsilon) && symbol == TokenEOF {
return true
}
return false
}
// Computes the set of input symbols which could follow the current parser
// state and context, as given by {@link //GetState} and {@link //GetContext},
// respectively.
//
// @see ATN//getExpectedTokens(int, RuleContext)
//
func (p *BaseParser) GetExpectedTokens() *IntervalSet {
return p.Interpreter.atn.getExpectedTokens(p.state, p.ctx)
}
func (p *BaseParser) GetExpectedTokensWithinCurrentRule() *IntervalSet {
atn := p.Interpreter.atn
s := atn.states[p.state]
return atn.NextTokens(s, nil)
}
// Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found.//
func (p *BaseParser) GetRuleIndex(ruleName string) int {
var ruleIndex, ok = p.GetRuleIndexMap()[ruleName]
if ok {
return ruleIndex
}
return -1
}
// Return List&ltString&gt of the rule names in your parser instance
// leading up to a call to the current rule. You could override if
// you want more details such as the file/line info of where
// in the ATN a rule is invoked.
//
// this very useful for error messages.
func (p *BaseParser) GetRuleInvocationStack(c ParserRuleContext) []string {
if c == nil {
c = p.ctx
}
stack := make([]string, 0)
for c != nil {
// compute what follows who invoked us
ruleIndex := c.GetRuleIndex()
if ruleIndex < 0 {
stack = append(stack, "n/a")
} else {
stack = append(stack, p.GetRuleNames()[ruleIndex])
}
vp := c.GetParent()
if vp == nil {
break
}
c = vp.(ParserRuleContext)
}
return stack
}
// For debugging and other purposes.//
func (p *BaseParser) GetDFAStrings() string {
return fmt.Sprint(p.Interpreter.decisionToDFA)
}
// For debugging and other purposes.//
func (p *BaseParser) DumpDFA() {
seenOne := false
for _, dfa := range p.Interpreter.decisionToDFA {
if dfa.numStates() > 0 {
if seenOne {
fmt.Println()
}
fmt.Println("Decision " + strconv.Itoa(dfa.decision) + ":")
fmt.Print(dfa.String(p.LiteralNames, p.SymbolicNames))
seenOne = true
}
}
}
func (p *BaseParser) GetSourceName() string {
return p.GrammarFileName
}
// During a parse is sometimes useful to listen in on the rule entry and exit
// events as well as token Matches. p.is for quick and dirty debugging.
//
func (p *BaseParser) SetTrace(trace *TraceListener) {
if trace == nil {
p.RemoveParseListener(p.tracer)
p.tracer = nil
} else {
if p.tracer != nil {
p.RemoveParseListener(p.tracer)
}
p.tracer = NewTraceListener(p)
p.AddParseListener(p.tracer)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,362 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"reflect"
"strconv"
)
type ParserRuleContext interface {
RuleContext
SetException(RecognitionException)
AddTokenNode(token Token) *TerminalNodeImpl
AddErrorNode(badToken Token) *ErrorNodeImpl
EnterRule(listener ParseTreeListener)
ExitRule(listener ParseTreeListener)
SetStart(Token)
GetStart() Token
SetStop(Token)
GetStop() Token
AddChild(child RuleContext) RuleContext
RemoveLastChild()
}
type BaseParserRuleContext struct {
*BaseRuleContext
start, stop Token
exception RecognitionException
children []Tree
}
func NewBaseParserRuleContext(parent ParserRuleContext, invokingStateNumber int) *BaseParserRuleContext {
prc := new(BaseParserRuleContext)
prc.BaseRuleContext = NewBaseRuleContext(parent, invokingStateNumber)
prc.RuleIndex = -1
// * If we are debugging or building a parse tree for a Visitor,
// we need to track all of the tokens and rule invocations associated
// with prc rule's context. This is empty for parsing w/o tree constr.
// operation because we don't the need to track the details about
// how we parse prc rule.
// /
prc.children = nil
prc.start = nil
prc.stop = nil
// The exception that forced prc rule to return. If the rule successfully
// completed, prc is {@code nil}.
prc.exception = nil
return prc
}
func (prc *BaseParserRuleContext) SetException(e RecognitionException) {
prc.exception = e
}
func (prc *BaseParserRuleContext) GetChildren() []Tree {
return prc.children
}
func (prc *BaseParserRuleContext) CopyFrom(ctx *BaseParserRuleContext) {
// from RuleContext
prc.parentCtx = ctx.parentCtx
prc.invokingState = ctx.invokingState
prc.children = nil
prc.start = ctx.start
prc.stop = ctx.stop
}
func (prc *BaseParserRuleContext) GetText() string {
if prc.GetChildCount() == 0 {
return ""
}
var s string
for _, child := range prc.children {
s += child.(ParseTree).GetText()
}
return s
}
// Double dispatch methods for listeners
func (prc *BaseParserRuleContext) EnterRule(listener ParseTreeListener) {
}
func (prc *BaseParserRuleContext) ExitRule(listener ParseTreeListener) {
}
// * Does not set parent link other add methods do that///
func (prc *BaseParserRuleContext) addTerminalNodeChild(child TerminalNode) TerminalNode {
if prc.children == nil {
prc.children = make([]Tree, 0)
}
if child == nil {
panic("Child may not be null")
}
prc.children = append(prc.children, child)
return child
}
func (prc *BaseParserRuleContext) AddChild(child RuleContext) RuleContext {
if prc.children == nil {
prc.children = make([]Tree, 0)
}
if child == nil {
panic("Child may not be null")
}
prc.children = append(prc.children, child)
return child
}
// * Used by EnterOuterAlt to toss out a RuleContext previously added as
// we entered a rule. If we have // label, we will need to remove
// generic ruleContext object.
// /
func (prc *BaseParserRuleContext) RemoveLastChild() {
if prc.children != nil && len(prc.children) > 0 {
prc.children = prc.children[0 : len(prc.children)-1]
}
}
func (prc *BaseParserRuleContext) AddTokenNode(token Token) *TerminalNodeImpl {
node := NewTerminalNodeImpl(token)
prc.addTerminalNodeChild(node)
node.parentCtx = prc
return node
}
func (prc *BaseParserRuleContext) AddErrorNode(badToken Token) *ErrorNodeImpl {
node := NewErrorNodeImpl(badToken)
prc.addTerminalNodeChild(node)
node.parentCtx = prc
return node
}
func (prc *BaseParserRuleContext) GetChild(i int) Tree {
if prc.children != nil && len(prc.children) >= i {
return prc.children[i]
}
return nil
}
func (prc *BaseParserRuleContext) GetChildOfType(i int, childType reflect.Type) RuleContext {
if childType == nil {
return prc.GetChild(i).(RuleContext)
}
for j := 0; j < len(prc.children); j++ {
child := prc.children[j]
if reflect.TypeOf(child) == childType {
if i == 0 {
return child.(RuleContext)
}
i--
}
}
return nil
}
func (prc *BaseParserRuleContext) ToStringTree(ruleNames []string, recog Recognizer) string {
return TreesStringTree(prc, ruleNames, recog)
}
func (prc *BaseParserRuleContext) GetRuleContext() RuleContext {
return prc
}
func (prc *BaseParserRuleContext) Accept(visitor ParseTreeVisitor) interface{} {
return visitor.VisitChildren(prc)
}
func (prc *BaseParserRuleContext) SetStart(t Token) {
prc.start = t
}
func (prc *BaseParserRuleContext) GetStart() Token {
return prc.start
}
func (prc *BaseParserRuleContext) SetStop(t Token) {
prc.stop = t
}
func (prc *BaseParserRuleContext) GetStop() Token {
return prc.stop
}
func (prc *BaseParserRuleContext) GetToken(ttype int, i int) TerminalNode {
for j := 0; j < len(prc.children); j++ {
child := prc.children[j]
if c2, ok := child.(TerminalNode); ok {
if c2.GetSymbol().GetTokenType() == ttype {
if i == 0 {
return c2
}
i--
}
}
}
return nil
}
func (prc *BaseParserRuleContext) GetTokens(ttype int) []TerminalNode {
if prc.children == nil {
return make([]TerminalNode, 0)
}
tokens := make([]TerminalNode, 0)
for j := 0; j < len(prc.children); j++ {
child := prc.children[j]
if tchild, ok := child.(TerminalNode); ok {
if tchild.GetSymbol().GetTokenType() == ttype {
tokens = append(tokens, tchild)
}
}
}
return tokens
}
func (prc *BaseParserRuleContext) GetPayload() interface{} {
return prc
}
func (prc *BaseParserRuleContext) getChild(ctxType reflect.Type, i int) RuleContext {
if prc.children == nil || i < 0 || i >= len(prc.children) {
return nil
}
j := -1 // what element have we found with ctxType?
for _, o := range prc.children {
childType := reflect.TypeOf(o)
if childType.Implements(ctxType) {
j++
if j == i {
return o.(RuleContext)
}
}
}
return nil
}
// Go lacks generics, so it's not possible for us to return the child with the correct type, but we do
// check for convertibility
func (prc *BaseParserRuleContext) GetTypedRuleContext(ctxType reflect.Type, i int) RuleContext {
return prc.getChild(ctxType, i)
}
func (prc *BaseParserRuleContext) GetTypedRuleContexts(ctxType reflect.Type) []RuleContext {
if prc.children == nil {
return make([]RuleContext, 0)
}
contexts := make([]RuleContext, 0)
for _, child := range prc.children {
childType := reflect.TypeOf(child)
if childType.ConvertibleTo(ctxType) {
contexts = append(contexts, child.(RuleContext))
}
}
return contexts
}
func (prc *BaseParserRuleContext) GetChildCount() int {
if prc.children == nil {
return 0
}
return len(prc.children)
}
func (prc *BaseParserRuleContext) GetSourceInterval() *Interval {
if prc.start == nil || prc.stop == nil {
return TreeInvalidInterval
}
return NewInterval(prc.start.GetTokenIndex(), prc.stop.GetTokenIndex())
}
//need to manage circular dependencies, so export now
// Print out a whole tree, not just a node, in LISP format
// (root child1 .. childN). Print just a node if b is a leaf.
//
func (prc *BaseParserRuleContext) String(ruleNames []string, stop RuleContext) string {
var p ParserRuleContext = prc
s := "["
for p != nil && p != stop {
if ruleNames == nil {
if !p.IsEmpty() {
s += strconv.Itoa(p.GetInvokingState())
}
} else {
ri := p.GetRuleIndex()
var ruleName string
if ri >= 0 && ri < len(ruleNames) {
ruleName = ruleNames[ri]
} else {
ruleName = strconv.Itoa(ri)
}
s += ruleName
}
if p.GetParent() != nil && (ruleNames != nil || !p.GetParent().(ParserRuleContext).IsEmpty()) {
s += " "
}
pi := p.GetParent()
if pi != nil {
p = pi.(ParserRuleContext)
} else {
p = nil
}
}
s += "]"
return s
}
var RuleContextEmpty = NewBaseParserRuleContext(nil, -1)
type InterpreterRuleContext interface {
ParserRuleContext
}
type BaseInterpreterRuleContext struct {
*BaseParserRuleContext
}
func NewBaseInterpreterRuleContext(parent BaseInterpreterRuleContext, invokingStateNumber, ruleIndex int) *BaseInterpreterRuleContext {
prc := new(BaseInterpreterRuleContext)
prc.BaseParserRuleContext = NewBaseParserRuleContext(parent, invokingStateNumber)
prc.RuleIndex = ruleIndex
return prc
}

View File

@@ -0,0 +1,756 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"strconv"
)
// Represents {@code $} in local context prediction, which means wildcard.
// {@code//+x =//}.
// /
const (
BasePredictionContextEmptyReturnState = 0x7FFFFFFF
)
// Represents {@code $} in an array in full context mode, when {@code $}
// doesn't mean wildcard: {@code $ + x = [$,x]}. Here,
// {@code $} = {@link //EmptyReturnState}.
// /
var (
BasePredictionContextglobalNodeCount = 1
BasePredictionContextid = BasePredictionContextglobalNodeCount
)
type PredictionContext interface {
hash() int
GetParent(int) PredictionContext
getReturnState(int) int
equals(PredictionContext) bool
length() int
isEmpty() bool
hasEmptyPath() bool
String() string
}
type BasePredictionContext struct {
cachedHash int
}
func NewBasePredictionContext(cachedHash int) *BasePredictionContext {
pc := new(BasePredictionContext)
pc.cachedHash = cachedHash
return pc
}
func (b *BasePredictionContext) isEmpty() bool {
return false
}
func calculateHash(parent PredictionContext, returnState int) int {
h := murmurInit(1)
h = murmurUpdate(h, parent.hash())
h = murmurUpdate(h, returnState)
return murmurFinish(h, 2)
}
func calculateEmptyHash() int {
h := murmurInit(1)
return murmurFinish(h, 0)
}
// Used to cache {@link BasePredictionContext} objects. Its used for the shared
// context cash associated with contexts in DFA states. This cache
// can be used for both lexers and parsers.
type PredictionContextCache struct {
cache map[PredictionContext]PredictionContext
}
func NewPredictionContextCache() *PredictionContextCache {
t := new(PredictionContextCache)
t.cache = make(map[PredictionContext]PredictionContext)
return t
}
// Add a context to the cache and return it. If the context already exists,
// return that one instead and do not add a Newcontext to the cache.
// Protect shared cache from unsafe thread access.
//
func (p *PredictionContextCache) add(ctx PredictionContext) PredictionContext {
if ctx == BasePredictionContextEMPTY {
return BasePredictionContextEMPTY
}
existing := p.cache[ctx]
if existing != nil {
return existing
}
p.cache[ctx] = ctx
return ctx
}
func (p *PredictionContextCache) Get(ctx PredictionContext) PredictionContext {
return p.cache[ctx]
}
func (p *PredictionContextCache) length() int {
return len(p.cache)
}
type SingletonPredictionContext interface {
PredictionContext
}
type BaseSingletonPredictionContext struct {
*BasePredictionContext
parentCtx PredictionContext
returnState int
}
func NewBaseSingletonPredictionContext(parent PredictionContext, returnState int) *BaseSingletonPredictionContext {
s := new(BaseSingletonPredictionContext)
s.BasePredictionContext = NewBasePredictionContext(37)
if parent != nil {
s.cachedHash = calculateHash(parent, returnState)
} else {
s.cachedHash = calculateEmptyHash()
}
s.parentCtx = parent
s.returnState = returnState
return s
}
func SingletonBasePredictionContextCreate(parent PredictionContext, returnState int) PredictionContext {
if returnState == BasePredictionContextEmptyReturnState && parent == nil {
// someone can pass in the bits of an array ctx that mean $
return BasePredictionContextEMPTY
}
return NewBaseSingletonPredictionContext(parent, returnState)
}
func (b *BaseSingletonPredictionContext) length() int {
return 1
}
func (b *BaseSingletonPredictionContext) GetParent(index int) PredictionContext {
return b.parentCtx
}
func (b *BaseSingletonPredictionContext) getReturnState(index int) int {
return b.returnState
}
func (b *BaseSingletonPredictionContext) hasEmptyPath() bool {
return b.returnState == BasePredictionContextEmptyReturnState
}
func (b *BaseSingletonPredictionContext) equals(other PredictionContext) bool {
if b == other {
return true
} else if _, ok := other.(*BaseSingletonPredictionContext); !ok {
return false
} else if b.hash() != other.hash() {
return false // can't be same if hash is different
}
otherP := other.(*BaseSingletonPredictionContext)
if b.returnState != other.getReturnState(0) {
return false
} else if b.parentCtx == nil {
return otherP.parentCtx == nil
}
return b.parentCtx.equals(otherP.parentCtx)
}
func (b *BaseSingletonPredictionContext) hash() int {
h := murmurInit(1)
if b.parentCtx == nil {
return murmurFinish(h, 0)
}
h = murmurUpdate(h, b.parentCtx.hash())
h = murmurUpdate(h, b.returnState)
return murmurFinish(h, 2)
}
func (b *BaseSingletonPredictionContext) String() string {
var up string
if b.parentCtx == nil {
up = ""
} else {
up = b.parentCtx.String()
}
if len(up) == 0 {
if b.returnState == BasePredictionContextEmptyReturnState {
return "$"
}
return strconv.Itoa(b.returnState)
}
return strconv.Itoa(b.returnState) + " " + up
}
var BasePredictionContextEMPTY = NewEmptyPredictionContext()
type EmptyPredictionContext struct {
*BaseSingletonPredictionContext
}
func NewEmptyPredictionContext() *EmptyPredictionContext {
p := new(EmptyPredictionContext)
p.BaseSingletonPredictionContext = NewBaseSingletonPredictionContext(nil, BasePredictionContextEmptyReturnState)
return p
}
func (e *EmptyPredictionContext) isEmpty() bool {
return true
}
func (e *EmptyPredictionContext) GetParent(index int) PredictionContext {
return nil
}
func (e *EmptyPredictionContext) getReturnState(index int) int {
return e.returnState
}
func (e *EmptyPredictionContext) equals(other PredictionContext) bool {
return e == other
}
func (e *EmptyPredictionContext) String() string {
return "$"
}
type ArrayPredictionContext struct {
*BasePredictionContext
parents []PredictionContext
returnStates []int
}
func NewArrayPredictionContext(parents []PredictionContext, returnStates []int) *ArrayPredictionContext {
// Parent can be nil only if full ctx mode and we make an array
// from {@link //EMPTY} and non-empty. We merge {@link //EMPTY} by using
// nil parent and
// returnState == {@link //EmptyReturnState}.
c := new(ArrayPredictionContext)
c.BasePredictionContext = NewBasePredictionContext(37)
for i := range parents {
c.cachedHash += calculateHash(parents[i], returnStates[i])
}
c.parents = parents
c.returnStates = returnStates
return c
}
func (a *ArrayPredictionContext) GetReturnStates() []int {
return a.returnStates
}
func (a *ArrayPredictionContext) hasEmptyPath() bool {
return a.getReturnState(a.length()-1) == BasePredictionContextEmptyReturnState
}
func (a *ArrayPredictionContext) isEmpty() bool {
// since EmptyReturnState can only appear in the last position, we
// don't need to verify that size==1
return a.returnStates[0] == BasePredictionContextEmptyReturnState
}
func (a *ArrayPredictionContext) length() int {
return len(a.returnStates)
}
func (a *ArrayPredictionContext) GetParent(index int) PredictionContext {
return a.parents[index]
}
func (a *ArrayPredictionContext) getReturnState(index int) int {
return a.returnStates[index]
}
func (a *ArrayPredictionContext) equals(other PredictionContext) bool {
if _, ok := other.(*ArrayPredictionContext); !ok {
return false
} else if a.cachedHash != other.hash() {
return false // can't be same if hash is different
} else {
otherP := other.(*ArrayPredictionContext)
return &a.returnStates == &otherP.returnStates && &a.parents == &otherP.parents
}
}
func (a *ArrayPredictionContext) hash() int {
h := murmurInit(1)
for _, p := range a.parents {
h = murmurUpdate(h, p.hash())
}
for _, r := range a.returnStates {
h = murmurUpdate(h, r)
}
return murmurFinish(h, 2 * len(a.parents))
}
func (a *ArrayPredictionContext) String() string {
if a.isEmpty() {
return "[]"
}
s := "["
for i := 0; i < len(a.returnStates); i++ {
if i > 0 {
s = s + ", "
}
if a.returnStates[i] == BasePredictionContextEmptyReturnState {
s = s + "$"
continue
}
s = s + strconv.Itoa(a.returnStates[i])
if a.parents[i] != nil {
s = s + " " + a.parents[i].String()
} else {
s = s + "nil"
}
}
return s + "]"
}
// Convert a {@link RuleContext} tree to a {@link BasePredictionContext} graph.
// Return {@link //EMPTY} if {@code outerContext} is empty or nil.
// /
func predictionContextFromRuleContext(a *ATN, outerContext RuleContext) PredictionContext {
if outerContext == nil {
outerContext = RuleContextEmpty
}
// if we are in RuleContext of start rule, s, then BasePredictionContext
// is EMPTY. Nobody called us. (if we are empty, return empty)
if outerContext.GetParent() == nil || outerContext == RuleContextEmpty {
return BasePredictionContextEMPTY
}
// If we have a parent, convert it to a BasePredictionContext graph
parent := predictionContextFromRuleContext(a, outerContext.GetParent().(RuleContext))
state := a.states[outerContext.GetInvokingState()]
transition := state.GetTransitions()[0]
return SingletonBasePredictionContextCreate(parent, transition.(*RuleTransition).followState.GetStateNumber())
}
func merge(a, b PredictionContext, rootIsWildcard bool, mergeCache *DoubleDict) PredictionContext {
// share same graph if both same
if a == b {
return a
}
ac, ok1 := a.(*BaseSingletonPredictionContext)
bc, ok2 := b.(*BaseSingletonPredictionContext)
if ok1 && ok2 {
return mergeSingletons(ac, bc, rootIsWildcard, mergeCache)
}
// At least one of a or b is array
// If one is $ and rootIsWildcard, return $ as// wildcard
if rootIsWildcard {
if _, ok := a.(*EmptyPredictionContext); ok {
return a
}
if _, ok := b.(*EmptyPredictionContext); ok {
return b
}
}
// convert singleton so both are arrays to normalize
if _, ok := a.(*BaseSingletonPredictionContext); ok {
a = NewArrayPredictionContext([]PredictionContext{a.GetParent(0)}, []int{a.getReturnState(0)})
}
if _, ok := b.(*BaseSingletonPredictionContext); ok {
b = NewArrayPredictionContext([]PredictionContext{b.GetParent(0)}, []int{b.getReturnState(0)})
}
return mergeArrays(a.(*ArrayPredictionContext), b.(*ArrayPredictionContext), rootIsWildcard, mergeCache)
}
//
// Merge two {@link SingletonBasePredictionContext} instances.
//
// <p>Stack tops equal, parents merge is same return left graph.<br>
// <embed src="images/SingletonMerge_SameRootSamePar.svg"
// type="image/svg+xml"/></p>
//
// <p>Same stack top, parents differ merge parents giving array node, then
// remainders of those graphs. A Newroot node is created to point to the
// merged parents.<br>
// <embed src="images/SingletonMerge_SameRootDiffPar.svg"
// type="image/svg+xml"/></p>
//
// <p>Different stack tops pointing to same parent. Make array node for the
// root where both element in the root point to the same (original)
// parent.<br>
// <embed src="images/SingletonMerge_DiffRootSamePar.svg"
// type="image/svg+xml"/></p>
//
// <p>Different stack tops pointing to different parents. Make array node for
// the root where each element points to the corresponding original
// parent.<br>
// <embed src="images/SingletonMerge_DiffRootDiffPar.svg"
// type="image/svg+xml"/></p>
//
// @param a the first {@link SingletonBasePredictionContext}
// @param b the second {@link SingletonBasePredictionContext}
// @param rootIsWildcard {@code true} if this is a local-context merge,
// otherwise false to indicate a full-context merge
// @param mergeCache
// /
func mergeSingletons(a, b *BaseSingletonPredictionContext, rootIsWildcard bool, mergeCache *DoubleDict) PredictionContext {
if mergeCache != nil {
previous := mergeCache.Get(a.hash(), b.hash())
if previous != nil {
return previous.(PredictionContext)
}
previous = mergeCache.Get(b.hash(), a.hash())
if previous != nil {
return previous.(PredictionContext)
}
}
rootMerge := mergeRoot(a, b, rootIsWildcard)
if rootMerge != nil {
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), rootMerge)
}
return rootMerge
}
if a.returnState == b.returnState {
parent := merge(a.parentCtx, b.parentCtx, rootIsWildcard, mergeCache)
// if parent is same as existing a or b parent or reduced to a parent,
// return it
if parent == a.parentCtx {
return a // ax + bx = ax, if a=b
}
if parent == b.parentCtx {
return b // ax + bx = bx, if a=b
}
// else: ax + ay = a'[x,y]
// merge parents x and y, giving array node with x,y then remainders
// of those graphs. dup a, a' points at merged array
// Newjoined parent so create Newsingleton pointing to it, a'
spc := SingletonBasePredictionContextCreate(parent, a.returnState)
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), spc)
}
return spc
}
// a != b payloads differ
// see if we can collapse parents due to $+x parents if local ctx
var singleParent PredictionContext
if a == b || (a.parentCtx != nil && a.parentCtx == b.parentCtx) { // ax +
// bx =
// [a,b]x
singleParent = a.parentCtx
}
if singleParent != nil { // parents are same
// sort payloads and use same parent
payloads := []int{a.returnState, b.returnState}
if a.returnState > b.returnState {
payloads[0] = b.returnState
payloads[1] = a.returnState
}
parents := []PredictionContext{singleParent, singleParent}
apc := NewArrayPredictionContext(parents, payloads)
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), apc)
}
return apc
}
// parents differ and can't merge them. Just pack together
// into array can't merge.
// ax + by = [ax,by]
payloads := []int{a.returnState, b.returnState}
parents := []PredictionContext{a.parentCtx, b.parentCtx}
if a.returnState > b.returnState { // sort by payload
payloads[0] = b.returnState
payloads[1] = a.returnState
parents = []PredictionContext{b.parentCtx, a.parentCtx}
}
apc := NewArrayPredictionContext(parents, payloads)
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), apc)
}
return apc
}
//
// Handle case where at least one of {@code a} or {@code b} is
// {@link //EMPTY}. In the following diagrams, the symbol {@code $} is used
// to represent {@link //EMPTY}.
//
// <h2>Local-Context Merges</h2>
//
// <p>These local-context merge operations are used when {@code rootIsWildcard}
// is true.</p>
//
// <p>{@link //EMPTY} is superset of any graph return {@link //EMPTY}.<br>
// <embed src="images/LocalMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
//
// <p>{@link //EMPTY} and anything is {@code //EMPTY}, so merged parent is
// {@code //EMPTY} return left graph.<br>
// <embed src="images/LocalMerge_EmptyParent.svg" type="image/svg+xml"/></p>
//
// <p>Special case of last merge if local context.<br>
// <embed src="images/LocalMerge_DiffRoots.svg" type="image/svg+xml"/></p>
//
// <h2>Full-Context Merges</h2>
//
// <p>These full-context merge operations are used when {@code rootIsWildcard}
// is false.</p>
//
// <p><embed src="images/FullMerge_EmptyRoots.svg" type="image/svg+xml"/></p>
//
// <p>Must keep all contexts {@link //EMPTY} in array is a special value (and
// nil parent).<br>
// <embed src="images/FullMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
//
// <p><embed src="images/FullMerge_SameRoot.svg" type="image/svg+xml"/></p>
//
// @param a the first {@link SingletonBasePredictionContext}
// @param b the second {@link SingletonBasePredictionContext}
// @param rootIsWildcard {@code true} if this is a local-context merge,
// otherwise false to indicate a full-context merge
// /
func mergeRoot(a, b SingletonPredictionContext, rootIsWildcard bool) PredictionContext {
if rootIsWildcard {
if a == BasePredictionContextEMPTY {
return BasePredictionContextEMPTY // // + b =//
}
if b == BasePredictionContextEMPTY {
return BasePredictionContextEMPTY // a +// =//
}
} else {
if a == BasePredictionContextEMPTY && b == BasePredictionContextEMPTY {
return BasePredictionContextEMPTY // $ + $ = $
} else if a == BasePredictionContextEMPTY { // $ + x = [$,x]
payloads := []int{b.getReturnState(-1), BasePredictionContextEmptyReturnState}
parents := []PredictionContext{b.GetParent(-1), nil}
return NewArrayPredictionContext(parents, payloads)
} else if b == BasePredictionContextEMPTY { // x + $ = [$,x] ($ is always first if present)
payloads := []int{a.getReturnState(-1), BasePredictionContextEmptyReturnState}
parents := []PredictionContext{a.GetParent(-1), nil}
return NewArrayPredictionContext(parents, payloads)
}
}
return nil
}
//
// Merge two {@link ArrayBasePredictionContext} instances.
//
// <p>Different tops, different parents.<br>
// <embed src="images/ArrayMerge_DiffTopDiffPar.svg" type="image/svg+xml"/></p>
//
// <p>Shared top, same parents.<br>
// <embed src="images/ArrayMerge_ShareTopSamePar.svg" type="image/svg+xml"/></p>
//
// <p>Shared top, different parents.<br>
// <embed src="images/ArrayMerge_ShareTopDiffPar.svg" type="image/svg+xml"/></p>
//
// <p>Shared top, all shared parents.<br>
// <embed src="images/ArrayMerge_ShareTopSharePar.svg"
// type="image/svg+xml"/></p>
//
// <p>Equal tops, merge parents and reduce top to
// {@link SingletonBasePredictionContext}.<br>
// <embed src="images/ArrayMerge_EqualTop.svg" type="image/svg+xml"/></p>
// /
func mergeArrays(a, b *ArrayPredictionContext, rootIsWildcard bool, mergeCache *DoubleDict) PredictionContext {
if mergeCache != nil {
previous := mergeCache.Get(a.hash(), b.hash())
if previous != nil {
return previous.(PredictionContext)
}
previous = mergeCache.Get(b.hash(), a.hash())
if previous != nil {
return previous.(PredictionContext)
}
}
// merge sorted payloads a + b => M
i := 0 // walks a
j := 0 // walks b
k := 0 // walks target M array
mergedReturnStates := make([]int, len(a.returnStates)+len(b.returnStates))
mergedParents := make([]PredictionContext, len(a.returnStates)+len(b.returnStates))
// walk and merge to yield mergedParents, mergedReturnStates
for i < len(a.returnStates) && j < len(b.returnStates) {
aParent := a.parents[i]
bParent := b.parents[j]
if a.returnStates[i] == b.returnStates[j] {
// same payload (stack tops are equal), must yield merged singleton
payload := a.returnStates[i]
// $+$ = $
bothDollars := payload == BasePredictionContextEmptyReturnState && aParent == nil && bParent == nil
axAX := (aParent != nil && bParent != nil && aParent == bParent) // ax+ax
// ->
// ax
if bothDollars || axAX {
mergedParents[k] = aParent // choose left
mergedReturnStates[k] = payload
} else { // ax+ay -> a'[x,y]
mergedParent := merge(aParent, bParent, rootIsWildcard, mergeCache)
mergedParents[k] = mergedParent
mergedReturnStates[k] = payload
}
i++ // hop over left one as usual
j++ // but also Skip one in right side since we merge
} else if a.returnStates[i] < b.returnStates[j] { // copy a[i] to M
mergedParents[k] = aParent
mergedReturnStates[k] = a.returnStates[i]
i++
} else { // b > a, copy b[j] to M
mergedParents[k] = bParent
mergedReturnStates[k] = b.returnStates[j]
j++
}
k++
}
// copy over any payloads remaining in either array
if i < len(a.returnStates) {
for p := i; p < len(a.returnStates); p++ {
mergedParents[k] = a.parents[p]
mergedReturnStates[k] = a.returnStates[p]
k++
}
} else {
for p := j; p < len(b.returnStates); p++ {
mergedParents[k] = b.parents[p]
mergedReturnStates[k] = b.returnStates[p]
k++
}
}
// trim merged if we combined a few that had same stack tops
if k < len(mergedParents) { // write index < last position trim
if k == 1 { // for just one merged element, return singleton top
pc := SingletonBasePredictionContextCreate(mergedParents[0], mergedReturnStates[0])
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), pc)
}
return pc
}
mergedParents = mergedParents[0:k]
mergedReturnStates = mergedReturnStates[0:k]
}
M := NewArrayPredictionContext(mergedParents, mergedReturnStates)
// if we created same array as a or b, return that instead
// TODO: track whether this is possible above during merge sort for speed
if M == a {
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), a)
}
return a
}
if M == b {
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), b)
}
return b
}
combineCommonParents(mergedParents)
if mergeCache != nil {
mergeCache.set(a.hash(), b.hash(), M)
}
return M
}
//
// Make pass over all <em>M</em> {@code parents} merge any {@code equals()}
// ones.
// /
func combineCommonParents(parents []PredictionContext) {
uniqueParents := make(map[PredictionContext]PredictionContext)
for p := 0; p < len(parents); p++ {
parent := parents[p]
if uniqueParents[parent] == nil {
uniqueParents[parent] = parent
}
}
for q := 0; q < len(parents); q++ {
parents[q] = uniqueParents[parents[q]]
}
}
func getCachedBasePredictionContext(context PredictionContext, contextCache *PredictionContextCache, visited map[PredictionContext]PredictionContext) PredictionContext {
if context.isEmpty() {
return context
}
existing := visited[context]
if existing != nil {
return existing
}
existing = contextCache.Get(context)
if existing != nil {
visited[context] = existing
return existing
}
changed := false
parents := make([]PredictionContext, context.length())
for i := 0; i < len(parents); i++ {
parent := getCachedBasePredictionContext(context.GetParent(i), contextCache, visited)
if changed || parent != context.GetParent(i) {
if !changed {
parents = make([]PredictionContext, context.length())
for j := 0; j < context.length(); j++ {
parents[j] = context.GetParent(j)
}
changed = true
}
parents[i] = parent
}
}
if !changed {
contextCache.add(context)
visited[context] = context
return context
}
var updated PredictionContext
if len(parents) == 0 {
updated = BasePredictionContextEMPTY
} else if len(parents) == 1 {
updated = SingletonBasePredictionContextCreate(parents[0], context.getReturnState(0))
} else {
updated = NewArrayPredictionContext(parents, context.(*ArrayPredictionContext).GetReturnStates())
}
contextCache.add(updated)
visited[updated] = updated
visited[context] = updated
return updated
}

View File

@@ -0,0 +1,553 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// This enumeration defines the prediction modes available in ANTLR 4 along with
// utility methods for analyzing configuration sets for conflicts and/or
// ambiguities.
const (
//
// The SLL(*) prediction mode. This prediction mode ignores the current
// parser context when making predictions. This is the fastest prediction
// mode, and provides correct results for many grammars. This prediction
// mode is more powerful than the prediction mode provided by ANTLR 3, but
// may result in syntax errors for grammar and input combinations which are
// not SLL.
//
// <p>
// When using this prediction mode, the parser will either return a correct
// parse tree (i.e. the same parse tree that would be returned with the
// {@link //LL} prediction mode), or it will Report a syntax error. If a
// syntax error is encountered when using the {@link //SLL} prediction mode,
// it may be due to either an actual syntax error in the input or indicate
// that the particular combination of grammar and input requires the more
// powerful {@link //LL} prediction abilities to complete successfully.</p>
//
// <p>
// This prediction mode does not provide any guarantees for prediction
// behavior for syntactically-incorrect inputs.</p>
//
PredictionModeSLL = 0
//
// The LL(*) prediction mode. This prediction mode allows the current parser
// context to be used for resolving SLL conflicts that occur during
// prediction. This is the fastest prediction mode that guarantees correct
// parse results for all combinations of grammars with syntactically correct
// inputs.
//
// <p>
// When using this prediction mode, the parser will make correct decisions
// for all syntactically-correct grammar and input combinations. However, in
// cases where the grammar is truly ambiguous this prediction mode might not
// Report a precise answer for <em>exactly which</em> alternatives are
// ambiguous.</p>
//
// <p>
// This prediction mode does not provide any guarantees for prediction
// behavior for syntactically-incorrect inputs.</p>
//
PredictionModeLL = 1
//
// The LL(*) prediction mode with exact ambiguity detection. In addition to
// the correctness guarantees provided by the {@link //LL} prediction mode,
// this prediction mode instructs the prediction algorithm to determine the
// complete and exact set of ambiguous alternatives for every ambiguous
// decision encountered while parsing.
//
// <p>
// This prediction mode may be used for diagnosing ambiguities during
// grammar development. Due to the performance overhead of calculating sets
// of ambiguous alternatives, this prediction mode should be avoided when
// the exact results are not necessary.</p>
//
// <p>
// This prediction mode does not provide any guarantees for prediction
// behavior for syntactically-incorrect inputs.</p>
//
PredictionModeLLExactAmbigDetection = 2
)
//
// Computes the SLL prediction termination condition.
//
// <p>
// This method computes the SLL prediction termination condition for both of
// the following cases.</p>
//
// <ul>
// <li>The usual SLL+LL fallback upon SLL conflict</li>
// <li>Pure SLL without LL fallback</li>
// </ul>
//
// <p><strong>COMBINED SLL+LL PARSING</strong></p>
//
// <p>When LL-fallback is enabled upon SLL conflict, correct predictions are
// ensured regardless of how the termination condition is computed by this
// method. Due to the substantially higher cost of LL prediction, the
// prediction should only fall back to LL when the additional lookahead
// cannot lead to a unique SLL prediction.</p>
//
// <p>Assuming combined SLL+LL parsing, an SLL configuration set with only
// conflicting subsets should fall back to full LL, even if the
// configuration sets don't resolve to the same alternative (e.g.
// {@code {1,2}} and {@code {3,4}}. If there is at least one non-conflicting
// configuration, SLL could continue with the hopes that more lookahead will
// resolve via one of those non-conflicting configurations.</p>
//
// <p>Here's the prediction termination rule them: SLL (for SLL+LL parsing)
// stops when it sees only conflicting configuration subsets. In contrast,
// full LL keeps going when there is uncertainty.</p>
//
// <p><strong>HEURISTIC</strong></p>
//
// <p>As a heuristic, we stop prediction when we see any conflicting subset
// unless we see a state that only has one alternative associated with it.
// The single-alt-state thing lets prediction continue upon rules like
// (otherwise, it would admit defeat too soon):</p>
//
// <p>{@code [12|1|[], 6|2|[], 12|2|[]]. s : (ID | ID ID?) '' }</p>
//
// <p>When the ATN simulation reaches the state before {@code ''}, it has a
// DFA state that looks like: {@code [12|1|[], 6|2|[], 12|2|[]]}. Naturally
// {@code 12|1|[]} and {@code 12|2|[]} conflict, but we cannot stop
// processing this node because alternative to has another way to continue,
// via {@code [6|2|[]]}.</p>
//
// <p>It also let's us continue for this rule:</p>
//
// <p>{@code [1|1|[], 1|2|[], 8|3|[]] a : A | A | A B }</p>
//
// <p>After Matching input A, we reach the stop state for rule A, state 1.
// State 8 is the state right before B. Clearly alternatives 1 and 2
// conflict and no amount of further lookahead will separate the two.
// However, alternative 3 will be able to continue and so we do not stop
// working on this state. In the previous example, we're concerned with
// states associated with the conflicting alternatives. Here alt 3 is not
// associated with the conflicting configs, but since we can continue
// looking for input reasonably, don't declare the state done.</p>
//
// <p><strong>PURE SLL PARSING</strong></p>
//
// <p>To handle pure SLL parsing, all we have to do is make sure that we
// combine stack contexts for configurations that differ only by semantic
// predicate. From there, we can do the usual SLL termination heuristic.</p>
//
// <p><strong>PREDICATES IN SLL+LL PARSING</strong></p>
//
// <p>SLL decisions don't evaluate predicates until after they reach DFA stop
// states because they need to create the DFA cache that works in all
// semantic situations. In contrast, full LL evaluates predicates collected
// during start state computation so it can ignore predicates thereafter.
// This means that SLL termination detection can totally ignore semantic
// predicates.</p>
//
// <p>Implementation-wise, {@link ATNConfigSet} combines stack contexts but not
// semantic predicate contexts so we might see two configurations like the
// following.</p>
//
// <p>{@code (s, 1, x, {}), (s, 1, x', {p})}</p>
//
// <p>Before testing these configurations against others, we have to merge
// {@code x} and {@code x'} (without modifying the existing configurations).
// For example, we test {@code (x+x')==x''} when looking for conflicts in
// the following configurations.</p>
//
// <p>{@code (s, 1, x, {}), (s, 1, x', {p}), (s, 2, x'', {})}</p>
//
// <p>If the configuration set has predicates (as indicated by
// {@link ATNConfigSet//hasSemanticContext}), this algorithm makes a copy of
// the configurations to strip out all of the predicates so that a standard
// {@link ATNConfigSet} will merge everything ignoring predicates.</p>
//
func PredictionModehasSLLConflictTerminatingPrediction(mode int, configs ATNConfigSet) bool {
// Configs in rule stop states indicate reaching the end of the decision
// rule (local context) or end of start rule (full context). If all
// configs meet this condition, then none of the configurations is able
// to Match additional input so we terminate prediction.
//
if PredictionModeallConfigsInRuleStopStates(configs) {
return true
}
// pure SLL mode parsing
if mode == PredictionModeSLL {
// Don't bother with combining configs from different semantic
// contexts if we can fail over to full LL costs more time
// since we'll often fail over anyway.
if configs.HasSemanticContext() {
// dup configs, tossing out semantic predicates
dup := NewBaseATNConfigSet(false)
for _, c := range configs.GetItems() {
// NewBaseATNConfig({semanticContext:}, c)
c = NewBaseATNConfig2(c, SemanticContextNone)
dup.Add(c, nil)
}
configs = dup
}
// now we have combined contexts for configs with dissimilar preds
}
// pure SLL or combined SLL+LL mode parsing
altsets := PredictionModegetConflictingAltSubsets(configs)
return PredictionModehasConflictingAltSet(altsets) && !PredictionModehasStateAssociatedWithOneAlt(configs)
}
// Checks if any configuration in {@code configs} is in a
// {@link RuleStopState}. Configurations meeting this condition have reached
// the end of the decision rule (local context) or end of start rule (full
// context).
//
// @param configs the configuration set to test
// @return {@code true} if any configuration in {@code configs} is in a
// {@link RuleStopState}, otherwise {@code false}
func PredictionModehasConfigInRuleStopState(configs ATNConfigSet) bool {
for _, c := range configs.GetItems() {
if _, ok := c.GetState().(*RuleStopState); ok {
return true
}
}
return false
}
// Checks if all configurations in {@code configs} are in a
// {@link RuleStopState}. Configurations meeting this condition have reached
// the end of the decision rule (local context) or end of start rule (full
// context).
//
// @param configs the configuration set to test
// @return {@code true} if all configurations in {@code configs} are in a
// {@link RuleStopState}, otherwise {@code false}
func PredictionModeallConfigsInRuleStopStates(configs ATNConfigSet) bool {
for _, c := range configs.GetItems() {
if _, ok := c.GetState().(*RuleStopState); !ok {
return false
}
}
return true
}
//
// Full LL prediction termination.
//
// <p>Can we stop looking ahead during ATN simulation or is there some
// uncertainty as to which alternative we will ultimately pick, after
// consuming more input? Even if there are partial conflicts, we might know
// that everything is going to resolve to the same minimum alternative. That
// means we can stop since no more lookahead will change that fact. On the
// other hand, there might be multiple conflicts that resolve to different
// minimums. That means we need more look ahead to decide which of those
// alternatives we should predict.</p>
//
// <p>The basic idea is to split the set of configurations {@code C}, into
// conflicting subsets {@code (s, _, ctx, _)} and singleton subsets with
// non-conflicting configurations. Two configurations conflict if they have
// identical {@link ATNConfig//state} and {@link ATNConfig//context} values
// but different {@link ATNConfig//alt} value, e.g. {@code (s, i, ctx, _)}
// and {@code (s, j, ctx, _)} for {@code i!=j}.</p>
//
// <p>Reduce these configuration subsets to the set of possible alternatives.
// You can compute the alternative subsets in one pass as follows:</p>
//
// <p>{@code A_s,ctx = {i | (s, i, ctx, _)}} for each configuration in
// {@code C} holding {@code s} and {@code ctx} fixed.</p>
//
// <p>Or in pseudo-code, for each configuration {@code c} in {@code C}:</p>
//
// <pre>
// map[c] U= c.{@link ATNConfig//alt alt} // map hash/equals uses s and x, not
// alt and not pred
// </pre>
//
// <p>The values in {@code map} are the set of {@code A_s,ctx} sets.</p>
//
// <p>If {@code |A_s,ctx|=1} then there is no conflict associated with
// {@code s} and {@code ctx}.</p>
//
// <p>Reduce the subsets to singletons by choosing a minimum of each subset. If
// the union of these alternative subsets is a singleton, then no amount of
// more lookahead will help us. We will always pick that alternative. If,
// however, there is more than one alternative, then we are uncertain which
// alternative to predict and must continue looking for resolution. We may
// or may not discover an ambiguity in the future, even if there are no
// conflicting subsets this round.</p>
//
// <p>The biggest sin is to terminate early because it means we've made a
// decision but were uncertain as to the eventual outcome. We haven't used
// enough lookahead. On the other hand, announcing a conflict too late is no
// big deal you will still have the conflict. It's just inefficient. It
// might even look until the end of file.</p>
//
// <p>No special consideration for semantic predicates is required because
// predicates are evaluated on-the-fly for full LL prediction, ensuring that
// no configuration contains a semantic context during the termination
// check.</p>
//
// <p><strong>CONFLICTING CONFIGS</strong></p>
//
// <p>Two configurations {@code (s, i, x)} and {@code (s, j, x')}, conflict
// when {@code i!=j} but {@code x=x'}. Because we merge all
// {@code (s, i, _)} configurations together, that means that there are at
// most {@code n} configurations associated with state {@code s} for
// {@code n} possible alternatives in the decision. The merged stacks
// complicate the comparison of configuration contexts {@code x} and
// {@code x'}. Sam checks to see if one is a subset of the other by calling
// merge and checking to see if the merged result is either {@code x} or
// {@code x'}. If the {@code x} associated with lowest alternative {@code i}
// is the superset, then {@code i} is the only possible prediction since the
// others resolve to {@code min(i)} as well. However, if {@code x} is
// associated with {@code j>i} then at least one stack configuration for
// {@code j} is not in conflict with alternative {@code i}. The algorithm
// should keep going, looking for more lookahead due to the uncertainty.</p>
//
// <p>For simplicity, I'm doing a equality check between {@code x} and
// {@code x'} that lets the algorithm continue to consume lookahead longer
// than necessary. The reason I like the equality is of course the
// simplicity but also because that is the test you need to detect the
// alternatives that are actually in conflict.</p>
//
// <p><strong>CONTINUE/STOP RULE</strong></p>
//
// <p>Continue if union of resolved alternative sets from non-conflicting and
// conflicting alternative subsets has more than one alternative. We are
// uncertain about which alternative to predict.</p>
//
// <p>The complete set of alternatives, {@code [i for (_,i,_)]}, tells us which
// alternatives are still in the running for the amount of input we've
// consumed at this point. The conflicting sets let us to strip away
// configurations that won't lead to more states because we resolve
// conflicts to the configuration with a minimum alternate for the
// conflicting set.</p>
//
// <p><strong>CASES</strong></p>
//
// <ul>
//
// <li>no conflicts and more than 1 alternative in set =&gt continue</li>
//
// <li> {@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s, 3, z)},
// {@code (s', 1, y)}, {@code (s', 2, y)} yields non-conflicting set
// {@code {3}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} =
// {@code {1,3}} =&gt continue
// </li>
//
// <li>{@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)},
// {@code (s', 2, y)}, {@code (s'', 1, z)} yields non-conflicting set
// {@code {1}} U conflicting sets {@code min({1,2})} U {@code min({1,2})} =
// {@code {1}} =&gt stop and predict 1</li>
//
// <li>{@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 1, y)},
// {@code (s', 2, y)} yields conflicting, reduced sets {@code {1}} U
// {@code {1}} = {@code {1}} =&gt stop and predict 1, can announce
// ambiguity {@code {1,2}}</li>
//
// <li>{@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 2, y)},
// {@code (s', 3, y)} yields conflicting, reduced sets {@code {1}} U
// {@code {2}} = {@code {1,2}} =&gt continue</li>
//
// <li>{@code (s, 1, x)}, {@code (s, 2, x)}, {@code (s', 3, y)},
// {@code (s', 4, y)} yields conflicting, reduced sets {@code {1}} U
// {@code {3}} = {@code {1,3}} =&gt continue</li>
//
// </ul>
//
// <p><strong>EXACT AMBIGUITY DETECTION</strong></p>
//
// <p>If all states Report the same conflicting set of alternatives, then we
// know we have the exact ambiguity set.</p>
//
// <p><code>|A_<em>i</em>|&gt1</code> and
// <code>A_<em>i</em> = A_<em>j</em></code> for all <em>i</em>, <em>j</em>.</p>
//
// <p>In other words, we continue examining lookahead until all {@code A_i}
// have more than one alternative and all {@code A_i} are the same. If
// {@code A={{1,2}, {1,3}}}, then regular LL prediction would terminate
// because the resolved set is {@code {1}}. To determine what the real
// ambiguity is, we have to know whether the ambiguity is between one and
// two or one and three so we keep going. We can only stop prediction when
// we need exact ambiguity detection when the sets look like
// {@code A={{1,2}}} or {@code {{1,2},{1,2}}}, etc...</p>
//
func PredictionModeresolvesToJustOneViableAlt(altsets []*BitSet) int {
return PredictionModegetSingleViableAlt(altsets)
}
//
// Determines if every alternative subset in {@code altsets} contains more
// than one alternative.
//
// @param altsets a collection of alternative subsets
// @return {@code true} if every {@link BitSet} in {@code altsets} has
// {@link BitSet//cardinality cardinality} &gt 1, otherwise {@code false}
//
func PredictionModeallSubsetsConflict(altsets []*BitSet) bool {
return !PredictionModehasNonConflictingAltSet(altsets)
}
//
// Determines if any single alternative subset in {@code altsets} contains
// exactly one alternative.
//
// @param altsets a collection of alternative subsets
// @return {@code true} if {@code altsets} contains a {@link BitSet} with
// {@link BitSet//cardinality cardinality} 1, otherwise {@code false}
//
func PredictionModehasNonConflictingAltSet(altsets []*BitSet) bool {
for i := 0; i < len(altsets); i++ {
alts := altsets[i]
if alts.length() == 1 {
return true
}
}
return false
}
//
// Determines if any single alternative subset in {@code altsets} contains
// more than one alternative.
//
// @param altsets a collection of alternative subsets
// @return {@code true} if {@code altsets} contains a {@link BitSet} with
// {@link BitSet//cardinality cardinality} &gt 1, otherwise {@code false}
//
func PredictionModehasConflictingAltSet(altsets []*BitSet) bool {
for i := 0; i < len(altsets); i++ {
alts := altsets[i]
if alts.length() > 1 {
return true
}
}
return false
}
//
// Determines if every alternative subset in {@code altsets} is equivalent.
//
// @param altsets a collection of alternative subsets
// @return {@code true} if every member of {@code altsets} is equal to the
// others, otherwise {@code false}
//
func PredictionModeallSubsetsEqual(altsets []*BitSet) bool {
var first *BitSet
for i := 0; i < len(altsets); i++ {
alts := altsets[i]
if first == nil {
first = alts
} else if alts != first {
return false
}
}
return true
}
//
// Returns the unique alternative predicted by all alternative subsets in
// {@code altsets}. If no such alternative exists, this method returns
// {@link ATN//INVALID_ALT_NUMBER}.
//
// @param altsets a collection of alternative subsets
//
func PredictionModegetUniqueAlt(altsets []*BitSet) int {
all := PredictionModeGetAlts(altsets)
if all.length() == 1 {
return all.minValue()
}
return ATNInvalidAltNumber
}
// Gets the complete set of represented alternatives for a collection of
// alternative subsets. This method returns the union of each {@link BitSet}
// in {@code altsets}.
//
// @param altsets a collection of alternative subsets
// @return the set of represented alternatives in {@code altsets}
//
func PredictionModeGetAlts(altsets []*BitSet) *BitSet {
all := NewBitSet()
for _, alts := range altsets {
all.or(alts)
}
return all
}
//
// This func gets the conflicting alt subsets from a configuration set.
// For each configuration {@code c} in {@code configs}:
//
// <pre>
// map[c] U= c.{@link ATNConfig//alt alt} // map hash/equals uses s and x, not
// alt and not pred
// </pre>
//
func PredictionModegetConflictingAltSubsets(configs ATNConfigSet) []*BitSet {
configToAlts := make(map[int]*BitSet)
for _, c := range configs.GetItems() {
key := 31 * c.GetState().GetStateNumber() + c.GetContext().hash()
alts, ok := configToAlts[key]
if !ok {
alts = NewBitSet()
configToAlts[key] = alts
}
alts.add(c.GetAlt())
}
values := make([]*BitSet, 0, 10)
for _, v := range configToAlts {
values = append(values, v)
}
return values
}
//
// Get a map from state to alt subset from a configuration set. For each
// configuration {@code c} in {@code configs}:
//
// <pre>
// map[c.{@link ATNConfig//state state}] U= c.{@link ATNConfig//alt alt}
// </pre>
//
func PredictionModeGetStateToAltMap(configs ATNConfigSet) *AltDict {
m := NewAltDict()
for _, c := range configs.GetItems() {
alts := m.Get(c.GetState().String())
if alts == nil {
alts = NewBitSet()
m.put(c.GetState().String(), alts)
}
alts.(*BitSet).add(c.GetAlt())
}
return m
}
func PredictionModehasStateAssociatedWithOneAlt(configs ATNConfigSet) bool {
values := PredictionModeGetStateToAltMap(configs).values()
for i := 0; i < len(values); i++ {
if values[i].(*BitSet).length() == 1 {
return true
}
}
return false
}
func PredictionModegetSingleViableAlt(altsets []*BitSet) int {
result := ATNInvalidAltNumber
for i := 0; i < len(altsets); i++ {
alts := altsets[i]
minAlt := alts.minValue()
if result == ATNInvalidAltNumber {
result = minAlt
} else if result != minAlt { // more than 1 viable alt
return ATNInvalidAltNumber
}
}
return result
}

View File

@@ -0,0 +1,217 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strings"
"strconv"
)
type Recognizer interface {
GetLiteralNames() []string
GetSymbolicNames() []string
GetRuleNames() []string
Sempred(RuleContext, int, int) bool
Precpred(RuleContext, int) bool
GetState() int
SetState(int)
Action(RuleContext, int, int)
AddErrorListener(ErrorListener)
RemoveErrorListeners()
GetATN() *ATN
GetErrorListenerDispatch() ErrorListener
}
type BaseRecognizer struct {
listeners []ErrorListener
state int
RuleNames []string
LiteralNames []string
SymbolicNames []string
GrammarFileName string
}
func NewBaseRecognizer() *BaseRecognizer {
rec := new(BaseRecognizer)
rec.listeners = []ErrorListener{ConsoleErrorListenerINSTANCE}
rec.state = -1
return rec
}
var tokenTypeMapCache = make(map[string]int)
var ruleIndexMapCache = make(map[string]int)
func (b *BaseRecognizer) checkVersion(toolVersion string) {
runtimeVersion := "4.9.2"
if runtimeVersion != toolVersion {
fmt.Println("ANTLR runtime and generated code versions disagree: " + runtimeVersion + "!=" + toolVersion)
}
}
func (b *BaseRecognizer) Action(context RuleContext, ruleIndex, actionIndex int) {
panic("action not implemented on Recognizer!")
}
func (b *BaseRecognizer) AddErrorListener(listener ErrorListener) {
b.listeners = append(b.listeners, listener)
}
func (b *BaseRecognizer) RemoveErrorListeners() {
b.listeners = make([]ErrorListener, 0)
}
func (b *BaseRecognizer) GetRuleNames() []string {
return b.RuleNames
}
func (b *BaseRecognizer) GetTokenNames() []string {
return b.LiteralNames
}
func (b *BaseRecognizer) GetSymbolicNames() []string {
return b.SymbolicNames
}
func (b *BaseRecognizer) GetLiteralNames() []string {
return b.LiteralNames
}
func (b *BaseRecognizer) GetState() int {
return b.state
}
func (b *BaseRecognizer) SetState(v int) {
b.state = v
}
//func (b *Recognizer) GetTokenTypeMap() {
// var tokenNames = b.GetTokenNames()
// if (tokenNames==nil) {
// panic("The current recognizer does not provide a list of token names.")
// }
// var result = tokenTypeMapCache[tokenNames]
// if(result==nil) {
// result = tokenNames.reduce(function(o, k, i) { o[k] = i })
// result.EOF = TokenEOF
// tokenTypeMapCache[tokenNames] = result
// }
// return result
//}
// Get a map from rule names to rule indexes.
//
// <p>Used for XPath and tree pattern compilation.</p>
//
func (b *BaseRecognizer) GetRuleIndexMap() map[string]int {
panic("Method not defined!")
// var ruleNames = b.GetRuleNames()
// if (ruleNames==nil) {
// panic("The current recognizer does not provide a list of rule names.")
// }
//
// var result = ruleIndexMapCache[ruleNames]
// if(result==nil) {
// result = ruleNames.reduce(function(o, k, i) { o[k] = i })
// ruleIndexMapCache[ruleNames] = result
// }
// return result
}
func (b *BaseRecognizer) GetTokenType(tokenName string) int {
panic("Method not defined!")
// var ttype = b.GetTokenTypeMap()[tokenName]
// if (ttype !=nil) {
// return ttype
// } else {
// return TokenInvalidType
// }
}
//func (b *Recognizer) GetTokenTypeMap() map[string]int {
// Vocabulary vocabulary = getVocabulary()
//
// Synchronized (tokenTypeMapCache) {
// Map<String, Integer> result = tokenTypeMapCache.Get(vocabulary)
// if (result == null) {
// result = new HashMap<String, Integer>()
// for (int i = 0; i < GetATN().maxTokenType; i++) {
// String literalName = vocabulary.getLiteralName(i)
// if (literalName != null) {
// result.put(literalName, i)
// }
//
// String symbolicName = vocabulary.GetSymbolicName(i)
// if (symbolicName != null) {
// result.put(symbolicName, i)
// }
// }
//
// result.put("EOF", Token.EOF)
// result = Collections.unmodifiableMap(result)
// tokenTypeMapCache.put(vocabulary, result)
// }
//
// return result
// }
//}
// What is the error header, normally line/character position information?//
func (b *BaseRecognizer) GetErrorHeader(e RecognitionException) string {
line := e.GetOffendingToken().GetLine()
column := e.GetOffendingToken().GetColumn()
return "line " + strconv.Itoa(line) + ":" + strconv.Itoa(column)
}
// How should a token be displayed in an error message? The default
// is to display just the text, but during development you might
// want to have a lot of information spit out. Override in that case
// to use t.String() (which, for CommonToken, dumps everything about
// the token). This is better than forcing you to override a method in
// your token objects because you don't have to go modify your lexer
// so that it creates a NewJava type.
//
// @deprecated This method is not called by the ANTLR 4 Runtime. Specific
// implementations of {@link ANTLRErrorStrategy} may provide a similar
// feature when necessary. For example, see
// {@link DefaultErrorStrategy//GetTokenErrorDisplay}.
//
func (b *BaseRecognizer) GetTokenErrorDisplay(t Token) string {
if t == nil {
return "<no token>"
}
s := t.GetText()
if s == "" {
if t.GetTokenType() == TokenEOF {
s = "<EOF>"
} else {
s = "<" + strconv.Itoa(t.GetTokenType()) + ">"
}
}
s = strings.Replace(s, "\t", "\\t", -1)
s = strings.Replace(s, "\n", "\\n", -1)
s = strings.Replace(s, "\r", "\\r", -1)
return "'" + s + "'"
}
func (b *BaseRecognizer) GetErrorListenerDispatch() ErrorListener {
return NewProxyErrorListener(b.listeners)
}
// subclass needs to override these if there are sempreds or actions
// that the ATN interp needs to execute
func (b *BaseRecognizer) Sempred(localctx RuleContext, ruleIndex int, actionIndex int) bool {
return true
}
func (b *BaseRecognizer) Precpred(localctx RuleContext, precedence int) bool {
return true
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// A rule context is a record of a single rule invocation. It knows
// which context invoked it, if any. If there is no parent context, then
// naturally the invoking state is not valid. The parent link
// provides a chain upwards from the current rule invocation to the root
// of the invocation tree, forming a stack. We actually carry no
// information about the rule associated with b context (except
// when parsing). We keep only the state number of the invoking state from
// the ATN submachine that invoked b. Contrast b with the s
// pointer inside ParserRuleContext that tracks the current state
// being "executed" for the current rule.
//
// The parent contexts are useful for computing lookahead sets and
// getting error information.
//
// These objects are used during parsing and prediction.
// For the special case of parsers, we use the subclass
// ParserRuleContext.
//
// @see ParserRuleContext
//
type RuleContext interface {
RuleNode
GetInvokingState() int
SetInvokingState(int)
GetRuleIndex() int
IsEmpty() bool
GetAltNumber() int
SetAltNumber(altNumber int)
String([]string, RuleContext) string
}
type BaseRuleContext struct {
parentCtx RuleContext
invokingState int
RuleIndex int
}
func NewBaseRuleContext(parent RuleContext, invokingState int) *BaseRuleContext {
rn := new(BaseRuleContext)
// What context invoked b rule?
rn.parentCtx = parent
// What state invoked the rule associated with b context?
// The "return address" is the followState of invokingState
// If parent is nil, b should be -1.
if parent == nil {
rn.invokingState = -1
} else {
rn.invokingState = invokingState
}
return rn
}
func (b *BaseRuleContext) GetBaseRuleContext() *BaseRuleContext {
return b
}
func (b *BaseRuleContext) SetParent(v Tree) {
if v == nil {
b.parentCtx = nil
} else {
b.parentCtx = v.(RuleContext)
}
}
func (b *BaseRuleContext) GetInvokingState() int {
return b.invokingState
}
func (b *BaseRuleContext) SetInvokingState(t int) {
b.invokingState = t
}
func (b *BaseRuleContext) GetRuleIndex() int {
return b.RuleIndex
}
func (b *BaseRuleContext) GetAltNumber() int {
return ATNInvalidAltNumber
}
func (b *BaseRuleContext) SetAltNumber(altNumber int) {}
// A context is empty if there is no invoking state meaning nobody call
// current context.
func (b *BaseRuleContext) IsEmpty() bool {
return b.invokingState == -1
}
// Return the combined text of all child nodes. This method only considers
// tokens which have been added to the parse tree.
// <p>
// Since tokens on hidden channels (e.g. whitespace or comments) are not
// added to the parse trees, they will not appear in the output of b
// method.
//
func (b *BaseRuleContext) GetParent() Tree {
return b.parentCtx
}

View File

@@ -0,0 +1,455 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
// A tree structure used to record the semantic context in which
// an ATN configuration is valid. It's either a single predicate,
// a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}.
//
// <p>I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of
// {@link SemanticContext} within the scope of this outer class.</p>
//
type SemanticContext interface {
comparable
evaluate(parser Recognizer, outerContext RuleContext) bool
evalPrecedence(parser Recognizer, outerContext RuleContext) SemanticContext
hash() int
String() string
}
func SemanticContextandContext(a, b SemanticContext) SemanticContext {
if a == nil || a == SemanticContextNone {
return b
}
if b == nil || b == SemanticContextNone {
return a
}
result := NewAND(a, b)
if len(result.opnds) == 1 {
return result.opnds[0]
}
return result
}
func SemanticContextorContext(a, b SemanticContext) SemanticContext {
if a == nil {
return b
}
if b == nil {
return a
}
if a == SemanticContextNone || b == SemanticContextNone {
return SemanticContextNone
}
result := NewOR(a, b)
if len(result.opnds) == 1 {
return result.opnds[0]
}
return result
}
type Predicate struct {
ruleIndex int
predIndex int
isCtxDependent bool
}
func NewPredicate(ruleIndex, predIndex int, isCtxDependent bool) *Predicate {
p := new(Predicate)
p.ruleIndex = ruleIndex
p.predIndex = predIndex
p.isCtxDependent = isCtxDependent // e.g., $i ref in pred
return p
}
//The default {@link SemanticContext}, which is semantically equivalent to
//a predicate of the form {@code {true}?}.
var SemanticContextNone SemanticContext = NewPredicate(-1, -1, false)
func (p *Predicate) evalPrecedence(parser Recognizer, outerContext RuleContext) SemanticContext {
return p
}
func (p *Predicate) evaluate(parser Recognizer, outerContext RuleContext) bool {
var localctx RuleContext
if p.isCtxDependent {
localctx = outerContext
}
return parser.Sempred(localctx, p.ruleIndex, p.predIndex)
}
func (p *Predicate) equals(other interface{}) bool {
if p == other {
return true
} else if _, ok := other.(*Predicate); !ok {
return false
} else {
return p.ruleIndex == other.(*Predicate).ruleIndex &&
p.predIndex == other.(*Predicate).predIndex &&
p.isCtxDependent == other.(*Predicate).isCtxDependent
}
}
func (p *Predicate) hash() int {
return p.ruleIndex*43 + p.predIndex*47
}
func (p *Predicate) String() string {
return "{" + strconv.Itoa(p.ruleIndex) + ":" + strconv.Itoa(p.predIndex) + "}?"
}
type PrecedencePredicate struct {
precedence int
}
func NewPrecedencePredicate(precedence int) *PrecedencePredicate {
p := new(PrecedencePredicate)
p.precedence = precedence
return p
}
func (p *PrecedencePredicate) evaluate(parser Recognizer, outerContext RuleContext) bool {
return parser.Precpred(outerContext, p.precedence)
}
func (p *PrecedencePredicate) evalPrecedence(parser Recognizer, outerContext RuleContext) SemanticContext {
if parser.Precpred(outerContext, p.precedence) {
return SemanticContextNone
}
return nil
}
func (p *PrecedencePredicate) compareTo(other *PrecedencePredicate) int {
return p.precedence - other.precedence
}
func (p *PrecedencePredicate) equals(other interface{}) bool {
if p == other {
return true
} else if _, ok := other.(*PrecedencePredicate); !ok {
return false
} else {
return p.precedence == other.(*PrecedencePredicate).precedence
}
}
func (p *PrecedencePredicate) hash() int {
return p.precedence * 51
}
func (p *PrecedencePredicate) String() string {
return "{" + strconv.Itoa(p.precedence) + ">=prec}?"
}
func PrecedencePredicatefilterPrecedencePredicates(set *Set) []*PrecedencePredicate {
result := make([]*PrecedencePredicate, 0)
for _, v := range set.values() {
if c2, ok := v.(*PrecedencePredicate); ok {
result = append(result, c2)
}
}
return result
}
// A semantic context which is true whenever none of the contained contexts
// is false.`
type AND struct {
opnds []SemanticContext
}
func NewAND(a, b SemanticContext) *AND {
operands := NewSet(nil, nil)
if aa, ok := a.(*AND); ok {
for _, o := range aa.opnds {
operands.add(o)
}
} else {
operands.add(a)
}
if ba, ok := b.(*AND); ok {
for _, o := range ba.opnds {
operands.add(o)
}
} else {
operands.add(b)
}
precedencePredicates := PrecedencePredicatefilterPrecedencePredicates(operands)
if len(precedencePredicates) > 0 {
// interested in the transition with the lowest precedence
var reduced *PrecedencePredicate
for _, p := range precedencePredicates {
if reduced == nil || p.precedence < reduced.precedence {
reduced = p
}
}
operands.add(reduced)
}
vs := operands.values()
opnds := make([]SemanticContext, len(vs))
for i, v := range vs {
opnds[i] = v.(SemanticContext)
}
and := new(AND)
and.opnds = opnds
return and
}
func (a *AND) equals(other interface{}) bool {
if a == other {
return true
} else if _, ok := other.(*AND); !ok {
return false
} else {
for i, v := range other.(*AND).opnds {
if !a.opnds[i].equals(v) {
return false
}
}
return true
}
}
//
// {@inheritDoc}
//
// <p>
// The evaluation of predicates by a context is short-circuiting, but
// unordered.</p>
//
func (a *AND) evaluate(parser Recognizer, outerContext RuleContext) bool {
for i := 0; i < len(a.opnds); i++ {
if !a.opnds[i].evaluate(parser, outerContext) {
return false
}
}
return true
}
func (a *AND) evalPrecedence(parser Recognizer, outerContext RuleContext) SemanticContext {
differs := false
operands := make([]SemanticContext, 0)
for i := 0; i < len(a.opnds); i++ {
context := a.opnds[i]
evaluated := context.evalPrecedence(parser, outerContext)
differs = differs || (evaluated != context)
if evaluated == nil {
// The AND context is false if any element is false
return nil
} else if evaluated != SemanticContextNone {
// Reduce the result by Skipping true elements
operands = append(operands, evaluated)
}
}
if !differs {
return a
}
if len(operands) == 0 {
// all elements were true, so the AND context is true
return SemanticContextNone
}
var result SemanticContext
for _, o := range operands {
if result == nil {
result = o
} else {
result = SemanticContextandContext(result, o)
}
}
return result
}
func (a *AND) hash() int {
h := murmurInit(37) // Init with a value different from OR
for _, op := range a.opnds {
h = murmurUpdate(h, op.hash())
}
return murmurFinish(h, len(a.opnds))
}
func (a *OR) hash() int {
h := murmurInit(41) // Init with a value different from AND
for _, op := range a.opnds {
h = murmurUpdate(h, op.hash())
}
return murmurFinish(h, len(a.opnds))
}
func (a *AND) String() string {
s := ""
for _, o := range a.opnds {
s += "&& " + fmt.Sprint(o)
}
if len(s) > 3 {
return s[0:3]
}
return s
}
//
// A semantic context which is true whenever at least one of the contained
// contexts is true.
//
type OR struct {
opnds []SemanticContext
}
func NewOR(a, b SemanticContext) *OR {
operands := NewSet(nil, nil)
if aa, ok := a.(*OR); ok {
for _, o := range aa.opnds {
operands.add(o)
}
} else {
operands.add(a)
}
if ba, ok := b.(*OR); ok {
for _, o := range ba.opnds {
operands.add(o)
}
} else {
operands.add(b)
}
precedencePredicates := PrecedencePredicatefilterPrecedencePredicates(operands)
if len(precedencePredicates) > 0 {
// interested in the transition with the lowest precedence
var reduced *PrecedencePredicate
for _, p := range precedencePredicates {
if reduced == nil || p.precedence > reduced.precedence {
reduced = p
}
}
operands.add(reduced)
}
vs := operands.values()
opnds := make([]SemanticContext, len(vs))
for i, v := range vs {
opnds[i] = v.(SemanticContext)
}
o := new(OR)
o.opnds = opnds
return o
}
func (o *OR) equals(other interface{}) bool {
if o == other {
return true
} else if _, ok := other.(*OR); !ok {
return false
} else {
for i, v := range other.(*OR).opnds {
if !o.opnds[i].equals(v) {
return false
}
}
return true
}
}
// <p>
// The evaluation of predicates by o context is short-circuiting, but
// unordered.</p>
//
func (o *OR) evaluate(parser Recognizer, outerContext RuleContext) bool {
for i := 0; i < len(o.opnds); i++ {
if o.opnds[i].evaluate(parser, outerContext) {
return true
}
}
return false
}
func (o *OR) evalPrecedence(parser Recognizer, outerContext RuleContext) SemanticContext {
differs := false
operands := make([]SemanticContext, 0)
for i := 0; i < len(o.opnds); i++ {
context := o.opnds[i]
evaluated := context.evalPrecedence(parser, outerContext)
differs = differs || (evaluated != context)
if evaluated == SemanticContextNone {
// The OR context is true if any element is true
return SemanticContextNone
} else if evaluated != nil {
// Reduce the result by Skipping false elements
operands = append(operands, evaluated)
}
}
if !differs {
return o
}
if len(operands) == 0 {
// all elements were false, so the OR context is false
return nil
}
var result SemanticContext
for _, o := range operands {
if result == nil {
result = o
} else {
result = SemanticContextorContext(result, o)
}
}
return result
}
func (o *OR) String() string {
s := ""
for _, o := range o.opnds {
s += "|| " + fmt.Sprint(o)
}
if len(s) > 3 {
return s[0:3]
}
return s
}

View File

@@ -0,0 +1,210 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"strconv"
"strings"
)
type TokenSourceCharStreamPair struct {
tokenSource TokenSource
charStream CharStream
}
// A token has properties: text, type, line, character position in the line
// (so we can ignore tabs), token channel, index, and source from which
// we obtained this token.
type Token interface {
GetSource() *TokenSourceCharStreamPair
GetTokenType() int
GetChannel() int
GetStart() int
GetStop() int
GetLine() int
GetColumn() int
GetText() string
SetText(s string)
GetTokenIndex() int
SetTokenIndex(v int)
GetTokenSource() TokenSource
GetInputStream() CharStream
}
type BaseToken struct {
source *TokenSourceCharStreamPair
tokenType int // token type of the token
channel int // The parser ignores everything not on DEFAULT_CHANNEL
start int // optional return -1 if not implemented.
stop int // optional return -1 if not implemented.
tokenIndex int // from 0..n-1 of the token object in the input stream
line int // line=1..n of the 1st character
column int // beginning of the line at which it occurs, 0..n-1
text string // text of the token.
readOnly bool
}
const (
TokenInvalidType = 0
// During lookahead operations, this "token" signifies we hit rule end ATN state
// and did not follow it despite needing to.
TokenEpsilon = -2
TokenMinUserTokenType = 1
TokenEOF = -1
// All tokens go to the parser (unless Skip() is called in that rule)
// on a particular "channel". The parser tunes to a particular channel
// so that whitespace etc... can go to the parser on a "hidden" channel.
TokenDefaultChannel = 0
// Anything on different channel than DEFAULT_CHANNEL is not parsed
// by parser.
TokenHiddenChannel = 1
)
func (b *BaseToken) GetChannel() int {
return b.channel
}
func (b *BaseToken) GetStart() int {
return b.start
}
func (b *BaseToken) GetStop() int {
return b.stop
}
func (b *BaseToken) GetLine() int {
return b.line
}
func (b *BaseToken) GetColumn() int {
return b.column
}
func (b *BaseToken) GetTokenType() int {
return b.tokenType
}
func (b *BaseToken) GetSource() *TokenSourceCharStreamPair {
return b.source
}
func (b *BaseToken) GetTokenIndex() int {
return b.tokenIndex
}
func (b *BaseToken) SetTokenIndex(v int) {
b.tokenIndex = v
}
func (b *BaseToken) GetTokenSource() TokenSource {
return b.source.tokenSource
}
func (b *BaseToken) GetInputStream() CharStream {
return b.source.charStream
}
type CommonToken struct {
*BaseToken
}
func NewCommonToken(source *TokenSourceCharStreamPair, tokenType, channel, start, stop int) *CommonToken {
t := new(CommonToken)
t.BaseToken = new(BaseToken)
t.source = source
t.tokenType = tokenType
t.channel = channel
t.start = start
t.stop = stop
t.tokenIndex = -1
if t.source.tokenSource != nil {
t.line = source.tokenSource.GetLine()
t.column = source.tokenSource.GetCharPositionInLine()
} else {
t.column = -1
}
return t
}
// An empty {@link Pair} which is used as the default value of
// {@link //source} for tokens that do not have a source.
//CommonToken.EMPTY_SOURCE = [ nil, nil ]
// Constructs a New{@link CommonToken} as a copy of another {@link Token}.
//
// <p>
// If {@code oldToken} is also a {@link CommonToken} instance, the newly
// constructed token will share a reference to the {@link //text} field and
// the {@link Pair} stored in {@link //source}. Otherwise, {@link //text} will
// be assigned the result of calling {@link //GetText}, and {@link //source}
// will be constructed from the result of {@link Token//GetTokenSource} and
// {@link Token//GetInputStream}.</p>
//
// @param oldToken The token to copy.
//
func (c *CommonToken) clone() *CommonToken {
t := NewCommonToken(c.source, c.tokenType, c.channel, c.start, c.stop)
t.tokenIndex = c.GetTokenIndex()
t.line = c.GetLine()
t.column = c.GetColumn()
t.text = c.GetText()
return t
}
func (c *CommonToken) GetText() string {
if c.text != "" {
return c.text
}
input := c.GetInputStream()
if input == nil {
return ""
}
n := input.Size()
if c.start < n && c.stop < n {
return input.GetTextFromInterval(NewInterval(c.start, c.stop))
}
return "<EOF>"
}
func (c *CommonToken) SetText(text string) {
c.text = text
}
func (c *CommonToken) String() string {
txt := c.GetText()
if txt != "" {
txt = strings.Replace(txt, "\n", "\\n", -1)
txt = strings.Replace(txt, "\r", "\\r", -1)
txt = strings.Replace(txt, "\t", "\\t", -1)
} else {
txt = "<no text>"
}
var ch string
if c.channel > 0 {
ch = ",channel=" + strconv.Itoa(c.channel)
} else {
ch = ""
}
return "[@" + strconv.Itoa(c.tokenIndex) + "," + strconv.Itoa(c.start) + ":" + strconv.Itoa(c.stop) + "='" +
txt + "',<" + strconv.Itoa(c.tokenType) + ">" +
ch + "," + strconv.Itoa(c.line) + ":" + strconv.Itoa(c.column) + "]"
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type TokenSource interface {
NextToken() Token
Skip()
More()
GetLine() int
GetCharPositionInLine() int
GetInputStream() CharStream
GetSourceName() string
setTokenFactory(factory TokenFactory)
GetTokenFactory() TokenFactory
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
type TokenStream interface {
IntStream
LT(k int) Token
Get(index int) Token
GetTokenSource() TokenSource
SetTokenSource(TokenSource)
GetAllText() string
GetTextFromInterval(*Interval) string
GetTextFromRuleContext(RuleContext) string
GetTextFromTokens(Token, Token) string
}

View File

@@ -0,0 +1,649 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"bytes"
"fmt"
)
//
// Useful for rewriting out a buffered input token stream after doing some
// augmentation or other manipulations on it.
// <p>
// You can insert stuff, replace, and delete chunks. Note that the operations
// are done lazily--only if you convert the buffer to a {@link String} with
// {@link TokenStream#getText()}. This is very efficient because you are not
// moving data around all the time. As the buffer of tokens is converted to
// strings, the {@link #getText()} method(s) scan the input token stream and
// check to see if there is an operation at the current index. If so, the
// operation is done and then normal {@link String} rendering continues on the
// buffer. This is like having multiple Turing machine instruction streams
// (programs) operating on a single input tape. :)</p>
// <p>
// This rewriter makes no modifications to the token stream. It does not ask the
// stream to fill itself up nor does it advance the input cursor. The token
// stream {@link TokenStream#index()} will return the same value before and
// after any {@link #getText()} call.</p>
// <p>
// The rewriter only works on tokens that you have in the buffer and ignores the
// current input cursor. If you are buffering tokens on-demand, calling
// {@link #getText()} halfway through the input will only do rewrites for those
// tokens in the first half of the file.</p>
// <p>
// Since the operations are done lazily at {@link #getText}-time, operations do
// not screw up the token index values. That is, an insert operation at token
// index {@code i} does not change the index values for tokens
// {@code i}+1..n-1.</p>
// <p>
// Because operations never actually alter the buffer, you may always get the
// original token stream back without undoing anything. Since the instructions
// are queued up, you can easily simulate transactions and roll back any changes
// if there is an error just by removing instructions. For example,</p>
// <pre>
// CharStream input = new ANTLRFileStream("input");
// TLexer lex = new TLexer(input);
// CommonTokenStream tokens = new CommonTokenStream(lex);
// T parser = new T(tokens);
// TokenStreamRewriter rewriter = new TokenStreamRewriter(tokens);
// parser.startRule();
// </pre>
// <p>
// Then in the rules, you can execute (assuming rewriter is visible):</p>
// <pre>
// Token t,u;
// ...
// rewriter.insertAfter(t, "text to put after t");}
// rewriter.insertAfter(u, "text after u");}
// System.out.println(rewriter.getText());
// </pre>
// <p>
// You can also have multiple "instruction streams" and get multiple rewrites
// from a single pass over the input. Just name the instruction streams and use
// that name again when printing the buffer. This could be useful for generating
// a C file and also its header file--all from the same buffer:</p>
// <pre>
// rewriter.insertAfter("pass1", t, "text to put after t");}
// rewriter.insertAfter("pass2", u, "text after u");}
// System.out.println(rewriter.getText("pass1"));
// System.out.println(rewriter.getText("pass2"));
// </pre>
// <p>
// If you don't use named rewrite streams, a "default" stream is used as the
// first example shows.</p>
const(
Default_Program_Name = "default"
Program_Init_Size = 100
Min_Token_Index = 0
)
// Define the rewrite operation hierarchy
type RewriteOperation interface {
// Execute the rewrite operation by possibly adding to the buffer.
// Return the index of the next token to operate on.
Execute(buffer *bytes.Buffer) int
String() string
GetInstructionIndex() int
GetIndex() int
GetText() string
GetOpName() string
GetTokens() TokenStream
SetInstructionIndex(val int)
SetIndex(int)
SetText(string)
SetOpName(string)
SetTokens(TokenStream)
}
type BaseRewriteOperation struct {
//Current index of rewrites list
instruction_index int
//Token buffer index
index int
//Substitution text
text string
//Actual operation name
op_name string
//Pointer to token steam
tokens TokenStream
}
func (op *BaseRewriteOperation)GetInstructionIndex() int{
return op.instruction_index
}
func (op *BaseRewriteOperation)GetIndex() int{
return op.index
}
func (op *BaseRewriteOperation)GetText() string{
return op.text
}
func (op *BaseRewriteOperation)GetOpName() string{
return op.op_name
}
func (op *BaseRewriteOperation)GetTokens() TokenStream{
return op.tokens
}
func (op *BaseRewriteOperation)SetInstructionIndex(val int){
op.instruction_index = val
}
func (op *BaseRewriteOperation)SetIndex(val int) {
op.index = val
}
func (op *BaseRewriteOperation)SetText(val string){
op.text = val
}
func (op *BaseRewriteOperation)SetOpName(val string){
op.op_name = val
}
func (op *BaseRewriteOperation)SetTokens(val TokenStream) {
op.tokens = val
}
func (op *BaseRewriteOperation) Execute(buffer *bytes.Buffer) int{
return op.index
}
func (op *BaseRewriteOperation) String() string {
return fmt.Sprintf("<%s@%d:\"%s\">",
op.op_name,
op.tokens.Get(op.GetIndex()),
op.text,
)
}
type InsertBeforeOp struct {
BaseRewriteOperation
}
func NewInsertBeforeOp(index int, text string, stream TokenStream) *InsertBeforeOp{
return &InsertBeforeOp{BaseRewriteOperation:BaseRewriteOperation{
index:index,
text:text,
op_name:"InsertBeforeOp",
tokens:stream,
}}
}
func (op *InsertBeforeOp) Execute(buffer *bytes.Buffer) int{
buffer.WriteString(op.text)
if op.tokens.Get(op.index).GetTokenType() != TokenEOF{
buffer.WriteString(op.tokens.Get(op.index).GetText())
}
return op.index+1
}
func (op *InsertBeforeOp) String() string {
return op.BaseRewriteOperation.String()
}
// Distinguish between insert after/before to do the "insert afters"
// first and then the "insert befores" at same index. Implementation
// of "insert after" is "insert before index+1".
type InsertAfterOp struct {
BaseRewriteOperation
}
func NewInsertAfterOp(index int, text string, stream TokenStream) *InsertAfterOp{
return &InsertAfterOp{BaseRewriteOperation:BaseRewriteOperation{
index:index+1,
text:text,
tokens:stream,
}}
}
func (op *InsertAfterOp) Execute(buffer *bytes.Buffer) int {
buffer.WriteString(op.text)
if op.tokens.Get(op.index).GetTokenType() != TokenEOF{
buffer.WriteString(op.tokens.Get(op.index).GetText())
}
return op.index+1
}
func (op *InsertAfterOp) String() string {
return op.BaseRewriteOperation.String()
}
// I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
// instructions.
type ReplaceOp struct{
BaseRewriteOperation
LastIndex int
}
func NewReplaceOp(from, to int, text string, stream TokenStream)*ReplaceOp {
return &ReplaceOp{
BaseRewriteOperation:BaseRewriteOperation{
index:from,
text:text,
op_name:"ReplaceOp",
tokens:stream,
},
LastIndex:to,
}
}
func (op *ReplaceOp)Execute(buffer *bytes.Buffer) int{
if op.text != ""{
buffer.WriteString(op.text)
}
return op.LastIndex +1
}
func (op *ReplaceOp) String() string {
if op.text == "" {
return fmt.Sprintf("<DeleteOP@%d..%d>",
op.tokens.Get(op.index), op.tokens.Get(op.LastIndex))
}
return fmt.Sprintf("<ReplaceOp@%d..%d:\"%s\">",
op.tokens.Get(op.index), op.tokens.Get(op.LastIndex), op.text)
}
type TokenStreamRewriter struct {
//Our source stream
tokens TokenStream
// You may have multiple, named streams of rewrite operations.
// I'm calling these things "programs."
// Maps String (name) &rarr; rewrite (List)
programs map[string][]RewriteOperation
last_rewrite_token_indexes map[string]int
}
func NewTokenStreamRewriter(tokens TokenStream) *TokenStreamRewriter{
return &TokenStreamRewriter{
tokens: tokens,
programs: map[string][]RewriteOperation{
Default_Program_Name:make([]RewriteOperation,0, Program_Init_Size),
},
last_rewrite_token_indexes: map[string]int{},
}
}
func (tsr *TokenStreamRewriter) GetTokenStream() TokenStream{
return tsr.tokens
}
// Rollback the instruction stream for a program so that
// the indicated instruction (via instructionIndex) is no
// longer in the stream. UNTESTED!
func (tsr *TokenStreamRewriter) Rollback(program_name string, instruction_index int){
is, ok := tsr.programs[program_name]
if ok{
tsr.programs[program_name] = is[Min_Token_Index:instruction_index]
}
}
func (tsr *TokenStreamRewriter) RollbackDefault(instruction_index int){
tsr.Rollback(Default_Program_Name, instruction_index)
}
//Reset the program so that no instructions exist
func (tsr *TokenStreamRewriter) DeleteProgram(program_name string){
tsr.Rollback(program_name, Min_Token_Index) //TODO: double test on that cause lower bound is not included
}
func (tsr *TokenStreamRewriter) DeleteProgramDefault(){
tsr.DeleteProgram(Default_Program_Name)
}
func (tsr *TokenStreamRewriter) InsertAfter(program_name string, index int, text string){
// to insert after, just insert before next index (even if past end)
var op RewriteOperation = NewInsertAfterOp(index, text, tsr.tokens)
rewrites := tsr.GetProgram(program_name)
op.SetInstructionIndex(len(rewrites))
tsr.AddToProgram(program_name, op)
}
func (tsr *TokenStreamRewriter) InsertAfterDefault(index int, text string){
tsr.InsertAfter(Default_Program_Name, index, text)
}
func (tsr *TokenStreamRewriter) InsertAfterToken(program_name string, token Token, text string){
tsr.InsertAfter(program_name, token.GetTokenIndex(), text)
}
func (tsr* TokenStreamRewriter) InsertBefore(program_name string, index int, text string){
var op RewriteOperation = NewInsertBeforeOp(index, text, tsr.tokens)
rewrites := tsr.GetProgram(program_name)
op.SetInstructionIndex(len(rewrites))
tsr.AddToProgram(program_name, op)
}
func (tsr *TokenStreamRewriter) InsertBeforeDefault(index int, text string){
tsr.InsertBefore(Default_Program_Name, index, text)
}
func (tsr *TokenStreamRewriter) InsertBeforeToken(program_name string,token Token, text string){
tsr.InsertBefore(program_name, token.GetTokenIndex(), text)
}
func (tsr *TokenStreamRewriter) Replace(program_name string, from, to int, text string){
if from > to || from < 0 || to < 0 || to >= tsr.tokens.Size(){
panic(fmt.Sprintf("replace: range invalid: %d..%d(size=%d)",
from, to, tsr.tokens.Size()))
}
var op RewriteOperation = NewReplaceOp(from, to, text, tsr.tokens)
rewrites := tsr.GetProgram(program_name)
op.SetInstructionIndex(len(rewrites))
tsr.AddToProgram(program_name, op)
}
func (tsr *TokenStreamRewriter)ReplaceDefault(from, to int, text string) {
tsr.Replace(Default_Program_Name, from, to, text)
}
func (tsr *TokenStreamRewriter)ReplaceDefaultPos(index int, text string){
tsr.ReplaceDefault(index, index, text)
}
func (tsr *TokenStreamRewriter)ReplaceToken(program_name string, from, to Token, text string){
tsr.Replace(program_name, from.GetTokenIndex(), to.GetTokenIndex(), text)
}
func (tsr *TokenStreamRewriter)ReplaceTokenDefault(from, to Token, text string){
tsr.ReplaceToken(Default_Program_Name, from, to, text)
}
func (tsr *TokenStreamRewriter)ReplaceTokenDefaultPos(index Token, text string){
tsr.ReplaceTokenDefault(index, index, text)
}
func (tsr *TokenStreamRewriter)Delete(program_name string, from, to int){
tsr.Replace(program_name, from, to, "" )
}
func (tsr *TokenStreamRewriter)DeleteDefault(from, to int){
tsr.Delete(Default_Program_Name, from, to)
}
func (tsr *TokenStreamRewriter)DeleteDefaultPos(index int){
tsr.DeleteDefault(index,index)
}
func (tsr *TokenStreamRewriter)DeleteToken(program_name string, from, to Token) {
tsr.ReplaceToken(program_name, from, to, "")
}
func (tsr *TokenStreamRewriter)DeleteTokenDefault(from,to Token){
tsr.DeleteToken(Default_Program_Name, from, to)
}
func (tsr *TokenStreamRewriter)GetLastRewriteTokenIndex(program_name string)int {
i, ok := tsr.last_rewrite_token_indexes[program_name]
if !ok{
return -1
}
return i
}
func (tsr *TokenStreamRewriter)GetLastRewriteTokenIndexDefault()int{
return tsr.GetLastRewriteTokenIndex(Default_Program_Name)
}
func (tsr *TokenStreamRewriter)SetLastRewriteTokenIndex(program_name string, i int){
tsr.last_rewrite_token_indexes[program_name] = i
}
func (tsr *TokenStreamRewriter)InitializeProgram(name string)[]RewriteOperation{
is := make([]RewriteOperation, 0, Program_Init_Size)
tsr.programs[name] = is
return is
}
func (tsr *TokenStreamRewriter)AddToProgram(name string, op RewriteOperation){
is := tsr.GetProgram(name)
is = append(is, op)
tsr.programs[name] = is
}
func (tsr *TokenStreamRewriter)GetProgram(name string) []RewriteOperation {
is, ok := tsr.programs[name]
if !ok{
is = tsr.InitializeProgram(name)
}
return is
}
// Return the text from the original tokens altered per the
// instructions given to this rewriter.
func (tsr *TokenStreamRewriter)GetTextDefault() string{
return tsr.GetText(
Default_Program_Name,
NewInterval(0, tsr.tokens.Size()-1))
}
// Return the text from the original tokens altered per the
// instructions given to this rewriter.
func (tsr *TokenStreamRewriter)GetText(program_name string, interval *Interval) string {
rewrites := tsr.programs[program_name]
start := interval.Start
stop := interval.Stop
// ensure start/end are in range
stop = min(stop, tsr.tokens.Size()-1)
start = max(start,0)
if rewrites == nil || len(rewrites) == 0{
return tsr.tokens.GetTextFromInterval(interval) // no instructions to execute
}
buf := bytes.Buffer{}
// First, optimize instruction stream
indexToOp := reduceToSingleOperationPerIndex(rewrites)
// Walk buffer, executing instructions and emitting tokens
for i:=start; i<=stop && i<tsr.tokens.Size();{
op := indexToOp[i]
delete(indexToOp, i)// remove so any left have index size-1
t := tsr.tokens.Get(i)
if op == nil{
// no operation at that index, just dump token
if t.GetTokenType() != TokenEOF {buf.WriteString(t.GetText())}
i++ // move to next token
}else {
i = op.Execute(&buf)// execute operation and skip
}
}
// include stuff after end if it's last index in buffer
// So, if they did an insertAfter(lastValidIndex, "foo"), include
// foo if end==lastValidIndex.
if stop == tsr.tokens.Size()-1{
// Scan any remaining operations after last token
// should be included (they will be inserts).
for _, op := range indexToOp{
if op.GetIndex() >= tsr.tokens.Size()-1 {buf.WriteString(op.GetText())}
}
}
return buf.String()
}
// We need to combine operations and report invalid operations (like
// overlapping replaces that are not completed nested). Inserts to
// same index need to be combined etc... Here are the cases:
//
// I.i.u I.j.v leave alone, nonoverlapping
// I.i.u I.i.v combine: Iivu
//
// R.i-j.u R.x-y.v | i-j in x-y delete first R
// R.i-j.u R.i-j.v delete first R
// R.i-j.u R.x-y.v | x-y in i-j ERROR
// R.i-j.u R.x-y.v | boundaries overlap ERROR
//
// Delete special case of replace (text==null):
// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
//
// I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before
// we're not deleting i)
// I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping
// R.x-y.v I.i.u | i in x-y ERROR
// R.x-y.v I.x.u R.x-y.uv (combine, delete I)
// R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping
//
// I.i.u = insert u before op @ index i
// R.x-y.u = replace x-y indexed tokens with u
//
// First we need to examine replaces. For any replace op:
//
// 1. wipe out any insertions before op within that range.
// 2. Drop any replace op before that is contained completely within
// that range.
// 3. Throw exception upon boundary overlap with any previous replace.
//
// Then we can deal with inserts:
//
// 1. for any inserts to same index, combine even if not adjacent.
// 2. for any prior replace with same left boundary, combine this
// insert with replace and delete this replace.
// 3. throw exception if index in same range as previous replace
//
// Don't actually delete; make op null in list. Easier to walk list.
// Later we can throw as we add to index &rarr; op map.
//
// Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
// inserted stuff would be before the replace range. But, if you
// add tokens in front of a method body '{' and then delete the method
// body, I think the stuff before the '{' you added should disappear too.
//
// Return a map from token index to operation.
//
func reduceToSingleOperationPerIndex(rewrites []RewriteOperation) map[int]RewriteOperation{
// WALK REPLACES
for i:=0; i < len(rewrites); i++{
op := rewrites[i]
if op == nil{continue}
rop, ok := op.(*ReplaceOp)
if !ok{continue}
// Wipe prior inserts within range
for j:=0; j<i && j < len(rewrites); j++{
if iop, ok := rewrites[j].(*InsertBeforeOp);ok{
if iop.index == rop.index{
// E.g., insert before 2, delete 2..2; update replace
// text to include insert before, kill insert
rewrites[iop.instruction_index] = nil
if rop.text != ""{
rop.text = iop.text + rop.text
}else{
rop.text = iop.text
}
}else if iop.index > rop.index && iop.index <=rop.LastIndex{
// delete insert as it's a no-op.
rewrites[iop.instruction_index] = nil
}
}
}
// Drop any prior replaces contained within
for j:=0; j<i && j < len(rewrites); j++{
if prevop, ok := rewrites[j].(*ReplaceOp);ok{
if prevop.index>=rop.index && prevop.LastIndex <= rop.LastIndex{
// delete replace as it's a no-op.
rewrites[prevop.instruction_index] = nil
continue
}
// throw exception unless disjoint or identical
disjoint := prevop.LastIndex < rop.index || prevop.index > rop.LastIndex
// Delete special case of replace (text==null):
// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
if prevop.text == "" && rop.text == "" && !disjoint{
rewrites[prevop.instruction_index] = nil
rop.index = min(prevop.index, rop.index)
rop.LastIndex = max(prevop.LastIndex, rop.LastIndex)
println("new rop" + rop.String()) //TODO: remove console write, taken from Java version
}else if !disjoint{
panic("replace op boundaries of " + rop.String() + " overlap with previous " + prevop.String())
}
}
}
}
// WALK INSERTS
for i:=0; i < len(rewrites); i++ {
op := rewrites[i]
if op == nil{continue}
//hack to replicate inheritance in composition
_, iok := rewrites[i].(*InsertBeforeOp)
_, aok := rewrites[i].(*InsertAfterOp)
if !iok && !aok{continue}
iop := rewrites[i]
// combine current insert with prior if any at same index
// deviating a bit from TokenStreamRewriter.java - hard to incorporate inheritance logic
for j:=0; j<i && j < len(rewrites); j++{
if nextIop, ok := rewrites[j].(*InsertAfterOp); ok{
if nextIop.index == iop.GetIndex(){
iop.SetText(nextIop.text + iop.GetText())
rewrites[j] = nil
}
}
if prevIop, ok := rewrites[j].(*InsertBeforeOp); ok{
if prevIop.index == iop.GetIndex(){
iop.SetText(iop.GetText() + prevIop.text)
rewrites[prevIop.instruction_index] = nil
}
}
}
// look for replaces where iop.index is in range; error
for j:=0; j<i && j < len(rewrites); j++{
if rop,ok := rewrites[j].(*ReplaceOp); ok{
if iop.GetIndex() == rop.index{
rop.text = iop.GetText() + rop.text
rewrites[i] = nil
continue
}
if iop.GetIndex() >= rop.index && iop.GetIndex() <= rop.LastIndex{
panic("insert op "+iop.String()+" within boundaries of previous "+rop.String())
}
}
}
}
m := map[int]RewriteOperation{}
for i:=0; i < len(rewrites); i++{
op := rewrites[i]
if op == nil {continue}
if _, ok := m[op.GetIndex()]; ok{
panic("should only be one op per index")
}
m[op.GetIndex()] = op
}
return m
}
/*
Quick fixing Go lack of overloads
*/
func max(a,b int)int{
if a>b{
return a
}else {
return b
}
}
func min(a,b int)int{
if a<b{
return a
}else {
return b
}
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import "fmt"
type TraceListener struct {
parser *BaseParser
}
func NewTraceListener(parser *BaseParser) *TraceListener {
tl := new(TraceListener)
tl.parser = parser
return tl
}
func (t *TraceListener) VisitErrorNode(_ ErrorNode) {
}
func (t *TraceListener) EnterEveryRule(ctx ParserRuleContext) {
fmt.Println("enter " + t.parser.GetRuleNames()[ctx.GetRuleIndex()] + ", LT(1)=" + t.parser.input.LT(1).GetText())
}
func (t *TraceListener) VisitTerminal(node TerminalNode) {
fmt.Println("consume " + fmt.Sprint(node.GetSymbol()) + " rule " + t.parser.GetRuleNames()[t.parser.ctx.GetRuleIndex()])
}
func (t *TraceListener) ExitEveryRule(ctx ParserRuleContext) {
fmt.Println("exit " + t.parser.GetRuleNames()[ctx.GetRuleIndex()] + ", LT(1)=" + t.parser.input.LT(1).GetText())
}

View File

@@ -0,0 +1,421 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"fmt"
"strconv"
)
// atom, set, epsilon, action, predicate, rule transitions.
//
// <p>This is a one way link. It emanates from a state (usually via a list of
// transitions) and has a target state.</p>
//
// <p>Since we never have to change the ATN transitions once we construct it,
// the states. We'll use the term Edge for the DFA to distinguish them from
// ATN transitions.</p>
type Transition interface {
getTarget() ATNState
setTarget(ATNState)
getIsEpsilon() bool
getLabel() *IntervalSet
getSerializationType() int
Matches(int, int, int) bool
}
type BaseTransition struct {
target ATNState
isEpsilon bool
label int
intervalSet *IntervalSet
serializationType int
}
func NewBaseTransition(target ATNState) *BaseTransition {
if target == nil {
panic("target cannot be nil.")
}
t := new(BaseTransition)
t.target = target
// Are we epsilon, action, sempred?
t.isEpsilon = false
t.intervalSet = nil
return t
}
func (t *BaseTransition) getTarget() ATNState {
return t.target
}
func (t *BaseTransition) setTarget(s ATNState) {
t.target = s
}
func (t *BaseTransition) getIsEpsilon() bool {
return t.isEpsilon
}
func (t *BaseTransition) getLabel() *IntervalSet {
return t.intervalSet
}
func (t *BaseTransition) getSerializationType() int {
return t.serializationType
}
func (t *BaseTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
panic("Not implemented")
}
const (
TransitionEPSILON = 1
TransitionRANGE = 2
TransitionRULE = 3
TransitionPREDICATE = 4 // e.g., {isType(input.LT(1))}?
TransitionATOM = 5
TransitionACTION = 6
TransitionSET = 7 // ~(A|B) or ~atom, wildcard, which convert to next 2
TransitionNOTSET = 8
TransitionWILDCARD = 9
TransitionPRECEDENCE = 10
)
var TransitionserializationNames = []string{
"INVALID",
"EPSILON",
"RANGE",
"RULE",
"PREDICATE",
"ATOM",
"ACTION",
"SET",
"NOT_SET",
"WILDCARD",
"PRECEDENCE",
}
//var TransitionserializationTypes struct {
// EpsilonTransition int
// RangeTransition int
// RuleTransition int
// PredicateTransition int
// AtomTransition int
// ActionTransition int
// SetTransition int
// NotSetTransition int
// WildcardTransition int
// PrecedencePredicateTransition int
//}{
// TransitionEPSILON,
// TransitionRANGE,
// TransitionRULE,
// TransitionPREDICATE,
// TransitionATOM,
// TransitionACTION,
// TransitionSET,
// TransitionNOTSET,
// TransitionWILDCARD,
// TransitionPRECEDENCE
//}
// TODO: make all transitions sets? no, should remove set edges
type AtomTransition struct {
*BaseTransition
}
func NewAtomTransition(target ATNState, intervalSet int) *AtomTransition {
t := new(AtomTransition)
t.BaseTransition = NewBaseTransition(target)
t.label = intervalSet // The token type or character value or, signifies special intervalSet.
t.intervalSet = t.makeLabel()
t.serializationType = TransitionATOM
return t
}
func (t *AtomTransition) makeLabel() *IntervalSet {
s := NewIntervalSet()
s.addOne(t.label)
return s
}
func (t *AtomTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return t.label == symbol
}
func (t *AtomTransition) String() string {
return strconv.Itoa(t.label)
}
type RuleTransition struct {
*BaseTransition
followState ATNState
ruleIndex, precedence int
}
func NewRuleTransition(ruleStart ATNState, ruleIndex, precedence int, followState ATNState) *RuleTransition {
t := new(RuleTransition)
t.BaseTransition = NewBaseTransition(ruleStart)
t.ruleIndex = ruleIndex
t.precedence = precedence
t.followState = followState
t.serializationType = TransitionRULE
t.isEpsilon = true
return t
}
func (t *RuleTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return false
}
type EpsilonTransition struct {
*BaseTransition
outermostPrecedenceReturn int
}
func NewEpsilonTransition(target ATNState, outermostPrecedenceReturn int) *EpsilonTransition {
t := new(EpsilonTransition)
t.BaseTransition = NewBaseTransition(target)
t.serializationType = TransitionEPSILON
t.isEpsilon = true
t.outermostPrecedenceReturn = outermostPrecedenceReturn
return t
}
func (t *EpsilonTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return false
}
func (t *EpsilonTransition) String() string {
return "epsilon"
}
type RangeTransition struct {
*BaseTransition
start, stop int
}
func NewRangeTransition(target ATNState, start, stop int) *RangeTransition {
t := new(RangeTransition)
t.BaseTransition = NewBaseTransition(target)
t.serializationType = TransitionRANGE
t.start = start
t.stop = stop
t.intervalSet = t.makeLabel()
return t
}
func (t *RangeTransition) makeLabel() *IntervalSet {
s := NewIntervalSet()
s.addRange(t.start, t.stop)
return s
}
func (t *RangeTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return symbol >= t.start && symbol <= t.stop
}
func (t *RangeTransition) String() string {
return "'" + string(t.start) + "'..'" + string(t.stop) + "'"
}
type AbstractPredicateTransition interface {
Transition
IAbstractPredicateTransitionFoo()
}
type BaseAbstractPredicateTransition struct {
*BaseTransition
}
func NewBasePredicateTransition(target ATNState) *BaseAbstractPredicateTransition {
t := new(BaseAbstractPredicateTransition)
t.BaseTransition = NewBaseTransition(target)
return t
}
func (a *BaseAbstractPredicateTransition) IAbstractPredicateTransitionFoo() {}
type PredicateTransition struct {
*BaseAbstractPredicateTransition
isCtxDependent bool
ruleIndex, predIndex int
}
func NewPredicateTransition(target ATNState, ruleIndex, predIndex int, isCtxDependent bool) *PredicateTransition {
t := new(PredicateTransition)
t.BaseAbstractPredicateTransition = NewBasePredicateTransition(target)
t.serializationType = TransitionPREDICATE
t.ruleIndex = ruleIndex
t.predIndex = predIndex
t.isCtxDependent = isCtxDependent // e.g., $i ref in pred
t.isEpsilon = true
return t
}
func (t *PredicateTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return false
}
func (t *PredicateTransition) getPredicate() *Predicate {
return NewPredicate(t.ruleIndex, t.predIndex, t.isCtxDependent)
}
func (t *PredicateTransition) String() string {
return "pred_" + strconv.Itoa(t.ruleIndex) + ":" + strconv.Itoa(t.predIndex)
}
type ActionTransition struct {
*BaseTransition
isCtxDependent bool
ruleIndex, actionIndex, predIndex int
}
func NewActionTransition(target ATNState, ruleIndex, actionIndex int, isCtxDependent bool) *ActionTransition {
t := new(ActionTransition)
t.BaseTransition = NewBaseTransition(target)
t.serializationType = TransitionACTION
t.ruleIndex = ruleIndex
t.actionIndex = actionIndex
t.isCtxDependent = isCtxDependent // e.g., $i ref in pred
t.isEpsilon = true
return t
}
func (t *ActionTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return false
}
func (t *ActionTransition) String() string {
return "action_" + strconv.Itoa(t.ruleIndex) + ":" + strconv.Itoa(t.actionIndex)
}
type SetTransition struct {
*BaseTransition
}
func NewSetTransition(target ATNState, set *IntervalSet) *SetTransition {
t := new(SetTransition)
t.BaseTransition = NewBaseTransition(target)
t.serializationType = TransitionSET
if set != nil {
t.intervalSet = set
} else {
t.intervalSet = NewIntervalSet()
t.intervalSet.addOne(TokenInvalidType)
}
return t
}
func (t *SetTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return t.intervalSet.contains(symbol)
}
func (t *SetTransition) String() string {
return t.intervalSet.String()
}
type NotSetTransition struct {
*SetTransition
}
func NewNotSetTransition(target ATNState, set *IntervalSet) *NotSetTransition {
t := new(NotSetTransition)
t.SetTransition = NewSetTransition(target, set)
t.serializationType = TransitionNOTSET
return t
}
func (t *NotSetTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol && !t.intervalSet.contains(symbol)
}
func (t *NotSetTransition) String() string {
return "~" + t.intervalSet.String()
}
type WildcardTransition struct {
*BaseTransition
}
func NewWildcardTransition(target ATNState) *WildcardTransition {
t := new(WildcardTransition)
t.BaseTransition = NewBaseTransition(target)
t.serializationType = TransitionWILDCARD
return t
}
func (t *WildcardTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return symbol >= minVocabSymbol && symbol <= maxVocabSymbol
}
func (t *WildcardTransition) String() string {
return "."
}
type PrecedencePredicateTransition struct {
*BaseAbstractPredicateTransition
precedence int
}
func NewPrecedencePredicateTransition(target ATNState, precedence int) *PrecedencePredicateTransition {
t := new(PrecedencePredicateTransition)
t.BaseAbstractPredicateTransition = NewBasePredicateTransition(target)
t.serializationType = TransitionPRECEDENCE
t.precedence = precedence
t.isEpsilon = true
return t
}
func (t *PrecedencePredicateTransition) Matches(symbol, minVocabSymbol, maxVocabSymbol int) bool {
return false
}
func (t *PrecedencePredicateTransition) getPredicate() *PrecedencePredicate {
return NewPrecedencePredicate(t.precedence)
}
func (t *PrecedencePredicateTransition) String() string {
return fmt.Sprint(t.precedence) + " >= _p"
}

256
vendor/github.com/antlr/antlr4/runtime/Go/antlr/tree.go generated vendored Normal file
View File

@@ -0,0 +1,256 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
// The basic notion of a tree has a parent, a payload, and a list of children.
// It is the most abstract interface for all the trees used by ANTLR.
///
var TreeInvalidInterval = NewInterval(-1, -2)
type Tree interface {
GetParent() Tree
SetParent(Tree)
GetPayload() interface{}
GetChild(i int) Tree
GetChildCount() int
GetChildren() []Tree
}
type SyntaxTree interface {
Tree
GetSourceInterval() *Interval
}
type ParseTree interface {
SyntaxTree
Accept(Visitor ParseTreeVisitor) interface{}
GetText() string
ToStringTree([]string, Recognizer) string
}
type RuleNode interface {
ParseTree
GetRuleContext() RuleContext
GetBaseRuleContext() *BaseRuleContext
}
type TerminalNode interface {
ParseTree
GetSymbol() Token
}
type ErrorNode interface {
TerminalNode
errorNode()
}
type ParseTreeVisitor interface {
Visit(tree ParseTree) interface{}
VisitChildren(node RuleNode) interface{}
VisitTerminal(node TerminalNode) interface{}
VisitErrorNode(node ErrorNode) interface{}
}
type BaseParseTreeVisitor struct{}
var _ ParseTreeVisitor = &BaseParseTreeVisitor{}
func (v *BaseParseTreeVisitor) Visit(tree ParseTree) interface{} { return nil }
func (v *BaseParseTreeVisitor) VisitChildren(node RuleNode) interface{} { return nil }
func (v *BaseParseTreeVisitor) VisitTerminal(node TerminalNode) interface{} { return nil }
func (v *BaseParseTreeVisitor) VisitErrorNode(node ErrorNode) interface{} { return nil }
// TODO
//func (this ParseTreeVisitor) Visit(ctx) {
// if (Utils.isArray(ctx)) {
// self := this
// return ctx.map(function(child) { return VisitAtom(self, child)})
// } else {
// return VisitAtom(this, ctx)
// }
//}
//
//func VisitAtom(Visitor, ctx) {
// if (ctx.parser == nil) { //is terminal
// return
// }
//
// name := ctx.parser.ruleNames[ctx.ruleIndex]
// funcName := "Visit" + Utils.titleCase(name)
//
// return Visitor[funcName](ctx)
//}
type ParseTreeListener interface {
VisitTerminal(node TerminalNode)
VisitErrorNode(node ErrorNode)
EnterEveryRule(ctx ParserRuleContext)
ExitEveryRule(ctx ParserRuleContext)
}
type BaseParseTreeListener struct{}
var _ ParseTreeListener = &BaseParseTreeListener{}
func (l *BaseParseTreeListener) VisitTerminal(node TerminalNode) {}
func (l *BaseParseTreeListener) VisitErrorNode(node ErrorNode) {}
func (l *BaseParseTreeListener) EnterEveryRule(ctx ParserRuleContext) {}
func (l *BaseParseTreeListener) ExitEveryRule(ctx ParserRuleContext) {}
type TerminalNodeImpl struct {
parentCtx RuleContext
symbol Token
}
var _ TerminalNode = &TerminalNodeImpl{}
func NewTerminalNodeImpl(symbol Token) *TerminalNodeImpl {
tn := new(TerminalNodeImpl)
tn.parentCtx = nil
tn.symbol = symbol
return tn
}
func (t *TerminalNodeImpl) GetChild(i int) Tree {
return nil
}
func (t *TerminalNodeImpl) GetChildren() []Tree {
return nil
}
func (t *TerminalNodeImpl) SetChildren(tree []Tree) {
panic("Cannot set children on terminal node")
}
func (t *TerminalNodeImpl) GetSymbol() Token {
return t.symbol
}
func (t *TerminalNodeImpl) GetParent() Tree {
return t.parentCtx
}
func (t *TerminalNodeImpl) SetParent(tree Tree) {
t.parentCtx = tree.(RuleContext)
}
func (t *TerminalNodeImpl) GetPayload() interface{} {
return t.symbol
}
func (t *TerminalNodeImpl) GetSourceInterval() *Interval {
if t.symbol == nil {
return TreeInvalidInterval
}
tokenIndex := t.symbol.GetTokenIndex()
return NewInterval(tokenIndex, tokenIndex)
}
func (t *TerminalNodeImpl) GetChildCount() int {
return 0
}
func (t *TerminalNodeImpl) Accept(v ParseTreeVisitor) interface{} {
return v.VisitTerminal(t)
}
func (t *TerminalNodeImpl) GetText() string {
return t.symbol.GetText()
}
func (t *TerminalNodeImpl) String() string {
if t.symbol.GetTokenType() == TokenEOF {
return "<EOF>"
}
return t.symbol.GetText()
}
func (t *TerminalNodeImpl) ToStringTree(s []string, r Recognizer) string {
return t.String()
}
// Represents a token that was consumed during reSynchronization
// rather than during a valid Match operation. For example,
// we will create this kind of a node during single token insertion
// and deletion as well as during "consume until error recovery set"
// upon no viable alternative exceptions.
type ErrorNodeImpl struct {
*TerminalNodeImpl
}
var _ ErrorNode = &ErrorNodeImpl{}
func NewErrorNodeImpl(token Token) *ErrorNodeImpl {
en := new(ErrorNodeImpl)
en.TerminalNodeImpl = NewTerminalNodeImpl(token)
return en
}
func (e *ErrorNodeImpl) errorNode() {}
func (e *ErrorNodeImpl) Accept(v ParseTreeVisitor) interface{} {
return v.VisitErrorNode(e)
}
type ParseTreeWalker struct {
}
func NewParseTreeWalker() *ParseTreeWalker {
return new(ParseTreeWalker)
}
// Performs a walk on the given parse tree starting at the root and going down recursively
// with depth-first search. On each node, EnterRule is called before
// recursively walking down into child nodes, then
// ExitRule is called after the recursive call to wind up.
func (p *ParseTreeWalker) Walk(listener ParseTreeListener, t Tree) {
switch tt := t.(type) {
case ErrorNode:
listener.VisitErrorNode(tt)
case TerminalNode:
listener.VisitTerminal(tt)
default:
p.EnterRule(listener, t.(RuleNode))
for i := 0; i < t.GetChildCount(); i++ {
child := t.GetChild(i)
p.Walk(listener, child)
}
p.ExitRule(listener, t.(RuleNode))
}
}
//
// Enters a grammar rule by first triggering the generic event {@link ParseTreeListener//EnterEveryRule}
// then by triggering the event specific to the given parse tree node
//
func (p *ParseTreeWalker) EnterRule(listener ParseTreeListener, r RuleNode) {
ctx := r.GetRuleContext().(ParserRuleContext)
listener.EnterEveryRule(ctx)
ctx.EnterRule(listener)
}
// Exits a grammar rule by first triggering the event specific to the given parse tree node
// then by triggering the generic event {@link ParseTreeListener//ExitEveryRule}
//
func (p *ParseTreeWalker) ExitRule(listener ParseTreeListener, r RuleNode) {
ctx := r.GetRuleContext().(ParserRuleContext)
ctx.ExitRule(listener)
listener.ExitEveryRule(ctx)
}
var ParseTreeWalkerDefault = NewParseTreeWalker()

View File

@@ -0,0 +1,137 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import "fmt"
/** A set of utility routines useful for all kinds of ANTLR trees. */
// Print out a whole tree in LISP form. {@link //getNodeText} is used on the
// node payloads to get the text for the nodes. Detect
// parse trees and extract data appropriately.
func TreesStringTree(tree Tree, ruleNames []string, recog Recognizer) string {
if recog != nil {
ruleNames = recog.GetRuleNames()
}
s := TreesGetNodeText(tree, ruleNames, nil)
s = EscapeWhitespace(s, false)
c := tree.GetChildCount()
if c == 0 {
return s
}
res := "(" + s + " "
if c > 0 {
s = TreesStringTree(tree.GetChild(0), ruleNames, nil)
res += s
}
for i := 1; i < c; i++ {
s = TreesStringTree(tree.GetChild(i), ruleNames, nil)
res += (" " + s)
}
res += ")"
return res
}
func TreesGetNodeText(t Tree, ruleNames []string, recog Parser) string {
if recog != nil {
ruleNames = recog.GetRuleNames()
}
if ruleNames != nil {
switch t2 := t.(type) {
case RuleNode:
t3 := t2.GetRuleContext()
altNumber := t3.GetAltNumber()
if altNumber != ATNInvalidAltNumber {
return fmt.Sprintf("%s:%d", ruleNames[t3.GetRuleIndex()], altNumber)
}
return ruleNames[t3.GetRuleIndex()]
case ErrorNode:
return fmt.Sprint(t2)
case TerminalNode:
if t2.GetSymbol() != nil {
return t2.GetSymbol().GetText()
}
}
}
// no recog for rule names
payload := t.GetPayload()
if p2, ok := payload.(Token); ok {
return p2.GetText()
}
return fmt.Sprint(t.GetPayload())
}
// Return ordered list of all children of this node
func TreesGetChildren(t Tree) []Tree {
list := make([]Tree, 0)
for i := 0; i < t.GetChildCount(); i++ {
list = append(list, t.GetChild(i))
}
return list
}
// Return a list of all ancestors of this node. The first node of
// list is the root and the last is the parent of this node.
//
func TreesgetAncestors(t Tree) []Tree {
ancestors := make([]Tree, 0)
t = t.GetParent()
for t != nil {
f := []Tree{t}
ancestors = append(f, ancestors...)
t = t.GetParent()
}
return ancestors
}
func TreesFindAllTokenNodes(t ParseTree, ttype int) []ParseTree {
return TreesfindAllNodes(t, ttype, true)
}
func TreesfindAllRuleNodes(t ParseTree, ruleIndex int) []ParseTree {
return TreesfindAllNodes(t, ruleIndex, false)
}
func TreesfindAllNodes(t ParseTree, index int, findTokens bool) []ParseTree {
nodes := make([]ParseTree, 0)
treesFindAllNodes(t, index, findTokens, &nodes)
return nodes
}
func treesFindAllNodes(t ParseTree, index int, findTokens bool, nodes *[]ParseTree) {
// check this node (the root) first
t2, ok := t.(TerminalNode)
t3, ok2 := t.(ParserRuleContext)
if findTokens && ok {
if t2.GetSymbol().GetTokenType() == index {
*nodes = append(*nodes, t2)
}
} else if !findTokens && ok2 {
if t3.GetRuleIndex() == index {
*nodes = append(*nodes, t3)
}
}
// check children
for i := 0; i < t.GetChildCount(); i++ {
treesFindAllNodes(t.GetChild(i).(ParseTree), index, findTokens, nodes)
}
}
func TreesDescendants(t ParseTree) []ParseTree {
nodes := []ParseTree{t}
for i := 0; i < t.GetChildCount(); i++ {
nodes = append(nodes, TreesDescendants(t.GetChild(i).(ParseTree))...)
}
return nodes
}

View File

@@ -0,0 +1,417 @@
// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
// Use of this file is governed by the BSD 3-clause license that
// can be found in the LICENSE.txt file in the project root.
package antlr
import (
"bytes"
"errors"
"fmt"
"sort"
"strconv"
"strings"
)
func intMin(a, b int) int {
if a < b {
return a
}
return b
}
func intMax(a, b int) int {
if a > b {
return a
}
return b
}
// A simple integer stack
type IntStack []int
var ErrEmptyStack = errors.New("Stack is empty")
func (s *IntStack) Pop() (int, error) {
l := len(*s) - 1
if l < 0 {
return 0, ErrEmptyStack
}
v := (*s)[l]
*s = (*s)[0:l]
return v, nil
}
func (s *IntStack) Push(e int) {
*s = append(*s, e)
}
type Set struct {
data map[int][]interface{}
hashcodeFunction func(interface{}) int
equalsFunction func(interface{}, interface{}) bool
}
func NewSet(
hashcodeFunction func(interface{}) int,
equalsFunction func(interface{}, interface{}) bool) *Set {
s := new(Set)
s.data = make(map[int][]interface{})
if hashcodeFunction != nil {
s.hashcodeFunction = hashcodeFunction
} else {
s.hashcodeFunction = standardHashFunction
}
if equalsFunction == nil {
s.equalsFunction = standardEqualsFunction
} else {
s.equalsFunction = equalsFunction
}
return s
}
func standardEqualsFunction(a interface{}, b interface{}) bool {
ac, oka := a.(comparable)
bc, okb := b.(comparable)
if !oka || !okb {
panic("Not Comparable")
}
return ac.equals(bc)
}
func standardHashFunction(a interface{}) int {
if h, ok := a.(hasher); ok {
return h.hash()
}
panic("Not Hasher")
}
type hasher interface {
hash() int
}
func (s *Set) length() int {
return len(s.data)
}
func (s *Set) add(value interface{}) interface{} {
key := s.hashcodeFunction(value)
values := s.data[key]
if s.data[key] != nil {
for i := 0; i < len(values); i++ {
if s.equalsFunction(value, values[i]) {
return values[i]
}
}
s.data[key] = append(s.data[key], value)
return value
}
v := make([]interface{}, 1, 10)
v[0] = value
s.data[key] = v
return value
}
func (s *Set) contains(value interface{}) bool {
key := s.hashcodeFunction(value)
values := s.data[key]
if s.data[key] != nil {
for i := 0; i < len(values); i++ {
if s.equalsFunction(value, values[i]) {
return true
}
}
}
return false
}
func (s *Set) values() []interface{} {
var l []interface{}
for _, v := range s.data {
l = append(l, v...)
}
return l
}
func (s *Set) String() string {
r := ""
for _, av := range s.data {
for _, v := range av {
r += fmt.Sprint(v)
}
}
return r
}
type BitSet struct {
data map[int]bool
}
func NewBitSet() *BitSet {
b := new(BitSet)
b.data = make(map[int]bool)
return b
}
func (b *BitSet) add(value int) {
b.data[value] = true
}
func (b *BitSet) clear(index int) {
delete(b.data, index)
}
func (b *BitSet) or(set *BitSet) {
for k := range set.data {
b.add(k)
}
}
func (b *BitSet) remove(value int) {
delete(b.data, value)
}
func (b *BitSet) contains(value int) bool {
return b.data[value]
}
func (b *BitSet) values() []int {
ks := make([]int, len(b.data))
i := 0
for k := range b.data {
ks[i] = k
i++
}
sort.Ints(ks)
return ks
}
func (b *BitSet) minValue() int {
min := 2147483647
for k := range b.data {
if k < min {
min = k
}
}
return min
}
func (b *BitSet) equals(other interface{}) bool {
otherBitSet, ok := other.(*BitSet)
if !ok {
return false
}
if len(b.data) != len(otherBitSet.data) {
return false
}
for k, v := range b.data {
if otherBitSet.data[k] != v {
return false
}
}
return true
}
func (b *BitSet) length() int {
return len(b.data)
}
func (b *BitSet) String() string {
vals := b.values()
valsS := make([]string, len(vals))
for i, val := range vals {
valsS[i] = strconv.Itoa(val)
}
return "{" + strings.Join(valsS, ", ") + "}"
}
type AltDict struct {
data map[string]interface{}
}
func NewAltDict() *AltDict {
d := new(AltDict)
d.data = make(map[string]interface{})
return d
}
func (a *AltDict) Get(key string) interface{} {
key = "k-" + key
return a.data[key]
}
func (a *AltDict) put(key string, value interface{}) {
key = "k-" + key
a.data[key] = value
}
func (a *AltDict) values() []interface{} {
vs := make([]interface{}, len(a.data))
i := 0
for _, v := range a.data {
vs[i] = v
i++
}
return vs
}
type DoubleDict struct {
data map[int]map[int]interface{}
}
func NewDoubleDict() *DoubleDict {
dd := new(DoubleDict)
dd.data = make(map[int]map[int]interface{})
return dd
}
func (d *DoubleDict) Get(a, b int) interface{} {
data := d.data[a]
if data == nil {
return nil
}
return data[b]
}
func (d *DoubleDict) set(a, b int, o interface{}) {
data := d.data[a]
if data == nil {
data = make(map[int]interface{})
d.data[a] = data
}
data[b] = o
}
func EscapeWhitespace(s string, escapeSpaces bool) string {
s = strings.Replace(s, "\t", "\\t", -1)
s = strings.Replace(s, "\n", "\\n", -1)
s = strings.Replace(s, "\r", "\\r", -1)
if escapeSpaces {
s = strings.Replace(s, " ", "\u00B7", -1)
}
return s
}
func TerminalNodeToStringArray(sa []TerminalNode) []string {
st := make([]string, len(sa))
for i, s := range sa {
st[i] = fmt.Sprintf("%v", s)
}
return st
}
func PrintArrayJavaStyle(sa []string) string {
var buffer bytes.Buffer
buffer.WriteString("[")
for i, s := range sa {
buffer.WriteString(s)
if i != len(sa)-1 {
buffer.WriteString(", ")
}
}
buffer.WriteString("]")
return buffer.String()
}
// The following routines were lifted from bits.rotate* available in Go 1.9.
const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
// rotateLeft returns the value of x rotated left by (k mod UintSize) bits.
// To rotate x right by k bits, call RotateLeft(x, -k).
func rotateLeft(x uint, k int) uint {
if uintSize == 32 {
return uint(rotateLeft32(uint32(x), k))
}
return uint(rotateLeft64(uint64(x), k))
}
// rotateLeft32 returns the value of x rotated left by (k mod 32) bits.
func rotateLeft32(x uint32, k int) uint32 {
const n = 32
s := uint(k) & (n - 1)
return x<<s | x>>(n-s)
}
// rotateLeft64 returns the value of x rotated left by (k mod 64) bits.
func rotateLeft64(x uint64, k int) uint64 {
const n = 64
s := uint(k) & (n - 1)
return x<<s | x>>(n-s)
}
// murmur hash
const (
c1_32 uint = 0xCC9E2D51
c2_32 uint = 0x1B873593
n1_32 uint = 0xE6546B64
)
func murmurInit(seed int) int {
return seed
}
func murmurUpdate(h1 int, k1 int) int {
var k1u uint
k1u = uint(k1) * c1_32
k1u = rotateLeft(k1u, 15)
k1u *= c2_32
var h1u = uint(h1) ^ k1u
k1u = rotateLeft(k1u, 13)
h1u = h1u*5 + 0xe6546b64
return int(h1u)
}
func murmurFinish(h1 int, numberOfWords int) int {
var h1u uint = uint(h1)
h1u ^= uint(numberOfWords * 4)
h1u ^= h1u >> 16
h1u *= uint(0x85ebca6b)
h1u ^= h1u >> 13
h1u *= 0xc2b2ae35
h1u ^= h1u >> 16
return int(h1u)
}

202
vendor/github.com/google/cel-go/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

64
vendor/github.com/google/cel-go/cel/BUILD.bazel generated vendored Normal file
View File

@@ -0,0 +1,64 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"cel.go",
"env.go",
"io.go",
"library.go",
"options.go",
"program.go",
],
importpath = "github.com/google/cel-go/cel",
visibility = ["//visibility:public"],
deps = [
"//checker:go_default_library",
"//checker/decls:go_default_library",
"//common:go_default_library",
"//common/containers:go_default_library",
"//common/types:go_default_library",
"//common/types/pb:go_default_library",
"//common/types/ref:go_default_library",
"//interpreter:go_default_library",
"//interpreter/functions:go_default_library",
"//parser:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//reflect/protoregistry:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
"@org_golang_google_protobuf//types/dynamicpb:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"cel_test.go",
],
data = [
"//cel/testdata:gen_test_fds",
],
embed = [
":go_default_library",
],
deps = [
"//checker/decls:go_default_library",
"//common/operators:go_default_library",
"//common/overloads:go_default_library",
"//common/types:go_default_library",
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"//interpreter/functions:go_default_library",
"//test/proto2pb:go_default_library",
"//test/proto3pb:go_default_library",
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)

19
vendor/github.com/google/cel-go/cel/cel.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
// Copyright 2019 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 cel defines the top-level interface for the Common Expression Language (CEL).
//
// CEL is a non-Turing complete expression language designed to parse, check, and evaluate
// expressions against user-defined environments.
package cel

466
vendor/github.com/google/cel-go/cel/env.go generated vendored Normal file
View File

@@ -0,0 +1,466 @@
// Copyright 2019 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 cel
import (
"errors"
"sync"
"github.com/google/cel-go/checker"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common"
"github.com/google/cel-go/common/containers"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter"
"github.com/google/cel-go/parser"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Source interface representing a user-provided expression.
type Source interface {
common.Source
}
// Ast representing the checked or unchecked expression, its source, and related metadata such as
// source position information.
type Ast struct {
expr *exprpb.Expr
info *exprpb.SourceInfo
source Source
refMap map[int64]*exprpb.Reference
typeMap map[int64]*exprpb.Type
}
// Expr returns the proto serializable instance of the parsed/checked expression.
func (ast *Ast) Expr() *exprpb.Expr {
return ast.expr
}
// IsChecked returns whether the Ast value has been successfully type-checked.
func (ast *Ast) IsChecked() bool {
return ast.typeMap != nil && len(ast.typeMap) > 0
}
// SourceInfo returns character offset and newling position information about expression elements.
func (ast *Ast) SourceInfo() *exprpb.SourceInfo {
return ast.info
}
// ResultType returns the output type of the expression if the Ast has been type-checked, else
// returns decls.Dyn as the parse step cannot infer the type.
func (ast *Ast) ResultType() *exprpb.Type {
if !ast.IsChecked() {
return decls.Dyn
}
return ast.typeMap[ast.expr.Id]
}
// Source returns a view of the input used to create the Ast. This source may be complete or
// constructed from the SourceInfo.
func (ast *Ast) Source() Source {
return ast.source
}
// FormatType converts a type message into a string representation.
func FormatType(t *exprpb.Type) string {
return checker.FormatCheckedType(t)
}
// Env encapsulates the context necessary to perform parsing, type checking, or generation of
// evaluable programs for different expressions.
type Env struct {
Container *containers.Container
declarations []*exprpb.Decl
macros []parser.Macro
adapter ref.TypeAdapter
provider ref.TypeProvider
features map[int]bool
// program options tied to the environment.
progOpts []ProgramOption
// Internal checker representation
chk *checker.Env
chkErr error
once sync.Once
}
// NewEnv creates a program environment configured with the standard library of CEL functions and
// macros. The Env value returned can parse and check any CEL program which builds upon the core
// features documented in the CEL specification.
//
// See the EnvOption helper functions for the options that can be used to configure the
// environment.
func NewEnv(opts ...EnvOption) (*Env, error) {
stdOpts := append([]EnvOption{StdLib()}, opts...)
return NewCustomEnv(stdOpts...)
}
// NewCustomEnv creates a custom program environment which is not automatically configured with the
// standard library of functions and macros documented in the CEL spec.
//
// The purpose for using a custom environment might be for subsetting the standard library produced
// by the cel.StdLib() function. Subsetting CEL is a core aspect of its design that allows users to
// limit the compute and memory impact of a CEL program by controlling the functions and macros
// that may appear in a given expression.
//
// See the EnvOption helper functions for the options that can be used to configure the
// environment.
func NewCustomEnv(opts ...EnvOption) (*Env, error) {
registry, err := types.NewRegistry()
if err != nil {
return nil, err
}
return (&Env{
declarations: []*exprpb.Decl{},
macros: []parser.Macro{},
Container: containers.DefaultContainer,
adapter: registry,
provider: registry,
features: map[int]bool{},
progOpts: []ProgramOption{},
}).configure(opts)
}
// Check performs type-checking on the input Ast and yields a checked Ast and/or set of Issues.
//
// Checking has failed if the returned Issues value and its Issues.Err() value are non-nil.
// Issues should be inspected if they are non-nil, but may not represent a fatal error.
//
// It is possible to have both non-nil Ast and Issues values returned from this call: however,
// the mere presence of an Ast does not imply that it is valid for use.
func (e *Env) Check(ast *Ast) (*Ast, *Issues) {
// Note, errors aren't currently possible on the Ast to ParsedExpr conversion.
pe, _ := AstToParsedExpr(ast)
// Construct the internal checker env, erroring if there is an issue adding the declarations.
e.once.Do(func() {
ce := checker.NewEnv(e.Container, e.provider)
ce.EnableDynamicAggregateLiterals(true)
if e.HasFeature(FeatureDisableDynamicAggregateLiterals) {
ce.EnableDynamicAggregateLiterals(false)
}
err := ce.Add(e.declarations...)
if err != nil {
e.chkErr = err
} else {
e.chk = ce
}
})
// The once call will ensure that this value is set or nil for all invocations.
if e.chkErr != nil {
errs := common.NewErrors(ast.Source())
errs.ReportError(common.NoLocation, e.chkErr.Error())
return nil, NewIssues(errs)
}
res, errs := checker.Check(pe, ast.Source(), e.chk)
if len(errs.GetErrors()) > 0 {
return nil, NewIssues(errs)
}
// Manually create the Ast to ensure that the Ast source information (which may be more
// detailed than the information provided by Check), is returned to the caller.
return &Ast{
source: ast.Source(),
expr: res.GetExpr(),
info: res.GetSourceInfo(),
refMap: res.GetReferenceMap(),
typeMap: res.GetTypeMap()}, nil
}
// Compile combines the Parse and Check phases CEL program compilation to produce an Ast and
// associated issues.
//
// If an error is encountered during parsing the Compile step will not continue with the Check
// phase. If non-error issues are encountered during Parse, they may be combined with any issues
// discovered during Check.
//
// Note, for parse-only uses of CEL use Parse.
func (e *Env) Compile(txt string) (*Ast, *Issues) {
return e.CompileSource(common.NewTextSource(txt))
}
// CompileSource combines the Parse and Check phases CEL program compilation to produce an Ast and
// associated issues.
//
// If an error is encountered during parsing the CompileSource step will not continue with the
// Check phase. If non-error issues are encountered during Parse, they may be combined with any
// issues discovered during Check.
//
// Note, for parse-only uses of CEL use Parse.
func (e *Env) CompileSource(src common.Source) (*Ast, *Issues) {
ast, iss := e.ParseSource(src)
if iss.Err() != nil {
return nil, iss
}
checked, iss2 := e.Check(ast)
iss = iss.Append(iss2)
if iss.Err() != nil {
return nil, iss
}
return checked, iss
}
// Extend the current environment with additional options to produce a new Env.
//
// Note, the extended Env value should not share memory with the original. It is possible, however,
// that a CustomTypeAdapter or CustomTypeProvider options could provide values which are mutable.
// To ensure separation of state between extended environments either make sure the TypeAdapter and
// TypeProvider are immutable, or that their underlying implementations are based on the
// ref.TypeRegistry which provides a Copy method which will be invoked by this method.
func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
if e.chkErr != nil {
return nil, e.chkErr
}
// Copy slices.
decsCopy := make([]*exprpb.Decl, len(e.declarations))
macsCopy := make([]parser.Macro, len(e.macros))
progOptsCopy := make([]ProgramOption, len(e.progOpts))
copy(decsCopy, e.declarations)
copy(macsCopy, e.macros)
copy(progOptsCopy, e.progOpts)
// Copy the adapter / provider if they appear to be mutable.
adapter := e.adapter
provider := e.provider
adapterReg, isAdapterReg := e.adapter.(ref.TypeRegistry)
providerReg, isProviderReg := e.provider.(ref.TypeRegistry)
// In most cases the provider and adapter will be a ref.TypeRegistry;
// however, in the rare cases where they are not, they are assumed to
// be immutable. Since it is possible to set the TypeProvider separately
// from the TypeAdapter, the possible configurations which could use a
// TypeRegistry as the base implementation are captured below.
if isAdapterReg && isProviderReg {
reg := providerReg.Copy()
provider = reg
// If the adapter and provider are the same object, set the adapter
// to the same ref.TypeRegistry as the provider.
if adapterReg == providerReg {
adapter = reg
} else {
// Otherwise, make a copy of the adapter.
adapter = adapterReg.Copy()
}
} else if isProviderReg {
provider = providerReg.Copy()
} else if isAdapterReg {
adapter = adapterReg.Copy()
}
featuresCopy := make(map[int]bool, len(e.features))
for k, v := range e.features {
featuresCopy[k] = v
}
ext := &Env{
Container: e.Container,
declarations: decsCopy,
macros: macsCopy,
progOpts: progOptsCopy,
adapter: adapter,
features: featuresCopy,
provider: provider,
}
return ext.configure(opts)
}
// HasFeature checks whether the environment enables the given feature
// flag, as enumerated in options.go.
func (e *Env) HasFeature(flag int) bool {
_, has := e.features[flag]
return has
}
// Parse parses the input expression value `txt` to a Ast and/or a set of Issues.
//
// This form of Parse creates a common.Source value for the input `txt` and forwards to the
// ParseSource method.
func (e *Env) Parse(txt string) (*Ast, *Issues) {
src := common.NewTextSource(txt)
return e.ParseSource(src)
}
// ParseSource parses the input source to an Ast and/or set of Issues.
//
// Parsing has failed if the returned Issues value and its Issues.Err() value is non-nil.
// Issues should be inspected if they are non-nil, but may not represent a fatal error.
//
// It is possible to have both non-nil Ast and Issues values returned from this call; however,
// the mere presence of an Ast does not imply that it is valid for use.
func (e *Env) ParseSource(src common.Source) (*Ast, *Issues) {
res, errs := parser.ParseWithMacros(src, e.macros)
if len(errs.GetErrors()) > 0 {
return nil, &Issues{errs: errs}
}
// Manually create the Ast to ensure that the text source information is propagated on
// subsequent calls to Check.
return &Ast{
source: Source(src),
expr: res.GetExpr(),
info: res.GetSourceInfo()}, nil
}
// Program generates an evaluable instance of the Ast within the environment (Env).
func (e *Env) Program(ast *Ast, opts ...ProgramOption) (Program, error) {
optSet := e.progOpts
if len(opts) != 0 {
mergedOpts := []ProgramOption{}
mergedOpts = append(mergedOpts, e.progOpts...)
mergedOpts = append(mergedOpts, opts...)
optSet = mergedOpts
}
return newProgram(e, ast, optSet)
}
// SetFeature sets the given feature flag, as enumerated in options.go.
func (e *Env) SetFeature(flag int) {
e.features[flag] = true
}
// TypeAdapter returns the `ref.TypeAdapter` configured for the environment.
func (e *Env) TypeAdapter() ref.TypeAdapter {
return e.adapter
}
// TypeProvider returns the `ref.TypeProvider` configured for the environment.
func (e *Env) TypeProvider() ref.TypeProvider {
return e.provider
}
// UnknownVars returns an interpreter.PartialActivation which marks all variables
// declared in the Env as unknown AttributePattern values.
//
// Note, the UnknownVars will behave the same as an interpreter.EmptyActivation
// unless the PartialAttributes option is provided as a ProgramOption.
func (e *Env) UnknownVars() interpreter.PartialActivation {
var unknownPatterns []*interpreter.AttributePattern
for _, d := range e.declarations {
switch d.GetDeclKind().(type) {
case *exprpb.Decl_Ident:
unknownPatterns = append(unknownPatterns,
interpreter.NewAttributePattern(d.GetName()))
}
}
part, _ := PartialVars(
interpreter.EmptyActivation(),
unknownPatterns...)
return part
}
// ResidualAst takes an Ast and its EvalDetails to produce a new Ast which only contains the
// attribute references which are unknown.
//
// Residual expressions are beneficial in a few scenarios:
//
// - Optimizing constant expression evaluations away.
// - Indexing and pruning expressions based on known input arguments.
// - Surfacing additional requirements that are needed in order to complete an evaluation.
// - Sharing the evaluation of an expression across multiple machines/nodes.
//
// For example, if an expression targets a 'resource' and 'request' attribute and the possible
// values for the resource are known, a PartialActivation could mark the 'request' as an unknown
// interpreter.AttributePattern and the resulting ResidualAst would be reduced to only the parts
// of the expression that reference the 'request'.
//
// Note, the expression ids within the residual AST generated through this method have no
// correlation to the expression ids of the original AST.
//
// See the PartialVars helper for how to construct a PartialActivation.
//
// TODO: Consider adding an option to generate a Program.Residual to avoid round-tripping to an
// Ast format and then Program again.
func (e *Env) ResidualAst(a *Ast, details *EvalDetails) (*Ast, error) {
pruned := interpreter.PruneAst(a.Expr(), details.State())
expr, err := AstToString(ParsedExprToAst(&exprpb.ParsedExpr{Expr: pruned}))
if err != nil {
return nil, err
}
parsed, iss := e.Parse(expr)
if iss != nil && iss.Err() != nil {
return nil, iss.Err()
}
if !a.IsChecked() {
return parsed, nil
}
checked, iss := e.Check(parsed)
if iss != nil && iss.Err() != nil {
return nil, iss.Err()
}
return checked, nil
}
// configure applies a series of EnvOptions to the current environment.
func (e *Env) configure(opts []EnvOption) (*Env, error) {
// Customized the environment using the provided EnvOption values. If an error is
// generated at any step this, will be returned as a nil Env with a non-nil error.
var err error
for _, opt := range opts {
e, err = opt(e)
if err != nil {
return nil, err
}
}
return e, nil
}
// Issues defines methods for inspecting the error details of parse and check calls.
//
// Note: in the future, non-fatal warnings and notices may be inspectable via the Issues struct.
type Issues struct {
errs *common.Errors
}
// NewIssues returns an Issues struct from a common.Errors object.
func NewIssues(errs *common.Errors) *Issues {
return &Issues{
errs: errs,
}
}
// Err returns an error value if the issues list contains one or more errors.
func (i *Issues) Err() error {
if i == nil {
return nil
}
if len(i.Errors()) > 0 {
return errors.New(i.String())
}
return nil
}
// Errors returns the collection of errors encountered in more granular detail.
func (i *Issues) Errors() []common.Error {
if i == nil {
return []common.Error{}
}
return i.errs.GetErrors()
}
// Append collects the issues from another Issues struct into a new Issues object.
func (i *Issues) Append(other *Issues) *Issues {
if i == nil {
return other
}
return NewIssues(i.errs.Append(other.errs.GetErrors()))
}
// String converts the issues to a suitable display string.
func (i *Issues) String() string {
if i == nil {
return ""
}
return i.errs.ToDisplayString()
}

122
vendor/github.com/google/cel-go/cel/io.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
// Copyright 2019 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 cel
import (
"fmt"
"github.com/google/cel-go/common"
"github.com/google/cel-go/parser"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// CheckedExprToAst converts a checked expression proto message to an Ast.
func CheckedExprToAst(checkedExpr *exprpb.CheckedExpr) *Ast {
return CheckedExprToAstWithSource(checkedExpr, nil)
}
// CheckedExprToAstWithSource converts a checked expression proto message to an Ast,
// using the provided Source as the textual contents.
//
// In general the source is not necessary unless the AST has been modified between the
// `Parse` and `Check` calls as an `Ast` created from the `Parse` step will carry the source
// through future calls.
//
// Prefer CheckedExprToAst if loading expressions from storage.
func CheckedExprToAstWithSource(checkedExpr *exprpb.CheckedExpr, src common.Source) *Ast {
refMap := checkedExpr.GetReferenceMap()
if refMap == nil {
refMap = map[int64]*exprpb.Reference{}
}
typeMap := checkedExpr.GetTypeMap()
if typeMap == nil {
typeMap = map[int64]*exprpb.Type{}
}
si := checkedExpr.GetSourceInfo()
if si == nil {
si = &exprpb.SourceInfo{}
}
if src == nil {
src = common.NewInfoSource(si)
}
return &Ast{
expr: checkedExpr.GetExpr(),
info: si,
source: src,
refMap: refMap,
typeMap: typeMap,
}
}
// AstToCheckedExpr converts an Ast to an protobuf CheckedExpr value.
//
// If the Ast.IsChecked() returns false, this conversion method will return an error.
func AstToCheckedExpr(a *Ast) (*exprpb.CheckedExpr, error) {
if !a.IsChecked() {
return nil, fmt.Errorf("cannot convert unchecked ast")
}
return &exprpb.CheckedExpr{
Expr: a.Expr(),
SourceInfo: a.SourceInfo(),
ReferenceMap: a.refMap,
TypeMap: a.typeMap,
}, nil
}
// ParsedExprToAst converts a parsed expression proto message to an Ast.
func ParsedExprToAst(parsedExpr *exprpb.ParsedExpr) *Ast {
return ParsedExprToAstWithSource(parsedExpr, nil)
}
// ParsedExprToAstWithSource converts a parsed expression proto message to an Ast,
// using the provided Source as the textual contents.
//
// In general you only need this if you need to recheck a previously checked
// expression, or if you need to separately check a subset of an expression.
//
// Prefer ParsedExprToAst if loading expressions from storage.
func ParsedExprToAstWithSource(parsedExpr *exprpb.ParsedExpr, src common.Source) *Ast {
si := parsedExpr.GetSourceInfo()
if si == nil {
si = &exprpb.SourceInfo{}
}
if src == nil {
src = common.NewInfoSource(si)
}
return &Ast{
expr: parsedExpr.GetExpr(),
info: si,
source: src,
}
}
// AstToParsedExpr converts an Ast to an protobuf ParsedExpr value.
func AstToParsedExpr(a *Ast) (*exprpb.ParsedExpr, error) {
return &exprpb.ParsedExpr{
Expr: a.Expr(),
SourceInfo: a.SourceInfo(),
}, nil
}
// AstToString converts an Ast back to a string if possible.
//
// Note, the conversion may not be an exact replica of the original expression, but will produce
// a string that is semantically equivalent and whose textual representation is stable.
func AstToString(a *Ast) (string, error) {
expr := a.Expr()
info := a.SourceInfo()
return parser.Unparse(expr, info)
}

77
vendor/github.com/google/cel-go/cel/library.go generated vendored Normal file
View File

@@ -0,0 +1,77 @@
// Copyright 2020 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 cel
import (
"github.com/google/cel-go/checker"
"github.com/google/cel-go/interpreter/functions"
"github.com/google/cel-go/parser"
)
// Library provides a collection of EnvOption and ProgramOption values used to confiugre a CEL
// environment for a particular use case or with a related set of functionality.
//
// Note, the ProgramOption values provided by a library are expected to be static and not vary
// between calls to Env.Program(). If there is a need for such dynamic configuration, prefer to
// configure these options outside the Library and within the Env.Program() call directly.
type Library interface {
// CompileOptions returns a collection of funcitional options for configuring the Parse / Check
// environment.
CompileOptions() []EnvOption
// ProgramOptions returns a collection of functional options which should be included in every
// Program generated from the Env.Program() call.
ProgramOptions() []ProgramOption
}
// Lib creates an EnvOption out of a Library, allowing libraries to be provided as functional args,
// and to be linked to each other.
func Lib(l Library) EnvOption {
return func(e *Env) (*Env, error) {
var err error
for _, opt := range l.CompileOptions() {
e, err = opt(e)
if err != nil {
return nil, err
}
}
e.progOpts = append(e.progOpts, l.ProgramOptions()...)
return e, nil
}
}
// StdLib returns an EnvOption for the standard library of CEL functions and macros.
func StdLib() EnvOption {
return Lib(stdLibrary{})
}
// stdLibrary implements the Library interface and provides functional options for the core CEL
// features documented in the specification.
type stdLibrary struct{}
// EnvOptions returns options for the standard CEL function declarations and macros.
func (stdLibrary) CompileOptions() []EnvOption {
return []EnvOption{
Declarations(checker.StandardDeclarations()...),
Macros(parser.AllMacros...),
}
}
// ProgramOptions returns function implementations for the standard CEL functions.
func (stdLibrary) ProgramOptions() []ProgramOption {
return []ProgramOption{
Functions(functions.StandardOverloads()...),
}
}

451
vendor/github.com/google/cel-go/cel/options.go generated vendored Normal file
View File

@@ -0,0 +1,451 @@
// Copyright 2019 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 cel
import (
"fmt"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/containers"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter"
"github.com/google/cel-go/interpreter/functions"
"github.com/google/cel-go/parser"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/dynamicpb"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
descpb "google.golang.org/protobuf/types/descriptorpb"
)
// These constants beginning with "Feature" enable optional behavior in
// the library. See the documentation for each constant to see its
// effects, compatibility restrictions, and standard conformance.
const (
_ = iota
// Disallow heterogeneous aggregate (list, map) literals.
// Note, it is still possible to have heterogeneous aggregates when
// provided as variables to the expression, as well as via conversion
// of well-known dynamic types, or with unchecked expressions.
// Affects checking. Provides a subset of standard behavior.
FeatureDisableDynamicAggregateLiterals
)
// EnvOption is a functional interface for configuring the environment.
type EnvOption func(e *Env) (*Env, error)
// ClearMacros options clears all parser macros.
//
// Clearing macros will ensure CEL expressions can only contain linear evaluation paths, as
// comprehensions such as `all` and `exists` are enabled only via macros.
func ClearMacros() EnvOption {
return func(e *Env) (*Env, error) {
e.macros = parser.NoMacros
return e, nil
}
}
// CustomTypeAdapter swaps the default ref.TypeAdapter implementation with a custom one.
//
// Note: This option must be specified before the Types and TypeDescs options when used together.
func CustomTypeAdapter(adapter ref.TypeAdapter) EnvOption {
return func(e *Env) (*Env, error) {
e.adapter = adapter
return e, nil
}
}
// CustomTypeProvider swaps the default ref.TypeProvider implementation with a custom one.
//
// Note: This option must be specified before the Types and TypeDescs options when used together.
func CustomTypeProvider(provider ref.TypeProvider) EnvOption {
return func(e *Env) (*Env, error) {
e.provider = provider
return e, nil
}
}
// Declarations option extends the declaration set configured in the environment.
//
// Note: Declarations will by default be appended to the pre-existing declaration set configured
// for the environment. The NewEnv call builds on top of the standard CEL declarations. For a
// purely custom set of declarations use NewCustomEnv.
func Declarations(decls ...*exprpb.Decl) EnvOption {
// TODO: provide an alternative means of specifying declarations that doesn't refer
// to the underlying proto implementations.
return func(e *Env) (*Env, error) {
e.declarations = append(e.declarations, decls...)
return e, nil
}
}
// Features sets the given feature flags. See list of Feature constants above.
func Features(flags ...int) EnvOption {
return func(e *Env) (*Env, error) {
for _, flag := range flags {
e.SetFeature(flag)
}
return e, nil
}
}
// HomogeneousAggregateLiterals option ensures that list and map literal entry types must agree
// during type-checking.
//
// Note, it is still possible to have heterogeneous aggregates when provided as variables to the
// expression, as well as via conversion of well-known dynamic types, or with unchecked
// expressions.
func HomogeneousAggregateLiterals() EnvOption {
return Features(FeatureDisableDynamicAggregateLiterals)
}
// Macros option extends the macro set configured in the environment.
//
// Note: This option must be specified after ClearMacros if used together.
func Macros(macros ...parser.Macro) EnvOption {
return func(e *Env) (*Env, error) {
e.macros = append(e.macros, macros...)
return e, nil
}
}
// Container sets the container for resolving variable names. Defaults to an empty container.
//
// If all references within an expression are relative to a protocol buffer package, then
// specifying a container of `google.type` would make it possible to write expressions such as
// `Expr{expression: 'a < b'}` instead of having to write `google.type.Expr{...}`.
func Container(name string) EnvOption {
return func(e *Env) (*Env, error) {
cont, err := e.Container.Extend(containers.Name(name))
if err != nil {
return nil, err
}
e.Container = cont
return e, nil
}
}
// Abbrevs configures a set of simple names as abbreviations for fully-qualified names.
//
// An abbreviation (abbrev for short) is a simple name that expands to a fully-qualified name.
// Abbreviations can be useful when working with variables, functions, and especially types from
// multiple namespaces:
//
// // CEL object construction
// qual.pkg.version.ObjTypeName{
// field: alt.container.ver.FieldTypeName{value: ...}
// }
//
// Only one the qualified names above may be used as the CEL container, so at least one of these
// references must be a long qualified name within an otherwise short CEL program. Using the
// following abbreviations, the program becomes much simpler:
//
// // CEL Go option
// Abbrevs("qual.pkg.version.ObjTypeName", "alt.container.ver.FieldTypeName")
// // Simplified Object construction
// ObjTypeName{field: FieldTypeName{value: ...}}
//
// There are a few rules for the qualified names and the simple abbreviations generated from them:
// - Qualified names must be dot-delimited, e.g. `package.subpkg.name`.
// - The last element in the qualified name is the abbreviation.
// - Abbreviations must not collide with each other.
// - The abbreviation must not collide with unqualified names in use.
//
// Abbreviations are distinct from container-based references in the following important ways:
// - Abbreviations must expand to a fully-qualified name.
// - Expanded abbreviations do not participate in namespace resolution.
// - Abbreviation expansion is done instead of the container search for a matching identifier.
// - Containers follow C++ namespace resolution rules with searches from the most qualified name
// to the least qualified name.
// - Container references within the CEL program may be relative, and are resolved to fully
// qualified names at either type-check time or program plan time, whichever comes first.
//
// If there is ever a case where an identifier could be in both the container and as an
// abbreviation, the abbreviation wins as this will ensure that the meaning of a program is
// preserved between compilations even as the container evolves.
func Abbrevs(qualifiedNames ...string) EnvOption {
return func(e *Env) (*Env, error) {
cont, err := e.Container.Extend(containers.Abbrevs(qualifiedNames...))
if err != nil {
return nil, err
}
e.Container = cont
return e, nil
}
}
// Types adds one or more type declarations to the environment, allowing for construction of
// type-literals whose definitions are included in the common expression built-in set.
//
// The input types may either be instances of `proto.Message` or `ref.Type`. Any other type
// provided to this option will result in an error.
//
// Well-known protobuf types within the `google.protobuf.*` package are included in the standard
// environment by default.
//
// Note: This option must be specified after the CustomTypeProvider option when used together.
func Types(addTypes ...interface{}) EnvOption {
return func(e *Env) (*Env, error) {
reg, isReg := e.provider.(ref.TypeRegistry)
if !isReg {
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
}
for _, t := range addTypes {
switch v := t.(type) {
case proto.Message:
fdMap := pb.CollectFileDescriptorSet(v)
for _, fd := range fdMap {
err := reg.RegisterDescriptor(fd)
if err != nil {
return nil, err
}
}
case ref.Type:
err := reg.RegisterType(v)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported type: %T", t)
}
}
return e, nil
}
}
// TypeDescs adds type declarations from any protoreflect.FileDescriptor, protoregistry.Files,
// google.protobuf.FileDescriptorProto or google.protobuf.FileDescriptorSet provided.
//
// Note that messages instantiated from these descriptors will be *dynamicpb.Message values
// rather than the concrete message type.
//
// TypeDescs are hermetic to a single Env object, but may be copied to other Env values via
// extension or by re-using the same EnvOption with another NewEnv() call.
func TypeDescs(descs ...interface{}) EnvOption {
return func(e *Env) (*Env, error) {
reg, isReg := e.provider.(ref.TypeRegistry)
if !isReg {
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
}
// Scan the input descriptors for FileDescriptorProto messages and accumulate them into a
// synthetic FileDescriptorSet as the FileDescriptorProto messages may refer to each other
// and will not resolve properly unless they are part of the same set.
var fds *descpb.FileDescriptorSet
for _, d := range descs {
switch f := d.(type) {
case *descpb.FileDescriptorProto:
if fds == nil {
fds = &descpb.FileDescriptorSet{
File: []*descpb.FileDescriptorProto{},
}
}
fds.File = append(fds.File, f)
}
}
if fds != nil {
if err := registerFileSet(reg, fds); err != nil {
return nil, err
}
}
for _, d := range descs {
switch f := d.(type) {
case *protoregistry.Files:
if err := registerFiles(reg, f); err != nil {
return nil, err
}
case protoreflect.FileDescriptor:
if err := reg.RegisterDescriptor(f); err != nil {
return nil, err
}
case *descpb.FileDescriptorSet:
if err := registerFileSet(reg, f); err != nil {
return nil, err
}
case *descpb.FileDescriptorProto:
// skip, handled as a synthetic file descriptor set.
default:
return nil, fmt.Errorf("unsupported type descriptor: %T", d)
}
}
return e, nil
}
}
func registerFileSet(reg ref.TypeRegistry, fileSet *descpb.FileDescriptorSet) error {
files, err := protodesc.NewFiles(fileSet)
if err != nil {
return fmt.Errorf("protodesc.NewFiles(%v) failed: %v", fileSet, err)
}
return registerFiles(reg, files)
}
func registerFiles(reg ref.TypeRegistry, files *protoregistry.Files) error {
var err error
files.RangeFiles(func(fd protoreflect.FileDescriptor) bool {
err = reg.RegisterDescriptor(fd)
return err == nil
})
return err
}
// ProgramOption is a functional interface for configuring evaluation bindings and behaviors.
type ProgramOption func(p *prog) (*prog, error)
// CustomDecorator appends an InterpreterDecorator to the program.
//
// InterpretableDecorators can be used to inspect, alter, or replace the Program plan.
func CustomDecorator(dec interpreter.InterpretableDecorator) ProgramOption {
return func(p *prog) (*prog, error) {
p.decorators = append(p.decorators, dec)
return p, nil
}
}
// Functions adds function overloads that extend or override the set of CEL built-ins.
func Functions(funcs ...*functions.Overload) ProgramOption {
return func(p *prog) (*prog, error) {
if err := p.dispatcher.Add(funcs...); err != nil {
return nil, err
}
return p, nil
}
}
// Globals sets the global variable values for a given program. These values may be shadowed by
// variables with the same name provided to the Eval() call.
//
// The vars value may either be an `interpreter.Activation` instance or a `map[string]interface{}`.
func Globals(vars interface{}) ProgramOption {
return func(p *prog) (*prog, error) {
defaultVars, err :=
interpreter.NewActivation(vars)
if err != nil {
return nil, err
}
p.defaultVars = defaultVars
return p, nil
}
}
// EvalOption indicates an evaluation option that may affect the evaluation behavior or information
// in the output result.
type EvalOption int
const (
// OptTrackState will cause the runtime to return an immutable EvalState value in the Result.
OptTrackState EvalOption = 1 << iota
// OptExhaustiveEval causes the runtime to disable short-circuits and track state.
OptExhaustiveEval EvalOption = 1<<iota | OptTrackState
// OptOptimize precomputes functions and operators with constants as arguments at program
// creation time. This flag is useful when the expression will be evaluated repeatedly against
// a series of different inputs.
OptOptimize EvalOption = 1 << iota
// OptPartialEval enables the evaluation of a partial state where the input data that may be
// known to be missing, either as top-level variables, or somewhere within a variable's object
// member graph.
//
// By itself, OptPartialEval does not change evaluation behavior unless the input to the
// Program Eval is an PartialVars.
OptPartialEval EvalOption = 1 << iota
)
// EvalOptions sets one or more evaluation options which may affect the evaluation or Result.
func EvalOptions(opts ...EvalOption) ProgramOption {
return func(p *prog) (*prog, error) {
for _, opt := range opts {
p.evalOpts |= opt
}
return p, nil
}
}
func fieldToCELType(field protoreflect.FieldDescriptor) (*exprpb.Type, error) {
if field.Kind() == protoreflect.MessageKind {
msgName := (string)(field.Message().FullName())
wellKnownType, found := pb.CheckedWellKnowns[msgName]
if found {
return wellKnownType, nil
}
return decls.NewObjectType(msgName), nil
}
if primitiveType, found := pb.CheckedPrimitives[field.Kind()]; found {
return primitiveType, nil
}
if field.Kind() == protoreflect.EnumKind {
return decls.Int, nil
}
return nil, fmt.Errorf("field %s type %s not implemented", field.FullName(), field.Kind().String())
}
func fieldToDecl(field protoreflect.FieldDescriptor) (*exprpb.Decl, error) {
name := string(field.Name())
if field.IsMap() {
mapKey := field.MapKey()
mapValue := field.MapValue()
keyType, err := fieldToCELType(mapKey)
if err != nil {
return nil, err
}
valueType, err := fieldToCELType(mapValue)
if err != nil {
return nil, err
}
return decls.NewVar(name, decls.NewMapType(keyType, valueType)), nil
} else if field.IsList() {
elemType, err := fieldToCELType(field)
if err != nil {
return nil, err
}
return decls.NewVar(name, decls.NewListType(elemType)), nil
} else {
celType, err := fieldToCELType(field)
if err != nil {
return nil, err
}
return decls.NewVar(name, celType), nil
}
}
// DeclareContextProto returns an option to extend CEL environment with declarations from the given context proto.
// Each field of the proto defines a variable of the same name in the environment.
// https://github.com/google/cel-spec/blob/master/doc/langdef.md#evaluation-environment
func DeclareContextProto(descriptor protoreflect.MessageDescriptor) EnvOption {
return func(e *Env) (*Env, error) {
var decls []*exprpb.Decl
fields := descriptor.Fields()
for i := 0; i < fields.Len(); i++ {
field := fields.Get(i)
decl, err := fieldToDecl(field)
if err != nil {
return nil, err
}
decls = append(decls, decl)
}
var err error
e, err = Declarations(decls...)(e)
if err != nil {
return nil, err
}
return Types(dynamicpb.NewMessage(descriptor))(e)
}
}

318
vendor/github.com/google/cel-go/cel/program.go generated vendored Normal file
View File

@@ -0,0 +1,318 @@
// Copyright 2019 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 cel
import (
"fmt"
"math"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/interpreter"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Program is an evaluable view of an Ast.
type Program interface {
// Eval returns the result of an evaluation of the Ast and environment against the input vars.
//
// The vars value may either be an `interpreter.Activation` or a `map[string]interface{}`.
//
// If the `OptTrackState` or `OptExhaustiveEval` flags are used, the `details` response will
// be non-nil. Given this caveat on `details`, the return state from evaluation will be:
//
// * `val`, `details`, `nil` - Successful evaluation of a non-error result.
// * `val`, `details`, `err` - Successful evaluation to an error result.
// * `nil`, `details`, `err` - Unsuccessful evaluation.
//
// An unsuccessful evaluation is typically the result of a series of incompatible `EnvOption`
// or `ProgramOption` values used in the creation of the evaluation environment or executable
// program.
Eval(vars interface{}) (ref.Val, *EvalDetails, error)
}
// NoVars returns an empty Activation.
func NoVars() interpreter.Activation {
return interpreter.EmptyActivation()
}
// PartialVars returns a PartialActivation which contains variables and a set of AttributePattern
// values that indicate variables or parts of variables whose value are not yet known.
//
// The `vars` value may either be an interpreter.Activation or any valid input to the
// interpreter.NewActivation call.
func PartialVars(vars interface{},
unknowns ...*interpreter.AttributePattern) (interpreter.PartialActivation, error) {
return interpreter.NewPartialActivation(vars, unknowns...)
}
// AttributePattern returns an AttributePattern that matches a top-level variable. The pattern is
// mutable, and its methods support the specification of one or more qualifier patterns.
//
// For example, the AttributePattern(`a`).QualString(`b`) represents a variable access `a` with a
// string field or index qualification `b`. This pattern will match Attributes `a`, and `a.b`,
// but not `a.c`.
//
// When using a CEL expression within a container, e.g. a package or namespace, the variable name
// in the pattern must match the qualified name produced during the variable namespace resolution.
// For example, when variable `a` is declared within an expression whose container is `ns.app`, the
// fully qualified variable name may be `ns.app.a`, `ns.a`, or `a` per the CEL namespace resolution
// rules. Pick the fully qualified variable name that makes sense within the container as the
// AttributePattern `varName` argument.
//
// See the interpreter.AttributePattern and interpreter.AttributeQualifierPattern for more info
// about how to create and manipulate AttributePattern values.
func AttributePattern(varName string) *interpreter.AttributePattern {
return interpreter.NewAttributePattern(varName)
}
// EvalDetails holds additional information observed during the Eval() call.
type EvalDetails struct {
state interpreter.EvalState
}
// State of the evaluation, non-nil if the OptTrackState or OptExhaustiveEval is specified
// within EvalOptions.
func (ed *EvalDetails) State() interpreter.EvalState {
return ed.state
}
// prog is the internal implementation of the Program interface.
type prog struct {
*Env
evalOpts EvalOption
decorators []interpreter.InterpretableDecorator
defaultVars interpreter.Activation
dispatcher interpreter.Dispatcher
interpreter interpreter.Interpreter
interpretable interpreter.Interpretable
attrFactory interpreter.AttributeFactory
}
// progFactory is a helper alias for marking a program creation factory function.
type progFactory func(interpreter.EvalState) (Program, error)
// progGen holds a reference to a progFactory instance and implements the Program interface.
type progGen struct {
factory progFactory
}
// newProgram creates a program instance with an environment, an ast, and an optional list of
// ProgramOption values.
//
// If the program cannot be configured the prog will be nil, with a non-nil error response.
func newProgram(e *Env, ast *Ast, opts []ProgramOption) (Program, error) {
// Build the dispatcher, interpreter, and default program value.
disp := interpreter.NewDispatcher()
// Ensure the default attribute factory is set after the adapter and provider are
// configured.
p := &prog{
Env: e,
decorators: []interpreter.InterpretableDecorator{},
dispatcher: disp,
}
// Configure the program via the ProgramOption values.
var err error
for _, opt := range opts {
if opt == nil {
return nil, fmt.Errorf("program options should be non-nil")
}
p, err = opt(p)
if err != nil {
return nil, err
}
}
// Set the attribute factory after the options have been set.
if p.evalOpts&OptPartialEval == OptPartialEval {
p.attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider)
} else {
p.attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider)
}
interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, p.attrFactory)
p.interpreter = interp
// Translate the EvalOption flags into InterpretableDecorator instances.
decorators := make([]interpreter.InterpretableDecorator, len(p.decorators))
copy(decorators, p.decorators)
// Enable constant folding first.
if p.evalOpts&OptOptimize == OptOptimize {
decorators = append(decorators, interpreter.Optimize())
}
// Enable exhaustive eval over state tracking since it offers a superset of features.
if p.evalOpts&OptExhaustiveEval == OptExhaustiveEval {
// State tracking requires that each Eval() call operate on an isolated EvalState
// object; hence, the presence of the factory.
factory := func(state interpreter.EvalState) (Program, error) {
decs := append(decorators, interpreter.ExhaustiveEval(state))
clone := &prog{
evalOpts: p.evalOpts,
defaultVars: p.defaultVars,
Env: e,
dispatcher: disp,
interpreter: interp}
return initInterpretable(clone, ast, decs)
}
return initProgGen(factory)
}
// Enable state tracking last since it too requires the factory approach but is less
// featured than the ExhaustiveEval decorator.
if p.evalOpts&OptTrackState == OptTrackState {
factory := func(state interpreter.EvalState) (Program, error) {
decs := append(decorators, interpreter.TrackState(state))
clone := &prog{
evalOpts: p.evalOpts,
defaultVars: p.defaultVars,
Env: e,
dispatcher: disp,
interpreter: interp}
return initInterpretable(clone, ast, decs)
}
return initProgGen(factory)
}
return initInterpretable(p, ast, decorators)
}
// initProgGen tests the factory object by calling it once and returns a factory-based Program if
// the test is successful.
func initProgGen(factory progFactory) (Program, error) {
// Test the factory to make sure that configuration errors are spotted at config
_, err := factory(interpreter.NewEvalState())
if err != nil {
return nil, err
}
return &progGen{factory: factory}, nil
}
// initIterpretable creates a checked or unchecked interpretable depending on whether the Ast
// has been run through the type-checker.
func initInterpretable(
p *prog,
ast *Ast,
decorators []interpreter.InterpretableDecorator) (Program, error) {
var err error
// Unchecked programs do not contain type and reference information and may be
// slower to execute than their checked counterparts.
if !ast.IsChecked() {
p.interpretable, err =
p.interpreter.NewUncheckedInterpretable(ast.Expr(), decorators...)
if err != nil {
return nil, err
}
return p, nil
}
// When the AST has been checked it contains metadata that can be used to speed up program
// execution.
var checked *exprpb.CheckedExpr
checked, err = AstToCheckedExpr(ast)
if err != nil {
return nil, err
}
p.interpretable, err = p.interpreter.NewInterpretable(checked, decorators...)
if err != nil {
return nil, err
}
return p, nil
}
// Eval implements the Program interface method.
func (p *prog) Eval(input interface{}) (v ref.Val, det *EvalDetails, err error) {
// Configure error recovery for unexpected panics during evaluation. Note, the use of named
// return values makes it possible to modify the error response during the recovery
// function.
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("internal error: %v", r)
}
}()
// Build a hierarchical activation if there are default vars set.
vars, err := interpreter.NewActivation(input)
if err != nil {
return
}
if p.defaultVars != nil {
vars = interpreter.NewHierarchicalActivation(p.defaultVars, vars)
}
v = p.interpretable.Eval(vars)
// The output of an internal Eval may have a value (`v`) that is a types.Err. This step
// translates the CEL value to a Go error response. This interface does not quite match the
// RPC signature which allows for multiple errors to be returned, but should be sufficient.
if types.IsError(v) {
err = v.(*types.Err)
}
return
}
// Cost implements the Coster interface method.
func (p *prog) Cost() (min, max int64) {
return estimateCost(p.interpretable)
}
// Eval implements the Program interface method.
func (gen *progGen) Eval(input interface{}) (ref.Val, *EvalDetails, error) {
// The factory based Eval() differs from the standard evaluation model in that it generates a
// new EvalState instance for each call to ensure that unique evaluations yield unique stateful
// results.
state := interpreter.NewEvalState()
det := &EvalDetails{state: state}
// Generate a new instance of the interpretable using the factory configured during the call to
// newProgram(). It is incredibly unlikely that the factory call will generate an error given
// the factory test performed within the Program() call.
p, err := gen.factory(state)
if err != nil {
return nil, det, err
}
// Evaluate the input, returning the result and the 'state' within EvalDetails.
v, _, err := p.Eval(input)
if err != nil {
return v, det, err
}
return v, det, nil
}
// Cost implements the Coster interface method.
func (gen *progGen) Cost() (min, max int64) {
// Use an empty state value since no evaluation is performed.
p, err := gen.factory(emptyEvalState)
if err != nil {
return 0, math.MaxInt64
}
return estimateCost(p)
}
var (
emptyEvalState = interpreter.NewEvalState()
)
// EstimateCost returns the heuristic cost interval for the program.
func EstimateCost(p Program) (min, max int64) {
return estimateCost(p)
}
func estimateCost(i interface{}) (min, max int64) {
c, ok := i.(interpreter.Coster)
if !ok {
return 0, math.MaxInt64
}
return c.Cost()
}

57
vendor/github.com/google/cel-go/checker/BUILD.bazel generated vendored Normal file
View File

@@ -0,0 +1,57 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"checker.go",
"env.go",
"errors.go",
"mapping.go",
"printer.go",
"standard.go",
"types.go",
],
importpath = "github.com/google/cel-go/checker",
visibility = ["//visibility:public"],
deps = [
"//checker/decls:go_default_library",
"//common:go_default_library",
"//common/containers:go_default_library",
"//common/debug:go_default_library",
"//common/operators:go_default_library",
"//common/overloads:go_default_library",
"//common/types:go_default_library",
"//common/types/pb:go_default_library",
"//common/types/ref:go_default_library",
"//parser:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"checker_test.go",
"env_test.go",
],
embed = [
":go_default_library",
],
deps = [
"//common/types:go_default_library",
"//parser:go_default_library",
"//test:go_default_library",
"//test/proto2pb:go_default_library",
"//test/proto3pb:go_default_library",
"@com_github_antlr//runtime/Go/antlr:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)

642
vendor/github.com/google/cel-go/checker/checker.go generated vendored Normal file
View File

@@ -0,0 +1,642 @@
// 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 checker defines functions to type-checked a parsed expression
// against a set of identifier and function declarations.
package checker
import (
"fmt"
"reflect"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common"
"github.com/google/cel-go/common/containers"
"github.com/google/cel-go/common/types/ref"
"google.golang.org/protobuf/proto"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type checker struct {
env *Env
errors *typeErrors
mappings *mapping
freeTypeVarCounter int
sourceInfo *exprpb.SourceInfo
types map[int64]*exprpb.Type
references map[int64]*exprpb.Reference
}
// Check performs type checking, giving a typed AST.
// The input is a ParsedExpr proto and an env which encapsulates
// type binding of variables, declarations of built-in functions,
// descriptions of protocol buffers, and a registry for errors.
// Returns a CheckedExpr proto, which might not be usable if
// there are errors in the error registry.
func Check(parsedExpr *exprpb.ParsedExpr,
source common.Source,
env *Env) (*exprpb.CheckedExpr, *common.Errors) {
c := checker{
env: env,
errors: &typeErrors{common.NewErrors(source)},
mappings: newMapping(),
freeTypeVarCounter: 0,
sourceInfo: parsedExpr.GetSourceInfo(),
types: make(map[int64]*exprpb.Type),
references: make(map[int64]*exprpb.Reference),
}
c.check(parsedExpr.GetExpr())
// Walk over the final type map substituting any type parameters either by their bound value or
// by DYN.
m := make(map[int64]*exprpb.Type)
for k, v := range c.types {
m[k] = substitute(c.mappings, v, true)
}
return &exprpb.CheckedExpr{
Expr: parsedExpr.GetExpr(),
SourceInfo: parsedExpr.GetSourceInfo(),
TypeMap: m,
ReferenceMap: c.references,
}, c.errors.Errors
}
func (c *checker) check(e *exprpb.Expr) {
if e == nil {
return
}
switch e.ExprKind.(type) {
case *exprpb.Expr_ConstExpr:
literal := e.GetConstExpr()
switch literal.ConstantKind.(type) {
case *exprpb.Constant_BoolValue:
c.checkBoolLiteral(e)
case *exprpb.Constant_BytesValue:
c.checkBytesLiteral(e)
case *exprpb.Constant_DoubleValue:
c.checkDoubleLiteral(e)
case *exprpb.Constant_Int64Value:
c.checkInt64Literal(e)
case *exprpb.Constant_NullValue:
c.checkNullLiteral(e)
case *exprpb.Constant_StringValue:
c.checkStringLiteral(e)
case *exprpb.Constant_Uint64Value:
c.checkUint64Literal(e)
}
case *exprpb.Expr_IdentExpr:
c.checkIdent(e)
case *exprpb.Expr_SelectExpr:
c.checkSelect(e)
case *exprpb.Expr_CallExpr:
c.checkCall(e)
case *exprpb.Expr_ListExpr:
c.checkCreateList(e)
case *exprpb.Expr_StructExpr:
c.checkCreateStruct(e)
case *exprpb.Expr_ComprehensionExpr:
c.checkComprehension(e)
default:
c.errors.ReportError(
c.location(e), "Unrecognized ast type: %v", reflect.TypeOf(e))
}
}
func (c *checker) checkInt64Literal(e *exprpb.Expr) {
c.setType(e, decls.Int)
}
func (c *checker) checkUint64Literal(e *exprpb.Expr) {
c.setType(e, decls.Uint)
}
func (c *checker) checkStringLiteral(e *exprpb.Expr) {
c.setType(e, decls.String)
}
func (c *checker) checkBytesLiteral(e *exprpb.Expr) {
c.setType(e, decls.Bytes)
}
func (c *checker) checkDoubleLiteral(e *exprpb.Expr) {
c.setType(e, decls.Double)
}
func (c *checker) checkBoolLiteral(e *exprpb.Expr) {
c.setType(e, decls.Bool)
}
func (c *checker) checkNullLiteral(e *exprpb.Expr) {
c.setType(e, decls.Null)
}
func (c *checker) checkIdent(e *exprpb.Expr) {
identExpr := e.GetIdentExpr()
// Check to see if the identifier is declared.
if ident := c.env.LookupIdent(identExpr.GetName()); ident != nil {
c.setType(e, ident.GetIdent().Type)
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().Value))
// Overwrite the identifier with its fully qualified name.
identExpr.Name = ident.GetName()
return
}
c.setType(e, decls.Error)
c.errors.undeclaredReference(
c.location(e), c.env.container.Name(), identExpr.GetName())
}
func (c *checker) checkSelect(e *exprpb.Expr) {
sel := e.GetSelectExpr()
// Before traversing down the tree, try to interpret as qualified name.
qname, found := containers.ToQualifiedName(e)
if found {
ident := c.env.LookupIdent(qname)
if ident != nil {
if sel.TestOnly {
c.errors.expressionDoesNotSelectField(c.location(e))
c.setType(e, decls.Bool)
return
}
// Rewrite the node to be a variable reference to the resolved fully-qualified
// variable name.
c.setType(e, ident.GetIdent().Type)
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().Value))
identName := ident.GetName()
e.ExprKind = &exprpb.Expr_IdentExpr{
IdentExpr: &exprpb.Expr_Ident{
Name: identName,
},
}
return
}
}
// Interpret as field selection, first traversing down the operand.
c.check(sel.Operand)
targetType := c.getType(sel.Operand)
// Assume error type by default as most types do not support field selection.
resultType := decls.Error
switch kindOf(targetType) {
case kindMap:
// Maps yield their value type as the selection result type.
mapType := targetType.GetMapType()
resultType = mapType.ValueType
case kindObject:
// Objects yield their field type declaration as the selection result type, but only if
// the field is defined.
messageType := targetType
if fieldType, found := c.lookupFieldType(
c.location(e),
messageType.GetMessageType(),
sel.Field); found {
resultType = fieldType.Type
}
case kindTypeParam:
// Set the operand type to DYN to prevent assignment to a potentionally incorrect type
// at a later point in type-checking. The isAssignable call will update the type
// substitutions for the type param under the covers.
c.isAssignable(decls.Dyn, targetType)
// Also, set the result type to DYN.
resultType = decls.Dyn
default:
// Dynamic / error values are treated as DYN type. Errors are handled this way as well
// in order to allow forward progress on the check.
if isDynOrError(targetType) {
resultType = decls.Dyn
} else {
c.errors.typeDoesNotSupportFieldSelection(c.location(e), targetType)
}
}
if sel.TestOnly {
resultType = decls.Bool
}
c.setType(e, resultType)
}
func (c *checker) checkCall(e *exprpb.Expr) {
// Note: similar logic exists within the `interpreter/planner.go`. If making changes here
// please consider the impact on planner.go and consolidate implementations or mirror code
// as appropriate.
call := e.GetCallExpr()
target := call.GetTarget()
args := call.GetArgs()
fnName := call.GetFunction()
// Traverse arguments.
for _, arg := range args {
c.check(arg)
}
// Regular static call with simple name.
if target == nil {
// Check for the existence of the function.
fn := c.env.LookupFunction(fnName)
if fn == nil {
c.errors.undeclaredReference(
c.location(e), c.env.container.Name(), fnName)
c.setType(e, decls.Error)
return
}
// Overwrite the function name with its fully qualified resolved name.
call.Function = fn.GetName()
// Check to see whether the overload resolves.
c.resolveOverloadOrError(c.location(e), e, fn, nil, args)
return
}
// If a receiver 'target' is present, it may either be a receiver function, or a namespaced
// function, but not both. Given a.b.c() either a.b.c is a function or c is a function with
// target a.b.
//
// Check whether the target is a namespaced function name.
qualifiedPrefix, maybeQualified := containers.ToQualifiedName(target)
if maybeQualified {
maybeQualifiedName := qualifiedPrefix + "." + fnName
fn := c.env.LookupFunction(maybeQualifiedName)
if fn != nil {
// The function name is namespaced and so preserving the target operand would
// be an inaccurate representation of the desired evaluation behavior.
// Overwrite with fully-qualified resolved function name sans receiver target.
call.Target = nil
call.Function = fn.GetName()
c.resolveOverloadOrError(c.location(e), e, fn, nil, args)
return
}
}
// Regular instance call.
c.check(call.Target)
fn := c.env.LookupFunction(fnName)
// Function found, attempt overload resolution.
if fn != nil {
c.resolveOverloadOrError(c.location(e), e, fn, target, args)
return
}
// Function name not declared, record error.
c.errors.undeclaredReference(c.location(e), c.env.container.Name(), fnName)
}
func (c *checker) resolveOverloadOrError(
loc common.Location,
e *exprpb.Expr,
fn *exprpb.Decl, target *exprpb.Expr, args []*exprpb.Expr) {
// Attempt to resolve the overload.
resolution := c.resolveOverload(loc, fn, target, args)
// No such overload, error noted in the resolveOverload call, type recorded here.
if resolution == nil {
c.setType(e, decls.Error)
return
}
// Overload found.
c.setType(e, resolution.Type)
c.setReference(e, resolution.Reference)
}
func (c *checker) resolveOverload(
loc common.Location,
fn *exprpb.Decl, target *exprpb.Expr, args []*exprpb.Expr) *overloadResolution {
var argTypes []*exprpb.Type
if target != nil {
argTypes = append(argTypes, c.getType(target))
}
for _, arg := range args {
argTypes = append(argTypes, c.getType(arg))
}
var resultType *exprpb.Type
var checkedRef *exprpb.Reference
for _, overload := range fn.GetFunction().Overloads {
if (target == nil && overload.IsInstanceFunction) ||
(target != nil && !overload.IsInstanceFunction) {
// not a compatible call style.
continue
}
overloadType := decls.NewFunctionType(overload.ResultType, overload.Params...)
if len(overload.TypeParams) > 0 {
// Instantiate overload's type with fresh type variables.
substitutions := newMapping()
for _, typePar := range overload.TypeParams {
substitutions.add(decls.NewTypeParamType(typePar), c.newTypeVar())
}
overloadType = substitute(substitutions, overloadType, false)
}
candidateArgTypes := overloadType.GetFunction().ArgTypes
if c.isAssignableList(argTypes, candidateArgTypes) {
if checkedRef == nil {
checkedRef = newFunctionReference(overload.OverloadId)
} else {
checkedRef.OverloadId = append(checkedRef.OverloadId, overload.OverloadId)
}
// First matching overload, determines result type.
fnResultType := substitute(c.mappings,
overloadType.GetFunction().ResultType,
false)
if resultType == nil {
resultType = fnResultType
} else if !isDyn(resultType) && !proto.Equal(fnResultType, resultType) {
resultType = decls.Dyn
}
}
}
if resultType == nil {
c.errors.noMatchingOverload(loc, fn.GetName(), argTypes, target != nil)
resultType = decls.Error
return nil
}
return newResolution(checkedRef, resultType)
}
func (c *checker) checkCreateList(e *exprpb.Expr) {
create := e.GetListExpr()
var elemType *exprpb.Type
for _, e := range create.Elements {
c.check(e)
elemType = c.joinTypes(c.location(e), elemType, c.getType(e))
}
if elemType == nil {
// If the list is empty, assign free type var to elem type.
elemType = c.newTypeVar()
}
c.setType(e, decls.NewListType(elemType))
}
func (c *checker) checkCreateStruct(e *exprpb.Expr) {
str := e.GetStructExpr()
if str.MessageName != "" {
c.checkCreateMessage(e)
} else {
c.checkCreateMap(e)
}
}
func (c *checker) checkCreateMap(e *exprpb.Expr) {
mapVal := e.GetStructExpr()
var keyType *exprpb.Type
var valueType *exprpb.Type
for _, ent := range mapVal.GetEntries() {
key := ent.GetMapKey()
c.check(key)
keyType = c.joinTypes(c.location(key), keyType, c.getType(key))
c.check(ent.Value)
valueType = c.joinTypes(c.location(ent.Value), valueType, c.getType(ent.Value))
}
if keyType == nil {
// If the map is empty, assign free type variables to typeKey and value type.
keyType = c.newTypeVar()
valueType = c.newTypeVar()
}
c.setType(e, decls.NewMapType(keyType, valueType))
}
func (c *checker) checkCreateMessage(e *exprpb.Expr) {
msgVal := e.GetStructExpr()
// Determine the type of the message.
messageType := decls.Error
decl := c.env.LookupIdent(msgVal.MessageName)
if decl == nil {
c.errors.undeclaredReference(
c.location(e), c.env.container.Name(), msgVal.MessageName)
return
}
// Ensure the type name is fully qualified in the AST.
msgVal.MessageName = decl.GetName()
c.setReference(e, newIdentReference(decl.GetName(), nil))
ident := decl.GetIdent()
identKind := kindOf(ident.Type)
if identKind != kindError {
if identKind != kindType {
c.errors.notAType(c.location(e), ident.Type)
} else {
messageType = ident.Type.GetType()
if kindOf(messageType) != kindObject {
c.errors.notAMessageType(c.location(e), messageType)
messageType = decls.Error
}
}
}
if isObjectWellKnownType(messageType) {
c.setType(e, getObjectWellKnownType(messageType))
} else {
c.setType(e, messageType)
}
// Check the field initializers.
for _, ent := range msgVal.GetEntries() {
field := ent.GetFieldKey()
value := ent.Value
c.check(value)
fieldType := decls.Error
if t, found := c.lookupFieldType(
c.locationByID(ent.Id),
messageType.GetMessageType(),
field); found {
fieldType = t.Type
}
if !c.isAssignable(fieldType, c.getType(value)) {
c.errors.fieldTypeMismatch(
c.locationByID(ent.Id), field, fieldType, c.getType(value))
}
}
}
func (c *checker) checkComprehension(e *exprpb.Expr) {
comp := e.GetComprehensionExpr()
c.check(comp.IterRange)
c.check(comp.AccuInit)
accuType := c.getType(comp.AccuInit)
rangeType := c.getType(comp.IterRange)
var varType *exprpb.Type
switch kindOf(rangeType) {
case kindList:
varType = rangeType.GetListType().ElemType
case kindMap:
// Ranges over the keys.
varType = rangeType.GetMapType().KeyType
case kindDyn, kindError, kindTypeParam:
// Set the range type to DYN to prevent assignment to a potentionally incorrect type
// at a later point in type-checking. The isAssignable call will update the type
// substitutions for the type param under the covers.
c.isAssignable(decls.Dyn, rangeType)
// Set the range iteration variable to type DYN as well.
varType = decls.Dyn
default:
c.errors.notAComprehensionRange(c.location(comp.IterRange), rangeType)
varType = decls.Error
}
// Create a scope for the comprehension since it has a local accumulation variable.
// This scope will contain the accumulation variable used to compute the result.
c.env = c.env.enterScope()
c.env.Add(decls.NewVar(comp.AccuVar, accuType))
// Create a block scope for the loop.
c.env = c.env.enterScope()
c.env.Add(decls.NewVar(comp.IterVar, varType))
// Check the variable references in the condition and step.
c.check(comp.LoopCondition)
c.assertType(comp.LoopCondition, decls.Bool)
c.check(comp.LoopStep)
c.assertType(comp.LoopStep, accuType)
// Exit the loop's block scope before checking the result.
c.env = c.env.exitScope()
c.check(comp.Result)
// Exit the comprehension scope.
c.env = c.env.exitScope()
c.setType(e, c.getType(comp.Result))
}
// Checks compatibility of joined types, and returns the most general common type.
func (c *checker) joinTypes(loc common.Location,
previous *exprpb.Type,
current *exprpb.Type) *exprpb.Type {
if previous == nil {
return current
}
if c.isAssignable(previous, current) {
return mostGeneral(previous, current)
}
if c.dynAggregateLiteralElementTypesEnabled() {
return decls.Dyn
}
c.errors.typeMismatch(loc, previous, current)
return decls.Error
}
func (c *checker) dynAggregateLiteralElementTypesEnabled() bool {
return c.env.aggLitElemType == dynElementType
}
func (c *checker) newTypeVar() *exprpb.Type {
id := c.freeTypeVarCounter
c.freeTypeVarCounter++
return decls.NewTypeParamType(fmt.Sprintf("_var%d", id))
}
func (c *checker) isAssignable(t1 *exprpb.Type, t2 *exprpb.Type) bool {
subs := isAssignable(c.mappings, t1, t2)
if subs != nil {
c.mappings = subs
return true
}
return false
}
func (c *checker) isAssignableList(l1 []*exprpb.Type, l2 []*exprpb.Type) bool {
subs := isAssignableList(c.mappings, l1, l2)
if subs != nil {
c.mappings = subs
return true
}
return false
}
func (c *checker) lookupFieldType(l common.Location, messageType string, fieldName string) (*ref.FieldType, bool) {
if _, found := c.env.provider.FindType(messageType); !found {
// This should not happen, anyway, report an error.
c.errors.unexpectedFailedResolution(l, messageType)
return nil, false
}
if ft, found := c.env.provider.FindFieldType(messageType, fieldName); found {
return ft, found
}
c.errors.undefinedField(l, fieldName)
return nil, false
}
func (c *checker) setType(e *exprpb.Expr, t *exprpb.Type) {
if old, found := c.types[e.Id]; found && !proto.Equal(old, t) {
c.errors.ReportError(c.location(e),
"(Incompatible) Type already exists for expression: %v(%d) old:%v, new:%v", e, e.GetId(), old, t)
return
}
c.types[e.Id] = t
}
func (c *checker) getType(e *exprpb.Expr) *exprpb.Type {
return c.types[e.Id]
}
func (c *checker) setReference(e *exprpb.Expr, r *exprpb.Reference) {
if old, found := c.references[e.Id]; found && !proto.Equal(old, r) {
c.errors.ReportError(c.location(e),
"Reference already exists for expression: %v(%d) old:%v, new:%v", e, e.Id, old, r)
return
}
c.references[e.Id] = r
}
func (c *checker) assertType(e *exprpb.Expr, t *exprpb.Type) {
if !c.isAssignable(t, c.getType(e)) {
c.errors.typeMismatch(c.location(e), t, c.getType(e))
}
}
type overloadResolution struct {
Reference *exprpb.Reference
Type *exprpb.Type
}
func newResolution(checkedRef *exprpb.Reference, t *exprpb.Type) *overloadResolution {
return &overloadResolution{
Reference: checkedRef,
Type: t,
}
}
func (c *checker) location(e *exprpb.Expr) common.Location {
return c.locationByID(e.Id)
}
func (c *checker) locationByID(id int64) common.Location {
positions := c.sourceInfo.GetPositions()
var line = 1
if offset, found := positions[id]; found {
col := int(offset)
for _, lineOffset := range c.sourceInfo.LineOffsets {
if lineOffset < offset {
line++
col = int(offset - lineOffset)
} else {
break
}
}
return common.NewLocation(line, col)
}
return common.NoLocation
}
func newIdentReference(name string, value *exprpb.Constant) *exprpb.Reference {
return &exprpb.Reference{Name: name, Value: value}
}
func newFunctionReference(overloads ...string) *exprpb.Reference {
return &exprpb.Reference{OverloadId: overloads}
}

View File

@@ -0,0 +1,20 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"decls.go",
"scopes.go",
],
importpath = "github.com/google/cel-go/checker/decls",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
],
)

231
vendor/github.com/google/cel-go/checker/decls/decls.go generated vendored Normal file
View File

@@ -0,0 +1,231 @@
// 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 decls provides helpers for creating variable and function declarations.
package decls
import (
emptypb "google.golang.org/protobuf/types/known/emptypb"
structpb "google.golang.org/protobuf/types/known/structpb"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
var (
// Error type used to communicate issues during type-checking.
Error = &exprpb.Type{
TypeKind: &exprpb.Type_Error{
Error: &emptypb.Empty{}}}
// Dyn is a top-type used to represent any value.
Dyn = &exprpb.Type{
TypeKind: &exprpb.Type_Dyn{
Dyn: &emptypb.Empty{}}}
)
// Commonly used types.
var (
Bool = NewPrimitiveType(exprpb.Type_BOOL)
Bytes = NewPrimitiveType(exprpb.Type_BYTES)
Double = NewPrimitiveType(exprpb.Type_DOUBLE)
Int = NewPrimitiveType(exprpb.Type_INT64)
Null = &exprpb.Type{
TypeKind: &exprpb.Type_Null{
Null: structpb.NullValue_NULL_VALUE}}
String = NewPrimitiveType(exprpb.Type_STRING)
Uint = NewPrimitiveType(exprpb.Type_UINT64)
)
// Well-known types.
// TODO: Replace with an abstract type registry.
var (
Any = NewWellKnownType(exprpb.Type_ANY)
Duration = NewWellKnownType(exprpb.Type_DURATION)
Timestamp = NewWellKnownType(exprpb.Type_TIMESTAMP)
)
// NewAbstractType creates an abstract type declaration which references a proto
// message name and may also include type parameters.
func NewAbstractType(name string, paramTypes ...*exprpb.Type) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_AbstractType_{
AbstractType: &exprpb.Type_AbstractType{
Name: name,
ParameterTypes: paramTypes}}}
}
// NewFunctionType creates a function invocation contract, typically only used
// by type-checking steps after overload resolution.
func NewFunctionType(resultType *exprpb.Type,
argTypes ...*exprpb.Type) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_Function{
Function: &exprpb.Type_FunctionType{
ResultType: resultType,
ArgTypes: argTypes}}}
}
// NewFunction creates a named function declaration with one or more overloads.
func NewFunction(name string,
overloads ...*exprpb.Decl_FunctionDecl_Overload) *exprpb.Decl {
return &exprpb.Decl{
Name: name,
DeclKind: &exprpb.Decl_Function{
Function: &exprpb.Decl_FunctionDecl{
Overloads: overloads}}}
}
// NewIdent creates a named identifier declaration with an optional literal
// value.
//
// Literal values are typically only associated with enum identifiers.
//
// Deprecated: Use NewVar or NewConst instead.
func NewIdent(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl {
return &exprpb.Decl{
Name: name,
DeclKind: &exprpb.Decl_Ident{
Ident: &exprpb.Decl_IdentDecl{
Type: t,
Value: v}}}
}
// NewConst creates a constant identifier with a CEL constant literal value.
func NewConst(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl {
return NewIdent(name, t, v)
}
// NewVar creates a variable identifier.
func NewVar(name string, t *exprpb.Type) *exprpb.Decl {
return NewIdent(name, t, nil)
}
// NewInstanceOverload creates a instance function overload contract.
// First element of argTypes is instance.
func NewInstanceOverload(id string, argTypes []*exprpb.Type,
resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload {
return &exprpb.Decl_FunctionDecl_Overload{
OverloadId: id,
ResultType: resultType,
Params: argTypes,
IsInstanceFunction: true}
}
// NewListType generates a new list with elements of a certain type.
func NewListType(elem *exprpb.Type) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_ListType_{
ListType: &exprpb.Type_ListType{
ElemType: elem}}}
}
// NewMapType generates a new map with typed keys and values.
func NewMapType(key *exprpb.Type, value *exprpb.Type) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_MapType_{
MapType: &exprpb.Type_MapType{
KeyType: key,
ValueType: value}}}
}
// NewObjectType creates an object type for a qualified type name.
func NewObjectType(typeName string) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_MessageType{
MessageType: typeName}}
}
// NewOverload creates a function overload declaration which contains a unique
// overload id as well as the expected argument and result types. Overloads
// must be aggregated within a Function declaration.
func NewOverload(id string, argTypes []*exprpb.Type,
resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload {
return &exprpb.Decl_FunctionDecl_Overload{
OverloadId: id,
ResultType: resultType,
Params: argTypes,
IsInstanceFunction: false}
}
// NewParameterizedInstanceOverload creates a parametric function instance overload type.
func NewParameterizedInstanceOverload(id string,
argTypes []*exprpb.Type,
resultType *exprpb.Type,
typeParams []string) *exprpb.Decl_FunctionDecl_Overload {
return &exprpb.Decl_FunctionDecl_Overload{
OverloadId: id,
ResultType: resultType,
Params: argTypes,
TypeParams: typeParams,
IsInstanceFunction: true}
}
// NewParameterizedOverload creates a parametric function overload type.
func NewParameterizedOverload(id string,
argTypes []*exprpb.Type,
resultType *exprpb.Type,
typeParams []string) *exprpb.Decl_FunctionDecl_Overload {
return &exprpb.Decl_FunctionDecl_Overload{
OverloadId: id,
ResultType: resultType,
Params: argTypes,
TypeParams: typeParams,
IsInstanceFunction: false}
}
// NewPrimitiveType creates a type for a primitive value. See the var declarations
// for Int, Uint, etc.
func NewPrimitiveType(primitive exprpb.Type_PrimitiveType) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_Primitive{
Primitive: primitive}}
}
// NewTypeType creates a new type designating a type.
func NewTypeType(nested *exprpb.Type) *exprpb.Type {
if nested == nil {
// must set the nested field for a valid oneof option
nested = &exprpb.Type{}
}
return &exprpb.Type{
TypeKind: &exprpb.Type_Type{
Type: nested}}
}
// NewTypeParamType creates a type corresponding to a named, contextual parameter.
func NewTypeParamType(name string) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_TypeParam{
TypeParam: name}}
}
// NewWellKnownType creates a type corresponding to a protobuf well-known type
// value.
func NewWellKnownType(wellKnown exprpb.Type_WellKnownType) *exprpb.Type {
return &exprpb.Type{
TypeKind: &exprpb.Type_WellKnown{
WellKnown: wellKnown}}
}
// NewWrapperType creates a wrapped primitive type instance. Wrapped types
// are roughly equivalent to a nullable, or optionally valued type.
func NewWrapperType(wrapped *exprpb.Type) *exprpb.Type {
primitive := wrapped.GetPrimitive()
if primitive == exprpb.Type_PRIMITIVE_TYPE_UNSPECIFIED {
// TODO: return an error
panic("Wrapped type must be a primitive")
}
return &exprpb.Type{
TypeKind: &exprpb.Type_Wrapper{
Wrapper: primitive}}
}

115
vendor/github.com/google/cel-go/checker/decls/scopes.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
// 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 decls
import exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
// Scopes represents nested Decl sets where the Scopes value contains a Groups containing all
// identifiers in scope and an optional parent representing outer scopes.
// Each Groups value is a mapping of names to Decls in the ident and function namespaces.
// Lookups are performed such that bindings in inner scopes shadow those in outer scopes.
type Scopes struct {
parent *Scopes
scopes *Group
}
// NewScopes creates a new, empty Scopes.
// Some operations can't be safely performed until a Group is added with Push.
func NewScopes() *Scopes {
return &Scopes{
scopes: newGroup(),
}
}
// Push creates a new Scopes value which references the current Scope as its parent.
func (s *Scopes) Push() *Scopes {
return &Scopes{
parent: s,
scopes: newGroup(),
}
}
// Pop returns the parent Scopes value for the current scope, or the current scope if the parent
// is nil.
func (s *Scopes) Pop() *Scopes {
if s.parent != nil {
return s.parent
}
// TODO: Consider whether this should be an error / panic.
return s
}
// AddIdent adds the ident Decl in the current scope.
// Note: If the name collides with an existing identifier in the scope, the Decl is overwritten.
func (s *Scopes) AddIdent(decl *exprpb.Decl) {
s.scopes.idents[decl.Name] = decl
}
// FindIdent finds the first ident Decl with a matching name in Scopes, or nil if one cannot be
// found.
// Note: The search is performed from innermost to outermost.
func (s *Scopes) FindIdent(name string) *exprpb.Decl {
if ident, found := s.scopes.idents[name]; found {
return ident
}
if s.parent != nil {
return s.parent.FindIdent(name)
}
return nil
}
// FindIdentInScope finds the first ident Decl with a matching name in the current Scopes value, or
// nil if one does not exist.
// Note: The search is only performed on the current scope and does not search outer scopes.
func (s *Scopes) FindIdentInScope(name string) *exprpb.Decl {
if ident, found := s.scopes.idents[name]; found {
return ident
}
return nil
}
// AddFunction adds the function Decl to the current scope.
// Note: Any previous entry for a function in the current scope with the same name is overwritten.
func (s *Scopes) AddFunction(fn *exprpb.Decl) {
s.scopes.functions[fn.Name] = fn
}
// FindFunction finds the first function Decl with a matching name in Scopes.
// The search is performed from innermost to outermost.
// Returns nil if no such function in Scopes.
func (s *Scopes) FindFunction(name string) *exprpb.Decl {
if fn, found := s.scopes.functions[name]; found {
return fn
}
if s.parent != nil {
return s.parent.FindFunction(name)
}
return nil
}
// Group is a set of Decls that is pushed on or popped off a Scopes as a unit.
// Contains separate namespaces for idenifier and function Decls.
// (Should be named "Scope" perhaps?)
type Group struct {
idents map[string]*exprpb.Decl
functions map[string]*exprpb.Decl
}
func newGroup() *Group {
return &Group{
idents: make(map[string]*exprpb.Decl),
functions: make(map[string]*exprpb.Decl),
}
}

346
vendor/github.com/google/cel-go/checker/env.go generated vendored Normal file
View File

@@ -0,0 +1,346 @@
// 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 checker
import (
"fmt"
"strings"
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/containers"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/parser"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type aggregateLiteralElementType int
const (
dynElementType aggregateLiteralElementType = iota
homogenousElementType aggregateLiteralElementType = 1 << iota
)
// Env is the environment for type checking.
//
// The Env is comprised of a container, type provider, declarations, and other related objects
// which can be used to assist with type-checking.
type Env struct {
container *containers.Container
provider ref.TypeProvider
declarations *decls.Scopes
aggLitElemType aggregateLiteralElementType
}
// NewEnv returns a new *Env with the given parameters.
func NewEnv(container *containers.Container, provider ref.TypeProvider) *Env {
declarations := decls.NewScopes()
declarations.Push()
return &Env{
container: container,
provider: provider,
declarations: declarations,
}
}
// NewStandardEnv returns a new *Env with the given params plus standard declarations.
func NewStandardEnv(container *containers.Container, provider ref.TypeProvider) *Env {
e := NewEnv(container, provider)
if err := e.Add(StandardDeclarations()...); err != nil {
// The standard declaration set should never have duplicate declarations.
panic(err)
}
// TODO: isolate standard declarations from the custom set which may be provided layer.
return e
}
// EnableDynamicAggregateLiterals detmerines whether list and map literals may support mixed
// element types at check-time. This does not preclude the presence of a dynamic list or map
// somewhere in the CEL evaluation process.
func (e *Env) EnableDynamicAggregateLiterals(enabled bool) *Env {
e.aggLitElemType = dynElementType
if !enabled {
e.aggLitElemType = homogenousElementType
}
return e
}
// Add adds new Decl protos to the Env.
// Returns an error for identifier redeclarations.
func (e *Env) Add(decls ...*exprpb.Decl) error {
errMsgs := make([]errorMsg, 0)
for _, decl := range decls {
switch decl.DeclKind.(type) {
case *exprpb.Decl_Ident:
errMsgs = append(errMsgs, e.addIdent(sanitizeIdent(decl)))
case *exprpb.Decl_Function:
errMsgs = append(errMsgs, e.addFunction(sanitizeFunction(decl))...)
}
}
return formatError(errMsgs)
}
// LookupIdent returns a Decl proto for typeName as an identifier in the Env.
// Returns nil if no such identifier is found in the Env.
func (e *Env) LookupIdent(name string) *exprpb.Decl {
for _, candidate := range e.container.ResolveCandidateNames(name) {
if ident := e.declarations.FindIdent(candidate); ident != nil {
return ident
}
// Next try to import the name as a reference to a message type. If found,
// the declaration is added to the outest (global) scope of the
// environment, so next time we can access it faster.
if t, found := e.provider.FindType(candidate); found {
decl := decls.NewVar(candidate, t)
e.declarations.AddIdent(decl)
return decl
}
// Next try to import this as an enum value by splitting the name in a type prefix and
// the enum inside.
if enumValue := e.provider.EnumValue(candidate); enumValue.Type() != types.ErrType {
decl := decls.NewIdent(candidate,
decls.Int,
&exprpb.Constant{
ConstantKind: &exprpb.Constant_Int64Value{
Int64Value: int64(enumValue.(types.Int))}})
e.declarations.AddIdent(decl)
return decl
}
}
return nil
}
// LookupFunction returns a Decl proto for typeName as a function in env.
// Returns nil if no such function is found in env.
func (e *Env) LookupFunction(name string) *exprpb.Decl {
for _, candidate := range e.container.ResolveCandidateNames(name) {
if fn := e.declarations.FindFunction(candidate); fn != nil {
return fn
}
}
return nil
}
// addOverload adds overload to function declaration f.
// Returns one or more errorMsg values if the overload overlaps with an existing overload or macro.
func (e *Env) addOverload(f *exprpb.Decl, overload *exprpb.Decl_FunctionDecl_Overload) []errorMsg {
errMsgs := make([]errorMsg, 0)
function := f.GetFunction()
emptyMappings := newMapping()
overloadFunction := decls.NewFunctionType(overload.GetResultType(),
overload.GetParams()...)
overloadErased := substitute(emptyMappings, overloadFunction, true)
for _, existing := range function.GetOverloads() {
existingFunction := decls.NewFunctionType(existing.GetResultType(),
existing.GetParams()...)
existingErased := substitute(emptyMappings, existingFunction, true)
overlap := isAssignable(emptyMappings, overloadErased, existingErased) != nil ||
isAssignable(emptyMappings, existingErased, overloadErased) != nil
if overlap &&
overload.GetIsInstanceFunction() == existing.GetIsInstanceFunction() {
errMsgs = append(errMsgs,
overlappingOverloadError(f.Name,
overload.GetOverloadId(), overloadFunction,
existing.GetOverloadId(), existingFunction))
}
}
for _, macro := range parser.AllMacros {
if macro.Function() == f.Name &&
macro.IsReceiverStyle() == overload.GetIsInstanceFunction() &&
macro.ArgCount() == len(overload.GetParams()) {
errMsgs = append(errMsgs, overlappingMacroError(f.Name, macro.ArgCount()))
}
}
if len(errMsgs) > 0 {
return errMsgs
}
function.Overloads = append(function.GetOverloads(), overload)
return errMsgs
}
// addFunction adds the function Decl to the Env.
// Adds a function decl if one doesn't already exist, then adds all overloads from the Decl.
// If overload overlaps with an existing overload, adds to the errors in the Env instead.
func (e *Env) addFunction(decl *exprpb.Decl) []errorMsg {
current := e.declarations.FindFunction(decl.Name)
if current == nil {
//Add the function declaration without overloads and check the overloads below.
current = decls.NewFunction(decl.Name)
e.declarations.AddFunction(current)
}
errorMsgs := make([]errorMsg, 0)
for _, overload := range decl.GetFunction().GetOverloads() {
errorMsgs = append(errorMsgs, e.addOverload(current, overload)...)
}
return errorMsgs
}
// addIdent adds the Decl to the declarations in the Env.
// Returns a non-empty errorMsg if the identifier is already declared in the scope.
func (e *Env) addIdent(decl *exprpb.Decl) errorMsg {
current := e.declarations.FindIdentInScope(decl.Name)
if current != nil {
return overlappingIdentifierError(decl.Name)
}
e.declarations.AddIdent(decl)
return ""
}
// sanitizeFunction replaces well-known types referenced by message name with their equivalent
// CEL built-in type instances.
func sanitizeFunction(decl *exprpb.Decl) *exprpb.Decl {
fn := decl.GetFunction()
// Determine whether the declaration requires replacements from proto-based message type
// references to well-known CEL type references.
var needsSanitizing bool
for _, o := range fn.GetOverloads() {
if isObjectWellKnownType(o.GetResultType()) {
needsSanitizing = true
break
}
for _, p := range o.GetParams() {
if isObjectWellKnownType(p) {
needsSanitizing = true
break
}
}
}
// Early return if the declaration requires no modification.
if !needsSanitizing {
return decl
}
// Sanitize all of the overloads if any overload requires an update to its type references.
overloads := make([]*exprpb.Decl_FunctionDecl_Overload, len(fn.GetOverloads()))
for i, o := range fn.GetOverloads() {
rt := o.GetResultType()
if isObjectWellKnownType(rt) {
rt = getObjectWellKnownType(rt)
}
params := make([]*exprpb.Type, len(o.GetParams()))
copy(params, o.GetParams())
for j, p := range params {
if isObjectWellKnownType(p) {
params[j] = getObjectWellKnownType(p)
}
}
// If sanitized, replace the overload definition.
if o.IsInstanceFunction {
overloads[i] =
decls.NewInstanceOverload(o.GetOverloadId(), params, rt)
} else {
overloads[i] =
decls.NewOverload(o.GetOverloadId(), params, rt)
}
}
return decls.NewFunction(decl.GetName(), overloads...)
}
// sanitizeIdent replaces the identifier's well-known types referenced by message name with
// references to CEL built-in type instances.
func sanitizeIdent(decl *exprpb.Decl) *exprpb.Decl {
id := decl.GetIdent()
t := id.GetType()
if !isObjectWellKnownType(t) {
return decl
}
return decls.NewIdent(decl.GetName(), getObjectWellKnownType(t), id.GetValue())
}
// isObjectWellKnownType returns true if the input type is an OBJECT type with a message name
// that corresponds the message name of a built-in CEL type.
func isObjectWellKnownType(t *exprpb.Type) bool {
if kindOf(t) != kindObject {
return false
}
_, found := pb.CheckedWellKnowns[t.GetMessageType()]
return found
}
// getObjectWellKnownType returns the built-in CEL type declaration for input type's message name.
func getObjectWellKnownType(t *exprpb.Type) *exprpb.Type {
return pb.CheckedWellKnowns[t.GetMessageType()]
}
// enterScope creates a new Env instance with a new innermost declaration scope.
func (e *Env) enterScope() *Env {
childDecls := e.declarations.Push()
return &Env{
declarations: childDecls,
container: e.container,
provider: e.provider,
aggLitElemType: e.aggLitElemType,
}
}
// exitScope creates a new Env instance with the nearest outer declaration scope.
func (e *Env) exitScope() *Env {
parentDecls := e.declarations.Pop()
return &Env{
declarations: parentDecls,
container: e.container,
provider: e.provider,
aggLitElemType: e.aggLitElemType,
}
}
// errorMsg is a type alias meant to represent error-based return values which
// may be accumulated into an error at a later point in execution.
type errorMsg string
func overlappingIdentifierError(name string) errorMsg {
return errorMsg(fmt.Sprintf("overlapping identifier for name '%s'", name))
}
func overlappingOverloadError(name string,
overloadID1 string, f1 *exprpb.Type,
overloadID2 string, f2 *exprpb.Type) errorMsg {
return errorMsg(fmt.Sprintf(
"overlapping overload for name '%s' (type '%s' with overloadId: '%s' "+
"cannot be distinguished from '%s' with overloadId: '%s')",
name,
FormatCheckedType(f1),
overloadID1,
FormatCheckedType(f2),
overloadID2))
}
func overlappingMacroError(name string, argCount int) errorMsg {
return errorMsg(fmt.Sprintf(
"overlapping macro for name '%s' with %d args", name, argCount))
}
func formatError(errMsgs []errorMsg) error {
errStrs := make([]string, 0)
if len(errMsgs) > 0 {
for i := 0; i < len(errMsgs); i++ {
if errMsgs[i] != "" {
errStrs = append(errStrs, string(errMsgs[i]))
}
}
}
if len(errStrs) > 0 {
return fmt.Errorf("%s", strings.Join(errStrs, "\n"))
}
return nil
}

100
vendor/github.com/google/cel-go/checker/errors.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
// 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 checker
import (
"github.com/google/cel-go/common"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// typeErrors is a specialization of Errors.
type typeErrors struct {
*common.Errors
}
func (e *typeErrors) undeclaredReference(l common.Location, container string, name string) {
e.ReportError(l, "undeclared reference to '%s' (in container '%s')", name, container)
}
func (e *typeErrors) expressionDoesNotSelectField(l common.Location) {
e.ReportError(l, "expression does not select a field")
}
func (e *typeErrors) typeDoesNotSupportFieldSelection(l common.Location, t *exprpb.Type) {
e.ReportError(l, "type '%s' does not support field selection", t)
}
func (e *typeErrors) undefinedField(l common.Location, field string) {
e.ReportError(l, "undefined field '%s'", field)
}
func (e *typeErrors) noMatchingOverload(l common.Location, name string, args []*exprpb.Type, isInstance bool) {
signature := formatFunction(nil, args, isInstance)
e.ReportError(l, "found no matching overload for '%s' applied to '%s'", name, signature)
}
func (e *typeErrors) notAType(l common.Location, t *exprpb.Type) {
e.ReportError(l, "'%s(%v)' is not a type", FormatCheckedType(t), t)
}
func (e *typeErrors) notAMessageType(l common.Location, t *exprpb.Type) {
e.ReportError(l, "'%s' is not a message type", FormatCheckedType(t))
}
func (e *typeErrors) fieldTypeMismatch(l common.Location, name string, field *exprpb.Type, value *exprpb.Type) {
e.ReportError(l, "expected type of field '%s' is '%s' but provided type is '%s'",
name, FormatCheckedType(field), FormatCheckedType(value))
}
func (e *typeErrors) unexpectedFailedResolution(l common.Location, typeName string) {
e.ReportError(l, "[internal] unexpected failed resolution of '%s'", typeName)
}
func (e *typeErrors) notAComprehensionRange(l common.Location, t *exprpb.Type) {
e.ReportError(l, "expression of type '%s' cannot be range of a comprehension (must be list, map, or dynamic)",
FormatCheckedType(t))
}
func (e *typeErrors) typeMismatch(l common.Location, expected *exprpb.Type, actual *exprpb.Type) {
e.ReportError(l, "expected type '%s' but found '%s'",
FormatCheckedType(expected), FormatCheckedType(actual))
}
func formatFunction(resultType *exprpb.Type, argTypes []*exprpb.Type, isInstance bool) string {
result := ""
if isInstance {
target := argTypes[0]
argTypes = argTypes[1:]
result += FormatCheckedType(target)
result += "."
}
result += "("
for i, arg := range argTypes {
if i > 0 {
result += ", "
}
result += FormatCheckedType(arg)
}
result += ")"
if resultType != nil {
result += " -> "
result += FormatCheckedType(resultType)
}
return result
}

49
vendor/github.com/google/cel-go/checker/mapping.go generated vendored Normal file
View File

@@ -0,0 +1,49 @@
// 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 checker
import (
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type mapping struct {
mapping map[string]*exprpb.Type
}
func newMapping() *mapping {
return &mapping{
mapping: make(map[string]*exprpb.Type),
}
}
func (m *mapping) add(from *exprpb.Type, to *exprpb.Type) {
m.mapping[typeKey(from)] = to
}
func (m *mapping) find(from *exprpb.Type) (*exprpb.Type, bool) {
if r, found := m.mapping[typeKey(from)]; found {
return r, found
}
return nil, false
}
func (m *mapping) copy() *mapping {
c := newMapping()
for k, v := range m.mapping {
c.mapping[k] = v
}
return c
}

71
vendor/github.com/google/cel-go/checker/printer.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
// 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 checker
import (
"github.com/google/cel-go/common/debug"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type semanticAdorner struct {
checks *exprpb.CheckedExpr
}
var _ debug.Adorner = &semanticAdorner{}
func (a *semanticAdorner) GetMetadata(elem interface{}) string {
result := ""
e, isExpr := elem.(*exprpb.Expr)
if !isExpr {
return result
}
t := a.checks.TypeMap[e.Id]
if t != nil {
result += "~"
result += FormatCheckedType(t)
}
switch e.ExprKind.(type) {
case *exprpb.Expr_IdentExpr,
*exprpb.Expr_CallExpr,
*exprpb.Expr_StructExpr,
*exprpb.Expr_SelectExpr:
if ref, found := a.checks.ReferenceMap[e.Id]; found {
if len(ref.GetOverloadId()) == 0 {
result += "^" + ref.Name
} else {
for i, overload := range ref.OverloadId {
if i == 0 {
result += "^"
} else {
result += "|"
}
result += overload
}
}
}
}
return result
}
// Print returns a string representation of the Expr message,
// annotated with types from the CheckedExpr. The Expr must
// be a sub-expression embedded in the CheckedExpr.
func Print(e *exprpb.Expr, checks *exprpb.CheckedExpr) string {
a := &semanticAdorner{checks: checks}
return debug.ToAdornedDebugString(e, a)
}

440
vendor/github.com/google/cel-go/checker/standard.go generated vendored Normal file
View File

@@ -0,0 +1,440 @@
// 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 checker
import (
"github.com/google/cel-go/checker/decls"
"github.com/google/cel-go/common/operators"
"github.com/google/cel-go/common/overloads"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// StandardDeclarations returns the Decls for all functions and constants in the evaluator.
func StandardDeclarations() []*exprpb.Decl {
// Some shortcuts we use when building declarations.
paramA := decls.NewTypeParamType("A")
typeParamAList := []string{"A"}
listOfA := decls.NewListType(paramA)
paramB := decls.NewTypeParamType("B")
typeParamABList := []string{"A", "B"}
mapOfAB := decls.NewMapType(paramA, paramB)
var idents []*exprpb.Decl
for _, t := range []*exprpb.Type{
decls.Int, decls.Uint, decls.Bool,
decls.Double, decls.Bytes, decls.String} {
idents = append(idents,
decls.NewVar(FormatCheckedType(t), decls.NewTypeType(t)))
}
idents = append(idents,
decls.NewVar("list", decls.NewTypeType(listOfA)),
decls.NewVar("map", decls.NewTypeType(mapOfAB)),
decls.NewVar("null_type", decls.NewTypeType(decls.Null)),
decls.NewVar("type", decls.NewTypeType(decls.NewTypeType(nil))))
// Booleans
// TODO: allow the conditional to return a heterogenous type.
return append(idents, []*exprpb.Decl{
decls.NewFunction(operators.Conditional,
decls.NewParameterizedOverload(overloads.Conditional,
[]*exprpb.Type{decls.Bool, paramA, paramA}, paramA,
typeParamAList)),
decls.NewFunction(operators.LogicalAnd,
decls.NewOverload(overloads.LogicalAnd,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool)),
decls.NewFunction(operators.LogicalOr,
decls.NewOverload(overloads.LogicalOr,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool)),
decls.NewFunction(operators.LogicalNot,
decls.NewOverload(overloads.LogicalNot,
[]*exprpb.Type{decls.Bool}, decls.Bool)),
decls.NewFunction(operators.NotStrictlyFalse,
decls.NewOverload(overloads.NotStrictlyFalse,
[]*exprpb.Type{decls.Bool}, decls.Bool)),
// Relations.
decls.NewFunction(operators.Less,
decls.NewOverload(overloads.LessBool,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
decls.NewOverload(overloads.LessInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
decls.NewOverload(overloads.LessUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
decls.NewOverload(overloads.LessDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
decls.NewOverload(overloads.LessString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
decls.NewOverload(overloads.LessBytes,
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
decls.NewOverload(overloads.LessTimestamp,
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
decls.NewOverload(overloads.LessDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
decls.NewFunction(operators.LessEquals,
decls.NewOverload(overloads.LessEqualsBool,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
decls.NewOverload(overloads.LessEqualsInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
decls.NewOverload(overloads.LessEqualsUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
decls.NewOverload(overloads.LessEqualsDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
decls.NewOverload(overloads.LessEqualsString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
decls.NewOverload(overloads.LessEqualsBytes,
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
decls.NewOverload(overloads.LessEqualsTimestamp,
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
decls.NewOverload(overloads.LessEqualsDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
decls.NewFunction(operators.Greater,
decls.NewOverload(overloads.GreaterBool,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
decls.NewOverload(overloads.GreaterInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
decls.NewOverload(overloads.GreaterUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
decls.NewOverload(overloads.GreaterDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
decls.NewOverload(overloads.GreaterString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
decls.NewOverload(overloads.GreaterBytes,
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
decls.NewOverload(overloads.GreaterTimestamp,
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
decls.NewOverload(overloads.GreaterDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
decls.NewFunction(operators.GreaterEquals,
decls.NewOverload(overloads.GreaterEqualsBool,
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsBytes,
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsTimestamp,
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
decls.NewOverload(overloads.GreaterEqualsDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
decls.NewFunction(operators.Equals,
decls.NewParameterizedOverload(overloads.Equals,
[]*exprpb.Type{paramA, paramA}, decls.Bool,
typeParamAList)),
decls.NewFunction(operators.NotEquals,
decls.NewParameterizedOverload(overloads.NotEquals,
[]*exprpb.Type{paramA, paramA}, decls.Bool,
typeParamAList)),
// Algebra.
decls.NewFunction(operators.Subtract,
decls.NewOverload(overloads.SubtractInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
decls.NewOverload(overloads.SubtractUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
decls.NewOverload(overloads.SubtractDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double),
decls.NewOverload(overloads.SubtractTimestampTimestamp,
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Duration),
decls.NewOverload(overloads.SubtractTimestampDuration,
[]*exprpb.Type{decls.Timestamp, decls.Duration}, decls.Timestamp),
decls.NewOverload(overloads.SubtractDurationDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Duration)),
decls.NewFunction(operators.Multiply,
decls.NewOverload(overloads.MultiplyInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
decls.NewOverload(overloads.MultiplyUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
decls.NewOverload(overloads.MultiplyDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double)),
decls.NewFunction(operators.Divide,
decls.NewOverload(overloads.DivideInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
decls.NewOverload(overloads.DivideUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
decls.NewOverload(overloads.DivideDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double)),
decls.NewFunction(operators.Modulo,
decls.NewOverload(overloads.ModuloInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
decls.NewOverload(overloads.ModuloUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint)),
decls.NewFunction(operators.Add,
decls.NewOverload(overloads.AddInt64,
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
decls.NewOverload(overloads.AddUint64,
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
decls.NewOverload(overloads.AddDouble,
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double),
decls.NewOverload(overloads.AddString,
[]*exprpb.Type{decls.String, decls.String}, decls.String),
decls.NewOverload(overloads.AddBytes,
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bytes),
decls.NewParameterizedOverload(overloads.AddList,
[]*exprpb.Type{listOfA, listOfA}, listOfA,
typeParamAList),
decls.NewOverload(overloads.AddTimestampDuration,
[]*exprpb.Type{decls.Timestamp, decls.Duration}, decls.Timestamp),
decls.NewOverload(overloads.AddDurationTimestamp,
[]*exprpb.Type{decls.Duration, decls.Timestamp}, decls.Timestamp),
decls.NewOverload(overloads.AddDurationDuration,
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Duration)),
decls.NewFunction(operators.Negate,
decls.NewOverload(overloads.NegateInt64,
[]*exprpb.Type{decls.Int}, decls.Int),
decls.NewOverload(overloads.NegateDouble,
[]*exprpb.Type{decls.Double}, decls.Double)),
// Index.
decls.NewFunction(operators.Index,
decls.NewParameterizedOverload(overloads.IndexList,
[]*exprpb.Type{listOfA, decls.Int}, paramA,
typeParamAList),
decls.NewParameterizedOverload(overloads.IndexMap,
[]*exprpb.Type{mapOfAB, paramA}, paramB,
typeParamABList)),
//decls.NewOverload(overloads.IndexMessage,
// []*expr.Type{decls.Dyn, decls.String}, decls.Dyn)),
// Collections.
decls.NewFunction(overloads.Size,
decls.NewInstanceOverload(overloads.SizeStringInst,
[]*exprpb.Type{decls.String}, decls.Int),
decls.NewInstanceOverload(overloads.SizeBytesInst,
[]*exprpb.Type{decls.Bytes}, decls.Int),
decls.NewParameterizedInstanceOverload(overloads.SizeListInst,
[]*exprpb.Type{listOfA}, decls.Int, typeParamAList),
decls.NewParameterizedInstanceOverload(overloads.SizeMapInst,
[]*exprpb.Type{mapOfAB}, decls.Int, typeParamABList),
decls.NewOverload(overloads.SizeString,
[]*exprpb.Type{decls.String}, decls.Int),
decls.NewOverload(overloads.SizeBytes,
[]*exprpb.Type{decls.Bytes}, decls.Int),
decls.NewParameterizedOverload(overloads.SizeList,
[]*exprpb.Type{listOfA}, decls.Int, typeParamAList),
decls.NewParameterizedOverload(overloads.SizeMap,
[]*exprpb.Type{mapOfAB}, decls.Int, typeParamABList)),
decls.NewFunction(operators.In,
decls.NewParameterizedOverload(overloads.InList,
[]*exprpb.Type{paramA, listOfA}, decls.Bool,
typeParamAList),
decls.NewParameterizedOverload(overloads.InMap,
[]*exprpb.Type{paramA, mapOfAB}, decls.Bool,
typeParamABList)),
// Deprecated 'in()' function.
decls.NewFunction(overloads.DeprecatedIn,
decls.NewParameterizedOverload(overloads.InList,
[]*exprpb.Type{paramA, listOfA}, decls.Bool,
typeParamAList),
decls.NewParameterizedOverload(overloads.InMap,
[]*exprpb.Type{paramA, mapOfAB}, decls.Bool,
typeParamABList)),
//decls.NewOverload(overloads.InMessage,
// []*expr.Type{Dyn, decls.String},decls.Bool)),
// Conversions to type.
decls.NewFunction(overloads.TypeConvertType,
decls.NewParameterizedOverload(overloads.TypeConvertType,
[]*exprpb.Type{paramA}, decls.NewTypeType(paramA), typeParamAList)),
// Conversions to int.
decls.NewFunction(overloads.TypeConvertInt,
decls.NewOverload(overloads.IntToInt, []*exprpb.Type{decls.Int}, decls.Int),
decls.NewOverload(overloads.UintToInt, []*exprpb.Type{decls.Uint}, decls.Int),
decls.NewOverload(overloads.DoubleToInt, []*exprpb.Type{decls.Double}, decls.Int),
decls.NewOverload(overloads.StringToInt, []*exprpb.Type{decls.String}, decls.Int),
decls.NewOverload(overloads.TimestampToInt, []*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewOverload(overloads.DurationToInt, []*exprpb.Type{decls.Duration}, decls.Int)),
// Conversions to uint.
decls.NewFunction(overloads.TypeConvertUint,
decls.NewOverload(overloads.UintToUint, []*exprpb.Type{decls.Uint}, decls.Uint),
decls.NewOverload(overloads.IntToUint, []*exprpb.Type{decls.Int}, decls.Uint),
decls.NewOverload(overloads.DoubleToUint, []*exprpb.Type{decls.Double}, decls.Uint),
decls.NewOverload(overloads.StringToUint, []*exprpb.Type{decls.String}, decls.Uint)),
// Conversions to double.
decls.NewFunction(overloads.TypeConvertDouble,
decls.NewOverload(overloads.DoubleToDouble, []*exprpb.Type{decls.Double}, decls.Double),
decls.NewOverload(overloads.IntToDouble, []*exprpb.Type{decls.Int}, decls.Double),
decls.NewOverload(overloads.UintToDouble, []*exprpb.Type{decls.Uint}, decls.Double),
decls.NewOverload(overloads.StringToDouble, []*exprpb.Type{decls.String}, decls.Double)),
// Conversions to bool.
decls.NewFunction(overloads.TypeConvertBool,
decls.NewOverload(overloads.BoolToBool, []*exprpb.Type{decls.Bool}, decls.Bool),
decls.NewOverload(overloads.StringToBool, []*exprpb.Type{decls.String}, decls.Bool)),
// Conversions to string.
decls.NewFunction(overloads.TypeConvertString,
decls.NewOverload(overloads.StringToString, []*exprpb.Type{decls.String}, decls.String),
decls.NewOverload(overloads.BoolToString, []*exprpb.Type{decls.Bool}, decls.String),
decls.NewOverload(overloads.IntToString, []*exprpb.Type{decls.Int}, decls.String),
decls.NewOverload(overloads.UintToString, []*exprpb.Type{decls.Uint}, decls.String),
decls.NewOverload(overloads.DoubleToString, []*exprpb.Type{decls.Double}, decls.String),
decls.NewOverload(overloads.BytesToString, []*exprpb.Type{decls.Bytes}, decls.String),
decls.NewOverload(overloads.TimestampToString, []*exprpb.Type{decls.Timestamp}, decls.String),
decls.NewOverload(overloads.DurationToString, []*exprpb.Type{decls.Duration}, decls.String)),
// Conversions to bytes.
decls.NewFunction(overloads.TypeConvertBytes,
decls.NewOverload(overloads.BytesToBytes, []*exprpb.Type{decls.Bytes}, decls.Bytes),
decls.NewOverload(overloads.StringToBytes, []*exprpb.Type{decls.String}, decls.Bytes)),
// Conversions to timestamps.
decls.NewFunction(overloads.TypeConvertTimestamp,
decls.NewOverload(overloads.TimestampToTimestamp,
[]*exprpb.Type{decls.Timestamp}, decls.Timestamp),
decls.NewOverload(overloads.StringToTimestamp,
[]*exprpb.Type{decls.String}, decls.Timestamp),
decls.NewOverload(overloads.IntToTimestamp,
[]*exprpb.Type{decls.Int}, decls.Timestamp)),
// Conversions to durations.
decls.NewFunction(overloads.TypeConvertDuration,
decls.NewOverload(overloads.DurationToDuration,
[]*exprpb.Type{decls.Duration}, decls.Duration),
decls.NewOverload(overloads.StringToDuration,
[]*exprpb.Type{decls.String}, decls.Duration),
decls.NewOverload(overloads.IntToDuration,
[]*exprpb.Type{decls.Int}, decls.Duration)),
// Conversions to Dyn.
decls.NewFunction(overloads.TypeConvertDyn,
decls.NewParameterizedOverload(overloads.ToDyn,
[]*exprpb.Type{paramA}, decls.Dyn,
typeParamAList)),
// String functions.
decls.NewFunction(overloads.Contains,
decls.NewInstanceOverload(overloads.ContainsString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
decls.NewFunction(overloads.EndsWith,
decls.NewInstanceOverload(overloads.EndsWithString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
decls.NewFunction(overloads.Matches,
decls.NewInstanceOverload(overloads.MatchesString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
decls.NewFunction(overloads.StartsWith,
decls.NewInstanceOverload(overloads.StartsWithString,
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
// Date/time functions.
decls.NewFunction(overloads.TimeGetFullYear,
decls.NewInstanceOverload(overloads.TimestampToYear,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToYearWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetMonth,
decls.NewInstanceOverload(overloads.TimestampToMonth,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToMonthWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetDayOfYear,
decls.NewInstanceOverload(overloads.TimestampToDayOfYear,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToDayOfYearWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetDayOfMonth,
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthZeroBased,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthZeroBasedWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetDate,
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthOneBased,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthOneBasedWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetDayOfWeek,
decls.NewInstanceOverload(overloads.TimestampToDayOfWeek,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToDayOfWeekWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
decls.NewFunction(overloads.TimeGetHours,
decls.NewInstanceOverload(overloads.TimestampToHours,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToHoursWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
decls.NewInstanceOverload(overloads.DurationToHours,
[]*exprpb.Type{decls.Duration}, decls.Int)),
decls.NewFunction(overloads.TimeGetMinutes,
decls.NewInstanceOverload(overloads.TimestampToMinutes,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToMinutesWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
decls.NewInstanceOverload(overloads.DurationToMinutes,
[]*exprpb.Type{decls.Duration}, decls.Int)),
decls.NewFunction(overloads.TimeGetSeconds,
decls.NewInstanceOverload(overloads.TimestampToSeconds,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToSecondsWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
decls.NewInstanceOverload(overloads.DurationToSeconds,
[]*exprpb.Type{decls.Duration}, decls.Int)),
decls.NewFunction(overloads.TimeGetMilliseconds,
decls.NewInstanceOverload(overloads.TimestampToMilliseconds,
[]*exprpb.Type{decls.Timestamp}, decls.Int),
decls.NewInstanceOverload(overloads.TimestampToMillisecondsWithTz,
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
decls.NewInstanceOverload(overloads.DurationToMilliseconds,
[]*exprpb.Type{decls.Duration}, decls.Int))}...)
}

505
vendor/github.com/google/cel-go/checker/types.go generated vendored Normal file
View File

@@ -0,0 +1,505 @@
// 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 checker
import (
"fmt"
"strings"
"github.com/google/cel-go/checker/decls"
"google.golang.org/protobuf/proto"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
const (
kindUnknown = iota + 1
kindError
kindFunction
kindDyn
kindPrimitive
kindWellKnown
kindWrapper
kindNull
kindAbstract
kindType
kindList
kindMap
kindObject
kindTypeParam
)
// FormatCheckedType converts a type message into a string representation.
func FormatCheckedType(t *exprpb.Type) string {
switch kindOf(t) {
case kindDyn:
return "dyn"
case kindFunction:
return formatFunction(t.GetFunction().GetResultType(),
t.GetFunction().GetArgTypes(),
false)
case kindList:
return fmt.Sprintf("list(%s)", FormatCheckedType(t.GetListType().ElemType))
case kindObject:
return t.GetMessageType()
case kindMap:
return fmt.Sprintf("map(%s, %s)",
FormatCheckedType(t.GetMapType().KeyType),
FormatCheckedType(t.GetMapType().ValueType))
case kindNull:
return "null"
case kindPrimitive:
switch t.GetPrimitive() {
case exprpb.Type_UINT64:
return "uint"
case exprpb.Type_INT64:
return "int"
}
return strings.Trim(strings.ToLower(t.GetPrimitive().String()), " ")
case kindType:
if t.GetType() == nil {
return "type"
}
return fmt.Sprintf("type(%s)", FormatCheckedType(t.GetType()))
case kindWellKnown:
switch t.GetWellKnown() {
case exprpb.Type_ANY:
return "any"
case exprpb.Type_DURATION:
return "duration"
case exprpb.Type_TIMESTAMP:
return "timestamp"
}
case kindWrapper:
return fmt.Sprintf("wrapper(%s)",
FormatCheckedType(decls.NewPrimitiveType(t.GetWrapper())))
case kindError:
return "!error!"
}
return t.String()
}
// isDyn returns true if the input t is either type DYN or a well-known ANY message.
func isDyn(t *exprpb.Type) bool {
// Note: object type values that are well-known and map to a DYN value in practice
// are sanitized prior to being added to the environment.
switch kindOf(t) {
case kindDyn:
return true
case kindWellKnown:
return t.GetWellKnown() == exprpb.Type_ANY
default:
return false
}
}
// isDynOrError returns true if the input is either an Error, DYN, or well-known ANY message.
func isDynOrError(t *exprpb.Type) bool {
switch kindOf(t) {
case kindError:
return true
default:
return isDyn(t)
}
}
// isEqualOrLessSpecific checks whether one type is equal or less specific than the other one.
// A type is less specific if it matches the other type using the DYN type.
func isEqualOrLessSpecific(t1 *exprpb.Type, t2 *exprpb.Type) bool {
kind1, kind2 := kindOf(t1), kindOf(t2)
// The first type is less specific.
if isDyn(t1) || kind1 == kindTypeParam {
return true
}
// The first type is not less specific.
if isDyn(t2) || kind2 == kindTypeParam {
return false
}
// Types must be of the same kind to be equal.
if kind1 != kind2 {
return false
}
// With limited exceptions for ANY and JSON values, the types must agree and be equivalent in
// order to return true.
switch kind1 {
case kindAbstract:
a1 := t1.GetAbstractType()
a2 := t2.GetAbstractType()
if a1.GetName() != a2.GetName() ||
len(a1.GetParameterTypes()) != len(a2.GetParameterTypes()) {
return false
}
for i, p1 := range a1.GetParameterTypes() {
if !isEqualOrLessSpecific(p1, a2.GetParameterTypes()[i]) {
return false
}
}
return true
case kindFunction:
fn1 := t1.GetFunction()
fn2 := t2.GetFunction()
if len(fn1.ArgTypes) != len(fn2.ArgTypes) {
return false
}
if !isEqualOrLessSpecific(fn1.ResultType, fn2.ResultType) {
return false
}
for i, a1 := range fn1.ArgTypes {
if !isEqualOrLessSpecific(a1, fn2.ArgTypes[i]) {
return false
}
}
return true
case kindList:
return isEqualOrLessSpecific(t1.GetListType().ElemType, t2.GetListType().ElemType)
case kindMap:
m1 := t1.GetMapType()
m2 := t2.GetMapType()
return isEqualOrLessSpecific(m1.KeyType, m2.KeyType) &&
isEqualOrLessSpecific(m1.ValueType, m2.ValueType)
case kindType:
return true
default:
return proto.Equal(t1, t2)
}
}
/// internalIsAssignable returns true if t1 is assignable to t2.
func internalIsAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) bool {
// A type is always assignable to itself.
// Early terminate the call to avoid cases of infinite recursion.
if proto.Equal(t1, t2) {
return true
}
// Process type parameters.
kind1, kind2 := kindOf(t1), kindOf(t2)
if kind2 == kindTypeParam {
if t2Sub, found := m.find(t2); found {
// If the types are compatible, pick the more general type and return true
if !internalIsAssignable(m, t1, t2Sub) {
return false
}
m.add(t2, mostGeneral(t1, t2Sub))
return true
}
if notReferencedIn(m, t2, t1) {
m.add(t2, t1)
return true
}
}
if kind1 == kindTypeParam {
// For the lower type bound, we currently do not perform adjustment. The restricted
// way we use type parameters in lower type bounds, it is not necessary, but may
// become if we generalize type unification.
if t1Sub, found := m.find(t1); found {
// If the types are compatible, pick the more general type and return true
if !internalIsAssignable(m, t1Sub, t2) {
return false
}
m.add(t1, mostGeneral(t1Sub, t2))
return true
}
if notReferencedIn(m, t1, t2) {
m.add(t1, t2)
return true
}
}
// Next check for wildcard types.
if isDynOrError(t1) || isDynOrError(t2) {
return true
}
// Test for when the types do not need to agree, but are more specific than dyn.
switch kind1 {
case kindNull:
return internalIsAssignableNull(t2)
case kindPrimitive:
return internalIsAssignablePrimitive(t1.GetPrimitive(), t2)
case kindWrapper:
return internalIsAssignable(m, decls.NewPrimitiveType(t1.GetWrapper()), t2)
default:
if kind1 != kind2 {
return false
}
}
// Test for when the types must agree.
switch kind1 {
// ERROR, TYPE_PARAM, and DYN handled above.
case kindAbstract:
return internalIsAssignableAbstractType(m, t1.GetAbstractType(), t2.GetAbstractType())
case kindFunction:
return internalIsAssignableFunction(m, t1.GetFunction(), t2.GetFunction())
case kindList:
return internalIsAssignable(m, t1.GetListType().GetElemType(), t2.GetListType().GetElemType())
case kindMap:
return internalIsAssignableMap(m, t1.GetMapType(), t2.GetMapType())
case kindObject:
return t1.GetMessageType() == t2.GetMessageType()
case kindType:
// A type is a type is a type, any additional parameterization of the
// type cannot affect method resolution or assignability.
return true
case kindWellKnown:
return t1.GetWellKnown() == t2.GetWellKnown()
default:
return false
}
}
// internalIsAssignableAbstractType returns true if the abstract type names agree and all type
// parameters are assignable.
func internalIsAssignableAbstractType(m *mapping,
a1 *exprpb.Type_AbstractType,
a2 *exprpb.Type_AbstractType) bool {
if a1.GetName() != a2.GetName() {
return false
}
if internalIsAssignableList(m, a1.GetParameterTypes(), a2.GetParameterTypes()) {
return true
}
return false
}
// internalIsAssignableFunction returns true if the function return type and arg types are
// assignable.
func internalIsAssignableFunction(m *mapping,
f1 *exprpb.Type_FunctionType,
f2 *exprpb.Type_FunctionType) bool {
f1ArgTypes := flattenFunctionTypes(f1)
f2ArgTypes := flattenFunctionTypes(f2)
if internalIsAssignableList(m, f1ArgTypes, f2ArgTypes) {
return true
}
return false
}
// internalIsAssignableList returns true if the element types at each index in the list are
// assignable from l1[i] to l2[i]. The list lengths must also agree for the lists to be
// assignable.
func internalIsAssignableList(m *mapping, l1 []*exprpb.Type, l2 []*exprpb.Type) bool {
if len(l1) != len(l2) {
return false
}
for i, t1 := range l1 {
if !internalIsAssignable(m, t1, l2[i]) {
return false
}
}
return true
}
// internalIsAssignableMap returns true if map m1 may be assigned to map m2.
func internalIsAssignableMap(m *mapping, m1 *exprpb.Type_MapType, m2 *exprpb.Type_MapType) bool {
if internalIsAssignableList(m,
[]*exprpb.Type{m1.GetKeyType(), m1.GetValueType()},
[]*exprpb.Type{m2.GetKeyType(), m2.GetValueType()}) {
return true
}
return false
}
// internalIsAssignableNull returns true if the type is nullable.
func internalIsAssignableNull(t *exprpb.Type) bool {
switch kindOf(t) {
case kindAbstract, kindObject, kindNull, kindWellKnown, kindWrapper:
return true
default:
return false
}
}
// internalIsAssignablePrimitive returns true if the target type is the same or if it is a wrapper
// for the primitive type.
func internalIsAssignablePrimitive(p exprpb.Type_PrimitiveType, target *exprpb.Type) bool {
switch kindOf(target) {
case kindPrimitive:
return p == target.GetPrimitive()
case kindWrapper:
return p == target.GetWrapper()
default:
return false
}
}
// isAssignable returns an updated type substitution mapping if t1 is assignable to t2.
func isAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) *mapping {
mCopy := m.copy()
if internalIsAssignable(mCopy, t1, t2) {
return mCopy
}
return nil
}
// isAssignableList returns an updated type substitution mapping if l1 is assignable to l2.
func isAssignableList(m *mapping, l1 []*exprpb.Type, l2 []*exprpb.Type) *mapping {
mCopy := m.copy()
if internalIsAssignableList(mCopy, l1, l2) {
return mCopy
}
return nil
}
// kindOf returns the kind of the type as defined in the checked.proto.
func kindOf(t *exprpb.Type) int {
if t == nil || t.TypeKind == nil {
return kindUnknown
}
switch t.TypeKind.(type) {
case *exprpb.Type_Error:
return kindError
case *exprpb.Type_Function:
return kindFunction
case *exprpb.Type_Dyn:
return kindDyn
case *exprpb.Type_Primitive:
return kindPrimitive
case *exprpb.Type_WellKnown:
return kindWellKnown
case *exprpb.Type_Wrapper:
return kindWrapper
case *exprpb.Type_Null:
return kindNull
case *exprpb.Type_Type:
return kindType
case *exprpb.Type_ListType_:
return kindList
case *exprpb.Type_MapType_:
return kindMap
case *exprpb.Type_MessageType:
return kindObject
case *exprpb.Type_TypeParam:
return kindTypeParam
case *exprpb.Type_AbstractType_:
return kindAbstract
}
return kindUnknown
}
// mostGeneral returns the more general of two types which are known to unify.
func mostGeneral(t1 *exprpb.Type, t2 *exprpb.Type) *exprpb.Type {
if isEqualOrLessSpecific(t1, t2) {
return t1
}
return t2
}
// notReferencedIn checks whether the type doesn't appear directly or transitively within the other
// type. This is a standard requirement for type unification, commonly referred to as the "occurs
// check".
func notReferencedIn(m *mapping, t *exprpb.Type, withinType *exprpb.Type) bool {
if proto.Equal(t, withinType) {
return false
}
withinKind := kindOf(withinType)
switch withinKind {
case kindTypeParam:
wtSub, found := m.find(withinType)
if !found {
return true
}
return notReferencedIn(m, t, wtSub)
case kindAbstract:
for _, pt := range withinType.GetAbstractType().GetParameterTypes() {
if !notReferencedIn(m, t, pt) {
return false
}
}
return true
case kindFunction:
fn := withinType.GetFunction()
types := flattenFunctionTypes(fn)
for _, a := range types {
if !notReferencedIn(m, t, a) {
return false
}
}
return true
case kindList:
return notReferencedIn(m, t, withinType.GetListType().ElemType)
case kindMap:
mt := withinType.GetMapType()
return notReferencedIn(m, t, mt.KeyType) && notReferencedIn(m, t, mt.ValueType)
case kindWrapper:
return notReferencedIn(m, t, decls.NewPrimitiveType(withinType.GetWrapper()))
default:
return true
}
}
// substitute replaces all direct and indirect occurrences of bound type parameters. Unbound type
// parameters are replaced by DYN if typeParamToDyn is true.
func substitute(m *mapping, t *exprpb.Type, typeParamToDyn bool) *exprpb.Type {
if tSub, found := m.find(t); found {
return substitute(m, tSub, typeParamToDyn)
}
kind := kindOf(t)
if typeParamToDyn && kind == kindTypeParam {
return decls.Dyn
}
switch kind {
case kindAbstract:
// TODO: implement!
at := t.GetAbstractType()
params := make([]*exprpb.Type, len(at.GetParameterTypes()))
for i, p := range at.GetParameterTypes() {
params[i] = substitute(m, p, typeParamToDyn)
}
return decls.NewAbstractType(at.GetName(), params...)
case kindFunction:
fn := t.GetFunction()
rt := substitute(m, fn.ResultType, typeParamToDyn)
args := make([]*exprpb.Type, len(fn.ArgTypes))
for i, a := range fn.ArgTypes {
args[i] = substitute(m, a, typeParamToDyn)
}
return decls.NewFunctionType(rt, args...)
case kindList:
return decls.NewListType(substitute(m, t.GetListType().ElemType, typeParamToDyn))
case kindMap:
mt := t.GetMapType()
return decls.NewMapType(substitute(m, mt.KeyType, typeParamToDyn),
substitute(m, mt.ValueType, typeParamToDyn))
case kindType:
if t.GetType() != nil {
return decls.NewTypeType(substitute(m, t.GetType(), typeParamToDyn))
}
return t
default:
return t
}
}
func typeKey(t *exprpb.Type) string {
return FormatCheckedType(t)
}
// flattenFunctionTypes takes a function with arg types T1, T2, ..., TN and result type TR
// and returns a slice containing {T1, T2, ..., TN, TR}.
func flattenFunctionTypes(f *exprpb.Type_FunctionType) []*exprpb.Type {
argTypes := f.GetArgTypes()
if len(argTypes) == 0 {
return []*exprpb.Type{f.GetResultType()}
}
flattend := make([]*exprpb.Type, len(argTypes)+1, len(argTypes)+1)
for i, at := range argTypes {
flattend[i] = at
}
flattend[len(argTypes)] = f.GetResultType()
return flattend
}

34
vendor/github.com/google/cel-go/common/BUILD.bazel generated vendored Normal file
View File

@@ -0,0 +1,34 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"error.go",
"errors.go",
"location.go",
"source.go",
],
importpath = "github.com/google/cel-go/common",
deps = [
"//common/runes:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_x_text//width:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"errors_test.go",
"source_test.go",
],
embed = [
":go_default_library",
],
)

View File

@@ -0,0 +1,31 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"container.go",
],
importpath = "github.com/google/cel-go/common/containers",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"container_test.go",
],
embed = [
":go_default_library",
],
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)

View File

@@ -0,0 +1,316 @@
// 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 containers defines types and functions for resolving qualified names within a namespace
// or type provided to CEL.
package containers
import (
"fmt"
"strings"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
var (
// DefaultContainer has an empty container name.
DefaultContainer *Container = nil
// Empty map to search for aliases when needed.
noAliases = make(map[string]string)
)
// NewContainer creates a new Container with the fully-qualified name.
func NewContainer(opts ...ContainerOption) (*Container, error) {
var c *Container
var err error
for _, opt := range opts {
c, err = opt(c)
if err != nil {
return nil, err
}
}
return c, nil
}
// Container holds a reference to an optional qualified container name and set of aliases.
//
// The program container can be used to simplify variable, function, and type specification within
// CEL programs and behaves more or less like a C++ namespace. See ResolveCandidateNames for more
// details.
type Container struct {
name string
aliases map[string]string
}
// Extend creates a new Container with the existing settings and applies a series of
// ContainerOptions to further configure the new container.
func (c *Container) Extend(opts ...ContainerOption) (*Container, error) {
if c == nil {
return NewContainer(opts...)
}
// Copy the name and aliases of the existing container.
ext := &Container{name: c.Name()}
if len(c.aliasSet()) > 0 {
aliasSet := make(map[string]string, len(c.aliasSet()))
for k, v := range c.aliasSet() {
aliasSet[k] = v
}
ext.aliases = aliasSet
}
// Apply the new options to the container.
var err error
for _, opt := range opts {
ext, err = opt(ext)
if err != nil {
return nil, err
}
}
return ext, nil
}
// Name returns the fully-qualified name of the container.
//
// The name may conceptually be a namespace, package, or type.
func (c *Container) Name() string {
if c == nil {
return ""
}
return c.name
}
// ResolveCandidateNames returns the candidates name of namespaced identifiers in C++ resolution
// order.
//
// Names which shadow other names are returned first. If a name includes a leading dot ('.'),
// the name is treated as an absolute identifier which cannot be shadowed.
//
// Given a container name a.b.c.M.N and a type name R.s, this will deliver in order:
//
// a.b.c.M.N.R.s
// a.b.c.M.R.s
// a.b.c.R.s
// a.b.R.s
// a.R.s
// R.s
//
// If aliases or abbreviations are configured for the container, then alias names will take
// precedence over containerized names.
func (c *Container) ResolveCandidateNames(name string) []string {
if strings.HasPrefix(name, ".") {
qn := name[1:]
alias, isAlias := c.findAlias(qn)
if isAlias {
return []string{alias}
}
return []string{qn}
}
alias, isAlias := c.findAlias(name)
if isAlias {
return []string{alias}
}
if c.Name() == "" {
return []string{name}
}
nextCont := c.Name()
candidates := []string{nextCont + "." + name}
for i := strings.LastIndex(nextCont, "."); i >= 0; i = strings.LastIndex(nextCont, ".") {
nextCont = nextCont[:i]
candidates = append(candidates, nextCont+"."+name)
}
return append(candidates, name)
}
// aliasSet returns the alias to fully-qualified name mapping stored in the container.
func (c *Container) aliasSet() map[string]string {
if c == nil || c.aliases == nil {
return noAliases
}
return c.aliases
}
// findAlias takes a name as input and returns an alias expansion if one exists.
//
// If the name is qualified, the first component of the qualified name is checked against known
// aliases. Any alias that is found in a qualified name is expanded in the result:
//
// alias: R -> my.alias.R
// name: R.S.T
// output: my.alias.R.S.T
//
// Note, the name must not have a leading dot.
func (c *Container) findAlias(name string) (string, bool) {
// If an alias exists for the name, ensure it is searched last.
simple := name
qualifier := ""
dot := strings.Index(name, ".")
if dot >= 0 {
simple = name[0:dot]
qualifier = name[dot:]
}
alias, found := c.aliasSet()[simple]
if !found {
return "", false
}
return alias + qualifier, true
}
// ContainerOption specifies a functional configuration option for a Container.
//
// Note, ContainerOption implementations must be able to handle nil container inputs.
type ContainerOption func(*Container) (*Container, error)
// Abbrevs configures a set of simple names as abbreviations for fully-qualified names.
//
// An abbreviation (abbrev for short) is a simple name that expands to a fully-qualified name.
// Abbreviations can be useful when working with variables, functions, and especially types from
// multiple namespaces:
//
// // CEL object construction
// qual.pkg.version.ObjTypeName{
// field: alt.container.ver.FieldTypeName{value: ...}
// }
//
// Only one the qualified names above may be used as the CEL container, so at least one of these
// references must be a long qualified name within an otherwise short CEL program. Using the
// following abbreviations, the program becomes much simpler:
//
// // CEL Go option
// Abbrevs("qual.pkg.version.ObjTypeName", "alt.container.ver.FieldTypeName")
// // Simplified Object construction
// ObjTypeName{field: FieldTypeName{value: ...}}
//
// There are a few rules for the qualified names and the simple abbreviations generated from them:
// - Qualified names must be dot-delimited, e.g. `package.subpkg.name`.
// - The last element in the qualified name is the abbreviation.
// - Abbreviations must not collide with each other.
// - The abbreviation must not collide with unqualified names in use.
//
// Abbreviations are distinct from container-based references in the following important ways:
// - Abbreviations must expand to a fully-qualified name.
// - Expanded abbreviations do not participate in namespace resolution.
// - Abbreviation expansion is done instead of the container search for a matching identifier.
// - Containers follow C++ namespace resolution rules with searches from the most qualified name
// to the least qualified name.
// - Container references within the CEL program may be relative, and are resolved to fully
// qualified names at either type-check time or program plan time, whichever comes first.
//
// If there is ever a case where an identifier could be in both the container and as an
// abbreviation, the abbreviation wins as this will ensure that the meaning of a program is
// preserved between compilations even as the container evolves.
func Abbrevs(qualifiedNames ...string) ContainerOption {
return func(c *Container) (*Container, error) {
for _, qn := range qualifiedNames {
ind := strings.LastIndex(qn, ".")
if ind <= 0 || ind >= len(qn)-1 {
return nil, fmt.Errorf(
"invalid qualified name: %s, wanted name of the form 'qualified.name'", qn)
}
alias := qn[ind+1:]
var err error
c, err = aliasAs("abbreviation", qn, alias)(c)
if err != nil {
return nil, err
}
}
return c, nil
}
}
// Alias associates a fully-qualified name with a user-defined alias.
//
// In general, Abbrevs is preferred to Alias since the names generated from the Abbrevs option
// are more easily traced back to source code. The Alias option is useful for propagating alias
// configuration from one Container instance to another, and may also be useful for remapping
// poorly chosen protobuf message / package names.
//
// Note: all of the rules that apply to Abbrevs also apply to Alias.
func Alias(qualifiedName, alias string) ContainerOption {
return aliasAs("alias", qualifiedName, alias)
}
func aliasAs(kind, qualifiedName, alias string) ContainerOption {
return func(c *Container) (*Container, error) {
if len(alias) == 0 || strings.Contains(alias, ".") {
return nil, fmt.Errorf(
"%s must be non-empty and simple (not qualified): %s=%s", kind, kind, alias)
}
if qualifiedName[0:1] == "." {
return nil, fmt.Errorf("qualified name must not begin with a leading '.': %s",
qualifiedName)
}
ind := strings.LastIndex(qualifiedName, ".")
if ind <= 0 || ind == len(qualifiedName)-1 {
return nil, fmt.Errorf("%s must refer to a valid qualified name: %s",
kind, qualifiedName)
}
aliasRef, found := c.aliasSet()[alias]
if found {
return nil, fmt.Errorf(
"%s collides with existing reference: name=%s, %s=%s, existing=%s",
kind, qualifiedName, kind, alias, aliasRef)
}
if strings.HasPrefix(c.Name(), alias+".") || c.Name() == alias {
return nil, fmt.Errorf(
"%s collides with container name: name=%s, %s=%s, container=%s",
kind, qualifiedName, kind, alias, c.Name())
}
if c == nil {
c = &Container{}
}
if c.aliases == nil {
c.aliases = make(map[string]string)
}
c.aliases[alias] = qualifiedName
return c, nil
}
}
// Name sets the fully-qualified name of the Container.
func Name(name string) ContainerOption {
return func(c *Container) (*Container, error) {
if len(name) > 0 && name[0:1] == "." {
return nil, fmt.Errorf("container name must not contain a leading '.': %s", name)
}
if c.Name() == name {
return c, nil
}
if c == nil {
return &Container{name: name}, nil
}
c.name = name
return c, nil
}
}
// ToQualifiedName converts an expression AST into a qualified name if possible, with a boolean
// 'found' value that indicates if the conversion is successful.
func ToQualifiedName(e *exprpb.Expr) (string, bool) {
switch e.ExprKind.(type) {
case *exprpb.Expr_IdentExpr:
id := e.GetIdentExpr()
return id.Name, true
case *exprpb.Expr_SelectExpr:
sel := e.GetSelectExpr()
// Test only expressions are not valid as qualified names.
if sel.GetTestOnly() {
return "", false
}
if qual, found := ToQualifiedName(sel.Operand); found {
return qual + "." + sel.Field, true
}
}
return "", false
}

View File

@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"debug.go",
],
importpath = "github.com/google/cel-go/common/debug",
deps = [
"//common:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
],
)

305
vendor/github.com/google/cel-go/common/debug/debug.go generated vendored Normal file
View File

@@ -0,0 +1,305 @@
// 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 debug provides tools to print a parsed expression graph and
// adorn each expression element with additional metadata.
package debug
import (
"bytes"
"fmt"
"strconv"
"strings"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Adorner returns debug metadata that will be tacked on to the string
// representation of an expression.
type Adorner interface {
// GetMetadata for the input context.
GetMetadata(ctx interface{}) string
}
// Writer manages writing expressions to an internal string.
type Writer interface {
fmt.Stringer
// Buffer pushes an expression into an internal queue of expressions to
// write to a string.
Buffer(e *exprpb.Expr)
}
type emptyDebugAdorner struct {
}
var emptyAdorner Adorner = &emptyDebugAdorner{}
func (a *emptyDebugAdorner) GetMetadata(e interface{}) string {
return ""
}
// ToDebugString gives the unadorned string representation of the Expr.
func ToDebugString(e *exprpb.Expr) string {
return ToAdornedDebugString(e, emptyAdorner)
}
// ToAdornedDebugString gives the adorned string representation of the Expr.
func ToAdornedDebugString(e *exprpb.Expr, adorner Adorner) string {
w := newDebugWriter(adorner)
w.Buffer(e)
return w.String()
}
// debugWriter is used to print out pretty-printed debug strings.
type debugWriter struct {
adorner Adorner
buffer bytes.Buffer
indent int
lineStart bool
}
func newDebugWriter(a Adorner) *debugWriter {
return &debugWriter{
adorner: a,
indent: 0,
lineStart: true,
}
}
func (w *debugWriter) Buffer(e *exprpb.Expr) {
if e == nil {
return
}
switch e.ExprKind.(type) {
case *exprpb.Expr_ConstExpr:
w.append(formatLiteral(e.GetConstExpr()))
case *exprpb.Expr_IdentExpr:
w.append(e.GetIdentExpr().Name)
case *exprpb.Expr_SelectExpr:
w.appendSelect(e.GetSelectExpr())
case *exprpb.Expr_CallExpr:
w.appendCall(e.GetCallExpr())
case *exprpb.Expr_ListExpr:
w.appendList(e.GetListExpr())
case *exprpb.Expr_StructExpr:
w.appendStruct(e.GetStructExpr())
case *exprpb.Expr_ComprehensionExpr:
w.appendComprehension(e.GetComprehensionExpr())
}
w.adorn(e)
}
func (w *debugWriter) appendSelect(sel *exprpb.Expr_Select) {
w.Buffer(sel.Operand)
w.append(".")
w.append(sel.Field)
if sel.TestOnly {
w.append("~test-only~")
}
}
func (w *debugWriter) appendCall(call *exprpb.Expr_Call) {
if call.Target != nil {
w.Buffer(call.Target)
w.append(".")
}
w.append(call.Function)
w.append("(")
if len(call.GetArgs()) > 0 {
w.addIndent()
w.appendLine()
for i, arg := range call.Args {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(arg)
}
w.removeIndent()
w.appendLine()
}
w.append(")")
}
func (w *debugWriter) appendList(list *exprpb.Expr_CreateList) {
w.append("[")
if len(list.GetElements()) > 0 {
w.appendLine()
w.addIndent()
for i, elem := range list.Elements {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(elem)
}
w.removeIndent()
w.appendLine()
}
w.append("]")
}
func (w *debugWriter) appendStruct(obj *exprpb.Expr_CreateStruct) {
if obj.MessageName != "" {
w.appendObject(obj)
} else {
w.appendMap(obj)
}
}
func (w *debugWriter) appendObject(obj *exprpb.Expr_CreateStruct) {
w.append(obj.MessageName)
w.append("{")
if len(obj.Entries) > 0 {
w.appendLine()
w.addIndent()
for i, entry := range obj.Entries {
if i > 0 {
w.append(",")
w.appendLine()
}
w.append(entry.GetFieldKey())
w.append(":")
w.Buffer(entry.Value)
w.adorn(entry)
}
w.removeIndent()
w.appendLine()
}
w.append("}")
}
func (w *debugWriter) appendMap(obj *exprpb.Expr_CreateStruct) {
w.append("{")
if len(obj.Entries) > 0 {
w.appendLine()
w.addIndent()
for i, entry := range obj.Entries {
if i > 0 {
w.append(",")
w.appendLine()
}
w.Buffer(entry.GetMapKey())
w.append(":")
w.Buffer(entry.Value)
w.adorn(entry)
}
w.removeIndent()
w.appendLine()
}
w.append("}")
}
func (w *debugWriter) appendComprehension(comprehension *exprpb.Expr_Comprehension) {
w.append("__comprehension__(")
w.addIndent()
w.appendLine()
w.append("// Variable")
w.appendLine()
w.append(comprehension.IterVar)
w.append(",")
w.appendLine()
w.append("// Target")
w.appendLine()
w.Buffer(comprehension.IterRange)
w.append(",")
w.appendLine()
w.append("// Accumulator")
w.appendLine()
w.append(comprehension.AccuVar)
w.append(",")
w.appendLine()
w.append("// Init")
w.appendLine()
w.Buffer(comprehension.AccuInit)
w.append(",")
w.appendLine()
w.append("// LoopCondition")
w.appendLine()
w.Buffer(comprehension.LoopCondition)
w.append(",")
w.appendLine()
w.append("// LoopStep")
w.appendLine()
w.Buffer(comprehension.LoopStep)
w.append(",")
w.appendLine()
w.append("// Result")
w.appendLine()
w.Buffer(comprehension.Result)
w.append(")")
w.removeIndent()
}
func formatLiteral(c *exprpb.Constant) string {
switch c.ConstantKind.(type) {
case *exprpb.Constant_BoolValue:
return fmt.Sprintf("%t", c.GetBoolValue())
case *exprpb.Constant_BytesValue:
return fmt.Sprintf("b\"%s\"", string(c.GetBytesValue()))
case *exprpb.Constant_DoubleValue:
return fmt.Sprintf("%v", c.GetDoubleValue())
case *exprpb.Constant_Int64Value:
return fmt.Sprintf("%d", c.GetInt64Value())
case *exprpb.Constant_StringValue:
return strconv.Quote(c.GetStringValue())
case *exprpb.Constant_Uint64Value:
return fmt.Sprintf("%du", c.GetUint64Value())
case *exprpb.Constant_NullValue:
return "null"
default:
panic("Unknown constant type")
}
}
func (w *debugWriter) append(s string) {
w.doIndent()
w.buffer.WriteString(s)
}
func (w *debugWriter) appendFormat(f string, args ...interface{}) {
w.append(fmt.Sprintf(f, args...))
}
func (w *debugWriter) doIndent() {
if w.lineStart {
w.lineStart = false
w.buffer.WriteString(strings.Repeat(" ", w.indent))
}
}
func (w *debugWriter) adorn(e interface{}) {
w.append(w.adorner.GetMetadata(e))
}
func (w *debugWriter) appendLine() {
w.buffer.WriteString("\n")
w.lineStart = true
}
func (w *debugWriter) addIndent() {
w.indent++
}
func (w *debugWriter) removeIndent() {
w.indent--
if w.indent < 0 {
panic("negative indent")
}
}
func (w *debugWriter) String() string {
return w.buffer.String()
}

17
vendor/github.com/google/cel-go/common/doc.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
// 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 common defines types and utilities common to expression parsing,
// checking, and interpretation
package common

70
vendor/github.com/google/cel-go/common/error.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
// 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 common
import (
"fmt"
"strings"
"unicode/utf8"
"golang.org/x/text/width"
)
// Error type which references a location within source and a message.
type Error struct {
Location Location
Message string
}
const (
dot = "."
ind = "^"
)
var (
wideDot = width.Widen.String(dot)
wideInd = width.Widen.String(ind)
)
// ToDisplayString decorates the error message with the source location.
func (e *Error) ToDisplayString(source Source) string {
var result = fmt.Sprintf("ERROR: %s:%d:%d: %s",
source.Description(),
e.Location.Line(),
e.Location.Column()+1, // add one to the 0-based column for display
e.Message)
if snippet, found := source.Snippet(e.Location.Line()); found {
snippet := strings.Replace(snippet, "\t", " ", -1)
srcLine := "\n | " + snippet
var bytes = []byte(snippet)
var indLine = "\n | "
for i := 0; i < e.Location.Column() && len(bytes) > 0; i++ {
_, sz := utf8.DecodeRune(bytes)
bytes = bytes[sz:]
if sz > 1 {
indLine += wideDot
} else {
indLine += dot
}
}
if _, sz := utf8.DecodeRune(bytes); sz > 1 {
indLine += wideInd
} else {
indLine += ind
}
result += srcLine + indLine
}
return result
}

74
vendor/github.com/google/cel-go/common/errors.go generated vendored Normal file
View File

@@ -0,0 +1,74 @@
// 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 common
import (
"fmt"
"sort"
)
// Errors type which contains a list of errors observed during parsing.
type Errors struct {
errors []Error
source Source
}
// NewErrors creates a new instance of the Errors type.
func NewErrors(source Source) *Errors {
return &Errors{
errors: []Error{},
source: source}
}
// ReportError records an error at a source location.
func (e *Errors) ReportError(l Location, format string, args ...interface{}) {
err := Error{
Location: l,
Message: fmt.Sprintf(format, args...),
}
e.errors = append(e.errors, err)
}
// GetErrors returns the list of observed errors.
func (e *Errors) GetErrors() []Error {
return e.errors[:]
}
// Append takes an Errors object as input creates a new Errors object with the current and input
// errors.
func (e *Errors) Append(errs []Error) *Errors {
return &Errors{
errors: append(e.errors, errs...),
source: e.source,
}
}
// ToDisplayString returns the error set to a newline delimited string.
func (e *Errors) ToDisplayString() string {
var result = ""
sort.SliceStable(e.errors, func(i, j int) bool {
ei := e.errors[i].Location
ej := e.errors[j].Location
return ei.Line() < ej.Line() ||
(ei.Line() == ej.Line() && ei.Column() < ej.Column())
})
for i, err := range e.errors {
if i >= 1 {
result += "\n"
}
result += err.ToDisplayString(e.source)
}
return result
}

51
vendor/github.com/google/cel-go/common/location.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
// 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 common
// Location interface to represent a location within Source.
type Location interface {
Line() int // 1-based line number within source.
Column() int // 0-based column number within source.
}
// SourceLocation helper type to manually construct a location.
type SourceLocation struct {
line int
column int
}
var (
// Location implements the SourcceLocation interface.
_ Location = &SourceLocation{}
// NoLocation is a particular illegal location.
NoLocation = &SourceLocation{-1, -1}
)
// NewLocation creates a new location.
func NewLocation(line, column int) Location {
return &SourceLocation{
line: line,
column: column}
}
// Line returns the 1-based line of the location.
func (l *SourceLocation) Line() int {
return l.line
}
// Column returns the 0-based column number of the location.
func (l *SourceLocation) Column() int {
return l.column
}

View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"operators.go",
],
importpath = "github.com/google/cel-go/common/operators",
)

View File

@@ -0,0 +1,145 @@
// 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 operators defines the internal function names of operators.
//
// ALl operators in the expression language are modelled as function calls.
package operators
// String "names" for CEL operators.
const (
// Symbolic operators.
Conditional = "_?_:_"
LogicalAnd = "_&&_"
LogicalOr = "_||_"
LogicalNot = "!_"
Equals = "_==_"
NotEquals = "_!=_"
Less = "_<_"
LessEquals = "_<=_"
Greater = "_>_"
GreaterEquals = "_>=_"
Add = "_+_"
Subtract = "_-_"
Multiply = "_*_"
Divide = "_/_"
Modulo = "_%_"
Negate = "-_"
Index = "_[_]"
// Macros, must have a valid identifier.
Has = "has"
All = "all"
Exists = "exists"
ExistsOne = "exists_one"
Map = "map"
Filter = "filter"
// Named operators, must not have be valid identifiers.
NotStrictlyFalse = "@not_strictly_false"
In = "@in"
// Deprecated: named operators with valid identifiers.
OldNotStrictlyFalse = "__not_strictly_false__"
OldIn = "_in_"
)
var (
operators = map[string]string{
"+": Add,
"/": Divide,
"==": Equals,
">": Greater,
">=": GreaterEquals,
"in": In,
"<": Less,
"<=": LessEquals,
"%": Modulo,
"*": Multiply,
"!=": NotEquals,
"-": Subtract,
}
reverseOperators = map[string]string{
Add: "+",
Divide: "/",
Equals: "==",
Greater: ">",
GreaterEquals: ">=",
In: "in",
Less: "<",
LessEquals: "<=",
LogicalAnd: "&&",
LogicalNot: "!",
LogicalOr: "||",
Modulo: "%",
Multiply: "*",
Negate: "-",
NotEquals: "!=",
OldIn: "in",
Subtract: "-",
}
// precedence of the operator, where the higher value means higher.
precedence = map[string]int{
Conditional: 8,
LogicalOr: 7,
LogicalAnd: 6,
Equals: 5,
Greater: 5,
GreaterEquals: 5,
In: 5,
Less: 5,
LessEquals: 5,
NotEquals: 5,
OldIn: 5,
Add: 4,
Subtract: 4,
Divide: 3,
Modulo: 3,
Multiply: 3,
LogicalNot: 2,
Negate: 2,
Index: 1,
}
)
// Find the internal function name for an operator, if the input text is one.
func Find(text string) (string, bool) {
op, found := operators[text]
return op, found
}
// FindReverse returns the unmangled, text representation of the operator.
func FindReverse(op string) (string, bool) {
txt, found := reverseOperators[op]
return txt, found
}
// FindReverseBinaryOperator returns the unmangled, text representation of a binary operator.
func FindReverseBinaryOperator(op string) (string, bool) {
if op == LogicalNot || op == Negate {
return "", false
}
txt, found := reverseOperators[op]
return txt, found
}
// Precedence returns the operator precedence, where the higher the number indicates
// higher precedence operations.
func Precedence(op string) int {
p, found := precedence[op]
if found {
return p
}
return 0
}

View File

@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"overloads.go",
],
importpath = "github.com/google/cel-go/common/overloads",
)

View File

@@ -0,0 +1,293 @@
// 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 overloads defines the internal overload identifiers for function and
// operator overloads.
package overloads
// Boolean logic overloads
const (
Conditional = "conditional"
LogicalAnd = "logical_and"
LogicalOr = "logical_or"
LogicalNot = "logical_not"
NotStrictlyFalse = "not_strictly_false"
Equals = "equals"
NotEquals = "not_equals"
LessBool = "less_bool"
LessInt64 = "less_int64"
LessUint64 = "less_uint64"
LessDouble = "less_double"
LessString = "less_string"
LessBytes = "less_bytes"
LessTimestamp = "less_timestamp"
LessDuration = "less_duration"
LessEqualsBool = "less_equals_bool"
LessEqualsInt64 = "less_equals_int64"
LessEqualsUint64 = "less_equals_uint64"
LessEqualsDouble = "less_equals_double"
LessEqualsString = "less_equals_string"
LessEqualsBytes = "less_equals_bytes"
LessEqualsTimestamp = "less_equals_timestamp"
LessEqualsDuration = "less_equals_duration"
GreaterBool = "greater_bool"
GreaterInt64 = "greater_int64"
GreaterUint64 = "greater_uint64"
GreaterDouble = "greater_double"
GreaterString = "greater_string"
GreaterBytes = "greater_bytes"
GreaterTimestamp = "greater_timestamp"
GreaterDuration = "greater_duration"
GreaterEqualsBool = "greater_equals_bool"
GreaterEqualsInt64 = "greater_equals_int64"
GreaterEqualsUint64 = "greater_equals_uint64"
GreaterEqualsDouble = "greater_equals_double"
GreaterEqualsString = "greater_equals_string"
GreaterEqualsBytes = "greater_equals_bytes"
GreaterEqualsTimestamp = "greater_equals_timestamp"
GreaterEqualsDuration = "greater_equals_duration"
)
// Math overloads
const (
AddInt64 = "add_int64"
AddUint64 = "add_uint64"
AddDouble = "add_double"
AddString = "add_string"
AddBytes = "add_bytes"
AddList = "add_list"
AddTimestampDuration = "add_timestamp_duration"
AddDurationTimestamp = "add_duration_timestamp"
AddDurationDuration = "add_duration_duration"
SubtractInt64 = "subtract_int64"
SubtractUint64 = "subtract_uint64"
SubtractDouble = "subtract_double"
SubtractTimestampTimestamp = "subtract_timestamp_timestamp"
SubtractTimestampDuration = "subtract_timestamp_duration"
SubtractDurationDuration = "subtract_duration_duration"
MultiplyInt64 = "multiply_int64"
MultiplyUint64 = "multiply_uint64"
MultiplyDouble = "multiply_double"
DivideInt64 = "divide_int64"
DivideUint64 = "divide_uint64"
DivideDouble = "divide_double"
ModuloInt64 = "modulo_int64"
ModuloUint64 = "modulo_uint64"
NegateInt64 = "negate_int64"
NegateDouble = "negate_double"
)
// Index overloads
const (
IndexList = "index_list"
IndexMap = "index_map"
IndexMessage = "index_message" // TODO: introduce concept of types.Message
)
// In operators
const (
DeprecatedIn = "in"
InList = "in_list"
InMap = "in_map"
InMessage = "in_message" // TODO: introduce concept of types.Message
)
// Size overloads
const (
Size = "size"
SizeString = "size_string"
SizeBytes = "size_bytes"
SizeList = "size_list"
SizeMap = "size_map"
SizeStringInst = "string_size"
SizeBytesInst = "bytes_size"
SizeListInst = "list_size"
SizeMapInst = "map_size"
)
// String function names.
const (
Contains = "contains"
EndsWith = "endsWith"
Matches = "matches"
StartsWith = "startsWith"
)
// String function overload names.
const (
ContainsString = "contains_string"
EndsWithString = "ends_with_string"
MatchesString = "matches_string"
StartsWithString = "starts_with_string"
)
// Time-based functions.
const (
TimeGetFullYear = "getFullYear"
TimeGetMonth = "getMonth"
TimeGetDayOfYear = "getDayOfYear"
TimeGetDate = "getDate"
TimeGetDayOfMonth = "getDayOfMonth"
TimeGetDayOfWeek = "getDayOfWeek"
TimeGetHours = "getHours"
TimeGetMinutes = "getMinutes"
TimeGetSeconds = "getSeconds"
TimeGetMilliseconds = "getMilliseconds"
)
// Timestamp overloads for time functions without timezones.
const (
TimestampToYear = "timestamp_to_year"
TimestampToMonth = "timestamp_to_month"
TimestampToDayOfYear = "timestamp_to_day_of_year"
TimestampToDayOfMonthZeroBased = "timestamp_to_day_of_month"
TimestampToDayOfMonthOneBased = "timestamp_to_day_of_month_1_based"
TimestampToDayOfWeek = "timestamp_to_day_of_week"
TimestampToHours = "timestamp_to_hours"
TimestampToMinutes = "timestamp_to_minutes"
TimestampToSeconds = "timestamp_to_seconds"
TimestampToMilliseconds = "timestamp_to_milliseconds"
)
// Timestamp overloads for time functions with timezones.
const (
TimestampToYearWithTz = "timestamp_to_year_with_tz"
TimestampToMonthWithTz = "timestamp_to_month_with_tz"
TimestampToDayOfYearWithTz = "timestamp_to_day_of_year_with_tz"
TimestampToDayOfMonthZeroBasedWithTz = "timestamp_to_day_of_month_with_tz"
TimestampToDayOfMonthOneBasedWithTz = "timestamp_to_day_of_month_1_based_with_tz"
TimestampToDayOfWeekWithTz = "timestamp_to_day_of_week_with_tz"
TimestampToHoursWithTz = "timestamp_to_hours_with_tz"
TimestampToMinutesWithTz = "timestamp_to_minutes_with_tz"
TimestampToSecondsWithTz = "timestamp_to_seconds_tz"
TimestampToMillisecondsWithTz = "timestamp_to_milliseconds_with_tz"
)
// Duration overloads for time functions.
const (
DurationToHours = "duration_to_hours"
DurationToMinutes = "duration_to_minutes"
DurationToSeconds = "duration_to_seconds"
DurationToMilliseconds = "duration_to_milliseconds"
)
// Type conversion methods and overloads
const (
TypeConvertInt = "int"
TypeConvertUint = "uint"
TypeConvertDouble = "double"
TypeConvertBool = "bool"
TypeConvertString = "string"
TypeConvertBytes = "bytes"
TypeConvertTimestamp = "timestamp"
TypeConvertDuration = "duration"
TypeConvertType = "type"
TypeConvertDyn = "dyn"
)
// Int conversion functions.
const (
IntToInt = "int64_to_int64"
UintToInt = "uint64_to_int64"
DoubleToInt = "double_to_int64"
StringToInt = "string_to_int64"
TimestampToInt = "timestamp_to_int64"
DurationToInt = "duration_to_int64"
)
// Uint conversion functions.
const (
UintToUint = "uint64_to_uint64"
IntToUint = "int64_to_uint64"
DoubleToUint = "double_to_uint64"
StringToUint = "string_to_uint64"
)
// Double conversion functions.
const (
DoubleToDouble = "double_to_double"
IntToDouble = "int64_to_double"
UintToDouble = "uint64_to_double"
StringToDouble = "string_to_double"
)
// Bool conversion functions.
const (
BoolToBool = "bool_to_bool"
StringToBool = "string_to_bool"
)
// Bytes conversion functions.
const (
BytesToBytes = "bytes_to_bytes"
StringToBytes = "string_to_bytes"
)
// String conversion functions.
const (
StringToString = "string_to_string"
BoolToString = "bool_to_string"
IntToString = "int64_to_string"
UintToString = "uint64_to_string"
DoubleToString = "double_to_string"
BytesToString = "bytes_to_string"
TimestampToString = "timestamp_to_string"
DurationToString = "duration_to_string"
)
// Timestamp conversion functions
const (
TimestampToTimestamp = "timestamp_to_timestamp"
StringToTimestamp = "string_to_timestamp"
IntToTimestamp = "int64_to_timestamp"
)
// Convert duration from string
const (
DurationToDuration = "duration_to_duration"
StringToDuration = "string_to_duration"
IntToDuration = "int64_to_duration"
)
// Convert to dyn
const (
ToDyn = "to_dyn"
)
// Comprehensions helper methods, not directly accessible via a developer.
const (
Iterator = "@iterator"
HasNext = "@hasNext"
Next = "@next"
)
// IsTypeConversionFunction returns whether the input function is a standard library type
// conversion function.
func IsTypeConversionFunction(function string) bool {
switch function {
case TypeConvertBool,
TypeConvertBytes,
TypeConvertDouble,
TypeConvertDuration,
TypeConvertDyn,
TypeConvertInt,
TypeConvertString,
TypeConvertTimestamp,
TypeConvertType,
TypeConvertUint:
return true
default:
return false
}
}

View File

@@ -0,0 +1,25 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"buffer.go",
],
importpath = "github.com/google/cel-go/common/runes",
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"buffer_test.go",
],
embed = [
":go_default_library",
],
)

194
vendor/github.com/google/cel-go/common/runes/buffer.go generated vendored Normal file
View File

@@ -0,0 +1,194 @@
// Copyright 2021 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 runes provides interfaces and utilities for working with runes.
package runes
import (
"strings"
"unicode/utf8"
)
// Buffer is an interface for accessing a contiguous array of code points.
type Buffer interface {
Get(i int) rune
Slice(i, j int) string
Len() int
}
type emptyBuffer struct{}
func (e *emptyBuffer) Get(i int) rune {
panic("slice index out of bounds")
}
func (e *emptyBuffer) Slice(i, j int) string {
if i != 0 || i != j {
panic("slice index out of bounds")
}
return ""
}
func (e *emptyBuffer) Len() int {
return 0
}
var _ Buffer = &emptyBuffer{}
// asciiBuffer is an implementation for an array of code points that contain code points only from
// the ASCII character set.
type asciiBuffer struct {
arr []byte
}
func (a *asciiBuffer) Get(i int) rune {
return rune(uint32(a.arr[i]))
}
func (a *asciiBuffer) Slice(i, j int) string {
return string(a.arr[i:j])
}
func (a *asciiBuffer) Len() int {
return len(a.arr)
}
var _ Buffer = &asciiBuffer{}
// basicBuffer is an implementation for an array of code points that contain code points from both
// the Latin-1 character set and Basic Multilingual Plane.
type basicBuffer struct {
arr []uint16
}
func (b *basicBuffer) Get(i int) rune {
return rune(uint32(b.arr[i]))
}
func (b *basicBuffer) Slice(i, j int) string {
var str strings.Builder
str.Grow((j - i) * 3) // Worst case encoding size for 0xffff is 3.
for ; i < j; i++ {
str.WriteRune(rune(uint32(b.arr[i])))
}
return str.String()
}
func (b *basicBuffer) Len() int {
return len(b.arr)
}
var _ Buffer = &basicBuffer{}
// supplementalBuffer is an implementation for an array of code points that contain code points from
// the Latin-1 character set, Basic Multilingual Plane, or the Supplemental Multilingual Plane.
type supplementalBuffer struct {
arr []rune
}
func (s *supplementalBuffer) Get(i int) rune {
return rune(uint32(s.arr[i]))
}
func (s *supplementalBuffer) Slice(i, j int) string {
return string(s.arr[i:j])
}
func (s *supplementalBuffer) Len() int {
return len(s.arr)
}
var _ Buffer = &supplementalBuffer{}
var nilBuffer = &emptyBuffer{}
// NewBuffer returns an efficient implementation of Buffer for the given text based on the ranges of
// the encoded code points contained within.
//
// Code points are represented as an array of byte, uint16, or rune. This approach ensures that
// each index represents a code point by itself without needing to use an array of rune. At first
// we assume all code points are less than or equal to '\u007f'. If this holds true, the
// underlying storage is a byte array containing only ASCII characters. If we encountered a code
// point above this range but less than or equal to '\uffff' we allocate a uint16 array, copy the
// elements of previous byte array to the uint16 array, and continue. If this holds true, the
// underlying storage is a uint16 array containing only Unicode characters in the Basic Multilingual
// Plane. If we encounter a code point above '\uffff' we allocate an rune array, copy the previous
// elements of the byte or uint16 array, and continue. The underlying storage is an rune array
// containing any Unicode character.
func NewBuffer(data string) Buffer {
if len(data) == 0 {
return nilBuffer
}
var (
idx = 0
buf8 = make([]byte, 0, len(data))
buf16 []uint16
buf32 []rune
)
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if r < utf8.RuneSelf {
buf8 = append(buf8, byte(r))
continue
}
if r <= 0xffff {
buf16 = make([]uint16, len(buf8), len(data))
for i, v := range buf8 {
buf16[i] = uint16(v)
}
buf8 = nil
buf16 = append(buf16, uint16(r))
goto copy16
}
buf32 = make([]rune, len(buf8), len(data))
for i, v := range buf8 {
buf32[i] = rune(uint32(v))
}
buf8 = nil
buf32 = append(buf32, r)
goto copy32
}
return &asciiBuffer{
arr: buf8,
}
copy16:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
if r <= 0xffff {
buf16 = append(buf16, uint16(r))
continue
}
buf32 = make([]rune, len(buf16), len(data))
for i, v := range buf16 {
buf32[i] = rune(uint32(v))
}
buf16 = nil
buf32 = append(buf32, r)
goto copy32
}
return &basicBuffer{
arr: buf16,
}
copy32:
for idx < len(data) {
r, s := utf8.DecodeRuneInString(data[idx:])
idx += s
buf32 = append(buf32, r)
}
return &supplementalBuffer{
arr: buf32,
}
}

186
vendor/github.com/google/cel-go/common/source.go generated vendored Normal file
View File

@@ -0,0 +1,186 @@
// 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 common
import (
"strings"
"unicode/utf8"
"github.com/google/cel-go/common/runes"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
// Source interface for filter source contents.
type Source interface {
// Content returns the source content represented as a string.
// Examples contents are the single file contents, textbox field,
// or url parameter.
Content() string
// Description gives a brief description of the source.
// Example descriptions are a file name or ui element.
Description() string
// LineOffsets gives the character offsets at which lines occur.
// The zero-th entry should refer to the break between the first
// and second line, or EOF if there is only one line of source.
LineOffsets() []int32
// LocationOffset translates a Location to an offset.
// Given the line and column of the Location returns the
// Location's character offset in the Source, and a bool
// indicating whether the Location was found.
LocationOffset(location Location) (int32, bool)
// OffsetLocation translates a character offset to a Location, or
// false if the conversion was not feasible.
OffsetLocation(offset int32) (Location, bool)
// NewLocation takes an input line and column and produces a Location.
// The default behavior is to treat the line and column as absolute,
// but concrete derivations may use this method to convert a relative
// line and column position into an absolute location.
NewLocation(line, col int) Location
// Snippet returns a line of content and whether the line was found.
Snippet(line int) (string, bool)
}
// The sourceImpl type implementation of the Source interface.
type sourceImpl struct {
runes.Buffer
description string
lineOffsets []int32
idOffsets map[int64]int32
}
var _ runes.Buffer = &sourceImpl{}
// TODO(jimlarson) "Character offsets" should index the code points
// within the UTF-8 encoded string. It currently indexes bytes.
// Can be accomplished by using rune[] instead of string for contents.
// NewTextSource creates a new Source from the input text string.
func NewTextSource(text string) Source {
return NewStringSource(text, "<input>")
}
// NewStringSource creates a new Source from the given contents and description.
func NewStringSource(contents string, description string) Source {
// Compute line offsets up front as they are referred to frequently.
lines := strings.Split(contents, "\n")
offsets := make([]int32, len(lines))
var offset int32
for i, line := range lines {
offset = offset + int32(utf8.RuneCountInString(line)) + 1
offsets[int32(i)] = offset
}
return &sourceImpl{
Buffer: runes.NewBuffer(contents),
description: description,
lineOffsets: offsets,
idOffsets: map[int64]int32{},
}
}
// NewInfoSource creates a new Source from a SourceInfo.
func NewInfoSource(info *exprpb.SourceInfo) Source {
return &sourceImpl{
Buffer: runes.NewBuffer(""),
description: info.GetLocation(),
lineOffsets: info.GetLineOffsets(),
idOffsets: info.GetPositions(),
}
}
// Content implements the Source interface method.
func (s *sourceImpl) Content() string {
return s.Slice(0, s.Len())
}
// Description implements the Source interface method.
func (s *sourceImpl) Description() string {
return s.description
}
// LineOffsets implements the Source interface method.
func (s *sourceImpl) LineOffsets() []int32 {
return s.lineOffsets
}
// LocationOffset implements the Source interface method.
func (s *sourceImpl) LocationOffset(location Location) (int32, bool) {
if lineOffset, found := s.findLineOffset(location.Line()); found {
return lineOffset + int32(location.Column()), true
}
return -1, false
}
// NewLocation implements the Source interface method.
func (s *sourceImpl) NewLocation(line, col int) Location {
return NewLocation(line, col)
}
// OffsetLocation implements the Source interface method.
func (s *sourceImpl) OffsetLocation(offset int32) (Location, bool) {
line, lineOffset := s.findLine(offset)
return NewLocation(int(line), int(offset-lineOffset)), true
}
// Snippet implements the Source interface method.
func (s *sourceImpl) Snippet(line int) (string, bool) {
charStart, found := s.findLineOffset(line)
if !found || s.Len() == 0 {
return "", false
}
charEnd, found := s.findLineOffset(line + 1)
if found {
return s.Slice(int(charStart), int(charEnd-1)), true
}
return s.Slice(int(charStart), s.Len()), true
}
// findLineOffset returns the offset where the (1-indexed) line begins,
// or false if line doesn't exist.
func (s *sourceImpl) findLineOffset(line int) (int32, bool) {
if line == 1 {
return 0, true
}
if line > 1 && line <= int(len(s.lineOffsets)) {
offset := s.lineOffsets[line-2]
return offset, true
}
return -1, false
}
// findLine finds the line that contains the given character offset and
// returns the line number and offset of the beginning of that line.
// Note that the last line is treated as if it contains all offsets
// beyond the end of the actual source.
func (s *sourceImpl) findLine(characterOffset int32) (int32, int32) {
var line int32 = 1
for _, lineOffset := range s.lineOffsets {
if lineOffset > characterOffset {
break
} else {
line++
}
}
if line == 1 {
return line, 0
}
return line, s.lineOffsets[line-2]
}

View File

@@ -0,0 +1,84 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"any_value.go",
"bool.go",
"bytes.go",
"double.go",
"duration.go",
"err.go",
"int.go",
"iterator.go",
"json_value.go",
"list.go",
"map.go",
"null.go",
"object.go",
"overflow.go",
"provider.go",
"string.go",
"timestamp.go",
"type.go",
"uint.go",
"unknown.go",
"util.go",
],
importpath = "github.com/google/cel-go/common/types",
deps = [
"//common/overloads:go_default_library",
"//common/types/pb:go_default_library",
"//common/types/ref:go_default_library",
"//common/types/traits:go_default_library",
"@com_github_stoewer_go_strcase//:go_default_library",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"bool_test.go",
"bytes_test.go",
"double_test.go",
"duration_test.go",
"int_test.go",
"json_list_test.go",
"json_struct_test.go",
"list_test.go",
"map_test.go",
"null_test.go",
"object_test.go",
"provider_test.go",
"string_test.go",
"timestamp_test.go",
"type_test.go",
"uint_test.go",
],
embed = [":go_default_library"],
deps = [
"//common/types/ref:go_default_library",
"//test:go_default_library",
"//test/proto3pb:test_all_types_go_proto",
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
],
)

View File

@@ -0,0 +1,24 @@
// 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 types
import (
"reflect"
anypb "google.golang.org/protobuf/types/known/anypb"
)
// anyValueType constant representing the reflected type of google.protobuf.Any.
var anyValueType = reflect.TypeOf(&anypb.Any{})

144
vendor/github.com/google/cel-go/common/types/bool.go generated vendored Normal file
View File

@@ -0,0 +1,144 @@
// 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 types
import (
"fmt"
"reflect"
"strconv"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Bool type that implements ref.Val and supports comparison and negation.
type Bool bool
var (
// BoolType singleton.
BoolType = NewTypeValue("bool",
traits.ComparerType,
traits.NegatorType)
// boolWrapperType golang reflected type for protobuf bool wrapper type.
boolWrapperType = reflect.TypeOf(&wrapperspb.BoolValue{})
)
// Boolean constants
const (
False = Bool(false)
True = Bool(true)
)
// Compare implements the traits.Comparer interface method.
func (b Bool) Compare(other ref.Val) ref.Val {
otherBool, ok := other.(Bool)
if !ok {
return ValOrErr(other, "no such overload")
}
if b == otherBool {
return IntZero
}
if !b && otherBool {
return IntNegOne
}
return IntOne
}
// ConvertToNative implements the ref.Val interface method.
func (b Bool) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Bool:
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped to a wrapperspb.BoolValue before being packed into an Any.
return anypb.New(wrapperspb.Bool(bool(b)))
case boolWrapperType:
// Convert the bool to a wrapperspb.BoolValue.
return wrapperspb.Bool(bool(b)), nil
case jsonValueType:
// Return the bool as a new structpb.Value.
return structpb.NewBoolValue(bool(b)), nil
default:
if typeDesc.Elem().Kind() == reflect.Bool {
p := bool(b)
return &p, nil
}
}
case reflect.Interface:
bv := b.Value()
if reflect.TypeOf(bv).Implements(typeDesc) {
return bv, nil
}
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from bool to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (b Bool) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String(strconv.FormatBool(bool(b)))
case BoolType:
return b
case TypeType:
return BoolType
}
return NewErr("type conversion error from '%v' to '%v'", BoolType, typeVal)
}
// Equal implements the ref.Val interface method.
func (b Bool) Equal(other ref.Val) ref.Val {
otherBool, ok := other.(Bool)
if !ok {
return ValOrErr(other, "no such overload")
}
return Bool(b == otherBool)
}
// Negate implements the traits.Negater interface method.
func (b Bool) Negate() ref.Val {
return !b
}
// Type implements the ref.Val interface method.
func (b Bool) Type() ref.Type {
return BoolType
}
// Value implements the ref.Val interface method.
func (b Bool) Value() interface{} {
return bool(b)
}
// IsBool returns whether the input ref.Val or ref.Type is equal to BoolType.
func IsBool(elem interface{}) bool {
switch elem := elem.(type) {
case ref.Type:
return elem == BoolType
case ref.Val:
return IsBool(elem.Type())
}
return false
}

135
vendor/github.com/google/cel-go/common/types/bytes.go generated vendored Normal file
View File

@@ -0,0 +1,135 @@
// 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 types
import (
"bytes"
"encoding/base64"
"fmt"
"reflect"
"unicode/utf8"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Bytes type that implements ref.Val and supports add, compare, and size
// operations.
type Bytes []byte
var (
// BytesType singleton.
BytesType = NewTypeValue("bytes",
traits.AdderType,
traits.ComparerType,
traits.SizerType)
// byteWrapperType golang reflected type for protobuf bytes wrapper type.
byteWrapperType = reflect.TypeOf(&wrapperspb.BytesValue{})
)
// Add implements traits.Adder interface method by concatenating byte sequences.
func (b Bytes) Add(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
if !ok {
return ValOrErr(other, "no such overload")
}
return append(b, otherBytes...)
}
// Compare implments traits.Comparer interface method by lexicographic ordering.
func (b Bytes) Compare(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
if !ok {
return ValOrErr(other, "no such overload")
}
return Int(bytes.Compare(b, otherBytes))
}
// ConvertToNative implements the ref.Val interface method.
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Array, reflect.Slice:
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Bytes([]byte(b)))
case byteWrapperType:
// Convert the bytes to a wrapperspb.BytesValue.
return wrapperspb.Bytes([]byte(b)), nil
case jsonValueType:
// CEL follows the proto3 to JSON conversion by encoding bytes to a string via base64.
// The encoding below matches the golang 'encoding/json' behavior during marshaling,
// which uses base64.StdEncoding.
str := base64.StdEncoding.EncodeToString([]byte(b))
return structpb.NewStringValue(str), nil
}
case reflect.Interface:
bv := b.Value()
if reflect.TypeOf(bv).Implements(typeDesc) {
return bv, nil
}
if reflect.TypeOf(b).Implements(typeDesc) {
return b, nil
}
}
return nil, fmt.Errorf("type conversion error from Bytes to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (b Bytes) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
if !utf8.Valid(b) {
return NewErr("invalid UTF-8 in bytes, cannot convert to string")
}
return String(b)
case BytesType:
return b
case TypeType:
return BytesType
}
return NewErr("type conversion error from '%s' to '%s'", BytesType, typeVal)
}
// Equal implements the ref.Val interface method.
func (b Bytes) Equal(other ref.Val) ref.Val {
otherBytes, ok := other.(Bytes)
if !ok {
return ValOrErr(other, "no such overload")
}
return Bool(bytes.Equal(b, otherBytes))
}
// Size implements the traits.Sizer interface method.
func (b Bytes) Size() ref.Val {
return Int(len(b))
}
// Type implements the ref.Val interface method.
func (b Bytes) Type() ref.Type {
return BytesType
}
// Value implements the ref.Val interface method.
func (b Bytes) Value() interface{} {
return []byte(b)
}

17
vendor/github.com/google/cel-go/common/types/doc.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
// 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 types contains the types, traits, and utilities common to all
// components of expression handling.
package types

200
vendor/github.com/google/cel-go/common/types/double.go generated vendored Normal file
View File

@@ -0,0 +1,200 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Double type that implements ref.Val, comparison, and mathematical
// operations.
type Double float64
var (
// DoubleType singleton.
DoubleType = NewTypeValue("double",
traits.AdderType,
traits.ComparerType,
traits.DividerType,
traits.MultiplierType,
traits.NegatorType,
traits.SubtractorType)
// doubleWrapperType reflected type for protobuf double wrapper type.
doubleWrapperType = reflect.TypeOf(&wrapperspb.DoubleValue{})
// floatWrapperType reflected type for protobuf float wrapper type.
floatWrapperType = reflect.TypeOf(&wrapperspb.FloatValue{})
)
// Add implements traits.Adder.Add.
func (d Double) Add(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d + otherDouble
}
// Compare implements traits.Comparer.Compare.
func (d Double) Compare(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if d < otherDouble {
return IntNegOne
}
if d > otherDouble {
return IntOne
}
return IntZero
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Float32:
v := float32(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Float64:
v := float64(d)
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Double(float64(d)))
case doubleWrapperType:
// Convert to a wrapperspb.DoubleValue
return wrapperspb.Double(float64(d)), nil
case floatWrapperType:
// Convert to a wrapperspb.FloatValue (with truncation).
return wrapperspb.Float(float32(d)), nil
case jsonValueType:
// Note, there are special cases for proto3 to json conversion that
// expect the floating point value to be converted to a NaN,
// Infinity, or -Infinity string values, but the jsonpb string
// marshaling of the protobuf.Value will handle this conversion.
return structpb.NewNumberValue(float64(d)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Float32:
v := float32(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Float64:
v := float64(d)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
dv := d.Value()
if reflect.TypeOf(dv).Implements(typeDesc) {
return dv, nil
}
if reflect.TypeOf(d).Implements(typeDesc) {
return d, nil
}
}
return nil, fmt.Errorf("type conversion error from Double to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (d Double) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
i, err := doubleToInt64Checked(float64(d))
if err != nil {
return wrapErr(err)
}
return Int(i)
case UintType:
i, err := doubleToUint64Checked(float64(d))
if err != nil {
return wrapErr(err)
}
return Uint(i)
case DoubleType:
return d
case StringType:
return String(fmt.Sprintf("%g", float64(d)))
case TypeType:
return DoubleType
}
return NewErr("type conversion error from '%s' to '%s'", DoubleType, typeVal)
}
// Divide implements traits.Divider.Divide.
func (d Double) Divide(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d / otherDouble
}
// Equal implements ref.Val.Equal.
func (d Double) Equal(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
// TODO: Handle NaNs properly.
return Bool(d == otherDouble)
}
// Multiply implements traits.Multiplier.Multiply.
func (d Double) Multiply(other ref.Val) ref.Val {
otherDouble, ok := other.(Double)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return d * otherDouble
}
// Negate implements traits.Negater.Negate.
func (d Double) Negate() ref.Val {
return -d
}
// Subtract implements traits.Subtractor.Subtract.
func (d Double) Subtract(subtrahend ref.Val) ref.Val {
subtraDouble, ok := subtrahend.(Double)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
return d - subtraDouble
}
// Type implements ref.Val.Type.
func (d Double) Type() ref.Type {
return DoubleType
}
// Value implements ref.Val.Value.
func (d Double) Value() interface{} {
return float64(d)
}

View File

@@ -0,0 +1,202 @@
// 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 types
import (
"fmt"
"reflect"
"strconv"
"time"
"github.com/google/cel-go/common/overloads"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
dpb "google.golang.org/protobuf/types/known/durationpb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// Duration type that implements ref.Val and supports add, compare, negate,
// and subtract operators. This type is also a receiver which means it can
// participate in dispatch to receiver functions.
type Duration struct {
time.Duration
}
func durationOf(d time.Duration) Duration {
return Duration{Duration: d}
}
var (
// DurationType singleton.
DurationType = NewTypeValue("google.protobuf.Duration",
traits.AdderType,
traits.ComparerType,
traits.NegatorType,
traits.ReceiverType,
traits.SubtractorType)
)
// Add implements traits.Adder.Add.
func (d Duration) Add(other ref.Val) ref.Val {
switch other.Type() {
case DurationType:
dur2 := other.(Duration)
val, err := addDurationChecked(d.Duration, dur2.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
case TimestampType:
ts := other.(Timestamp).Time
val, err := addTimeDurationChecked(ts, d.Duration)
if err != nil {
return wrapErr(err)
}
return timestampOf(val)
}
return MaybeNoSuchOverloadErr(other)
}
// Compare implements traits.Comparer.Compare.
func (d Duration) Compare(other ref.Val) ref.Val {
otherDur, ok := other.(Duration)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
d1 := d.Duration
d2 := otherDur.Duration
switch {
case d1 < d2:
return IntNegOne
case d1 > d2:
return IntOne
default:
return IntZero
}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (d Duration) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the duration is already assignable to the desired type return it.
if reflect.TypeOf(d.Duration).AssignableTo(typeDesc) {
return d.Duration, nil
}
if reflect.TypeOf(d).AssignableTo(typeDesc) {
return d, nil
}
switch typeDesc {
case anyValueType:
// Pack the duration as a dpb.Duration into an Any value.
return anypb.New(dpb.New(d.Duration))
case durationValueType:
// Unwrap the CEL value to its underlying proto value.
return dpb.New(d.Duration), nil
case jsonValueType:
// CEL follows the proto3 to JSON conversion.
// Note, using jsonpb would wrap the result in extra double quotes.
v := d.ConvertToType(StringType)
if IsError(v) {
return nil, v.(*Err)
}
return structpb.NewStringValue(string(v.(String))), nil
}
return nil, fmt.Errorf("type conversion error from 'Duration' to '%v'", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (d Duration) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String(strconv.FormatFloat(d.Seconds(), 'f', -1, 64) + "s")
case IntType:
return Int(d.Duration)
case DurationType:
return d
case TypeType:
return DurationType
}
return NewErr("type conversion error from '%s' to '%s'", DurationType, typeVal)
}
// Equal implements ref.Val.Equal.
func (d Duration) Equal(other ref.Val) ref.Val {
otherDur, ok := other.(Duration)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return Bool(d.Duration == otherDur.Duration)
}
// Negate implements traits.Negater.Negate.
func (d Duration) Negate() ref.Val {
val, err := negateDurationChecked(d.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
}
// Receive implements traits.Receiver.Receive.
func (d Duration) Receive(function string, overload string, args []ref.Val) ref.Val {
if len(args) == 0 {
if f, found := durationZeroArgOverloads[function]; found {
return f(d.Duration)
}
}
return NoSuchOverloadErr()
}
// Subtract implements traits.Subtractor.Subtract.
func (d Duration) Subtract(subtrahend ref.Val) ref.Val {
subtraDur, ok := subtrahend.(Duration)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
val, err := subtractDurationChecked(d.Duration, subtraDur.Duration)
if err != nil {
return wrapErr(err)
}
return durationOf(val)
}
// Type implements ref.Val.Type.
func (d Duration) Type() ref.Type {
return DurationType
}
// Value implements ref.Val.Value.
func (d Duration) Value() interface{} {
return d.Duration
}
var (
durationValueType = reflect.TypeOf(&dpb.Duration{})
durationZeroArgOverloads = map[string]func(time.Duration) ref.Val{
overloads.TimeGetHours: func(dur time.Duration) ref.Val {
return Int(dur.Hours())
},
overloads.TimeGetMinutes: func(dur time.Duration) ref.Val {
return Int(dur.Minutes())
},
overloads.TimeGetSeconds: func(dur time.Duration) ref.Val {
return Int(dur.Seconds())
},
overloads.TimeGetMilliseconds: func(dur time.Duration) ref.Val {
return Int(dur.Milliseconds())
}}
)

130
vendor/github.com/google/cel-go/common/types/err.go generated vendored Normal file
View File

@@ -0,0 +1,130 @@
// 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 types
import (
"errors"
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
)
// Err type which extends the built-in go error and implements ref.Val.
type Err struct {
error
}
var (
// ErrType singleton.
ErrType = NewTypeValue("error")
// errDivideByZero is an error indicating a division by zero of an integer value.
errDivideByZero = errors.New("division by zero")
// errModulusByZero is an error indicating a modulus by zero of an integer value.
errModulusByZero = errors.New("modulus by zero")
// errIntOverflow is an error representing integer overflow.
errIntOverflow = errors.New("integer overflow")
// errUintOverflow is an error representing unsigned integer overflow.
errUintOverflow = errors.New("unsigned integer overflow")
// errDurationOverflow is an error representing duration overflow.
errDurationOverflow = errors.New("duration overflow")
// errTimestampOverflow is an error representing timestamp overflow.
errTimestampOverflow = errors.New("timestamp overflow")
celErrTimestampOverflow = &Err{error: errTimestampOverflow}
// celErrNoSuchOverload indicates that the call arguments did not match a supported method signature.
celErrNoSuchOverload = NewErr("no such overload")
)
// NewErr creates a new Err described by the format string and args.
// TODO: Audit the use of this function and standardize the error messages and codes.
func NewErr(format string, args ...interface{}) ref.Val {
return &Err{fmt.Errorf(format, args...)}
}
// NoSuchOverloadErr returns a new types.Err instance with a no such overload message.
func NoSuchOverloadErr() ref.Val {
return celErrNoSuchOverload
}
// UnsupportedRefValConversionErr returns a types.NewErr instance with a no such conversion
// message that indicates that the native value could not be converted to a CEL ref.Val.
func UnsupportedRefValConversionErr(val interface{}) ref.Val {
return NewErr("unsupported conversion to ref.Val: (%T)%v", val, val)
}
// MaybeNoSuchOverloadErr returns the error or unknown if the input ref.Val is one of these types,
// else a new no such overload error.
func MaybeNoSuchOverloadErr(val ref.Val) ref.Val {
return ValOrErr(val, "no such overload")
}
// ValOrErr either returns the existing error or create a new one.
// TODO: Audit the use of this function and standardize the error messages and codes.
func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val {
if val == nil {
return NewErr(format, args...)
}
switch val.Type() {
case ErrType, UnknownType:
return val
default:
return NewErr(format, args...)
}
}
// wrapErr wraps an existing Go error value into a CEL Err value.
func wrapErr(err error) ref.Val {
return &Err{error: err}
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (e *Err) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
return nil, e.error
}
// ConvertToType implements ref.Val.ConvertToType.
func (e *Err) ConvertToType(typeVal ref.Type) ref.Val {
// Errors are not convertible to other representations.
return e
}
// Equal implements ref.Val.Equal.
func (e *Err) Equal(other ref.Val) ref.Val {
// An error cannot be equal to any other value, so it returns itself.
return e
}
// String implements fmt.Stringer.
func (e *Err) String() string {
return e.error.Error()
}
// Type implements ref.Val.Type.
func (e *Err) Type() ref.Type {
return ErrType
}
// Value implements ref.Val.Value.
func (e *Err) Value() interface{} {
return e.error
}
// IsError returns whether the input element ref.Type or ref.Val is equal to
// the ErrType singleton.
func IsError(val ref.Val) bool {
return val.Type() == ErrType
}

286
vendor/github.com/google/cel-go/common/types/int.go generated vendored Normal file
View File

@@ -0,0 +1,286 @@
// 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 types
import (
"fmt"
"reflect"
"strconv"
"time"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
)
// Int type that implements ref.Val as well as comparison and math operators.
type Int int64
// Int constants used for comparison results.
const (
// IntZero is the zero-value for Int
IntZero = Int(0)
IntOne = Int(1)
IntNegOne = Int(-1)
)
var (
// IntType singleton.
IntType = NewTypeValue("int",
traits.AdderType,
traits.ComparerType,
traits.DividerType,
traits.ModderType,
traits.MultiplierType,
traits.NegatorType,
traits.SubtractorType)
// int32WrapperType reflected type for protobuf int32 wrapper type.
int32WrapperType = reflect.TypeOf(&wrapperspb.Int32Value{})
// int64WrapperType reflected type for protobuf int64 wrapper type.
int64WrapperType = reflect.TypeOf(&wrapperspb.Int64Value{})
)
// Add implements traits.Adder.Add.
func (i Int) Add(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := addInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Compare implements traits.Comparer.Compare.
func (i Int) Compare(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if i < otherInt {
return IntNegOne
}
if i > otherInt {
return IntOne
}
return IntZero
}
// ConvertToNative implements ref.Val.ConvertToNative.
func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Int, reflect.Int32:
// Enums are also mapped as int32 derivations.
// Note, the code doesn't convert to the enum value directly since this is not known, but
// the net effect with respect to proto-assignment is handled correctly by the reflection
// Convert method.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
case reflect.Int64:
return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Primitives must be wrapped before being set on an Any field.
return anypb.New(wrapperspb.Int64(int64(i)))
case int32WrapperType:
// Convert the value to a wrapperspb.Int32Value, error on overflow.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
return wrapperspb.Int32(v), nil
case int64WrapperType:
// Convert the value to a wrapperspb.Int64Value.
return wrapperspb.Int64(int64(i)), nil
case jsonValueType:
// The proto-to-JSON conversion rules would convert all 64-bit integer values to JSON
// decimal strings. Because CEL ints might come from the automatic widening of 32-bit
// values in protos, the JSON type is chosen dynamically based on the value.
//
// - Integers -2^53-1 < n < 2^53-1 are encoded as JSON numbers.
// - Integers outside this range are encoded as JSON strings.
//
// The integer to float range represents the largest interval where such a conversion
// can round-trip accurately. Thus, conversions from a 32-bit source can expect a JSON
// number as with protobuf. Those consuming JSON from a 64-bit source must be able to
// handle either a JSON number or a JSON decimal string. To handle these cases safely
// the string values must be explicitly converted to int() within a CEL expression;
// however, it is best to simply stay within the JSON number range when building JSON
// objects in CEL.
if i.isJSONSafe() {
return structpb.NewNumberValue(float64(i)), nil
}
// Proto3 to JSON conversion requires string-formatted int64 values
// since the conversion to floating point would result in truncation.
return structpb.NewStringValue(strconv.FormatInt(int64(i), 10)), nil
}
switch typeDesc.Elem().Kind() {
case reflect.Int32:
// Convert the value to a wrapperspb.Int32Value, error on overflow.
v, err := int64ToInt32Checked(int64(i))
if err != nil {
return nil, err
}
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
case reflect.Int64:
v := int64(i)
p := reflect.New(typeDesc.Elem())
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
return p.Interface(), nil
}
case reflect.Interface:
iv := i.Value()
if reflect.TypeOf(iv).Implements(typeDesc) {
return iv, nil
}
if reflect.TypeOf(i).Implements(typeDesc) {
return i, nil
}
}
return nil, fmt.Errorf("unsupported type conversion from 'int' to %v", typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (i Int) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case IntType:
return i
case UintType:
u, err := int64ToUint64Checked(int64(i))
if err != nil {
return wrapErr(err)
}
return Uint(u)
case DoubleType:
return Double(i)
case StringType:
return String(fmt.Sprintf("%d", int64(i)))
case TimestampType:
// The maximum positive value that can be passed to time.Unix is math.MaxInt64 minus the number
// of seconds between year 1 and year 1970. See comments on unixToInternal.
if int64(i) < minUnixTime || int64(i) > maxUnixTime {
return celErrTimestampOverflow
}
return timestampOf(time.Unix(int64(i), 0).UTC())
case TypeType:
return IntType
}
return NewErr("type conversion error from '%s' to '%s'", IntType, typeVal)
}
// Divide implements traits.Divider.Divide.
func (i Int) Divide(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := divideInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Equal implements ref.Val.Equal.
func (i Int) Equal(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
return Bool(i == otherInt)
}
// Modulo implements traits.Modder.Modulo.
func (i Int) Modulo(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := moduloInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Multiply implements traits.Multiplier.Multiply.
func (i Int) Multiply(other ref.Val) ref.Val {
otherInt, ok := other.(Int)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
val, err := multiplyInt64Checked(int64(i), int64(otherInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Negate implements traits.Negater.Negate.
func (i Int) Negate() ref.Val {
val, err := negateInt64Checked(int64(i))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Subtract implements traits.Subtractor.Subtract.
func (i Int) Subtract(subtrahend ref.Val) ref.Val {
subtraInt, ok := subtrahend.(Int)
if !ok {
return MaybeNoSuchOverloadErr(subtrahend)
}
val, err := subtractInt64Checked(int64(i), int64(subtraInt))
if err != nil {
return wrapErr(err)
}
return Int(val)
}
// Type implements ref.Val.Type.
func (i Int) Type() ref.Type {
return IntType
}
// Value implements ref.Val.Value.
func (i Int) Value() interface{} {
return int64(i)
}
// isJSONSafe indicates whether the int is safely representable as a floating point value in JSON.
func (i Int) isJSONSafe() bool {
return i >= minIntJSON && i <= maxIntJSON
}
const (
// maxIntJSON is defined as the Number.MAX_SAFE_INTEGER value per EcmaScript 6.
maxIntJSON = 1<<53 - 1
// minIntJSON is defined as the Number.MIN_SAFE_INTEGER value per EcmaScript 6.
minIntJSON = -maxIntJSON
)

View File

@@ -0,0 +1,55 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var (
// IteratorType singleton.
IteratorType = NewTypeValue("iterator", traits.IteratorType)
)
// baseIterator is the basis for list, map, and object iterators.
//
// An iterator in and of itself should not be a valid value for comparison, but must implement the
// `ref.Val` methods in order to be well-supported within instruction arguments processed by the
// interpreter.
type baseIterator struct{}
func (*baseIterator) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
return nil, fmt.Errorf("type conversion on iterators not supported")
}
func (*baseIterator) ConvertToType(typeVal ref.Type) ref.Val {
return NewErr("no such overload")
}
func (*baseIterator) Equal(other ref.Val) ref.Val {
return NewErr("no such overload")
}
func (*baseIterator) Type() ref.Type {
return IteratorType
}
func (*baseIterator) Value() interface{} {
return nil
}

View File

@@ -0,0 +1,28 @@
// 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 types
import (
"reflect"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// JSON type constants representing the reflected types of protobuf JSON values.
var (
jsonValueType = reflect.TypeOf(&structpb.Value{})
jsonListValueType = reflect.TypeOf(&structpb.ListValue{})
jsonStructType = reflect.TypeOf(&structpb.Struct{})
)

447
vendor/github.com/google/cel-go/common/types/list.go generated vendored Normal file
View File

@@ -0,0 +1,447 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
var (
// ListType singleton.
ListType = NewTypeValue("list",
traits.AdderType,
traits.ContainerType,
traits.IndexerType,
traits.IterableType,
traits.SizerType)
)
// NewDynamicList returns a traits.Lister with heterogenous elements.
// value should be an array of "native" types, i.e. any type that
// NativeToValue() can convert to a ref.Val.
func NewDynamicList(adapter ref.TypeAdapter, value interface{}) traits.Lister {
refValue := reflect.ValueOf(value)
return &baseList{
TypeAdapter: adapter,
value: value,
size: refValue.Len(),
get: func(i int) interface{} {
return refValue.Index(i).Interface()
},
}
}
// NewStringList returns a traits.Lister containing only strings.
func NewStringList(adapter ref.TypeAdapter, elems []string) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: elems,
size: len(elems),
get: func(i int) interface{} { return elems[i] },
}
}
// NewRefValList returns a traits.Lister with ref.Val elements.
//
// This type specialization is used with list literals within CEL expressions.
func NewRefValList(adapter ref.TypeAdapter, elems []ref.Val) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: elems,
size: len(elems),
get: func(i int) interface{} { return elems[i] },
}
}
// NewProtoList returns a traits.Lister based on a pb.List instance.
func NewProtoList(adapter ref.TypeAdapter, list protoreflect.List) traits.Lister {
return &baseList{
TypeAdapter: adapter,
value: list,
size: list.Len(),
get: func(i int) interface{} { return list.Get(i).Interface() },
}
}
// NewJSONList returns a traits.Lister based on structpb.ListValue instance.
func NewJSONList(adapter ref.TypeAdapter, l *structpb.ListValue) traits.Lister {
vals := l.GetValues()
return &baseList{
TypeAdapter: adapter,
value: l,
size: len(vals),
get: func(i int) interface{} { return vals[i] },
}
}
// baseList points to a list containing elements of any type.
// The `value` is an array of native values, and refValue is its reflection object.
// The `ref.TypeAdapter` enables native type to CEL type conversions.
type baseList struct {
ref.TypeAdapter
value interface{}
// size indicates the number of elements within the list.
// Since objects are immutable the size of a list is static.
size int
// get returns a value at the specified integer index.
// The index is guaranteed to be checked against the list index range.
get func(int) interface{}
}
// Add implements the traits.Adder interface method.
func (l *baseList) Add(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() == IntZero {
return other
}
if otherList.Size() == IntZero {
return l
}
return &concatList{
TypeAdapter: l.TypeAdapter,
prevList: l,
nextList: otherList}
}
// Contains implements the traits.Container interface method.
func (l *baseList) Contains(elem ref.Val) ref.Val {
if IsUnknownOrError(elem) {
return elem
}
var err ref.Val
for i := 0; i < l.size; i++ {
val := l.NativeToValue(l.get(i))
cmp := elem.Equal(val)
b, ok := cmp.(Bool)
// When there is an error on the contain check, this is not necessarily terminal.
// The contains call could find the element and return True, just as though the user
// had written a per-element comparison in an exists() macro or logical ||, e.g.
// list.exists(e, e == elem)
if !ok && err == nil {
err = ValOrErr(cmp, "no such overload")
}
if b == True {
return True
}
}
if err != nil {
return err
}
return False
}
// ConvertToNative implements the ref.Val interface method.
func (l *baseList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the underlying list value is assignable to the reflected type return it.
if reflect.TypeOf(l.value).AssignableTo(typeDesc) {
return l.value, nil
}
// If the list wrapper is assignable to the desired type return it.
if reflect.TypeOf(l).AssignableTo(typeDesc) {
return l, nil
}
// Attempt to convert the list to a set of well known protobuf types.
switch typeDesc {
case anyValueType:
json, err := l.ConvertToNative(jsonListValueType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonListValueType:
jsonValues, err :=
l.ConvertToNative(reflect.TypeOf([]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonList := &structpb.ListValue{Values: jsonValues.([]*structpb.Value)}
if typeDesc == jsonListValueType {
return jsonList, nil
}
return structpb.NewListValue(jsonList), nil
}
// Non-list conversion.
if typeDesc.Kind() != reflect.Slice && typeDesc.Kind() != reflect.Array {
return nil, fmt.Errorf("type conversion error from list to '%v'", typeDesc)
}
// List conversion.
// Allow the element ConvertToNative() function to determine whether conversion is possible.
otherElemType := typeDesc.Elem()
elemCount := l.size
nativeList := reflect.MakeSlice(typeDesc, elemCount, elemCount)
for i := 0; i < elemCount; i++ {
elem := l.NativeToValue(l.get(i))
nativeElemVal, err := elem.ConvertToNative(otherElemType)
if err != nil {
return nil, err
}
nativeList.Index(i).Set(reflect.ValueOf(nativeElemVal))
}
return nativeList.Interface(), nil
}
// ConvertToType implements the ref.Val interface method.
func (l *baseList) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case ListType:
return l
case TypeType:
return ListType
}
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
}
// Equal implements the ref.Val interface method.
func (l *baseList) Equal(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() != otherList.Size() {
return False
}
var maybeErr ref.Val
for i := IntZero; i < l.Size().(Int); i++ {
thisElem := l.Get(i)
otherElem := otherList.Get(i)
elemEq := thisElem.Equal(otherElem)
if elemEq == False {
return False
}
if maybeErr == nil && IsUnknownOrError(elemEq) {
maybeErr = elemEq
}
}
if maybeErr != nil {
return maybeErr
}
return True
}
// Get implements the traits.Indexer interface method.
func (l *baseList) Get(index ref.Val) ref.Val {
i, ok := index.(Int)
if !ok {
return ValOrErr(index, "unsupported index type '%s' in list", index.Type())
}
iv := int(i)
if iv < 0 || iv >= l.size {
return NewErr("index '%d' out of range in list size '%d'", i, l.Size())
}
elem := l.get(iv)
return l.NativeToValue(elem)
}
// Iterator implements the traits.Iterable interface method.
func (l *baseList) Iterator() traits.Iterator {
return newListIterator(l)
}
// Size implements the traits.Sizer interface method.
func (l *baseList) Size() ref.Val {
return Int(l.size)
}
// Type implements the ref.Val interface method.
func (l *baseList) Type() ref.Type {
return ListType
}
// Value implements the ref.Val interface method.
func (l *baseList) Value() interface{} {
return l.value
}
// concatList combines two list implementations together into a view.
// The `ref.TypeAdapter` enables native type to CEL type conversions.
type concatList struct {
ref.TypeAdapter
value interface{}
prevList traits.Lister
nextList traits.Lister
}
// Add implements the traits.Adder interface method.
func (l *concatList) Add(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() == IntZero {
return other
}
if otherList.Size() == IntZero {
return l
}
return &concatList{
TypeAdapter: l.TypeAdapter,
prevList: l,
nextList: otherList}
}
// Contains implments the traits.Container interface method.
func (l *concatList) Contains(elem ref.Val) ref.Val {
// The concat list relies on the IsErrorOrUnknown checks against the input element to be
// performed by the `prevList` and/or `nextList`.
prev := l.prevList.Contains(elem)
// Short-circuit the return if the elem was found in the prev list.
if prev == True {
return prev
}
// Return if the elem was found in the next list.
next := l.nextList.Contains(elem)
if next == True {
return next
}
// Handle the case where an error or unknown was encountered before checking next.
if IsUnknownOrError(prev) {
return prev
}
// Otherwise, rely on the next value as the representative result.
return next
}
// ConvertToNative implements the ref.Val interface method.
func (l *concatList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
combined := NewDynamicList(l.TypeAdapter, l.Value().([]interface{}))
return combined.ConvertToNative(typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (l *concatList) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case ListType:
return l
case TypeType:
return ListType
}
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
}
// Equal implements the ref.Val interface method.
func (l *concatList) Equal(other ref.Val) ref.Val {
otherList, ok := other.(traits.Lister)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if l.Size() != otherList.Size() {
return False
}
var maybeErr ref.Val
for i := IntZero; i < l.Size().(Int); i++ {
thisElem := l.Get(i)
otherElem := otherList.Get(i)
elemEq := thisElem.Equal(otherElem)
if elemEq == False {
return False
}
if maybeErr == nil && IsUnknownOrError(elemEq) {
maybeErr = elemEq
}
}
if maybeErr != nil {
return maybeErr
}
return True
}
// Get implements the traits.Indexer interface method.
func (l *concatList) Get(index ref.Val) ref.Val {
i, ok := index.(Int)
if !ok {
return MaybeNoSuchOverloadErr(index)
}
if i < l.prevList.Size().(Int) {
return l.prevList.Get(i)
}
offset := i - l.prevList.Size().(Int)
return l.nextList.Get(offset)
}
// Iterator implements the traits.Iterable interface method.
func (l *concatList) Iterator() traits.Iterator {
return newListIterator(l)
}
// Size implements the traits.Sizer interface method.
func (l *concatList) Size() ref.Val {
return l.prevList.Size().(Int).Add(l.nextList.Size())
}
// Type implements the ref.Val interface method.
func (l *concatList) Type() ref.Type {
return ListType
}
// Value implements the ref.Val interface method.
func (l *concatList) Value() interface{} {
if l.value == nil {
merged := make([]interface{}, l.Size().(Int))
prevLen := l.prevList.Size().(Int)
for i := Int(0); i < prevLen; i++ {
merged[i] = l.prevList.Get(i).Value()
}
nextLen := l.nextList.Size().(Int)
for j := Int(0); j < nextLen; j++ {
merged[prevLen+j] = l.nextList.Get(j).Value()
}
l.value = merged
}
return l.value
}
func newListIterator(listValue traits.Lister) traits.Iterator {
return &listIterator{
listValue: listValue,
len: listValue.Size().(Int),
}
}
type listIterator struct {
*baseIterator
listValue traits.Lister
cursor Int
len Int
}
// HasNext implements the traits.Iterator interface method.
func (it *listIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *listIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
return it.listValue.Get(index)
}
return nil
}

809
vendor/github.com/google/cel-go/common/types/map.go generated vendored Normal file
View File

@@ -0,0 +1,809 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"github.com/stoewer/go-strcase"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// NewDynamicMap returns a traits.Mapper value with dynamic key, value pairs.
func NewDynamicMap(adapter ref.TypeAdapter, value interface{}) traits.Mapper {
refValue := reflect.ValueOf(value)
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newReflectMapAccessor(adapter, refValue),
value: value,
size: refValue.Len(),
}
}
// NewJSONStruct creates a traits.Mapper implementation backed by a JSON struct that has been
// encoded in protocol buffer form.
//
// The `adapter` argument provides type adaptation capabilities from proto to CEL.
func NewJSONStruct(adapter ref.TypeAdapter, value *structpb.Struct) traits.Mapper {
fields := value.GetFields()
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newJSONStructAccessor(adapter, fields),
value: value,
size: len(fields),
}
}
// NewRefValMap returns a specialized traits.Mapper with CEL valued keys and values.
func NewRefValMap(adapter ref.TypeAdapter, value map[ref.Val]ref.Val) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newRefValMapAccessor(value),
value: value,
size: len(value),
}
}
// NewStringInterfaceMap returns a specialized traits.Mapper with string keys and interface values.
func NewStringInterfaceMap(adapter ref.TypeAdapter, value map[string]interface{}) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newStringIfaceMapAccessor(adapter, value),
value: value,
size: len(value),
}
}
// NewStringStringMap returns a specialized traits.Mapper with string keys and values.
func NewStringStringMap(adapter ref.TypeAdapter, value map[string]string) traits.Mapper {
return &baseMap{
TypeAdapter: adapter,
mapAccessor: newStringMapAccessor(value),
value: value,
size: len(value),
}
}
// NewProtoMap returns a specialized traits.Mapper for handling protobuf map values.
func NewProtoMap(adapter ref.TypeAdapter, value *pb.Map) traits.Mapper {
return &protoMap{
TypeAdapter: adapter,
value: value,
}
}
var (
// MapType singleton.
MapType = NewTypeValue("map",
traits.ContainerType,
traits.IndexerType,
traits.IterableType,
traits.SizerType)
)
// mapAccessor is a private interface for finding values within a map and iterating over the keys.
// This interface implements portions of the API surface area required by the traits.Mapper
// interface.
type mapAccessor interface {
// Find returns a value, if one exists, for the inpput key.
//
// If the key is not found the function returns (nil, false).
// If the input key is not valid for the map, or is Err or Unknown the function returns
// (Unknown|Err, false).
Find(ref.Val) (ref.Val, bool)
// Iterator returns an Iterator over the map key set.
Iterator() traits.Iterator
}
// baseMap is a reflection based map implementation designed to handle a variety of map-like types.
//
// Since CEL is side-effect free, the base map represents an immutable object.
type baseMap struct {
// TypeAdapter used to convert keys and values accessed within the map.
ref.TypeAdapter
// mapAccessor interface implementation used to find and iterate over map keys.
mapAccessor
// value is the native Go value upon which the map type operators.
value interface{}
// size is the number of entries in the map.
size int
}
// Contains implements the traits.Container interface method.
func (m *baseMap) Contains(index ref.Val) ref.Val {
val, found := m.Find(index)
// When the index is not found and val is non-nil, this is an error or unknown value.
if !found && val != nil && IsUnknownOrError(val) {
return val
}
return Bool(found)
}
// ConvertToNative implements the ref.Val interface method.
func (m *baseMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the map is already assignable to the desired type return it, e.g. interfaces and
// maps with the same key value types.
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
return m.value, nil
}
if reflect.TypeOf(m).AssignableTo(typeDesc) {
return m, nil
}
switch typeDesc {
case anyValueType:
json, err := m.ConvertToNative(jsonStructType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonStructType:
jsonEntries, err :=
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonMap := &structpb.Struct{Fields: jsonEntries.(map[string]*structpb.Value)}
if typeDesc == jsonStructType {
return jsonMap, nil
}
return structpb.NewStructValue(jsonMap), nil
}
// Unwrap pointers, but track their use.
isPtr := false
if typeDesc.Kind() == reflect.Ptr {
tk := typeDesc
typeDesc = typeDesc.Elem()
if typeDesc.Kind() == reflect.Ptr {
return nil, fmt.Errorf("unsupported type conversion to '%v'", tk)
}
isPtr = true
}
switch typeDesc.Kind() {
// Map conversion.
case reflect.Map:
otherKey := typeDesc.Key()
otherElem := typeDesc.Elem()
nativeMap := reflect.MakeMapWithSize(typeDesc, m.size)
it := m.Iterator()
for it.HasNext() == True {
key := it.Next()
refKeyValue, err := key.ConvertToNative(otherKey)
if err != nil {
return nil, err
}
refElemValue, err := m.Get(key).ConvertToNative(otherElem)
if err != nil {
return nil, err
}
nativeMap.SetMapIndex(reflect.ValueOf(refKeyValue), reflect.ValueOf(refElemValue))
}
return nativeMap.Interface(), nil
case reflect.Struct:
nativeStructPtr := reflect.New(typeDesc)
nativeStruct := nativeStructPtr.Elem()
it := m.Iterator()
for it.HasNext() == True {
key := it.Next()
// Ensure the field name being referenced is exported.
// Only exported (public) field names can be set by reflection, where the name
// must be at least one character in length and start with an upper-case letter.
fieldName := key.ConvertToType(StringType)
if IsError(fieldName) {
return nil, fieldName.(*Err)
}
name := string(fieldName.(String))
name = strcase.UpperCamelCase(name)
fieldRef := nativeStruct.FieldByName(name)
if !fieldRef.IsValid() {
return nil, fmt.Errorf("type conversion error, no such field '%s' in type '%v'", name, typeDesc)
}
fieldValue, err := m.Get(key).ConvertToNative(fieldRef.Type())
if err != nil {
return nil, err
}
fieldRef.Set(reflect.ValueOf(fieldValue))
}
if isPtr {
return nativeStructPtr.Interface(), nil
}
return nativeStruct.Interface(), nil
}
return nil, fmt.Errorf("type conversion error from map to '%v'", typeDesc)
}
// ConvertToType implements the ref.Val interface method.
func (m *baseMap) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case MapType:
return m
case TypeType:
return MapType
}
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
}
// Equal implements the ref.Val interface method.
func (m *baseMap) Equal(other ref.Val) ref.Val {
otherMap, ok := other.(traits.Mapper)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if m.Size() != otherMap.Size() {
return False
}
it := m.Iterator()
var maybeErr ref.Val
for it.HasNext() == True {
key := it.Next()
thisVal, _ := m.Find(key)
otherVal, found := otherMap.Find(key)
if !found {
if otherVal == nil {
return False
}
if maybeErr == nil {
maybeErr = MaybeNoSuchOverloadErr(otherVal)
}
continue
}
valEq := thisVal.Equal(otherVal)
if valEq == False {
return False
}
if maybeErr == nil && IsUnknownOrError(valEq) {
maybeErr = valEq
}
}
if maybeErr != nil {
return maybeErr
}
return True
}
// Get implements the traits.Indexer interface method.
func (m *baseMap) Get(key ref.Val) ref.Val {
v, found := m.Find(key)
if !found {
return ValOrErr(v, "no such key: %v", key)
}
return v
}
// Size implements the traits.Sizer interface method.
func (m *baseMap) Size() ref.Val {
return Int(m.size)
}
// Type implements the ref.Val interface method.
func (m *baseMap) Type() ref.Type {
return MapType
}
// Value implements the ref.Val interface method.
func (m *baseMap) Value() interface{} {
return m.value
}
func newJSONStructAccessor(adapter ref.TypeAdapter, st map[string]*structpb.Value) mapAccessor {
return &jsonStructAccessor{
TypeAdapter: adapter,
st: st,
}
}
type jsonStructAccessor struct {
ref.TypeAdapter
st map[string]*structpb.Value
}
// Find searches the json struct field map for the input key value and returns (value, true) if
// found.
//
// If the key is not found the function returns (nil, false).
// If the input key is not a String, or is an Err or Unknown, the function returns
// (Unknown|Err, false).
func (a *jsonStructAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
}
keyVal, found := a.st[string(strKey)]
if !found {
return nil, false
}
return a.NativeToValue(keyVal), true
}
// Iterator creates a new traits.Iterator from the set of JSON struct field names.
func (a *jsonStructAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.st))
i := 0
for k := range a.st {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
func newReflectMapAccessor(adapter ref.TypeAdapter, value reflect.Value) mapAccessor {
keyType := value.Type().Key()
return &reflectMapAccessor{
TypeAdapter: adapter,
refValue: value,
keyType: keyType,
}
}
type reflectMapAccessor struct {
ref.TypeAdapter
refValue reflect.Value
keyType reflect.Type
}
// Find converts the input key to a native Golang type and then uses reflection to find the key,
// returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
// If the input key is not a String, or is an Err or Unknown, the function returns
// (Unknown|Err, false).
func (a *reflectMapAccessor) Find(key ref.Val) (ref.Val, bool) {
if IsUnknownOrError(key) {
return MaybeNoSuchOverloadErr(key), false
}
if a.refValue.Len() == 0 {
return nil, false
}
k, err := key.ConvertToNative(a.keyType)
if err != nil {
return NewErr("unsupported key type: %v", key.Type()), false
}
refKey := reflect.ValueOf(k)
val := a.refValue.MapIndex(refKey)
if val.IsValid() {
return a.NativeToValue(val.Interface()), true
}
mapIt := a.refValue.MapRange()
for mapIt.Next() {
if refKey.Kind() == mapIt.Key().Kind() {
return nil, false
}
}
return NewErr("unsupported key type: %v", key.Type()), false
}
// Iterator creates a Golang reflection based traits.Iterator.
func (a *reflectMapAccessor) Iterator() traits.Iterator {
return &mapIterator{
TypeAdapter: a.TypeAdapter,
mapKeys: a.refValue.MapRange(),
len: a.refValue.Len(),
}
}
func newRefValMapAccessor(mapVal map[ref.Val]ref.Val) mapAccessor {
return &refValMapAccessor{mapVal: mapVal}
}
type refValMapAccessor struct {
mapVal map[ref.Val]ref.Val
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
// If the input key is an Err or Unknown, the function returns (Unknown|Err, false).
func (a *refValMapAccessor) Find(key ref.Val) (ref.Val, bool) {
if IsUnknownOrError(key) {
return key, false
}
if len(a.mapVal) == 0 {
return nil, false
}
keyVal, found := a.mapVal[key]
if found {
return keyVal, true
}
for k := range a.mapVal {
if k.Type().TypeName() == key.Type().TypeName() {
return nil, false
}
}
return NewErr("unsupported key type: %v", key.Type()), found
}
// Iterator produces a new traits.Iterator which iterates over the map keys via Golang reflection.
func (a *refValMapAccessor) Iterator() traits.Iterator {
return &mapIterator{
TypeAdapter: DefaultTypeAdapter,
mapKeys: reflect.ValueOf(a.mapVal).MapRange(),
len: len(a.mapVal),
}
}
func newStringMapAccessor(strMap map[string]string) mapAccessor {
return &stringMapAccessor{mapVal: strMap}
}
type stringMapAccessor struct {
mapVal map[string]string
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
// If the input key is not a String, or is an Err or Unknown, the function returns
// (Unknown|Err, false).
func (a *stringMapAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
}
keyVal, found := a.mapVal[string(strKey)]
if !found {
return nil, false
}
return String(keyVal), true
}
// Iterator creates a new traits.Iterator from the string key set of the map.
func (a *stringMapAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.mapVal))
i := 0
for k := range a.mapVal {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]interface{}) mapAccessor {
return &stringIfaceMapAccessor{
TypeAdapter: adapter,
mapVal: mapVal,
}
}
type stringIfaceMapAccessor struct {
ref.TypeAdapter
mapVal map[string]interface{}
}
// Find uses native map accesses to find the key, returning (value, true) if present.
//
// If the key is not found the function returns (nil, false).
// If the input key is not a String, or is an Err or Unknown, the function returns
// (Unknown|Err, false).
func (a *stringIfaceMapAccessor) Find(key ref.Val) (ref.Val, bool) {
strKey, ok := key.(String)
if !ok {
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
}
keyVal, found := a.mapVal[string(strKey)]
if !found {
return nil, false
}
return a.NativeToValue(keyVal), true
}
// Iterator creates a new traits.Iterator from the string key set of the map.
func (a *stringIfaceMapAccessor) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]string, len(a.mapVal))
i := 0
for k := range a.mapVal {
mapKeys[i] = k
i++
}
return &stringKeyIterator{
mapKeys: mapKeys,
len: len(mapKeys),
}
}
// protoMap is a specialized, separate implementation of the traits.Mapper interfaces tailored to
// accessing protoreflect.Map values.
type protoMap struct {
ref.TypeAdapter
value *pb.Map
}
// Contains returns whether the map contains the given key.
func (m *protoMap) Contains(key ref.Val) ref.Val {
val, found := m.Find(key)
// When the index is not found and val is non-nil, this is an error or unknown value.
if !found && val != nil && IsUnknownOrError(val) {
return val
}
return Bool(found)
}
// ConvertToNative implements the ref.Val interface method.
//
// Note, assignment to Golang struct types is not yet supported.
func (m *protoMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
// If the map is already assignable to the desired type return it, e.g. interfaces and
// maps with the same key value types.
switch typeDesc {
case anyValueType:
json, err := m.ConvertToNative(jsonStructType)
if err != nil {
return nil, err
}
return anypb.New(json.(proto.Message))
case jsonValueType, jsonStructType:
jsonEntries, err :=
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
if err != nil {
return nil, err
}
jsonMap := &structpb.Struct{
Fields: jsonEntries.(map[string]*structpb.Value)}
if typeDesc == jsonStructType {
return jsonMap, nil
}
return structpb.NewStructValue(jsonMap), nil
}
switch typeDesc.Kind() {
case reflect.Struct, reflect.Ptr:
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
return m.value, nil
}
if reflect.TypeOf(m).AssignableTo(typeDesc) {
return m, nil
}
}
if typeDesc.Kind() != reflect.Map {
return nil, fmt.Errorf("unsupported type conversion: %v to map", typeDesc)
}
keyType := m.value.KeyType.ReflectType()
valType := m.value.ValueType.ReflectType()
otherKeyType := typeDesc.Key()
otherValType := typeDesc.Elem()
mapVal := reflect.MakeMapWithSize(typeDesc, m.value.Len())
var err error
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
ntvKey := key.Interface()
ntvVal := val.Interface()
switch ntvVal.(type) {
case protoreflect.Message:
ntvVal = ntvVal.(protoreflect.Message).Interface()
}
if keyType == otherKeyType && valType == otherValType {
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
return true
}
celKey := m.NativeToValue(ntvKey)
celVal := m.NativeToValue(ntvVal)
ntvKey, err = celKey.ConvertToNative(otherKeyType)
if err != nil {
// early terminate the range loop.
return false
}
ntvVal, err = celVal.ConvertToNative(otherValType)
if err != nil {
// early terminate the range loop.
return false
}
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
return true
})
if err != nil {
return nil, err
}
return mapVal.Interface(), nil
}
// ConvertToType implements the ref.Val interface method.
func (m *protoMap) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case MapType:
return m
case TypeType:
return MapType
}
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
}
// Equal implements the ref.Val interface method.
func (m *protoMap) Equal(other ref.Val) ref.Val {
otherMap, ok := other.(traits.Mapper)
if !ok {
return MaybeNoSuchOverloadErr(other)
}
if m.value.Map.Len() != int(otherMap.Size().(Int)) {
return False
}
var retVal ref.Val = True
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
keyVal := m.NativeToValue(key.Interface())
valVal := m.NativeToValue(val)
otherVal, found := otherMap.Find(keyVal)
if !found {
if otherVal == nil {
retVal = False
return false
}
retVal = MaybeNoSuchOverloadErr(otherVal)
return false
}
valEq := valVal.Equal(otherVal)
if valEq != True {
retVal = valEq
return false
}
return true
})
return retVal
}
// Find returns whether the protoreflect.Map contains the input key.
//
// If the key is not found the function returns (nil, false).
// If the input key is not a supported proto map key type, or is an Err or Unknown,
// the function returns
// (Unknown|Err, false).
func (m *protoMap) Find(key ref.Val) (ref.Val, bool) {
if IsUnknownOrError(key) {
return key, false
}
// Convert the input key to the expected protobuf key type.
ntvKey, err := key.ConvertToNative(m.value.KeyType.ReflectType())
if err != nil {
return NewErr("unsupported key type: %v", key.Type()), false
}
// Use protoreflection to get the key value.
val := m.value.Get(protoreflect.ValueOf(ntvKey).MapKey())
if !val.IsValid() {
return nil, false
}
// Perform nominal type unwrapping from the input value.
switch v := val.Interface().(type) {
case protoreflect.List, protoreflect.Map:
// Maps do not support list or map values
return NewErr("unsupported map element type: (%T)%v", v, v), false
default:
return m.NativeToValue(v), true
}
}
// Get implements the traits.Indexer interface method.
func (m *protoMap) Get(key ref.Val) ref.Val {
v, found := m.Find(key)
if !found {
return ValOrErr(v, "no such key: %v", key)
}
return v
}
// Iterator implements the traits.Iterable interface method.
func (m *protoMap) Iterator() traits.Iterator {
// Copy the keys to make their order stable.
mapKeys := make([]protoreflect.MapKey, 0, m.value.Len())
m.value.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
mapKeys = append(mapKeys, k)
return true
})
return &protoMapIterator{
TypeAdapter: m.TypeAdapter,
mapKeys: mapKeys,
len: m.value.Len(),
}
}
// Size returns the number of entries in the protoreflect.Map.
func (m *protoMap) Size() ref.Val {
return Int(m.value.Len())
}
// Type implements the ref.Val interface method.
func (m *protoMap) Type() ref.Type {
return MapType
}
// Value implements the ref.Val interface method.
func (m *protoMap) Value() interface{} {
return m.value
}
type mapIterator struct {
*baseIterator
ref.TypeAdapter
mapKeys *reflect.MapIter
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *mapIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *mapIterator) Next() ref.Val {
if it.HasNext() == True && it.mapKeys.Next() {
it.cursor++
refKey := it.mapKeys.Key()
return it.NativeToValue(refKey.Interface())
}
return nil
}
type protoMapIterator struct {
*baseIterator
ref.TypeAdapter
mapKeys []protoreflect.MapKey
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *protoMapIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *protoMapIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
refKey := it.mapKeys[index]
return it.NativeToValue(refKey.Interface())
}
return nil
}
type stringKeyIterator struct {
*baseIterator
mapKeys []string
cursor int
len int
}
// HasNext implements the traits.Iterator interface method.
func (it *stringKeyIterator) HasNext() ref.Val {
return Bool(it.cursor < it.len)
}
// Next implements the traits.Iterator interface method.
func (it *stringKeyIterator) Next() ref.Val {
if it.HasNext() == True {
index := it.cursor
it.cursor++
return String(it.mapKeys[index])
}
return nil
}

100
vendor/github.com/google/cel-go/common/types/null.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/ref"
"google.golang.org/protobuf/proto"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
// Null type implementation.
type Null structpb.NullValue
var (
// NullType singleton.
NullType = NewTypeValue("null_type")
// NullValue singleton.
NullValue = Null(structpb.NullValue_NULL_VALUE)
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
)
// ConvertToNative implements ref.Val.ConvertToNative.
func (n Null) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
switch typeDesc.Kind() {
case reflect.Int32:
return reflect.ValueOf(n).Convert(typeDesc).Interface(), nil
case reflect.Ptr:
switch typeDesc {
case anyValueType:
// Convert to a JSON-null before packing to an Any field since the enum value for JSON
// null cannot be packed directly.
pb, err := n.ConvertToNative(jsonValueType)
if err != nil {
return nil, err
}
return anypb.New(pb.(proto.Message))
case jsonValueType:
return structpb.NewNullValue(), nil
}
case reflect.Interface:
nv := n.Value()
if reflect.TypeOf(nv).Implements(typeDesc) {
return nv, nil
}
if reflect.TypeOf(n).Implements(typeDesc) {
return n, nil
}
}
// If the type conversion isn't supported return an error.
return nil, fmt.Errorf("type conversion error from '%v' to '%v'", NullType, typeDesc)
}
// ConvertToType implements ref.Val.ConvertToType.
func (n Null) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case StringType:
return String("null")
case NullType:
return n
case TypeType:
return NullType
}
return NewErr("type conversion error from '%s' to '%s'", NullType, typeVal)
}
// Equal implements ref.Val.Equal.
func (n Null) Equal(other ref.Val) ref.Val {
if NullType != other.Type() {
return ValOrErr(other, "no such overload")
}
return True
}
// Type implements ref.Val.Type.
func (n Null) Type() ref.Type {
return NullType
}
// Value implements ref.Val.Value.
func (n Null) Value() interface{} {
return structpb.NullValue_NULL_VALUE
}

158
vendor/github.com/google/cel-go/common/types/object.go generated vendored Normal file
View File

@@ -0,0 +1,158 @@
// 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 types
import (
"fmt"
"reflect"
"github.com/google/cel-go/common/types/pb"
"github.com/google/cel-go/common/types/ref"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
anypb "google.golang.org/protobuf/types/known/anypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
type protoObj struct {
ref.TypeAdapter
value proto.Message
typeDesc *pb.TypeDescription
typeValue *TypeValue
}
// NewObject returns an object based on a proto.Message value which handles
// conversion between protobuf type values and expression type values.
// Objects support indexing and iteration.
//
// Note: the type value is pulled from the list of registered types within the
// type provider. If the proto type is not registered within the type provider,
// then this will result in an error within the type adapter / provider.
func NewObject(adapter ref.TypeAdapter,
typeDesc *pb.TypeDescription,
typeValue *TypeValue,
value proto.Message) ref.Val {
return &protoObj{
TypeAdapter: adapter,
value: value,
typeDesc: typeDesc,
typeValue: typeValue}
}
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
pb := o.value
if reflect.TypeOf(pb).AssignableTo(typeDesc) {
return pb, nil
}
if reflect.TypeOf(o).AssignableTo(typeDesc) {
return o, nil
}
switch typeDesc {
case anyValueType:
_, isAny := pb.(*anypb.Any)
if isAny {
return pb, nil
}
return anypb.New(pb)
case jsonValueType:
// Marshal the proto to JSON first, and then rehydrate as protobuf.Value as there is no
// support for direct conversion from proto.Message to protobuf.Value.
bytes, err := protojson.Marshal(pb)
if err != nil {
return nil, err
}
json := &structpb.Value{}
err = protojson.Unmarshal(bytes, json)
if err != nil {
return nil, err
}
return json, nil
default:
if typeDesc == o.typeDesc.ReflectType() {
return o.value, nil
}
if typeDesc.Kind() == reflect.Ptr {
val := reflect.New(typeDesc.Elem()).Interface()
dstPB, ok := val.(proto.Message)
if ok {
proto.Merge(dstPB, pb)
return dstPB, nil
}
}
}
return nil, fmt.Errorf("type conversion error from '%T' to '%v'", o.value, typeDesc)
}
func (o *protoObj) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
default:
if o.Type().TypeName() == typeVal.TypeName() {
return o
}
case TypeType:
return o.typeValue
}
return NewErr("type conversion error from '%s' to '%s'", o.typeDesc.Name(), typeVal)
}
func (o *protoObj) Equal(other ref.Val) ref.Val {
if o.typeDesc.Name() != other.Type().TypeName() {
return MaybeNoSuchOverloadErr(other)
}
return Bool(proto.Equal(o.value, other.Value().(proto.Message)))
}
// IsSet tests whether a field which is defined is set to a non-default value.
func (o *protoObj) IsSet(field ref.Val) ref.Val {
protoFieldName, ok := field.(String)
if !ok {
return MaybeNoSuchOverloadErr(field)
}
protoFieldStr := string(protoFieldName)
fd, found := o.typeDesc.FieldByName(protoFieldStr)
if !found {
return NewErr("no such field '%s'", field)
}
if fd.IsSet(o.value) {
return True
}
return False
}
func (o *protoObj) Get(index ref.Val) ref.Val {
protoFieldName, ok := index.(String)
if !ok {
return MaybeNoSuchOverloadErr(index)
}
protoFieldStr := string(protoFieldName)
fd, found := o.typeDesc.FieldByName(protoFieldStr)
if !found {
return NewErr("no such field '%s'", index)
}
fv, err := fd.GetFrom(o.value)
if err != nil {
return NewErr(err.Error())
}
return o.NativeToValue(fv)
}
func (o *protoObj) Type() ref.Type {
return o.typeValue
}
func (o *protoObj) Value() interface{} {
return o.value
}

View File

@@ -0,0 +1,357 @@
// Copyright 2021 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 types
import (
"math"
"time"
)
var (
doubleTwoTo64 = math.Ldexp(1.0, 64)
)
// addInt64Checked performs addition with overflow detection of two int64 values.
//
// If the operation fails the error return value will be non-nil.
func addInt64Checked(x, y int64) (int64, error) {
if (y > 0 && x > math.MaxInt64-y) || (y < 0 && x < math.MinInt64-y) {
return 0, errIntOverflow
}
return x + y, nil
}
// subtractInt64Checked performs subtraction with overflow detection of two int64 values.
//
// If the operation fails the error return value will be non-nil.
func subtractInt64Checked(x, y int64) (int64, error) {
if (y < 0 && x > math.MaxInt64+y) || (y > 0 && x < math.MinInt64+y) {
return 0, errIntOverflow
}
return x - y, nil
}
// negateInt64Checked performs negation with overflow detection of an int64.
//
// If the operation fails the error return value will be non-nil.
func negateInt64Checked(x int64) (int64, error) {
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 {
return 0, errIntOverflow
}
return -x, nil
}
// multiplyInt64Checked performs multiplication with overflow detection of two int64 value.
//
// If the operation fails the error return value will be non-nil.
func multiplyInt64Checked(x, y int64) (int64, error) {
// Detecting multiplication overflow is more complicated than the others. The first two detect
// attempting to negate MinInt64, which would result in MaxInt64+1. The other four detect normal
// overflow conditions.
if (x == -1 && y == math.MinInt64) || (y == -1 && x == math.MinInt64) ||
// x is positive, y is positive
(x > 0 && y > 0 && x > math.MaxInt64/y) ||
// x is positive, y is negative
(x > 0 && y < 0 && y < math.MinInt64/x) ||
// x is negative, y is positive
(x < 0 && y > 0 && x < math.MinInt64/y) ||
// x is negative, y is negative
(x < 0 && y < 0 && y < math.MaxInt64/x) {
return 0, errIntOverflow
}
return x * y, nil
}
// divideInt64Checked performs division with overflow detection of two int64 values,
// as well as a division by zero check.
//
// If the operation fails the error return value will be non-nil.
func divideInt64Checked(x, y int64) (int64, error) {
// Division by zero.
if y == 0 {
return 0, errDivideByZero
}
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 && y == -1 {
return 0, errIntOverflow
}
return x / y, nil
}
// moduloInt64Checked performs modulo with overflow detection of two int64 values
// as well as a modulus by zero check.
//
// If the operation fails the error return value will be non-nil.
func moduloInt64Checked(x, y int64) (int64, error) {
// Modulus by zero.
if y == 0 {
return 0, errModulusByZero
}
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
if x == math.MinInt64 && y == -1 {
return 0, errIntOverflow
}
return x % y, nil
}
// addUint64Checked performs addition with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addUint64Checked(x, y uint64) (uint64, error) {
if y > 0 && x > math.MaxUint64-y {
return 0, errUintOverflow
}
return x + y, nil
}
// subtractUint64Checked performs subtraction with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractUint64Checked(x, y uint64) (uint64, error) {
if y > x {
return 0, errUintOverflow
}
return x - y, nil
}
// multiplyUint64Checked performs multiplication with overflow detection of two uint64 values.
//
// If the operation fails due to overflow the error return value will be non-nil.
func multiplyUint64Checked(x, y uint64) (uint64, error) {
if y != 0 && x > math.MaxUint64/y {
return 0, errUintOverflow
}
return x * y, nil
}
// divideUint64Checked performs division with a test for division by zero.
//
// If the operation fails the error return value will be non-nil.
func divideUint64Checked(x, y uint64) (uint64, error) {
if y == 0 {
return 0, errDivideByZero
}
return x / y, nil
}
// moduloUint64Checked performs modulo with a test for modulus by zero.
//
// If the operation fails the error return value will be non-nil.
func moduloUint64Checked(x, y uint64) (uint64, error) {
if y == 0 {
return 0, errModulusByZero
}
return x % y, nil
}
// addDurationChecked performs addition with overflow detection of two time.Durations.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addDurationChecked(x, y time.Duration) (time.Duration, error) {
val, err := addInt64Checked(int64(x), int64(y))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// subtractDurationChecked performs subtraction with overflow detection of two time.Durations.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractDurationChecked(x, y time.Duration) (time.Duration, error) {
val, err := subtractInt64Checked(int64(x), int64(y))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// negateDurationChecked performs negation with overflow detection of a time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func negateDurationChecked(x time.Duration) (time.Duration, error) {
val, err := negateInt64Checked(int64(x))
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// addDurationChecked performs addition with overflow detection of a time.Time and time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
// This is tricky. A time is represented as (int64, int32) where the first is seconds and second
// is nanoseconds. A duration is int64 representing nanoseconds. We cannot normalize time to int64
// as it could potentially overflow. The only way to proceed is to break time and duration into
// second and nanosecond components.
// First we break time into its components by truncating and subtracting.
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Second we break duration into its components by dividing and modulo.
sec2 := int64(y) / int64(time.Second) // Truncate to seconds.
nsec2 := int64(y) % int64(time.Second) // Get remainder.
// Add seconds first, detecting any overflow.
sec, err := addInt64Checked(sec1, sec2)
if err != nil {
return time.Time{}, err
}
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
nsec := nsec1 + nsec2
// We need to normalize nanoseconds to be positive and carry extra nanoseconds to seconds.
// Adapted from time.Unix(int64, int64).
if nsec < 0 || nsec >= int64(time.Second) {
// Add seconds.
sec, err = addInt64Checked(sec, nsec/int64(time.Second))
if err != nil {
return time.Time{}, err
}
nsec -= (nsec / int64(time.Second)) * int64(time.Second)
if nsec < 0 {
// Subtract an extra second
sec, err = addInt64Checked(sec, -1)
if err != nil {
return time.Time{}, err
}
nsec += int64(time.Second)
}
}
// Check if the the number of seconds from Unix epoch is within our acceptable range.
if sec < minUnixTime || sec > maxUnixTime {
return time.Time{}, errTimestampOverflow
}
// Return resulting time and propagate time zone.
return time.Unix(sec, nsec).In(x.Location()), nil
}
// subtractTimeChecked performs subtraction with overflow detection of two time.Time.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractTimeChecked(x, y time.Time) (time.Duration, error) {
// Similar to addTimeDurationOverflow() above.
// First we break time into its components by truncating and subtracting.
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Second we break duration into its components by truncating and subtracting.
sec2 := y.Truncate(time.Second).Unix() // Truncate to seconds.
nsec2 := y.Sub(y.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
// Subtract seconds first, detecting any overflow.
sec, err := subtractInt64Checked(sec1, sec2)
if err != nil {
return time.Duration(0), err
}
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
nsec := nsec1 - nsec2
// Scale seconds to nanoseconds detecting overflow.
tsec, err := multiplyInt64Checked(sec, int64(time.Second))
if err != nil {
return time.Duration(0), err
}
// Lastly we need to add the two nanoseconds together.
val, err := addInt64Checked(tsec, nsec)
if err != nil {
return time.Duration(0), err
}
return time.Duration(val), nil
}
// subtractTimeDurationChecked performs subtraction with overflow detection of a time.Time and
// time.Duration.
//
// If the operation fails due to overflow the error return value will be non-nil.
func subtractTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
// The easiest way to implement this is to negate y and add them.
// x - y = x + -y
val, err := negateDurationChecked(y)
if err != nil {
return time.Time{}, err
}
return addTimeDurationChecked(x, val)
}
// doubleToInt64Checked converts a double to an int64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func doubleToInt64Checked(v float64) (int64, error) {
if math.IsInf(v, 0) || math.IsNaN(v) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
return 0, errIntOverflow
}
return int64(v), nil
}
// doubleToInt64Checked converts a double to a uint64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func doubleToUint64Checked(v float64) (uint64, error) {
if math.IsInf(v, 0) || math.IsNaN(v) || v < 0 || v >= doubleTwoTo64 {
return 0, errUintOverflow
}
return uint64(v), nil
}
// int64toUint64Checked converts an int64 to a uint64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func int64ToUint64Checked(v int64) (uint64, error) {
if v < 0 {
return 0, errUintOverflow
}
return uint64(v), nil
}
// int64toInt32Checked converts an int64 to an int32 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func int64ToInt32Checked(v int64) (int32, error) {
if v < math.MinInt32 || v > math.MaxInt32 {
return 0, errIntOverflow
}
return int32(v), nil
}
// uint64toUint32Checked converts a uint64 to a uint32 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func uint64ToUint32Checked(v uint64) (uint32, error) {
if v > math.MaxUint32 {
return 0, errUintOverflow
}
return uint32(v), nil
}
// uint64toInt64Checked converts a uint64 to an int64 value.
//
// If the conversion fails due to overflow the error return value will be non-nil.
func uint64ToInt64Checked(v uint64) (int64, error) {
if v > math.MaxInt64 {
return 0, errIntOverflow
}
return int64(v), nil
}

View File

@@ -0,0 +1,50 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
package(
default_visibility = ["//visibility:public"],
licenses = ["notice"], # Apache 2.0
)
go_library(
name = "go_default_library",
srcs = [
"checked.go",
"enum.go",
"file.go",
"pb.go",
"type.go",
],
importpath = "github.com/google/cel-go/common/types/pb",
deps = [
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//reflect/protoregistry:go_default_library",
"@org_golang_google_protobuf//types/dynamicpb:go_default_library",
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
],
)
go_test(
name = "go_default_test",
size = "small",
srcs = [
"file_test.go",
"pb_test.go",
"type_test.go",
],
embed = [":go_default_library"],
deps = [
"//checker/decls:go_default_library",
"//test/proto2pb:test_all_types_go_proto",
"//test/proto3pb:test_all_types_go_proto",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
],
)

View File

@@ -0,0 +1,93 @@
// 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 pb
import (
"google.golang.org/protobuf/reflect/protoreflect"
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
emptypb "google.golang.org/protobuf/types/known/emptypb"
structpb "google.golang.org/protobuf/types/known/structpb"
)
var (
// CheckedPrimitives map from proto field descriptor type to expr.Type.
CheckedPrimitives = map[protoreflect.Kind]*exprpb.Type{
protoreflect.BoolKind: checkedBool,
protoreflect.BytesKind: checkedBytes,
protoreflect.DoubleKind: checkedDouble,
protoreflect.FloatKind: checkedDouble,
protoreflect.Int32Kind: checkedInt,
protoreflect.Int64Kind: checkedInt,
protoreflect.Sint32Kind: checkedInt,
protoreflect.Sint64Kind: checkedInt,
protoreflect.Uint32Kind: checkedUint,
protoreflect.Uint64Kind: checkedUint,
protoreflect.Fixed32Kind: checkedUint,
protoreflect.Fixed64Kind: checkedUint,
protoreflect.Sfixed32Kind: checkedInt,
protoreflect.Sfixed64Kind: checkedInt,
protoreflect.StringKind: checkedString}
// CheckedWellKnowns map from qualified proto type name to expr.Type for
// well-known proto types.
CheckedWellKnowns = map[string]*exprpb.Type{
// Wrapper types.
"google.protobuf.BoolValue": checkedWrap(checkedBool),
"google.protobuf.BytesValue": checkedWrap(checkedBytes),
"google.protobuf.DoubleValue": checkedWrap(checkedDouble),
"google.protobuf.FloatValue": checkedWrap(checkedDouble),
"google.protobuf.Int64Value": checkedWrap(checkedInt),
"google.protobuf.Int32Value": checkedWrap(checkedInt),
"google.protobuf.UInt64Value": checkedWrap(checkedUint),
"google.protobuf.UInt32Value": checkedWrap(checkedUint),
"google.protobuf.StringValue": checkedWrap(checkedString),
// Well-known types.
"google.protobuf.Any": checkedAny,
"google.protobuf.Duration": checkedDuration,
"google.protobuf.Timestamp": checkedTimestamp,
// Json types.
"google.protobuf.ListValue": checkedListDyn,
"google.protobuf.NullValue": checkedNull,
"google.protobuf.Struct": checkedMapStringDyn,
"google.protobuf.Value": checkedDyn,
}
// common types
checkedDyn = &exprpb.Type{TypeKind: &exprpb.Type_Dyn{Dyn: &emptypb.Empty{}}}
// Wrapper and primitive types.
checkedBool = checkedPrimitive(exprpb.Type_BOOL)
checkedBytes = checkedPrimitive(exprpb.Type_BYTES)
checkedDouble = checkedPrimitive(exprpb.Type_DOUBLE)
checkedInt = checkedPrimitive(exprpb.Type_INT64)
checkedString = checkedPrimitive(exprpb.Type_STRING)
checkedUint = checkedPrimitive(exprpb.Type_UINT64)
// Well-known type equivalents.
checkedAny = checkedWellKnown(exprpb.Type_ANY)
checkedDuration = checkedWellKnown(exprpb.Type_DURATION)
checkedTimestamp = checkedWellKnown(exprpb.Type_TIMESTAMP)
// Json-based type equivalents.
checkedNull = &exprpb.Type{
TypeKind: &exprpb.Type_Null{
Null: structpb.NullValue_NULL_VALUE}}
checkedListDyn = &exprpb.Type{
TypeKind: &exprpb.Type_ListType_{
ListType: &exprpb.Type_ListType{ElemType: checkedDyn}}}
checkedMapStringDyn = &exprpb.Type{
TypeKind: &exprpb.Type_MapType_{
MapType: &exprpb.Type_MapType{
KeyType: checkedString,
ValueType: checkedDyn}}}
)

View File

@@ -0,0 +1,44 @@
// 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 pb
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// NewEnumValueDescription produces an enum value description with the fully qualified enum value
// name and the enum value descriptor.
func NewEnumValueDescription(name string, desc protoreflect.EnumValueDescriptor) *EnumValueDescription {
return &EnumValueDescription{
enumValueName: name,
desc: desc,
}
}
// EnumValueDescription maps a fully-qualified enum value name to its numeric value.
type EnumValueDescription struct {
enumValueName string
desc protoreflect.EnumValueDescriptor
}
// Name returns the fully-qualified identifier name for the enum value.
func (ed *EnumValueDescription) Name() string {
return ed.enumValueName
}
// Value returns the (numeric) value of the enum.
func (ed *EnumValueDescription) Value() int32 {
return int32(ed.desc.Number())
}

Some files were not shown because too many files have changed in this diff Show More