function definition and usage rationalized
This commit is contained in:
parent
d545a35acf
commit
e5f63c3d9d
@ -7,7 +7,7 @@ package expr
|
||||
const (
|
||||
typeAny = "any"
|
||||
typeBoolean = "boolean"
|
||||
typeFloat = "decimal"
|
||||
typeFloat = "float"
|
||||
typeFraction = "fraction"
|
||||
typeHandle = "handle"
|
||||
typeInt = "integer"
|
||||
|
@ -24,7 +24,7 @@ func exportFunc(ctx ExprContext, name string, info ExprFunc) {
|
||||
}
|
||||
// ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
|
||||
// ctx.RegisterFuncInfo(name, info)
|
||||
ctx.RegisterFunc2(name, info.Functor(), info.ReturnType(), info.Params())
|
||||
ctx.RegisterFunc(name, info.Functor(), info.ReturnType(), info.Params())
|
||||
}
|
||||
|
||||
func exportObjects(destCtx, sourceCtx ExprContext) {
|
||||
|
24
context.go
24
context.go
@ -4,28 +4,11 @@
|
||||
// context.go
|
||||
package expr
|
||||
|
||||
// ---- Function template
|
||||
type FuncTemplate func(ctx ExprContext, name string, args []any) (result any, err error)
|
||||
|
||||
// ---- Functor interface
|
||||
type Functor interface {
|
||||
Invoke(ctx ExprContext, name string, args []any) (result any, err error)
|
||||
}
|
||||
|
||||
type simpleFunctor struct {
|
||||
f FuncTemplate
|
||||
}
|
||||
|
||||
func newSimpleFunctor(f FuncTemplate) *simpleFunctor {
|
||||
return &simpleFunctor{f: f}
|
||||
}
|
||||
|
||||
func (functor *simpleFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
return functor.f(ctx, name, args)
|
||||
}
|
||||
|
||||
func (functor *simpleFunctor) ToString(opt FmtOpt) string {
|
||||
return "func() {<body>}"
|
||||
SetFunc(info ExprFunc)
|
||||
GetFunc() ExprFunc
|
||||
}
|
||||
|
||||
// ---- Function Param Info
|
||||
@ -39,6 +22,7 @@ type ExprFuncParam interface {
|
||||
|
||||
// ---- Function Info
|
||||
type ExprFunc interface {
|
||||
Formatter
|
||||
Name() string
|
||||
MinArgs() int
|
||||
MaxArgs() int
|
||||
@ -59,5 +43,5 @@ type ExprContext interface {
|
||||
Call(name string, args []any) (result any, err error)
|
||||
// RegisterFunc(name string, f Functor, minArgs, maxArgs int)
|
||||
RegisterFuncInfo(info ExprFunc)
|
||||
RegisterFunc2(name string, f Functor, returnType string, param []ExprFuncParam) error
|
||||
RegisterFunc(name string, f Functor, returnType string, param []ExprFuncParam) error
|
||||
}
|
||||
|
60
func-base.go
60
func-base.go
@ -54,6 +54,24 @@ func isDictionaryFunc(ctx ExprContext, name string, args []any) (result any, err
|
||||
return
|
||||
}
|
||||
|
||||
func boolFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
result = (v != 0)
|
||||
case *fraction:
|
||||
result = v.num != 0
|
||||
case float64:
|
||||
result = v != 0.0
|
||||
case bool:
|
||||
result = v
|
||||
case string:
|
||||
result = len(v) > 0
|
||||
default:
|
||||
err = errCantConvert(name, v, "bool")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
@ -144,34 +162,20 @@ func ImportBuiltinsFuncs(ctx ExprContext) {
|
||||
newFuncParam(paramValue),
|
||||
}
|
||||
|
||||
// ctx.RegisterFunc("isNil", &simpleFunctor{f: isNilFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isNil", newSimpleFunctor(isNilFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isInt", &simpleFunctor{f: isIntFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isInt", newSimpleFunctor(isIntFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isFloat", &simpleFunctor{f: isFloatFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isFloat", newSimpleFunctor(isFloatFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isBool", &simpleFunctor{f: isBoolFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isBool", newSimpleFunctor(isBoolFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isString", &simpleFunctor{f: isStringFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isString", newSimpleFunctor(isStringFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isFraction", &simpleFunctor{f: isFractionFunc}, 1, 1)
|
||||
//ctx.RegisterFunc2("isFraction", &simpleFunctor{f: isFractionFunc}, typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isFract", &simpleFunctor{f: isFractionFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isFract", newSimpleFunctor(isFractionFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isRational", &simpleFunctor{f: isRationalFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isRational", newSimpleFunctor(isRationalFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isList", &simpleFunctor{f: isListFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isList", newSimpleFunctor(isListFunc), typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isDictionary", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
|
||||
//ctx.RegisterFunc2("isDictionary", &simpleFunctor{f: isDictionaryFunc}, typeBoolean, anyParams)
|
||||
// ctx.RegisterFunc("isDict", &simpleFunctor{f: isDictionaryFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("isDict", newSimpleFunctor(isDictionaryFunc), typeBoolean, anyParams)
|
||||
//ctx.RegisterFunc("int", &simpleFunctor{f: intFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("int", newSimpleFunctor(intFunc), typeInt, anyParams)
|
||||
// ctx.RegisterFunc("dec", &simpleFunctor{f: decFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("dec", newSimpleFunctor(decFunc), typeFloat, anyParams)
|
||||
// ctx.RegisterFunc("fract", &simpleFunctor{f: fractFunc}, 1, 2)
|
||||
ctx.RegisterFunc2("fract", newSimpleFunctor(fractFunc), typeFraction, []ExprFuncParam{
|
||||
ctx.RegisterFunc("isNil", newGolangFunctor(isNilFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isInt", newGolangFunctor(isIntFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isFloat", newGolangFunctor(isFloatFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isBool", newGolangFunctor(isBoolFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isString", newGolangFunctor(isStringFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isFract", newGolangFunctor(isFractionFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isRational", newGolangFunctor(isRationalFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isList", newGolangFunctor(isListFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("isDict", newGolangFunctor(isDictionaryFunc), typeBoolean, anyParams)
|
||||
|
||||
ctx.RegisterFunc("bool", newGolangFunctor(boolFunc), typeBoolean, anyParams)
|
||||
ctx.RegisterFunc("int", newGolangFunctor(intFunc), typeInt, anyParams)
|
||||
ctx.RegisterFunc("dec", newGolangFunctor(decFunc), typeFloat, anyParams)
|
||||
ctx.RegisterFunc("fract", newGolangFunctor(fractFunc), typeFraction, []ExprFuncParam{
|
||||
newFuncParam(paramValue),
|
||||
newFuncParamFlagDef("denominator", pfOptional, 1),
|
||||
})
|
||||
|
@ -137,12 +137,10 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
|
||||
}
|
||||
|
||||
func ImportImportFuncs(ctx ExprContext) {
|
||||
// ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
||||
ctx.RegisterFunc2("import", newSimpleFunctor(importFunc), typeAny, []ExprFuncParam{
|
||||
ctx.RegisterFunc("import", newGolangFunctor(importFunc), typeAny, []ExprFuncParam{
|
||||
newFuncParamFlag(typeFilepath, pfRepeat),
|
||||
})
|
||||
//ctx.RegisterFunc("importAll", &simpleFunctor{f: importAllFunc}, 1, -1)
|
||||
ctx.RegisterFunc2("importAll", newSimpleFunctor(importAllFunc), typeAny, []ExprFuncParam{
|
||||
ctx.RegisterFunc("importAll", newGolangFunctor(importAllFunc), typeAny, []ExprFuncParam{
|
||||
newFuncParamFlag(typeFilepath, pfRepeat),
|
||||
})
|
||||
}
|
||||
|
@ -167,13 +167,11 @@ func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
}
|
||||
|
||||
func ImportMathFuncs(ctx ExprContext) {
|
||||
//ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1)
|
||||
ctx.RegisterFunc2("add", &simpleFunctor{f: addFunc}, typeNumber, []ExprFuncParam{
|
||||
ctx.RegisterFunc("add", &golangFunctor{f: addFunc}, typeNumber, []ExprFuncParam{
|
||||
newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 0),
|
||||
})
|
||||
|
||||
// ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1)
|
||||
ctx.RegisterFunc2("mul", &simpleFunctor{f: mulFunc}, typeNumber, []ExprFuncParam{
|
||||
ctx.RegisterFunc("mul", &golangFunctor{f: mulFunc}, typeNumber, []ExprFuncParam{
|
||||
newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 1),
|
||||
})
|
||||
}
|
||||
|
18
func-os.go
18
func-os.go
@ -158,30 +158,24 @@ func readFileFunc(ctx ExprContext, name string, args []any) (result any, err err
|
||||
}
|
||||
|
||||
func ImportOsFuncs(ctx ExprContext) {
|
||||
// ctx.RegisterFunc("openFile", &simpleFunctor{f: openFileFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("openFile", newSimpleFunctor(openFileFunc), typeHandle, []ExprFuncParam{
|
||||
ctx.RegisterFunc("openFile", newGolangFunctor(openFileFunc), typeHandle, []ExprFuncParam{
|
||||
newFuncParam(typeFilepath),
|
||||
})
|
||||
// ctx.RegisterFunc("appendFile", &simpleFunctor{f: appendFileFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("appendFile", newSimpleFunctor(appendFileFunc), typeHandle, []ExprFuncParam{
|
||||
ctx.RegisterFunc("appendFile", newGolangFunctor(appendFileFunc), typeHandle, []ExprFuncParam{
|
||||
newFuncParam(typeFilepath),
|
||||
})
|
||||
// ctx.RegisterFunc("createFile", &simpleFunctor{f: createFileFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("createFile", newSimpleFunctor(createFileFunc), typeHandle, []ExprFuncParam{
|
||||
ctx.RegisterFunc("createFile", newGolangFunctor(createFileFunc), typeHandle, []ExprFuncParam{
|
||||
newFuncParam(typeFilepath),
|
||||
})
|
||||
// ctx.RegisterFunc("writeFile", &simpleFunctor{f: writeFileFunc}, 1, -1)
|
||||
ctx.RegisterFunc2("writeFile", newSimpleFunctor(writeFileFunc), typeInt, []ExprFuncParam{
|
||||
ctx.RegisterFunc("writeFile", newGolangFunctor(writeFileFunc), typeInt, []ExprFuncParam{
|
||||
newFuncParam(typeHandle),
|
||||
newFuncParamFlagDef(typeItem, pfOptional|pfRepeat, ""),
|
||||
})
|
||||
// ctx.RegisterFunc("readFile", &simpleFunctor{f: readFileFunc}, 1, 2)
|
||||
ctx.RegisterFunc2("readFile", newSimpleFunctor(readFileFunc), typeString, []ExprFuncParam{
|
||||
ctx.RegisterFunc("readFile", newGolangFunctor(readFileFunc), typeString, []ExprFuncParam{
|
||||
newFuncParam(typeHandle),
|
||||
newFuncParamFlagDef("limitCh", pfOptional, "\\n"),
|
||||
})
|
||||
//ctx.RegisterFunc("closeFile", &simpleFunctor{f: closeFileFunc}, 1, 1)
|
||||
ctx.RegisterFunc2("closeFile", newSimpleFunctor(closeFileFunc), typeBoolean, []ExprFuncParam{
|
||||
ctx.RegisterFunc("closeFile", newGolangFunctor(closeFileFunc), typeBoolean, []ExprFuncParam{
|
||||
newFuncParam(typeHandle),
|
||||
})
|
||||
}
|
||||
|
@ -183,33 +183,33 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
|
||||
|
||||
// Import above functions in the context
|
||||
func ImportStringFuncs(ctx ExprContext) {
|
||||
ctx.RegisterFunc2("joinStr", newSimpleFunctor(joinStrFunc), typeString, []ExprFuncParam{
|
||||
ctx.RegisterFunc("joinStr", newGolangFunctor(joinStrFunc), typeString, []ExprFuncParam{
|
||||
newFuncParam(paramSeparator),
|
||||
newFuncParamFlagDef(paramItem, pfOptional|pfRepeat, ""),
|
||||
})
|
||||
|
||||
ctx.RegisterFunc2("subStr", newSimpleFunctor(subStrFunc), typeString, []ExprFuncParam{
|
||||
ctx.RegisterFunc("subStr", newGolangFunctor(subStrFunc), typeString, []ExprFuncParam{
|
||||
newFuncParam(paramSource),
|
||||
newFuncParamFlagDef(paramStart, pfOptional, 0),
|
||||
newFuncParamFlagDef(paramCount, pfOptional, -1),
|
||||
})
|
||||
|
||||
ctx.RegisterFunc2("splitStr", newSimpleFunctor(splitStrFunc), "list of "+typeString, []ExprFuncParam{
|
||||
ctx.RegisterFunc("splitStr", newGolangFunctor(splitStrFunc), "list of "+typeString, []ExprFuncParam{
|
||||
newFuncParam(paramSource),
|
||||
newFuncParamFlagDef(paramSeparator, pfOptional, ""),
|
||||
newFuncParamFlagDef(paramCount, pfOptional, -1),
|
||||
})
|
||||
|
||||
ctx.RegisterFunc2("trimStr", newSimpleFunctor(trimStrFunc), typeString, []ExprFuncParam{
|
||||
ctx.RegisterFunc("trimStr", newGolangFunctor(trimStrFunc), typeString, []ExprFuncParam{
|
||||
newFuncParam(paramSource),
|
||||
})
|
||||
|
||||
ctx.RegisterFunc2("startsWithStr", newSimpleFunctor(startsWithStrFunc), typeBoolean, []ExprFuncParam{
|
||||
ctx.RegisterFunc("startsWithStr", newGolangFunctor(startsWithStrFunc), typeBoolean, []ExprFuncParam{
|
||||
newFuncParam(paramSource),
|
||||
newFuncParamFlag(paramPrefix, pfRepeat),
|
||||
})
|
||||
|
||||
ctx.RegisterFunc2("endsWithStr", newSimpleFunctor(endsWithStrFunc), typeBoolean, []ExprFuncParam{
|
||||
ctx.RegisterFunc("endsWithStr", newGolangFunctor(endsWithStrFunc), typeBoolean, []ExprFuncParam{
|
||||
newFuncParam(paramSource),
|
||||
newFuncParamFlag(paramSuffix, pfRepeat),
|
||||
})
|
||||
|
232
function.go
Normal file
232
function.go
Normal file
@ -0,0 +1,232 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// function.go
|
||||
package expr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ---- Function template
|
||||
type FuncTemplate func(ctx ExprContext, name string, args []any) (result any, err error)
|
||||
|
||||
// ---- Common functor definition
|
||||
type baseFunctor struct {
|
||||
info ExprFunc
|
||||
}
|
||||
|
||||
func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
|
||||
if functor.info != nil {
|
||||
s = functor.info.ToString(opt)
|
||||
} else {
|
||||
s = "func() {<body>}"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (functor *baseFunctor) SetFunc(info ExprFunc) {
|
||||
functor.info = info
|
||||
}
|
||||
|
||||
func (functor *baseFunctor) GetFunc() ExprFunc {
|
||||
return functor.info
|
||||
}
|
||||
|
||||
// ---- Linking with the functions of Go
|
||||
type golangFunctor struct {
|
||||
baseFunctor
|
||||
f FuncTemplate
|
||||
}
|
||||
|
||||
func newGolangFunctor(f FuncTemplate) *golangFunctor {
|
||||
return &golangFunctor{f: f}
|
||||
}
|
||||
|
||||
func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
return functor.f(ctx, name, args)
|
||||
}
|
||||
|
||||
// ---- Linking with the functions of Expr
|
||||
type exprFunctor struct {
|
||||
baseFunctor
|
||||
params []string
|
||||
expr Expr
|
||||
}
|
||||
|
||||
func newExprFunctor(e Expr, params []string) *exprFunctor {
|
||||
return &exprFunctor{expr: e, params: params}
|
||||
}
|
||||
|
||||
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
for i, p := range functor.params {
|
||||
if i < len(args) {
|
||||
arg := args[i]
|
||||
if funcArg, ok := arg.(Functor); ok {
|
||||
// ctx.RegisterFunc(p, functor, 0, -1)
|
||||
ctx.RegisterFunc(p, funcArg, typeAny, []ExprFuncParam{
|
||||
newFuncParam(paramValue),
|
||||
})
|
||||
} else {
|
||||
ctx.UnsafeSetVar(p, arg)
|
||||
}
|
||||
} else {
|
||||
ctx.UnsafeSetVar(p, nil)
|
||||
}
|
||||
}
|
||||
result, err = functor.expr.eval(ctx, false)
|
||||
return
|
||||
}
|
||||
|
||||
// ---- Function Parameters
|
||||
type paramFlags uint16
|
||||
|
||||
const (
|
||||
pfOptional paramFlags = 1 << iota
|
||||
pfRepeat
|
||||
)
|
||||
|
||||
type funcParamInfo struct {
|
||||
name string
|
||||
flags paramFlags
|
||||
defaultValue any
|
||||
}
|
||||
|
||||
func newFuncParam(name string) ExprFuncParam {
|
||||
return &funcParamInfo{name: name}
|
||||
}
|
||||
|
||||
func newFuncParamFlag(name string, flags paramFlags) ExprFuncParam {
|
||||
return &funcParamInfo{name: name, flags: flags}
|
||||
}
|
||||
|
||||
func newFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo {
|
||||
return &funcParamInfo{name: name, flags: flags, defaultValue: defValue}
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) Name() string {
|
||||
return param.name
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) Type() string {
|
||||
return "any"
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) IsOptional() bool {
|
||||
return (param.flags & pfOptional) != 0
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) IsRepeat() bool {
|
||||
return (param.flags & pfRepeat) != 0
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) DefaultValue() any {
|
||||
return param.defaultValue
|
||||
}
|
||||
|
||||
// --- Functions
|
||||
type funcInfo struct {
|
||||
name string
|
||||
minArgs int
|
||||
maxArgs int
|
||||
functor Functor
|
||||
params []ExprFuncParam
|
||||
returnType string
|
||||
}
|
||||
|
||||
func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
|
||||
var minArgs = 0
|
||||
var maxArgs = 0
|
||||
if params != nil {
|
||||
for _, p := range params {
|
||||
if maxArgs == -1 {
|
||||
return nil, fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name())
|
||||
}
|
||||
if p.IsOptional() {
|
||||
maxArgs++
|
||||
} else if maxArgs == minArgs {
|
||||
minArgs++
|
||||
maxArgs++
|
||||
} else {
|
||||
return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
|
||||
}
|
||||
if p.IsRepeat() {
|
||||
maxArgs = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
info = &funcInfo{
|
||||
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params,
|
||||
}
|
||||
functor.SetFunc(info)
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
|
||||
return newFuncInfo("unnamed", functor, returnType, params)
|
||||
}
|
||||
|
||||
func (info *funcInfo) Params() []ExprFuncParam {
|
||||
return info.params
|
||||
}
|
||||
|
||||
func (info *funcInfo) ReturnType() string {
|
||||
return info.returnType
|
||||
}
|
||||
|
||||
func (info *funcInfo) ToString(opt FmtOpt) string {
|
||||
var sb strings.Builder
|
||||
if len(info.Name()) == 0 {
|
||||
sb.WriteString("func")
|
||||
} else {
|
||||
sb.WriteString(info.Name())
|
||||
}
|
||||
sb.WriteByte('(')
|
||||
if info.params != nil {
|
||||
for i, p := range info.params {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(p.Name())
|
||||
|
||||
if p.IsOptional() {
|
||||
sb.WriteByte('=')
|
||||
if s, ok := p.DefaultValue().(string); ok {
|
||||
sb.WriteByte('"')
|
||||
sb.WriteString(s)
|
||||
sb.WriteByte('"')
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%v", p.DefaultValue()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if info.maxArgs < 0 {
|
||||
sb.WriteString(" ...")
|
||||
}
|
||||
sb.WriteString("): ")
|
||||
if len(info.returnType) > 0 {
|
||||
sb.WriteString(info.returnType)
|
||||
} else {
|
||||
sb.WriteString(typeAny)
|
||||
}
|
||||
sb.WriteString(" {<body>}")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (info *funcInfo) Name() string {
|
||||
return info.name
|
||||
}
|
||||
|
||||
func (info *funcInfo) MinArgs() int {
|
||||
return info.minArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) MaxArgs() int {
|
||||
return info.maxArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) Functor() Functor {
|
||||
return info.functor
|
||||
}
|
@ -38,9 +38,9 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
|
||||
for _, arg := range args {
|
||||
if isFunc(arg.Value) {
|
||||
if f, ok := arg.Value.(FuncTemplate); ok {
|
||||
functor := newSimpleFunctor(f)
|
||||
functor := newGolangFunctor(f)
|
||||
// ctx.RegisterFunc(arg.Name, functor, 0, -1)
|
||||
ctx.RegisterFunc2(arg.Name, functor, typeAny, []ExprFuncParam{
|
||||
ctx.RegisterFunc(arg.Name, functor, typeAny, []ExprFuncParam{
|
||||
newFuncParamFlagDef(paramValue, pfOptional|pfRepeat, 0),
|
||||
})
|
||||
} else {
|
||||
|
@ -76,30 +76,30 @@ func newFuncDefTerm(tk *Token, args []*term) *term {
|
||||
|
||||
// -------- eval func def
|
||||
// TODO
|
||||
type funcDefFunctor struct {
|
||||
params []string
|
||||
expr Expr
|
||||
}
|
||||
// type funcDefFunctor struct {
|
||||
// params []string
|
||||
// expr Expr
|
||||
// }
|
||||
|
||||
func (funcDef *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
for i, p := range funcDef.params {
|
||||
if i < len(args) {
|
||||
arg := args[i]
|
||||
if functor, ok := arg.(Functor); ok {
|
||||
// ctx.RegisterFunc(p, functor, 0, -1)
|
||||
ctx.RegisterFunc2(p, functor, typeAny, []ExprFuncParam{
|
||||
newFuncParam(paramValue),
|
||||
})
|
||||
} else {
|
||||
ctx.UnsafeSetVar(p, arg)
|
||||
}
|
||||
} else {
|
||||
ctx.UnsafeSetVar(p, nil)
|
||||
}
|
||||
}
|
||||
result, err = funcDef.expr.eval(ctx, false)
|
||||
return
|
||||
}
|
||||
// func (funcDef *funcDefFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
// for i, p := range funcDef.params {
|
||||
// if i < len(args) {
|
||||
// arg := args[i]
|
||||
// if functor, ok := arg.(Functor); ok {
|
||||
// // ctx.RegisterFunc(p, functor, 0, -1)
|
||||
// ctx.RegisterFunc2(p, functor, typeAny, []ExprFuncParam{
|
||||
// newFuncParam(paramValue),
|
||||
// })
|
||||
// } else {
|
||||
// ctx.UnsafeSetVar(p, arg)
|
||||
// }
|
||||
// } else {
|
||||
// ctx.UnsafeSetVar(p, nil)
|
||||
// }
|
||||
// }
|
||||
// result, err = funcDef.expr.eval(ctx, false)
|
||||
// return
|
||||
// }
|
||||
|
||||
func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
|
||||
bodySpec := self.value()
|
||||
@ -108,10 +108,11 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
|
||||
for _, param := range self.children {
|
||||
paramList = append(paramList, param.source())
|
||||
}
|
||||
v = &funcDefFunctor{
|
||||
params: paramList,
|
||||
expr: expr,
|
||||
}
|
||||
v = newExprFunctor(expr, paramList)
|
||||
// v = &funcDefFunctor{
|
||||
// params: paramList,
|
||||
// expr: expr,
|
||||
// }
|
||||
} else {
|
||||
err = errors.New("invalid function definition: the body specification must be an expression")
|
||||
}
|
||||
|
@ -74,7 +74,8 @@ func getDataSourceDict(ctx ExprContext, self *term, firstChildValue any) (ds map
|
||||
ds = make(map[string]Functor)
|
||||
for keyAny, item := range *dictAny {
|
||||
if key, ok := keyAny.(string); ok {
|
||||
if functor, ok := item.(*funcDefFunctor); ok {
|
||||
//if functor, ok := item.(*funcDefFunctor); ok {
|
||||
if functor, ok := item.(Functor); ok {
|
||||
ds[key] = functor
|
||||
if index := slices.Index(requiredFields, key); index >= 0 {
|
||||
foundFields |= 1 << index
|
||||
|
@ -34,14 +34,15 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) {
|
||||
funcName := rightChild.source()
|
||||
if info, exists, _ := GetFuncInfo(ctx, funcName); exists {
|
||||
// ctx.RegisterFuncInfo(info)
|
||||
ctx.RegisterFunc2(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
|
||||
} else if funcDef, ok := functor.(*funcDefFunctor); ok {
|
||||
paramCount := len(funcDef.params)
|
||||
paramSpecs := make([]ExprFuncParam, paramCount)
|
||||
for i := range paramSpecs {
|
||||
paramSpecs[i] = newFuncParam(funcDef.params[i])
|
||||
}
|
||||
ctx.RegisterFunc2(leftTerm.source(), functor, typeAny, paramSpecs)
|
||||
ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params())
|
||||
} else if funcDef, ok := functor.(*exprFunctor); ok {
|
||||
paramSpecs := ForAll(funcDef.params, newFuncParam)
|
||||
// paramCount := len(funcDef.params)
|
||||
// paramSpecs := make([]ExprFuncParam, paramCount)
|
||||
// for i := range paramSpecs {
|
||||
// paramSpecs[i] = newFuncParam(funcDef.params[i])
|
||||
// }
|
||||
ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs)
|
||||
} else {
|
||||
err = self.Errorf("unknown function %s()", funcName)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func evalAssignCoalesce(ctx ExprContext, self *term) (v any, err error) {
|
||||
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||
if functor, ok := rightValue.(Functor); ok {
|
||||
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
||||
ctx.RegisterFunc2(leftTerm.source(), functor, typeAny, []ExprFuncParam{
|
||||
ctx.RegisterFunc(leftTerm.source(), functor, typeAny, []ExprFuncParam{
|
||||
newFuncParamFlag(paramValue, pfOptional|pfRepeat),
|
||||
})
|
||||
} else {
|
||||
|
142
simple-store.go
142
simple-store.go
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// simple-func-store.go
|
||||
// simple-store.go
|
||||
package expr
|
||||
|
||||
import (
|
||||
@ -15,117 +15,6 @@ type SimpleStore struct {
|
||||
funcStore map[string]*funcInfo
|
||||
}
|
||||
|
||||
type paramFlags uint16
|
||||
|
||||
const (
|
||||
pfOptional paramFlags = 1 << iota
|
||||
pfRepeat
|
||||
)
|
||||
|
||||
type funcParamInfo struct {
|
||||
name string
|
||||
flags paramFlags
|
||||
defaultValue any
|
||||
}
|
||||
|
||||
func newFuncParam(name string) *funcParamInfo {
|
||||
return &funcParamInfo{name: name}
|
||||
}
|
||||
|
||||
func newFuncParamFlag(name string, flags paramFlags) *funcParamInfo {
|
||||
return &funcParamInfo{name: name, flags: flags}
|
||||
}
|
||||
|
||||
func newFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo {
|
||||
return &funcParamInfo{name: name, flags: flags, defaultValue: defValue}
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) Name() string {
|
||||
return param.name
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) Type() string {
|
||||
return "any"
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) IsOptional() bool {
|
||||
return (param.flags & pfOptional) != 0
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) IsRepeat() bool {
|
||||
return (param.flags & pfRepeat) != 0
|
||||
}
|
||||
|
||||
func (param *funcParamInfo) DefaultValue() any {
|
||||
return param.defaultValue
|
||||
}
|
||||
|
||||
type funcInfo struct {
|
||||
name string
|
||||
minArgs int
|
||||
maxArgs int
|
||||
functor Functor
|
||||
params []ExprFuncParam
|
||||
returnType string
|
||||
}
|
||||
|
||||
func (info *funcInfo) Params() []ExprFuncParam {
|
||||
return info.params
|
||||
}
|
||||
|
||||
func (info *funcInfo) ReturnType() string {
|
||||
return info.returnType
|
||||
}
|
||||
|
||||
func (info *funcInfo) ToString(opt FmtOpt) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteByte('(')
|
||||
if info.params != nil {
|
||||
for i, p := range info.params {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(p.Name())
|
||||
if p.IsOptional() {
|
||||
sb.WriteByte('=')
|
||||
if s, ok := p.DefaultValue().(string); ok {
|
||||
sb.WriteByte('"')
|
||||
sb.WriteString(s)
|
||||
sb.WriteByte('"')
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("%v", p.DefaultValue()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if info.maxArgs < 0 {
|
||||
sb.WriteString(" ...")
|
||||
}
|
||||
sb.WriteString(") -> ")
|
||||
if len(info.returnType) > 0 {
|
||||
sb.WriteString(info.returnType)
|
||||
} else {
|
||||
sb.WriteString(typeAny)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (info *funcInfo) Name() string {
|
||||
return info.name
|
||||
}
|
||||
|
||||
func (info *funcInfo) MinArgs() int {
|
||||
return info.minArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) MaxArgs() int {
|
||||
return info.maxArgs
|
||||
}
|
||||
|
||||
func (info *funcInfo) Functor() Functor {
|
||||
return info.functor
|
||||
}
|
||||
|
||||
func NewSimpleStore() *SimpleStore {
|
||||
ctx := &SimpleStore{
|
||||
varStore: make(map[string]any),
|
||||
@ -251,31 +140,12 @@ func (ctx *SimpleStore) RegisterFuncInfo(info ExprFunc) {
|
||||
ctx.funcStore[info.Name()], _ = info.(*funcInfo)
|
||||
}
|
||||
|
||||
func (ctx *SimpleStore) RegisterFunc2(name string, functor Functor, returnType string, params []ExprFuncParam) error {
|
||||
var minArgs = 0
|
||||
var maxArgs = 0
|
||||
if params != nil {
|
||||
for _, p := range params {
|
||||
if maxArgs == -1 {
|
||||
return fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name())
|
||||
func (ctx *SimpleStore) RegisterFunc(name string, functor Functor, returnType string, params []ExprFuncParam) (err error) {
|
||||
var info *funcInfo
|
||||
if info, err = newFuncInfo(name, functor, returnType, params); err == nil {
|
||||
ctx.funcStore[name] = info
|
||||
}
|
||||
if p.IsOptional() {
|
||||
maxArgs++
|
||||
} else if maxArgs == minArgs {
|
||||
minArgs++
|
||||
maxArgs++
|
||||
} else {
|
||||
return fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
|
||||
}
|
||||
if p.IsRepeat() {
|
||||
maxArgs = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.funcStore[name] = &funcInfo{
|
||||
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params,
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *SimpleStore) EnumFuncs(acceptor func(name string) (accept bool)) (funcNames []string) {
|
||||
|
Loading…
Reference in New Issue
Block a user