Compare commits
14 Commits
723976b37e
...
bf8f1a175f
Author | SHA1 | Date | |
---|---|---|---|
bf8f1a175f | |||
6dd8283308 | |||
06ab303b9e | |||
2ccbdb2254 | |||
c5fca70cfc | |||
895778f236 | |||
81c85afbea | |||
354cb79580 | |||
327bffa01f | |||
c99be491df | |||
60effe8f1b | |||
824b9382be | |||
9ce6b7255b | |||
9dbf472630 |
@ -5,11 +5,14 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
initName = "init"
|
initName = "init"
|
||||||
|
cleanName = "clean"
|
||||||
|
resetName = "reset"
|
||||||
nextName = "next"
|
nextName = "next"
|
||||||
currentName = "current"
|
currentName = "current"
|
||||||
)
|
)
|
||||||
@ -20,6 +23,8 @@ type dataCursor struct {
|
|||||||
index int
|
index int
|
||||||
resource any
|
resource any
|
||||||
nextFunc Functor
|
nextFunc Functor
|
||||||
|
cleanFunc Functor
|
||||||
|
resetFunc Functor
|
||||||
currentFunc Functor
|
currentFunc Functor
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +40,30 @@ func (dc *dataCursor) String() string {
|
|||||||
return "$(...)"
|
return "$(...)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dc *dataCursor) Reset() (err error) {
|
||||||
|
if dc.resetFunc != nil {
|
||||||
|
ctx := cloneContext(dc.ctx)
|
||||||
|
if _, err = dc.resetFunc.Invoke(ctx, resetName, []any{}); err == nil {
|
||||||
|
dc.index = -1
|
||||||
|
}
|
||||||
|
exportObjects(dc.ctx, ctx)
|
||||||
|
} else {
|
||||||
|
err = errors.New("no 'reset' function defined in the data-source")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc *dataCursor) Clean() (err error) {
|
||||||
|
if dc.cleanFunc != nil {
|
||||||
|
ctx := cloneContext(dc.ctx)
|
||||||
|
_, err = dc.cleanFunc.Invoke(ctx, cleanName, []any{})
|
||||||
|
exportObjects(dc.ctx, ctx)
|
||||||
|
} else {
|
||||||
|
err = errors.New("no 'clean' function defined in the data-source")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
|
func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
|
||||||
ctx := cloneContext(dc.ctx)
|
ctx := cloneContext(dc.ctx)
|
||||||
if item, err = dc.currentFunc.Invoke(ctx, currentName, []any{}); err == nil && item == nil {
|
if item, err = dc.currentFunc.Invoke(ctx, currentName, []any{}); err == nil && item == nil {
|
||||||
|
@ -55,5 +55,5 @@ func ImportBuiltinsFuncs(ctx ExprContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerImport("builtins", ImportBuiltinsFuncs)
|
registerImport("base", ImportBuiltinsFuncs, "Base expression tools like isNil(), int(), etc.")
|
||||||
}
|
}
|
@ -142,5 +142,5 @@ func ImportImportFuncs(ctx ExprContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerImport("import", ImportImportFuncs)
|
registerImport("import", ImportImportFuncs, "Functions import() and include()")
|
||||||
}
|
}
|
||||||
|
@ -115,5 +115,5 @@ func ImportMathFuncs(ctx ExprContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerImport("math.arith", ImportMathFuncs)
|
registerImport("math.arith", ImportMathFuncs, "Function add() and mul()")
|
||||||
}
|
}
|
||||||
|
@ -164,5 +164,5 @@ func ImportOsFuncs(ctx ExprContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerImport("os", ImportOsFuncs)
|
registerImport("os.file", ImportOsFuncs, "Operating system file functions")
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// function-register.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var functionRegister map[string]func(ExprContext)
|
|
||||||
|
|
||||||
func registerImport(name string, importFunc func(ExprContext)) {
|
|
||||||
if functionRegister == nil {
|
|
||||||
functionRegister = make(map[string]func(ExprContext))
|
|
||||||
}
|
|
||||||
functionRegister[name] = importFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func ImportInContext(ctx ExprContext, name string) (exists bool) {
|
|
||||||
var importFunc func(ExprContext)
|
|
||||||
if importFunc, exists = functionRegister[name]; exists {
|
|
||||||
importFunc(ctx)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ImportInContextByGlobPattern(ctx ExprContext, pattern string) (count int, err error) {
|
|
||||||
var matched bool
|
|
||||||
for name, importFunc := range functionRegister {
|
|
||||||
if matched, err = filepath.Match(pattern, name); err == nil {
|
|
||||||
if matched {
|
|
||||||
count++
|
|
||||||
importFunc(ctx)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if functionRegister == nil {
|
|
||||||
functionRegister = make(map[string]func(ExprContext))
|
|
||||||
}
|
|
||||||
}
|
|
23
helpers.go
23
helpers.go
@ -6,6 +6,8 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,3 +61,24 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EvalStream(ctx ExprContext, r io.Reader) (result any, err error) {
|
||||||
|
var tree *ast
|
||||||
|
scanner := NewScanner(r, DefaultTranslations())
|
||||||
|
parser := NewParser(ctx)
|
||||||
|
|
||||||
|
if tree, err = parser.Parse(scanner); err == nil {
|
||||||
|
result, err = tree.Eval(ctx)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EvalFile(ctx ExprContext, filePath string) (result any, err error) {
|
||||||
|
var fh *os.File
|
||||||
|
if fh, err = os.Open(filePath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
result, err = EvalStream(ctx, fh)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
74
module-register.go
Normal file
74
module-register.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// module-register.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type module struct {
|
||||||
|
importFunc func(ExprContext)
|
||||||
|
description string
|
||||||
|
imported bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModule(importFunc func(ExprContext), description string) *module {
|
||||||
|
return &module{importFunc, description, false}
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleRegister map[string]*module
|
||||||
|
|
||||||
|
func registerImport(name string, importFunc func(ExprContext), description string) {
|
||||||
|
if moduleRegister == nil {
|
||||||
|
moduleRegister = make(map[string]*module)
|
||||||
|
}
|
||||||
|
if _, exists := moduleRegister[name]; exists {
|
||||||
|
panic(fmt.Errorf("module %q already registered", name))
|
||||||
|
}
|
||||||
|
moduleRegister[name] = newModule(importFunc, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportInContext(ctx ExprContext, name string) (exists bool) {
|
||||||
|
var mod *module
|
||||||
|
if mod, exists = moduleRegister[name]; exists {
|
||||||
|
mod.importFunc(ctx)
|
||||||
|
mod.imported = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportInContextByGlobPattern(ctx ExprContext, 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(ctx)
|
||||||
|
mod.imported = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func IterateModules(op func(name, description string, imported bool) bool) {
|
||||||
|
if op != nil {
|
||||||
|
for name, mod := range moduleRegister {
|
||||||
|
if !op(name, mod.description, mod.imported) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
func init() {
|
||||||
|
if moduleRegister == nil {
|
||||||
|
moduleRegister = make(map[string]*module)
|
||||||
|
}
|
||||||
|
}
|
@ -54,14 +54,23 @@ func getDataSourceDict(ctx ExprContext, self *term) (ds map[string]Functor, err
|
|||||||
|
|
||||||
if dictAny, ok := value.(map[any]any); ok {
|
if dictAny, ok := value.(map[any]any); ok {
|
||||||
ds = make(map[string]Functor)
|
ds = make(map[string]Functor)
|
||||||
for _, k := range []string{initName, currentName, nextName} {
|
// required functions
|
||||||
|
for _, k := range []string{currentName, nextName} {
|
||||||
if item, exists := dictAny[k]; exists && item != nil {
|
if item, exists := dictAny[k]; exists && item != nil {
|
||||||
if functor, ok := item.(*funcDefFunctor); ok {
|
if functor, ok := item.(*funcDefFunctor); ok {
|
||||||
ds[k] = functor
|
ds[k] = functor
|
||||||
}
|
}
|
||||||
} else if k != initName {
|
} else {
|
||||||
err = fmt.Errorf("the data-source must provide a non-nil %q operator", k)
|
err = fmt.Errorf("the data-source must provide a non-nil %q operator", k)
|
||||||
break
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Optional functions
|
||||||
|
for _, k := range []string{initName, resetName, cleanName} {
|
||||||
|
if item, exists := dictAny[k]; exists && item != nil {
|
||||||
|
if functor, ok := item.(*funcDefFunctor); ok {
|
||||||
|
ds[k] = functor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -98,6 +107,9 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
|
|
||||||
dc.nextFunc, _ = ds[nextName]
|
dc.nextFunc, _ = ds[nextName]
|
||||||
dc.currentFunc, _ = ds[currentName]
|
dc.currentFunc, _ = ds[currentName]
|
||||||
|
dc.cleanFunc, _ = ds[cleanName]
|
||||||
|
dc.resetFunc, _ = ds[resetName]
|
||||||
|
|
||||||
v = dc
|
v = dc
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-length.go
|
// operator-builtin.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
//-------- builtin term
|
//-------- builtin term
|
||||||
|
@ -17,50 +17,67 @@ func newDotTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifyIndex(ctx ExprContext, indexTerm *term, maxValue int) (index int, err error) {
|
||||||
|
var v int
|
||||||
|
var indexValue any
|
||||||
|
if indexValue, err = indexTerm.compute(ctx); err == nil {
|
||||||
|
if v, err = indexTerm.toInt(indexValue, "index expression value must be integer"); err == nil {
|
||||||
|
if v >= 0 && v < maxValue {
|
||||||
|
index = v
|
||||||
|
} else if index >= -maxValue {
|
||||||
|
index = maxValue + v
|
||||||
|
} else {
|
||||||
|
err = indexTerm.Errorf("index %d out of bounds", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func evalDot(ctx ExprContext, self *term) (v any, err error) {
|
func evalDot(ctx ExprContext, self *term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
var leftValue, rightValue any
|
||||||
|
|
||||||
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
if err = self.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if leftValue, err = self.children[0].compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
indexTerm := self.children[1]
|
indexTerm := self.children[1]
|
||||||
|
|
||||||
if isList(leftValue) {
|
switch unboxedValue := leftValue.(type) {
|
||||||
|
case []any:
|
||||||
var index int
|
var index int
|
||||||
if index, err = indexTerm.toInt(rightValue, "index expression value must be integer"); err != nil {
|
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
|
||||||
return
|
v = unboxedValue[index]
|
||||||
}
|
}
|
||||||
|
case string:
|
||||||
list, _ := leftValue.([]any)
|
|
||||||
if index >= 0 && index < len(list) {
|
|
||||||
v = list[index]
|
|
||||||
} else if index >= -len(list) {
|
|
||||||
v = list[len(list)+index]
|
|
||||||
} else {
|
|
||||||
err = indexTerm.Errorf("index %v out of bounds", index)
|
|
||||||
}
|
|
||||||
} else if isString(leftValue) {
|
|
||||||
var index int
|
var index int
|
||||||
if index, err = indexTerm.toInt(rightValue, "index expression value must be integer"); err != nil {
|
if index, err = verifyIndex(ctx, indexTerm, len(unboxedValue)); err == nil {
|
||||||
return
|
v = unboxedValue[index]
|
||||||
}
|
}
|
||||||
|
case map[any]any:
|
||||||
s, _ := leftValue.(string)
|
|
||||||
if index >= 0 && index < len(s) {
|
|
||||||
v = string(s[index])
|
|
||||||
} else if index >= -len(s) {
|
|
||||||
v = string(s[len(s)+index])
|
|
||||||
} else {
|
|
||||||
err = indexTerm.Errorf("index %v out of bounds", index)
|
|
||||||
}
|
|
||||||
} else if isDict(leftValue) {
|
|
||||||
var ok bool
|
var ok bool
|
||||||
d, _ := leftValue.(map[any]any)
|
var indexValue any
|
||||||
if v, ok = d[rightValue]; !ok {
|
if indexValue, err = indexTerm.compute(ctx); err == nil {
|
||||||
|
if v, ok = unboxedValue[indexValue]; !ok {
|
||||||
err = fmt.Errorf("key %v does not belong to the dictionary", rightValue)
|
err = fmt.Errorf("key %v does not belong to the dictionary", rightValue)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
case *dataCursor:
|
||||||
|
if indexTerm.symbol() == SymIdentifier {
|
||||||
|
opName := indexTerm.source()
|
||||||
|
if opName == resetName {
|
||||||
|
err = unboxedValue.Reset()
|
||||||
|
} else if opName == cleanName {
|
||||||
|
err = unboxedValue.Clean()
|
||||||
} else {
|
} else {
|
||||||
|
err = indexTerm.Errorf("iterators do not support command %q", opName)
|
||||||
|
}
|
||||||
|
v = err == nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
57
operator-include.go
Normal file
57
operator-include.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-include.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
//-------- include term
|
||||||
|
|
||||||
|
func newIncludeTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 1),
|
||||||
|
position: posPrefix,
|
||||||
|
priority: priSign,
|
||||||
|
evalFunc: evalInclude,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalInclude(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var childValue any
|
||||||
|
|
||||||
|
if childValue, err = self.evalPrefix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
if isList(childValue) {
|
||||||
|
list, _ := childValue.([]any)
|
||||||
|
for i, filePathSpec := range list {
|
||||||
|
if filePath, ok := filePathSpec.(string); ok {
|
||||||
|
if v, err = EvalFile(ctx, filePath); err == nil {
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
err = self.Errorf("can't load file %q", filePath)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = self.Errorf("expected string at item nr %d, got %T", i+1, filePathSpec)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if isString(childValue) {
|
||||||
|
filePath, _ := childValue.(string)
|
||||||
|
v, err = EvalFile(ctx, filePath)
|
||||||
|
} else {
|
||||||
|
err = self.errIncompatibleType(childValue)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
v = count
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymKwInclude, newIncludeTerm)
|
||||||
|
}
|
@ -25,12 +25,12 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
|
|
||||||
if isList(rightValue) {
|
if isList(rightValue) {
|
||||||
list, _ := rightValue.([]any)
|
list, _ := rightValue.([]any)
|
||||||
v = len(list)
|
v = int64(len(list))
|
||||||
} else if isString(rightValue) {
|
} else if isString(rightValue) {
|
||||||
s, _ := rightValue.(string)
|
s, _ := rightValue.(string)
|
||||||
v = len(s)
|
v = int64(len(s))
|
||||||
} else if it, ok := rightValue.(Iterator); ok {
|
} else if it, ok := rightValue.(Iterator); ok {
|
||||||
v = it.Index()
|
v = int64(it.Index())
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleType(rightValue)
|
err = self.errIncompatibleType(rightValue)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ const (
|
|||||||
SymBackTick // 22: '`'
|
SymBackTick // 22: '`'
|
||||||
SymExclamation // 23: '!'
|
SymExclamation // 23: '!'
|
||||||
SymQuestion // 24: '?'
|
SymQuestion // 24: '?'
|
||||||
SymAmpersand // 25: '&&'
|
SymAmpersand // 25: '&'
|
||||||
SymDoubleAmpersand // 26: '&&'
|
SymDoubleAmpersand // 26: '&&'
|
||||||
SymPercent // 27: '%'
|
SymPercent // 27: '%'
|
||||||
SymAt // 28: '@'
|
SymAt // 28: '@'
|
||||||
@ -64,7 +64,7 @@ const (
|
|||||||
SymCaret // 53: '^'
|
SymCaret // 53: '^'
|
||||||
SymDollarRound // 54: '$('
|
SymDollarRound // 54: '$('
|
||||||
SymOpenClosedRound // 55: '()'
|
SymOpenClosedRound // 55: '()'
|
||||||
SymDoubleDollar // 56: '$$
|
SymDoubleDollar // 56: '$$'
|
||||||
SymChangeSign
|
SymChangeSign
|
||||||
SymUnchangeSign
|
SymUnchangeSign
|
||||||
SymIdentifier
|
SymIdentifier
|
||||||
@ -96,6 +96,7 @@ const (
|
|||||||
SymKwBut
|
SymKwBut
|
||||||
SymKwFunc
|
SymKwFunc
|
||||||
SymKwBuiltin
|
SymKwBuiltin
|
||||||
|
SymKwInclude
|
||||||
SymKwNil
|
SymKwNil
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -108,6 +109,7 @@ func init() {
|
|||||||
"BUILTIN": SymKwBuiltin,
|
"BUILTIN": SymKwBuiltin,
|
||||||
"BUT": SymKwBut,
|
"BUT": SymKwBut,
|
||||||
"FUNC": SymKwFunc,
|
"FUNC": SymKwFunc,
|
||||||
|
"INCLUDE": SymKwInclude,
|
||||||
"NOT": SymKwNot,
|
"NOT": SymKwNot,
|
||||||
"OR": SymKwOr,
|
"OR": SymKwOr,
|
||||||
"NIL": SymKwNil,
|
"NIL": SymKwNil,
|
||||||
|
4
term.go
4
term.go
@ -217,9 +217,9 @@ func (self *term) evalInfix(ctx ExprContext) (leftValue, rightValue any, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *term) evalPrefix(ctx ExprContext) (rightValue any, err error) {
|
func (self *term) evalPrefix(ctx ExprContext) (childValue any, err error) {
|
||||||
if err = self.checkOperands(); err == nil {
|
if err = self.checkOperands(); err == nil {
|
||||||
rightValue, err = self.children[0].compute(ctx)
|
childValue, err = self.children[0].compute(ctx)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user