Variable reference

This commit is contained in:
Celestino Amoroso 2024-04-06 01:00:29 +02:00
parent 574a6f5215
commit 0ba96e65a5
7 changed files with 60 additions and 25 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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)

View File

@ -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
}

View File

@ -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};