Variable reference
This commit is contained in:
parent
574a6f5215
commit
0ba96e65a5
@ -25,6 +25,7 @@ type exprFunc interface {
|
||||
Name() string
|
||||
MinArgs() int
|
||||
MaxArgs() int
|
||||
Functor() Functor
|
||||
}
|
||||
|
||||
// ----Expression Context
|
||||
@ -33,6 +34,7 @@ type exprContext interface {
|
||||
GetVar(varName string) (value any, exists bool)
|
||||
SetVar(varName string, value any)
|
||||
EnumVars(func(name string) (accept bool)) (varNames []string)
|
||||
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
||||
GetFuncInfo(name string) exprFunc
|
||||
Call(name string, args []any) (result any, err error)
|
||||
RegisterFunc(name string, f Functor, minArgs, maxArgs int)
|
||||
|
@ -104,9 +104,14 @@ func doImport(ctx exprContext, name string, dirList []string, it Iterator) (resu
|
||||
var expr *ast
|
||||
scanner := NewScanner(file, DefaultTranslations())
|
||||
parser := NewParser(ctx)
|
||||
if expr, err = parser.parse(scanner); err == nil {
|
||||
if expr, err = parser.parseGeneral(scanner, true, true); err == nil {
|
||||
_, err = expr.Eval(ctx, false)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil && err == io.EOF {
|
||||
|
@ -36,10 +36,17 @@ func evalFuncCall(parentCtx exprContext, self *term) (v any, err error) {
|
||||
}
|
||||
if err == nil {
|
||||
if v, err = ctx.Call(name, params); err == nil {
|
||||
// Export variables
|
||||
for _, refName := range ctx.EnumVars(func(name string) bool { return name[0] == '@' }) {
|
||||
refValue, _ := ctx.GetVar(refName)
|
||||
parentCtx.SetVar(refName[1:], refValue)
|
||||
}
|
||||
// Export functions
|
||||
for _, refName := range ctx.EnumFuncs(func(name string) bool { return name[0] == '@' }) {
|
||||
if info := ctx.GetFuncInfo(refName); info != nil {
|
||||
parentCtx.RegisterFunc(refName[1:], info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -139,11 +139,11 @@ func TestParser(t *testing.T) {
|
||||
/* 118 */ {`x="hello"; x ?= "default"; x`, "hello", nil},
|
||||
/* 119 */ {`@x="hello"; @x`, nil, errors.New(`[1:3] variable references are not allowed in top level expressions: "@x"`)},
|
||||
/* 120 */ {`f=func(){@x="hello"}; f(); x`, "hello", nil},
|
||||
/* 120 */ {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil},
|
||||
/* 121 */ {`f=func(@y){g=func(){@x=5}; @y=@y+g()}; f(2); y+x`, nil, errors.New(`undefined variable "x"`)},
|
||||
/* 122 */ {`f=func(@y){g=func(){@x=5}; @z=g(); @y=@y+@z}; f(2); y+z`, int64(12), nil},
|
||||
/* 123 */ {`f=func(@y){g=func(){@x=5}; g(); @z=@x; @y=@y+@z}; f(2); y+z`, int64(12), nil},
|
||||
// TODO Fix this: /* 124 */ {`f=func(@y){g=func(){@x=5}; g(); @z=@x; @y=@y+@z}; f(2); y+x`, nil, errors.New(`undefined variable "x"`)},
|
||||
/* 121 */ {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil},
|
||||
/* 122 */ {`f=func(@y){g=func(){@x=5}; @y=@y+g()}; f(2); y+x`, nil, errors.New(`undefined variable "x"`)},
|
||||
/* 123 */ {`f=func(@y){g=func(){@x=5}; @z=g(); @y=@y+@z}; f(2); y+z`, int64(12), nil},
|
||||
/* 124 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @y=@y+@z}; f(2); y+z`, int64(12), nil},
|
||||
/* 125 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @x=@y+@z}; f(2); y+x`, int64(9), nil},
|
||||
}
|
||||
check_env_expr_path := 113
|
||||
|
||||
@ -151,6 +151,7 @@ func TestParser(t *testing.T) {
|
||||
failed := 0
|
||||
|
||||
// inputs1 := []inputType{
|
||||
// {`f=func(@y){g=func(){@x=5}; g(); @z=x}; f(2)`, int64(5), nil},
|
||||
// {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil},
|
||||
// {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
||||
// {`add(1,2,3)`, int64(6), nil},
|
||||
@ -205,7 +206,7 @@ func TestParser(t *testing.T) {
|
||||
t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed))
|
||||
}
|
||||
|
||||
func NoTestListParser(t *testing.T) {
|
||||
func TestListParser(t *testing.T) {
|
||||
type inputType struct {
|
||||
source string
|
||||
wantResult any
|
||||
@ -261,7 +262,6 @@ func NoTestListParser(t *testing.T) {
|
||||
good = false
|
||||
}
|
||||
|
||||
// if good {}
|
||||
if gotList, okGot := gotResult.([]any); okGot {
|
||||
if wantList, okWant := input.wantResult.([]any); okWant {
|
||||
if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) {
|
||||
|
@ -5,13 +5,14 @@ import "fmt"
|
||||
|
||||
type SimpleFuncStore struct {
|
||||
varStore map[string]any
|
||||
funcStore map[string]Functor
|
||||
funcStore map[string]*funcInfo
|
||||
}
|
||||
|
||||
type funcInfo struct {
|
||||
name string
|
||||
// minArgs int
|
||||
// maxArgs int
|
||||
minArgs int
|
||||
maxArgs int
|
||||
functor Functor
|
||||
}
|
||||
|
||||
func (info *funcInfo) Name() string {
|
||||
@ -19,17 +20,21 @@ func (info *funcInfo) Name() string {
|
||||
}
|
||||
|
||||
func (info *funcInfo) MinArgs() int {
|
||||
return 0
|
||||
return info.minArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) MaxArgs() int {
|
||||
return -1
|
||||
return info.maxArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) Functor() Functor {
|
||||
return info.functor
|
||||
}
|
||||
|
||||
func NewSimpleFuncStore() *SimpleFuncStore {
|
||||
return &SimpleFuncStore{
|
||||
varStore: make(map[string]any),
|
||||
funcStore: make(map[string]Functor),
|
||||
funcStore: make(map[string]*funcInfo),
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,20 +68,32 @@ func (ctx *SimpleFuncStore) EnumVars(acceptor func(name string) (accept bool)) (
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (f exprFunc) {
|
||||
var exists bool
|
||||
if _, exists = ctx.funcStore[name]; exists {
|
||||
f = &funcInfo{name: name}
|
||||
}
|
||||
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (info exprFunc) {
|
||||
info, _ = ctx.funcStore[name]
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *SimpleFuncStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
|
||||
ctx.funcStore[name] = functor
|
||||
ctx.funcStore[name] = &funcInfo{name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor}
|
||||
}
|
||||
|
||||
func (ctx *SimpleFuncStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
|
||||
funcNames = make([]string, 0)
|
||||
for name := range ctx.funcStore {
|
||||
if acceptor != nil {
|
||||
if acceptor(name) {
|
||||
funcNames = append(funcNames, name)
|
||||
}
|
||||
} else {
|
||||
funcNames = append(funcNames, name)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *SimpleFuncStore) Call(name string, args []any) (result any, err error) {
|
||||
if functor, exists := ctx.funcStore[name]; exists {
|
||||
if info, exists := ctx.funcStore[name]; exists {
|
||||
functor := info.functor
|
||||
result, err = functor.Invoke(ctx, name, args)
|
||||
} else {
|
||||
err = fmt.Errorf("unknown function %s()", name)
|
||||
|
@ -51,3 +51,7 @@ func (ctx *SimpleVarStore) Call(name string, args []any) (result any, err error)
|
||||
|
||||
func (ctx *SimpleVarStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
|
||||
}
|
||||
|
||||
func (ctx *SimpleVarStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
|
||||
return
|
||||
}
|
||||
|
@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
// double(x): returns 2*x
|
||||
double=func(x){2*x};
|
||||
@double=func(x){2*x};
|
||||
|
||||
// Define variable 'a' wth value 5
|
||||
a=5;
|
||||
@a=5;
|
||||
|
||||
// two(): returns 2
|
||||
two=func() {2};
|
||||
@two=func() {2};
|
||||
|
Loading…
Reference in New Issue
Block a user