...

Source file src/github.com/PaesslerAG/gval/language.go

Documentation: github.com/PaesslerAG/gval

     1  package gval
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"text/scanner"
     7  	"unicode"
     8  
     9  	"github.com/shopspring/decimal"
    10  )
    11  
    12  // Language is an expression language
    13  type Language struct {
    14  	prefixes        map[interface{}]extension
    15  	operators       map[string]operator
    16  	operatorSymbols map[rune]struct{}
    17  	init            extension
    18  	def             extension
    19  	selector        func(Evaluables) Evaluable
    20  }
    21  
    22  // NewLanguage returns the union of given Languages as new Language.
    23  func NewLanguage(bases ...Language) Language {
    24  	l := newLanguage()
    25  	for _, base := range bases {
    26  		for i, e := range base.prefixes {
    27  			l.prefixes[i] = e
    28  		}
    29  		for i, e := range base.operators {
    30  			l.operators[i] = e.merge(l.operators[i])
    31  			l.operators[i].initiate(i)
    32  		}
    33  		for i := range base.operatorSymbols {
    34  			l.operatorSymbols[i] = struct{}{}
    35  		}
    36  		if base.init != nil {
    37  			l.init = base.init
    38  		}
    39  		if base.def != nil {
    40  			l.def = base.def
    41  		}
    42  		if base.selector != nil {
    43  			l.selector = base.selector
    44  		}
    45  	}
    46  	return l
    47  }
    48  
    49  func newLanguage() Language {
    50  	return Language{
    51  		prefixes:        map[interface{}]extension{},
    52  		operators:       map[string]operator{},
    53  		operatorSymbols: map[rune]struct{}{},
    54  	}
    55  }
    56  
    57  // NewEvaluable returns an Evaluable for given expression in the specified language
    58  func (l Language) NewEvaluable(expression string) (Evaluable, error) {
    59  	return l.NewEvaluableWithContext(context.Background(), expression)
    60  }
    61  
    62  // NewEvaluableWithContext returns an Evaluable for given expression in the specified language using context
    63  func (l Language) NewEvaluableWithContext(c context.Context, expression string) (Evaluable, error) {
    64  	p := newParser(expression, l)
    65  
    66  	eval, err := p.parse(c)
    67  	if err == nil && p.isCamouflaged() && p.lastScan != scanner.EOF {
    68  		err = p.camouflage
    69  	}
    70  	if err != nil {
    71  		pos := p.scanner.Pos()
    72  		return nil, fmt.Errorf("parsing error: %s - %d:%d %w", p.scanner.Position, pos.Line, pos.Column, err)
    73  	}
    74  
    75  	return eval, nil
    76  }
    77  
    78  // Evaluate given parameter with given expression
    79  func (l Language) Evaluate(expression string, parameter interface{}) (interface{}, error) {
    80  	return l.EvaluateWithContext(context.Background(), expression, parameter)
    81  }
    82  
    83  // Evaluate given parameter with given expression using context
    84  func (l Language) EvaluateWithContext(c context.Context, expression string, parameter interface{}) (interface{}, error) {
    85  	eval, err := l.NewEvaluableWithContext(c, expression)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	v, err := eval(c, parameter)
    90  	if err != nil {
    91  		return nil, fmt.Errorf("can not evaluate %s: %w", expression, err)
    92  	}
    93  	return v, nil
    94  }
    95  
    96  // Function returns a Language with given function.
    97  // Function has no conversion for input types.
    98  //
    99  // If the function returns an error it must be the last return parameter.
   100  //
   101  // If the function has (without the error) more then one return parameter,
   102  // it returns them as []interface{}.
   103  func Function(name string, function interface{}) Language {
   104  	l := newLanguage()
   105  	l.prefixes[name] = func(c context.Context, p *Parser) (eval Evaluable, err error) {
   106  		args := []Evaluable{}
   107  		scan := p.Scan()
   108  		switch scan {
   109  		case '(':
   110  			args, err = p.parseArguments(c)
   111  			if err != nil {
   112  				return nil, err
   113  			}
   114  		default:
   115  			p.Camouflage("function call", '(')
   116  		}
   117  		return p.callFunc(toFunc(function), args...), nil
   118  	}
   119  	return l
   120  }
   121  
   122  // Constant returns a Language with given constant
   123  func Constant(name string, value interface{}) Language {
   124  	l := newLanguage()
   125  	l.prefixes[l.makePrefixKey(name)] = func(c context.Context, p *Parser) (eval Evaluable, err error) {
   126  		return p.Const(value), nil
   127  	}
   128  	return l
   129  }
   130  
   131  // PrefixExtension extends a Language
   132  func PrefixExtension(r rune, ext func(context.Context, *Parser) (Evaluable, error)) Language {
   133  	l := newLanguage()
   134  	l.prefixes[r] = ext
   135  	return l
   136  }
   137  
   138  // Init is a language that does no parsing, but invokes the given function when
   139  // parsing starts. It is incumbent upon the function to call ParseExpression to
   140  // continue parsing.
   141  //
   142  // This function can be used to customize the parser settings, such as
   143  // whitespace or ident behavior.
   144  func Init(ext func(context.Context, *Parser) (Evaluable, error)) Language {
   145  	l := newLanguage()
   146  	l.init = ext
   147  	return l
   148  }
   149  
   150  // DefaultExtension is a language that runs the given function if no other
   151  // prefix matches.
   152  func DefaultExtension(ext func(context.Context, *Parser) (Evaluable, error)) Language {
   153  	l := newLanguage()
   154  	l.def = ext
   155  	return l
   156  }
   157  
   158  // PrefixMetaPrefix chooses a Prefix to be executed
   159  func PrefixMetaPrefix(r rune, ext func(context.Context, *Parser) (call string, alternative func() (Evaluable, error), err error)) Language {
   160  	l := newLanguage()
   161  	l.prefixes[r] = func(c context.Context, p *Parser) (Evaluable, error) {
   162  		call, alternative, err := ext(c, p)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		if prefix, ok := p.prefixes[l.makePrefixKey(call)]; ok {
   167  			return prefix(c, p)
   168  		}
   169  		return alternative()
   170  	}
   171  	return l
   172  }
   173  
   174  //PrefixOperator returns a Language with given prefix
   175  func PrefixOperator(name string, e Evaluable) Language {
   176  	l := newLanguage()
   177  	l.prefixes[l.makePrefixKey(name)] = func(c context.Context, p *Parser) (Evaluable, error) {
   178  		eval, err := p.ParseNextExpression(c)
   179  		if err != nil {
   180  			return nil, err
   181  		}
   182  		prefix := func(c context.Context, v interface{}) (interface{}, error) {
   183  			a, err := eval(c, v)
   184  			if err != nil {
   185  				return nil, err
   186  			}
   187  			return e(c, a)
   188  		}
   189  		if eval.IsConst() {
   190  			v, err := prefix(c, nil)
   191  			if err != nil {
   192  				return nil, err
   193  			}
   194  			prefix = p.Const(v)
   195  		}
   196  		return prefix, nil
   197  	}
   198  	return l
   199  }
   200  
   201  // PostfixOperator extends a Language.
   202  func PostfixOperator(name string, ext func(context.Context, *Parser, Evaluable) (Evaluable, error)) Language {
   203  	l := newLanguage()
   204  	l.operators[l.makeInfixKey(name)] = postfix{
   205  		f: func(c context.Context, p *Parser, eval Evaluable, pre operatorPrecedence) (Evaluable, error) {
   206  			return ext(c, p, eval)
   207  		},
   208  	}
   209  	return l
   210  }
   211  
   212  // InfixOperator for two arbitrary values.
   213  func InfixOperator(name string, f func(a, b interface{}) (interface{}, error)) Language {
   214  	return newLanguageOperator(name, &infix{arbitrary: f})
   215  }
   216  
   217  // InfixShortCircuit operator is called after the left operand is evaluated.
   218  func InfixShortCircuit(name string, f func(a interface{}) (interface{}, bool)) Language {
   219  	return newLanguageOperator(name, &infix{shortCircuit: f})
   220  }
   221  
   222  // InfixTextOperator for two text values.
   223  func InfixTextOperator(name string, f func(a, b string) (interface{}, error)) Language {
   224  	return newLanguageOperator(name, &infix{text: f})
   225  }
   226  
   227  // InfixNumberOperator for two number values.
   228  func InfixNumberOperator(name string, f func(a, b float64) (interface{}, error)) Language {
   229  	return newLanguageOperator(name, &infix{number: f})
   230  }
   231  
   232  // InfixDecimalOperator for two decimal values.
   233  func InfixDecimalOperator(name string, f func(a, b decimal.Decimal) (interface{}, error)) Language {
   234  	return newLanguageOperator(name, &infix{decimal: f})
   235  }
   236  
   237  // InfixBoolOperator for two bool values.
   238  func InfixBoolOperator(name string, f func(a, b bool) (interface{}, error)) Language {
   239  	return newLanguageOperator(name, &infix{boolean: f})
   240  }
   241  
   242  // Precedence of operator. The Operator with higher operatorPrecedence is evaluated first.
   243  func Precedence(name string, operatorPrecendence uint8) Language {
   244  	return newLanguageOperator(name, operatorPrecedence(operatorPrecendence))
   245  }
   246  
   247  // InfixEvalOperator operates on the raw operands.
   248  // Therefore it cannot be combined with operators for other operand types.
   249  func InfixEvalOperator(name string, f func(a, b Evaluable) (Evaluable, error)) Language {
   250  	return newLanguageOperator(name, directInfix{infixBuilder: f})
   251  }
   252  
   253  func newLanguageOperator(name string, op operator) Language {
   254  	op.initiate(name)
   255  	l := newLanguage()
   256  	l.operators[l.makeInfixKey(name)] = op
   257  	return l
   258  }
   259  
   260  func (l *Language) makePrefixKey(key string) interface{} {
   261  	runes := []rune(key)
   262  	if len(runes) == 1 && !unicode.IsLetter(runes[0]) {
   263  		return runes[0]
   264  	}
   265  	return key
   266  }
   267  
   268  func (l *Language) makeInfixKey(key string) string {
   269  	for _, r := range key {
   270  		l.operatorSymbols[r] = struct{}{}
   271  	}
   272  	return key
   273  }
   274  
   275  // VariableSelector returns a Language which uses given variable selector.
   276  // It must be combined with a Language that uses the vatiable selector. E.g. gval.Base().
   277  func VariableSelector(selector func(path Evaluables) Evaluable) Language {
   278  	l := newLanguage()
   279  	l.selector = selector
   280  	return l
   281  }
   282  

View as plain text