2017-06-25 22:21:31 +02:00
|
|
|
%{
|
2017-06-26 15:33:07 +02:00
|
|
|
package expressions
|
2017-06-25 22:21:31 +02:00
|
|
|
import (
|
2017-06-26 14:23:50 +02:00
|
|
|
"fmt"
|
2017-06-26 04:59:33 +02:00
|
|
|
"reflect"
|
2017-06-25 22:21:31 +02:00
|
|
|
)
|
2017-06-26 14:23:50 +02:00
|
|
|
|
|
|
|
func init() {
|
|
|
|
_ = fmt.Sprint("")
|
|
|
|
}
|
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
%}
|
|
|
|
%union {
|
|
|
|
name string
|
2017-06-26 02:47:31 +02:00
|
|
|
val interface{}
|
|
|
|
f func(Context) interface{}
|
2017-06-25 22:21:31 +02:00
|
|
|
}
|
2017-06-27 03:32:08 +02:00
|
|
|
%type <f> expr rel expr1
|
2017-06-26 02:47:31 +02:00
|
|
|
%token <val> LITERAL
|
2017-06-27 03:32:08 +02:00
|
|
|
%token <name> IDENTIFIER KEYWORD RELATION
|
2017-06-26 21:36:05 +02:00
|
|
|
%token ASSIGN
|
2017-06-26 15:06:55 +02:00
|
|
|
%token EQ
|
2017-06-27 03:32:08 +02:00
|
|
|
%left '.' '|'
|
2017-06-26 15:06:55 +02:00
|
|
|
%left '<' '>'
|
2017-06-25 22:21:31 +02:00
|
|
|
%%
|
2017-06-26 21:36:05 +02:00
|
|
|
start:
|
|
|
|
rel ';' { yylex.(*lexer).val = $1 }
|
2017-06-27 03:32:08 +02:00
|
|
|
| ASSIGN IDENTIFIER '=' expr1 ';' {
|
2017-06-26 21:36:05 +02:00
|
|
|
name, expr := $2, $4
|
|
|
|
yylex.(*lexer).val = func(ctx Context) interface{} {
|
|
|
|
ctx.Set(name, expr(ctx))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
};
|
2017-06-25 22:21:31 +02:00
|
|
|
|
2017-06-26 02:47:31 +02:00
|
|
|
expr:
|
2017-06-26 13:50:53 +02:00
|
|
|
LITERAL { val := $1; $$ = func(_ Context) interface{} { return val } }
|
2017-06-26 21:36:05 +02:00
|
|
|
| IDENTIFIER { name := $1; $$ = func(ctx Context) interface{} { return ctx.Get(name) } }
|
2017-06-26 13:50:53 +02:00
|
|
|
| expr '.' IDENTIFIER {
|
|
|
|
e, attr := $1, $3
|
2017-06-26 04:59:33 +02:00
|
|
|
$$ = func(ctx Context) interface{} {
|
2017-06-26 14:23:50 +02:00
|
|
|
obj := e(ctx)
|
|
|
|
ref := reflect.ValueOf(obj)
|
2017-06-26 04:59:33 +02:00
|
|
|
switch ref.Kind() {
|
|
|
|
case reflect.Map:
|
2017-06-26 14:23:50 +02:00
|
|
|
val := ref.MapIndex(reflect.ValueOf(attr))
|
|
|
|
if val.Kind()!= reflect.Invalid {
|
|
|
|
return val.Interface()
|
|
|
|
}
|
2017-06-26 13:50:53 +02:00
|
|
|
}
|
2017-06-26 14:23:50 +02:00
|
|
|
return nil
|
2017-06-26 13:50:53 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-26 14:23:50 +02:00
|
|
|
| expr '[' expr ']' {
|
2017-06-26 13:50:53 +02:00
|
|
|
e, i := $1, $3
|
|
|
|
$$ = func(ctx Context) interface{} {
|
|
|
|
ref := reflect.ValueOf(e(ctx))
|
|
|
|
index := reflect.ValueOf(i(ctx))
|
|
|
|
switch ref.Kind() {
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
|
|
switch index.Kind() {
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
n := int(index.Int())
|
|
|
|
if 0 <= n && n < ref.Len() {
|
|
|
|
return ref.Index(n).Interface()
|
|
|
|
}
|
|
|
|
}
|
2017-06-26 04:59:33 +02:00
|
|
|
}
|
2017-06-26 14:23:50 +02:00
|
|
|
return nil
|
2017-06-26 04:59:33 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-27 03:32:08 +02:00
|
|
|
|
|
|
|
expr1:
|
|
|
|
expr
|
|
|
|
| expr1 '|' IDENTIFIER { $$ = makeFilter($1, $3, nil) }
|
|
|
|
| expr1 '|' KEYWORD expr { $$ = makeFilter($1, $3, $4) }
|
2017-06-26 04:59:33 +02:00
|
|
|
;
|
2017-06-26 13:50:53 +02:00
|
|
|
|
2017-06-26 15:06:55 +02:00
|
|
|
rel:
|
2017-06-27 03:32:08 +02:00
|
|
|
expr1
|
2017-06-26 15:06:55 +02:00
|
|
|
| expr EQ expr {
|
|
|
|
a, b := $1, $3
|
|
|
|
$$ = func(ctx Context) interface{} {
|
|
|
|
aref, bref := reflect.ValueOf(a(ctx)), reflect.ValueOf(b(ctx))
|
|
|
|
return GenericCompare(aref, bref) == 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
| expr '<' expr {
|
|
|
|
a, b := $1, $3
|
|
|
|
$$ = func(ctx Context) interface{} {
|
|
|
|
aref, bref := reflect.ValueOf(a(ctx)), reflect.ValueOf(b(ctx))
|
|
|
|
return GenericCompare(aref, bref) < 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
| expr '>' expr {
|
|
|
|
a, b := $1, $3
|
|
|
|
$$ = func(ctx Context) interface{} {
|
|
|
|
aref, bref := reflect.ValueOf(a(ctx)), reflect.ValueOf(b(ctx))
|
|
|
|
return GenericCompare(aref, bref) > 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|