Documentation ¶
Overview ¶
Package eval implements evaluated objects
Package eval implements evaluated objects ¶
Package eval implements expression values that can be evaluated ¶
Expression syntax ¶
The language used by eval is a very simple infix expression. The terms can be numbers or quoted strings or names.
Arrays and objects can be specified like so:
(1, 2, 3) (x = 42, y = 23)
Empty arrays can be specified like: ()
Arrays with single items can be expressed via (x,). Just doing (x) will only work for function call args -- everywhere else, it is treated as a grouping operator
Empty objects can be found via the global "nil"
Object definitions automatically create local lexical scopes:
(x = y + 100, y = 23) == (x = 123, y = 23)
Scoping is lexical (nesting appropriately) and the order of definitions is not important all all expressions are immutable.
Fields and methods can be accessed via dot:
(1, 2, 3).count == 3
Arrays and maps support filter, map and reduce:
(1, 2, 3).filter(value <= 2)
The expression within filter and map can refer to "value" and "key/index". These are dynamically scoped to a specific array element. Reduce also provides a "last" variable to track cumulative result.
(1, 2, 3).reduce(100, last + value) == 106
The Parser ¶
An expression value can be produced by use of Parse:
eval.Parse(scope, "list.map(value + 2)") => equivalent to the following: // first define all the tokens dot := &data.Ref{ID: types.S16(".")} plus := &data.Ref{ID: types.S16("+")} list := &data.Ref{ID: types.S16("list")} doMap := &data.Ref{ID: types.S16("map")} value := &data.Ref{ID: types.S16("value")} two := changes.Atomic{Value: 2} now create a call expression for the above expr := &data.Call{A: types.A{ // first element evaluates to list.map &data.Call{A: types.A{dot, list, doMap}}, // second element represents value+2 &data.Call{A: types.A{plus, value, two}}, }}
Evaluation ¶
An expression can be evaluated with Eval(). Eval converts call expression to the actual evaluated values using the provided scope. Eval also walks the contents of any containers, replacing any expressions with their evaluated values. Eval honors references via Dir (so this is an easy way to create local scopes).
Package eval implements evaluated objects
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Eval ¶
Eval evaluates a value within a particular scope
Values of type CallExpr evaluate to the corresponding call. All other values are simply the same values but with any nested call expressions evaluated.
The provided scope is used to lookup IDs with Ref{} values. Any Dir values automatically contribute by creating a new scope
Types ¶
type Call ¶
Call represents a "call" expression. The first element of the array is expected to be "Callable" which can be called with the rest as args.
All errors result in a nil result.
type Callable ¶
Callable wraps a function into a value type that can be called
var Dot Callable = func(s Scope, args []changes.Value) changes.Value { var receiver changes.Value = changes.Nil if len(args) > 0 { receiver = args[0] for _, arg := range args[1:] { receiver = dot(s, receiver, arg) } } return receiver }
Dot is the "callable" which evaluates args[0].args[1].args[2]...
Equal compares if value are all the same
NotEqual compares if values are all different
NumLess compares if numbers are in ascending order
NumLessThanEqual is like NumEqual but with equality allowed
NumMore compares if numbers are in descending order
NumMoreThanEqual compares if numbers are in descending order
var Sum Callable = func(s Scope, args []changes.Value) changes.Value { var sum int for _, arg := range args { atomic, _ := Eval(s, arg).(changes.Atomic) val, _ := atomic.Value.(int) sum += val } return changes.Atomic{Value: sum} }
Sum is the "callable" which evaluates the sum of all args
Non-numeric values are treated as zeros
type ParseError ¶
ParseError captures the error state