123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- package govaluate
- import (
- "errors"
- "fmt"
- )
- type lexerState struct {
- isEOF bool
- isNullable bool
- kind TokenKind
- validNextKinds []TokenKind
- }
- // lexer states.
- // Constant for all purposes except compiler.
- var validLexerStates = []lexerState{
- lexerState{
- kind: UNKNOWN,
- isEOF: false,
- isNullable: true,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- PATTERN,
- FUNCTION,
- STRING,
- TIME,
- CLAUSE,
- },
- },
- lexerState{
- kind: CLAUSE,
- isEOF: false,
- isNullable: true,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- PATTERN,
- FUNCTION,
- STRING,
- TIME,
- CLAUSE,
- CLAUSE_CLOSE,
- },
- },
- lexerState{
- kind: CLAUSE_CLOSE,
- isEOF: true,
- isNullable: true,
- validNextKinds: []TokenKind{
- COMPARATOR,
- MODIFIER,
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- STRING,
- PATTERN,
- TIME,
- CLAUSE,
- CLAUSE_CLOSE,
- LOGICALOP,
- TERNARY,
- SEPARATOR,
- },
- },
- lexerState{
- kind: NUMERIC,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- TERNARY,
- SEPARATOR,
- },
- },
- lexerState{
- kind: BOOLEAN,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- TERNARY,
- SEPARATOR,
- },
- },
- lexerState{
- kind: STRING,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- TERNARY,
- SEPARATOR,
- },
- },
- lexerState{
- kind: TIME,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- SEPARATOR,
- },
- },
- lexerState{
- kind: PATTERN,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- SEPARATOR,
- },
- },
- lexerState{
- kind: VARIABLE,
- isEOF: true,
- isNullable: false,
- validNextKinds: []TokenKind{
- MODIFIER,
- COMPARATOR,
- LOGICALOP,
- CLAUSE_CLOSE,
- TERNARY,
- SEPARATOR,
- },
- },
- lexerState{
- kind: MODIFIER,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- VARIABLE,
- FUNCTION,
- STRING,
- BOOLEAN,
- CLAUSE,
- CLAUSE_CLOSE,
- },
- },
- lexerState{
- kind: COMPARATOR,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- FUNCTION,
- STRING,
- TIME,
- CLAUSE,
- CLAUSE_CLOSE,
- PATTERN,
- },
- },
- lexerState{
- kind: LOGICALOP,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- FUNCTION,
- STRING,
- TIME,
- CLAUSE,
- CLAUSE_CLOSE,
- },
- },
- lexerState{
- kind: PREFIX,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- NUMERIC,
- BOOLEAN,
- VARIABLE,
- FUNCTION,
- CLAUSE,
- CLAUSE_CLOSE,
- },
- },
- lexerState{
- kind: TERNARY,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- STRING,
- TIME,
- VARIABLE,
- FUNCTION,
- CLAUSE,
- SEPARATOR,
- },
- },
- lexerState{
- kind: FUNCTION,
- isEOF: false,
- isNullable: false,
- validNextKinds: []TokenKind{
- CLAUSE,
- },
- },
- lexerState{
- kind: SEPARATOR,
- isEOF: false,
- isNullable: true,
- validNextKinds: []TokenKind{
- PREFIX,
- NUMERIC,
- BOOLEAN,
- STRING,
- TIME,
- VARIABLE,
- FUNCTION,
- CLAUSE,
- },
- },
- }
- func (this lexerState) canTransitionTo(kind TokenKind) bool {
- for _, validKind := range this.validNextKinds {
- if validKind == kind {
- return true
- }
- }
- return false
- }
- func checkExpressionSyntax(tokens []ExpressionToken) error {
- var state lexerState
- var lastToken ExpressionToken
- var err error
- state = validLexerStates[0]
- for _, token := range tokens {
- if !state.canTransitionTo(token.Kind) {
- // call out a specific error for tokens looking like they want to be functions.
- if lastToken.Kind == VARIABLE && token.Kind == CLAUSE {
- return errors.New("Undefined function " + lastToken.Value.(string))
- }
- firstStateName := fmt.Sprintf("%s [%v]", state.kind.String(), lastToken.Value)
- nextStateName := fmt.Sprintf("%s [%v]", token.Kind.String(), token.Value)
- return errors.New("Cannot transition token types from " + firstStateName + " to " + nextStateName)
- }
- state, err = getLexerStateForToken(token.Kind)
- if err != nil {
- return err
- }
- if !state.isNullable && token.Value == nil {
- errorMsg := fmt.Sprintf("Token kind '%v' cannot have a nil value", token.Kind.String())
- return errors.New(errorMsg)
- }
- lastToken = token
- }
- if !state.isEOF {
- return errors.New("Unexpected end of expression")
- }
- return nil
- }
- func getLexerStateForToken(kind TokenKind) (lexerState, error) {
- for _, possibleState := range validLexerStates {
- if possibleState.kind == kind {
- return possibleState, nil
- }
- }
- errorMsg := fmt.Sprintf("No lexer state found for token kind '%v'\n", kind.String())
- return validLexerStates[0], errors.New(errorMsg)
- }
|