Compare commits

...

10 Commits

144 changed files with 3502 additions and 2574 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// function.go
@@ -12,7 +12,7 @@ import (
type exprFunctor struct {
kern.BaseFunctor
params []kern.ExprFuncParam
expr Expr
expr kern.Expr
defCtx kern.ExprContext
}
@@ -20,7 +20,7 @@ func (functor *exprFunctor) GetParams() (params []kern.ExprFuncParam) {
return functor.params
}
func newExprFunctor(e Expr, params []kern.ExprFuncParam, ctx kern.ExprContext) *exprFunctor {
func newExprFunctor(e kern.Expr, params []kern.ExprFuncParam, ctx kern.ExprContext) *exprFunctor {
var defCtx kern.ExprContext
if ctx != nil {
defCtx = ctx
+33 -26
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-base.go
@@ -11,6 +11,7 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
const (
@@ -199,7 +200,7 @@ func fractFunc(ctx kern.ExprContext, name string, args map[string]any) (result a
func evalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if source, ok := args[kern.ParamSource].(string); ok {
var ast Expr
var ast kern.Expr
parser := NewParser()
if ctx == nil {
@@ -207,7 +208,7 @@ func evalFunc(ctx kern.ExprContext, name string, args map[string]any) (result an
}
r := strings.NewReader(source)
scanner := NewScanner(r, DefaultTranslations())
scanner := scan.NewScanner(r, scan.DefaultTranslations())
if ast, err = parser.Parse(scanner); err == nil {
CtrlEnable(ctx, kern.ControlExportAll)
@@ -254,24 +255,31 @@ func setFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
return
}
// func unsetFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
// var varName string
// var ok bool
func charFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var ord int
// if varName, ok = args[kern.ParamName].(string); !ok {
// return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
// } else {
// ctx.GetParent().DeleteVar(varName)
// result = nil
// }
// return
// }
if n, ok := args[kern.ParamValue].(byte); ok {
ord = int(n)
} else if n, ok := args[kern.ParamValue].(int64); ok {
ord = int(n)
} else if n, ok := args[kern.ParamValue].(int); ok {
ord = n
} else {
return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
}
if ord < 0 || ord > 255 {
err = kern.ErrFuncInvalidArg(name, fmt.Sprintf("character code must be in range 0-255, got %d", ord))
} else {
result = string(rune(ord))
}
return
}
//// import
func ImportBuiltinsFuncs(ctx kern.ExprContext) {
anyParams := []kern.ExprFuncParam{
NewFuncParam(kern.ParamValue),
kern.NewFuncParam(kern.ParamValue),
}
ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams)
@@ -289,28 +297,27 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams)
ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{
NewFuncParam(kern.ParamValue),
NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)),
kern.NewFuncParam(kern.ParamValue),
kern.NewFuncParamFlagDef(ParamDenominator, kern.PfDefault, int64(1)),
})
ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamName),
NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil),
kern.NewFuncParam(kern.ParamName),
kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault, nil),
})
ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamName),
NewFuncParam(kern.ParamValue),
kern.NewFuncParam(kern.ParamName),
kern.NewFuncParam(kern.ParamValue),
})
// ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{
// NewFuncParam(kern.ParamName),
// NewFuncParam(kern.ParamValue),
// })
ctx.RegisterFunc("char", kern.NewGolangFunctor(charFunc), kern.TypeString, []kern.ExprFuncParam{
kern.NewFuncParam(kern.ParamValue),
})
}
func init() {
+3 -3
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-fmt.go
@@ -47,10 +47,10 @@ func printLnFunc(ctx kern.ExprContext, name string, args map[string]any) (result
func ImportFmtFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("print", kern.NewGolangFunctor(printFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamItem, PfRepeat),
kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat),
})
ctx.RegisterFunc("println", kern.NewGolangFunctor(printLnFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamItem, PfRepeat),
kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat),
})
}
+7 -6
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-import.go
@@ -9,6 +9,7 @@ import (
"os"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
@@ -43,10 +44,10 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera
var file *os.File
if file, err = os.Open(sourceFilepath); err == nil {
defer file.Close()
var expr *ast
scanner := NewScanner(file, DefaultTranslations())
var expr *scan.Ast
scanner := scan.NewScanner(file, scan.DefaultTranslations())
parser := NewParser()
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, SymEos); err == nil {
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymEos); err == nil {
result, err = expr.Eval(ctx)
}
if err != nil {
@@ -68,10 +69,10 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera
func ImportImportFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamFilepath, PfRepeat),
kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat),
})
ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamFilepath, PfRepeat),
kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat),
})
}
+4 -4
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-iterator.go
@@ -94,9 +94,9 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
func ImportIterFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
NewFuncParam(kern.ParamIterator),
NewFuncParamFlag(iterParamOperator, PfOptional),
NewFuncParamFlag(iterParamVars, PfOptional),
kern.NewFuncParam(kern.ParamIterator),
kern.NewFuncParamFlag(iterParamOperator, kern.PfOptional),
kern.NewFuncParamFlag(iterParamVars, kern.PfOptional),
})
}
+3 -3
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-math-arith.go
@@ -172,11 +172,11 @@ func mulFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
func ImportMathFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("add", kern.NewGolangFunctor(addFunc), kern.TypeNumber, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(0)),
kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, int64(0)),
})
ctx.RegisterFunc("mul", kern.NewGolangFunctor(mulFunc), kern.TypeNumber, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(1)),
kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, int64(1)),
})
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-os-file.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/file"
"git.portale-stac.it/go-pkg/expr/kern"
)
const fileByteIteratorType = "fileByteIterator"
type fileFileByteIterator struct {
fileIterBase
b byte
}
func newFileByteIterator(r *file.Reader, autoClose bool) *fileFileByteIterator {
return &fileFileByteIterator{
fileIterBase: fileIterBase{reader: r, index: -1, count: 0, autoClose: autoClose},
b: 0}
}
func (it *fileFileByteIterator) TypeName() string {
return fileByteIteratorType
}
func (it *fileFileByteIterator) String() string {
return it.repr(fileByteIteratorType)
}
func (it *fileFileByteIterator) Next() (item any, err error) { // must return io.EOF after the last item
if it.b, err = it.reader.ReadByte(); err == nil {
it.increment()
item = it.b
} else if it.autoClose {
it.Clean()
}
return
}
func (it *fileFileByteIterator) Current() (item any, err error) {
item = it.b
return
}
func (it *fileFileByteIterator) Reset() (err error) {
if err = it.reader.Reset(); err == nil {
it.reset()
it.b = 0
}
return
}
func (it *fileFileByteIterator) Clean() (err error) {
if it.reader.Valid() {
if err = it.reader.GetFile().Close(); err == nil {
it.reader = nil
}
}
it.reset()
it.b = 0
return
}
func (it *fileFileByteIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
default:
err = kern.ErrNoOperation(name)
}
return
}
func fileByteIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle *file.Reader
var invalidFileHandle any
var autoClose bool
if handle, invalidFileHandle, autoClose, err = initFileHandle(ctx, name, args); err == nil {
if handle != nil {
result = newFileByteIterator(handle, autoClose)
}
}
if err == nil && (handle == nil || invalidFileHandle != nil) {
err = errInvalidFileHandle(name, invalidFileHandle)
}
return
}
+105
View File
@@ -0,0 +1,105 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-os-file.go
package expr
import (
"git.portale-stac.it/go-pkg/expr/file"
"git.portale-stac.it/go-pkg/expr/kern"
)
const fileLineIteratorType = "fileLineIterator"
type fileFileLineIterator struct {
fileIterBase
line string
}
func newFileLineIterator(r *file.Reader, autoClose bool) *fileFileLineIterator {
return &fileFileLineIterator{
fileIterBase: fileIterBase{reader: r, index: -1, count: 0, autoClose: autoClose},
line: "",
}
}
func (it *fileFileLineIterator) TypeName() string {
return fileLineIteratorType
}
func (it *fileFileLineIterator) String() string {
return it.repr(fileLineIteratorType)
}
func (it *fileFileLineIterator) Next() (item any, err error) { // must return io.EOF after the last item
if it.line, err = it.reader.ReadString('\n'); err == nil {
it.increment()
item = it.line[0 : len(it.line)-1]
} else if it.autoClose {
it.Clean()
}
return
}
func (it *fileFileLineIterator) Current() (item any, err error) {
if len(it.line) > 0 {
item = it.line[0 : len(it.line)-1]
}
return
}
func (it *fileFileLineIterator) Reset() (err error) {
if err = it.reader.Reset(); err == nil {
it.reset()
it.line = ""
}
return
}
func (it *fileFileLineIterator) Clean() (err error) {
if it.reader != nil {
if err = it.reader.Close(); err == nil {
it.reader = nil
}
}
it.reset()
it.line = ""
return
}
func (it *fileFileLineIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
default:
err = kern.ErrNoOperation(name)
}
return
}
func fileLineIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle *file.Reader
var invalidFileHandle any
var autoClose bool
if handle, invalidFileHandle, autoClose, err = initFileHandle(ctx, name, args); err == nil {
if handle != nil {
result = newFileLineIterator(handle, autoClose)
}
}
if err == nil && (handle == nil || invalidFileHandle != nil) {
err = errInvalidFileHandle(name, invalidFileHandle)
}
return
}
+24 -104
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-os-file.go
@@ -6,146 +6,66 @@ package expr
import (
"fmt"
"io"
"slices"
"git.portale-stac.it/go-pkg/expr/file"
"git.portale-stac.it/go-pkg/expr/kern"
)
const paramHandleOrPath = "handle-or-path"
const fileReadTextIteratorType = "fileReadTextIterator"
type fileReadTextIterator struct {
osReader *osReader
type fileIterBase struct {
reader *file.Reader
index int64
count int64
line string
autoClose bool
}
func newReadTextIterator(r *osReader, autoClose bool) *fileReadTextIterator {
return &fileReadTextIterator{osReader: r, index: -1, autoClose: autoClose}
}
func (it *fileReadTextIterator) TypeName() string {
return fileReadTextIteratorType
}
func (it *fileReadTextIterator) String() string {
if it.osReader != nil && it.osReader.fh != nil {
return fmt.Sprintf("$(%s@%q)", fileReadTextIteratorType, it.osReader.fh.Name())
}
return fmt.Sprintf("$(%s@<nil>)", fileReadTextIteratorType)
}
func (it *fileReadTextIterator) Count() int64 {
func (it *fileIterBase) Count() int64 {
return it.count
}
func (it *fileReadTextIterator) Next() (item any, err error) { // must return io.EOF after the last item
if it.osReader.fh != nil {
if it.line, err = it.osReader.reader.ReadString('\n'); err == nil {
it.index++
it.count++
item = it.line[0 : len(it.line)-1]
} else if it.autoClose {
it.Clean()
}
}
return
}
func (it *fileReadTextIterator) Current() (item any, err error) {
if len(it.line) > 0 {
item = it.line[0 : len(it.line)-1]
}
return
}
func (it *fileReadTextIterator) Index() int64 {
func (it *fileIterBase) Index() int64 {
return it.index
}
func (it *fileReadTextIterator) Reset() (err error) {
if _, err = it.osReader.fh.Seek(0, io.SeekStart); err == nil {
it.index = -1
it.count = 0
it.line = ""
}
return
}
func (it *fileReadTextIterator) HasOperation(name string) bool {
func (it *fileIterBase) HasOperation(name string) bool {
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
}
func (it *fileReadTextIterator) Clean() (err error) {
if it.osReader.fh != nil {
if err = it.osReader.fh.Close(); err == nil {
it.osReader = nil
}
}
return nil
func (it *fileIterBase) reset() {
it.index = -1
it.count = 0
}
func (it *fileReadTextIterator) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
default:
err = kern.ErrNoOperation(name)
}
return
func (it *fileIterBase) increment() {
it.index++
it.count++
}
func fileReadIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle *osReader
var invalidFileHandle any
var ok, autoClose bool
func (it *fileIterBase) repr(typeName string) string {
if it.reader.Valid() {
return fmt.Sprintf("$(%s@%q)", typeName, it.reader.GetName())
}
return fmt.Sprintf("$(%s@<nil>)", typeName)
}
result = nil
if handle, ok = args[paramHandleOrPath].(*osReader); !ok {
func initFileHandle(ctx kern.ExprContext, name string, args map[string]any) (handle *file.Reader, invalidFileHandle any, autoClose bool, err error) {
var ok bool
if handle, ok = args[paramHandleOrPath].(*file.Reader); !ok {
if fileName, ok := args[paramHandleOrPath].(string); ok && len(fileName) > 0 {
var handleAny any
if handleAny, err = openFileFunc(ctx, name, map[string]any{kern.ParamFilepath: fileName}); err != nil {
return
}
if handleAny != nil {
handle = handleAny.(*osReader)
handle = handleAny.(*file.Reader)
autoClose = true
}
} else {
invalidFileHandle = args[paramHandleOrPath]
}
}
if handle != nil {
result = newReadTextIterator(handle, autoClose)
}
if err == nil && (handle == nil || invalidFileHandle != nil) {
err = errInvalidFileHandle(name, invalidFileHandle)
}
return
}
// func ImportOsIterFuncs(ctx ExprContext) {
// ctx.RegisterFunc("fileReadIterator", NewGolangFunctor(fileReadIteratorFunc), TypeIterator, []ExprFuncParam{
// NewFuncParam(paramHandleOrPath),
// })
// }
// func init() {
// RegisterBuiltinModule("os.file", ImportOsIterFuncs, "Operating system file iterator functions")
// }
+53 -83
View File
@@ -1,15 +1,14 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-os-file.go
package expr
import (
"bufio"
"fmt"
"io"
"os"
"git.portale-stac.it/go-pkg/expr/file"
"git.portale-stac.it/go-pkg/expr/kern"
)
@@ -17,44 +16,6 @@ const (
osLimitCh = "limitCh"
)
type osHandle interface {
getFile() *os.File
}
type osWriter struct {
fh *os.File
writer *bufio.Writer
}
func (h *osWriter) TypeName() string {
return "osWriter"
}
func (h *osWriter) String() string {
return "writer"
}
func (h *osWriter) getFile() *os.File {
return h.fh
}
type osReader struct {
fh *os.File
reader *bufio.Reader
}
func (h *osReader) TypeName() string {
return "osReader"
}
func (h *osReader) String() string {
return "reader"
}
func (h *osReader) getFile() *os.File {
return h.fh
}
func errMissingFilePath(funcName string) error {
return fmt.Errorf("%s(): missing or invalid file path", funcName)
}
@@ -67,24 +28,26 @@ func errInvalidFileHandle(funcName string, v any) error {
}
}
func createFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.Create(filePath); err == nil {
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
}
// var fh *os.File
// if fh, err = os.Open(filePath); err == nil {
// result = file.NewReader(fh)
// }
result, err = file.OpenReader(filePath)
} else {
err = errMissingFilePath(name)
}
return
}
func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
func createFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.Open(filePath); err == nil {
result = &osReader{fh: fh, reader: bufio.NewReader(fh)}
}
// var fh *os.File
// if fh, err = os.Create(filePath); err == nil {
// result = file.NewWriter(fh)
// }
result, err = file.CreateWriter(filePath)
} else {
err = errMissingFilePath(name)
}
@@ -93,10 +56,11 @@ func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (resul
func appendFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
var fh *os.File
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil {
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
}
// var fh *os.File
// if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil {
// result = file.NewWriter(fh)
// }
result, err = file.AppendWriter(filePath)
} else {
err = errMissingFilePath(name)
}
@@ -104,18 +68,18 @@ func appendFileFunc(ctx kern.ExprContext, name string, args map[string]any) (res
}
func closeFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var handle file.Handle
var invalidFileHandle any
var ok bool
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
if fh := handle.getFile(); fh != nil {
if w, ok := handle.(*osWriter); ok {
err = w.writer.Flush()
if fh := handle.GetFile(); fh != nil {
if w, ok := handle.(*file.Writer); ok {
err = w.Flush()
}
if err == nil {
@@ -131,19 +95,20 @@ func closeFileFunc(ctx kern.ExprContext, name string, args map[string]any) (resu
}
func fileWriteTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var handle file.Handle
var invalidFileHandle any
var ok bool
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
if w, ok := handle.(*osWriter); ok {
if w, ok := handle.(*file.Writer); ok {
if v, exists := args[kern.ParamItem]; exists {
argv := v.([]any)
result, err = fmt.Fprint(w.writer, argv...)
// result, err = fmt.Fprint(w.writer, argv...)
result, err = w.Write(argv...)
}
} else {
invalidFileHandle = handle
@@ -157,24 +122,24 @@ func fileWriteTextFunc(ctx kern.ExprContext, name string, args map[string]any) (
}
func fileReadTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var handle file.Handle
var invalidFileHandle any
var ok bool
result = nil
if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil {
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok || args[kern.ParamHandle] == nil {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
if r, ok := handle.(*osReader); ok {
if r, ok := handle.(*file.Reader); ok {
var limit byte = '\n'
var v string
if s, ok := args[osLimitCh].(string); ok && len(s) > 0 {
limit = s[0]
}
v, err = r.reader.ReadString(limit)
v, err = r.ReadString(limit)
if err == io.EOF {
err = nil
}
@@ -197,19 +162,19 @@ func fileReadTextFunc(ctx kern.ExprContext, name string, args map[string]any) (r
}
func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
var handle osHandle
var handle file.Handle
var invalidFileHandle any
var ok bool
result = nil
if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil {
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok || args[kern.ParamHandle] == nil {
invalidFileHandle = args[kern.ParamHandle]
}
if handle != nil {
if r, ok := handle.(*osReader); ok {
if r, ok := handle.(*file.Reader); ok {
var b []byte
b, err = io.ReadAll(r.reader)
b, err = r.ReadAll()
result = string(b)
} else {
invalidFileHandle = handle
@@ -224,38 +189,43 @@ func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any)
func ImportOsFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
kern.NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileAppend", kern.NewGolangFunctor(appendFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
kern.NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileCreate", kern.NewGolangFunctor(createFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
NewFuncParam(kern.ParamFilepath),
kern.NewFuncParam(kern.ParamFilepath),
})
ctx.RegisterFunc("fileClose", kern.NewGolangFunctor(closeFileFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
kern.NewFuncParam(kern.ParamHandle),
})
ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
NewFuncParamFlagDef(kern.ParamItem, PfDefault|PfRepeat, ""),
kern.NewFuncParam(kern.ParamHandle),
kern.NewFuncParamFlagDef(kern.ParamItem, kern.PfDefault|kern.PfRepeat, ""),
})
ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
NewFuncParamFlagDef(osLimitCh, PfDefault, "\n"),
kern.NewFuncParam(kern.ParamHandle),
kern.NewFuncParamFlagDef(osLimitCh, kern.PfDefault, "\n"),
})
ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamHandle),
kern.NewFuncParam(kern.ParamHandle),
})
ctx.RegisterFunc("fileReadIterator", kern.NewGolangFunctor(fileReadIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
NewFuncParam(paramHandleOrPath),
ctx.RegisterFunc("fileLineIterator", kern.NewGolangFunctor(fileLineIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
kern.NewFuncParam(paramHandleOrPath),
})
ctx.RegisterFunc("fileByteIterator", kern.NewGolangFunctor(fileByteIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
kern.NewFuncParam(paramHandleOrPath),
})
}
func init() {
+18 -18
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtin-string.go
@@ -225,44 +225,44 @@ func lowerStrFunc(ctx kern.ExprContext, name string, args map[string]any) (resul
// Import above functions in the context
func ImportStringFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSeparator),
NewFuncParamFlag(kern.ParamItem, PfRepeat),
kern.NewFuncParam(kern.ParamSeparator),
kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat),
})
ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParamFlagDef(kern.ParamStart, PfDefault, int64(0)),
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
kern.NewFuncParam(kern.ParamSource),
kern.NewFuncParamFlagDef(kern.ParamStart, kern.PfDefault, int64(0)),
kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)),
})
ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParamFlagDef(kern.ParamSeparator, PfDefault, ""),
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
kern.NewFuncParam(kern.ParamSource),
kern.NewFuncParamFlagDef(kern.ParamSeparator, kern.PfDefault, ""),
kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)),
})
ctx.RegisterFunc("strTrim", kern.NewGolangFunctor(trimStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("strStartsWith", kern.NewGolangFunctor(startsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParam(kern.ParamPrefix),
NewFuncParamFlag(strParamOther, PfRepeat),
kern.NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamPrefix),
kern.NewFuncParamFlag(strParamOther, kern.PfRepeat),
})
ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
NewFuncParam(kern.ParamSuffix),
NewFuncParamFlag(strParamOther, PfRepeat),
kern.NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamSuffix),
kern.NewFuncParamFlag(strParamOther, kern.PfRepeat),
})
ctx.RegisterFunc("strUpper", kern.NewGolangFunctor(upperStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamSource),
})
ctx.RegisterFunc("strLower", kern.NewGolangFunctor(lowerStrFunc), kern.TypeString, []kern.ExprFuncParam{
NewFuncParam(kern.ParamSource),
kern.NewFuncParam(kern.ParamSource),
})
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// builtins-register.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// data-cursors.go
+6 -4
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// dict-iterator.go
@@ -116,8 +116,11 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err
}
}
dictIt.makeKeys(*dict, sortType)
return dictIt, err
if err == nil {
dictIt.makeKeys(*dict, sortType)
it = dictIt
}
return
}
func NewMapIterator(m map[any]any) (it *DictIterator) {
@@ -139,7 +142,6 @@ func (it *DictIterator) TypeName() string {
}
func (it *DictIterator) HasOperation(name string) bool {
// yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, kern.KeyName, kern.ValueName}, name)
return yes
}
+87 -38
View File
@@ -34,7 +34,7 @@ Expressions calculator
toc::[]
#TODO: Work in progress (last update on 2026/04/21, 6:49 p.m.)#
#TODO: Work in progress (last update on 2026/05/08)#
== Expr
_Expr_ is a GO package that can analyze, interpret and calculate expressions.
@@ -698,9 +698,9 @@ The value on the left side of [blue]`=` must be a variable identifier or an expr
=== Selector operator [blue]`? : ::`
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
.Selector literal Syntax
.Selector literal syntax
====
_selector-operator_ = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
*_selector-operator_* = _select-expression_ "*?*" _selector-case_ { "*:*" _selector-case_ } ["*::*" _default-multi-expression_] +
_selector-case_ = [_match-list_] _case-value_ +
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
_item_ = _expression_ +
@@ -737,19 +737,38 @@ The [blue]`:` symbol (colon) is the separator of the selector-cases. Note that i
`>>>` [blue]`10 ? {"a"} : {"b"}` +
[red]`Eval Error: [1:3] no case catches the value (10) of the selection expression`
==== Triple special case of the selector operator
If the _select-expression_ is a boolean expression, the selector operator can be used as a sort of _if-then-else_ statement. In this case, the first case is evaluated if the _select-expression_ is true, and the second case is evaluated if the _select-expression_ is false. In this special case, the _match-list_ of both cases must be empty.
.Example
`>>>` [blue]`(true) ? {"T"}: {"F"}` +
[green]`T` +
`>>>` [blue]`(2 > 1) ? {"a"} : {"b"}` +
[green]`a` +
`>>>` [blue]`(2 < 1) ? {"a"} : {"b"}` +
[green]`b`
[WARNING]
====
The triple special case of the selector operator is very useful, but it only works with boolean expressions.
.Example of confusion
`>>>` [blue]`int(true) ? {"T"}: {"F"}` +
[green]`F`
====
=== Variable default value [blue]`??`, [blue]`?=`, and [blue]`?!`
The left operand of the first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operator can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.
The left operand of the first two operators, [blue]`??` and [blue]`?=`, must be a variable. The right operatand can be any expression. They return the value of the variable if this is defined; otherwise they return the value of the right expression.
IMPORTANT: If the left variable is defined, the right expression is not evaluated at all.
The [blue]`??` operator do not change the status of the left variable.
The [blue]`?=` assigns the calculated value of the right expression to the left variable.
The [blue]`?=` assigns the calculated value of the right expression to the variable on the left side.
The third one, [blue]`?!`, is the alternate operator. If the variable on the left size is not defined, it returns [blue]_nil_. Otherwise it returns the result of the expressione on the right side.
IMPORTANT: If the left variable is NOT defined, the right expression is not evaluated at all.
IMPORTANT: If the variable [blue]`?!` is NOT defined, the expression is not evaluated at all.
.Examples
`>>>` [blue]`var ?? (1+2)` +
@@ -836,8 +855,14 @@ The table below shows all supported operators by decreasing priorities.
.2+|*INSERT*| [blue]`+>` | _Infix_ | _Prepend_ | _any_ `+>` _list_ -> _list_
| [blue]`<+` | _Infix_ | _Append_ | _list_ `<+` _any_ -> _list_
.2+|*ASSIGN*| [blue]`=` | _Infix_ | _Assignment_ | _identifier_ `=` _any_ -> _any_
4+| _See also the table of special allocation operators below_
4+| _See also the table of special assignment operators below_
.1+|*BUT*| [blue]`but` | _Infix_ | _But_ | _any_ `but` _any_ -> _any_
.6+|*ITER-OP*| [blue]`digest` | _Infix_ | _Item-digesting_ | _iterable_ `digest` _expr_ -> _any_
| [blue]`filter` | _Infix_ | _Item-filtering_ | _iterable_ `filter` _expr_ -> _list_
| [blue]`groupby` | _Infix_ | _Dict-grouping_ | _iterable_ `groupby` _key-expr_ -> _dict_
| [blue]`join` | _Infix_ | _Item-joining_ | _iterable_ `join` _iterable_ -> _list_
| [blue]`map` | _Infix_ | _Item-mapping_ | _iterable_ `map` _-expr_ -> _list_
4+| _See iterators section for examples_
.1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_
|===
@@ -921,12 +946,12 @@ _param-name_ = _identifier_
[green]`fib(n):any{}`
`>>>` [gray]_// Required and optional parameters_ +
`>>>` [blue]`measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? [true] {"s"} :: {""}}` +
`>>>` [blue]`measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? {"s"} :: {""}}` +
[green]`measure(value, unit="meter"):any{}`
=== _Golang_ function definition
Description of how to define Golang functions and how to bind them to _Expr_ are topics covered in another document that I'll write, one day, maybe.
Description of how to define Golang functions and how to bind them to _Expr_ are topics covered in another documents that I'll write, one day, maybe.
=== Function calls
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
@@ -1010,7 +1035,7 @@ Clone variables are normal local variables. The only diffence will appear when t
.Example
`>>>` [blue]`f = func() { @x = 3; x = 5 }` [gray]_// f() declares two *different* local variables: ``@x`` and ``x``_ +
[green]`f():any{}` +
`>>>` [blue]`f()` [gray]_// The multi-expression (two) in f() is calculated and the last result is returned_ +
`>>>` [blue]`f()` [gray]_// The multi-expression (two expressions) in f() is calculated and the last result is returned_ +
[green]`5` +
`>>>` [blue]`x` [gray]_// The `x` variable was not defined in the main context before the f() invocation. It appears in the main context by cloning the `@x` variable, local to f() after its termnation._ +
[green]`3`
@@ -1048,7 +1073,7 @@ Builtins activation is done by using the [blue]`BUILTIN` operator. All modules e
.Builtin activation syntax
====
*_builtin-activation_* = [blue]`BUILTIN` (_builtin-name_ | _list-of-builtin-names_) +
*_builtin-activation_* = [blue]`BUILTIN` (_builtin-name_ | _list-of-builtin-names_ | **"*"**) +
_builtin-name_ = _string_ +
_list-of-builtin-names_ = **[** _string_ { "**,**" _string_ } **]**
====
@@ -1086,9 +1111,9 @@ The "base" builtin module provides functions for type checking and type conversi
* <<_fract,fract()>>
.Other functions
* <<_char,char()>>
* <<_eval,eval()>>
* <<_set,set()>>
* <<_unset,unset()>>
* <<_var,var()>>
@@ -1100,7 +1125,9 @@ Returns _true_ if the value type of _<expr>_ is boolean, false otherwise.
`>>>` [blue]`isBool(true)` +
[green]`true` +
`>>>` [blue]`isBool(3==2)` +
[green]`true`
[green]`true` +
`>>>` [blue]`isBool(3 + 2)` +
[green]`false`
===== isDict()
Syntax: `isDict(<expr>) -> bool` +
@@ -1178,7 +1205,7 @@ Returns _true_ if the value type of _<expr>_ is fraction or int, false otherwise
===== isString()
Syntax: `isString(<expr>) -> bool` +
Returns a boolean value , false otherwise.
Returns _true_ if the value type of _<expr>_ is string, false otherwise.
.Examples
`>>>` [blue]`isString("ciao")` +
@@ -1190,7 +1217,7 @@ Returns a boolean value , false otherwise.
===== bool()
Syntax: `bool(<expr>) -> bool` +
Returns a _boolean_ value consisent to the value of the expression.
Returns a _boolean_ value consisent with the value of the expression.
.Examples
`>>>` [blue]`bool(1)` +
@@ -1295,6 +1322,16 @@ Returns a _fraction_ value consistent with the value of the expression.
`>>>` [blue]`fract(true)` +
[green]`1:1`
===== char()
Syntax: `char(<intexpr>) -> string` +
Returns the character whose ASCII (soon Unicode too) code point is specified by the integer expression.
.Examples
`>>>` [blue]`char(65)` +
[green]`"A"` +
`>>>` [blue]`char(97)` +
[green]`"a"`
===== eval()
Syntax: `eval(<string-expr>) -> any` +
Computes and returns the value of the [.underline]#string# expression.
@@ -1308,12 +1345,12 @@ Syntax: +
`{4sp}var(<string-expr>, <expr>) -> any` +
`{4sp}var(<string-expr>) -> any`
This function allows you to define variables whose names must include special characters. The first form of the function allows you to define a variable with a name specified by the first parameter and assign it the value of the second parameter. The second form only returns the value of the variable with the specified name.
This function allows you to define variables whose names can include special characters. The first form of the function allows you to define a variable with a name specified by the first parameter and assign it the value of the second parameter. The second form only returns the value of the variable with the specified name.
.Examples
`>>>` [blue]`var("$x", 3+9)` +
[green]`12` +
`>>>` [blue]`var("$x")` +
`>>>` [blue]`var("$"+"x")` +
[green]`12` +
`>>>` [blue]`var("gain%", var("$x"))` +
[green]`12` +
@@ -1334,26 +1371,17 @@ It is equivalent to the first form of the var() function, but it is more explici
`>>>` [blue]`var("$x")` +
[green]`100` +
===== unset()
Syntax: +
`{4sp}unset(<string-expr>) -> any`
This function allows you to unset a variable whose name can include special characters. The parameter is the name of the variable to unset.
.Examples
`>>>` [blue]`unset("$x")` +
[green]`nil` +
`>>>` [blue]`var("$x")` +
[red]`Eval Error: var(): unknown variable "$x"`
==== Module "fmt"
#to-do#
===== print()
===== println()
==== Module "import"
Module actiovation: +
Module activation: +
`{4sp}BUILTIN "import"`
===== _import()_
Syntax: +
@@ -1364,6 +1392,8 @@ Loads the multi-expression contained in the specified source and returns its val
===== _importAll()_
==== Module "iterator"
Module activation: +
`{4sp}BUILTIN "iterator"`
===== run()
Syntax: +
@@ -1372,6 +1402,9 @@ Syntax: +
Iterates over the specified iterator and applies the specified operator to the current value of the iterator.
==== Module "math.arith"
Module activation: +
`{4sp}BUILTIN "math.arith"`
Currently, the "math.arith" module provides two functions, add() and mul(), that perform addition and multiplication of an arbitrary number of parameters. More functions will be added in the future.
* <<_add,add()>>
@@ -1421,13 +1454,12 @@ Same as <<_add,add()>> but returns the product of the values of the parameters.
[green]`24`
==== Module "os.file"
Module activation: +
`{4sp}BUILTIN "os.file"`
The "os.file" module provides functions for working with files.
Activation: +
`{4sp}builtin "os.file"`
Currently available functions:
.File related functions
* <<_fileOpen,fileOpen()>>
* <<_fileAppend,fileAppend()>>
* <<_fileCreate,fileCreate()>>
@@ -1436,6 +1468,10 @@ Currently available functions:
* <<_fileReadText,fileReadText()>>
* <<_fileReadTextAll,fileReadTextAll()>>
.Iterator functions for files
* <<_fileByteIterator,fileByteIterator()>>
* <<_fileLineIterator,fileLineIterator()>>
More functions will be added in the future.
---
@@ -1447,6 +1483,10 @@ Syntax: +
Returns a file handle for the specified file path. The file is opened in read-write mode. If the file does not exist, it is created.
===== fileAppend()
Syntax: +
`{4sp}fileAppend(<file-path>) -> any`
Like <<_fileCreate,fileCreate()>> but write operations happen at the end of the file.
===== fileCreate()
Syntax: +
@@ -1455,21 +1495,30 @@ Syntax: +
Creates or truncates the named _<file-path>_. If the file already exists, it is truncated. If the file does not exist, it is created with mode 0o666 (before umask). The associated file descriptor has mode [O_RDWR]. The directory containing the file must already exist.
===== fileClose()
#to-do#
===== fileWriteText()
#to-do#
===== fileReadText()
#to-do#
===== fileReadTextAll()
#to-do#
===== fileByteIterator()
#to-do#
===== fileLineIterator()
#to-do#
==== Module "string"
Module activation: +
`{4sp}BUILTIN "string"`
This module provides functions for working with strings.
Activation: +
`{4sp}builtin "string"`
Currently available functions:
* <<_strJoin,strJoin()>>
-16
View File
@@ -1,16 +0,0 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// expr.go
package expr
import (
kern "git.portale-stac.it/go-pkg/expr/kern"
)
// ----Expression interface
type Expr interface {
kern.Typer
Eval(ctx kern.ExprContext) (result any, err error)
String() string
}
+322
View File
@@ -0,0 +1,322 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>file: Go Coverage Report</title>
<style>
body {
background: black;
color: rgb(80, 80, 80);
}
body, pre, #legend span {
font-family: Menlo, monospace;
font-weight: bold;
}
#topbar {
background: black;
position: fixed;
top: 0; left: 0; right: 0;
height: 42px;
border-bottom: 1px solid rgb(80, 80, 80);
}
#content {
margin-top: 50px;
}
#nav, #legend {
float: left;
margin-left: 10px;
}
#legend {
margin-top: 12px;
}
#nav {
margin-top: 10px;
}
#legend span {
margin: 0 5px;
}
.cov0 { color: rgb(192, 0, 0) }
.cov1 { color: rgb(128, 128, 128) }
.cov2 { color: rgb(116, 140, 131) }
.cov3 { color: rgb(104, 152, 134) }
.cov4 { color: rgb(92, 164, 137) }
.cov5 { color: rgb(80, 176, 140) }
.cov6 { color: rgb(68, 188, 143) }
.cov7 { color: rgb(56, 200, 146) }
.cov8 { color: rgb(44, 212, 149) }
.cov9 { color: rgb(32, 224, 152) }
.cov10 { color: rgb(20, 236, 155) }
</style>
</head>
<body>
<div id="topbar">
<div id="nav">
<select id="files">
<option value="file0">git.portale-stac.it/go-pkg/expr/file/file.go (88.9%)</option>
<option value="file1">git.portale-stac.it/go-pkg/expr/file/reader.go (77.8%)</option>
<option value="file2">git.portale-stac.it/go-pkg/expr/file/writer.go (100.0%)</option>
</select>
</div>
<div id="legend">
<span>not tracked</span>
<span class="cov0">not covered</span>
<span class="cov8">covered</span>
</div>
</div>
<div id="content">
<pre class="file" id="file0" style="display: none">// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// file.go
package file
import (
"os"
"git.portale-stac.it/go-pkg/expr/kern"
)
type Handle interface {
kern.Typer
GetFile() *os.File
GetName() string
Valid() bool
Close() error
}
type handleBase struct {
fh *os.File
}
func (h *handleBase) GetFile() *os.File <span class="cov0" title="0">{
return h.fh
}</span>
func (h *handleBase) GetName() (name string) <span class="cov8" title="1">{
if h.fh != nil </span><span class="cov8" title="1">{
name = h.fh.Name()
}</span>
<span class="cov8" title="1">return</span>
}
func (h *handleBase) Valid() bool <span class="cov8" title="1">{
return h.fh != nil
}</span>
func (h *handleBase) Close() (err error) <span class="cov8" title="1">{
if h.fh != nil </span><span class="cov8" title="1">{
err = h.fh.Close()
h.fh = nil
}</span>
<span class="cov8" title="1">return</span>
}
</pre>
<pre class="file" id="file1" style="display: none">// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// reader.go
package file
import (
"bufio"
"io"
"os"
)
type Reader struct {
// fh *os.File
handleBase
reader *bufio.Reader
}
func NewReader(fh *os.File) *Reader <span class="cov8" title="1">{
return &amp;Reader{handleBase: handleBase{fh: fh}, reader: bufio.NewReader(fh)}
}</span>
func OpenReader(filePath string) (r *Reader, err error) <span class="cov8" title="1">{
var fh *os.File
if fh, err = os.Open(filePath); err == nil </span><span class="cov8" title="1">{
r = NewReader(fh)
}</span>
<span class="cov8" title="1">return</span>
}
func (h *Reader) TypeName() string <span class="cov8" title="1">{
return "fileReader"
}</span>
func (h *Reader) String() string <span class="cov8" title="1">{
return "reader"
}</span>
func (h *Reader) Valid() bool <span class="cov8" title="1">{
return h.handleBase.Valid() &amp;&amp; h.reader != nil
}</span>
func (w *Reader) Close() (err error) <span class="cov8" title="1">{
w.reader = nil
err = w.handleBase.Close()
return
}</span>
func (h *Reader) ReadByte() (b byte, err error) <span class="cov8" title="1">{
if h.reader != nil </span><span class="cov8" title="1">{
b, err = h.reader.ReadByte()
}</span> else<span class="cov0" title="0"> {
err = io.ErrClosedPipe
}</span>
<span class="cov8" title="1">return</span>
}
func (h *Reader) ReadAll() (p []byte, err error) <span class="cov8" title="1">{
if h.reader != nil </span><span class="cov8" title="1">{
p, err = io.ReadAll(h.reader)
}</span> else<span class="cov0" title="0"> {
err = io.ErrClosedPipe
}</span>
<span class="cov8" title="1">return</span>
}
func (h *Reader) ReadString(delim byte) (s string, err error) <span class="cov0" title="0">{
if h.reader != nil </span><span class="cov0" title="0">{
s, err = h.reader.ReadString(delim)
}</span> else<span class="cov0" title="0"> {
err = io.ErrClosedPipe
}</span>
<span class="cov0" title="0">return</span>
}
func (h *Reader) Reset() (err error) <span class="cov8" title="1">{
if h.fh != nil </span><span class="cov8" title="1">{
if _, err = h.fh.Seek(0, 0); err == nil </span><span class="cov8" title="1">{
h.reader.Reset(h.fh)
}</span>
}
<span class="cov8" title="1">return</span>
}
</pre>
<pre class="file" id="file2" style="display: none">// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// writer.go
package file
import (
"bufio"
"fmt"
"os"
)
type Writer struct {
// fh *os.File
handleBase
writer *bufio.Writer
}
func NewWriter(fh *os.File) *Writer <span class="cov8" title="1">{
return &amp;Writer{handleBase: handleBase{fh: fh}, writer: bufio.NewWriter(fh)}
}</span>
func CreateWriter(filePath string) (w *Writer, err error) <span class="cov8" title="1">{
var fh *os.File
if fh, err = os.Create(filePath); err == nil </span><span class="cov8" title="1">{
w = NewWriter(fh)
}</span>
<span class="cov8" title="1">return</span>
}
func AppendWriter(filePath string) (w *Writer, err error) <span class="cov8" title="1">{
var fh *os.File
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644); err == nil </span><span class="cov8" title="1">{
w = NewWriter(fh)
}</span>
<span class="cov8" title="1">return</span>
}
func (w *Writer) TypeName() string <span class="cov8" title="1">{
return "fileWriter"
}</span>
func (w *Writer) String() string <span class="cov8" title="1">{
return "writer"
}</span>
func (w *Writer) Valid() bool <span class="cov8" title="1">{
return w.handleBase.Valid() &amp;&amp; w.writer != nil
}</span>
func (w *Writer) Close() (err error) <span class="cov8" title="1">{
var err1 error
if w.writer != nil </span><span class="cov8" title="1">{
err1 = w.Flush()
w.writer = nil
}</span>
<span class="cov8" title="1">if err = w.handleBase.Close(); err == nil </span><span class="cov8" title="1">{
err = err1
}</span>
<span class="cov8" title="1">return</span>
}
func (w *Writer) Flush() (err error) <span class="cov8" title="1">{
if w.writer != nil </span><span class="cov8" title="1">{
err = w.writer.Flush()
}</span>
<span class="cov8" title="1">return</span>
}
func (w *Writer) Write(args ...any) (n int, err error) <span class="cov8" title="1">{
if w.writer != nil </span><span class="cov8" title="1">{
n, err = fmt.Fprint(w.writer, args...)
}</span>
<span class="cov8" title="1">return</span>
}
func (w *Writer) Writef(format string, args ...any) (n int, err error) <span class="cov8" title="1">{
if w.writer != nil </span><span class="cov8" title="1">{
n, err = fmt.Fprintf(w.writer, format, args...)
}</span>
<span class="cov8" title="1">return</span>
}
</pre>
</div>
</body>
<script>
(function() {
var files = document.getElementById('files');
var visible;
files.addEventListener('change', onChange, false);
function select(part) {
if (visible)
visible.style.display = 'none';
visible = document.getElementById(part);
if (!visible)
return;
files.value = part;
visible.style.display = 'block';
location.hash = part;
}
function onChange() {
select(files.value);
window.scrollTo(0, 0);
}
if (location.hash != "") {
select(location.hash.substr(1));
}
if (!visible) {
select("file0");
}
})();
</script>
</html>
+46
View File
@@ -0,0 +1,46 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// file.go
package file
import (
"os"
"git.portale-stac.it/go-pkg/expr/kern"
)
type Handle interface {
kern.Typer
GetFile() *os.File
GetName() string
Valid() bool
Close() error
}
type handleBase struct {
fh *os.File
}
func (h *handleBase) GetFile() *os.File {
return h.fh
}
func (h *handleBase) GetName() (name string) {
if h.fh != nil {
name = h.fh.Name()
}
return
}
func (h *handleBase) Valid() bool {
return h.fh != nil
}
func (h *handleBase) Close() (err error) {
if h.fh != nil {
err = h.fh.Close()
h.fh = nil
}
return
}
+83
View File
@@ -0,0 +1,83 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// reader.go
package file
import (
"bufio"
"io"
"os"
)
type Reader struct {
// fh *os.File
handleBase
reader *bufio.Reader
}
func NewReader(fh *os.File) *Reader {
return &Reader{handleBase: handleBase{fh: fh}, reader: bufio.NewReader(fh)}
}
func OpenReader(filePath string) (r *Reader, err error) {
var fh *os.File
if fh, err = os.Open(filePath); err == nil {
r = NewReader(fh)
}
return
}
func (h *Reader) TypeName() string {
return "fileReader"
}
func (h *Reader) String() string {
return "reader"
}
func (h *Reader) Valid() bool {
return h.handleBase.Valid() && h.reader != nil
}
func (w *Reader) Close() (err error) {
w.reader = nil
err = w.handleBase.Close()
return
}
func (h *Reader) ReadByte() (b byte, err error) {
if h.reader != nil {
b, err = h.reader.ReadByte()
} else {
err = io.ErrClosedPipe
}
return
}
func (h *Reader) ReadAll() (p []byte, err error) {
if h.reader != nil {
p, err = io.ReadAll(h.reader)
} else {
err = io.ErrClosedPipe
}
return
}
func (h *Reader) ReadString(delim byte) (s string, err error) {
if h.reader != nil {
s, err = h.reader.ReadString(delim)
} else {
err = io.ErrClosedPipe
}
return
}
func (h *Reader) Reset() (err error) {
if h.fh != nil {
if _, err = h.fh.Seek(0, 0); err == nil {
h.reader.Reset(h.fh)
}
}
return
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// reader.go
package file
import "testing"
func TestOpenReader(t *testing.T) {
r, err := OpenReader("t_reader_test.go")
if err != nil {
t.Fatalf("OpenReader failed: %v", err)
}
defer r.Close()
if !r.Valid() {
t.Fatal("Reader should be valid after opening")
}
if r.TypeName() != "fileReader" {
t.Fatalf("Expected TypeName 'fileReader', got '%s'", r.TypeName())
}
if r.String() != "reader" {
t.Fatalf("Expected String 'reader', got '%s'", r.String())
}
// GetName may return either "t_reader_test.go" or "./t_reader_test.go" depending on the environment
name := r.GetName()
if (name != "t_reader_test.go") && (name != "./t_reader_test.go") {
t.Fatalf("Expected GetName 't_reader_test.go' or './t_reader_test.go', got '%s'", name)
}
// Test reading a byte
b, err := r.ReadByte()
if err != nil {
t.Fatalf("ReadByte failed: %v", err)
}
if b == 0 {
t.Fatal("ReadByte should not return zero byte")
}
err = r.Reset()
if err != nil {
t.Fatalf("Reset failed: %v", err)
}
if s, err := r.ReadString('\n'); err != nil {
t.Fatalf("ReadString failed: %v", err)
} else {
t.Logf("ReadString: %s", s)
}
// Test reading all content
content, err := r.ReadAll()
if err != nil {
t.Fatalf("ReadAll failed: %v", err)
}
if len(content) == 0 {
t.Fatal("ReadAll should return non-empty content")
}
}
+69
View File
@@ -0,0 +1,69 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// writer.go
package file
import "testing"
func TestCreateWriter(t *testing.T) {
w, err := CreateWriter("/tmp/test_writer.txt")
if err != nil {
t.Fatalf("CreateWriter failed: %v", err)
}
defer w.Close()
if !w.Valid() {
t.Fatal("Writer should be valid after creation")
}
if w.TypeName() != "fileWriter" {
t.Fatalf("Expected TypeName 'fileWriter', got '%s'", w.TypeName())
}
if w.String() != "writer" {
t.Fatalf("Expected String 'writer', got '%s'", w.String())
}
name := w.GetName()
if name != "/tmp/test_writer.txt" {
t.Fatalf("Expected GetName '/tmp/test_writer.txt', got '%s'", name)
}
if n, err := w.Write("Hello, World!\n"); err != nil {
t.Fatalf("Write failed: %v", err)
} else if n != len("Hello, World!\n") {
t.Fatalf("Expected to write %d bytes, wrote %d", len("Hello, World!\n"), n)
}
if n, err := w.Writef("This is a %s.\n", "test"); err != nil {
t.Fatalf("Writef failed: %v", err)
} else if n != len("This is a test.\n") {
t.Fatalf("Expected to write %d bytes, wrote %d", len("This is a test.\n"), n)
}
}
func TestAppendWriter(t *testing.T) {
w, err := AppendWriter("/tmp/test_writer.txt")
if err != nil {
t.Fatalf("AppendWriter failed: %v", err)
}
defer w.Close()
if !w.Valid() {
t.Fatal("Writer should be valid after opening for append")
}
if w.TypeName() != "fileWriter" {
t.Fatalf("Expected TypeName 'fileWriter', got '%s'", w.TypeName())
}
if w.String() != "writer" {
t.Fatalf("Expected String 'writer', got '%s'", w.String())
}
name := w.GetName()
if name != "/tmp/test_writer.txt" {
t.Fatalf("Expected GetName '/tmp/test_writer.txt', got '%s'", name)
}
}
+82
View File
@@ -0,0 +1,82 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// writer.go
package file
import (
"bufio"
"fmt"
"os"
)
type Writer struct {
// fh *os.File
handleBase
writer *bufio.Writer
}
func NewWriter(fh *os.File) *Writer {
return &Writer{handleBase: handleBase{fh: fh}, writer: bufio.NewWriter(fh)}
}
func CreateWriter(filePath string) (w *Writer, err error) {
var fh *os.File
if fh, err = os.Create(filePath); err == nil {
w = NewWriter(fh)
}
return
}
func AppendWriter(filePath string) (w *Writer, err error) {
var fh *os.File
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644); err == nil {
w = NewWriter(fh)
}
return
}
func (w *Writer) TypeName() string {
return "fileWriter"
}
func (w *Writer) String() string {
return "writer"
}
func (w *Writer) Valid() bool {
return w.handleBase.Valid() && w.writer != nil
}
func (w *Writer) Close() (err error) {
var err1 error
if w.writer != nil {
err1 = w.Flush()
w.writer = nil
}
if err = w.handleBase.Close(); err == nil {
err = err1
}
return
}
func (w *Writer) Flush() (err error) {
if w.writer != nil {
err = w.writer.Flush()
}
return
}
func (w *Writer) Write(args ...any) (n int, err error) {
if w.writer != nil {
n, err = fmt.Fprint(w.writer, args...)
}
return
}
func (w *Writer) Writef(format string, args ...any) (n int, err error) {
if w.writer != nil {
n, err = fmt.Fprintf(w.writer, format, args...)
}
return
}
-387
View File
@@ -1,387 +0,0 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// function.go
package expr
import (
"fmt"
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
)
// ---- Function template
// type FuncTemplate func(ctx expr.ExprContext, name string, args map[string]any) (result any, err error)
// ---- Common functor definition
type BaseFunctor struct {
info kern.ExprFunc
}
func (functor *BaseFunctor) ToString(opt kern.FmtOpt) (s string) {
if functor.info != nil {
s = functor.info.ToString(opt)
} else {
s = "func(){}"
}
return s
}
func (functor *BaseFunctor) GetParams() (params []kern.ExprFuncParam) {
if functor.info != nil {
return functor.info.Params()
} else {
return []kern.ExprFuncParam{}
}
}
func (functor *BaseFunctor) SetFunc(info kern.ExprFunc) {
functor.info = info
}
func (functor *BaseFunctor) GetFunc() kern.ExprFunc {
return functor.info
}
func (functor *BaseFunctor) GetDefinitionContext() kern.ExprContext {
return nil
}
// ---- Function Parameters
type paramFlags uint16
const (
PfDefault paramFlags = 1 << iota
PfOptional
PfRepeat
)
type funcParamInfo struct {
name string
flags paramFlags
defaultValue any
}
func NewFuncParam(name string) kern.ExprFuncParam {
return &funcParamInfo{name: name}
}
func NewFuncParamFlag(name string, flags paramFlags) kern.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 kern.TypeAny
}
func (param *funcParamInfo) IsDefault() bool {
return (param.flags & PfDefault) != 0
}
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
// funcInfo implements expr.ExprFunc
type funcInfo struct {
name string
minArgs int
maxArgs int
functor kern.Functor
formalParams []kern.ExprFuncParam
returnType string
}
func newFuncInfo(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (info *funcInfo, err error) {
var minArgs = 0
var maxArgs = 0
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.IsDefault() || 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() {
minArgs--
maxArgs = -1
}
}
info = &funcInfo{
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params,
}
functor.SetFunc(info)
return info, nil
}
func (info *funcInfo) Params() []kern.ExprFuncParam {
return info.formalParams
}
func (info *funcInfo) ReturnType() string {
return info.returnType
}
func (info *funcInfo) ToString(opt kern.FmtOpt) string {
var sb strings.Builder
if len(info.Name()) == 0 {
sb.WriteString("func")
} else {
sb.WriteString(info.Name())
}
sb.WriteByte('(')
if info.formalParams != nil {
for i, p := range info.formalParams {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(p.Name())
if p.IsDefault() {
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(kern.TypeAny)
}
sb.WriteString("{}")
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() kern.Functor {
return info.functor
}
func (info *funcInfo) AllocContext(parentCtx kern.ExprContext) (ctx kern.ExprContext) {
if defCtx := info.functor.GetDefinitionContext(); defCtx != nil {
ctx = defCtx.Clone()
ctx.SetParent(defCtx)
} else {
ctx = parentCtx.Clone()
ctx.SetParent(parentCtx)
}
return
}
func (info *funcInfo) ParamSpec(paramName string) kern.ExprFuncParam {
for _, spec := range info.formalParams {
if spec.Name() == paramName {
return spec
}
}
return nil
}
func initActualParams(ctx kern.ExprContext, info kern.ExprFunc, callTerm *term) (actualParams map[string]any, err error) {
var varArgs []any
var varName string
namedParamsStarted := false
formalParams := info.Params()
actualParams = make(map[string]any, len(formalParams))
if callTerm == nil {
return
}
for i, tree := range callTerm.children {
var paramValue any
paramCtx := ctx.Clone()
if paramValue, err = tree.Compute(paramCtx); err != nil {
break
}
if paramName, namedParam := kern.GetAssignVarName(tree); namedParam {
if info.ParamSpec(paramName) == nil {
err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName)
break
}
actualParams[paramName] = paramValue
namedParamsStarted = true
} else if !namedParamsStarted {
if varArgs != nil {
varArgs = append(varArgs, paramValue)
} else if i < len(formalParams) {
spec := formalParams[i]
if spec.IsRepeat() {
varArgs = make([]any, 0, len(callTerm.children)-i)
varArgs = append(varArgs, paramValue)
varName = spec.Name()
} else {
actualParams[spec.Name()] = paramValue
}
} else {
err = kern.ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children))
break
}
} else {
err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", info.Name(), i+1)
break
}
}
if err == nil {
if varArgs != nil {
actualParams[varName] = varArgs
}
}
return
}
func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) {
passedCount := len(actualParams)
if info.MinArgs() > passedCount {
err = kern.ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
return
}
if passedCount < len(info.formalParams) {
for _, p := range info.formalParams {
if _, exists := actualParams[p.Name()]; !exists {
if !p.IsDefault() {
break
}
if p.IsRepeat() {
varArgs := make([]any, 1)
varArgs[0] = p.DefaultValue()
actualParams[p.Name()] = varArgs
} else {
actualParams[p.Name()] = p.DefaultValue()
}
}
}
}
if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) {
err = kern.ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
}
return
}
// ----- Call a function ---
// func getAssignVarName(t *term) (name string, ok bool) {
// if ok = t.symbol() == SymEqual; ok {
// name = t.children[0].source()
// }
// return
// }
// func CallFunctionByTerm(parentCtx expr.ExprContext, name string, callTerm *term) (result any, err error) {
// var actualParams map[string]any
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil {
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// functor := info.Functor()
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
// func CallFunctionByArgs(parentCtx expr.ExprContext, name string, args []any) (result any, err error) {
// var actualParams map[string]any
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// functor := info.Functor()
// actualParams = bindActualParams(functor, args)
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
// func CallFunctionByParams(parentCtx expr.ExprContext, name string, actualParams map[string]any) (result any, err error) {
// //var actualParams map[string]any
// if info, exists := GetFuncInfo(parentCtx, name); exists {
// functor := info.Functor()
// ctx := info.AllocContext(parentCtx)
// if err = info.PrepareCall(name, actualParams); err == nil {
// result, err = functor.InvokeNamed(ctx, name, actualParams)
// exportObjectsToParent(ctx)
// }
// } else {
// err = fmt.Errorf("unknown function %s()", name)
// }
// return
// }
// func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) {
// if value, exists = args[paramName]; !exists {
// if paramNum > 0 && paramNum <= len(args) {
// value, exists = args["arg"+strconv.Itoa(paramNum)]
// }
// }
// return
// }
// func bindActualParams(functor Functor, args []any) (actualParams map[string]any) {
// formalParams := functor.GetParams()
// actualParams = make(map[string]any, len(args))
// for i, arg := range args {
// if i < len(formalParams) {
// actualParams[formalParams[i].Name()] = arg
// } else {
// actualParams["arg"+strconv.Itoa(i+1)] = arg
// }
// }
// return
// }
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// global-context.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
//go:build graph
+7 -6
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// helpers.go
@@ -11,14 +11,15 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
"git.portale-stac.it/go-pkg/expr/util"
)
func EvalString(ctx kern.ExprContext, source string) (result any, err error) {
var tree *ast
var tree *scan.Ast
r := strings.NewReader(source)
scanner := NewScanner(r, DefaultTranslations())
scanner := scan.NewScanner(r, scan.DefaultTranslations())
parser := NewParser()
if tree, err = parser.Parse(scanner); err == nil {
@@ -44,7 +45,7 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
functor := kern.NewGolangFunctor(f)
// ctx.RegisterFunc(arg.Name, functor, 0, -1)
ctx.RegisterFunc(arg.Name, functor, kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, 0),
kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault|kern.PfRepeat, 0),
})
} else {
err = fmt.Errorf("invalid function specification: %q", arg.Name)
@@ -69,8 +70,8 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
}
func EvalStream(ctx kern.ExprContext, r io.Reader) (result any, err error) {
var tree *ast
scanner := NewScanner(r, DefaultTranslations())
var tree *scan.Ast
scanner := scan.NewScanner(r, scan.DefaultTranslations())
parser := NewParser()
if tree, err = parser.Parse(scanner); err == nil {
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// import-utils.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// int-iterator.go
+18 -3
View File
@@ -1,14 +1,17 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// iter-factory.go
package expr
import (
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
func NewIterator(value any) (it kern.Iterator, err error) {
func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Iterator, err error) {
if value == nil {
return NewArrayIterator([]any{}), nil
}
@@ -21,9 +24,21 @@ func NewIterator(value any) (it kern.Iterator, err error) {
case []any:
it = NewArrayIterator(v)
case kern.Iterator:
it = v
// var exprs []*scan.Term
it, err = NewIterIter(v, ctx, ops)
default:
it = NewArrayIterator([]any{value})
}
return
}
func HasIterStandardOperations(name string) bool {
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
}
func HasIterOperations(name string, ops ...string) bool {
return slices.Contains([]string{
kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName,
}, name) ||
slices.Contains(ops, name)
}
+135
View File
@@ -0,0 +1,135 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// iter-iter.go
package expr
import (
"fmt"
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
const iterIterType = "IterIter"
type IterIter struct {
it kern.Iterator
count int64
index int64
ctx kern.ExprContext
exprList []*scan.Term
current any
}
func NewIterIter(it kern.Iterator, ctx kern.ExprContext, exprs []*scan.Term) (iter kern.Iterator, err error) {
if ctx == nil {
err = fmt.Errorf("context is required for %s", iterIterType)
} else if it == nil {
err = fmt.Errorf("source iterator is required for %s", iterIterType)
} else {
iter = &IterIter{it: it, count: 0, index: -1, ctx: ctx, exprList: exprs, current: nil}
}
return
}
func (it *IterIter) String() string {
return fmt.Sprintf("$(%s)", it.it)
}
func (it *IterIter) TypeName() string {
return iterIterType
}
func (it *IterIter) HasOperation(name string) bool {
return HasIterStandardOperations(name)
}
func (it *IterIter) CallOperation(name string, args map[string]any) (v any, err error) {
switch name {
case kern.NextName:
v, err = it.Next()
case kern.ResetName:
err = it.Reset()
case kern.CleanName:
err = it.Clean()
case kern.IndexName:
v = int64(it.Index())
case kern.CurrentName:
v, err = it.Current()
case kern.CountName:
v = it.count
default:
err = kern.ErrNoOperation(name)
}
return
}
func (it *IterIter) Current() (item any, err error) {
if it.current != nil {
item = it.current
} else if len(it.exprList) > 0 {
// Evaluate the expression list and use the result as the current item
var exprValue any
for _, expr := range it.exprList {
if exprValue, err = expr.Compute(it.ctx); err != nil {
break
}
it.ctx.UnsafeSetVar(kern.ControlLastResult, exprValue)
}
if err == nil {
item = exprValue
}
} else {
var exists bool
if it.current, exists = it.ctx.GetVar("_"); !exists {
err = fmt.Errorf("current item not available")
} else {
item = it.current
}
}
return
}
func (it *IterIter) Next() (item any, err error) {
var src any
it.current = nil
ctx := it.ctx
for src, err = it.it.Next(); src == nil && err == nil; src, err = it.it.Next() {
}
if err == nil {
if src == nil {
err = io.EOF
} else {
ctx.UnsafeSetVar("_", src)
ctx.UnsafeSetVar("__", it.it.Index())
ctx.UnsafeSetVar("_#", it.it.Count())
item, err = it.Current()
ctx.DeleteVar("_#")
ctx.DeleteVar("__")
ctx.DeleteVar("_")
}
}
return
}
func (it *IterIter) Index() int64 {
return it.index
}
func (it *IterIter) Count() int64 {
return it.count
}
func (it *IterIter) Reset() error {
it.index = -1
it.count = 0
return nil
}
func (it *IterIter) Clean() error {
return nil
}
+6 -6
View File
@@ -1,23 +1,23 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// bind-go-function.go
package kern
// ---- Linking with Go functions
type golangFunctor struct {
type GolangFunctor struct {
BaseFunctor
f FuncTemplate
}
func NewGolangFunctor(f FuncTemplate) *golangFunctor {
return &golangFunctor{f: f}
func NewGolangFunctor(f FuncTemplate) *GolangFunctor {
return &GolangFunctor{f: f}
}
func (functor *golangFunctor) TypeName() string {
func (functor *GolangFunctor) TypeName() string {
return "GoFunctor"
}
func (functor *golangFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) {
func (functor *GolangFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) {
return functor.f(ctx, name, args)
}
+5 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// common-errors.go
@@ -84,6 +84,10 @@ func ErrUnknownVar(funcName, varName string) error {
return fmt.Errorf("%s(): unknown variable %q", funcName, varName)
}
func ErrFuncInvalidArg(funcName, details string) error {
return fmt.Errorf("%s(): invalid argument -- %s", funcName, details)
}
// --- Operator errors
func ErrLeftOperandMustBeVariable(leftTerm, opTerm Term) error {
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// common-params.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// common-type-names.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// context-helpers.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// control.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// dict-type.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// expr-context.go
+6 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// expr-function.go
@@ -37,3 +37,8 @@ type ExprFunc interface {
PrepareCall(name string, actualParams map[string]any) (err error)
AllocContext(parentCtx ExprContext) (ctx ExprContext)
}
func IsFunctor(v any) (ok bool) {
_, ok = v.(Functor)
return
}
+12
View File
@@ -0,0 +1,12 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// expr.go
package kern
// ----Expression interface
type Expr interface {
Typer
Eval(ctx ExprContext) (result any, err error)
String() string
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// formatter.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// fraction-type.go
+164
View File
@@ -0,0 +1,164 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// func-info.go
package kern
import (
"fmt"
"strings"
)
// --- Functions
// FuncInfo implements expr.ExprFunc
type FuncInfo struct {
name string
minArgs int
maxArgs int
functor Functor
formalParams []ExprFuncParam
returnType string
}
func NewFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *FuncInfo, err error) {
var minArgs = 0
var maxArgs = 0
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.IsDefault() || 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() {
minArgs--
maxArgs = -1
}
}
info = &FuncInfo{
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params,
}
functor.SetFunc(info)
return info, nil
}
func (info *FuncInfo) Params() []ExprFuncParam {
return info.formalParams
}
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.formalParams != nil {
for i, p := range info.formalParams {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(p.Name())
if p.IsDefault() {
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("{}")
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 (info *FuncInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) {
if defCtx := info.functor.GetDefinitionContext(); defCtx != nil {
ctx = defCtx.Clone()
ctx.SetParent(defCtx)
} else {
ctx = parentCtx.Clone()
ctx.SetParent(parentCtx)
}
return
}
func (info *FuncInfo) ParamSpec(paramName string) ExprFuncParam {
for _, spec := range info.formalParams {
if spec.Name() == paramName {
return spec
}
}
return nil
}
func (info *FuncInfo) PrepareCall(name string, actualParams map[string]any) (err error) {
passedCount := len(actualParams)
if info.MinArgs() > passedCount {
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
return
}
if passedCount < len(info.formalParams) {
for _, p := range info.formalParams {
if _, exists := actualParams[p.Name()]; !exists {
if !p.IsDefault() {
break
}
if p.IsRepeat() {
varArgs := make([]any, 1)
varArgs[0] = p.DefaultValue()
actualParams[p.Name()] = varArgs
} else {
actualParams[p.Name()] = p.DefaultValue()
}
}
}
}
if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) {
err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
}
return
}
+6 -11
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// function.go
@@ -14,11 +14,6 @@ type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (resul
type DeepFuncTemplate func(a, b any) (eq bool, err error)
func IsFunctor(v any) (ok bool) {
_, ok = v.(Functor)
return
}
// ---- Common functor definition
type BaseFunctor struct {
info ExprFunc
@@ -54,17 +49,17 @@ func (functor *BaseFunctor) GetDefinitionContext() ExprContext {
}
// ---- Function Parameters
type paramFlags uint16
type FuncParamFlags uint16
const (
PfDefault paramFlags = 1 << iota
PfDefault FuncParamFlags = 1 << iota
PfOptional
PfRepeat
)
type funcParamInfo struct {
name string
flags paramFlags
flags FuncParamFlags
defaultValue any
}
@@ -72,11 +67,11 @@ func NewFuncParam(name string) ExprFuncParam {
return &funcParamInfo{name: name}
}
func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam {
func NewFuncParamFlag(name string, flags FuncParamFlags) ExprFuncParam {
return &funcParamInfo{name: name, flags: flags}
}
func NewFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo {
func NewFuncParamFlagDef(name string, flags FuncParamFlags, defValue any) *funcParamInfo {
return &funcParamInfo{name: name, flags: flags, defaultValue: defValue}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// iterator.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// list-type.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// term.go
+1 -1
View File
@@ -1,6 +1,6 @@
//go:build darwin
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-darwin.go
+1 -1
View File
@@ -1,6 +1,6 @@
//go:build linux
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-linux.go
+1 -1
View File
@@ -1,6 +1,6 @@
//go:build windows
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// lib-ext-windows.go
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// list-iterator.go
+12 -11
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-dict.go
@@ -6,23 +6,24 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- dict term
func newDictTerm(args map[any]*term) *term {
return &term{
tk: *NewValueToken(0, 0, SymDict, "{}", args),
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalDict,
func newDictTerm(args map[any]*scan.Term) *scan.Term {
return &scan.Term{
Tk: *scan.NewValueToken(0, 0, scan.SymDict, "{}", args),
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalDict,
}
}
// -------- dict func
func evalDict(ctx kern.ExprContext, opTerm *term) (v any, err error) {
dict, _ := opTerm.value().(map[any]*term)
func evalDict(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
dict, _ := opTerm.Value().(map[any]*scan.Term)
items := make(kern.DictType, len(dict))
for key, tree := range dict {
var param any
+14 -13
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-expr.go
@@ -8,27 +8,28 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- expr term
func newExprTerm(root *term) *term {
tk := NewValueToken(root.tk.row, root.tk.col, SymExpression, root.Source(), root)
return &term{
tk: *tk,
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalExpr,
func newExprTerm(root *scan.Term) *scan.Term {
tk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymExpression, root.Source(), root)
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalExpr,
}
}
// -------- eval expr
func evalExpr(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if ast, ok := opTerm.value().(*term); ok {
func evalExpr(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
if ast, ok := opTerm.Value().(*scan.Term); ok {
v, err = ast.Compute(ctx)
} else {
err = fmt.Errorf("expression expected, got %T", opTerm.value())
err = fmt.Errorf("expression expected, got %T", opTerm.Value())
}
return
}
+36 -35
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-func.go
@@ -8,31 +8,32 @@ import (
"errors"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- function call term
func newFuncCallTerm(tk *Token, args []*term) *term {
var pos termPosition = posLeaf
func newFuncCallTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
var pos scan.TermPosition = scan.PosLeaf
if len(args) > 0 {
pos = posMultifix
pos = scan.PosMultifix
}
return &term{
tk: *tk,
parent: nil,
children: args,
position: pos,
priority: priValue,
evalFunc: evalFuncCall,
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: args,
Position: pos,
Priority: scan.PriValue,
EvalFunc: evalFuncCall,
}
}
// -------- eval func call
// func _evalFuncCall(ctx ExprContext, opTerm *term) (v any, err error) {
// name, _ := opTerm.tk.Value.(string)
// params := make([]any, len(opTerm.children), len(opTerm.children)+5)
// for i, tree := range opTerm.children {
// name, _ := opTerm.Tk.Value.(string)
// params := make([]any, len(opTerm.Children), len(opTerm.Children)+5)
// for i, tree := range opTerm.Children {
// var param any
// if param, err = tree.compute(ctx); err != nil {
// if param, err = tree.Compute(ctx); err != nil {
// break
// }
// params[i] = param
@@ -44,39 +45,39 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
// return
// }
func evalFuncCall(ctx kern.ExprContext, opTerm *term) (v any, err error) {
name, _ := opTerm.tk.Value.(string)
func evalFuncCall(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
name, _ := opTerm.Tk.Value.(string)
v, err = kern.CallFunctionByTerm(ctx, name, opTerm)
return
}
// -------- function definition term
func newFuncDefTerm(tk *Token, args []*term) *term {
return &term{
tk: *tk, // value is the expression body
parent: nil,
children: args, // function params
position: posLeaf,
priority: priValue,
evalFunc: evalFuncDef,
func newFuncDefTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
return &scan.Term{
Tk: *tk, // value is the expression body
Parent: nil,
Children: args, // function params
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalFuncDef,
}
}
// -------- eval func def
func evalFuncDef(ctx kern.ExprContext, opTerm *term) (v any, err error) {
bodySpec := opTerm.value()
if ast, ok := bodySpec.(*ast); ok {
paramList := make([]kern.ExprFuncParam, 0, len(opTerm.children))
for _, param := range opTerm.children {
func evalFuncDef(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
bodySpec := opTerm.Value()
if ast, ok := bodySpec.(*scan.Ast); ok {
paramList := make([]kern.ExprFuncParam, 0, len(opTerm.Children))
for _, param := range opTerm.Children {
var defValue any
flags := paramFlags(0)
if len(param.children) > 0 {
flags |= PfDefault
if defValue, err = param.children[0].Compute(ctx); err != nil {
flags := kern.FuncParamFlags(0)
if len(param.Children) > 0 {
flags |= kern.PfDefault
if defValue, err = param.Children[0].Compute(ctx); err != nil {
return
}
}
info := NewFuncParamFlagDef(param.Source(), flags, defValue)
info := kern.NewFuncParamFlagDef(param.Source(), flags, defValue)
paramList = append(paramList, info)
}
v = newExprFunctor(ast, paramList, ctx)
+59 -27
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-iterator.go
@@ -9,25 +9,26 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- iterator term
func newIteratorTerm(tk *Token, args []*term) *term {
tk.Sym = SymIterator
return &term{
tk: *tk,
parent: nil,
children: args,
position: posLeaf,
priority: priValue,
evalFunc: evalIterator,
func newIteratorTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
tk.Sym = scan.SymIterator
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: args,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalIterator,
}
}
// -------- eval iterator
func evalTermArray(ctx kern.ExprContext, terms []*term) (values []any, err error) {
func evalTermArray(ctx kern.ExprContext, terms []*scan.Term) (values []any, err error) {
values = make([]any, len(terms))
for i, t := range terms {
var value any
@@ -40,17 +41,17 @@ func evalTermArray(ctx kern.ExprContext, terms []*term) (values []any, err error
return
}
func evalFirstChild(ctx kern.ExprContext, iteratorTerm *term) (value any, err error) {
if len(iteratorTerm.children) < 1 || iteratorTerm.children[0] == nil {
func evalFirstChild(ctx kern.ExprContext, iteratorTerm *scan.Term) (value any, err error) {
if len(iteratorTerm.Children) < 1 || iteratorTerm.Children[0] == nil {
err = iteratorTerm.Errorf("missing the data-source parameter")
return
}
value, err = iteratorTerm.children[0].Compute(ctx)
value, err = iteratorTerm.Children[0].Compute(ctx)
return
}
func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]kern.Functor, err error) {
func getDataSourceDict(iteratorTerm *scan.Term, firstChildValue any) (ds map[string]kern.Functor, err error) {
if dictAny, ok := firstChildValue.(*kern.DictType); ok {
requiredFields := []string{kern.NextName}
fieldsMask := 0b1
@@ -74,13 +75,13 @@ func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]k
missingFields = append(missingFields, field)
}
}
err = iteratorTerm.children[0].Errorf("the data-source must provide a non-nil %q operator(s)", strings.Join(missingFields, ", "))
err = iteratorTerm.Children[0].Errorf("the data-source must provide a non-nil %q operator(s)", strings.Join(missingFields, ", "))
}
}
return
}
func evalIterator(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var firstChildValue any
var ds map[string]kern.Functor
@@ -100,8 +101,8 @@ func evalIterator(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if initFunc, exists := ds[kern.InitName]; exists && initFunc != nil {
var args []any
var resource any
if len(opTerm.children) > 1 {
if args, err = evalTermArray(ctx, opTerm.children[1:]); err != nil {
if len(opTerm.Children) > 1 {
if args, err = evalTermArray(ctx, opTerm.Children[1:]); err != nil {
return
}
} else {
@@ -124,33 +125,64 @@ func evalIterator(ctx kern.ExprContext, opTerm *term) (v any, err error) {
} else {
if dictIt, ok := firstChildValue.(*kern.DictType); ok {
var args []any
if args, err = evalSibling(ctx, opTerm.children, nil); err == nil {
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
v, err = NewDictIterator(dictIt, args)
}
} else {
err = opTerm.children[0].Errorf("the data-source must be a dictionary")
err = opTerm.Children[0].Errorf("the data-source must be a dictionary")
}
}
} else if list, ok := firstChildValue.(*kern.ListType); ok {
var args []any
if args, err = evalSibling(ctx, opTerm.children, nil); err == nil {
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
v = NewListIterator(list, args)
}
} else if intVal, ok := firstChildValue.(int64); ok {
var args []any
if args, err = evalSibling(ctx, opTerm.children, intVal); err == nil {
if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil {
v, err = NewIntIterator(args)
}
} else if it, ok := firstChildValue.(kern.Iterator); ok {
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
} else {
var list []any
if list, err = evalSibling(ctx, opTerm.children, firstChildValue); err == nil {
v = NewArrayIterator(list)
var siblings []any
if siblings, err = evalSiblings(ctx, opTerm.Children, firstChildValue); err == nil {
v = NewArrayIterator(siblings)
}
}
return
}
func evalSibling(ctx kern.ExprContext, terms []*term, firstChildValue any) (list []any, err error) {
// func evalIterIter(ctx kern.ExprContext, firstChildValue any, siblings []any) (v any, err error) {
// var op kern.Functor
// var args map[string]any
// if it, ok := firstChildValue.(kern.Iterator); ok {
// if len(siblings) > 1 {
// if op, ok = siblings[1].(kern.Functor); ok {
// args = make(map[string]any, len(siblings)-2)
// for i, arg := range siblings[2:] {
// switch a := arg.(type) {
// case *kern.DictType:
// for keyAny, item := range *a {
// if key, ok := keyAny.(string); ok {
// args[key] = item
// }
// }
// default:
// args["arg"+strconv.Itoa(i+1)] = arg
// }
// }
// } else if op == nil {
// return nil, fmt.Errorf("the first sibling parameter must be a functor to be used as operation for the iterator")
// }
// }
// v, err = NewIterIter(it, ctx, op, args)
// }
// return
// }
func evalSiblings(ctx kern.ExprContext, terms []*scan.Term, firstChildValue any) (list []any, err error) {
items := make([]any, 0, len(terms))
for i, tree := range terms {
var param any
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-list.go
@@ -6,27 +6,28 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- list term
func newListTermA(args ...*term) *term {
func newListTermA(args ...*scan.Term) *scan.Term {
return newListTerm(0, 0, args)
}
func newListTerm(row, col int, args []*term) *term {
return &term{
tk: *NewValueToken(row, col, SymList, "[]", args),
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalList,
func newListTerm(row, col int, args []*scan.Term) *scan.Term {
return &scan.Term{
Tk: *scan.NewValueToken(row, col, scan.SymList, "[]", args),
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalList,
}
}
// -------- list func
func evalList(ctx kern.ExprContext, opTerm *term) (v any, err error) {
list, _ := opTerm.value().([]*term)
func evalList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
list, _ := opTerm.Value().([]*scan.Term)
items := make(kern.ListType, len(list))
for i, tree := range list {
var param any
+18 -17
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-literal.go
@@ -6,32 +6,33 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- literal term
func newLiteralTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalLiteral,
func newLiteralTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalLiteral,
}
}
// -------- eval func
func evalLiteral(ctx kern.ExprContext, opTerm *term) (v any, err error) {
v = opTerm.tk.Value
func evalLiteral(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
v = opTerm.Tk.Value
return
}
// init
func init() {
registerTermConstructor(SymString, newLiteralTerm)
registerTermConstructor(SymInteger, newLiteralTerm)
registerTermConstructor(SymFloat, newLiteralTerm)
registerTermConstructor(SymFraction, newLiteralTerm)
registerTermConstructor(SymBool, newLiteralTerm)
registerTermConstructor(SymKwNil, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymString, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymInteger, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymFloat, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymFraction, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymBool, newLiteralTerm)
scan.RegisterTermConstructor(scan.SymKwNil, newLiteralTerm)
}
+17 -16
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-selector-case.go
@@ -9,19 +9,20 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- selector case term
type selectorCase struct {
filterList *term
caseExpr Expr
filterList *scan.Term
caseExpr kern.Expr
}
func (sc *selectorCase) String() string {
var sb strings.Builder
if sc.filterList != nil {
sc.filterList.toString(&sb)
sc.filterList.ToString(&sb)
sb.WriteByte(' ')
}
sb.WriteByte('{')
@@ -30,23 +31,23 @@ func (sc *selectorCase) String() string {
return sb.String()
}
func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term {
tk := NewValueToken(row, col, SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
return &term{
tk: *tk,
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalSelectorCase,
func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr) *scan.Term {
tk := scan.NewValueToken(row, col, scan.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalSelectorCase,
}
}
// -------- eval selector case
func evalSelectorCase(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var ok bool
if v, ok = opTerm.value().(*selectorCase); !ok {
err = fmt.Errorf("selector-case expected, got %T", opTerm.value())
if v, ok = opTerm.Value().(*selectorCase); !ok {
err = fmt.Errorf("selector-case expected, got %T", opTerm.Value())
}
return
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-var.go
@@ -8,24 +8,25 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- variable term
func newVarTerm(tk *Token) *term {
t := &term{
tk: *tk,
parent: nil,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalVar,
func newVarTerm(tk *scan.Token) *scan.Term {
t := &scan.Term{
Tk: *tk,
Parent: nil,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalVar,
}
t.tk.Sym = SymVariable
t.Tk.Sym = scan.SymVariable
return t
}
// -------- eval func
func evalVar(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalVar(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var exists bool
name := opTerm.Source()
if v, exists = ctx.GetVar(name); !exists {
@@ -40,5 +41,5 @@ func evalVar(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymIdentifier, newVarTerm)
scan.RegisterTermConstructor(scan.SymIdentifier, newVarTerm)
}
+61 -60
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserightChilded.
// operator-assign.go
@@ -6,22 +6,23 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
"git.portale-stac.it/go-pkg/expr/util"
)
//-------- assign term
func newAssignTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priAssign,
evalFunc: evalAssign,
func newAssignTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriAssign,
EvalFunc: evalAssign,
}
}
func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *term, value any) (err error) {
func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *scan.Term, value any) (err error) {
var collectionValue, keyListValue, keyValue any
var keyList *kern.ListType
var ok bool
@@ -56,32 +57,32 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *ter
return
}
func assignValue(ctx kern.ExprContext, leftTerm *term, v any) (err error) {
if leftTerm.symbol() == SymIndex {
err = assignCollectionItem(ctx, leftTerm.children[0], leftTerm.children[1], v)
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any) (err error) {
if leftTerm.Symbol() == scan.SymIndex {
err = assignCollectionItem(ctx, leftTerm.Children[0], leftTerm.Children[1], v)
} else {
ctx.UnsafeSetVar(leftTerm.Source(), v)
}
return
}
func evalAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if err = opTerm.checkOperands(); err != nil {
func evalAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
if err = opTerm.CheckOperands(); err != nil {
return
}
leftTerm := opTerm.children[0]
leftSym := leftTerm.symbol()
if leftSym != SymVariable && leftSym != SymIndex {
err = leftTerm.tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.tk.source)
leftTerm := opTerm.Children[0]
leftSym := leftTerm.Symbol()
if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
err = leftTerm.Tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.Tk.Source())
return
}
rightChild := opTerm.children[1]
rightChild := opTerm.Children[1]
if v, err = rightChild.Compute(ctx); err == nil {
if functor, ok := v.(kern.Functor); ok {
if leftSym == SymVariable {
if leftSym == scan.SymVariable {
if info := functor.GetFunc(); info != nil {
ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params())
} else if funcDef, ok := functor.(*exprFunctor); ok {
@@ -106,17 +107,17 @@ func evalAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- assign term
func newOpAssignTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priAssign,
evalFunc: evalOpAssign,
func newOpAssignTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriAssign,
EvalFunc: evalOpAssign,
}
}
func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *term) (value any, err error) {
func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *scan.Term) (value any, err error) {
var collectionValue, keyListValue, keyValue any
var keyList *kern.ListType
var ok bool
@@ -151,52 +152,52 @@ func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *t
return
}
func getAssignValue(ctx kern.ExprContext, leftTerm *term) (value any, err error) {
if leftTerm.symbol() == SymIndex {
value, err = getCollectionItemValue(ctx, leftTerm.children[0], leftTerm.children[1])
func getAssignValue(ctx kern.ExprContext, leftTerm *scan.Term) (value any, err error) {
if leftTerm.Symbol() == scan.SymIndex {
value, err = getCollectionItemValue(ctx, leftTerm.Children[0], leftTerm.Children[1])
} else {
value, _ = ctx.GetVar(leftTerm.Source())
}
return
}
func evalOpAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue, leftValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
leftTerm := opTerm.children[0]
leftSym := leftTerm.symbol()
if leftSym != SymVariable && leftSym != SymIndex {
err = leftTerm.tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.tk.source)
leftTerm := opTerm.Children[0]
leftSym := leftTerm.Symbol()
if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
err = leftTerm.Tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.Tk.Source())
return
}
rightChild := opTerm.children[1]
rightChild := opTerm.Children[1]
if rightValue, err = rightChild.Compute(ctx); err == nil {
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
switch opTerm.symbol() {
case SymPlusEqual:
switch opTerm.Symbol() {
case scan.SymPlusEqual:
v, err = sumValues(opTerm, leftValue, rightValue)
case SymMinusEqual:
case scan.SymMinusEqual:
v, err = diffValues(opTerm, leftValue, rightValue)
case SymStarEqual:
case scan.SymStarEqual:
v, err = mulValues(opTerm, leftValue, rightValue)
case SymSlashEqual:
case scan.SymSlashEqual:
v, err = divValues(opTerm, leftValue, rightValue)
case SymPercEqual:
case scan.SymPercEqual:
v, err = remainderValues(opTerm, leftValue, rightValue)
case SymAmpersandEqual:
case scan.SymAmpersandEqual:
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
case SymVertBarEqual:
case scan.SymVertBarEqual:
v, err = bitwiseOr(opTerm, leftValue, rightValue)
case SymCaretEqual:
case scan.SymCaretEqual:
v, err = bitwiseXor(opTerm, leftValue, rightValue)
case SymDoubleLessEqual:
case scan.SymDoubleLessEqual:
v, err = bitLeftShift(opTerm, leftValue, rightValue)
case SymDoubleGreaterEqual:
case scan.SymDoubleGreaterEqual:
v, err = bitRightShift(opTerm, leftValue, rightValue)
default:
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
@@ -211,15 +212,15 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymEqual, newAssignTerm)
registerTermConstructor(SymPlusEqual, newOpAssignTerm)
registerTermConstructor(SymMinusEqual, newOpAssignTerm)
registerTermConstructor(SymStarEqual, newOpAssignTerm)
registerTermConstructor(SymSlashEqual, newOpAssignTerm)
registerTermConstructor(SymPercEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleLessEqual, newOpAssignTerm)
registerTermConstructor(SymDoubleGreaterEqual, newOpAssignTerm)
registerTermConstructor(SymAmpersandEqual, newOpAssignTerm)
registerTermConstructor(SymVertBarEqual, newOpAssignTerm)
registerTermConstructor(SymCaretEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymEqual, newAssignTerm)
scan.RegisterTermConstructor(scan.SymPlusEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymMinusEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymStarEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymSlashEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymPercEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymDoubleLessEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymDoubleGreaterEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymAmpersandEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymVertBarEqual, newOpAssignTerm)
scan.RegisterTermConstructor(scan.SymCaretEqual, newOpAssignTerm)
}
+49 -48
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-bitwise.go
@@ -6,24 +6,25 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- Bitwise NOT term
func newBitwiseNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priBitwiseNot,
evalFunc: evalBitwiseNot,
func newBitwiseNotTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriBitwiseNot,
EvalFunc: evalBitwiseNot,
}
}
func evalBitwiseNot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalBitwiseNot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var value any
if value, err = opTerm.evalPrefix(ctx); err != nil {
if value, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -31,24 +32,24 @@ func evalBitwiseNot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
i, _ := value.(int64)
v = ^i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(value)
err = opTerm.ErrIncompatiblePrefixPostfixType(value)
}
return
}
//-------- Bitwise AND term
func newBitwiseAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseAnd,
evalFunc: evalBitwiseAnd,
func newBitwiseAndTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBitwiseAnd,
EvalFunc: evalBitwiseAnd,
}
}
func bitwiseAnd(opTerm *term, leftValue, rightValue any) (v any, err error) {
func bitwiseAnd(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
@@ -58,15 +59,15 @@ func bitwiseAnd(opTerm *term, leftValue, rightValue any) (v any, err error) {
if lok && rok {
v = leftInt & rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseAnd(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalBitwiseAnd(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
@@ -75,17 +76,17 @@ func evalBitwiseAnd(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- Bitwise OR term
func newBitwiseOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseOr,
func newBitwiseOrTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBitwiseOr,
EvalFunc: evalBitwiseOr,
}
}
func bitwiseOr(opTerm *term, leftValue, rightValue any) (v any, err error) {
func bitwiseOr(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
@@ -95,15 +96,15 @@ func bitwiseOr(opTerm *term, leftValue, rightValue any) (v any, err error) {
if lok && rok {
v = leftInt | rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseOr(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalBitwiseOr(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -113,17 +114,17 @@ func evalBitwiseOr(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- Bitwise XOR term
func newBitwiseXorTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseXor,
func newBitwiseXorTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBitwiseXor,
EvalFunc: evalBitwiseXor,
}
}
func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) {
func bitwiseXor(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
@@ -133,15 +134,15 @@ func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) {
if lok && rok {
v = leftInt ^ rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseXor(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalBitwiseXor(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -151,8 +152,8 @@ func evalBitwiseXor(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymTilde, newBitwiseNotTerm)
registerTermConstructor(SymAmpersand, newBitwiseAndTerm)
registerTermConstructor(SymVertBar, newBitwiseOrTerm)
registerTermConstructor(SymCaret, newBitwiseXorTerm)
scan.RegisterTermConstructor(scan.SymTilde, newBitwiseNotTerm)
scan.RegisterTermConstructor(scan.SymAmpersand, newBitwiseAndTerm)
scan.RegisterTermConstructor(scan.SymVertBar, newBitwiseOrTerm)
scan.RegisterTermConstructor(scan.SymCaret, newBitwiseXorTerm)
}
+48 -47
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-bool.go
@@ -8,48 +8,49 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- NOT term
func newNotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priNot,
evalFunc: evalNot,
func newNotTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriNot,
EvalFunc: evalNot,
}
}
func evalNot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalNot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue any
if rightValue, err = opTerm.evalPrefix(ctx); err != nil {
if rightValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
if b, ok := kern.ToBool(rightValue); ok {
v = !b
} else {
err = opTerm.errIncompatiblePrefixPostfixType(rightValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(rightValue)
}
return
}
//-------- AND term
func newAndTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priAnd,
evalFunc: evalAnd,
func newAndTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriAnd,
EvalFunc: evalAnd,
}
}
func evalAnd(ctx kern.ExprContext, self *term) (v any, err error) {
func evalAnd(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) {
v, err = evalAndWithShortcut(ctx, self)
} else {
@@ -58,12 +59,12 @@ func evalAnd(ctx kern.ExprContext, self *term) (v any, err error) {
return
}
func evalAndWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
func evalAndWithoutShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
var leftValue, rightValue any
var leftBool, rightBool bool
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = self.EvalInfix(ctx); err != nil {
return
}
@@ -73,33 +74,33 @@ func evalAndWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error)
if lok && rok {
v = leftBool && rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
err = self.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalAndWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
func evalAndWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
var leftValue, rightValue any
if err = self.checkOperands(); err != nil {
if err = self.CheckOperands(); err != nil {
return
}
if leftValue, err = self.children[0].Compute(ctx); err != nil {
if leftValue, err = self.Children[0].Compute(ctx); err != nil {
return
}
if leftBool, lok := kern.ToBool(leftValue); !lok {
// err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", expr.TypeName(leftValue))
// return
err = self.errIncompatibleType(leftValue, "left")
err = self.ErrIncompatibleType(leftValue, "left")
} else if !leftBool {
v = false
} else if rightValue, err = self.children[1].Compute(ctx); err == nil {
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
if rightBool, rok := kern.ToBool(rightValue); rok {
v = rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
err = self.ErrIncompatibleTypes(leftValue, rightValue)
}
}
return
@@ -107,17 +108,17 @@ func evalAndWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
//-------- OR term
func newOrTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priOr,
evalFunc: evalOr,
func newOrTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriOr,
EvalFunc: evalOr,
}
}
func evalOr(ctx kern.ExprContext, self *term) (v any, err error) {
func evalOr(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) {
v, err = evalOrWithShortcut(ctx, self)
} else {
@@ -126,12 +127,12 @@ func evalOr(ctx kern.ExprContext, self *term) (v any, err error) {
return
}
func evalOrWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
func evalOrWithoutShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
var leftValue, rightValue any
var leftBool, rightBool bool
var lok, rok bool
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = self.EvalInfix(ctx); err != nil {
return
}
@@ -141,19 +142,19 @@ func evalOrWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error)
if lok && rok {
v = leftBool || rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
err = self.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalOrWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
func evalOrWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error) {
var leftValue, rightValue any
if err = self.checkOperands(); err != nil {
if err = self.CheckOperands(); err != nil {
return
}
if leftValue, err = self.children[0].Compute(ctx); err != nil {
if leftValue, err = self.Children[0].Compute(ctx); err != nil {
return
}
@@ -162,11 +163,11 @@ func evalOrWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
return
} else if leftBool {
v = true
} else if rightValue, err = self.children[1].Compute(ctx); err == nil {
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
if rightBool, rok := kern.ToBool(rightValue); rok {
v = rightBool
} else {
err = self.errIncompatibleTypes(leftValue, rightValue)
err = self.ErrIncompatibleTypes(leftValue, rightValue)
}
}
return
@@ -174,7 +175,7 @@ func evalOrWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymNot, newNotTerm)
registerTermConstructor(SymAnd, newAndTerm)
registerTermConstructor(SymOr, newOrTerm)
scan.RegisterTermConstructor(scan.SymNot, newNotTerm)
scan.RegisterTermConstructor(scan.SymAnd, newAndTerm)
scan.RegisterTermConstructor(scan.SymOr, newOrTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-builtin.go
@@ -8,24 +8,25 @@ import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- builtin term
func newBuiltinTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalBuiltin,
func newBuiltinTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalBuiltin,
}
}
func evalBuiltin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -36,7 +37,7 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
} else {
var moduleSpec any
var it kern.Iterator
if it, err = NewIterator(childValue); err != nil {
if it, err = NewIterator(ctx, childValue, nil); err != nil {
return
}
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
@@ -64,5 +65,5 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwBuiltin, newBuiltinTerm)
scan.RegisterTermConstructor(scan.SymKwBuiltin, newBuiltinTerm)
}
+12 -11
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-but.go
@@ -6,26 +6,27 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- but term
func newButTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBut,
evalFunc: evalBut,
func newButTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBut,
EvalFunc: evalBut,
}
}
func evalBut(ctx kern.ExprContext, opTerm *term) (v any, err error) {
_, v, err = opTerm.evalInfix(ctx)
func evalBut(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
_, v, err = opTerm.EvalInfix(ctx)
return
}
// init
func init() {
registerTermConstructor(SymKwBut, newButTerm)
scan.RegisterTermConstructor(scan.SymKwBut, newButTerm)
}
+15 -14
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-context-value.go
@@ -6,29 +6,30 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- context term
func newContextTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIncDec,
evalFunc: evalContextValue,
func newContextTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriIncDec,
EvalFunc: evalContextValue,
}
}
func evalContextValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
var sourceCtx kern.ExprContext
if len(opTerm.children) == 0 {
if len(opTerm.Children) == 0 {
sourceCtx = ctx
} else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].Source() == "global" {
} else if opTerm.Children[0].Symbol() == scan.SymVariable && opTerm.Children[0].Source() == "global" {
sourceCtx = ctx.GetGlobal()
} else if childValue, err = opTerm.evalPrefix(ctx); err == nil {
} else if childValue, err = opTerm.EvalPrefix(ctx); err == nil {
if dc, ok := childValue.(*dataCursor); ok {
sourceCtx = dc.ctx
}
@@ -53,12 +54,12 @@ func evalContextValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
v = d
}
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymDoubleDollar, newContextTerm)
scan.RegisterTermConstructor(scan.SymDoubleDollar, newContextTerm)
}
+11 -10
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-ctrl.go
@@ -6,26 +6,27 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- export all term
func newExportAllTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalExportAll,
func newExportAllTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: nil,
Position: scan.PosLeaf,
Priority: scan.PriValue,
EvalFunc: evalExportAll,
}
}
func evalExportAll(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalExportAll(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
CtrlEnable(ctx, kern.ControlExportAll)
return
}
// init
func init() {
registerTermConstructor(SymDoubleAt, newExportAllTerm)
scan.RegisterTermConstructor(scan.SymDoubleAt, newExportAllTerm)
}
+42 -41
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-default.go
@@ -6,29 +6,30 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- default term
func newDefaultTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDefault,
evalFunc: evalDefault,
func newDefaultTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriDefault,
EvalFunc: evalDefault,
}
}
func evalDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
leftTerm := opTerm.Children[0]
if leftTerm.Tk.Sym != scan.SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
@@ -36,7 +37,7 @@ func evalDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists {
v = leftValue
} else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
v = rightValue
}
return
@@ -44,32 +45,32 @@ func evalDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- alternate term
func newAlternateTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDefault,
evalFunc: evalAlternate,
func newAlternateTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriDefault,
EvalFunc: evalAlternate,
}
}
func evalAlternate(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalAlternate(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
leftTerm := opTerm.Children[0]
if leftTerm.Tk.Sym != scan.SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
}
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists && leftValue != nil {
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
v = rightValue
}
} else {
@@ -80,25 +81,25 @@ func evalAlternate(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- default assign term
func newDefaultAssignTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDefault,
evalFunc: evalAssignDefault,
func newDefaultAssignTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriDefault,
EvalFunc: evalAssignDefault,
}
}
func evalAssignDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
leftTerm := opTerm.children[0]
if leftTerm.tk.Sym != SymVariable {
leftTerm := opTerm.Children[0]
if leftTerm.Tk.Sym != scan.SymVariable {
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
return
@@ -106,11 +107,11 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists {
v = leftValue
} else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
if functor, ok := rightValue.(kern.Functor); ok {
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{
NewFuncParamFlag(kern.ParamValue, PfDefault|PfRepeat),
kern.NewFuncParamFlag(kern.ParamValue, kern.PfDefault|kern.PfRepeat),
})
} else {
v = rightValue
@@ -122,7 +123,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymDoubleQuestion, newDefaultTerm)
registerTermConstructor(SymQuestionEqual, newDefaultAssignTerm)
registerTermConstructor(SymQuestionExclam, newAlternateTerm)
scan.RegisterTermConstructor(scan.SymDoubleQuestion, newDefaultTerm)
scan.RegisterTermConstructor(scan.SymQuestionEqual, newDefaultAssignTerm)
scan.RegisterTermConstructor(scan.SymQuestionExclam, newAlternateTerm)
}
+15 -14
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-digest.go
@@ -9,34 +9,35 @@ import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- digest term
func newDigestTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalDigest,
func newDigestTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriIterOp,
EvalFunc: evalDigest,
}
}
func evalDigest(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item, lastValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
@@ -45,7 +46,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *term) (v any, err error) {
ctx.SetVar("_", item)
ctx.SetVar("__", it.Index())
ctx.SetVar("_#", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
if rightValue == nil {
break
} else {
@@ -68,5 +69,5 @@ func evalDigest(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwDigest, newDigestTerm)
scan.RegisterTermConstructor(scan.SymKwDigest, newDigestTerm)
}
+24 -23
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-dot.go
@@ -6,34 +6,35 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- dot term
func newDotTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDot,
evalFunc: evalDot,
func newDotTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriDot,
EvalFunc: evalDot,
}
}
func evalDot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
indexTerm := opTerm.children[1]
indexTerm := opTerm.Children[1]
switch unboxedValue := leftValue.(type) {
case kern.ExtIterator:
if indexTerm.symbol() == SymVariable /*|| indexTerm.symbol() == SymString */ {
if indexTerm.Tk.Sym == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ {
opName := indexTerm.Source()
if unboxedValue.HasOperation(opName) {
v, err = unboxedValue.CallOperation(opName, map[string]any{})
@@ -42,27 +43,27 @@ func evalDot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
v = false
}
} else {
err = indexTerm.tk.ErrorExpectedGot("identifier")
err = indexTerm.Tk.ErrorExpectedGot("identifier")
}
case *kern.DictType:
var ok bool
s := opTerm.children[1].symbol()
if s == SymVariable || s == SymString {
src := opTerm.children[1].Source()
s := opTerm.Children[1].Tk.Sym
if s == scan.SymVariable || s == scan.SymString {
src := opTerm.Children[1].Source()
if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
src = src[1 : len(src)-1]
}
if v, ok = unboxedValue.GetItem(src); !ok {
err = opTerm.errKeyNotFound(src)
err = opTerm.Errorf("key %q not found", src)
}
} else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
if v, ok = unboxedValue.GetItem(rightValue); !ok {
err = opTerm.errKeyNotFound(rightValue)
err = opTerm.Errorf("key %q not found", rightValue)
}
}
default:
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
err = opTerm.Errorf("incompatible types: %s and %s", kern.TypeName(leftValue), kern.TypeName(rightValue))
}
}
return
@@ -70,5 +71,5 @@ func evalDot(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymDot, newDotTerm)
scan.RegisterTermConstructor(scan.SymDot, newDotTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-fact.go
@@ -8,24 +8,25 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- fact term
func newFactTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priFact,
evalFunc: evalFact,
func newFactTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPostfix,
Priority: scan.PriFact,
EvalFunc: evalFact,
}
}
func evalFact(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalFact(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue any
if leftValue, err = opTerm.evalPrefix(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
@@ -40,12 +41,12 @@ func evalFact(ctx kern.ExprContext, opTerm *term) (v any, err error) {
err = fmt.Errorf("factorial of a negative integer (%d) is not allowed", i)
}
} else {
err = opTerm.errIncompatiblePrefixPostfixType(leftValue)
err = opTerm.Errorf("incompatible type for factorial: %s", kern.TypeName(leftValue))
}
return
}
// init
func init() {
registerTermConstructor(SymExclamation, newFactTerm)
scan.RegisterTermConstructor(scan.SymExclamation, newFactTerm)
}
+19 -15
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-filter.go
@@ -9,35 +9,39 @@ import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- map term
func newFilterTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalFilter,
func newFilterTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriIterOp,
EvalFunc: evalFilter,
}
}
func evalFilter(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item any
var ok bool
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue))
if it, ok = leftValue.(kern.Iterator); !ok {
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
}
values := kern.NewListA()
@@ -45,7 +49,7 @@ func evalFilter(ctx kern.ExprContext, opTerm *term) (v any, err error) {
ctx.SetVar("_", item)
ctx.SetVar("__", it.Index())
ctx.SetVar("_#", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
if success, valid := kern.ToBool(rightValue); valid {
if success {
values.AppendItem(item)
@@ -70,5 +74,5 @@ func evalFilter(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwFilter, newFilterTerm)
scan.RegisterTermConstructor(scan.SymKwFilter, newFilterTerm)
}
+13 -13
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operand-fraction.go
@@ -10,27 +10,27 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- fraction term
func newFractionTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 2),
position: posInfix,
priority: priFraction,
evalFunc: evalFraction,
func newFractionTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriFraction,
EvalFunc: evalFraction,
}
}
// -------- eval func
func evalFraction(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var numValue, denValue any
var num, den int64
var ok bool
if numValue, denValue, err = opTerm.evalInfix(ctx); err != nil {
if numValue, denValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
if num, ok = numValue.(int64); !ok {
@@ -42,7 +42,7 @@ func evalFraction(ctx kern.ExprContext, opTerm *term) (v any, err error) {
return
}
if den == 0 {
err = opTerm.errDivisionByZero()
err = opTerm.Errorf("division by zero")
return
}
@@ -71,5 +71,5 @@ func evalFraction(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
// registerTermConstructor(SymVertBar, newFractionTerm)
registerTermConstructor(SymColon, newFractionTerm)
scan.RegisterTermConstructor(scan.SymColon, newFractionTerm)
}
+20 -16
View File
@@ -10,43 +10,47 @@ import (
"strconv"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- group by term
func newGroupByTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalGroupBy,
func newGroupByTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriIterOp,
EvalFunc: evalGroupBy,
}
}
func evalGroupBy(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item any
var sKey string
var keyByIndex bool
var ok bool
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
if it, ok = leftValue.(kern.Iterator); !ok {
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
}
rightTk := opTerm.children[1].tk
if rightTk.IsSymbol(SymVariable) && rightTk.source == "__" {
rightTk := opTerm.Children[1].Tk
if rightTk.IsSymbol(scan.SymVariable) && rightTk.Source() == "__" {
keyByIndex = true
} else if rightValue, err = opTerm.children[1].Compute(ctx); err != nil {
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
return
} else if kern.IsString(rightValue) {
sKey = rightValue.(string)
@@ -101,5 +105,5 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwGroupBy, newGroupByTerm)
scan.RegisterTermConstructor(scan.SymKwGroupBy, newGroupByTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-in.go
@@ -6,17 +6,18 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- in term
func newInTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalIn,
func newInTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalIn,
}
}
@@ -25,10 +26,10 @@ func newInTerm(tk *Token) (inst *term) {
// return
// }
func evalIn(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalIn(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -39,12 +40,12 @@ func evalIn(ctx kern.ExprContext, opTerm *term) (v any, err error) {
dict, _ := rightValue.(*kern.DictType)
v = dict.HasKey(leftValue)
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymKwIn, newInTerm)
scan.RegisterTermConstructor(scan.SymKwIn, newInTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-include.go
@@ -6,24 +6,25 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- include term
func newIncludeTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalInclude,
func newIncludeTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalInclude,
}
}
func evalInclude(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalInclude(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -49,7 +50,7 @@ func evalInclude(ctx kern.ExprContext, opTerm *term) (v any, err error) {
count++
}
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
if err != nil {
//v = count
@@ -60,5 +61,5 @@ func evalInclude(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwInclude, newIncludeTerm)
scan.RegisterTermConstructor(scan.SymKwInclude, newIncludeTerm)
}
+19 -18
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-index.go
@@ -6,16 +6,17 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- index term
func newIndexTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priDot,
evalFunc: evalIndex,
func newIndexTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriDot,
EvalFunc: evalIndex,
}
}
@@ -24,7 +25,7 @@ func verifyKey(indexList *kern.ListType) (index any, err error) {
return
}
func verifyIndex(indexTerm *term, indexList *kern.ListType, maxValue int) (index int, err error) {
func verifyIndex(indexTerm *scan.Term, indexList *kern.ListType, maxValue int) (index int, err error) {
var v int
if v, err = kern.ToGoInt((*indexList)[0], "index expression"); err == nil {
@@ -40,7 +41,7 @@ func verifyIndex(indexTerm *term, indexList *kern.ListType, maxValue int) (index
return
}
func verifyRange(indexTerm *term, indexList *kern.ListType, maxValue int) (startIndex, endIndex int, err error) {
func verifyRange(indexTerm *scan.Term, indexList *kern.ListType, maxValue int) (startIndex, endIndex int, err error) {
v, _ := ((*indexList)[0]).(*intPair)
startIndex = v.a
endIndex = v.b
@@ -63,16 +64,16 @@ func verifyRange(indexTerm *term, indexList *kern.ListType, maxValue int) (start
return
}
func evalIndex(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var indexList *kern.ListType
var ok bool
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
indexTerm := opTerm.children[1]
indexTerm := opTerm.Children[1]
if indexList, ok = rightValue.(*kern.ListType); !ok {
err = opTerm.Errorf("invalid index expression")
return
@@ -96,7 +97,7 @@ func evalIndex(ctx kern.ExprContext, opTerm *term) (v any, err error) {
case *kern.DictType:
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
default:
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
} else if isIntPair((*indexList)[0]) {
switch unboxedValue := leftValue.(type) {
@@ -112,19 +113,19 @@ func evalIndex(ctx kern.ExprContext, opTerm *term) (v any, err error) {
v = unboxedValue[start:end]
}
default:
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
} else if kern.IsDict(leftValue) {
d := leftValue.(*kern.DictType)
v, err = getDictItem(d, indexTerm, indexList, rightValue)
} else {
rightChild := opTerm.children[1]
rightChild := opTerm.Children[1]
err = rightChild.Errorf("invalid index type: %v", (*indexList)[0])
}
return
}
func getDictItem(d *kern.DictType, indexTerm *term, indexList *kern.ListType, rightValue any) (v any, err error) {
func getDictItem(d *kern.DictType, indexTerm *scan.Term, indexList *kern.ListType, rightValue any) (v any, err error) {
var ok bool
var indexValue any
@@ -138,5 +139,5 @@ func getDictItem(d *kern.DictType, indexTerm *term, indexList *kern.ListType, ri
// init
func init() {
registerTermConstructor(SymIndex, newIndexTerm)
scan.RegisterTermConstructor(scan.SymIndex, newIndexTerm)
}
+28 -27
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-insert.go
@@ -6,34 +6,35 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- prepend term
func newPrependTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priInsert,
evalFunc: evalPrepend,
func newPrependTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriInsert,
EvalFunc: evalPrepend,
}
}
func newAppendTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priInsert,
evalFunc: evalAppend,
func newAppendTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriInsert,
EvalFunc: evalAppend,
}
}
func evalPrepend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -41,19 +42,19 @@ func evalPrepend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
list, _ := rightValue.(*kern.ListType)
newList := append(kern.ListType{leftValue}, *list...)
v = &newList
if opTerm.children[1].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[1].Source(), v)
if opTerm.Children[1].Symbol() == scan.SymVariable {
ctx.UnsafeSetVar(opTerm.Children[1].Source(), v)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalAppend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -61,11 +62,11 @@ func evalAppend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
list, _ := leftValue.(*kern.ListType)
newList := append(*list, rightValue)
v = &newList
if opTerm.children[0].symbol() == SymVariable {
ctx.UnsafeSetVar(opTerm.children[0].Source(), v)
if opTerm.Children[0].Symbol() == scan.SymVariable {
ctx.UnsafeSetVar(opTerm.Children[0].Source(), v)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
@@ -90,6 +91,6 @@ func evalAppend(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymPlusGreater, newPrependTerm)
registerTermConstructor(SymLessPlus, newAppendTerm)
scan.RegisterTermConstructor(scan.SymPlusGreater, newPrependTerm)
scan.RegisterTermConstructor(scan.SymLessPlus, newAppendTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-iter-value.go
@@ -6,31 +6,32 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- iter value term
func newIterValueTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priDereference,
evalFunc: evalIterValue,
func newIterValueTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriDereference,
EvalFunc: evalIterValue,
}
}
func evalIterValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalIterValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
if it, ok := childValue.(kern.Iterator); ok {
v, err = it.Current()
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
@@ -38,5 +39,5 @@ func evalIterValue(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
registerTermConstructor(SymDereference, newIterValueTerm)
scan.RegisterTermConstructor(scan.SymDereference, newIterValueTerm)
}
+23 -17
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-join.go
@@ -9,43 +9,49 @@ import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- join term
func newJoinTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalJoin,
func newJoinTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriIterOp,
EvalFunc: evalJoin,
}
}
func evalJoin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalJoin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var itLeft, itRight kern.Iterator
var item any
var ok bool
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
if rightValue, err = opTerm.children[1].Compute(ctx); err != nil {
if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
return
}
if itLeft, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", kern.TypeName(leftValue))
if itLeft, ok = leftValue.(kern.Iterator); !ok {
if itLeft, err = NewIterator(ctx, leftValue, nil); err != nil {
return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
}
if itRight, err = NewIterator(rightValue); err != nil {
return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", kern.TypeName(rightValue))
if itRight, ok = rightValue.(kern.Iterator); !ok {
if itRight, err = NewIterator(ctx, rightValue, nil); err != nil {
return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", kern.TypeName(rightValue))
}
}
values := kern.NewListA()
@@ -63,5 +69,5 @@ func evalJoin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwJoin, newJoinTerm)
scan.RegisterTermConstructor(scan.SymKwJoin, newJoinTerm)
}
+13 -12
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-length.go
@@ -6,24 +6,25 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- length term
func newLengthTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalLength,
func newLengthTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalLength,
}
}
func evalLength(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalLength(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -45,12 +46,12 @@ func evalLength(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// v = int64(it.Index() + 1)
// }
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymHash, newLengthTerm)
scan.RegisterTermConstructor(scan.SymHash, newLengthTerm)
}
+19 -15
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-map.go
@@ -9,35 +9,39 @@ import (
"io"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- map term
func newMapTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priIterOp,
evalFunc: evalMap,
func newMapTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriIterOp,
EvalFunc: evalMap,
}
}
func evalMap(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
var it kern.Iterator
var item any
var ok bool
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
if it, err = NewIterator(leftValue); err != nil {
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
if it, ok = leftValue.(kern.Iterator); !ok {
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
}
}
values := kern.NewListA()
@@ -45,7 +49,7 @@ func evalMap(ctx kern.ExprContext, opTerm *term) (v any, err error) {
ctx.SetVar("_", item)
ctx.SetVar("__", it.Index())
ctx.SetVar("_#", it.Count())
if rightValue, err = opTerm.children[1].Compute(ctx); err == nil {
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
values.AppendItem(rightValue)
}
ctx.DeleteVar("_#")
@@ -66,5 +70,5 @@ func evalMap(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwMap, newMapTerm)
scan.RegisterTermConstructor(scan.SymKwMap, newMapTerm)
}
+12 -11
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-plugin.go
@@ -6,25 +6,26 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- plugin term
func newPluginTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalPlugin,
func newPluginTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalPlugin,
}
}
func evalPlugin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPlugin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
var count int
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -36,5 +37,5 @@ func evalPlugin(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwPlugin, newPluginTerm)
scan.RegisterTermConstructor(scan.SymKwPlugin, newPluginTerm)
}
+30 -31
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-post-inc-dec.go
@@ -6,24 +6,24 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- post increment term
func newPostIncTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostInc,
func newPostIncTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPostfix,
Priority: scan.PriIncDec,
EvalFunc: evalPostInc,
}
}
func evalPostInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPostInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -31,8 +31,8 @@ func evalPostInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
var namePrefix string
v, err = it.Next()
if opTerm.children[0].symbol() == SymVariable {
namePrefix = opTerm.children[0].Source()
if opTerm.Children[0].Symbol() == scan.SymVariable {
namePrefix = opTerm.Children[0].Source()
}
ctx.UnsafeSetVar(namePrefix+"_index", it.Index())
if c, err1 := it.Current(); err1 == nil {
@@ -49,49 +49,48 @@ func evalPostInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
ctx.UnsafeSetVar(namePrefix+"_value", v1)
}
}
} else if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
} else if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].Source(), i+1)
ctx.SetVar(opTerm.Children[0].Source(), i+1)
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// -------- post decrement term
func newPostDecTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPostfix,
priority: priIncDec,
evalFunc: evalPostDec,
func newPostDecTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPostfix,
Priority: scan.PriIncDec,
EvalFunc: evalPostDec,
}
}
func evalPostDec(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPostDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
/* if it, ok := childValue.(Iterator); ok {
v, err = it.Next()
} else */if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
} else */if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
v = childValue
i, _ := childValue.(int64)
ctx.SetVar(opTerm.children[0].Source(), i-1)
ctx.SetVar(opTerm.Children[0].Source(), i-1)
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymDoublePlus, newPostIncTerm)
registerTermConstructor(SymDoubleMinus, newPostDecTerm)
scan.RegisterTermConstructor(scan.SymDoublePlus, newPostIncTerm)
scan.RegisterTermConstructor(scan.SymDoubleMinus, newPostDecTerm)
}
+29 -29
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-pre-inc-dec.go
@@ -6,68 +6,68 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- pre increment term
func newPreIncTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIncDec,
evalFunc: evalPreInc,
func newPreIncTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriIncDec,
EvalFunc: evalPreInc,
}
}
func evalPreInc(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPreInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
i := childValue.(int64) + 1
ctx.SetVar(opTerm.children[0].Source(), i)
ctx.SetVar(opTerm.Children[0].Source(), i)
v = i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// -------- pre decrement term
func newPreDecTerm(tk *Token) *term {
return &term{
tk: *tk,
parent: nil,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priIncDec,
evalFunc: evalPreDec,
func newPreDecTerm(tk *scan.Token) *scan.Term {
return &scan.Term{
Tk: *tk,
Parent: nil,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriIncDec,
EvalFunc: evalPreDec,
}
}
func evalPreDec(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable {
if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
i := childValue.(int64) - 1
ctx.SetVar(opTerm.children[0].Source(), i)
ctx.SetVar(opTerm.Children[0].Source(), i)
v = i
} else {
err = opTerm.errIncompatiblePrefixPostfixType(childValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
}
return
}
// init
func init() {
registerTermConstructor(SymPreInc, newPreIncTerm)
registerTermConstructor(SymPreDec, newPreDecTerm)
scan.RegisterTermConstructor(scan.SymPreInc, newPreIncTerm)
scan.RegisterTermConstructor(scan.SymPreDec, newPreDecTerm)
}
+54 -53
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-prod.go
@@ -8,21 +8,22 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- multiply term
func newMultiplyTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priProduct,
evalFunc: evalMultiply,
func newMultiplyTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriProduct,
EvalFunc: evalMultiply,
}
}
func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
func mulValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsString(leftValue) && kern.IsInteger(rightValue) {
s, _ := leftValue.(string)
n, _ := rightValue.(int64)
@@ -38,15 +39,15 @@ func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
v = leftInt * rightInt
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalMultiply(ctx kern.ExprContext, prodTerm *term) (v any, err error) {
func evalMultiply(ctx kern.ExprContext, prodTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = prodTerm.EvalInfix(ctx); err != nil {
return
}
@@ -55,22 +56,22 @@ func evalMultiply(ctx kern.ExprContext, prodTerm *term) (v any, err error) {
//-------- divide term
func newDivideTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priProduct,
evalFunc: evalDivide,
func newDivideTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriProduct,
EvalFunc: evalDivide,
}
}
func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
func divValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
d := kern.NumAsFloat(rightValue)
if d == 0.0 {
err = opTerm.errDivisionByZero()
err = opTerm.ErrDivisionByZero()
} else {
v = kern.NumAsFloat(leftValue) / d
}
@@ -79,7 +80,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
} else {
leftInt, _ := leftValue.(int64)
if rightInt, _ := rightValue.(int64); rightInt == 0 {
err = opTerm.errDivisionByZero()
err = opTerm.ErrDivisionByZero()
} else {
v = leftInt / rightInt
}
@@ -92,7 +93,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
source := leftValue.(string)
partSize := int(rightValue.(int64))
if partSize == 0 {
err = opTerm.errDivisionByZero()
err = opTerm.ErrDivisionByZero()
} else {
partCount := len(source) / partSize
remainder := len(source) % partSize
@@ -110,15 +111,15 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
v = kern.NewList(parts)
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalDivide(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalDivide(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -127,66 +128,66 @@ func evalDivide(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- divide as float term
func newDivideAsFloatTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priProduct,
evalFunc: evalDivideAsFloat,
func newDivideAsFloatTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriProduct,
EvalFunc: evalDivideAsFloat,
}
}
func evalDivideAsFloat(ctx kern.ExprContext, floatDivTerm *term) (v any, err error) {
func evalDivideAsFloat(ctx kern.ExprContext, floatDivTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = floatDivTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = floatDivTerm.EvalInfix(ctx); err != nil {
return
}
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
d := kern.NumAsFloat(rightValue)
if d == 0.0 {
err = floatDivTerm.errDivisionByZero()
err = floatDivTerm.ErrDivisionByZero()
} else {
v = kern.NumAsFloat(leftValue) / d
}
} else {
err = floatDivTerm.errIncompatibleTypes(leftValue, rightValue)
err = floatDivTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
//-------- reminder term
func newRemainderTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priProduct,
evalFunc: evalRemainder,
func newRemainderTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriProduct,
EvalFunc: evalRemainder,
}
}
func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
func remainderValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
rightInt, _ := rightValue.(int64)
if rightInt == 0 {
err = opTerm.errDivisionByZero()
err = opTerm.ErrDivisionByZero()
} else {
leftInt, _ := leftValue.(int64)
v = leftInt % rightInt
}
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalRemainder(ctx kern.ExprContext, remainderTerm *term) (v any, err error) {
func evalRemainder(ctx kern.ExprContext, remainderTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = remainderTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = remainderTerm.EvalInfix(ctx); err != nil {
return
}
@@ -195,8 +196,8 @@ func evalRemainder(ctx kern.ExprContext, remainderTerm *term) (v any, err error)
// init
func init() {
registerTermConstructor(SymStar, newMultiplyTerm)
registerTermConstructor(SymSlash, newDivideTerm)
registerTermConstructor(SymDotSlash, newDivideAsFloatTerm)
registerTermConstructor(SymPercent, newRemainderTerm)
scan.RegisterTermConstructor(scan.SymStar, newMultiplyTerm)
scan.RegisterTermConstructor(scan.SymSlash, newDivideTerm)
scan.RegisterTermConstructor(scan.SymDotSlash, newDivideAsFloatTerm)
scan.RegisterTermConstructor(scan.SymPercent, newRemainderTerm)
}
+21 -20
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-range.go
@@ -8,6 +8,7 @@ import (
"fmt"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
// -------- range term
@@ -28,35 +29,35 @@ func isIntPair(v any) bool {
return ok
}
func newRangeTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRange,
evalFunc: evalRange,
func newRangeTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRange,
EvalFunc: evalRange,
}
}
func changeColonToRange(t *term) {
if t.tk.IsSymbol(SymColon) {
t.tk.Sym = SymRange
t.evalFunc = evalRange
func changeColonToRange(t *scan.Term) {
if t.Tk.IsSymbol(scan.SymColon) {
t.Tk.Sym = scan.SymRange
t.EvalFunc = evalRange
}
}
func evalRange(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalRange(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if len(opTerm.children) == 0 {
if len(opTerm.Children) == 0 {
leftValue = int64(0)
rightValue = int64(-1)
} else if len(opTerm.children) == 1 {
if leftValue, err = opTerm.children[0].Compute(ctx); err != nil {
} else if len(opTerm.Children) == 1 {
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
return
}
rightValue = int64(kern.ConstLastIndex)
} else if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
} else if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
if !(kern.IsInteger(leftValue) && kern.IsInteger(rightValue)) {
@@ -72,15 +73,15 @@ func evalRange(ctx kern.ExprContext, opTerm *term) (v any, err error) {
return
}
func errRangeInvalidSpecification(t *term) error {
func errRangeInvalidSpecification(t *scan.Term) error {
return t.Errorf("invalid range specification")
}
func errRangeUnexpectedExpression(t *term) error {
func errRangeUnexpectedExpression(t *scan.Term) error {
return t.Errorf("unexpected range expression")
}
// init
func init() {
registerTermConstructor(SymRange, newRangeTerm)
scan.RegisterTermConstructor(scan.SymRange, newRangeTerm)
}
+64 -63
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-rel.go
@@ -8,17 +8,18 @@ import (
"reflect"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- equal term
func newEqualTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalEqual,
func newEqualTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalEqual,
}
}
@@ -49,10 +50,10 @@ func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) {
return
}
func evalEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -62,17 +63,17 @@ func evalEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- not equal term
func newNotEqualTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalNotEqual,
func newNotEqualTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalNotEqual,
}
}
func evalNotEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalNotEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
if v, err = evalEqual(ctx, opTerm); err == nil {
b, _ := kern.ToBool(v)
v = !b
@@ -82,17 +83,17 @@ func evalNotEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- less term
func newLessTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalLess,
func newLessTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalLess,
}
}
func lessThan(self *term, a, b any) (isLess bool, err error) {
func lessThan(self *scan.Term, a, b any) (isLess bool, err error) {
if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) {
if kern.IsNumber(a) && kern.IsNumber(b) {
if kern.IsInteger(a) && kern.IsInteger(b) {
@@ -118,15 +119,15 @@ func lessThan(self *term, a, b any) (isLess bool, err error) {
bList, _ := b.(*kern.ListType)
isLess = len(*aList) < len(*bList) && bList.Contains(aList)
} else {
err = self.errIncompatibleTypes(a, b)
err = self.ErrIncompatibleTypes(a, b)
}
return
}
func evalLess(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalLess(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
v, err = lessThan(opTerm, leftValue, rightValue)
@@ -135,17 +136,17 @@ func evalLess(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- less or equal term
func newLessEqualTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalLessEqual,
func newLessEqualTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalLessEqual,
}
}
func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
func lessThanOrEqual(self *scan.Term, a, b any) (isLessEq bool, err error) {
if isLessEq, err = lessThan(self, a, b); err == nil {
if !isLessEq {
if kern.IsList(a) && kern.IsList(b) {
@@ -158,10 +159,10 @@ func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
return
}
func evalLessEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalLessEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -172,20 +173,20 @@ func evalLessEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- greater term
func newGreaterTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalGreater,
func newGreaterTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalGreater,
}
}
func evalGreater(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalGreater(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -195,20 +196,20 @@ func evalGreater(ctx kern.ExprContext, opTerm *term) (v any, err error) {
//-------- greater or equal term
func newGreaterEqualTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priRelational,
evalFunc: evalGreaterEqual,
func newGreaterEqualTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriRelational,
EvalFunc: evalGreaterEqual,
}
}
func evalGreaterEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalGreaterEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -218,10 +219,10 @@ func evalGreaterEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymDoubleEqual, newEqualTerm)
registerTermConstructor(SymNotEqual, newNotEqualTerm)
registerTermConstructor(SymLess, newLessTerm)
registerTermConstructor(SymLessOrEqual, newLessEqualTerm)
registerTermConstructor(SymGreater, newGreaterTerm)
registerTermConstructor(SymGreaterOrEqual, newGreaterEqualTerm)
scan.RegisterTermConstructor(scan.SymDoubleEqual, newEqualTerm)
scan.RegisterTermConstructor(scan.SymNotEqual, newNotEqualTerm)
scan.RegisterTermConstructor(scan.SymLess, newLessTerm)
scan.RegisterTermConstructor(scan.SymLessOrEqual, newLessEqualTerm)
scan.RegisterTermConstructor(scan.SymGreater, newGreaterTerm)
scan.RegisterTermConstructor(scan.SymGreaterOrEqual, newGreaterEqualTerm)
}
+18 -17
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-selector.go
@@ -6,17 +6,18 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- selector term
func newSelectorTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 3),
position: posInfix,
priority: priSelector,
evalFunc: evalSelector,
func newSelectorTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 3),
Position: scan.PosInfix,
Priority: scan.PriSelector,
EvalFunc: evalSelector,
}
}
@@ -25,7 +26,7 @@ func trySelectorCase(ctx kern.ExprContext, exprValue, caseSel any, caseIndex int
if caseData.filterList == nil {
selectedValue, err = caseData.caseExpr.Eval(ctx)
match = true
} else if filterList, ok := caseData.filterList.value().([]*term); ok {
} else if filterList, ok := caseData.filterList.Value().([]*scan.Term); ok {
if len(filterList) == 0 {
var valueAsInt = int64(0)
if b, ok := exprValue.(bool); ok {
@@ -53,33 +54,33 @@ func trySelectorCase(ctx kern.ExprContext, exprValue, caseSel any, caseIndex int
return
}
func evalSelector(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalSelector(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var exprValue any
var match bool
if err = opTerm.checkOperands(); err != nil {
if err = opTerm.CheckOperands(); err != nil {
return
}
exprTerm := opTerm.children[0]
exprTerm := opTerm.Children[0]
if exprValue, err = exprTerm.Compute(ctx); err != nil {
return
}
caseListTerm := opTerm.children[1]
caseList, _ := caseListTerm.value().([]*term)
caseListTerm := opTerm.Children[1]
caseList, _ := caseListTerm.Value().([]*scan.Term)
for i, caseTerm := range caseList {
caseSel := caseTerm.value()
caseSel := caseTerm.Value()
if match, v, err = trySelectorCase(ctx, exprValue, caseSel, i); err != nil || match {
break
}
}
if err == nil && !match {
err = exprTerm.tk.Errorf("no case catches the value (%v) of the selection expression", exprValue)
err = exprTerm.Tk.Errorf("no case catches the value (%v) of the selection expression", exprValue)
}
return
}
// init
func init() {
registerTermConstructor(SymSelector, newSelectorTerm)
scan.RegisterTermConstructor(scan.SymSelector, newSelectorTerm)
}
+26 -25
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-shift.go
@@ -6,35 +6,36 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- bit right shift term
func newRightShiftTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinShift,
evalFunc: evalRightShift,
func newRightShiftTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBinShift,
EvalFunc: evalRightShift,
}
}
func bitRightShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
func bitRightShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt >> rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalRightShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalRightShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -42,31 +43,31 @@ func evalRightShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
return
}
func newLeftShiftTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBinShift,
evalFunc: evalLeftShift,
func newLeftShiftTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriBinShift,
EvalFunc: evalLeftShift,
}
}
func bitLeftShift(opTerm *term, leftValue, rightValue any) (v any, err error) {
func bitLeftShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
leftInt := leftValue.(int64)
rightInt := rightValue.(int64)
v = leftInt << rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalLeftShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
return
}
@@ -76,6 +77,6 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymDoubleGreater, newRightShiftTerm)
registerTermConstructor(SymDoubleLess, newLeftShiftTerm)
scan.RegisterTermConstructor(scan.SymDoubleGreater, newRightShiftTerm)
scan.RegisterTermConstructor(scan.SymDoubleLess, newLeftShiftTerm)
}
+23 -24
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-sign.go
@@ -6,61 +6,60 @@ package expr
import (
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- plus sign term
func newPlusSignTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
// class: classOperator,
// kind: kindUnknown,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalSign,
func newPlusSignTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalSign,
}
}
func newMinusSignTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalSign,
func newMinusSignTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalSign,
}
}
func evalSign(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalSign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var rightValue any
if rightValue, err = opTerm.evalPrefix(ctx); err != nil {
if rightValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
if kern.IsFloat(rightValue) {
if opTerm.tk.Sym == SymChangeSign {
if opTerm.Tk.Sym == scan.SymChangeSign {
f, _ := rightValue.(float64)
v = -f
} else {
v = rightValue
}
} else if kern.IsInteger(rightValue) {
if opTerm.tk.Sym == SymChangeSign {
if opTerm.Tk.Sym == scan.SymChangeSign {
i, _ := rightValue.(int64)
v = -i
} else {
v = rightValue
}
} else {
err = opTerm.errIncompatiblePrefixPostfixType(rightValue)
err = opTerm.ErrIncompatiblePrefixPostfixType(rightValue)
}
return
}
// init
func init() {
registerTermConstructor(SymUnchangeSign, newPlusSignTerm)
registerTermConstructor(SymChangeSign, newMinusSignTerm)
scan.RegisterTermConstructor(scan.SymUnchangeSign, newPlusSignTerm)
scan.RegisterTermConstructor(scan.SymChangeSign, newMinusSignTerm)
}
+26 -25
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-sum.go
@@ -9,21 +9,22 @@ import (
"slices"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- plus term
func newPlusTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priSum,
evalFunc: evalPlus,
func newPlusTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriSum,
EvalFunc: evalPlus,
}
}
func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) {
func sumValues(plusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if (kern.IsString(leftValue) && kern.IsNumberString(rightValue)) || (kern.IsString(rightValue) && kern.IsNumberString(leftValue)) {
v = fmt.Sprintf("%v%v", leftValue, rightValue)
} else if kern.IsNumber(leftValue) && kern.IsNumber(rightValue) {
@@ -58,15 +59,15 @@ func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) {
} else if kern.IsFraction(leftValue) && kern.IsFraction(rightValue) {
v, err = kern.SumAnyFract(leftValue, rightValue)
} else {
err = plusTerm.errIncompatibleTypes(leftValue, rightValue)
err = plusTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return v, err
}
func evalPlus(ctx kern.ExprContext, plusTerm *term) (v any, err error) {
func evalPlus(ctx kern.ExprContext, plusTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = plusTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = plusTerm.EvalInfix(ctx); err != nil {
return
}
@@ -75,17 +76,17 @@ func evalPlus(ctx kern.ExprContext, plusTerm *term) (v any, err error) {
//-------- minus term
func newMinusTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priSum,
evalFunc: evalMinus,
func newMinusTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 2),
Position: scan.PosInfix,
Priority: scan.PriSum,
EvalFunc: evalMinus,
}
}
func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
func diffValues(minusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
v = kern.NumAsFloat(leftValue) - kern.NumAsFloat(rightValue)
@@ -107,15 +108,15 @@ func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
}
v = &diffList
} else {
err = minusTerm.errIncompatibleTypes(leftValue, rightValue)
err = minusTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalMinus(ctx kern.ExprContext, minusTerm *term) (v any, err error) {
func evalMinus(ctx kern.ExprContext, minusTerm *scan.Term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = minusTerm.evalInfix(ctx); err != nil {
if leftValue, rightValue, err = minusTerm.EvalInfix(ctx); err != nil {
return
}
@@ -124,6 +125,6 @@ func evalMinus(ctx kern.ExprContext, minusTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymPlus, newPlusTerm)
registerTermConstructor(SymMinus, newMinusTerm)
scan.RegisterTermConstructor(scan.SymPlus, newPlusTerm)
scan.RegisterTermConstructor(scan.SymMinus, newMinusTerm)
}
+14 -13
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-unset.go
@@ -8,21 +8,22 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
)
//-------- unset term
func newUnsetTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 1),
position: posPrefix,
priority: priSign,
evalFunc: evalUnset,
func newUnsetTerm(tk *scan.Token) (inst *scan.Term) {
return &scan.Term{
Tk: *tk,
Children: make([]*scan.Term, 0, 1),
Position: scan.PosPrefix,
Priority: scan.PriSign,
EvalFunc: evalUnset,
}
}
func deleteContextItem(ctx kern.ExprContext, opTerm *term, item any) (deleted bool, err error) {
func deleteContextItem(ctx kern.ExprContext, opTerm *scan.Term, item any) (deleted bool, err error) {
if name, ok := item.(string); ok {
var size int
if strings.HasSuffix(name, "()") {
@@ -35,16 +36,16 @@ func deleteContextItem(ctx kern.ExprContext, opTerm *term, item any) (deleted bo
deleted = ctx.VarCount() < size
}
} else {
err = opTerm.errIncompatiblePrefixPostfixType(item)
err = opTerm.ErrIncompatiblePrefixPostfixType(item)
}
return
}
func evalUnset(ctx kern.ExprContext, opTerm *term) (v any, err error) {
func evalUnset(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
var childValue any
var deleted bool
if childValue, err = opTerm.evalPrefix(ctx); err != nil {
if childValue, err = opTerm.EvalPrefix(ctx); err != nil {
return
}
@@ -69,5 +70,5 @@ func evalUnset(ctx kern.ExprContext, opTerm *term) (v any, err error) {
// init
func init() {
registerTermConstructor(SymKwUnset, newUnsetTerm)
scan.RegisterTermConstructor(scan.SymKwUnset, newUnsetTerm)
}
+173 -172
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// parser.go
@@ -7,6 +7,7 @@ package expr
import (
"errors"
"git.portale-stac.it/go-pkg/expr/scan"
"golang.org/x/exp/constraints"
)
@@ -54,34 +55,34 @@ func NewParser() (p *parser) {
return p
}
func (parser *parser) Next(scanner *scanner) (tk *Token) {
for tk = scanner.Next(); tk.IsSymbol(SymComment); tk = scanner.Next() {
func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
for tk = scanner.Next(); tk.IsSymbol(scan.SymComment); tk = scanner.Next() {
}
return
}
func (parser *parser) parseFuncCall(scanner *scanner, ctx parserContext, tk *Token) (tree *term, err error) {
args := make([]*term, 0, 10)
func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk *scan.Token) (tree *scan.Term, err error) {
args := make([]*scan.Term, 0, 10)
itemExpected := false
lastSym := SymUnknown
for lastSym != SymClosedRound && lastSym != SymEos {
var subTree *ast
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedRound); err != nil {
lastSym := scan.SymUnknown
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
var subTree *scan.Ast
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err != nil {
break
}
prev := scanner.Previous()
if subTree.root != nil {
args = append(args, subTree.root)
if subTree.Root() != nil {
args = append(args, subTree.Root())
} else if itemExpected {
err = prev.ErrorExpectedGot("function-param-value")
break
}
itemExpected = prev.Sym == SymComma
itemExpected = prev.Sym == scan.SymComma
lastSym = scanner.Previous().Sym
}
if err == nil {
if lastSym != SymClosedRound {
if lastSym != scan.SymClosedRound {
err = errors.New("unterminated arguments list")
} else {
tree = newFuncCallTerm(tk, args)
@@ -90,18 +91,18 @@ func (parser *parser) parseFuncCall(scanner *scanner, ctx parserContext, tk *Tok
return
}
func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err error) {
// Example: "add = func(x,y) {x+y}
var body *ast
args := make([]*term, 0)
lastSym := SymUnknown
var body *scan.Ast
args := make([]*scan.Term, 0)
lastSym := scan.SymUnknown
defaultParamsStarted := false
itemExpected := false
tk := scanner.Previous()
for lastSym != SymClosedRound && lastSym != SymEos {
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
tk = parser.Next(scanner)
if tk.IsSymbol(SymIdentifier) {
param := newTerm(tk)
if tk.IsSymbol(scan.SymIdentifier) {
param := scan.NewTerm(tk)
if len(args) > 0 {
if pos := paramAlreadyDefined(args, param); pos > 0 {
err = tk.Errorf("parameter %q at position %d already defined at position %d", param.Source(), len(args)+1, pos)
@@ -110,13 +111,13 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
}
args = append(args, param)
tk = parser.Next(scanner)
if tk.Sym == SymEqual {
var paramExpr *ast
if tk.Sym == scan.SymEqual {
var paramExpr *scan.Ast
defaultParamsStarted = true
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, SymComma, SymClosedRound); err != nil {
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, scan.SymComma, scan.SymClosedRound); err != nil {
break
}
param.forceChild(paramExpr.root)
param.ForceChild(paramExpr.Root())
} else if defaultParamsStarted {
err = tk.Errorf("can't mix default and non-default parameters")
break
@@ -127,32 +128,32 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
break
}
lastSym = scanner.Previous().Sym
itemExpected = lastSym == SymComma
itemExpected = lastSym == scan.SymComma
}
if err == nil && lastSym != SymClosedRound {
if err == nil && lastSym != scan.SymClosedRound {
err = tk.ErrorExpectedGot(")")
}
if err == nil {
tk = parser.Next(scanner)
if tk.IsSymbol(SymOpenBrace) {
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, SymClosedBrace)
if tk.IsSymbol(scan.SymOpenBrace) {
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymClosedBrace)
} else {
err = tk.ErrorExpectedGot("{")
}
}
if err == nil {
if scanner.Previous().Sym != SymClosedBrace {
if scanner.Previous().Sym != scan.SymClosedBrace {
err = scanner.Previous().ErrorExpectedGot("}")
} else {
tk = scanner.makeValueToken(SymExpression, "", body)
tk = scanner.MakeValueToken(scan.SymExpression, "", body)
tree = newFuncDefTerm(tk, args)
}
}
return
}
func paramAlreadyDefined(args []*term, param *term) (position int) {
func paramAlreadyDefined(args []*scan.Term, param *scan.Term) (position int) {
position = 0
for i, arg := range args {
if arg.Source() == param.Source() {
@@ -162,39 +163,39 @@ func paramAlreadyDefined(args []*term, param *term) (position int) {
return
}
func (parser *parser) parseList(scanner *scanner, ctx parserContext) (listTerm *term, err error) {
r, c := scanner.lastPos()
args := make([]*term, 0)
lastSym := SymUnknown
func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext) (listTerm *scan.Term, err error) {
r, c := scanner.LastPos()
args := make([]*scan.Term, 0)
lastSym := scan.SymUnknown
itemExpected := false
itemCtx := remFlags(ctx, allowIndex)
for lastSym != SymClosedSquare && lastSym != SymEos {
zeroRequired := scanner.current.Sym == SymColon
var itemTree *ast
if itemTree, err = parser.parseItem(scanner, itemCtx, SymComma, SymClosedSquare); err == nil {
root := itemTree.root
for lastSym != scan.SymClosedSquare && lastSym != scan.SymEos {
zeroRequired := scanner.Current().Sym == scan.SymColon
var itemTree *scan.Ast
if itemTree, err = parser.parseItem(scanner, itemCtx, scan.SymComma, scan.SymClosedSquare); err == nil {
root := itemTree.Root()
if root != nil {
if hasFlag(ctx, allowIndex) && root.symbol() == SymColon {
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymColon {
changeColonToRange(root)
}
if !hasFlag(ctx, allowIndex) && root.symbol() == SymRange {
if !hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange {
// err = root.Errorf("unexpected range expression")
err = errRangeUnexpectedExpression(root)
break
}
args = append(args, root)
if hasFlag(ctx, allowIndex) && root.symbol() == SymRange && zeroRequired { //len(root.children) == 0 {
if len(root.children) == 1 {
root.children = append(root.children, root.children[0])
} else if len(root.children) > 1 {
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange && zeroRequired { //len(root.children) == 0 {
if len(root.Children) == 1 {
root.Children = append(root.Children, root.Children[0])
} else if len(root.Children) > 1 {
// err = root.Errorf("invalid range specification")
err = errRangeInvalidSpecification(root)
break
}
zeroTk := NewValueToken(root.tk.row, root.tk.col, SymInteger, "0", int64(0))
zeroTerm := newTerm(zeroTk)
zeroTerm.setParent(root)
root.children[0] = zeroTerm
zeroTk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymInteger, "0", int64(0))
zeroTerm := scan.NewTerm(zeroTk)
zeroTerm.SetParent(root)
root.Children[0] = zeroTerm
}
} else if itemExpected {
prev := scanner.Previous()
@@ -205,12 +206,12 @@ func (parser *parser) parseList(scanner *scanner, ctx parserContext) (listTerm *
break
}
lastSym = scanner.Previous().Sym
if itemExpected = lastSym == SymComma; itemExpected {
if itemExpected = lastSym == scan.SymComma; itemExpected {
remFlags(ctx, allowIndex)
}
}
if err == nil {
if lastSym != SymClosedSquare {
if lastSym != scan.SymClosedSquare {
err = scanner.Previous().ErrorExpectedGot("]")
} else {
listTerm = newListTerm(r, c, args)
@@ -219,16 +220,16 @@ func (parser *parser) parseList(scanner *scanner, ctx parserContext) (listTerm *
return
}
func (parser *parser) parseIterDef(scanner *scanner, ctx parserContext) (subtree *term, err error) {
func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
tk := scanner.Previous()
args := make([]*term, 0)
lastSym := SymUnknown
args := make([]*scan.Term, 0)
lastSym := scan.SymUnknown
itemExpected := false
for lastSym != SymClosedRound && lastSym != SymEos {
var subTree *ast
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedRound); err == nil {
if subTree.root != nil {
args = append(args, subTree.root)
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
var subTree *scan.Ast
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err == nil {
if subTree.Root() != nil {
args = append(args, subTree.Root())
} else if itemExpected {
prev := scanner.Previous()
err = prev.ErrorExpectedGot("iterator-param")
@@ -238,10 +239,10 @@ func (parser *parser) parseIterDef(scanner *scanner, ctx parserContext) (subtree
break
}
lastSym = scanner.Previous().Sym
itemExpected = lastSym == SymComma
itemExpected = lastSym == scan.SymComma
}
if err == nil {
if lastSym != SymClosedRound {
if lastSym != scan.SymClosedRound {
err = scanner.Previous().ErrorExpectedGot(")")
} else {
subtree = newIteratorTerm(tk, args)
@@ -250,18 +251,18 @@ func (parser *parser) parseIterDef(scanner *scanner, ctx parserContext) (subtree
return
}
func (parser *parser) parseDictKey(scanner *scanner) (key any, err error) {
func (parser *parser) parseDictKey(scanner *scan.Scanner) (key any, err error) {
tk := parser.Next(scanner)
if tk.Sym == SymError {
if tk.Sym == scan.SymError {
err = tk.Error()
return
}
if tk.Sym == SymClosedBrace || tk.Sym == SymEos {
if tk.Sym == scan.SymClosedBrace || tk.Sym == scan.SymEos {
return
}
if tk.Sym == SymInteger || tk.Sym == SymString {
if tk.Sym == scan.SymInteger || tk.Sym == scan.SymString {
tkSep := parser.Next(scanner)
if tkSep.Sym != SymColon {
if tkSep.Sym != scan.SymColon {
err = tkSep.ErrorExpectedGot(":")
} else {
key = tk.Value
@@ -272,12 +273,12 @@ func (parser *parser) parseDictKey(scanner *scanner) (key any, err error) {
return
}
func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subtree *term, err error) {
args := make(map[any]*term, 0)
lastSym := SymUnknown
func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
args := make(map[any]*scan.Term, 0)
lastSym := scan.SymUnknown
itemExpected := false
for lastSym != SymClosedBrace && lastSym != SymEos {
var subTree *ast
for lastSym != scan.SymClosedBrace && lastSym != scan.SymEos {
var subTree *scan.Ast
var key any
if key, err = parser.parseDictKey(scanner); err != nil {
break
@@ -289,9 +290,9 @@ func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subt
}
break
}
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedBrace); err == nil {
if subTree.root != nil {
args[key] = subTree.root
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedBrace); err == nil {
if subTree.Root() != nil {
args[key] = subTree.Root()
} else /*if key != nil*/ {
prev := scanner.Previous()
err = prev.ErrorExpectedGot("dictionary-value")
@@ -301,10 +302,10 @@ func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subt
break
}
lastSym = scanner.Previous().Sym
itemExpected = lastSym == SymComma
itemExpected = lastSym == scan.SymComma
}
if err == nil {
if lastSym != SymClosedBrace {
if lastSym != scan.SymClosedBrace {
err = scanner.Previous().ErrorExpectedGot("}")
} else {
subtree = newDictTerm(args)
@@ -313,14 +314,14 @@ func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subt
return
}
func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, defaultCase bool) (caseTerm *term, err error) {
var filterList *term
var caseExpr *ast
func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext, defaultCase bool) (caseTerm *scan.Term, err error) {
var filterList *scan.Term
var caseExpr *scan.Ast
ctx = remFlags(ctx, allowIndex)
tk := parser.Next(scanner)
startRow := tk.row
startCol := tk.col
if tk.Sym == SymOpenSquare {
startRow := tk.Row()
startCol := tk.Col()
if tk.Sym == scan.SymOpenSquare {
if defaultCase {
err = tk.Errorf("case list in default clause")
return
@@ -329,14 +330,14 @@ func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, def
return
}
tk = parser.Next(scanner)
startRow = tk.row
startCol = tk.col
startRow = tk.Row()
startCol = tk.Col()
} else if !defaultCase {
filterList = newListTerm(startRow, startCol, make([]*term, 0))
filterList = newListTerm(startRow, startCol, make([]*scan.Term, 0))
}
if tk.Sym == SymOpenBrace {
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, SymClosedBrace); err != nil {
if tk.Sym == scan.SymOpenBrace {
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, scan.SymClosedBrace); err != nil {
return
}
} else {
@@ -349,25 +350,25 @@ func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, def
return
}
func addSelectorCase(selectorTerm, caseTerm *term) {
if len(selectorTerm.children) < 2 {
func addSelectorCase(selectorTerm, caseTerm *scan.Term) {
if len(selectorTerm.Children) < 2 {
caseListTerm := newListTermA(caseTerm)
selectorTerm.children = append(selectorTerm.children, caseListTerm)
selectorTerm.Children = append(selectorTerm.Children, caseListTerm)
} else {
caseListTerm := selectorTerm.children[1]
caseList, _ := caseListTerm.value().([]*term)
caseListTerm := selectorTerm.Children[1]
caseList, _ := caseListTerm.Value().([]*scan.Term)
caseList = append(caseList, caseTerm)
caseListTerm.tk.Value = caseList
caseListTerm.Tk.Value = caseList
}
caseTerm.parent = selectorTerm
caseTerm.Parent = selectorTerm
}
func (parser *parser) parseSelector(scanner *scanner, tree *ast, ctx parserContext) (selectorTerm *term, err error) {
var caseTerm *term
func (parser *parser) parseSelector(scanner *scan.Scanner, tree *scan.Ast, ctx parserContext) (selectorTerm *scan.Term, err error) {
var caseTerm *scan.Term
ctx = remFlags(ctx, allowIndex)
tk := scanner.makeToken(SymSelector, '?')
if selectorTerm, err = tree.addToken(tk); err != nil {
tk := scanner.MakeToken(scan.SymSelector, '?')
if selectorTerm, err = tree.AddToken(tk); err != nil {
return
}
@@ -377,11 +378,11 @@ func (parser *parser) parseSelector(scanner *scanner, tree *ast, ctx parserConte
return
}
func (parser *parser) parseItem(scanner *scanner, ctx parserContext, termSymbols ...Symbol) (tree *ast, err error) {
func (parser *parser) parseItem(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
return parser.parseGeneral(scanner, ctx|allowVarRef, termSymbols...)
}
func (parser *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
defer func() {
if r := recover(); r != nil {
if errVal, ok := r.(error); ok {
@@ -391,56 +392,56 @@ func (parser *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast,
}
}
}()
termSymbols = append(termSymbols, SymEos)
termSymbols = append(termSymbols, scan.SymEos)
return parser.parseGeneral(scanner, allowMultiExpr, termSymbols...)
}
func couldBeACollection(t *term) bool {
var sym = SymUnknown
func couldBeACollection(t *scan.Term) bool {
var sym = scan.SymUnknown
if t != nil {
sym = t.symbol()
sym = t.Symbol()
}
return sym == SymList || sym == SymString || sym == SymDict || sym == SymExpression || sym == SymVariable
return sym == scan.SymList || sym == scan.SymString || sym == scan.SymDict || sym == scan.SymExpression || sym == scan.SymVariable
}
func listSubTree(tree *ast, listTerm *term, allowIndeces bool) (root *term, err error) {
var tk *Token
func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *scan.Term, err error) {
var tk *scan.Token
if allowIndeces {
tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.Source())
root = newTerm(tk)
if err = tree.addTerm(root); err == nil {
err = tree.addTerm(listTerm)
tk = scan.NewToken(listTerm.Tk.Row(), listTerm.Tk.Col(), scan.SymIndex, listTerm.Source())
root = scan.NewTerm(tk)
if err = tree.AddTerm(root); err == nil {
err = tree.AddTerm(listTerm)
}
} else {
root = listTerm
err = tree.addTerm(listTerm)
err = tree.AddTerm(listTerm)
}
return
}
func changePrefix(tk *Token) {
func changePrefix(tk *scan.Token) {
switch tk.Sym {
case SymMinus:
tk.SetSymbol(SymChangeSign)
case SymPlus:
tk.SetSymbol(SymUnchangeSign)
case SymStar:
tk.SetSymbol(SymDereference)
case SymExclamation:
tk.SetSymbol(SymNot)
case SymDoublePlus:
tk.SetSymbol(SymPreInc)
case SymDoubleMinus:
tk.SetSymbol(SymPreDec)
case scan.SymMinus:
tk.SetSymbol(scan.SymChangeSign)
case scan.SymPlus:
tk.SetSymbol(scan.SymUnchangeSign)
case scan.SymStar:
tk.SetSymbol(scan.SymDereference)
case scan.SymExclamation:
tk.SetSymbol(scan.SymNot)
case scan.SymDoublePlus:
tk.SetSymbol(scan.SymPreInc)
case scan.SymDoubleMinus:
tk.SetSymbol(scan.SymPreDec)
}
}
func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymbols ...Symbol) (tree *ast, err error) {
var selectorTerm *term = nil
var currentTerm *term = nil
var tk *Token
func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
var selectorTerm *scan.Term = nil
var currentTerm *scan.Term = nil
var tk *scan.Token
tree = NewAst()
tree = scan.NewAst()
firstToken := true
// lastSym := SymUnknown
for tk = parser.Next(scanner); err == nil && tk != nil && !tk.IsTerm(termSymbols); /*&& !areSymbolsOutOfCtx(tk, selectorTerm, SymColon, SymDoubleColon)*/ tk = parser.Next(scanner) {
@@ -448,7 +449,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
// continue
// }
if tk.Sym == SymSemiColon {
if tk.Sym == scan.SymSemiColon {
if hasFlag(ctx, allowMultiExpr) {
tree.ToForest()
firstToken = true
@@ -456,7 +457,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
selectorTerm = nil
continue
} else {
err = tk.Errorf(`unexpected token %q, expected ",", "]", or ")"`, tk.source)
err = tk.Errorf(`unexpected token %q, expected ",", "]", or ")"`, tk.Source())
break
}
}
@@ -468,87 +469,87 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
}
switch tk.Sym {
case SymOpenRound:
var subTree *ast
if subTree, err = parser.parseGeneral(scanner, ctx, SymClosedRound); err == nil {
if subTree.root == nil {
case scan.SymOpenRound:
var subTree *scan.Ast
if subTree, err = parser.parseGeneral(scanner, ctx, scan.SymClosedRound); err == nil {
if subTree.Root() == nil {
err = tk.ErrorExpectedGotString("expression", "()")
} else {
exprTerm := newExprTerm(subTree.root)
err = tree.addTerm(exprTerm)
exprTerm := newExprTerm(subTree.Root())
err = tree.AddTerm(exprTerm)
currentTerm = exprTerm
}
}
case SymFuncCall:
var funcCallTerm *term
case scan.SymFuncCall:
var funcCallTerm *scan.Term
if funcCallTerm, err = parser.parseFuncCall(scanner, ctx, tk); err == nil {
err = tree.addTerm(funcCallTerm)
err = tree.AddTerm(funcCallTerm)
currentTerm = funcCallTerm
}
case SymOpenSquare:
var listTerm *term
case scan.SymOpenSquare:
var listTerm *scan.Term
newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm))
if listTerm, err = parser.parseList(scanner, newCtx); err == nil {
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
}
case SymOpenBrace:
if currentTerm != nil && currentTerm.symbol() == SymColon {
case scan.SymOpenBrace:
if currentTerm != nil && currentTerm.Symbol() == scan.SymColon {
err = currentTerm.Errorf(`selector-case outside of a selector context`)
} else {
var mapTerm *term
var mapTerm *scan.Term
if mapTerm, err = parser.parseDictionary(scanner, ctx); err == nil {
err = tree.addTerm(mapTerm)
err = tree.AddTerm(mapTerm)
currentTerm = mapTerm
}
}
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual, SymAmpersandEqual, SymVertBarEqual, SymDoubleLessEqual, SymDoubleGreaterEqual, SymCaretEqual:
currentTerm, err = tree.addToken(tk)
case scan.SymEqual, scan.SymPlusEqual, scan.SymMinusEqual, scan.SymStarEqual, scan.SymSlashEqual, scan.SymPercEqual, scan.SymAmpersandEqual, scan.SymVertBarEqual, scan.SymDoubleLessEqual, scan.SymDoubleGreaterEqual, scan.SymCaretEqual:
currentTerm, err = tree.AddToken(tk)
firstToken = true
case SymFuncDef:
var funcDefTerm *term
case scan.SymFuncDef:
var funcDefTerm *scan.Term
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
err = tree.addTerm(funcDefTerm)
err = tree.AddTerm(funcDefTerm)
currentTerm = funcDefTerm
}
case SymDollarRound:
var iterDefTerm *term
case scan.SymDollarRound:
var iterDefTerm *scan.Term
if iterDefTerm, err = parser.parseIterDef(scanner, ctx); err == nil {
err = tree.addTerm(iterDefTerm)
err = tree.AddTerm(iterDefTerm)
currentTerm = iterDefTerm
}
case SymIdentifier:
if tk.source[0] == '@' && !hasFlag(ctx, allowVarRef) {
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.source)
case scan.SymIdentifier:
if tk.Source()[0] == '@' && !hasFlag(ctx, allowVarRef) {
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.Source())
} else {
currentTerm, err = tree.addToken(tk)
currentTerm, err = tree.AddToken(tk)
}
case SymQuestion:
case scan.SymQuestion:
if selectorTerm, err = parser.parseSelector(scanner, tree, ctx); err == nil {
currentTerm = selectorTerm
addFlags(ctx, selectorContext)
}
case SymColon, SymDoubleColon:
var caseTerm *term
case scan.SymColon, scan.SymDoubleColon:
var caseTerm *scan.Term
if selectorTerm != nil {
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == SymDoubleColon); err == nil {
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == scan.SymDoubleColon); err == nil {
addSelectorCase(selectorTerm, caseTerm)
currentTerm = caseTerm
if tk.Sym == SymDoubleColon {
if tk.Sym == scan.SymDoubleColon {
selectorTerm = nil
}
}
} else {
currentTerm, err = tree.addToken(tk)
if tk.IsOneOfA(SymColon, SymRange) {
currentTerm, err = tree.AddToken(tk)
if tk.IsOneOfA(scan.SymColon, scan.SymRange) {
// Colon outside a selector term acts like a separator
firstToken = true
}
}
default:
currentTerm, err = tree.addToken(tk)
currentTerm, err = tree.AddToken(tk)
}
if currentTerm != nil && currentTerm.tk.Sym != SymSelector && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
if currentTerm != nil && currentTerm.Tk.Sym != scan.SymSelector && currentTerm.Parent != nil && currentTerm.Parent.Tk.Sym != scan.SymSelector {
selectorTerm = nil
remFlags(ctx, selectorContext)
}
@@ -558,12 +559,12 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
if err == nil {
if !tk.IsOneOf(termSymbols) {
var symDesc string
if tk.IsSymbol(SymError) {
if tk.IsSymbol(scan.SymError) {
symDesc = tk.ErrorText()
} else {
symDesc = SymToString(tk.Sym)
symDesc = scan.SymToString(tk.Sym)
}
err = tk.ErrorExpectedGotStringWithPrefix("expected one of", SymListToString(termSymbols, true), symDesc)
err = tk.ErrorExpectedGotStringWithPrefix("expected one of", scan.SymListToString(termSymbols, true), symDesc)
} else {
err = tk.Error()
}
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// plugin.go
@@ -100,7 +100,7 @@ func importPluginFromSearchPath(ctx kern.ExprContext, name any) (count int, err
var it kern.Iterator
dirList := buildSearchDirList(ctx, "plugin", ENV_EXPR_PLUGIN_PATH)
count = 0
if it, err = NewIterator(name); err != nil {
if it, err = NewIterator(ctx, name, nil); err != nil {
return
}
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
+29 -25
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// ast.go
package expr
package scan
import (
"errors"
@@ -13,42 +13,46 @@ import (
//-------- ast
type ast struct {
forest []*term
root *term
type Ast struct {
forest []*Term
root *Term
}
func NewAst() *ast {
return &ast{}
func NewAst() *Ast {
return &Ast{}
}
func (ast *ast) TypeName() string {
func (ast *Ast) TypeName() string {
return "Expression"
}
func (ast *ast) ToForest() {
func (ast *Ast) Root() *Term {
return ast.root
}
func (ast *Ast) ToForest() {
if ast.root != nil {
if ast.forest == nil {
ast.forest = make([]*term, 0)
ast.forest = make([]*Term, 0)
}
ast.forest = append(ast.forest, ast.root)
ast.root = nil
}
}
func (ast *ast) String() string {
func (ast *Ast) String() string {
var sb strings.Builder
if ast.root == nil {
sb.WriteString("(nil)")
} else {
ast.root.toString(&sb)
ast.root.ToString(&sb)
}
return sb.String()
}
func (ast *ast) addTokens(tokens ...*Token) (err error) {
func (ast *Ast) AddTokens(tokens ...*Token) (err error) {
for _, tk := range tokens {
if _, err = ast.addToken(tk); err != nil {
if _, err = ast.AddToken(tk); err != nil {
break
}
}
@@ -60,16 +64,16 @@ func (ast *ast) addTokens(tokens ...*Token) (err error) {
// return
// }
func (ast *ast) addToken(tk *Token) (t *term, err error) {
if t = newTerm(tk); t != nil {
err = ast.addTerm(t)
func (ast *Ast) AddToken(tk *Token) (t *Term, err error) {
if t = NewTerm(tk); t != nil {
err = ast.AddTerm(t)
} else {
err = tk.Errorf("unexpected token %q", tk.String())
}
return
}
func (ast *ast) addTerm(node *term) (err error) {
func (ast *Ast) AddTerm(node *Term) (err error) {
if ast.root == nil {
ast.root = node
} else {
@@ -78,35 +82,35 @@ func (ast *ast) addTerm(node *term) (err error) {
return
}
func (ast *ast) insert(tree, node *term) (root *term, err error) {
func (ast *Ast) insert(tree, node *Term) (root *Term, err error) {
if tree.getPriority() < node.getPriority() {
root = tree
if tree.isComplete() {
var subRoot *term
var subRoot *Term
last := tree.removeLastChild()
if subRoot, err = ast.insert(last, node); err == nil {
subRoot.setParent(tree)
subRoot.SetParent(tree)
}
} else {
node.setParent(tree)
node.SetParent(tree)
}
} else if !node.isLeaf() {
root = node
tree.setParent(node)
tree.SetParent(node)
} else {
err = node.Errorf("two adjacent operators: %q and %q", tree, node)
}
return
}
func (ast *ast) Finish() {
func (ast *Ast) Finish() {
if ast.root == nil && ast.forest != nil && len(ast.forest) >= 1 {
ast.root = ast.forest[len(ast.forest)-1]
ast.forest = ast.forest[0 : len(ast.forest)-1]
}
}
func (ast *ast) Eval(ctx kern.ExprContext) (result any, err error) {
func (ast *Ast) Eval(ctx kern.ExprContext) (result any, err error) {
defer func() {
if r := recover(); r != nil {
if errVal, ok := r.(error); ok {
+75 -70
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// expr project scanner.go
package expr
package scan
import (
"bufio"
@@ -13,9 +13,10 @@ import (
"strings"
"git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/util"
)
type scanner struct {
type Scanner struct {
current *Token
prev *Token
stage *Token
@@ -25,8 +26,8 @@ type scanner struct {
translations map[Symbol]Symbol
}
func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *scanner) {
inst = &scanner{
func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *Scanner) {
inst = &Scanner{
stream: bufio.NewReader(s),
row: 1,
column: 1,
@@ -52,7 +53,11 @@ func DefaultTranslations() map[Symbol]Symbol {
// return self.current
// }
func (scanner *scanner) readChar() (ch byte, err error) {
func (scanner *Scanner) Current() *Token {
return scanner.current
}
func (scanner *Scanner) readChar() (ch byte, err error) {
if ch, err = scanner.stream.ReadByte(); err == nil {
if ch == '\n' {
scanner.row++
@@ -64,7 +69,7 @@ func (scanner *scanner) readChar() (ch byte, err error) {
return
}
func (scanner *scanner) unreadChar() (err error) {
func (scanner *Scanner) unreadChar() (err error) {
if err = scanner.stream.UnreadByte(); err == nil {
if scanner.column--; scanner.column == 0 {
if scanner.row--; scanner.row == 0 {
@@ -77,7 +82,7 @@ func (scanner *scanner) unreadChar() (err error) {
return
}
func (scanner *scanner) UnreadToken() (err error) {
func (scanner *Scanner) UnreadToken() (err error) {
if scanner.stage == nil {
scanner.stage = scanner.current
scanner.current = scanner.prev
@@ -87,7 +92,7 @@ func (scanner *scanner) UnreadToken() (err error) {
return
}
func (scanner *scanner) lastPos() (r, c int) {
func (scanner *Scanner) LastPos() (r, c int) {
if scanner.prev != nil {
r = scanner.prev.row
c = scanner.prev.col
@@ -95,11 +100,11 @@ func (scanner *scanner) lastPos() (r, c int) {
return
}
func (scanner *scanner) Previous() *Token {
func (scanner *Scanner) Previous() *Token {
return scanner.prev
}
func (scanner *scanner) Next() (tk *Token) {
func (scanner *Scanner) Next() (tk *Token) {
scanner.prev = scanner.current
tk = scanner.current
if scanner.stage != nil {
@@ -111,7 +116,7 @@ func (scanner *scanner) Next() (tk *Token) {
return tk
}
func (scanner *scanner) fetchNextToken() (tk *Token) {
func (scanner *Scanner) fetchNextToken() (tk *Token) {
var ch byte
if err := scanner.skipBlanks(); err != nil {
return scanner.makeErrorToken(err)
@@ -129,7 +134,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next == '>' {
tk = scanner.moveOn(SymPlusGreater, ch, next)
} else {
tk = scanner.makeToken(SymPlus, ch)
tk = scanner.MakeToken(SymPlus, ch)
}
case '-':
if next, _ := scanner.peek(); next == '-' {
@@ -137,7 +142,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next == '=' {
tk = scanner.moveOn(SymMinusEqual, ch, next)
} else {
tk = scanner.makeToken(SymMinus, ch)
tk = scanner.MakeToken(SymMinus, ch)
}
case '*':
if next, _ := scanner.peek(); next == '*' {
@@ -147,7 +152,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymStarEqual, ch, next)
} else {
tk = scanner.makeToken(SymStar, ch)
tk = scanner.MakeToken(SymStar, ch)
}
case '/':
if next, _ := scanner.peek(); next == '*' {
@@ -159,11 +164,11 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
scanner.readChar()
tk = scanner.fetchOnLineComment()
} else {
tk = scanner.makeToken(SymSlash, ch)
tk = scanner.MakeToken(SymSlash, ch)
}
case '\\':
if escape {
tk = scanner.makeToken(SymBackSlash, ch)
tk = scanner.MakeToken(SymBackSlash, ch)
escape = false
} else {
escape = true
@@ -174,24 +179,24 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymVertBarEqual, ch, next)
} else {
tk = scanner.makeToken(SymVertBar, ch)
tk = scanner.MakeToken(SymVertBar, ch)
}
case ',':
tk = scanner.makeToken(SymComma, ch)
tk = scanner.MakeToken(SymComma, ch)
case '^':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymCaretEqual, ch, next)
} else {
tk = scanner.makeToken(SymCaret, ch)
tk = scanner.MakeToken(SymCaret, ch)
}
case ':':
if next, _ := scanner.peek(); next == ':' {
tk = scanner.moveOn(SymDoubleColon, ch, next)
} else {
tk = scanner.makeToken(SymColon, ch)
tk = scanner.MakeToken(SymColon, ch)
}
case ';':
tk = scanner.makeToken(SymSemiColon, ch)
tk = scanner.MakeToken(SymSemiColon, ch)
case '.':
//if next, _ := self.peek(); next >= '0' && next <= '9' {
// tk = self.parseNumber(ch)
@@ -205,29 +210,29 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
tk = scanner.moveOn(SymDoubleDot, ch, next)
}
} else {
tk = scanner.makeToken(SymDot, ch)
tk = scanner.MakeToken(SymDot, ch)
}
case '\'':
if escape {
tk = scanner.makeToken(SymQuote, ch)
tk = scanner.MakeToken(SymQuote, ch)
escape = false
} else {
tk = scanner.fetchString(ch, true)
}
case '"':
if escape {
tk = scanner.makeToken(SymDoubleQuote, ch)
tk = scanner.MakeToken(SymDoubleQuote, ch)
escape = false
} else {
tk = scanner.fetchString(ch, true)
}
case '`':
tk = scanner.makeToken(SymBackTick, ch)
tk = scanner.MakeToken(SymBackTick, ch)
case '!':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymNotEqual, ch, next)
} else {
tk = scanner.makeToken(SymExclamation, ch)
tk = scanner.MakeToken(SymExclamation, ch)
}
case '?':
if next, _ := scanner.peek(); next == '?' {
@@ -237,7 +242,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next == '!' {
tk = scanner.moveOn(SymQuestionExclam, ch, next)
} else {
tk = scanner.makeToken(SymQuestion, ch)
tk = scanner.MakeToken(SymQuestion, ch)
}
case '&':
if next, _ := scanner.peek(); next == '&' {
@@ -245,16 +250,16 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next, _ = scanner.peek(); next == '=' {
tk = scanner.moveOn(SymAmpersandEqual, ch, next)
} else {
tk = scanner.makeToken(SymAmpersand, ch)
tk = scanner.MakeToken(SymAmpersand, ch)
}
case '%':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymPercEqual, ch, next)
} else {
tk = scanner.makeToken(SymPercent, ch)
tk = scanner.MakeToken(SymPercent, ch)
}
case '#':
tk = scanner.makeToken(SymHash, ch)
tk = scanner.MakeToken(SymHash, ch)
case '@':
if next, _ := scanner.peek(); (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
scanner.readChar()
@@ -267,15 +272,15 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next == '@' {
tk = scanner.moveOn(SymDoubleAt, ch, next)
} else {
tk = scanner.makeToken(SymAt, ch)
tk = scanner.MakeToken(SymAt, ch)
}
case '_':
tk = scanner.makeToken(SymUndescore, ch)
tk = scanner.MakeToken(SymUndescore, ch)
case '=':
if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymDoubleEqual, ch, next)
} else {
tk = scanner.makeToken(SymEqual, ch)
tk = scanner.MakeToken(SymEqual, ch)
}
case '<':
if next, _ := scanner.peek(); next == '=' {
@@ -294,7 +299,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
} else if next == '+' {
tk = scanner.moveOn(SymLessPlus, ch, next)
} else {
tk = scanner.makeToken(SymLess, ch)
tk = scanner.MakeToken(SymLess, ch)
}
case '>':
if next, _ := scanner.peek(); next == '=' {
@@ -309,7 +314,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
tk = scanner.accept(SymDoubleGreater, ch, next)
}
} else {
tk = scanner.makeToken(SymGreater, ch)
tk = scanner.MakeToken(SymGreater, ch)
}
case '$':
if next, _ := scanner.peek(); next == '(' {
@@ -326,26 +331,26 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
scanner.readChar()
tk = scanner.fetchIdentifier(next)
} else {
tk = scanner.makeToken(SymDollar, ch)
tk = scanner.MakeToken(SymDollar, ch)
}
case '(':
// if next, _ := scanner.peek(); next == ')' {
// tk = scanner.moveOn(SymOpenClosedRound, ch, next)
// } else {
tk = scanner.makeToken(SymOpenRound, ch)
tk = scanner.MakeToken(SymOpenRound, ch)
// }
case ')':
tk = scanner.makeToken(SymClosedRound, ch)
tk = scanner.MakeToken(SymClosedRound, ch)
case '[':
tk = scanner.makeToken(SymOpenSquare, ch)
tk = scanner.MakeToken(SymOpenSquare, ch)
case ']':
tk = scanner.makeToken(SymClosedSquare, ch)
tk = scanner.MakeToken(SymClosedSquare, ch)
case '{':
tk = scanner.makeToken(SymOpenBrace, ch)
tk = scanner.MakeToken(SymOpenBrace, ch)
case '}':
tk = scanner.makeToken(SymClosedBrace, ch)
tk = scanner.MakeToken(SymClosedBrace, ch)
case '~':
tk = scanner.makeToken(SymTilde, ch)
tk = scanner.MakeToken(SymTilde, ch)
case 0:
if escape {
tk = scanner.makeErrorToken(errors.New("incomplete escape sequence"))
@@ -372,7 +377,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
return
}
func (scanner *scanner) sync(err error) error {
func (scanner *Scanner) sync(err error) error {
if err == nil {
err = scanner.unreadChar()
}
@@ -395,7 +400,7 @@ func isHexDigit(ch byte) bool {
return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')
}
func (scanner *scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int, digitFunc func(byte) bool, err error) {
func (scanner *Scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int, digitFunc func(byte) bool, err error) {
var ch byte
var digitType string
firstCh = currentFirstCh
@@ -434,7 +439,7 @@ func (scanner *scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int
return
}
func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) {
func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
var err error
var ch byte
var sym Symbol = SymInteger
@@ -510,7 +515,7 @@ func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) {
value, err = strconv.ParseInt(txt, numBase, 64)
}
if err == nil {
tk = scanner.makeValueToken(sym, txt, value)
tk = scanner.MakeValueToken(sym, txt, value)
} else {
tk = scanner.makeErrorToken(err)
}
@@ -518,7 +523,7 @@ func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) {
return
}
func (scanner *scanner) fetchIdentifier(firstCh byte) (tk *Token) {
func (scanner *Scanner) fetchIdentifier(firstCh byte) (tk *Token) {
var err error
var sb strings.Builder
for ch := firstCh; err == nil && (ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')); ch, err = scanner.readChar() {
@@ -535,14 +540,14 @@ func (scanner *scanner) fetchIdentifier(firstCh byte) (tk *Token) {
if sym, ok := keywords[uptxt]; ok {
tk = scanner.makeKeywordToken(sym, uptxt)
} else if uptxt == `TRUE` {
tk = scanner.makeValueToken(SymBool, txt, true)
tk = scanner.MakeValueToken(SymBool, txt, true)
} else if uptxt == `FALSE` {
tk = scanner.makeValueToken(SymBool, txt, false)
tk = scanner.MakeValueToken(SymBool, txt, false)
} else if ch, _ := scanner.peek(); ch == '(' {
scanner.readChar()
tk = scanner.makeValueToken(SymFuncCall, txt+"(", txt)
tk = scanner.MakeValueToken(SymFuncCall, txt+"(", txt)
} else {
tk = scanner.makeValueToken(SymIdentifier, txt, txt)
tk = scanner.MakeValueToken(SymIdentifier, txt, txt)
}
}
@@ -562,20 +567,20 @@ func (scanner *scanner) fetchIdentifier(firstCh byte) (tk *Token) {
return
}
func (scanner *scanner) fetchBlockComment() *Token {
func (scanner *Scanner) fetchBlockComment() *Token {
return scanner.fetchUntil(SymComment, false, '*', '/')
}
func (scanner *scanner) fetchOnLineComment() *Token {
func (scanner *Scanner) fetchOnLineComment() *Token {
return scanner.fetchUntil(SymComment, true, '\n')
}
func (scanner *scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (tk *Token) {
func (scanner *Scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (tk *Token) {
var err error
var ch byte
var sb strings.Builder
var value string
ring := NewByteSlider(len(endings))
ring := util.NewByteSlider(len(endings))
endReached := false
for ch, err = scanner.readChar(); err == nil && !endReached; {
sb.WriteByte(ch)
@@ -593,14 +598,14 @@ func (scanner *scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (
}
if endReached {
tk = scanner.makeValueToken(sym, "", value)
tk = scanner.MakeValueToken(sym, "", value)
} else {
tk = scanner.makeErrorToken(err)
}
return
}
func (scanner *scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
func (scanner *Scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
var err error
var ch, prev byte
var sb strings.Builder
@@ -639,15 +644,15 @@ func (scanner *scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
} else {
txt := sb.String()
if addQuote {
tk = scanner.makeValueToken(SymString, `"`+txt+`"`, txt)
tk = scanner.MakeValueToken(SymString, `"`+txt+`"`, txt)
} else {
tk = scanner.makeValueToken(SymString, txt, txt)
tk = scanner.MakeValueToken(SymString, txt, txt)
}
}
return
}
func (scanner *scanner) peek() (next byte, err error) {
func (scanner *Scanner) peek() (next byte, err error) {
var one []byte
if one, err = scanner.stream.Peek(1); err == nil {
next = one[0]
@@ -655,7 +660,7 @@ func (scanner *scanner) peek() (next byte, err error) {
return
}
func (scanner *scanner) skipBlanks() (err error) {
func (scanner *Scanner) skipBlanks() (err error) {
var one []byte
for one, err = scanner.stream.Peek(1); err == nil && one[0] <= 32; one, err = scanner.stream.Peek(1) {
scanner.readChar()
@@ -663,7 +668,7 @@ func (scanner *scanner) skipBlanks() (err error) {
return
}
func (scanner *scanner) translate(sym Symbol) Symbol {
func (scanner *Scanner) translate(sym Symbol) Symbol {
if scanner.translations != nil {
if translatedSym, ok := scanner.translations[sym]; ok {
return translatedSym
@@ -672,7 +677,7 @@ func (scanner *scanner) translate(sym Symbol) Symbol {
return sym
}
func (scanner *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
func (scanner *Scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
// for i := 1; i < len(chars); i++ {
if len(chars) > 1 {
@@ -682,26 +687,26 @@ func (scanner *scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
return
}
func (scanner *scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
func (scanner *Scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
return
}
func (scanner *scanner) makeToken(sym Symbol, chars ...byte) (tk *Token) {
func (scanner *Scanner) MakeToken(sym Symbol, chars ...byte) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
return
}
func (scanner *scanner) makeKeywordToken(sym Symbol, upperCaseKeyword string) (tk *Token) {
func (scanner *Scanner) makeKeywordToken(sym Symbol, upperCaseKeyword string) (tk *Token) {
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), upperCaseKeyword)
return
}
func (scanner *scanner) makeValueToken(sym Symbol, source string, value any) (tk *Token) {
func (scanner *Scanner) MakeValueToken(sym Symbol, source string, value any) (tk *Token) {
tk = NewValueToken(scanner.row, scanner.column, scanner.translate(sym), source, value)
return
}
func (scanner *scanner) makeErrorToken(err error) *Token {
func (scanner *Scanner) makeErrorToken(err error) *Token {
return NewErrorToken(scanner.row, scanner.column, err)
}
+231
View File
@@ -0,0 +1,231 @@
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// Symbol.go
package scan
import (
"strings"
)
var symbolMap map[Symbol]symbolSpec
type SymbolClass int16
const (
SymClassOperator SymbolClass = iota
SymClassCommand
SymClassIdentifier
SymClassDelimiter
SymClassParenthesis
SymClassDeclaration
SymClassValue
SymClassOther
)
type symbolSpec struct {
repr string
kind SymbolClass
opType TermPosition
}
func init() {
symbolMap = map[Symbol]symbolSpec{
SymUnknown: {"<unknown>", SymClassOther, PosLeaf}, // -1: Unknown symbol
SymNone: {"<null>", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol
SymError: {"<error>", SymClassOther, PosLeaf}, // 1: Error reading from stream
SymEos: {"<eos>", SymClassOther, PosLeaf}, // 2: End of stream
SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-'
SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-='
SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--'
SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+'
SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+='
SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++'
SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*'
SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**'
SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/'
SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\'
SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|'
SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||'
SymComma: {",", SymClassOperator, PosInfix}, // 15: ','
SymColon: {":", SymClassOperator, PosInfix}, // 16: ':'
SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';'
SymDot: {".", SymClassOperator, PosInfix}, // 18: '.'
SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './'
SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\''
SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"'
SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`'
SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!'
SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?'
SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&'
SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&'
SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%'
SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@'
SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_'
SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '='
SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 31: '=='
SymLess: {"<", SymClassOperator, PosInfix}, // 32: '<'
SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 33: '<='
SymGreater: {">", SymClassOperator, PosInfix}, // 34: '>'
SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 35: '>='
SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 36: '<>'
SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 37: '!='
SymDollar: {"$", SymClassOperator, PosPrefix}, // 38: '$'
SymHash: {"#", SymClassOperator, PosPrefix}, // 39: '#'
SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 40: '('
SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 41: ')'
SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 42: '['
SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 43: ']'
SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 44: '{'
SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 45: '}'
SymTilde: {"~", SymClassOperator, PosPrefix}, // 46: '~'
SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 47: '??'
SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 48: '?='
SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 49: '?!'
SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 50: '@@'
SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 51: '::'
SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 52: '>>'
SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 53: '<<'
SymCaret: {"^", SymClassOperator, PosInfix}, // 54: '^'
SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 55: '$('
SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 56: '()'
SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 57: '$$'
SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 58: '..'
SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 59: '...'
SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 60: '*='
SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 61: '/='
SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 62: '%='
SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 63: '<<='
SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 64: '>>='
SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 65: '&='
SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 65: '|='
SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 66: '^='
SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 67: '+>'
SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 68: '<+'
SymPreInc: {"++", SymClassOperator, PosPrefix}, // : '++'
SymPreDec: {"--", SymClassOperator, PosPrefix}, // : '--'
// SymChangeSign
// SymUnchangeSign
// SymIdentifier
// SymBool
// SymInteger
// SymVariable
// SymFloat
// SymFraction
// SymString
// SymIterator
// SymOr: "or",
// SymAnd: "and",
// SymNot: "not",
// SymComment
// SymFuncCall
// SymFuncDef
// SymList
// SymDict
// SymIndex
// SymExpression
// SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
// SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
// // SymOpenComment // 0: '/*'
// // SymClosedComment // 0: '*/'
// // SymOneLineComment // 0: '//'
// keywordBase
SymKwAnd: {"and", SymClassOperator, PosInfix},
SymKwNot: {"not", SymClassOperator, PosInfix},
SymKwOr: {"or", SymClassOperator, PosInfix},
SymKwBut: {"but", SymClassOperator, PosInfix},
SymKwMap: {"map", SymClassOperator, PosInfix},
SymKwFilter: {"filter", SymClassOperator, PosInfix},
SymKwDigest: {"digest", SymClassOperator, PosInfix},
SymKwJoin: {"join", SymClassOperator, PosInfix},
SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
SymKwFunc: {"func(", SymClassDeclaration, PosPrefix},
SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
SymKwPlugin: {"plugin", SymClassOperator, PosPrefix},
SymKwIn: {"in", SymClassOperator, PosInfix},
SymKwInclude: {"include", SymClassOperator, PosPrefix},
SymKwNil: {"nil", SymClassValue, PosLeaf},
SymKwUnset: {"unset", SymClassOperator, PosPrefix},
}
}
func SymToString(sym Symbol) string {
if s, ok := symbolMap[sym]; ok {
return s.repr
}
return ""
}
func SymListToString(symList []Symbol, quote bool) string {
var sb strings.Builder
if len(symList) == 0 {
sb.WriteString("<nothing>")
} else {
for _, sym := range symList {
if sb.Len() > 0 {
sb.WriteByte(',')
sb.WriteByte(' ')
}
if quote {
sb.WriteByte('`')
}
sb.WriteString(SymToString(sym))
if quote {
sb.WriteByte('`')
}
}
}
return sb.String()
}
func StringEndsWithOperator(s string) bool {
return endingOperator(s) != SymNone
}
// func endingOperator(s string) (sym Symbol) {
// var matchLength = 0
// sym = SymNone
// lower := strings.TrimRight(strings.ToLower(s), " \t")
// for symbol, spec := range symbolMap {
// if strings.HasSuffix(lower, spec.repr) {
// if len(spec.repr) > matchLength {
// matchLength = len(spec.repr)
// if spec.kind == symClassOperator && (spec.opType == PosInfix || spec.opType == PosPrefix) {
// sym = symbol
// } else {
// sym = SymNone
// }
// }
// }
// }
// return
// }
func endingOperator(s string) (sym Symbol) {
var matchLength = 0
var repr string
sym = SymNone
lower := strings.TrimRight(strings.ToLower(s), " \t")
for symbol, spec := range symbolMap {
if len(spec.repr) > matchLength || repr == spec.repr {
if strings.HasSuffix(lower, spec.repr) {
if isNotEndingSymbol(spec) && repr != spec.repr {
repr = spec.repr
matchLength = len(spec.repr)
sym = symbol
} else {
sym = SymNone
break
// matchLength = 0
}
}
}
}
return
}
func isNotEndingSymbol(spec symbolSpec) bool {
return (spec.kind == SymClassOperator && (spec.opType == PosInfix || spec.opType == PosPrefix)) ||
(spec.kind == SymClassParenthesis && spec.opType == PosPrefix)
}
+2 -2
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// Symbol.go
package expr
package scan
type Symbol int16
+2 -2
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// t_scanner_test.go
package expr
package scan
import (
"errors"
@@ -1,23 +1,23 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// op-registry.go
package expr
// term-constructor-registry.go
package scan
const initialRegistryCapacity = 10
type termContructor func(tk *Token) *term
type termContructor func(tk *Token) *Term
var constructorRegistry map[Symbol]termContructor = nil
func registerTermConstructor(sym Symbol, constructor termContructor) {
func RegisterTermConstructor(sym Symbol, constructor termContructor) {
if constructorRegistry == nil {
constructorRegistry = make(map[Symbol]termContructor, initialRegistryCapacity)
}
constructorRegistry[sym] = constructor
}
func newTerm(tk *Token) (inst *term) {
func NewTerm(tk *Token) (inst *Term) {
if constructorRegistry != nil {
if construct, exists := constructorRegistry[tk.Sym]; exists {
inst = construct(tk)

Some files were not shown because too many files have changed in this diff Show More