Since now builtin functions are registared in a new global context. This reduces the effort to copy the whole set of builtin functions in the context of a function call; only the called function will be copied, if it is global.
This commit is contained in:
parent
0a9543543d
commit
50e7168214
@ -65,10 +65,11 @@ func TestFuncs(t *testing.T) {
|
|||||||
/* 52 */ {`isFract(1|3)`, true, nil},
|
/* 52 */ {`isFract(1|3)`, true, nil},
|
||||||
/* 53 */ {`isFract(3|1)`, false, nil},
|
/* 53 */ {`isFract(3|1)`, false, nil},
|
||||||
/* 54 */ {`isRational(3|1)`, true, nil},
|
/* 54 */ {`isRational(3|1)`, true, nil},
|
||||||
|
/* 55 */ {`builtin "math.arith"; add(1,2)`, int64(3), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("EXPR_PATH", ".")
|
t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// parserTest(t, "Func", inputs[25:26])
|
//parserTest(t, "Func", inputs[54:55])
|
||||||
parserTest(t, "Func", inputs)
|
parserTest(t, "Func", inputs)
|
||||||
}
|
}
|
||||||
|
54
global-context.go
Normal file
54
global-context.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// global-context.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import "path/filepath"
|
||||||
|
|
||||||
|
var globalCtx *SimpleFuncStore
|
||||||
|
|
||||||
|
func ImportInContext(name string) (exists bool) {
|
||||||
|
var mod *module
|
||||||
|
if mod, exists = moduleRegister[name]; exists {
|
||||||
|
mod.importFunc(globalCtx)
|
||||||
|
mod.imported = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportInContextByGlobPattern(pattern string) (count int, err error) {
|
||||||
|
var matched bool
|
||||||
|
for name, mod := range moduleRegister {
|
||||||
|
if matched, err = filepath.Match(pattern, name); err == nil {
|
||||||
|
if matched {
|
||||||
|
count++
|
||||||
|
mod.importFunc(globalCtx)
|
||||||
|
mod.imported = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVar(ctx ExprContext, name string) (value any, exists bool) {
|
||||||
|
if value, exists = ctx.GetVar(name); !exists {
|
||||||
|
value, exists = globalCtx.GetVar(name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool, ownerCtx ExprContext) {
|
||||||
|
if item, exists = ctx.GetFuncInfo(name); exists {
|
||||||
|
ownerCtx = ctx
|
||||||
|
} else if item, exists = globalCtx.GetFuncInfo(name); exists {
|
||||||
|
ownerCtx = globalCtx
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
globalCtx = NewSimpleFuncStore()
|
||||||
|
}
|
@ -6,7 +6,6 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type module struct {
|
type module struct {
|
||||||
@ -31,30 +30,30 @@ func registerImport(name string, importFunc func(ExprContext), description strin
|
|||||||
moduleRegister[name] = newModule(importFunc, description)
|
moduleRegister[name] = newModule(importFunc, description)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportInContext(ctx ExprContext, name string) (exists bool) {
|
// func ImportInContext(ctx ExprContext, name string) (exists bool) {
|
||||||
var mod *module
|
// var mod *module
|
||||||
if mod, exists = moduleRegister[name]; exists {
|
// if mod, exists = moduleRegister[name]; exists {
|
||||||
mod.importFunc(ctx)
|
// mod.importFunc(ctx)
|
||||||
mod.imported = true
|
// mod.imported = true
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
func ImportInContextByGlobPattern(ctx ExprContext, pattern string) (count int, err error) {
|
// func ImportInContextByGlobPattern(ctx ExprContext, pattern string) (count int, err error) {
|
||||||
var matched bool
|
// var matched bool
|
||||||
for name, mod := range moduleRegister {
|
// for name, mod := range moduleRegister {
|
||||||
if matched, err = filepath.Match(pattern, name); err == nil {
|
// if matched, err = filepath.Match(pattern, name); err == nil {
|
||||||
if matched {
|
// if matched {
|
||||||
count++
|
// count++
|
||||||
mod.importFunc(ctx)
|
// mod.importFunc(ctx)
|
||||||
mod.imported = true
|
// mod.imported = true
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
func IterateModules(op func(name, description string, imported bool) bool) {
|
func IterateModules(op func(name, description string, imported bool) bool) {
|
||||||
if op != nil {
|
if op != nil {
|
||||||
|
@ -23,7 +23,7 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
|
|||||||
|
|
||||||
// -------- eval func call
|
// -------- eval func call
|
||||||
func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
|
func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
|
||||||
if info, exists := ctx.GetFuncInfo(name); exists {
|
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
||||||
if info.MinArgs() > len(params) {
|
if info.MinArgs() > len(params) {
|
||||||
if info.MaxArgs() < 0 {
|
if info.MaxArgs() < 0 {
|
||||||
err = fmt.Errorf("too few params -- expected %d or more, got %d", info.MinArgs(), len(params))
|
err = fmt.Errorf("too few params -- expected %d or more, got %d", info.MinArgs(), len(params))
|
||||||
@ -31,9 +31,12 @@ func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
|
|||||||
err = fmt.Errorf("too few params -- expected %d, got %d", info.MinArgs(), len(params))
|
err = fmt.Errorf("too few params -- expected %d, got %d", info.MinArgs(), len(params))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if info.MaxArgs() >= 0 && info.MaxArgs() < len(params) {
|
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(params) {
|
||||||
err = fmt.Errorf("too much params -- expected %d, got %d", info.MaxArgs(), len(params))
|
err = fmt.Errorf("too much params -- expected %d, got %d", info.MaxArgs(), len(params))
|
||||||
}
|
}
|
||||||
|
if err == nil && owner != ctx {
|
||||||
|
ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("unknown function %s()", name)
|
err = fmt.Errorf("unknown function %s()", name)
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ func newVarTerm(tk *Token) *term {
|
|||||||
func evalVar(ctx ExprContext, self *term) (v any, err error) {
|
func evalVar(ctx ExprContext, self *term) (v any, err error) {
|
||||||
var exists bool
|
var exists bool
|
||||||
name := self.source()
|
name := self.source()
|
||||||
if v, exists = ctx.GetVar(name); !exists {
|
if v, exists = GetVar(ctx, name); !exists {
|
||||||
if info, exists := ctx.GetFuncInfo(name); exists {
|
if info, exists, _ := GetFuncInfo(ctx, name); exists {
|
||||||
v = info.Functor()
|
v = info.Functor()
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("undefined variable or function %q", name)
|
err = fmt.Errorf("undefined variable or function %q", name)
|
||||||
|
@ -28,13 +28,13 @@ func evalBuiltin(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
count := 0
|
count := 0
|
||||||
if IsString(childValue) {
|
if IsString(childValue) {
|
||||||
module, _ := childValue.(string)
|
module, _ := childValue.(string)
|
||||||
count, err = ImportInContextByGlobPattern(ctx, module)
|
count, err = ImportInContextByGlobPattern(module)
|
||||||
} else {
|
} else {
|
||||||
var moduleSpec any
|
var moduleSpec any
|
||||||
it := NewAnyIterator(childValue)
|
it := NewAnyIterator(childValue)
|
||||||
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
|
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
|
||||||
if module, ok := moduleSpec.(string); ok {
|
if module, ok := moduleSpec.(string); ok {
|
||||||
if ImportInContext(ctx, module) {
|
if ImportInContext(module) {
|
||||||
count++
|
count++
|
||||||
} else {
|
} else {
|
||||||
err = self.Errorf("unknown module %q", module)
|
err = self.Errorf("unknown module %q", module)
|
||||||
|
Loading…
Reference in New Issue
Block a user