Variable reference
This commit is contained in:
parent
574a6f5215
commit
0ba96e65a5
@ -25,6 +25,7 @@ type exprFunc interface {
|
|||||||
Name() string
|
Name() string
|
||||||
MinArgs() int
|
MinArgs() int
|
||||||
MaxArgs() int
|
MaxArgs() int
|
||||||
|
Functor() Functor
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----Expression Context
|
// ----Expression Context
|
||||||
@ -33,6 +34,7 @@ type exprContext interface {
|
|||||||
GetVar(varName string) (value any, exists bool)
|
GetVar(varName string) (value any, exists bool)
|
||||||
SetVar(varName string, value any)
|
SetVar(varName string, value any)
|
||||||
EnumVars(func(name string) (accept bool)) (varNames []string)
|
EnumVars(func(name string) (accept bool)) (varNames []string)
|
||||||
|
EnumFuncs(func(name string) (accept bool)) (funcNames []string)
|
||||||
GetFuncInfo(name string) exprFunc
|
GetFuncInfo(name string) exprFunc
|
||||||
Call(name string, args []any) (result any, err error)
|
Call(name string, args []any) (result any, err error)
|
||||||
RegisterFunc(name string, f Functor, minArgs, maxArgs int)
|
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
|
var expr *ast
|
||||||
scanner := NewScanner(file, DefaultTranslations())
|
scanner := NewScanner(file, DefaultTranslations())
|
||||||
parser := NewParser(ctx)
|
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)
|
_, err = expr.Eval(ctx, false)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil && err == io.EOF {
|
if err != nil && err == io.EOF {
|
||||||
|
@ -36,10 +36,17 @@ func evalFuncCall(parentCtx exprContext, self *term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if v, err = ctx.Call(name, params); 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] == '@' }) {
|
for _, refName := range ctx.EnumVars(func(name string) bool { return name[0] == '@' }) {
|
||||||
refValue, _ := ctx.GetVar(refName)
|
refValue, _ := ctx.GetVar(refName)
|
||||||
parentCtx.SetVar(refName[1:], refValue)
|
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
|
return
|
||||||
|
@ -139,11 +139,11 @@ func TestParser(t *testing.T) {
|
|||||||
/* 118 */ {`x="hello"; x ?= "default"; x`, "hello", nil},
|
/* 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"`)},
|
/* 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(){@x="hello"}; f(); x`, "hello", nil},
|
||||||
/* 120 */ {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil},
|
/* 121 */ {`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}; @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}; @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},
|
/* 124 */ {`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"`)},
|
/* 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
|
check_env_expr_path := 113
|
||||||
|
|
||||||
@ -151,6 +151,7 @@ func TestParser(t *testing.T) {
|
|||||||
failed := 0
|
failed := 0
|
||||||
|
|
||||||
// inputs1 := []inputType{
|
// 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},
|
// {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil},
|
||||||
// {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
// {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
||||||
// {`add(1,2,3)`, int64(6), nil},
|
// {`add(1,2,3)`, int64(6), nil},
|
||||||
@ -188,7 +189,7 @@ func TestParser(t *testing.T) {
|
|||||||
|
|
||||||
if gotErr != input.wantErr {
|
if gotErr != input.wantErr {
|
||||||
if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) {
|
if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) {
|
||||||
t.Errorf("%d: %q -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr)
|
t.Errorf("%d: %q -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr)
|
||||||
good = false
|
good = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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))
|
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 {
|
type inputType struct {
|
||||||
source string
|
source string
|
||||||
wantResult any
|
wantResult any
|
||||||
@ -261,7 +262,6 @@ func NoTestListParser(t *testing.T) {
|
|||||||
good = false
|
good = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// if good {}
|
|
||||||
if gotList, okGot := gotResult.([]any); okGot {
|
if gotList, okGot := gotResult.([]any); okGot {
|
||||||
if wantList, okWant := input.wantResult.([]any); okWant {
|
if wantList, okWant := input.wantResult.([]any); okWant {
|
||||||
if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) {
|
if (gotList == nil && wantList != nil) || (gotList != nil && wantList == nil) {
|
||||||
|
@ -5,13 +5,14 @@ import "fmt"
|
|||||||
|
|
||||||
type SimpleFuncStore struct {
|
type SimpleFuncStore struct {
|
||||||
varStore map[string]any
|
varStore map[string]any
|
||||||
funcStore map[string]Functor
|
funcStore map[string]*funcInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type funcInfo struct {
|
type funcInfo struct {
|
||||||
name string
|
name string
|
||||||
// minArgs int
|
minArgs int
|
||||||
// maxArgs int
|
maxArgs int
|
||||||
|
functor Functor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *funcInfo) Name() string {
|
func (info *funcInfo) Name() string {
|
||||||
@ -19,17 +20,21 @@ func (info *funcInfo) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (info *funcInfo) MinArgs() int {
|
func (info *funcInfo) MinArgs() int {
|
||||||
return 0
|
return info.minArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *funcInfo) MaxArgs() int {
|
func (info *funcInfo) MaxArgs() int {
|
||||||
return -1
|
return info.maxArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (info *funcInfo) Functor() Functor {
|
||||||
|
return info.functor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSimpleFuncStore() *SimpleFuncStore {
|
func NewSimpleFuncStore() *SimpleFuncStore {
|
||||||
return &SimpleFuncStore{
|
return &SimpleFuncStore{
|
||||||
varStore: make(map[string]any),
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (f exprFunc) {
|
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (info exprFunc) {
|
||||||
var exists bool
|
info, _ = ctx.funcStore[name]
|
||||||
if _, exists = ctx.funcStore[name]; exists {
|
|
||||||
f = &funcInfo{name: name}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleFuncStore) RegisterFunc(name string, functor Functor, minArgs, maxArgs int) {
|
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) {
|
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)
|
result, err = functor.Invoke(ctx, name, args)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("unknown function %s()", name)
|
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) 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(x): returns 2*x
|
||||||
double=func(x){2*x};
|
@double=func(x){2*x};
|
||||||
|
|
||||||
// Define variable 'a' wth value 5
|
// Define variable 'a' wth value 5
|
||||||
a=5;
|
@a=5;
|
||||||
|
|
||||||
// two(): returns 2
|
// two(): returns 2
|
||||||
two=func() {2};
|
@two=func() {2};
|
||||||
|
Loading…
Reference in New Issue
Block a user