Compare commits
32 Commits
v0.38.0
...
ac5c97bfd3
| Author | SHA1 | Date | |
|---|---|---|---|
| ac5c97bfd3 | |||
| e1c24daac4 | |||
| a62f27b104 | |||
| 1055569dd6 | |||
| 1aea1c14d2 | |||
| 081395be5f | |||
| 35a599b284 | |||
| eda3037855 | |||
| 47c181546a | |||
| a8a5d6aaa6 | |||
| 84b255a51b | |||
| 9efdeffcac | |||
| d34b9d8a48 | |||
| 1bf8015da1 | |||
| 3ccbeb3978 | |||
| 0c719025cd | |||
| 08617378e0 | |||
| e6844ad1e8 | |||
| 3a4e217891 | |||
| 0f293fdbbc | |||
| 45faea7620 | |||
| e5a61b5638 | |||
| 5285b61320 | |||
| 5950630cf7 | |||
| 78e431f2b9 | |||
| c7dce8288f | |||
| c10053253c | |||
| a3c7cf2efa | |||
| dfa1491093 | |||
| 99c1adc434 | |||
| 5585b496fb | |||
| acd4f8487d |
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// function.go
|
// function.go
|
||||||
|
|||||||
+44
-24
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-base.go
|
// builtin-base.go
|
||||||
@@ -255,24 +255,41 @@ func setFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func unsetFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func charFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
// var varName string
|
var ord int
|
||||||
// var ok bool
|
|
||||||
|
|
||||||
// if varName, ok = args[kern.ParamName].(string); !ok {
|
if n, ok := args[kern.ParamValue].(byte); ok {
|
||||||
// return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName])
|
ord = int(n)
|
||||||
// } else {
|
} else if n, ok := args[kern.ParamValue].(int64); ok {
|
||||||
// ctx.GetParent().DeleteVar(varName)
|
ord = int(n)
|
||||||
// result = nil
|
} else if n, ok := args[kern.ParamValue].(int); ok {
|
||||||
// }
|
ord = n
|
||||||
// return
|
} 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func seqFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
|
list := kern.NewLinkedList()
|
||||||
|
items := args[kern.ParamValue].([]any)
|
||||||
|
for _, arg := range items {
|
||||||
|
list.PushBack(arg)
|
||||||
|
}
|
||||||
|
result = list
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//// import
|
//// import
|
||||||
|
|
||||||
func ImportBuiltinsFuncs(ctx kern.ExprContext) {
|
func ImportBuiltinsFuncs(ctx kern.ExprContext) {
|
||||||
anyParams := []kern.ExprFuncParam{
|
anyParams := []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamValue),
|
kern.NewFuncParam(kern.ParamValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams)
|
||||||
@@ -290,28 +307,31 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) {
|
|||||||
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
|
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
|
||||||
ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams)
|
ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams)
|
||||||
ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{
|
ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamValue),
|
kern.NewFuncParam(kern.ParamValue),
|
||||||
NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)),
|
kern.NewFuncParamFlagDef(ParamDenominator, kern.PfDefault, int64(1)),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamName),
|
kern.NewFuncParam(kern.ParamName),
|
||||||
NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil),
|
kern.NewFuncParamFlagDef(kern.ParamValue, kern.PfDefault, nil),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{
|
ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamName),
|
kern.NewFuncParam(kern.ParamName),
|
||||||
NewFuncParam(kern.ParamValue),
|
kern.NewFuncParam(kern.ParamValue),
|
||||||
})
|
})
|
||||||
|
|
||||||
// ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{
|
ctx.RegisterFunc("char", kern.NewGolangFunctor(charFunc), kern.TypeString, []kern.ExprFuncParam{
|
||||||
// NewFuncParam(kern.ParamName),
|
kern.NewFuncParam(kern.ParamValue),
|
||||||
// NewFuncParam(kern.ParamValue),
|
})
|
||||||
// })
|
|
||||||
|
ctx.RegisterFunc("seq", kern.NewGolangFunctor(seqFunc), kern.TypeLinkedList, []kern.ExprFuncParam{
|
||||||
|
kern.NewFuncParamFlag(kern.ParamValue, kern.PfRepeat),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
+3
-3
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-fmt.go
|
// builtin-fmt.go
|
||||||
@@ -47,10 +47,10 @@ func printLnFunc(ctx kern.ExprContext, name string, args map[string]any) (result
|
|||||||
|
|
||||||
func ImportFmtFuncs(ctx kern.ExprContext) {
|
func ImportFmtFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("print", kern.NewGolangFunctor(printFunc), kern.TypeInt, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("println", kern.NewGolangFunctor(printLnFunc), kern.TypeInt, []kern.ExprFuncParam{
|
||||||
NewFuncParamFlag(kern.ParamItem, PfRepeat),
|
kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-import.go
|
// builtin-import.go
|
||||||
@@ -69,10 +69,10 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera
|
|||||||
|
|
||||||
func ImportImportFuncs(ctx kern.ExprContext) {
|
func ImportImportFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{
|
||||||
NewFuncParamFlag(kern.ParamFilepath, PfRepeat),
|
kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-iterator.go
|
// 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) {
|
func ImportIterFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
|
ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamIterator),
|
kern.NewFuncParam(kern.ParamIterator),
|
||||||
NewFuncParamFlag(iterParamOperator, PfOptional),
|
kern.NewFuncParamFlag(iterParamOperator, kern.PfOptional),
|
||||||
NewFuncParamFlag(iterParamVars, PfOptional),
|
kern.NewFuncParamFlag(iterParamVars, kern.PfOptional),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-math-arith.go
|
// 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) {
|
func ImportMathFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("add", kern.NewGolangFunctor(addFunc), kern.TypeNumber, []kern.ExprFuncParam{
|
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{
|
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)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-os-file.go
|
// builtin-os-file.go
|
||||||
@@ -6,146 +6,66 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/file"
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
)
|
)
|
||||||
|
|
||||||
const paramHandleOrPath = "handle-or-path"
|
const paramHandleOrPath = "handle-or-path"
|
||||||
const fileReadTextIteratorType = "fileReadTextIterator"
|
|
||||||
|
|
||||||
type fileReadTextIterator struct {
|
type fileIterBase struct {
|
||||||
osReader *osReader
|
reader *file.Reader
|
||||||
index int64
|
index int64
|
||||||
count int64
|
count int64
|
||||||
line string
|
|
||||||
autoClose bool
|
autoClose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newReadTextIterator(r *osReader, autoClose bool) *fileReadTextIterator {
|
func (it *fileIterBase) Count() int64 {
|
||||||
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 {
|
|
||||||
return it.count
|
return it.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *fileReadTextIterator) Next() (item any, err error) { // must return io.EOF after the last item
|
func (it *fileIterBase) Index() int64 {
|
||||||
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 {
|
|
||||||
return it.index
|
return it.index
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *fileReadTextIterator) Reset() (err error) {
|
func (it *fileIterBase) HasOperation(name string) bool {
|
||||||
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 {
|
|
||||||
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
|
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *fileReadTextIterator) Clean() (err error) {
|
func (it *fileIterBase) reset() {
|
||||||
if it.osReader.fh != nil {
|
it.index = -1
|
||||||
if err = it.osReader.fh.Close(); err == nil {
|
it.count = 0
|
||||||
it.osReader = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *fileReadTextIterator) CallOperation(name string, args map[string]any) (v any, err error) {
|
func (it *fileIterBase) increment() {
|
||||||
switch name {
|
it.index++
|
||||||
case kern.NextName:
|
it.count++
|
||||||
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 fileReadIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func (it *fileIterBase) repr(typeName string) string {
|
||||||
var handle *osReader
|
if it.reader.Valid() {
|
||||||
var invalidFileHandle any
|
return fmt.Sprintf("$(%s@%q)", typeName, it.reader.GetName())
|
||||||
var ok, autoClose bool
|
}
|
||||||
|
return fmt.Sprintf("$(%s@<nil>)", typeName)
|
||||||
|
}
|
||||||
|
|
||||||
result = nil
|
func initFileHandle(ctx kern.ExprContext, name string, args map[string]any) (handle *file.Reader, invalidFileHandle any, autoClose bool, err error) {
|
||||||
if handle, ok = args[paramHandleOrPath].(*osReader); !ok {
|
var ok bool
|
||||||
|
|
||||||
|
if handle, ok = args[paramHandleOrPath].(*file.Reader); !ok {
|
||||||
if fileName, ok := args[paramHandleOrPath].(string); ok && len(fileName) > 0 {
|
if fileName, ok := args[paramHandleOrPath].(string); ok && len(fileName) > 0 {
|
||||||
var handleAny any
|
var handleAny any
|
||||||
if handleAny, err = openFileFunc(ctx, name, map[string]any{kern.ParamFilepath: fileName}); err != nil {
|
if handleAny, err = openFileFunc(ctx, name, map[string]any{kern.ParamFilepath: fileName}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if handleAny != nil {
|
if handleAny != nil {
|
||||||
handle = handleAny.(*osReader)
|
handle = handleAny.(*file.Reader)
|
||||||
autoClose = true
|
autoClose = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
invalidFileHandle = args[paramHandleOrPath]
|
invalidFileHandle = args[paramHandleOrPath]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil {
|
|
||||||
result = newReadTextIterator(handle, autoClose)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil && (handle == nil || invalidFileHandle != nil) {
|
|
||||||
err = errInvalidFileHandle(name, invalidFileHandle)
|
|
||||||
}
|
|
||||||
return
|
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
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-os-file.go
|
// builtin-os-file.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/file"
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,44 +16,6 @@ const (
|
|||||||
osLimitCh = "limitCh"
|
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 {
|
func errMissingFilePath(funcName string) error {
|
||||||
return fmt.Errorf("%s(): missing or invalid file path", funcName)
|
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 {
|
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
|
||||||
var fh *os.File
|
// var fh *os.File
|
||||||
if fh, err = os.Create(filePath); err == nil {
|
// if fh, err = os.Open(filePath); err == nil {
|
||||||
result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
|
// result = file.NewReader(fh)
|
||||||
}
|
// }
|
||||||
|
result, err = file.OpenReader(filePath)
|
||||||
} else {
|
} else {
|
||||||
err = errMissingFilePath(name)
|
err = errMissingFilePath(name)
|
||||||
}
|
}
|
||||||
return
|
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 {
|
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
|
||||||
var fh *os.File
|
// var fh *os.File
|
||||||
if fh, err = os.Open(filePath); err == nil {
|
// if fh, err = os.Create(filePath); err == nil {
|
||||||
result = &osReader{fh: fh, reader: bufio.NewReader(fh)}
|
// result = file.NewWriter(fh)
|
||||||
}
|
// }
|
||||||
|
result, err = file.CreateWriter(filePath)
|
||||||
} else {
|
} else {
|
||||||
err = errMissingFilePath(name)
|
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) {
|
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 {
|
if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 {
|
||||||
var fh *os.File
|
// var fh *os.File
|
||||||
if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil {
|
// 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)}
|
// result = file.NewWriter(fh)
|
||||||
}
|
// }
|
||||||
|
result, err = file.AppendWriter(filePath)
|
||||||
} else {
|
} else {
|
||||||
err = errMissingFilePath(name)
|
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) {
|
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 invalidFileHandle any
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
|
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok {
|
||||||
invalidFileHandle = args[kern.ParamHandle]
|
invalidFileHandle = args[kern.ParamHandle]
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil {
|
if handle != nil {
|
||||||
if fh := handle.getFile(); fh != nil {
|
if fh := handle.GetFile(); fh != nil {
|
||||||
if w, ok := handle.(*osWriter); ok {
|
if w, ok := handle.(*file.Writer); ok {
|
||||||
err = w.writer.Flush()
|
err = w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
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) {
|
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 invalidFileHandle any
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if handle, ok = args[kern.ParamHandle].(osHandle); !ok {
|
if handle, ok = args[kern.ParamHandle].(file.Handle); !ok {
|
||||||
invalidFileHandle = args[kern.ParamHandle]
|
invalidFileHandle = args[kern.ParamHandle]
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil {
|
if handle != nil {
|
||||||
if w, ok := handle.(*osWriter); ok {
|
if w, ok := handle.(*file.Writer); ok {
|
||||||
if v, exists := args[kern.ParamItem]; exists {
|
if v, exists := args[kern.ParamItem]; exists {
|
||||||
argv := v.([]any)
|
argv := v.([]any)
|
||||||
result, err = fmt.Fprint(w.writer, argv...)
|
// result, err = fmt.Fprint(w.writer, argv...)
|
||||||
|
result, err = w.Write(argv...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
invalidFileHandle = handle
|
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) {
|
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 invalidFileHandle any
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
result = nil
|
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]
|
invalidFileHandle = args[kern.ParamHandle]
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil {
|
if handle != nil {
|
||||||
if r, ok := handle.(*osReader); ok {
|
if r, ok := handle.(*file.Reader); ok {
|
||||||
var limit byte = '\n'
|
var limit byte = '\n'
|
||||||
var v string
|
var v string
|
||||||
if s, ok := args[osLimitCh].(string); ok && len(s) > 0 {
|
if s, ok := args[osLimitCh].(string); ok && len(s) > 0 {
|
||||||
limit = s[0]
|
limit = s[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err = r.reader.ReadString(limit)
|
v, err = r.ReadString(limit)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
err = nil
|
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) {
|
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 invalidFileHandle any
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
result = nil
|
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]
|
invalidFileHandle = args[kern.ParamHandle]
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle != nil {
|
if handle != nil {
|
||||||
if r, ok := handle.(*osReader); ok {
|
if r, ok := handle.(*file.Reader); ok {
|
||||||
var b []byte
|
var b []byte
|
||||||
b, err = io.ReadAll(r.reader)
|
b, err = r.ReadAll()
|
||||||
result = string(b)
|
result = string(b)
|
||||||
} else {
|
} else {
|
||||||
invalidFileHandle = handle
|
invalidFileHandle = handle
|
||||||
@@ -224,38 +189,43 @@ func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any)
|
|||||||
|
|
||||||
func ImportOsFuncs(ctx kern.ExprContext) {
|
func ImportOsFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{
|
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{
|
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{
|
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{
|
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{
|
ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamHandle),
|
kern.NewFuncParam(kern.ParamHandle),
|
||||||
NewFuncParamFlagDef(kern.ParamItem, PfDefault|PfRepeat, ""),
|
kern.NewFuncParamFlagDef(kern.ParamItem, kern.PfDefault|kern.PfRepeat, ""),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{
|
ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamHandle),
|
kern.NewFuncParam(kern.ParamHandle),
|
||||||
NewFuncParamFlagDef(osLimitCh, PfDefault, "\n"),
|
kern.NewFuncParamFlagDef(osLimitCh, kern.PfDefault, "\n"),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("fileLineIterator", kern.NewGolangFunctor(fileLineIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
|
||||||
NewFuncParam(paramHandleOrPath),
|
kern.NewFuncParam(paramHandleOrPath),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.RegisterFunc("fileByteIterator", kern.NewGolangFunctor(fileByteIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{
|
||||||
|
kern.NewFuncParam(paramHandleOrPath),
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
+18
-18
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtin-string.go
|
// 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
|
// Import above functions in the context
|
||||||
func ImportStringFuncs(ctx kern.ExprContext) {
|
func ImportStringFuncs(ctx kern.ExprContext) {
|
||||||
ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSeparator),
|
kern.NewFuncParam(kern.ParamSeparator),
|
||||||
NewFuncParamFlag(kern.ParamItem, PfRepeat),
|
kern.NewFuncParamFlag(kern.ParamItem, kern.PfRepeat),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSource),
|
kern.NewFuncParam(kern.ParamSource),
|
||||||
NewFuncParamFlagDef(kern.ParamStart, PfDefault, int64(0)),
|
kern.NewFuncParamFlagDef(kern.ParamStart, kern.PfDefault, int64(0)),
|
||||||
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
|
kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{
|
ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSource),
|
kern.NewFuncParam(kern.ParamSource),
|
||||||
NewFuncParamFlagDef(kern.ParamSeparator, PfDefault, ""),
|
kern.NewFuncParamFlagDef(kern.ParamSeparator, kern.PfDefault, ""),
|
||||||
NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)),
|
kern.NewFuncParamFlagDef(kern.ParamCount, kern.PfDefault, int64(-1)),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("strTrim", kern.NewGolangFunctor(trimStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("strStartsWith", kern.NewGolangFunctor(startsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSource),
|
kern.NewFuncParam(kern.ParamSource),
|
||||||
NewFuncParam(kern.ParamPrefix),
|
kern.NewFuncParam(kern.ParamPrefix),
|
||||||
NewFuncParamFlag(strParamOther, PfRepeat),
|
kern.NewFuncParamFlag(strParamOther, kern.PfRepeat),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
|
ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSource),
|
kern.NewFuncParam(kern.ParamSource),
|
||||||
NewFuncParam(kern.ParamSuffix),
|
kern.NewFuncParam(kern.ParamSuffix),
|
||||||
NewFuncParamFlag(strParamOther, PfRepeat),
|
kern.NewFuncParamFlag(strParamOther, kern.PfRepeat),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("strUpper", kern.NewGolangFunctor(upperStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
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{
|
ctx.RegisterFunc("strLower", kern.NewGolangFunctor(lowerStrFunc), kern.TypeString, []kern.ExprFuncParam{
|
||||||
NewFuncParam(kern.ParamSource),
|
kern.NewFuncParam(kern.ParamSource),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// builtins-register.go
|
// builtins-register.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// data-cursors.go
|
// data-cursors.go
|
||||||
|
|||||||
+5
-3
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// dict-iterator.go
|
// dict-iterator.go
|
||||||
@@ -116,8 +116,11 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
dictIt.makeKeys(*dict, sortType)
|
dictIt.makeKeys(*dict, sortType)
|
||||||
return dictIt, err
|
it = dictIt
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapIterator(m map[any]any) (it *DictIterator) {
|
func NewMapIterator(m map[any]any) (it *DictIterator) {
|
||||||
@@ -139,7 +142,6 @@ func (it *DictIterator) TypeName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (it *DictIterator) HasOperation(name string) bool {
|
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)
|
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, kern.KeyName, kern.ValueName}, name)
|
||||||
return yes
|
return yes
|
||||||
}
|
}
|
||||||
|
|||||||
+216
-44
@@ -34,7 +34,7 @@ Expressions calculator
|
|||||||
|
|
||||||
toc::[]
|
toc::[]
|
||||||
|
|
||||||
#TODO: Work in progress (last update on 2026/04/21, 6:49 p.m.)#
|
#TODO: Work in progress#
|
||||||
|
|
||||||
== Expr
|
== Expr
|
||||||
_Expr_ is a GO package that can analyze, interpret and calculate expressions.
|
_Expr_ is a GO package that can analyze, interpret and calculate expressions.
|
||||||
@@ -100,7 +100,28 @@ An interactive tool could like `dev-expr` (see <<_dev-expr_test_tool>>) can be u
|
|||||||
[green]`{2sp}}` +
|
[green]`{2sp}}` +
|
||||||
[green]`}`
|
[green]`}`
|
||||||
|
|
||||||
In order to inspect the global context issue the [blue]`$$global` operator.
|
In order to inspect the global context issue the [blue]`$$ global` operation.
|
||||||
|
////
|
||||||
|
.Example: list all functions whose name starts with "str"
|
||||||
|
`>>>` [blue]`builtin "string` [gray]__// most function in the builtin module *string* have names starting with "str".__ +
|
||||||
|
[green]`1`
|
||||||
|
|
||||||
|
:dollar: $
|
||||||
|
:2dollars: $$
|
||||||
|
|
||||||
|
`>>>` [blue]`($(($$global).functions) filter strStartsWith($_, "str"))` +
|
||||||
|
[green]`[` +
|
||||||
|
[green]`{2sp}"strEndsWith",` +
|
||||||
|
[green]`{2sp}"strJoin",` +
|
||||||
|
[green]`{2sp}"strLower",` +
|
||||||
|
[green]`{2sp}"strSplit",` +
|
||||||
|
[green]`{2sp}"strStartsWith",` +
|
||||||
|
[green]`{2sp}"strSub",` +
|
||||||
|
[green]`{2sp}"strTrim",` +
|
||||||
|
[green]`{2sp}"strUpper",` +
|
||||||
|
[green]`{2sp}"string"` +
|
||||||
|
[green]`]`
|
||||||
|
////
|
||||||
|
|
||||||
=== `dev-expr` test tool
|
=== `dev-expr` test tool
|
||||||
Before we begin to describe the syntax of _Expr_, it is worth introducing _dev-expr_ because it will be used to show many examples of expressions.
|
Before we begin to describe the syntax of _Expr_, it is worth introducing _dev-expr_ because it will be used to show many examples of expressions.
|
||||||
@@ -223,14 +244,20 @@ Value range: *-9223372036854775808* to *9223372036854775807*
|
|||||||
[cols="^1,^2,6,4"]
|
[cols="^1,^2,6,4"]
|
||||||
|===
|
|===
|
||||||
| Symbol | Operation | Description | Examples
|
| Symbol | Operation | Description | Examples
|
||||||
| [blue]`+` | _Sum_ | Add two values | [blue]`-1 + 2` -> _1_
|
| [blue]`+` | _Sum_ | Add two values^(<<note_int_plus_string,1>>)^ | [blue]`-1 + 2` -> _1_
|
||||||
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> _2_
|
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`3 - 1` -> _2_
|
||||||
| [blue]`*` | _Product_ | Multiply two values | [blue]`-1 * 2` -> _-2_
|
| [blue]`*` | _Product_ | Multiply two values^(<<note_string_repl,2>>)^ | [blue]`-1 * 2` -> _-2_
|
||||||
| [blue]`/` | _Integer division_ | Divide the left value by the right one^(*)^ | [blue]`-11 / 2` -> _-5_
|
| [blue]`/` | _Integer division_ | Divide the left value by the right one^(<<note_float_division,3>>)^ | [blue]`-11 / 2` -> _-5_
|
||||||
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> _1_
|
| [blue]`%` | _Modulo_ | Remainder of the integer division | [blue]`5 % 2` -> _1_
|
||||||
|===
|
|===
|
||||||
|
[[note_int_plus_string]]
|
||||||
|
^(1)^ The sum operator [blue]`+` also supports adding an integer number to a string. In this case, the number is converted to a string and prependend or appended to the string, e.g. `"x" + 48` results in `"x48"`.
|
||||||
|
|
||||||
^(*)^ See also the _float division_ [blue]`./` below.
|
[[note_string_repl]]
|
||||||
|
^(2)^ The product operator also supports multiplying a string by an integer. In this case, the number represents homw may times the string has to be repeated in the result, e.g. `"foo" * 3` returnsn `"foofoofoo"`.
|
||||||
|
|
||||||
|
[[note_float_division]]
|
||||||
|
^(3)^ See also the _float division_ [blue]`./` below.
|
||||||
|
|
||||||
|
|
||||||
==== Floats
|
==== Floats
|
||||||
@@ -268,12 +295,14 @@ _dec-seq_ = _see-integer-literal-syntax_
|
|||||||
[cols="^1,^2,6,4"]
|
[cols="^1,^2,6,4"]
|
||||||
|===
|
|===
|
||||||
| Symbol | Operation | Description | Examples
|
| Symbol | Operation | Description | Examples
|
||||||
| [blue]`+` | _Sum_ | Add two values | [blue]`4 + 0.5` -> 4.5
|
| [blue]`+` | _Sum_ | Add two values^(<<note_float_plus_string,1>>)^ | [blue]`4 + 0.5` -> 4.5
|
||||||
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`4 - 0.5` -> 3.5
|
| [blue]`-` | _Subtraction_ | Subtract the right value from the left one | [blue]`4 - 0.5` -> 3.5
|
||||||
| [blue]`*` | _Product_ | Multiply two values | [blue]`4 * 0.5` -> 2.0
|
| [blue]`*` | _Product_ | Multiply two values | [blue]`4 * 0.5` -> 2.0
|
||||||
| [blue]`/` | _Float division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5
|
| [blue]`/` | _Float division_ | Divide the left value by the right one | [blue]`1.0 / 2` -> 0.5
|
||||||
| [blue]`./`| _Forced float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5
|
| [blue]`./`| _Forced float division_ | Force float division | [blue]`-1 ./ 2` -> -0.5
|
||||||
|===
|
|===
|
||||||
|
[[note_float_plus_string]]
|
||||||
|
^(1)^ The sum operator [blue]`+` also supports adding a float number to a string. In this case, the number is converted to a string and prependend or appended to the string, e.g. `"x" + 1.2` results in `"x1.2"`.
|
||||||
|
|
||||||
==== Fractions
|
==== Fractions
|
||||||
_Expr_ also supports fractions. Fraction literals are made with two integers separated by a colon character `:`.
|
_Expr_ also supports fractions. Fraction literals are made with two integers separated by a colon character `:`.
|
||||||
@@ -698,9 +727,9 @@ The value on the left side of [blue]`=` must be a variable identifier or an expr
|
|||||||
=== Selector operator [blue]`? : ::`
|
=== Selector operator [blue]`? : ::`
|
||||||
The _selector operator_ is very similar to the _switch/case/default_ statement available in many programming languages.
|
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_ +
|
_selector-case_ = [_match-list_] _case-value_ +
|
||||||
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
|
_match-list_ = "*[*" _item_ {"*,*" _items_} "*]*" +
|
||||||
_item_ = _expression_ +
|
_item_ = _expression_ +
|
||||||
@@ -737,19 +766,38 @@ The [blue]`:` symbol (colon) is the separator of the selector-cases. Note that i
|
|||||||
`>>>` [blue]`10 ? {"a"} : {"b"}` +
|
`>>>` [blue]`10 ? {"a"} : {"b"}` +
|
||||||
[red]`Eval Error: [1:3] no case catches the value (10) of the selection expression`
|
[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]`?!`
|
=== 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.
|
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]`??` 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.
|
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
|
.Examples
|
||||||
`>>>` [blue]`var ?? (1+2)` +
|
`>>>` [blue]`var ?? (1+2)` +
|
||||||
@@ -836,8 +884,14 @@ The table below shows all supported operators by decreasing priorities.
|
|||||||
.2+|*INSERT*| [blue]`+>` | _Infix_ | _Prepend_ | _any_ `+>` _list_ -> _list_
|
.2+|*INSERT*| [blue]`+>` | _Infix_ | _Prepend_ | _any_ `+>` _list_ -> _list_
|
||||||
| [blue]`<+` | _Infix_ | _Append_ | _list_ `<+` _any_ -> _list_
|
| [blue]`<+` | _Infix_ | _Append_ | _list_ `<+` _any_ -> _list_
|
||||||
.2+|*ASSIGN*| [blue]`=` | _Infix_ | _Assignment_ | _identifier_ `=` _any_ -> _any_
|
.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_
|
.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]`cat` | _Infix_ | _Item-concatenation_ | _iterable_ `cat ` _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_
|
.1+|*RANGE*| [blue]`:` | _Infix_ | _Index-range_ | _integer_ `:` _integer_ -> _integer-pair_
|
||||||
|===
|
|===
|
||||||
|
|
||||||
@@ -921,12 +975,12 @@ _param-name_ = _identifier_
|
|||||||
[green]`fib(n):any{}`
|
[green]`fib(n):any{}`
|
||||||
|
|
||||||
`>>>` [gray]_// Required and optional parameters_ +
|
`>>>` [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{}`
|
[green]`measure(value, unit="meter"):any{}`
|
||||||
|
|
||||||
|
|
||||||
=== _Golang_ function definition
|
=== _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
|
=== Function calls
|
||||||
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
|
To call a function, either Expr or Golang type, it is necessary to specify its name and, at least, its required parameters.
|
||||||
@@ -1010,7 +1064,7 @@ Clone variables are normal local variables. The only diffence will appear when t
|
|||||||
.Example
|
.Example
|
||||||
`>>>` [blue]`f = func() { @x = 3; x = 5 }` [gray]_// f() declares two *different* local variables: ``@x`` and ``x``_ +
|
`>>>` [blue]`f = func() { @x = 3; x = 5 }` [gray]_// f() declares two *different* local variables: ``@x`` and ``x``_ +
|
||||||
[green]`f():any{}` +
|
[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` +
|
[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._ +
|
`>>>` [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`
|
[green]`3`
|
||||||
@@ -1048,7 +1102,7 @@ Builtins activation is done by using the [blue]`BUILTIN` operator. All modules e
|
|||||||
|
|
||||||
.Builtin activation syntax
|
.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_ +
|
_builtin-name_ = _string_ +
|
||||||
_list-of-builtin-names_ = **[** _string_ { "**,**" _string_ } **]**
|
_list-of-builtin-names_ = **[** _string_ { "**,**" _string_ } **]**
|
||||||
====
|
====
|
||||||
@@ -1086,9 +1140,9 @@ The "base" builtin module provides functions for type checking and type conversi
|
|||||||
* <<_fract,fract()>>
|
* <<_fract,fract()>>
|
||||||
|
|
||||||
.Other functions
|
.Other functions
|
||||||
|
* <<_char,char()>>
|
||||||
* <<_eval,eval()>>
|
* <<_eval,eval()>>
|
||||||
* <<_set,set()>>
|
* <<_set,set()>>
|
||||||
* <<_unset,unset()>>
|
|
||||||
* <<_var,var()>>
|
* <<_var,var()>>
|
||||||
|
|
||||||
|
|
||||||
@@ -1100,7 +1154,9 @@ Returns _true_ if the value type of _<expr>_ is boolean, false otherwise.
|
|||||||
`>>>` [blue]`isBool(true)` +
|
`>>>` [blue]`isBool(true)` +
|
||||||
[green]`true` +
|
[green]`true` +
|
||||||
`>>>` [blue]`isBool(3==2)` +
|
`>>>` [blue]`isBool(3==2)` +
|
||||||
[green]`true`
|
[green]`true` +
|
||||||
|
`>>>` [blue]`isBool(3 + 2)` +
|
||||||
|
[green]`false`
|
||||||
|
|
||||||
===== isDict()
|
===== isDict()
|
||||||
Syntax: `isDict(<expr>) -> bool` +
|
Syntax: `isDict(<expr>) -> bool` +
|
||||||
@@ -1178,7 +1234,7 @@ Returns _true_ if the value type of _<expr>_ is fraction or int, false otherwise
|
|||||||
|
|
||||||
===== isString()
|
===== isString()
|
||||||
Syntax: `isString(<expr>) -> bool` +
|
Syntax: `isString(<expr>) -> bool` +
|
||||||
Returns a boolean value , false otherwise.
|
Returns _true_ if the value type of _<expr>_ is string, false otherwise.
|
||||||
|
|
||||||
.Examples
|
.Examples
|
||||||
`>>>` [blue]`isString("ciao")` +
|
`>>>` [blue]`isString("ciao")` +
|
||||||
@@ -1190,7 +1246,7 @@ Returns a boolean value , false otherwise.
|
|||||||
|
|
||||||
===== bool()
|
===== bool()
|
||||||
Syntax: `bool(<expr>) -> 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
|
.Examples
|
||||||
`>>>` [blue]`bool(1)` +
|
`>>>` [blue]`bool(1)` +
|
||||||
@@ -1295,6 +1351,16 @@ Returns a _fraction_ value consistent with the value of the expression.
|
|||||||
`>>>` [blue]`fract(true)` +
|
`>>>` [blue]`fract(true)` +
|
||||||
[green]`1:1`
|
[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()
|
===== eval()
|
||||||
Syntax: `eval(<string-expr>) -> any` +
|
Syntax: `eval(<string-expr>) -> any` +
|
||||||
Computes and returns the value of the [.underline]#string# expression.
|
Computes and returns the value of the [.underline]#string# expression.
|
||||||
@@ -1308,12 +1374,12 @@ Syntax: +
|
|||||||
`{4sp}var(<string-expr>, <expr>) -> any` +
|
`{4sp}var(<string-expr>, <expr>) -> any` +
|
||||||
`{4sp}var(<string-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
|
.Examples
|
||||||
`>>>` [blue]`var("$x", 3+9)` +
|
`>>>` [blue]`var("$x", 3+9)` +
|
||||||
[green]`12` +
|
[green]`12` +
|
||||||
`>>>` [blue]`var("$x")` +
|
`>>>` [blue]`var("$"+"x")` +
|
||||||
[green]`12` +
|
[green]`12` +
|
||||||
`>>>` [blue]`var("gain%", var("$x"))` +
|
`>>>` [blue]`var("gain%", var("$x"))` +
|
||||||
[green]`12` +
|
[green]`12` +
|
||||||
@@ -1334,26 +1400,17 @@ It is equivalent to the first form of the var() function, but it is more explici
|
|||||||
`>>>` [blue]`var("$x")` +
|
`>>>` [blue]`var("$x")` +
|
||||||
[green]`100` +
|
[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"
|
==== Module "fmt"
|
||||||
|
#to-do#
|
||||||
|
|
||||||
===== print()
|
===== print()
|
||||||
|
|
||||||
===== println()
|
===== println()
|
||||||
|
|
||||||
==== Module "import"
|
==== Module "import"
|
||||||
Module actiovation: +
|
Module activation: +
|
||||||
|
`{4sp}BUILTIN "import"`
|
||||||
|
|
||||||
===== _import()_
|
===== _import()_
|
||||||
Syntax: +
|
Syntax: +
|
||||||
@@ -1364,6 +1421,8 @@ Loads the multi-expression contained in the specified source and returns its val
|
|||||||
===== _importAll()_
|
===== _importAll()_
|
||||||
|
|
||||||
==== Module "iterator"
|
==== Module "iterator"
|
||||||
|
Module activation: +
|
||||||
|
`{4sp}BUILTIN "iterator"`
|
||||||
|
|
||||||
===== run()
|
===== run()
|
||||||
Syntax: +
|
Syntax: +
|
||||||
@@ -1372,6 +1431,9 @@ Syntax: +
|
|||||||
Iterates over the specified iterator and applies the specified operator to the current value of the iterator.
|
Iterates over the specified iterator and applies the specified operator to the current value of the iterator.
|
||||||
|
|
||||||
==== Module "math.arith"
|
==== 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.
|
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()>>
|
* <<_add,add()>>
|
||||||
@@ -1421,13 +1483,12 @@ Same as <<_add,add()>> but returns the product of the values of the parameters.
|
|||||||
[green]`24`
|
[green]`24`
|
||||||
|
|
||||||
==== Module "os.file"
|
==== Module "os.file"
|
||||||
|
Module activation: +
|
||||||
|
`{4sp}BUILTIN "os.file"`
|
||||||
|
|
||||||
The "os.file" module provides functions for working with files.
|
The "os.file" module provides functions for working with files.
|
||||||
|
|
||||||
Activation: +
|
.File related functions
|
||||||
`{4sp}builtin "os.file"`
|
|
||||||
|
|
||||||
Currently available functions:
|
|
||||||
|
|
||||||
* <<_fileOpen,fileOpen()>>
|
* <<_fileOpen,fileOpen()>>
|
||||||
* <<_fileAppend,fileAppend()>>
|
* <<_fileAppend,fileAppend()>>
|
||||||
* <<_fileCreate,fileCreate()>>
|
* <<_fileCreate,fileCreate()>>
|
||||||
@@ -1436,6 +1497,10 @@ Currently available functions:
|
|||||||
* <<_fileReadText,fileReadText()>>
|
* <<_fileReadText,fileReadText()>>
|
||||||
* <<_fileReadTextAll,fileReadTextAll()>>
|
* <<_fileReadTextAll,fileReadTextAll()>>
|
||||||
|
|
||||||
|
.Iterator functions for files
|
||||||
|
* <<_fileByteIterator,fileByteIterator()>>
|
||||||
|
* <<_fileLineIterator,fileLineIterator()>>
|
||||||
|
|
||||||
More functions will be added in the future.
|
More functions will be added in the future.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1447,6 +1512,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.
|
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()
|
===== fileAppend()
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}fileAppend(<file-path>) -> any`
|
||||||
|
|
||||||
|
Like <<_fileCreate,fileCreate()>> but write operations happen at the end of the file.
|
||||||
|
|
||||||
===== fileCreate()
|
===== fileCreate()
|
||||||
Syntax: +
|
Syntax: +
|
||||||
@@ -1455,21 +1524,76 @@ 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.
|
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()
|
===== fileClose()
|
||||||
|
#to-do#
|
||||||
|
|
||||||
===== fileWriteText()
|
===== fileWriteText()
|
||||||
|
#to-do#
|
||||||
|
|
||||||
===== fileReadText()
|
===== fileReadText()
|
||||||
|
#to-do#
|
||||||
|
|
||||||
===== fileReadTextAll()
|
===== fileReadTextAll()
|
||||||
|
#to-do#
|
||||||
|
|
||||||
|
===== fileByteIterator()
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}fileByteIterator(handle-or-path) -> iterator`
|
||||||
|
|
||||||
|
Returns an iterator that produces the bytes of the specified file. The parameter can be either a file handle or a file path. If a file path is provided, the file is opened and closed automatically by the iterator.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
>>> builtin "os.file" +
|
||||||
|
[green]`1` +
|
||||||
|
`>>>` [blue]`fileByteIterator("test-file.txt") map $_` +
|
||||||
|
[green]`[
|
||||||
|
117,
|
||||||
|
110,
|
||||||
|
111,
|
||||||
|
10,
|
||||||
|
100,
|
||||||
|
117,
|
||||||
|
101,
|
||||||
|
10
|
||||||
|
]`
|
||||||
|
|
||||||
|
>>> builtin ["os.file", "string"] +
|
||||||
|
[green]`2` +
|
||||||
|
`>>>` [blue]`fileByteIterator("test-file.txt") map char($_)` +
|
||||||
|
[green]`[
|
||||||
|
"u",
|
||||||
|
"n",
|
||||||
|
"o",
|
||||||
|
"
|
||||||
|
",
|
||||||
|
"d",
|
||||||
|
"u",
|
||||||
|
"e",
|
||||||
|
"
|
||||||
|
",
|
||||||
|
]`
|
||||||
|
|
||||||
|
===== fileLineIterator()
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}fileLineIterator(handle-or-path) -> iterator`
|
||||||
|
|
||||||
|
Returns an iterator that produces the lines of the specified file. The parameter can be either a file handle or a file path. If a file path is provided, the file is opened and closed automatically by the iterator.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
`>>>` [blue]`builtin "os.file"` +
|
||||||
|
[green]`1` +
|
||||||
|
`>>>` [blue]`fileLineIterator("test-file.txt") map $_` +
|
||||||
|
[green]`[
|
||||||
|
"uno",
|
||||||
|
"due"
|
||||||
|
]`
|
||||||
|
|
||||||
|
|
||||||
==== Module "string"
|
==== Module "string"
|
||||||
|
Module activation: +
|
||||||
|
`{4sp}BUILTIN "string"`
|
||||||
|
|
||||||
This module provides functions for working with strings.
|
This module provides functions for working with strings.
|
||||||
|
|
||||||
Activation: +
|
|
||||||
`{4sp}builtin "string"`
|
|
||||||
|
|
||||||
|
|
||||||
Currently available functions:
|
Currently available functions:
|
||||||
|
|
||||||
* <<_strJoin,strJoin()>>
|
* <<_strJoin,strJoin()>>
|
||||||
@@ -1726,6 +1850,54 @@ TIP: Iterators built on custom data-sources can provide additional named operato
|
|||||||
`>>>` [blue]`it.next` +
|
`>>>` [blue]`it.next` +
|
||||||
[green]`"one"`
|
[green]`"one"`
|
||||||
|
|
||||||
|
=== Infixed operators on iterators
|
||||||
|
There are also some infixed operators that can be used with iterators. They are defined as follows.
|
||||||
|
|
||||||
|
* <<_cat,cat operator>>
|
||||||
|
* <<_diget,digest operator>>
|
||||||
|
* <<_filter,filter operator>>
|
||||||
|
* <<_groupby,groupby operator>>
|
||||||
|
* <<_map,map operator>>
|
||||||
|
//* <<_reduce,reduce operator>>: applies a binary expression cumulatively to the elements of the iterator, from left to right, to reduce the iterator to a single value.
|
||||||
|
//* <<_zip,zip operator>>: takes two or more iterators and returns a list of tuples, where the i-th tuple contains the i-th element from each of the input iterators.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
==== [blue]`cat` operator
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}<iterable> cat <iterable> -> <iterator>{4sp}`
|
||||||
|
|
||||||
|
[blue]`cat` operator takes two iterators or iterables and returns a new iterator that produces the elements of the first iterator followed by the elements of the second iterator.
|
||||||
|
|
||||||
|
.Examples
|
||||||
|
|
||||||
|
|
||||||
|
==== [blue]`filter` operator
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}<iterable> filter <expr> -> <iterator>{4sp}`
|
||||||
|
|
||||||
|
[blue]`filter` applies a boolean expression to each element of the iterator and returns a list of the elements for which the expression evaluates to true.
|
||||||
|
|
||||||
|
|
||||||
|
==== [blue]`groupby` operator
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}<dict> groupby <key> -> <dict>{4sp}`
|
||||||
|
|
||||||
|
[blue]`groupby` operator groups the elements of the iterator based on the value of a specified expression and returns a dictionary where the keys are the group values and the values are lists of the elements in each group.
|
||||||
|
|
||||||
|
==== [blue]`map` operator
|
||||||
|
Syntax: +
|
||||||
|
`{4sp}<iterable> map <expr> -> <list>{4sp}`
|
||||||
|
|
||||||
|
|
||||||
|
[blue]`map` operator iterates over the elements of the iterator and evaluates the expressions provided on the right side for each element. Its result is a list of the computed values of the that expression. The current element of the iterator is available in the expression as the variable `$_`.
|
||||||
|
|
||||||
|
.Example: using the [blue]`map` operator
|
||||||
|
`>>>` [blue]`it = $(["one", "two", "three"])` +
|
||||||
|
[green]`$(#3)` +
|
||||||
|
`>>>` [blue]`it map $_ + "!"` +
|
||||||
|
[green]`["one!", "two!", "three!"]`
|
||||||
|
|
||||||
=== Iterator over custom data-sources
|
=== Iterator over custom data-sources
|
||||||
It is possible to create iterators over custom data-sources by defining a dictionary that has the key `next` whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.
|
It is possible to create iterators over custom data-sources by defining a dictionary that has the key `next` whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.
|
||||||
|
|
||||||
|
|||||||
+460
-30
@@ -581,7 +581,11 @@ pre.rouge .ss {
|
|||||||
<li><a href="#_operator">4.1. <code class="blue">;</code> operator</a></li>
|
<li><a href="#_operator">4.1. <code class="blue">;</code> operator</a></li>
|
||||||
<li><a href="#_but_operator">4.2. <code class="blue">but</code> operator</a></li>
|
<li><a href="#_but_operator">4.2. <code class="blue">but</code> operator</a></li>
|
||||||
<li><a href="#_assignment_operator">4.3. Assignment operator <code class="blue">=</code></a></li>
|
<li><a href="#_assignment_operator">4.3. Assignment operator <code class="blue">=</code></a></li>
|
||||||
<li><a href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a></li>
|
<li><a href="#_selector_operator">4.4. Selector operator <code class="blue">? : ::</code></a>
|
||||||
|
<ul class="sectlevel3">
|
||||||
|
<li><a href="#_triple_special_case_of_the_selector_operator">4.4.1. Triple special case of the selector operator</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li><a href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></li>
|
<li><a href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -613,8 +617,10 @@ pre.rouge .ss {
|
|||||||
<li><a href="#_dec">dec()</a></li>
|
<li><a href="#_dec">dec()</a></li>
|
||||||
<li><a href="#_string">string()</a></li>
|
<li><a href="#_string">string()</a></li>
|
||||||
<li><a href="#_fract">fract()</a></li>
|
<li><a href="#_fract">fract()</a></li>
|
||||||
|
<li><a href="#_char">char()</a></li>
|
||||||
<li><a href="#_eval">eval()</a></li>
|
<li><a href="#_eval">eval()</a></li>
|
||||||
<li><a href="#_var">var()</a></li>
|
<li><a href="#_var">var()</a></li>
|
||||||
|
<li><a href="#_set">set</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="#_module_fmt">7.1.2. Module "fmt"</a>
|
<li><a href="#_module_fmt">7.1.2. Module "fmt"</a>
|
||||||
@@ -649,6 +655,8 @@ pre.rouge .ss {
|
|||||||
<li><a href="#_filewritetext">fileWriteText()</a></li>
|
<li><a href="#_filewritetext">fileWriteText()</a></li>
|
||||||
<li><a href="#_filereadtext">fileReadText()</a></li>
|
<li><a href="#_filereadtext">fileReadText()</a></li>
|
||||||
<li><a href="#_filereadtextall">fileReadTextAll()</a></li>
|
<li><a href="#_filereadtextall">fileReadTextAll()</a></li>
|
||||||
|
<li><a href="#_filebyteiterator">fileByteIterator()</a></li>
|
||||||
|
<li><a href="#_filelineiterator">fileLineIterator()</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="#_module_string">7.1.7. Module "string"</a>
|
<li><a href="#_module_string">7.1.7. Module "string"</a>
|
||||||
@@ -674,7 +682,15 @@ pre.rouge .ss {
|
|||||||
<li><a href="#_named_operators">8.1.1. Named operators</a></li>
|
<li><a href="#_named_operators">8.1.1. Named operators</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="#_iterator_over_custom_data_sources">8.2. Iterator over custom data-sources</a></li>
|
<li><a href="#_infixed_operators_on_iterators">8.2. Infixed operators on iterators</a>
|
||||||
|
<ul class="sectlevel3">
|
||||||
|
<li><a href="#_cat_operator">8.2.1. <code class="blue">cat</code> operator</a></li>
|
||||||
|
<li><a href="#_filter_operator">8.2.2. <code class="blue">filter</code> operator</a></li>
|
||||||
|
<li><a href="#_groupby_operator">8.2.3. <code class="blue">groupby</code> operator</a></li>
|
||||||
|
<li><a href="#_map_operator">8.2.4. <code class="blue">map</code> operator</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="#_iterator_over_custom_data_sources">8.3. Iterator over custom data-sources</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="#_plugins">9. Plugins</a></li>
|
<li><a href="#_plugins">9. Plugins</a></li>
|
||||||
@@ -686,7 +702,7 @@ pre.rouge .ss {
|
|||||||
<div class="sectionbody">
|
<div class="sectionbody">
|
||||||
<!-- toc disabled -->
|
<!-- toc disabled -->
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><mark>TODO: Work in progress (last update on 2026/04/15, 6:02 p.m.)</mark></p>
|
<p><mark>TODO: Work in progress (last update on 2026/05/08)</mark></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -788,7 +804,26 @@ pre.rouge .ss {
|
|||||||
<code class="green">}</code></p>
|
<code class="green">}</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>In order to inspect the global context issue the <code class="blue">$$global</code> operator.</p>
|
<p>In order to inspect the global context issue the <code class="blue">$$ global</code> operation.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Example: list all functions whose name starts with "str"</div>
|
||||||
|
<p><code>>>></code> <code class="blue">builtin "string</code> <em class="gray">// most function in the builtin module <strong>string</strong> have names starting with "str".</em><br>
|
||||||
|
<code class="green">1</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code>>>></code> <code class="blue">($$$global).functions) filter strStartsWith($_, "str"</code><br>
|
||||||
|
<code class="green">[</code><br>
|
||||||
|
<code class="green">  "strEndsWith",</code><br>
|
||||||
|
<code class="green">  "strJoin",</code><br>
|
||||||
|
<code class="green">  "strLower",</code><br>
|
||||||
|
<code class="green">  "strSplit",</code><br>
|
||||||
|
<code class="green">  "strStartsWith",</code><br>
|
||||||
|
<code class="green">  "strSub",</code><br>
|
||||||
|
<code class="green">  "strTrim",</code><br>
|
||||||
|
<code class="green">  "strUpper",</code><br>
|
||||||
|
<code class="green">  "string"</code><br>
|
||||||
|
<code class="green">]</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1880,10 +1915,10 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
<p>The <em>selector operator</em> is very similar to the <em>switch/case/default</em> statement available in many programming languages.</p>
|
<p>The <em>selector operator</em> is very similar to the <em>switch/case/default</em> statement available in many programming languages.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="exampleblock">
|
<div class="exampleblock">
|
||||||
<div class="title">Example 13. Selector literal Syntax</div>
|
<div class="title">Example 13. Selector literal syntax</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><em>selector-operator</em> = <em>select-expression</em> "<strong>?</strong>" <em>selector-case</em> { "<strong>:</strong>" <em>selector-case</em> } ["<strong>::</strong>" <em>default-multi-expression</em>]<br>
|
<p><strong><em>selector-operator</em></strong> = <em>select-expression</em> "<strong>?</strong>" <em>selector-case</em> { "<strong>:</strong>" <em>selector-case</em> } ["<strong>::</strong>" <em>default-multi-expression</em>]<br>
|
||||||
<em>selector-case</em> = [<em>match-list</em>] <em>case-value</em><br>
|
<em>selector-case</em> = [<em>match-list</em>] <em>case-value</em><br>
|
||||||
<em>match-list</em> = "<strong>[</strong>" <em>item</em> {"<strong>,</strong>" <em>items</em>} "<strong>]</strong>"<br>
|
<em>match-list</em> = "<strong>[</strong>" <em>item</em> {"<strong>,</strong>" <em>items</em>} "<strong>]</strong>"<br>
|
||||||
<em>item</em> = <em>expression</em><br>
|
<em>item</em> = <em>expression</em><br>
|
||||||
@@ -1931,11 +1966,45 @@ Technically <code class="blue">;</code> is not treated as a real operator. It ac
|
|||||||
<p><code>>>></code> <code class="blue">10 ? {"a"} : {"b"}</code><br>
|
<p><code>>>></code> <code class="blue">10 ? {"a"} : {"b"}</code><br>
|
||||||
<code class="red">Eval Error: [1:3] no case catches the value (10) of the selection expression</code></p>
|
<code class="red">Eval Error: [1:3] no case catches the value (10) of the selection expression</code></p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sect3">
|
||||||
|
<h4 id="_triple_special_case_of_the_selector_operator"><a class="anchor" href="#_triple_special_case_of_the_selector_operator"></a><a class="link" href="#_triple_special_case_of_the_selector_operator">4.4.1. Triple special case of the selector operator</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>If the <em>select-expression</em> is a boolean expression, the selector operator can be used as a sort of <em>if-then-else</em> statement. In this case, the first case is evaluated if the <em>select-expression</em> is true, and the second case is evaluated if the <em>select-expression</em> is false. In this special case, the <em>match-list</em> of both cases must be empty.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Example</div>
|
||||||
|
<p><code>>>></code> <code class="blue">(true) ? {"T"}: {"F"}</code><br>
|
||||||
|
<code class="green">T</code><br>
|
||||||
|
<code>>>></code> <code class="blue">(2 > 1) ? {"a"} : {"b"}</code><br>
|
||||||
|
<code class="green">a</code><br>
|
||||||
|
<code>>>></code> <code class="blue">(2 < 1) ? {"a"} : {"b"}</code><br>
|
||||||
|
<code class="green">b</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="admonitionblock warning">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td class="icon">
|
||||||
|
<i class="fa icon-warning" title="Warning"></i>
|
||||||
|
</td>
|
||||||
|
<td class="content">
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>The triple special case of the selector operator is very useful, but it only works with boolean expressions.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Example of confusion</div>
|
||||||
|
<p><code>>>></code> <code class="blue">int(true) ? {"T"}: {"F"}</code><br>
|
||||||
|
<code class="green">F</code></p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect2">
|
<div class="sect2">
|
||||||
<h3 id="_variable_default_value_and"><a class="anchor" href="#_variable_default_value_and"></a><a class="link" href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></h3>
|
<h3 id="_variable_default_value_and"><a class="anchor" href="#_variable_default_value_and"></a><a class="link" href="#_variable_default_value_and">4.5. Variable default value <code class="blue">??</code>, <code class="blue">?=</code>, and <code class="blue">?!</code></a></h3>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The left operand of the first two operators, <code class="blue">??</code> and <code class="blue">?=</code>, 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.</p>
|
<p>The left operand of the first two operators, <code class="blue">??</code> and <code class="blue">?=</code>, 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.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="admonitionblock important">
|
<div class="admonitionblock important">
|
||||||
<table>
|
<table>
|
||||||
@@ -1953,7 +2022,7 @@ If the left variable is defined, the right expression is not evaluated at all.
|
|||||||
<p>The <code class="blue">??</code> operator do not change the status of the left variable.</p>
|
<p>The <code class="blue">??</code> operator do not change the status of the left variable.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The <code class="blue">?=</code> assigns the calculated value of the right expression to the left variable.</p>
|
<p>The <code class="blue">?=</code> assigns the calculated value of the right expression to the variable on the left side.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>The third one, <code class="blue">?!</code>, is the alternate operator. If the variable on the left size is not defined, it returns <em class="blue">nil</em>. Otherwise it returns the result of the expressione on the right side.</p>
|
<p>The third one, <code class="blue">?!</code>, is the alternate operator. If the variable on the left size is not defined, it returns <em class="blue">nil</em>. Otherwise it returns the result of the expressione on the right side.</p>
|
||||||
@@ -1965,7 +2034,7 @@ If the left variable is defined, the right expression is not evaluated at all.
|
|||||||
<i class="fa icon-important" title="Important"></i>
|
<i class="fa icon-important" title="Important"></i>
|
||||||
</td>
|
</td>
|
||||||
<td class="content">
|
<td class="content">
|
||||||
If the left variable is NOT defined, the right expression is not evaluated at all.
|
If the variable <code class="blue">?!</code> is NOT defined, the expression is not evaluated at all.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -2371,7 +2440,7 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>identifier</em> <code>=</code> <em>any</em> → <em>any</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>identifier</em> <code>=</code> <em>any</em> → <em>any</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-center valign-top" colspan="4"><p class="tableblock"><em>See also the table of special allocation operators below</em></p></td>
|
<td class="tableblock halign-center valign-top" colspan="4"><p class="tableblock"><em>See also the table of special assignment operators below</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BUT</strong></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>BUT</strong></p></td>
|
||||||
@@ -2381,6 +2450,40 @@ These operators have a high priority, in particular higher than the operator <co
|
|||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>but</code> <em>any</em> → <em>any</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>any</em> <code>but</code> <em>any</em> → <em>any</em></p></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top" rowspan="6"><p class="tableblock"><strong>ITER-OP</strong></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">digest</code></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Item-digesting</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterable</em> <code>digest</code> <em>expr</em> → <em>any</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">filter</code></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Item-filtering</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterable</em> <code>filter</code> <em>expr</em> → <em>list</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">groupby</code></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Dict-grouping</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterable</em> <code>groupby</code> <em>key-expr</em> → <em>dict</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">cat</code></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Item-concatenation</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterable</em> `cat ` <em>iterable</em> → <em>list</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">map</code></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Item-mapping</em></p></td>
|
||||||
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>iterable</em> <code>map</code> <em>-expr</em> → <em>list</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="tableblock halign-center valign-top" colspan="4"><p class="tableblock"><em>See iterators section for examples</em></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>RANGE</strong></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><strong>RANGE</strong></p></td>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">:</code></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">:</code></p></td>
|
||||||
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
|
||||||
@@ -2536,14 +2639,14 @@ short for<br>
|
|||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><code>>>></code> <em class="gray">// Required and optional parameters</em><br>
|
<p><code>>>></code> <em class="gray">// Required and optional parameters</em><br>
|
||||||
<code>>>></code> <code class="blue">measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? [true] {"s"} :: {""}}</code><br>
|
<code>>>></code> <code class="blue">measure = func(value, unit="meter"){ value + " " + unit + (value > 1) ? {"s"} :: {""}}</code><br>
|
||||||
<code class="green">measure(value, unit="meter"):any{}</code></p>
|
<code class="green">measure(value, unit="meter"):any{}</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect2">
|
<div class="sect2">
|
||||||
<h3 id="_golang_function_definition"><a class="anchor" href="#_golang_function_definition"></a><a class="link" href="#_golang_function_definition">6.2. <em>Golang</em> function definition</a></h3>
|
<h3 id="_golang_function_definition"><a class="anchor" href="#_golang_function_definition"></a><a class="link" href="#_golang_function_definition">6.2. <em>Golang</em> function definition</a></h3>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Description of how to define Golang functions and how to bind them to <em>Expr</em> are topics covered in another document that I’ll write, one day, maybe.</p>
|
<p>Description of how to define Golang functions and how to bind them to <em>Expr</em> are topics covered in another documents that I’ll write, one day, maybe.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect2">
|
<div class="sect2">
|
||||||
@@ -2642,7 +2745,7 @@ short for<br>
|
|||||||
<div class="title">Example</div>
|
<div class="title">Example</div>
|
||||||
<p><code>>>></code> <code class="blue">f = func() { @x = 3; x = 5 }</code> <em class="gray">// f() declares two <strong>different</strong> local variables: <code>@x</code> and <code>x</code></em><br>
|
<p><code>>>></code> <code class="blue">f = func() { @x = 3; x = 5 }</code> <em class="gray">// f() declares two <strong>different</strong> local variables: <code>@x</code> and <code>x</code></em><br>
|
||||||
<code class="green">f():any{}</code><br>
|
<code class="green">f():any{}</code><br>
|
||||||
<code>>>></code> <code class="blue">f()</code> <em class="gray">// The multi-expression (two) in f() is calculated and the last result is returned</em><br>
|
<code>>>></code> <code class="blue">f()</code> <em class="gray">// The multi-expression (two expressions) in f() is calculated and the last result is returned</em><br>
|
||||||
<code class="green">5</code><br>
|
<code class="green">5</code><br>
|
||||||
<code>>>></code> <code class="blue">x</code> <em class="gray">// The <code>x</code> variable was not defined in the main context before the f() invocation. It appears in the main context by cloning the <code>@x</code> variable, local to f() after its termnation.</em><br>
|
<code>>>></code> <code class="blue">x</code> <em class="gray">// The <code>x</code> variable was not defined in the main context before the f() invocation. It appears in the main context by cloning the <code>@x</code> variable, local to f() after its termnation.</em><br>
|
||||||
<code class="green">3</code></p>
|
<code class="green">3</code></p>
|
||||||
@@ -2727,7 +2830,7 @@ The clone modifier <code class="blue">@</code> does not make a variable a refere
|
|||||||
<div class="title">Example 16. Builtin activation syntax</div>
|
<div class="title">Example 16. Builtin activation syntax</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><strong><em>builtin-activation</em></strong> = <code class="blue">BUILTIN</code> (<em>builtin-name</em> | <em>list-of-builtin-names</em>)<br>
|
<p><strong><em>builtin-activation</em></strong> = <code class="blue">BUILTIN</code> (<em>builtin-name</em> | <em>list-of-builtin-names</em> | <strong>"*"</strong>)<br>
|
||||||
<em>builtin-name</em> = <em>string</em><br>
|
<em>builtin-name</em> = <em>string</em><br>
|
||||||
<em>list-of-builtin-names</em> = <strong>[</strong> <em>string</em> { "<strong>,</strong>" <em>string</em> } <strong>]</strong></p>
|
<em>list-of-builtin-names</em> = <strong>[</strong> <em>string</em> { "<strong>,</strong>" <em>string</em> } <strong>]</strong></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -2815,9 +2918,15 @@ To avoid the need to activate builtin modules one by one, it is possible to acti
|
|||||||
<div class="title">Other functions</div>
|
<div class="title">Other functions</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
<p><a href="#_char">char()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
<p><a href="#_eval">eval()</a></p>
|
<p><a href="#_eval">eval()</a></p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
<p><a href="#_set">set()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
<p><a href="#_var">var()</a></p>
|
<p><a href="#_var">var()</a></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -2833,7 +2942,9 @@ Returns <em>true</em> if the value type of <em><expr></em> is boolean, fal
|
|||||||
<p><code>>>></code> <code class="blue">isBool(true)</code><br>
|
<p><code>>>></code> <code class="blue">isBool(true)</code><br>
|
||||||
<code class="green">true</code><br>
|
<code class="green">true</code><br>
|
||||||
<code>>>></code> <code class="blue">isBool(3==2)</code><br>
|
<code>>>></code> <code class="blue">isBool(3==2)</code><br>
|
||||||
<code class="green">true</code></p>
|
<code class="green">true</code><br>
|
||||||
|
<code>>>></code> <code class="blue">isBool(3 + 2)</code><br>
|
||||||
|
<code class="green">false</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
@@ -2938,7 +3049,7 @@ Returns <em>true</em> if the value type of <em><expr></em> is fraction or
|
|||||||
<h5 id="_isstring"><a class="anchor" href="#_isstring"></a><a class="link" href="#_isstring">isString()</a></h5>
|
<h5 id="_isstring"><a class="anchor" href="#_isstring"></a><a class="link" href="#_isstring">isString()</a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Syntax: <code>isString(<expr>) → bool</code><br>
|
<p>Syntax: <code>isString(<expr>) → bool</code><br>
|
||||||
Returns a boolean value , false otherwise.</p>
|
Returns <em>true</em> if the value type of <em><expr></em> is string, false otherwise.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Examples</div>
|
<div class="title">Examples</div>
|
||||||
@@ -2954,7 +3065,7 @@ Returns a boolean value , false otherwise.</p>
|
|||||||
<h5 id="_bool"><a class="anchor" href="#_bool"></a><a class="link" href="#_bool">bool()</a></h5>
|
<h5 id="_bool"><a class="anchor" href="#_bool"></a><a class="link" href="#_bool">bool()</a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Syntax: <code>bool(<expr>) → bool</code><br>
|
<p>Syntax: <code>bool(<expr>) → bool</code><br>
|
||||||
Returns a <em>boolean</em> value consisent to the value of the expression.</p>
|
Returns a <em>boolean</em> value consisent with the value of the expression.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Examples</div>
|
<div class="title">Examples</div>
|
||||||
@@ -3077,6 +3188,20 @@ Returns a <em>fraction</em> value consistent with the value of the expression.</
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
|
<h5 id="_char"><a class="anchor" href="#_char"></a><a class="link" href="#_char">char()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax: <code>char(<intexpr>) → string</code><br>
|
||||||
|
Returns the character whose ASCII (soon Unicode too) code point is specified by the integer expression.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Examples</div>
|
||||||
|
<p><code>>>></code> <code class="blue">char(65)</code><br>
|
||||||
|
<code class="green">"A"</code><br>
|
||||||
|
<code>>>></code> <code class="blue">char(97)</code><br>
|
||||||
|
<code class="green">"a"</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect4">
|
||||||
<h5 id="_eval"><a class="anchor" href="#_eval"></a><a class="link" href="#_eval">eval()</a></h5>
|
<h5 id="_eval"><a class="anchor" href="#_eval"></a><a class="link" href="#_eval">eval()</a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>Syntax: <code>eval(<string-expr>) → any</code><br>
|
<p>Syntax: <code>eval(<string-expr>) → any</code><br>
|
||||||
@@ -3096,13 +3221,13 @@ Computes and returns the value of the <span class="underline">string</span> expr
|
|||||||
<code>    var(<string-expr>) → any</code></p>
|
<code>    var(<string-expr>) → any</code></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>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.</p>
|
<p>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.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<div class="title">Examples</div>
|
<div class="title">Examples</div>
|
||||||
<p><code>>>></code> <code class="blue">var("$x", 3+9)</code><br>
|
<p><code>>>></code> <code class="blue">var("$x", 3+9)</code><br>
|
||||||
<code class="green">12</code><br>
|
<code class="green">12</code><br>
|
||||||
<code>>>></code> <code class="blue">var("$x")</code><br>
|
<code>>>></code> <code class="blue">var("$"+"x")</code><br>
|
||||||
<code class="green">12</code><br>
|
<code class="green">12</code><br>
|
||||||
<code>>>></code> <code class="blue">var("gain%", var("$x"))</code><br>
|
<code>>>></code> <code class="blue">var("gain%", var("$x"))</code><br>
|
||||||
<code class="green">12</code><br>
|
<code class="green">12</code><br>
|
||||||
@@ -3110,9 +3235,32 @@ Computes and returns the value of the <span class="underline">string</span> expr
|
|||||||
<code class="green">13</code></p>
|
<code class="green">13</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sect4">
|
||||||
|
<h5 id="_set"><a class="anchor" href="#_set"></a><a class="link" href="#_set">set</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    set(<string-expr>, <expr>) → any</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>This function allows you to set the value of a variable whose name can include special characters. The first parameter is the name of the variable and the second parameter is the new value to assign to that variable.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>It is equivalent to the first form of the var() function, but it is more explicit about the intent of changing the value of an existing variable.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Examples</div>
|
||||||
|
<p><code>>>></code> <code class="blue">set("$x", 100)</code><br>
|
||||||
|
<code class="green">100</code><br>
|
||||||
|
<code>>>></code> <code class="blue">var("$x")</code><br>
|
||||||
|
<code class="green">100</code><br></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_fmt"><a class="anchor" href="#_module_fmt"></a><a class="link" href="#_module_fmt">7.1.2. Module "fmt"</a></h4>
|
<h4 id="_module_fmt"><a class="anchor" href="#_module_fmt"></a><a class="link" href="#_module_fmt">7.1.2. Module "fmt"</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><mark>to-do</mark></p>
|
||||||
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_print"><a class="anchor" href="#_print"></a><a class="link" href="#_print">print()</a></h5>
|
<h5 id="_print"><a class="anchor" href="#_print"></a><a class="link" href="#_print">print()</a></h5>
|
||||||
|
|
||||||
@@ -3124,10 +3272,18 @@ Computes and returns the value of the <span class="underline">string</span> expr
|
|||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_import"><a class="anchor" href="#_module_import"></a><a class="link" href="#_module_import">7.1.3. Module "import"</a></h4>
|
<h4 id="_module_import"><a class="anchor" href="#_module_import"></a><a class="link" href="#_module_import">7.1.3. Module "import"</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Module activation:<br>
|
||||||
|
<code>    BUILTIN "import"</code></p>
|
||||||
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_import"><a class="anchor" href="#_import"></a><a class="link" href="#_import"><em>import()</em></a></h5>
|
<h5 id="_import"><a class="anchor" href="#_import"></a><a class="link" href="#_import"><em>import()</em></a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p><em class="blue">import(<span class="grey"><source-file></span>)</em> — loads the multi-expression contained in the specified source and returns its value.</p>
|
<p>Syntax:<br>
|
||||||
|
<code>    import(<source-file>)</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Loads the multi-expression contained in the specified source and returns its value.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
@@ -3137,16 +3293,40 @@ Computes and returns the value of the <span class="underline">string</span> expr
|
|||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_iterator"><a class="anchor" href="#_module_iterator"></a><a class="link" href="#_module_iterator">7.1.4. Module "iterator"</a></h4>
|
<h4 id="_module_iterator"><a class="anchor" href="#_module_iterator"></a><a class="link" href="#_module_iterator">7.1.4. Module "iterator"</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Module activation:<br>
|
||||||
|
<code>    BUILTIN "iterator"</code></p>
|
||||||
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_run"><a class="anchor" href="#_run"></a><a class="link" href="#_run">run()</a></h5>
|
<h5 id="_run"><a class="anchor" href="#_run"></a><a class="link" href="#_run">run()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    run(<iterator>, <operator>, <vars>) → any</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Iterates over the specified iterator and applies the specified operator to the current value of the iterator.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_math_arith"><a class="anchor" href="#_module_math_arith"></a><a class="link" href="#_module_math_arith">7.1.5. Module "math.arith"</a></h4>
|
<h4 id="_module_math_arith"><a class="anchor" href="#_module_math_arith"></a><a class="link" href="#_module_math_arith">7.1.5. Module "math.arith"</a></h4>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
|
<p>Module activation:<br>
|
||||||
|
<code>    BUILTIN "math.arith"</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
<p>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.</p>
|
<p>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.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ulist">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_add">add()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_mul">mul()</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_add"><a class="anchor" href="#_add"></a><a class="link" href="#_add">add()</a></h5>
|
<h5 id="_add"><a class="anchor" href="#_add"></a><a class="link" href="#_add">add()</a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
@@ -3202,37 +3382,213 @@ Computes and returns the value of the <span class="underline">string</span> expr
|
|||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_os_file"><a class="anchor" href="#_module_os_file"></a><a class="link" href="#_module_os_file">7.1.6. Module "os.file"</a></h4>
|
<h4 id="_module_os_file"><a class="anchor" href="#_module_os_file"></a><a class="link" href="#_module_os_file">7.1.6. Module "os.file"</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Module activation:<br>
|
||||||
|
<code>    BUILTIN "os.file"</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>The "os.file" module provides functions for working with files.</p>
|
||||||
|
</div>
|
||||||
|
<div class="ulist">
|
||||||
|
<div class="title">File related functions</div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileOpen">fileOpen()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileAppend">fileAppend()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileCreate">fileCreate()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileClose">fileClose()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileWriteText">fileWriteText()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileReadText">fileReadText()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileReadTextAll">fileReadTextAll()</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="ulist">
|
||||||
|
<div class="title">Iterator functions for files</div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileByteIterator">fileByteIterator()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_fileLineIterator">fileLineIterator()</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>More functions will be added in the future.</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_fileopen"><a class="anchor" href="#_fileopen"></a><a class="link" href="#_fileopen">fileOpen()</a></h5>
|
<h5 id="_fileopen"><a class="anchor" href="#_fileopen"></a><a class="link" href="#_fileopen">fileOpen()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    fileOpen(<file-path>) → file-handle</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>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.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_fileappend"><a class="anchor" href="#_fileappend"></a><a class="link" href="#_fileappend">fileAppend()</a></h5>
|
<h5 id="_fileappend"><a class="anchor" href="#_fileappend"></a><a class="link" href="#_fileappend">fileAppend()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    fileAppend(<file-path>) → any</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Like <a href="#_fileCreate">fileCreate()</a> but write operations happen at the end of the file.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_filecreate"><a class="anchor" href="#_filecreate"></a><a class="link" href="#_filecreate">fileCreate()</a></h5>
|
<h5 id="_filecreate"><a class="anchor" href="#_filecreate"></a><a class="link" href="#_filecreate">fileCreate()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    fileCreate(<file-path>) → file-handle</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Creates or truncates the named <em><file-path></em>. 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.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_fileclose"><a class="anchor" href="#_fileclose"></a><a class="link" href="#_fileclose">fileClose()</a></h5>
|
<h5 id="_fileclose"><a class="anchor" href="#_fileclose"></a><a class="link" href="#_fileclose">fileClose()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><mark>to-do</mark></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_filewritetext"><a class="anchor" href="#_filewritetext"></a><a class="link" href="#_filewritetext">fileWriteText()</a></h5>
|
<h5 id="_filewritetext"><a class="anchor" href="#_filewritetext"></a><a class="link" href="#_filewritetext">fileWriteText()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><mark>to-do</mark></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_filereadtext"><a class="anchor" href="#_filereadtext"></a><a class="link" href="#_filereadtext">fileReadText()</a></h5>
|
<h5 id="_filereadtext"><a class="anchor" href="#_filereadtext"></a><a class="link" href="#_filereadtext">fileReadText()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><mark>to-do</mark></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_filereadtextall"><a class="anchor" href="#_filereadtextall"></a><a class="link" href="#_filereadtextall">fileReadTextAll()</a></h5>
|
<h5 id="_filereadtextall"><a class="anchor" href="#_filereadtextall"></a><a class="link" href="#_filereadtextall">fileReadTextAll()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><mark>to-do</mark></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect4">
|
||||||
|
<h5 id="_filebyteiterator"><a class="anchor" href="#_filebyteiterator"></a><a class="link" href="#_filebyteiterator">fileByteIterator()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    fileByteIterator(handle-or-path) → iterator</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Returns an iterator that produces the bytes of the specified file. The parameter can be either a file handle or a file path. If a file path is provided, the file is opened and closed automatically by the iterator.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Examples</div>
|
||||||
|
<p>>>> builtin "os.file"<br>
|
||||||
|
<code class="green">1</code><br>
|
||||||
|
<code>>>></code> <code class="blue">fileByteIterator("test-file.txt") map $_</code><br>
|
||||||
|
<code class="green">[
|
||||||
|
117,
|
||||||
|
110,
|
||||||
|
111,
|
||||||
|
10,
|
||||||
|
100,
|
||||||
|
117,
|
||||||
|
101,
|
||||||
|
10
|
||||||
|
]</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>>>> builtin ["os.file", "string"]<br>
|
||||||
|
<code class="green">2</code><br>
|
||||||
|
<code>>>></code> <code class="blue">fileByteIterator("test-file.txt") map char($_)</code><br>
|
||||||
|
<code class="green">[
|
||||||
|
"u",
|
||||||
|
"n",
|
||||||
|
"o",
|
||||||
|
"
|
||||||
|
",
|
||||||
|
"d",
|
||||||
|
"u",
|
||||||
|
"e",
|
||||||
|
"
|
||||||
|
",
|
||||||
|
]</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect4">
|
||||||
|
<h5 id="_filelineiterator"><a class="anchor" href="#_filelineiterator"></a><a class="link" href="#_filelineiterator">fileLineIterator()</a></h5>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    fileLineIterator(handle-or-path) → iterator</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Returns an iterator that produces the lines of the specified file. The parameter can be either a file handle or a file path. If a file path is provided, the file is opened and closed automatically by the iterator.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Examples</div>
|
||||||
|
<p><code>>>></code> <code class="blue">builtin "os.file"</code><br>
|
||||||
|
<code class="green">1</code><br>
|
||||||
|
<code>>>></code> <code class="blue">fileLineIterator("test-file.txt") map $_</code><br>
|
||||||
|
<code class="green">[
|
||||||
|
"uno",
|
||||||
|
"due"
|
||||||
|
]</code></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect3">
|
<div class="sect3">
|
||||||
<h4 id="_module_string"><a class="anchor" href="#_module_string"></a><a class="link" href="#_module_string">7.1.7. Module "string"</a></h4>
|
<h4 id="_module_string"><a class="anchor" href="#_module_string"></a><a class="link" href="#_module_string">7.1.7. Module "string"</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Module activation:<br>
|
||||||
|
<code>    BUILTIN "string"</code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>This module provides functions for working with strings.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Currently available functions:</p>
|
||||||
|
</div>
|
||||||
|
<div class="ulist">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strJoin">strJoin()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strSub">strSub()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strSplit">strSplit()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strTrim">strTrim()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strStartsWith">strStartsWith()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strEndsWith">strEndsWith()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strUpper">strUpper()</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_strLower">strLower()</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
<div class="sect4">
|
<div class="sect4">
|
||||||
<h5 id="_strjoin"><a class="anchor" href="#_strjoin"></a><a class="link" href="#_strjoin">strJoin()</a></h5>
|
<h5 id="_strjoin"><a class="anchor" href="#_strjoin"></a><a class="link" href="#_strjoin">strJoin()</a></h5>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
@@ -3589,7 +3945,81 @@ Iterators built on custom data-sources can provide additional named operators, d
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sect2">
|
<div class="sect2">
|
||||||
<h3 id="_iterator_over_custom_data_sources"><a class="anchor" href="#_iterator_over_custom_data_sources"></a><a class="link" href="#_iterator_over_custom_data_sources">8.2. Iterator over custom data-sources</a></h3>
|
<h3 id="_infixed_operators_on_iterators"><a class="anchor" href="#_infixed_operators_on_iterators"></a><a class="link" href="#_infixed_operators_on_iterators">8.2. Infixed operators on iterators</a></h3>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>There are also some infixed operators that can be used with iterators. They are defined as follows.</p>
|
||||||
|
</div>
|
||||||
|
<div class="ulist">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_cat">cat operator</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_diget">digest operator</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_filter">filter operator</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_groupby">groupby operator</a></p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p><a href="#_map">map operator</a></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="sect3">
|
||||||
|
<h4 id="_cat_operator"><a class="anchor" href="#_cat_operator"></a><a class="link" href="#_cat_operator">8.2.1. <code class="blue">cat</code> operator</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    <iterable> cat <iterable> → <iterator>    </code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code class="blue">cat</code> operator takes two iterators or iterables and returns a new iterator that produces the elements of the first iterator followed by the elements of the second iterator.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect3">
|
||||||
|
<h4 id="_filter_operator"><a class="anchor" href="#_filter_operator"></a><a class="link" href="#_filter_operator">8.2.2. <code class="blue">filter</code> operator</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Examples</div>
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    <iterable> filter <expr> → <iterator>    </code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code class="blue">filter</code> applies a boolean expression to each element of the iterator and returns a list of the elements for which the expression evaluates to true.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect3">
|
||||||
|
<h4 id="_groupby_operator"><a class="anchor" href="#_groupby_operator"></a><a class="link" href="#_groupby_operator">8.2.3. <code class="blue">groupby</code> operator</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    <dict> groupby <key> → <dict>    </code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code class="blue">groupby</code> operator groups the elements of the iterator based on the value of a specified expression and returns a dictionary where the keys are the group values and the values are lists of the elements in each group.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect3">
|
||||||
|
<h4 id="_map_operator"><a class="anchor" href="#_map_operator"></a><a class="link" href="#_map_operator">8.2.4. <code class="blue">map</code> operator</a></h4>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p>Syntax:<br>
|
||||||
|
<code>    <iterable> map <expr> → <list>    </code></p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<p><code class="blue">map</code> operator iterates over the elements of the iterator and evaluates the expressions provided on the right side for each element. Its result is a list of the computed values of the that expression. The current element of the iterator is available in the expression as the variable <code>$_</code>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="paragraph">
|
||||||
|
<div class="title">Example: using the <code class="blue">map</code> operator</div>
|
||||||
|
<p><code>>>></code> <code class="blue">it = $(["one", "two", "three"])</code><br>
|
||||||
|
<code class="green">$(#3)</code><br>
|
||||||
|
<code>>>></code> <code class="blue">it map $_ + "!"</code><br>
|
||||||
|
<code class="green">["one!", "two!", "three!"]</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sect2">
|
||||||
|
<h3 id="_iterator_over_custom_data_sources"><a class="anchor" href="#_iterator_over_custom_data_sources"></a><a class="link" href="#_iterator_over_custom_data_sources">8.3. Iterator over custom data-sources</a></h3>
|
||||||
<div class="paragraph">
|
<div class="paragraph">
|
||||||
<p>It is possible to create iterators over custom data-sources by defining a dictionary that has the key <code>next</code> whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.</p>
|
<p>It is possible to create iterators over custom data-sources by defining a dictionary that has the key <code>next</code> whose value is a function that returns the next element of the collection and updates the state of the iterator. The syntax for creating an iterator over a custom data-source is as follows.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -3610,7 +4040,7 @@ Iterators built on custom data-sources can provide additional named operators, d
|
|||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div id="footer-text">
|
<div id="footer-text">
|
||||||
Last updated 2026-04-21 06:35:14 +0200
|
Last updated 2026-05-12 16:25:27 +0200
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -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 &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() && 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 &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() && 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>
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
-388
@@ -1,388 +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"
|
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ---- 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 *scan.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
|
|
||||||
// }
|
|
||||||
+10
-12
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// global-context.go
|
// global-context.go
|
||||||
@@ -42,12 +42,16 @@ func ImportInContextByGlobPattern(ctx kern.ExprContext, pattern string) (count i
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) {
|
func fixCtrlVar(name string) string {
|
||||||
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
|
|
||||||
if !strings.HasPrefix(name, "_") {
|
if !strings.HasPrefix(name, "_") {
|
||||||
name = "_" + name
|
name = "_" + name
|
||||||
}
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) {
|
||||||
|
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
|
||||||
|
name = fixCtrlVar(name)
|
||||||
currentValue, _ = globalCtx.GetVar(name)
|
currentValue, _ = globalCtx.GetVar(name)
|
||||||
globalCtx.SetVar(name, newValue)
|
globalCtx.SetVar(name, newValue)
|
||||||
}
|
}
|
||||||
@@ -56,18 +60,14 @@ func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValu
|
|||||||
|
|
||||||
func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) {
|
func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) {
|
||||||
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
|
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
|
||||||
if !strings.HasPrefix(name, "_") {
|
name = fixCtrlVar(name)
|
||||||
name = "_" + name
|
|
||||||
}
|
|
||||||
currentValue, _ = globalCtx.GetVar(name)
|
currentValue, _ = globalCtx.GetVar(name)
|
||||||
}
|
}
|
||||||
return currentValue
|
return currentValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
||||||
if !strings.HasPrefix(name, "_") {
|
name = fixCtrlVar(name)
|
||||||
name = "_" + name
|
|
||||||
}
|
|
||||||
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
||||||
currentStatus, _ = v.(bool)
|
currentStatus, _ = v.(bool)
|
||||||
}
|
}
|
||||||
@@ -77,9 +77,7 @@ func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
||||||
if !strings.HasPrefix(name, "_") {
|
name = fixCtrlVar(name)
|
||||||
name = "_" + name
|
|
||||||
}
|
|
||||||
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
||||||
currentStatus, _ = v.(bool)
|
currentStatus, _ = v.(bool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
//go:build graph
|
//go:build graph
|
||||||
|
|||||||
+2
-2
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// helpers.go
|
// helpers.go
|
||||||
@@ -45,7 +45,7 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
|
|||||||
functor := kern.NewGolangFunctor(f)
|
functor := kern.NewGolangFunctor(f)
|
||||||
// ctx.RegisterFunc(arg.Name, functor, 0, -1)
|
// ctx.RegisterFunc(arg.Name, functor, 0, -1)
|
||||||
ctx.RegisterFunc(arg.Name, functor, kern.TypeAny, []kern.ExprFuncParam{
|
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 {
|
} else {
|
||||||
err = fmt.Errorf("invalid function specification: %q", arg.Name)
|
err = fmt.Errorf("invalid function specification: %q", arg.Name)
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// import-utils.go
|
// import-utils.go
|
||||||
|
|||||||
+5
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// int-iterator.go
|
// int-iterator.go
|
||||||
@@ -20,6 +20,10 @@ type IntIterator struct {
|
|||||||
step int64
|
step int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewIntIteratorA(args ...any) (it *IntIterator, err error) {
|
||||||
|
return NewIntIterator(args)
|
||||||
|
}
|
||||||
|
|
||||||
func NewIntIterator(args []any) (it *IntIterator, err error) {
|
func NewIntIterator(args []any) (it *IntIterator, err error) {
|
||||||
var argc int = 0
|
var argc int = 0
|
||||||
if args != nil {
|
if args != nil {
|
||||||
|
|||||||
+20
-3
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// iter-factory.go
|
// iter-factory.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"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 {
|
if value == nil {
|
||||||
return NewArrayIterator([]any{}), nil
|
return NewArrayIterator([]any{}), nil
|
||||||
}
|
}
|
||||||
@@ -16,14 +19,28 @@ func NewIterator(value any) (it kern.Iterator, err error) {
|
|||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case *kern.ListType:
|
case *kern.ListType:
|
||||||
it = NewListIterator(v, nil)
|
it = NewListIterator(v, nil)
|
||||||
|
case *kern.LinkedList:
|
||||||
|
it = NewLinkedListIterator(v, nil)
|
||||||
case *kern.DictType:
|
case *kern.DictType:
|
||||||
it, err = NewDictIterator(v, nil)
|
it, err = NewDictIterator(v, nil)
|
||||||
case []any:
|
case []any:
|
||||||
it = NewArrayIterator(v)
|
it = NewArrayIterator(v)
|
||||||
case kern.Iterator:
|
case kern.Iterator:
|
||||||
it = v
|
// var exprs []*scan.Term
|
||||||
|
it, err = NewIterIter(v, ctx, ops)
|
||||||
default:
|
default:
|
||||||
it = NewArrayIterator([]any{value})
|
it = NewArrayIterator([]any{value})
|
||||||
}
|
}
|
||||||
return
|
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
@@ -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
|
||||||
|
}
|
||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// bind-go-function.go
|
// bind-go-function.go
|
||||||
package kern
|
package kern
|
||||||
|
|
||||||
// ---- Linking with Go functions
|
// ---- Linking with Go functions
|
||||||
type golangFunctor struct {
|
type GolangFunctor struct {
|
||||||
BaseFunctor
|
BaseFunctor
|
||||||
f FuncTemplate
|
f FuncTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGolangFunctor(f FuncTemplate) *golangFunctor {
|
func NewGolangFunctor(f FuncTemplate) *GolangFunctor {
|
||||||
return &golangFunctor{f: f}
|
return &GolangFunctor{f: f}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (functor *golangFunctor) TypeName() string {
|
func (functor *GolangFunctor) TypeName() string {
|
||||||
return "GoFunctor"
|
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)
|
return functor.f(ctx, name, args)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// clone-value.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
func Clone(v any) (c any) {
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch unboxed := v.(type) {
|
||||||
|
case int64:
|
||||||
|
c = unboxed
|
||||||
|
case float64:
|
||||||
|
c = unboxed
|
||||||
|
case string:
|
||||||
|
c = unboxed
|
||||||
|
case bool:
|
||||||
|
c = unboxed
|
||||||
|
case *ListType:
|
||||||
|
c = unboxed.Clone()
|
||||||
|
case *DictType:
|
||||||
|
c = unboxed.Clone()
|
||||||
|
case *LinkedList:
|
||||||
|
c = unboxed.Clone()
|
||||||
|
default:
|
||||||
|
c = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// common-errors.go
|
// common-errors.go
|
||||||
@@ -84,6 +84,10 @@ func ErrUnknownVar(funcName, varName string) error {
|
|||||||
return fmt.Errorf("%s(): unknown variable %q", funcName, varName)
|
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
|
// --- Operator errors
|
||||||
|
|
||||||
func ErrLeftOperandMustBeVariable(leftTerm, opTerm Term) error {
|
func ErrLeftOperandMustBeVariable(leftTerm, opTerm Term) error {
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// common-params.go
|
// common-params.go
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// common-type-names.go
|
// common-type-names.go
|
||||||
@@ -20,4 +20,5 @@ const (
|
|||||||
TypeDict = "dict"
|
TypeDict = "dict"
|
||||||
TypeListOf = "list-of-"
|
TypeListOf = "list-of-"
|
||||||
TypeListOfStrings = "list-of-strings"
|
TypeListOfStrings = "list-of-strings"
|
||||||
|
TypeLinkedList = "linked-list"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ func Equal(value1, value2 any) (equal bool) {
|
|||||||
d1 := value1.(*DictType)
|
d1 := value1.(*DictType)
|
||||||
d2 := value2.(*DictType)
|
d2 := value2.(*DictType)
|
||||||
equal = d1.Equals(*d2)
|
equal = d1.Equals(*d2)
|
||||||
|
} else if IsLinkedList(value1) && IsLinkedList(value2) {
|
||||||
|
ll1 := value1.(*LinkedList)
|
||||||
|
ll2 := value2.(*LinkedList)
|
||||||
|
equal = ll1.Equals(ll2)
|
||||||
} else if IsInteger(value1) && IsInteger(value2) {
|
} else if IsInteger(value1) && IsInteger(value2) {
|
||||||
equal = value1.(int64) == value2.(int64)
|
equal = value1.(int64) == value2.(int64)
|
||||||
} else if IsString(value1) && IsString(value2) {
|
} else if IsString(value1) && IsString(value2) {
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// context-helpers.go
|
// context-helpers.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// control.go
|
// control.go
|
||||||
|
|||||||
+15
-9
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// dict-type.go
|
// dict-type.go
|
||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DictTypeName = "dict"
|
||||||
|
|
||||||
type DictType map[any]any
|
type DictType map[any]any
|
||||||
|
|
||||||
func IsDict(v any) (ok bool) {
|
func IsDict(v any) (ok bool) {
|
||||||
@@ -74,9 +76,11 @@ func (dict *DictType) toMultiLine(sb *strings.Builder, opt FmtOpt) {
|
|||||||
|
|
||||||
sb.WriteString(nest)
|
sb.WriteString(nest)
|
||||||
if key, ok := name.(string); ok {
|
if key, ok := name.(string); ok {
|
||||||
sb.WriteString(string('"') + key + string('"'))
|
sb.WriteByte('"')
|
||||||
|
sb.WriteString(key)
|
||||||
|
sb.WriteByte('"')
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("%v", name))
|
fmt.Fprintf(sb, "%v", name)
|
||||||
}
|
}
|
||||||
sb.WriteString(": ")
|
sb.WriteString(": ")
|
||||||
if f, ok := value.(Formatter); ok {
|
if f, ok := value.(Formatter); ok {
|
||||||
@@ -84,7 +88,7 @@ func (dict *DictType) toMultiLine(sb *strings.Builder, opt FmtOpt) {
|
|||||||
} else if _, ok = value.(Functor); ok {
|
} else if _, ok = value.(Functor); ok {
|
||||||
sb.WriteString("func(){}")
|
sb.WriteString("func(){}")
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("%v", value))
|
fmt.Fprintf(sb, "%v", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteByte('\n')
|
sb.WriteByte('\n')
|
||||||
@@ -108,9 +112,11 @@ func (dict *DictType) ToString(opt FmtOpt) string {
|
|||||||
sb.WriteString(", ")
|
sb.WriteString(", ")
|
||||||
}
|
}
|
||||||
if s, ok := key.(string); ok {
|
if s, ok := key.(string); ok {
|
||||||
sb.WriteString(string('"') + s + string('"'))
|
sb.WriteByte('"')
|
||||||
|
sb.WriteString(s)
|
||||||
|
sb.WriteByte('"')
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("%v", key))
|
fmt.Fprintf(&sb, "%v", key)
|
||||||
}
|
}
|
||||||
sb.WriteString(": ")
|
sb.WriteString(": ")
|
||||||
if formatter, ok := value.(Formatter); ok {
|
if formatter, ok := value.(Formatter); ok {
|
||||||
@@ -118,7 +124,7 @@ func (dict *DictType) ToString(opt FmtOpt) string {
|
|||||||
} else if t, ok := value.(Term); ok {
|
} else if t, ok := value.(Term); ok {
|
||||||
sb.WriteString(t.String())
|
sb.WriteString(t.String())
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("%#v", value))
|
fmt.Fprintf(&sb, "%#v", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteByte('}')
|
sb.WriteByte('}')
|
||||||
@@ -131,7 +137,7 @@ func (dict *DictType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dict *DictType) TypeName() string {
|
func (dict *DictType) TypeName() string {
|
||||||
return "dict"
|
return DictTypeName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *DictType) HasKey(target any) (ok bool) {
|
func (dict *DictType) HasKey(target any) (ok bool) {
|
||||||
@@ -155,7 +161,7 @@ func (dict *DictType) GetItem(key any) (value any, exists bool) {
|
|||||||
func (dict *DictType) Clone() (c *DictType) {
|
func (dict *DictType) Clone() (c *DictType) {
|
||||||
c = newDict(nil)
|
c = newDict(nil)
|
||||||
for k, v := range *dict {
|
for k, v := range *dict {
|
||||||
(*c)[k] = v
|
(*c)[k] = Clone(v)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// expr-context.go
|
// expr-context.go
|
||||||
@@ -28,4 +28,36 @@ type ExprContext interface {
|
|||||||
Call(name string, args map[string]any) (result any, err error)
|
Call(name string, args map[string]any) (result any, err error)
|
||||||
RegisterFuncInfo(info ExprFunc)
|
RegisterFuncInfo(info ExprFunc)
|
||||||
RegisterFunc(name string, f Functor, returnType string, param []ExprFuncParam) (funcInfo ExprFunc, err error)
|
RegisterFunc(name string, f Functor, returnType string, param []ExprFuncParam) (funcInfo ExprFunc, err error)
|
||||||
|
|
||||||
|
ToDict() (dict *DictType)
|
||||||
|
ToString(opt FmtOpt) string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextToDict(ctx ExprContext) (dict *DictType) {
|
||||||
|
var keys []string
|
||||||
|
// Variables
|
||||||
|
keys = ctx.EnumVars(nil)
|
||||||
|
vars := MakeDict()
|
||||||
|
for _, key := range keys {
|
||||||
|
value, _ := ctx.GetVar(key)
|
||||||
|
vars.SetItem(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
keys = ctx.EnumFuncs(func(name string) bool { return true })
|
||||||
|
funcs := MakeDict()
|
||||||
|
for _, key := range keys {
|
||||||
|
funcInfo, _ := ctx.GetFuncInfo(key)
|
||||||
|
funcs.SetItem(key, funcInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
dict = MakeDict()
|
||||||
|
dict.SetItem("vars", vars)
|
||||||
|
dict.SetItem("funcs", funcs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextToString(ctx ExprContext, opt FmtOpt) string {
|
||||||
|
dict := ctx.ToDict()
|
||||||
|
return dict.ToString(opt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// expr-function.go
|
// expr-function.go
|
||||||
@@ -37,3 +37,8 @@ type ExprFunc interface {
|
|||||||
PrepareCall(name string, actualParams map[string]any) (err error)
|
PrepareCall(name string, actualParams map[string]any) (err error)
|
||||||
AllocContext(parentCtx ExprContext) (ctx ExprContext)
|
AllocContext(parentCtx ExprContext) (ctx ExprContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsFunctor(v any) (ok bool) {
|
||||||
|
_, ok = v.(Functor)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// expr.go
|
// expr.go
|
||||||
|
|||||||
+17
-2
@@ -1,10 +1,13 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// formatter.go
|
// formatter.go
|
||||||
package kern
|
package kern
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number
|
type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number
|
||||||
|
|
||||||
@@ -46,6 +49,18 @@ type Formatter interface {
|
|||||||
ToString(options FmtOpt) string
|
ToString(options FmtOpt) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Format(sb *strings.Builder, item any, opt FmtOpt) {
|
||||||
|
if s, ok := item.(string); ok {
|
||||||
|
sb.WriteByte('"')
|
||||||
|
sb.WriteString(s)
|
||||||
|
sb.WriteByte('"')
|
||||||
|
} else if formatter, ok := item.(Formatter); ok {
|
||||||
|
sb.WriteString(formatter.ToString(opt))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v", item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetFormatted(v any, opt FmtOpt) (text string) {
|
func GetFormatted(v any, opt FmtOpt) (text string) {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
text = "(nil)"
|
text = "(nil)"
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// fraction-type.go
|
// fraction-type.go
|
||||||
@@ -44,10 +44,11 @@ func MakeGeneratingFraction(s string) (f *FractionType, err error) {
|
|||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
goto exit
|
goto exit
|
||||||
}
|
}
|
||||||
if s[0] == '-' {
|
switch s[0] {
|
||||||
|
case '-':
|
||||||
sign = int64(-1)
|
sign = int64(-1)
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
} else if s[0] == '+' {
|
case '+':
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
}
|
}
|
||||||
// if strings.HasSuffix(s, "()") {
|
// if strings.HasSuffix(s, "()") {
|
||||||
|
|||||||
@@ -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
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// function.go
|
// 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)
|
type DeepFuncTemplate func(a, b any) (eq bool, err error)
|
||||||
|
|
||||||
func IsFunctor(v any) (ok bool) {
|
|
||||||
_, ok = v.(Functor)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Common functor definition
|
// ---- Common functor definition
|
||||||
type BaseFunctor struct {
|
type BaseFunctor struct {
|
||||||
info ExprFunc
|
info ExprFunc
|
||||||
@@ -54,17 +49,17 @@ func (functor *BaseFunctor) GetDefinitionContext() ExprContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- Function Parameters
|
// ---- Function Parameters
|
||||||
type paramFlags uint16
|
type FuncParamFlags uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PfDefault paramFlags = 1 << iota
|
PfDefault FuncParamFlags = 1 << iota
|
||||||
PfOptional
|
PfOptional
|
||||||
PfRepeat
|
PfRepeat
|
||||||
)
|
)
|
||||||
|
|
||||||
type funcParamInfo struct {
|
type funcParamInfo struct {
|
||||||
name string
|
name string
|
||||||
flags paramFlags
|
flags FuncParamFlags
|
||||||
defaultValue any
|
defaultValue any
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,11 +67,11 @@ func NewFuncParam(name string) ExprFuncParam {
|
|||||||
return &funcParamInfo{name: name}
|
return &funcParamInfo{name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam {
|
func NewFuncParamFlag(name string, flags FuncParamFlags) ExprFuncParam {
|
||||||
return &funcParamInfo{name: name, flags: flags}
|
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}
|
return &funcParamInfo{name: name, flags: flags, defaultValue: defValue}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+44
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// iterator.go
|
// iterator.go
|
||||||
@@ -7,6 +7,7 @@ package kern
|
|||||||
import (
|
import (
|
||||||
// "errors"
|
// "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Operator names
|
// Operator names
|
||||||
@@ -50,3 +51,45 @@ func IsIterator(v any) (ok bool) {
|
|||||||
_, ok = v.(Iterator)
|
_, ok = v.(Iterator)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IteratorBase struct {
|
||||||
|
ItemIndex int64
|
||||||
|
ItemCount int64
|
||||||
|
current any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Current() (item any, err error) {
|
||||||
|
return it.current, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Index() int64 {
|
||||||
|
return it.ItemIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Count() int64 {
|
||||||
|
return it.ItemCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) HasOperation(name string) bool {
|
||||||
|
return slices.Contains([]string{NextName, IndexName, CountName, CurrentName}, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Clean() (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Reset() (err error) {
|
||||||
|
it.ItemIndex = -1
|
||||||
|
it.ItemCount = 0
|
||||||
|
it.current = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) Increment() {
|
||||||
|
it.ItemIndex++
|
||||||
|
it.ItemCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *IteratorBase) SetCurrent(v any) {
|
||||||
|
it.current = v
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// linked-list-type.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const LinkedListTypeName = "lisked-list"
|
||||||
|
const MaxUint64Allowed = uint64(9_223_372_036_854_775_807)
|
||||||
|
|
||||||
|
func IsLinkedList(v any) (ok bool) {
|
||||||
|
_, ok = v.(*LinkedList)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLinkedListA(listAny ...any) (list *LinkedList) {
|
||||||
|
if listAny == nil {
|
||||||
|
listAny = []any{}
|
||||||
|
}
|
||||||
|
list = NewLinkedList()
|
||||||
|
for _, item := range listAny {
|
||||||
|
list.PushBack(FixAnyNumber(item))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkedListFromStrings(stringList []string) (list *LinkedList) {
|
||||||
|
list = NewLinkedList()
|
||||||
|
for _, s := range stringList {
|
||||||
|
list.PushBack(s)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) ToString(opt FmtOpt) (s string) {
|
||||||
|
indent := GetFormatIndent(opt)
|
||||||
|
flags := GetFormatFlags(opt)
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("[<")
|
||||||
|
if ls.Len() > 0 {
|
||||||
|
innerOpt := MakeFormatOptions(flags, indent+1)
|
||||||
|
nest := strings.Repeat(" ", indent+1)
|
||||||
|
|
||||||
|
if flags&MultiLine != 0 {
|
||||||
|
sb.WriteByte('\n')
|
||||||
|
sb.WriteString(nest)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for item := ls.FirstNode(); item != nil; item = item.Next() {
|
||||||
|
if i > 0 {
|
||||||
|
if flags&MultiLine != 0 {
|
||||||
|
sb.WriteString(",\n")
|
||||||
|
sb.WriteString(nest)
|
||||||
|
} else {
|
||||||
|
sb.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// data := item.Data()
|
||||||
|
// if s, ok := data.(string); ok {
|
||||||
|
// sb.WriteByte('"')
|
||||||
|
// sb.WriteString(s)
|
||||||
|
// sb.WriteByte('"')
|
||||||
|
// } else if formatter, ok := data.(Formatter); ok {
|
||||||
|
// sb.WriteString(formatter.ToString(innerOpt))
|
||||||
|
// } else {
|
||||||
|
// fmt.Fprintf(&sb, "%v", data)
|
||||||
|
// }
|
||||||
|
Format(&sb, item.Data(), innerOpt)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if flags&MultiLine != 0 {
|
||||||
|
sb.WriteByte('\n')
|
||||||
|
sb.WriteString(strings.Repeat(" ", indent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.WriteString(">]")
|
||||||
|
s = sb.String()
|
||||||
|
if flags&Truncate != 0 && len(s) > TruncateSize {
|
||||||
|
s = TruncateString(s)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) String() string {
|
||||||
|
return ls.ToString(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) TypeName() string {
|
||||||
|
return LinkedListTypeName
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (ls *LinkedList) Contains(t *ListType) (answer bool) {
|
||||||
|
// if len(*ls) >= len(*t) {
|
||||||
|
// answer = true
|
||||||
|
// for _, item := range *t {
|
||||||
|
// if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (ls1 *LinkedList) Equals(ls2 *LinkedList) (answer bool) {
|
||||||
|
if ls2 != nil && ls1.Len() == ls2.Len() {
|
||||||
|
answer = true
|
||||||
|
i2 := ls2.FirstNode()
|
||||||
|
for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
|
||||||
|
if !Equal(i1.Data(), i2.Data()) {
|
||||||
|
answer = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i2 = i2.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls1 *LinkedList) Clone() (ls2 *LinkedList) {
|
||||||
|
ls2 = NewLinkedListA()
|
||||||
|
for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
|
||||||
|
ls2.PushBack(Clone(i1.Data()))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
// simple-list project slist.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListNode struct {
|
||||||
|
data any
|
||||||
|
next *ListNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *ListNode) Next() *ListNode {
|
||||||
|
return node.next
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ListNode) Data() any {
|
||||||
|
return self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinkedList struct {
|
||||||
|
count int
|
||||||
|
first *ListNode
|
||||||
|
last *ListNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLinkedList() (list *LinkedList) {
|
||||||
|
list = &LinkedList{0, nil, nil}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) Len() int {
|
||||||
|
return ls.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) Empty() bool {
|
||||||
|
return ls.count == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) PushFront(data any) *ListNode {
|
||||||
|
ls.first = &ListNode{data, ls.first}
|
||||||
|
if ls.last == nil {
|
||||||
|
ls.last = ls.first
|
||||||
|
}
|
||||||
|
ls.count++
|
||||||
|
return ls.first
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) SeqPushFront(data any) (result *LinkedList) {
|
||||||
|
switch seq := data.(type) {
|
||||||
|
case Iterator:
|
||||||
|
result = ls.IterPushFront(seq)
|
||||||
|
default:
|
||||||
|
ls.PushFront(data)
|
||||||
|
result = ls
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) IterPushFront(it Iterator) *LinkedList {
|
||||||
|
for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() {
|
||||||
|
ls.PushFront(item)
|
||||||
|
}
|
||||||
|
return ls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) PushBack(data any) (node *ListNode) {
|
||||||
|
node = &ListNode{data, nil}
|
||||||
|
if ls.last != nil {
|
||||||
|
ls.last.next = node
|
||||||
|
}
|
||||||
|
ls.last = node
|
||||||
|
if ls.first == nil {
|
||||||
|
ls.first = node
|
||||||
|
}
|
||||||
|
ls.count++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) SeqPushBack(data any) (result *LinkedList) {
|
||||||
|
switch seq := data.(type) {
|
||||||
|
case Iterator:
|
||||||
|
result = ls.IterPushBack(seq)
|
||||||
|
default:
|
||||||
|
ls.PushBack(data)
|
||||||
|
result = ls
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) IterPushBack(it Iterator) *LinkedList {
|
||||||
|
for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() {
|
||||||
|
ls.PushBack(item)
|
||||||
|
}
|
||||||
|
return ls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) FirstNode() *ListNode {
|
||||||
|
return ls.first
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) First() (data any, err error) {
|
||||||
|
if ls.first != nil {
|
||||||
|
data = ls.first.data
|
||||||
|
} else {
|
||||||
|
err = errorListEmpty()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) LastNode() *ListNode {
|
||||||
|
return ls.last
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) Last() (data interface{}, err error) {
|
||||||
|
if ls.last != nil {
|
||||||
|
data = ls.last.data
|
||||||
|
} else {
|
||||||
|
err = errorListEmpty()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) NodeAt(index int) (node *ListNode, err error) {
|
||||||
|
if ls.count == 0 {
|
||||||
|
err = errorListEmpty()
|
||||||
|
} else if index > ls.count {
|
||||||
|
err = errorOutOfRange()
|
||||||
|
} else if index == ls.count-1 {
|
||||||
|
node = ls.last
|
||||||
|
} else {
|
||||||
|
current := ls.first
|
||||||
|
for range index {
|
||||||
|
current = current.next
|
||||||
|
}
|
||||||
|
node = current
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) At(index int) (data interface{}, err error) {
|
||||||
|
node, err := ls.NodeAt(index)
|
||||||
|
if err == nil {
|
||||||
|
data = node.data
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) Insert(index int, data any) *ListNode {
|
||||||
|
var prev *ListNode
|
||||||
|
|
||||||
|
prev = nil
|
||||||
|
current := ls.first
|
||||||
|
for pos := 0; current != nil && pos < index; pos++ {
|
||||||
|
prev = current
|
||||||
|
current = current.next
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &ListNode{data, current}
|
||||||
|
|
||||||
|
if prev != nil {
|
||||||
|
prev.next = node
|
||||||
|
}
|
||||||
|
|
||||||
|
if ls.first == current {
|
||||||
|
ls.first = node
|
||||||
|
}
|
||||||
|
if node.next == nil {
|
||||||
|
ls.last = node
|
||||||
|
}
|
||||||
|
ls.count++
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) PushBackStringArray(items []string) {
|
||||||
|
for _, v := range items {
|
||||||
|
ls.PushBack(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) Sub(start, end int) (subList *LinkedList) {
|
||||||
|
subList = NewLinkedList()
|
||||||
|
if node, err := ls.NodeAt(start); err == nil {
|
||||||
|
for i := start; i < end && node != nil; i++ {
|
||||||
|
subList.PushBack(node.data)
|
||||||
|
node = node.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// type TraverseOperator func(index int, elem interface{}, userData interface{}) (err error)
|
||||||
|
|
||||||
|
// func (self *LinkedList) Traverse(op TraverseOperator, user_data interface{}) (err error) {
|
||||||
|
// index := int(0)
|
||||||
|
// for current := self.first; current != nil; current = current.next {
|
||||||
|
// err = op(index, current.data, user_data)
|
||||||
|
// if err != nil {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// index++
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (self *LinkedList) Traverse2(observer Observer, abortOnError bool) (err error) {
|
||||||
|
// index := int(0)
|
||||||
|
// for current := self.first; current != nil; current = current.next {
|
||||||
|
// err = observer.Observe(current, index)
|
||||||
|
// if err != nil && abortOnError {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// index++
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
type EqualFunc func(current, target any) bool
|
||||||
|
|
||||||
|
func (ls *LinkedList) FindFirst(eqFunc EqualFunc, targetData any) (targetNode *ListNode) {
|
||||||
|
for current := ls.first; current != nil && targetNode == nil; current = current.next {
|
||||||
|
if eqFunc(current.data, targetData) {
|
||||||
|
targetNode = current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *LinkedList) FindNext(eqFunc EqualFunc, startNode *ListNode) (targetNode *ListNode) {
|
||||||
|
if startNode != nil {
|
||||||
|
for current := startNode.next; current != nil && targetNode == nil; current = current.next {
|
||||||
|
if eqFunc(current.data, startNode.Data()) {
|
||||||
|
targetNode = current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// type DataFeeder func(user_data interface{}) interface{}
|
||||||
|
// type NodeObserver func(node *ListNode, index int, userData interface{})
|
||||||
|
|
||||||
|
// func (self *LinkedList) FeedTail(feeder DataFeeder, feederUserData interface{}, observer NodeObserver, observerUserData interface{}) (count int) {
|
||||||
|
// count = 0
|
||||||
|
// for item := feeder(feederUserData); item != nil; item = feeder(feederUserData) {
|
||||||
|
// // fmt.Println("Item", count, item)
|
||||||
|
// node := self.PushBack(item)
|
||||||
|
// if observer != nil {
|
||||||
|
// observer(node, count, observerUserData)
|
||||||
|
// }
|
||||||
|
// count++
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (self *LinkedList) FeedTail2(feeder Feeder, observer Observer, abortOnError bool) (count int, err error) {
|
||||||
|
// count = 0
|
||||||
|
// // item := feeder.Next()
|
||||||
|
// for item, err1 := feeder.Next(); item != nil; item, err1 = feeder.Next() {
|
||||||
|
// if err1 != nil {
|
||||||
|
// if err == nil {
|
||||||
|
// err = err1
|
||||||
|
// }
|
||||||
|
// if abortOnError {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // fmt.Println("Item", count, item)
|
||||||
|
// node := self.PushBack(item)
|
||||||
|
// if observer != nil {
|
||||||
|
// observer.Observe(node, count)
|
||||||
|
// }
|
||||||
|
// count++
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func errorListEmpty() error {
|
||||||
|
return fmt.Errorf("List is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorOutOfRange() error {
|
||||||
|
return fmt.Errorf("Out of range")
|
||||||
|
}
|
||||||
+31
-30
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// list-type.go
|
// list-type.go
|
||||||
@@ -50,13 +50,13 @@ func ListFromStrings(stringList []string) (list *ListType) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) ToString(opt FmtOpt) (s string) {
|
func (ls *ListType) ToString(opt FmtOpt) (s string) {
|
||||||
indent := GetFormatIndent(opt)
|
indent := GetFormatIndent(opt)
|
||||||
flags := GetFormatFlags(opt)
|
flags := GetFormatFlags(opt)
|
||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteByte('[')
|
sb.WriteByte('[')
|
||||||
if len(*dict) > 0 {
|
if len(*ls) > 0 {
|
||||||
innerOpt := MakeFormatOptions(flags, indent+1)
|
innerOpt := MakeFormatOptions(flags, indent+1)
|
||||||
nest := strings.Repeat(" ", indent+1)
|
nest := strings.Repeat(" ", indent+1)
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ func (dict *ListType) ToString(opt FmtOpt) (s string) {
|
|||||||
sb.WriteByte('\n')
|
sb.WriteByte('\n')
|
||||||
sb.WriteString(nest)
|
sb.WriteString(nest)
|
||||||
}
|
}
|
||||||
for i, item := range []any(*dict) {
|
for i, item := range []any(*ls) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if flags&MultiLine != 0 {
|
if flags&MultiLine != 0 {
|
||||||
sb.WriteString(",\n")
|
sb.WriteString(",\n")
|
||||||
@@ -73,15 +73,7 @@ func (dict *ListType) ToString(opt FmtOpt) (s string) {
|
|||||||
sb.WriteString(", ")
|
sb.WriteString(", ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s, ok := item.(string); ok {
|
Format(&sb, item, innerOpt)
|
||||||
sb.WriteByte('"')
|
|
||||||
sb.WriteString(s)
|
|
||||||
sb.WriteByte('"')
|
|
||||||
} else if formatter, ok := item.(Formatter); ok {
|
|
||||||
sb.WriteString(formatter.ToString(innerOpt))
|
|
||||||
} else {
|
|
||||||
sb.WriteString(fmt.Sprintf("%v", item))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if flags&MultiLine != 0 {
|
if flags&MultiLine != 0 {
|
||||||
sb.WriteByte('\n')
|
sb.WriteByte('\n')
|
||||||
@@ -96,19 +88,19 @@ func (dict *ListType) ToString(opt FmtOpt) (s string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) String() string {
|
func (ls *ListType) String() string {
|
||||||
return dict.ToString(0)
|
return ls.ToString(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) TypeName() string {
|
func (ls *ListType) TypeName() string {
|
||||||
return "list"
|
return "list"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) Contains(t *ListType) (answer bool) {
|
func (ls *ListType) Contains(t *ListType) (answer bool) {
|
||||||
if len(*dict) >= len(*t) {
|
if len(*ls) >= len(*t) {
|
||||||
answer = true
|
answer = true
|
||||||
for _, item := range *t {
|
for _, item := range *t {
|
||||||
if answer = dict.IndexDeepSameCmp(item) >= 0; !answer {
|
if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,10 +108,10 @@ func (dict *ListType) Contains(t *ListType) (answer bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls1 *ListType) Equals(ls2 ListType) (answer bool) {
|
func (ls *ListType) Equals(ls2 ListType) (answer bool) {
|
||||||
if ls2 != nil && len(*ls1) == len(ls2) {
|
if ls2 != nil && len(*ls) == len(ls2) {
|
||||||
answer = true
|
answer = true
|
||||||
for index, i1 := range *ls1 {
|
for index, i1 := range *ls {
|
||||||
// if !reflect.DeepEqual(i1, ls2[index]) {
|
// if !reflect.DeepEqual(i1, ls2[index]) {
|
||||||
// answer = false
|
// answer = false
|
||||||
// break
|
// break
|
||||||
@@ -133,11 +125,20 @@ func (ls1 *ListType) Equals(ls2 ListType) (answer bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) IndexDeepSameCmp(target any) (index int) {
|
func (ls1 *ListType) Clone() (ls2 *ListType) {
|
||||||
|
ls := make(ListType, len(*ls1))
|
||||||
|
for i, item := range *ls1 {
|
||||||
|
ls[i] = Clone(item)
|
||||||
|
}
|
||||||
|
ls2 = &ls
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *ListType) IndexDeepSameCmp(target any) (index int) {
|
||||||
var eq bool
|
var eq bool
|
||||||
var err error
|
var err error
|
||||||
index = -1
|
index = -1
|
||||||
for i, item := range *dict {
|
for i, item := range *ls {
|
||||||
if eq, err = deepSame(item, target, SameContent); err != nil {
|
if eq, err = deepSame(item, target, SameContent); err != nil {
|
||||||
break
|
break
|
||||||
} else if eq {
|
} else if eq {
|
||||||
@@ -188,15 +189,15 @@ func deepSame(a, b any, deepCmp DeepFuncTemplate) (eq bool, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) SetItem(index int64, value any) (err error) {
|
func (ls *ListType) SetItem(index int64, value any) (err error) {
|
||||||
if index >= 0 && index < int64(len(*dict)) {
|
if index >= 0 && index < int64(len(*ls)) {
|
||||||
(*dict)[index] = value
|
(*ls)[index] = value
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*dict)-1)
|
err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*ls)-1)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *ListType) AppendItem(value any) {
|
func (ls *ListType) AppendItem(value any) {
|
||||||
*dict = append(*dict, value)
|
*ls = append(*ls, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,38 @@ func AnyInteger(v any) (i int64, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FixAnyNumber(v any) (fixed any) {
|
||||||
|
switch unboxed := v.(type) {
|
||||||
|
case int:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case int8:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case int16:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case int32:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case uint:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case uint8:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case uint16:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case uint32:
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
case uint64:
|
||||||
|
if unboxed <= MaxUint64Allowed {
|
||||||
|
fixed = int64(unboxed)
|
||||||
|
} else {
|
||||||
|
fixed = float64(unboxed)
|
||||||
|
}
|
||||||
|
case float32:
|
||||||
|
fixed = float64(unboxed)
|
||||||
|
default:
|
||||||
|
fixed = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func ToGoInt(value any, description string) (i int, err error) {
|
func ToGoInt(value any, description string) (i int, err error) {
|
||||||
if valueInt64, ok := value.(int64); ok {
|
if valueInt64, ok := value.(int64); ok {
|
||||||
i = int(valueInt64)
|
i = int(valueInt64)
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// term.go
|
// term.go
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
//go:build darwin
|
//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.
|
// All rights reserved.
|
||||||
|
|
||||||
// lib-ext-darwin.go
|
// lib-ext-darwin.go
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
//go:build linux
|
//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.
|
// All rights reserved.
|
||||||
|
|
||||||
// lib-ext-linux.go
|
// lib-ext-linux.go
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
//go:build windows
|
//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.
|
// All rights reserved.
|
||||||
|
|
||||||
// lib-ext-windows.go
|
// lib-ext-windows.go
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// list-iterator.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LinkedListIterator struct {
|
||||||
|
a *kern.LinkedList
|
||||||
|
count int64
|
||||||
|
index int64
|
||||||
|
current *kern.ListNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLinkedListIterator(list *kern.LinkedList, args []any) (it *LinkedListIterator) {
|
||||||
|
it = &LinkedListIterator{a: list, count: 0, index: -1, current: list.FirstNode()}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) String() string {
|
||||||
|
var l = int64(0)
|
||||||
|
if it.a != nil {
|
||||||
|
l = int64(it.a.Len())
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("$([<#%d>])", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) TypeName() string {
|
||||||
|
return "LinkedListIterator"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) HasOperation(name string) bool {
|
||||||
|
yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name)
|
||||||
|
return yes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) 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 *LinkedListIterator) Current() (item any, err error) {
|
||||||
|
if it.current != nil {
|
||||||
|
item = it.current.Data()
|
||||||
|
} else {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) Next() (item any, err error) {
|
||||||
|
if it.current != nil {
|
||||||
|
item = it.current.Data()
|
||||||
|
it.current = it.current.Next()
|
||||||
|
it.index++
|
||||||
|
it.count++
|
||||||
|
} else {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) Index() int64 {
|
||||||
|
return it.index
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) Count() int64 {
|
||||||
|
return it.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) Reset() error {
|
||||||
|
it.current = it.a.FirstNode()
|
||||||
|
it.index = -1
|
||||||
|
it.count = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *LinkedListIterator) Clean() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// list-iterator.go
|
// list-iterator.go
|
||||||
|
|||||||
+9
-2
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-dict.go
|
// operand-dict.go
|
||||||
@@ -30,7 +30,14 @@ func evalDict(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
if param, err = tree.Compute(ctx); err != nil {
|
if param, err = tree.Compute(ctx); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
items[key] = param
|
var keyValue any
|
||||||
|
if keyValue, err = (key.(*scan.Term)).Compute(ctx); err == nil {
|
||||||
|
if kern.IsInteger(keyValue) || kern.IsString(keyValue) {
|
||||||
|
items[keyValue] = param
|
||||||
|
} else {
|
||||||
|
err = key.(*scan.Term).Errorf("dict key can be integer or string, got %s", kern.TypeName(keyValue))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
v = &items
|
v = &items
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-expr.go
|
// operand-expr.go
|
||||||
|
|||||||
+4
-4
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-func.go
|
// operand-func.go
|
||||||
@@ -70,14 +70,14 @@ func evalFuncDef(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
paramList := make([]kern.ExprFuncParam, 0, len(opTerm.Children))
|
paramList := make([]kern.ExprFuncParam, 0, len(opTerm.Children))
|
||||||
for _, param := range opTerm.Children {
|
for _, param := range opTerm.Children {
|
||||||
var defValue any
|
var defValue any
|
||||||
flags := paramFlags(0)
|
flags := kern.FuncParamFlags(0)
|
||||||
if len(param.Children) > 0 {
|
if len(param.Children) > 0 {
|
||||||
flags |= PfDefault
|
flags |= kern.PfDefault
|
||||||
if defValue, err = param.Children[0].Compute(ctx); err != nil {
|
if defValue, err = param.Children[0].Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info := NewFuncParamFlagDef(param.Source(), flags, defValue)
|
info := kern.NewFuncParamFlagDef(param.Source(), flags, defValue)
|
||||||
paramList = append(paramList, info)
|
paramList = append(paramList, info)
|
||||||
}
|
}
|
||||||
v = newExprFunctor(ast, paramList, ctx)
|
v = newExprFunctor(ast, paramList, ctx)
|
||||||
|
|||||||
+44
-8
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-iterator.go
|
// operand-iterator.go
|
||||||
@@ -125,7 +125,7 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
if dictIt, ok := firstChildValue.(*kern.DictType); ok {
|
if dictIt, ok := firstChildValue.(*kern.DictType); ok {
|
||||||
var args []any
|
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)
|
v, err = NewDictIterator(dictIt, args)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -134,24 +134,60 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
} else if list, ok := firstChildValue.(*kern.ListType); ok {
|
} else if list, ok := firstChildValue.(*kern.ListType); ok {
|
||||||
var args []any
|
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)
|
v = NewListIterator(list, args)
|
||||||
}
|
}
|
||||||
|
} else if list, ok := firstChildValue.(*kern.LinkedList); ok {
|
||||||
|
var args []any
|
||||||
|
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
|
||||||
|
v = NewLinkedListIterator(list, args)
|
||||||
|
}
|
||||||
} else if intVal, ok := firstChildValue.(int64); ok {
|
} else if intVal, ok := firstChildValue.(int64); ok {
|
||||||
var args []any
|
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)
|
v, err = NewIntIterator(args)
|
||||||
}
|
}
|
||||||
|
} else if it, ok := firstChildValue.(kern.Iterator); ok {
|
||||||
|
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
||||||
} else {
|
} else {
|
||||||
var list []any
|
var siblings []any
|
||||||
if list, err = evalSibling(ctx, opTerm.Children, firstChildValue); err == nil {
|
if siblings, err = evalSiblings(ctx, opTerm.Children, firstChildValue); err == nil {
|
||||||
v = NewArrayIterator(list)
|
v = NewArrayIterator(siblings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalSibling(ctx kern.ExprContext, terms []*scan.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))
|
items := make([]any, 0, len(terms))
|
||||||
for i, tree := range terms {
|
for i, tree := range terms {
|
||||||
var param any
|
var param any
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operand-list.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------- list term
|
||||||
|
// func newLinkedListTermA(args ...*scan.Term) *scan.Term {
|
||||||
|
// return newLinkedListTerm(0, 0, args)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term {
|
||||||
|
return &scan.Term{
|
||||||
|
Tk: *scan.NewValueToken(row, col, scan.SymLinkedList, "[<>]", args),
|
||||||
|
Parent: nil,
|
||||||
|
Children: nil,
|
||||||
|
Position: scan.PosLeaf,
|
||||||
|
Priority: scan.PriValue,
|
||||||
|
EvalFunc: evalLinkedList,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- list func
|
||||||
|
func evalLinkedList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
list, _ := opTerm.Value().([]*scan.Term)
|
||||||
|
items := kern.NewLinkedList()
|
||||||
|
for _, tree := range list {
|
||||||
|
var param any
|
||||||
|
if param, err = tree.Compute(ctx); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
items.PushBack(param)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
v = items
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-list.go
|
// operand-list.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-literal.go
|
// operand-literal.go
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-selector-case.go
|
// operand-selector-case.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-var.go
|
// operand-var.go
|
||||||
|
|||||||
+67
-7
@@ -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.
|
// All rights reserightChilded.
|
||||||
|
|
||||||
// operator-assign.go
|
// operator-assign.go
|
||||||
@@ -22,6 +22,26 @@ func newAssignTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func evalAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
v, err = generalEvalAssign(ctx, opTerm, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDeepCopyAssignTerm(tk *scan.Token) (inst *scan.Term) {
|
||||||
|
return &scan.Term{
|
||||||
|
Tk: *tk,
|
||||||
|
Children: make([]*scan.Term, 0, 2),
|
||||||
|
Position: scan.PosInfix,
|
||||||
|
Priority: scan.PriAssign,
|
||||||
|
EvalFunc: evalDeepCopyAssign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalDeepCopyAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
v, err = generalEvalAssign(ctx, opTerm, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *scan.Term, value any) (err error) {
|
func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *scan.Term, value any) (err error) {
|
||||||
var collectionValue, keyListValue, keyValue any
|
var collectionValue, keyListValue, keyValue any
|
||||||
var keyList *kern.ListType
|
var keyList *kern.ListType
|
||||||
@@ -57,23 +77,62 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any) (err error) {
|
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any, deepCopy bool) (err error) {
|
||||||
if leftTerm.Symbol() == scan.SymIndex {
|
if leftTerm.Symbol() == scan.SymIndex {
|
||||||
err = assignCollectionItem(ctx, leftTerm.Children[0], leftTerm.Children[1], v)
|
err = assignCollectionItem(ctx, leftTerm.Children[0], leftTerm.Children[1], v)
|
||||||
} else {
|
} else {
|
||||||
|
if deepCopy {
|
||||||
|
v = kern.Clone(v)
|
||||||
|
}
|
||||||
ctx.UnsafeSetVar(leftTerm.Source(), v)
|
ctx.UnsafeSetVar(leftTerm.Source(), v)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern.Term) (v any, err error) {
|
||||||
|
var ok bool
|
||||||
|
var dictAny, dotKey any
|
||||||
|
var dict *kern.DictType
|
||||||
|
|
||||||
|
if err = dotTerm.CheckOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dotLeftTerm := dotTerm.GetChild(0)
|
||||||
|
if dictAny, err = dotLeftTerm.Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if dict, ok = dictAny.(*kern.DictType); !ok {
|
||||||
|
err = dotTerm.Tk.ErrorExpectedGot(kern.DictTypeName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dotRightTerm := dotTerm.Children[1]
|
||||||
|
dotRightSym := dotRightTerm.Symbol()
|
||||||
|
if dotRightSym == scan.SymVariable || dotRightSym == scan.SymString {
|
||||||
|
dotKey = util.UnquoteString(dotRightTerm.Source())
|
||||||
|
} else if dotKey, err = dotRightTerm.Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err = valueTerm.Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.SetItem(dotKey, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func generalEvalAssign(ctx kern.ExprContext, opTerm *scan.Term, deepCopy bool) (v any, err error) {
|
||||||
if err = opTerm.CheckOperands(); err != nil {
|
if err = opTerm.CheckOperands(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
leftSym := leftTerm.Symbol()
|
leftSym := leftTerm.Symbol()
|
||||||
if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
|
if leftSym == scan.SymDot {
|
||||||
|
return evalAssignDictItem(ctx, opTerm.Children[0], opTerm.GetChild(1))
|
||||||
|
} else 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())
|
err = leftTerm.Tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.Tk.Source())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -93,10 +152,10 @@ func evalAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
err = opTerm.Errorf("unknown function %s()", rightChild.Source())
|
err = opTerm.Errorf("unknown function %s()", rightChild.Source())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = assignValue(ctx, leftTerm, v)
|
err = assignValue(ctx, leftTerm, v, deepCopy)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = assignValue(ctx, leftTerm, v)
|
err = assignValue(ctx, leftTerm, v, deepCopy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -203,7 +262,7 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
|
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = assignValue(ctx, leftTerm, v)
|
err = assignValue(ctx, leftTerm, v, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,6 +272,7 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymEqual, newAssignTerm)
|
scan.RegisterTermConstructor(scan.SymEqual, newAssignTerm)
|
||||||
|
scan.RegisterTermConstructor(scan.SymColonEqual, newDeepCopyAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymPlusEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(scan.SymPlusEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymMinusEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(scan.SymMinusEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymStarEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(scan.SymStarEqual, newOpAssignTerm)
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-bitwise.go
|
// operator-bitwise.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-bool.go
|
// operator-bool.go
|
||||||
|
|||||||
+2
-2
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-builtin.go
|
// operator-builtin.go
|
||||||
@@ -37,7 +37,7 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
var moduleSpec any
|
var moduleSpec any
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, err = NewIterator(childValue); err != nil {
|
if it, err = NewIterator(ctx, childValue, nil); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
|
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-but.go
|
// operator-but.go
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-cat.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------- cat term
|
||||||
|
|
||||||
|
func newCatTerm(tk *scan.Token) (inst *scan.Term) {
|
||||||
|
return &scan.Term{
|
||||||
|
Tk: *tk,
|
||||||
|
Children: make([]*scan.Term, 0, 2),
|
||||||
|
Position: scan.PosInfix,
|
||||||
|
Priority: scan.PriIterOp,
|
||||||
|
EvalFunc: evalCat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalCat(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 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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()
|
||||||
|
// for _, it := range []kern.Iterator{itLeft, itRight} {
|
||||||
|
// for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
|
// values.AppendItem(item)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if err == io.EOF {
|
||||||
|
// err = nil
|
||||||
|
// }
|
||||||
|
// v = values
|
||||||
|
v = newCatIterator(itLeft, itRight)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const catIteratorType = "cat"
|
||||||
|
|
||||||
|
type catIterator struct {
|
||||||
|
kern.IteratorBase
|
||||||
|
itLeft kern.Iterator
|
||||||
|
itRight kern.Iterator
|
||||||
|
itCurrent kern.Iterator
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCatIterator(itLeft, itRight kern.Iterator) (it *catIterator) {
|
||||||
|
it = &catIterator{
|
||||||
|
IteratorBase: kern.IteratorBase{},
|
||||||
|
itLeft: itLeft,
|
||||||
|
itRight: itRight,
|
||||||
|
itCurrent: itLeft,
|
||||||
|
}
|
||||||
|
it.Reset()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *catIterator) TypeName() string {
|
||||||
|
return catIteratorType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *catIterator) String() string {
|
||||||
|
return fmt.Sprintf("$(%s %s %s)", it.itLeft, catIteratorType, it.itRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *catIterator) Next() (item any, err error) {
|
||||||
|
if it.itCurrent == nil {
|
||||||
|
err = io.EOF
|
||||||
|
} else {
|
||||||
|
if item, err = it.itCurrent.Next(); err == nil {
|
||||||
|
it.Increment()
|
||||||
|
} else if err == io.EOF {
|
||||||
|
if it.itCurrent == it.itLeft {
|
||||||
|
it.itCurrent = it.itRight
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if item, err = it.itCurrent.Next(); err == nil {
|
||||||
|
it.Increment()
|
||||||
|
} else {
|
||||||
|
it.itCurrent = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.SetCurrent(item)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (it *catIterator) Reset() (err error) {
|
||||||
|
// err = it.itLeft.Reset()
|
||||||
|
// it.IteratorBase.Reset()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (it *catIterator) 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 = it.Index()
|
||||||
|
case kern.CurrentName:
|
||||||
|
v, err = it.Current()
|
||||||
|
case kern.CountName:
|
||||||
|
v = it.Count()
|
||||||
|
default:
|
||||||
|
err = kern.ErrNoOperation(name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
scan.RegisterTermConstructor(scan.SymKwCat, newCatTerm)
|
||||||
|
}
|
||||||
+20
-16
@@ -1,10 +1,12 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-context-value.go
|
// operator-context-value.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
)
|
)
|
||||||
@@ -23,8 +25,8 @@ func newContextTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
|
|
||||||
func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var childValue any
|
var childValue any
|
||||||
|
|
||||||
var sourceCtx kern.ExprContext
|
var sourceCtx kern.ExprContext
|
||||||
|
|
||||||
if len(opTerm.Children) == 0 {
|
if len(opTerm.Children) == 0 {
|
||||||
sourceCtx = ctx
|
sourceCtx = ctx
|
||||||
} else if opTerm.Children[0].Symbol() == scan.SymVariable && opTerm.Children[0].Source() == "global" {
|
} else if opTerm.Children[0].Symbol() == scan.SymVariable && opTerm.Children[0].Source() == "global" {
|
||||||
@@ -33,25 +35,27 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
|||||||
if dc, ok := childValue.(*dataCursor); ok {
|
if dc, ok := childValue.(*dataCursor); ok {
|
||||||
sourceCtx = dc.ctx
|
sourceCtx = dc.ctx
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if sourceCtx != nil {
|
if sourceCtx != nil {
|
||||||
if formatter, ok := sourceCtx.(kern.DictFormat); ok {
|
v = sourceCtx.ToDict()
|
||||||
v = formatter.ToDict()
|
} else if childValue != nil {
|
||||||
} else if formatter, ok := sourceCtx.(kern.Formatter); ok {
|
it, ok := childValue.(kern.Iterator)
|
||||||
v = formatter.ToString(0)
|
if !ok {
|
||||||
} else {
|
it, err = NewIterator(ctx, childValue, nil)
|
||||||
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
|
|
||||||
keys := sourceCtx.EnumVars(nil)
|
|
||||||
d := make(map[string]any)
|
|
||||||
for _, key := range keys {
|
|
||||||
d[key], _ = sourceCtx.GetVar(key)
|
|
||||||
}
|
}
|
||||||
keys = sourceCtx.EnumFuncs(func(name string) bool { return true })
|
if err == nil {
|
||||||
for _, key := range keys {
|
var item any
|
||||||
d[key], _ = sourceCtx.GetFuncInfo(key)
|
values := kern.NewLinkedListA()
|
||||||
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
|
values.PushBack(item)
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
v = values
|
||||||
}
|
}
|
||||||
v = d
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
|
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-ctrl.go
|
// operator-ctrl.go
|
||||||
|
|||||||
+2
-2
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-default.go
|
// operator-default.go
|
||||||
@@ -111,7 +111,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro
|
|||||||
if functor, ok := rightValue.(kern.Functor); ok {
|
if functor, ok := rightValue.(kern.Functor); ok {
|
||||||
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
||||||
ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{
|
ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{
|
||||||
NewFuncParamFlag(kern.ParamValue, PfDefault|PfRepeat),
|
kern.NewFuncParamFlag(kern.ParamValue, kern.PfDefault|kern.PfRepeat),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
v = rightValue
|
v = rightValue
|
||||||
|
|||||||
+2
-2
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-digest.go
|
// operator-digest.go
|
||||||
@@ -37,7 +37,7 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
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))
|
return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", kern.TypeName(leftValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+47
-17
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-dot.go
|
// operator-dot.go
|
||||||
@@ -7,6 +7,7 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- dot term
|
// -------- dot term
|
||||||
@@ -34,7 +35,7 @@ func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
switch unboxedValue := leftValue.(type) {
|
switch unboxedValue := leftValue.(type) {
|
||||||
case kern.ExtIterator:
|
case kern.ExtIterator:
|
||||||
if indexTerm.Tk.Sym == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ {
|
if indexTerm.Symbol() == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ {
|
||||||
opName := indexTerm.Source()
|
opName := indexTerm.Source()
|
||||||
if unboxedValue.HasOperation(opName) {
|
if unboxedValue.HasOperation(opName) {
|
||||||
v, err = unboxedValue.CallOperation(opName, map[string]any{})
|
v, err = unboxedValue.CallOperation(opName, map[string]any{})
|
||||||
@@ -46,21 +47,22 @@ func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
err = indexTerm.Tk.ErrorExpectedGot("identifier")
|
err = indexTerm.Tk.ErrorExpectedGot("identifier")
|
||||||
}
|
}
|
||||||
case *kern.DictType:
|
case *kern.DictType:
|
||||||
var ok bool
|
// var ok bool
|
||||||
s := opTerm.Children[1].Tk.Sym
|
// s := opTerm.Children[1].Symbol()
|
||||||
if s == scan.SymVariable || s == scan.SymString {
|
// if s == scan.SymVariable || s == scan.SymString {
|
||||||
src := opTerm.Children[1].Source()
|
// src := opTerm.Children[1].Source()
|
||||||
if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
|
// if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
|
||||||
src = src[1 : len(src)-1]
|
// src = src[1 : len(src)-1]
|
||||||
}
|
// }
|
||||||
if v, ok = unboxedValue.GetItem(src); !ok {
|
// if v, ok = unboxedValue.GetItem(src); !ok {
|
||||||
err = opTerm.Errorf("key %q not found", 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 {
|
// if v, ok = unboxedValue.GetItem(rightValue); !ok {
|
||||||
err = opTerm.Errorf("key %q not found", rightValue)
|
// err = opTerm.Errorf("key %q not found", rightValue)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
v, err = dotGetDictItemValue(ctx, unboxedValue, opTerm.Children[1])
|
||||||
default:
|
default:
|
||||||
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
||||||
err = opTerm.Errorf("incompatible types: %s and %s", kern.TypeName(leftValue), kern.TypeName(rightValue))
|
err = opTerm.Errorf("incompatible types: %s and %s", kern.TypeName(leftValue), kern.TypeName(rightValue))
|
||||||
@@ -69,6 +71,34 @@ func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dotGetDictItemValue(ctx kern.ExprContext, d *kern.DictType, rightTerm *scan.Term) (v any, err error) {
|
||||||
|
var ok bool
|
||||||
|
var rightValue any
|
||||||
|
s := rightTerm.Symbol()
|
||||||
|
if s == scan.SymVariable || s == scan.SymString {
|
||||||
|
// src := rightTerm.Source()
|
||||||
|
// if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
|
||||||
|
// src = src[1 : len(src)-1]
|
||||||
|
// }
|
||||||
|
src := util.UnquoteString(rightTerm.Source())
|
||||||
|
if v, ok = d.GetItem(src); !ok {
|
||||||
|
err = errDictKeyNotFound(rightTerm, src)
|
||||||
|
}
|
||||||
|
} else if rightValue, err = rightTerm.Compute(ctx); err == nil {
|
||||||
|
if v, ok = d.GetItem(rightValue); !ok {
|
||||||
|
err = errDictKeyNotFound(rightTerm, rightValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func errDictKeyNotFound(term *scan.Term, key any) error {
|
||||||
|
if s, ok := key.(string); ok {
|
||||||
|
return term.Errorf("key %q not found", s)
|
||||||
|
}
|
||||||
|
return term.Errorf("key %v not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDot, newDotTerm)
|
scan.RegisterTermConstructor(scan.SymDot, newDotTerm)
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-fact.go
|
// operator-fact.go
|
||||||
|
|||||||
+112
-20
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-filter.go
|
// operator-filter.go
|
||||||
@@ -6,7 +6,6 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
@@ -25,9 +24,11 @@ func newFilterTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
// var leftValue, rightValue any
|
||||||
|
var leftValue any
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
var item any
|
// var item any
|
||||||
|
var ok bool
|
||||||
|
|
||||||
if err = opTerm.CheckOperands(); err != nil {
|
if err = opTerm.CheckOperands(); err != nil {
|
||||||
return
|
return
|
||||||
@@ -37,35 +38,126 @@ func evalFilter(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if it, err = NewIterator(leftValue); err != nil {
|
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))
|
return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
values := kern.NewListA()
|
// values := kern.NewListA()
|
||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
// for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
ctx.SetVar("_", item)
|
// ctx.SetVar("_", item)
|
||||||
|
// ctx.SetVar("__", it.Index())
|
||||||
|
// ctx.SetVar("_#", it.Count())
|
||||||
|
// if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
||||||
|
// if success, valid := kern.ToBool(rightValue); valid {
|
||||||
|
// if success {
|
||||||
|
// values.AppendItem(item)
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", rightValue, rightValue)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ctx.DeleteVar("_#")
|
||||||
|
// ctx.DeleteVar("__")
|
||||||
|
// ctx.DeleteVar("_")
|
||||||
|
// if err != nil {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if err == io.EOF {
|
||||||
|
// err = nil
|
||||||
|
// }
|
||||||
|
// v = values
|
||||||
|
|
||||||
|
v = newFilerIterator(ctx, it, opTerm.Children[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterIteratorType = "filter"
|
||||||
|
|
||||||
|
type filterIterator struct {
|
||||||
|
kern.IteratorBase
|
||||||
|
ctx kern.ExprContext
|
||||||
|
itSrc kern.Iterator
|
||||||
|
expr *scan.Term
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFilerIterator(ctx kern.ExprContext, itSrc kern.Iterator, filterExpr *scan.Term) (it *filterIterator) {
|
||||||
|
it = &filterIterator{
|
||||||
|
IteratorBase: kern.IteratorBase{},
|
||||||
|
ctx: ctx,
|
||||||
|
itSrc: itSrc,
|
||||||
|
expr: filterExpr,
|
||||||
|
}
|
||||||
|
it.IteratorBase.Reset()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *filterIterator) TypeName() string {
|
||||||
|
return filterIteratorType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *filterIterator) String() string {
|
||||||
|
return fmt.Sprintf("$(%s %s bool-expr)", it.itSrc, filterIteratorType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *filterIterator) Next() (item any, err error) {
|
||||||
|
var attempt, result any
|
||||||
|
|
||||||
|
ctx := it.ctx
|
||||||
|
|
||||||
|
for attempt, err = it.itSrc.Next(); err == nil; attempt, err = it.itSrc.Next() {
|
||||||
|
ctx.SetVar("_", attempt)
|
||||||
ctx.SetVar("__", it.Index())
|
ctx.SetVar("__", it.Index())
|
||||||
ctx.SetVar("_#", it.Count())
|
ctx.SetVar("_#", it.Count())
|
||||||
if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
result, err = it.expr.Compute(ctx)
|
||||||
if success, valid := kern.ToBool(rightValue); valid {
|
|
||||||
if success {
|
|
||||||
values.AppendItem(item)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", rightValue, rightValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.DeleteVar("_#")
|
ctx.DeleteVar("_#")
|
||||||
ctx.DeleteVar("__")
|
ctx.DeleteVar("__")
|
||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
if success, valid := kern.ToBool(result); valid {
|
||||||
|
if success {
|
||||||
|
item = attempt
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", result, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == io.EOF {
|
|
||||||
err = nil
|
it.SetCurrent(item)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (it *filterIterator) Reset() (err error) {
|
||||||
|
// err = it.itLeft.Reset()
|
||||||
|
// it.IteratorBase.Reset()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (it *filterIterator) 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 = it.Index()
|
||||||
|
case kern.CurrentName:
|
||||||
|
v, err = it.Current()
|
||||||
|
case kern.CountName:
|
||||||
|
v = it.Count()
|
||||||
|
default:
|
||||||
|
err = kern.ErrNoOperation(name)
|
||||||
}
|
}
|
||||||
v = values
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operand-fraction.go
|
// operand-fraction.go
|
||||||
|
|||||||
+4
-1
@@ -31,6 +31,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
var item any
|
var item any
|
||||||
var sKey string
|
var sKey string
|
||||||
var keyByIndex bool
|
var keyByIndex bool
|
||||||
|
var ok bool
|
||||||
|
|
||||||
if err = opTerm.CheckOperands(); err != nil {
|
if err = opTerm.CheckOperands(); err != nil {
|
||||||
return
|
return
|
||||||
@@ -40,9 +41,11 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if it, err = NewIterator(leftValue); err != nil {
|
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))
|
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rightTk := opTerm.Children[1].Tk
|
rightTk := opTerm.Children[1].Tk
|
||||||
if rightTk.IsSymbol(scan.SymVariable) && rightTk.Source() == "__" {
|
if rightTk.IsSymbol(scan.SymVariable) && rightTk.Source() == "__" {
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-in.go
|
// operator-in.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-include.go
|
// operator-include.go
|
||||||
|
|||||||
+11
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-index.go
|
// operator-index.go
|
||||||
@@ -89,6 +89,11 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil {
|
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil {
|
||||||
v = (*unboxedValue)[index]
|
v = (*unboxedValue)[index]
|
||||||
}
|
}
|
||||||
|
case *kern.LinkedList:
|
||||||
|
var index int
|
||||||
|
if index, err = verifyIndex(indexTerm, indexList, unboxedValue.Len()); err == nil {
|
||||||
|
v, err = unboxedValue.At(index)
|
||||||
|
}
|
||||||
case string:
|
case string:
|
||||||
var index int
|
var index int
|
||||||
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil {
|
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil {
|
||||||
@@ -107,6 +112,11 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
sublist := kern.ListType((*unboxedValue)[start:end])
|
sublist := kern.ListType((*unboxedValue)[start:end])
|
||||||
v = &sublist
|
v = &sublist
|
||||||
}
|
}
|
||||||
|
case *kern.LinkedList:
|
||||||
|
var start, end int
|
||||||
|
if start, end, err = verifyRange(indexTerm, indexList, unboxedValue.Len()); err == nil {
|
||||||
|
v = unboxedValue.Sub(start, end)
|
||||||
|
}
|
||||||
case string:
|
case string:
|
||||||
var start, end int
|
var start, end int
|
||||||
if start, end, err = verifyRange(indexTerm, indexList, len(unboxedValue)); err == nil {
|
if start, end, err = verifyRange(indexTerm, indexList, len(unboxedValue)); err == nil {
|
||||||
|
|||||||
+70
-17
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-insert.go
|
// operator-insert.go
|
||||||
@@ -31,6 +31,41 @@ func newAppendTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prependToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
|
if list, ok := rightValue.(*kern.ListType); ok {
|
||||||
|
var it kern.Iterator
|
||||||
|
if it, ok = leftValue.(kern.Iterator); !ok {
|
||||||
|
if it, err = NewIterator(ctx, leftValue, nil); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := kern.NewLinkedList()
|
||||||
|
ls.SeqPushBack(it)
|
||||||
|
|
||||||
|
newList := kern.ListType(nil)
|
||||||
|
if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) {
|
||||||
|
newList = make([]any, 0, newSize)
|
||||||
|
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
||||||
|
newList = append(newList, node.Data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, item := range *list {
|
||||||
|
newList = append(newList, item)
|
||||||
|
}
|
||||||
|
result = &newList
|
||||||
|
|
||||||
|
// ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE
|
||||||
|
// ***** CON UN OPERATORE SPECIFICO
|
||||||
|
// if opTerm.Children[1].Symbol() == scan.SymVariable {
|
||||||
|
// ctx.UnsafeSetVar(opTerm.Children[1].Source(), result)
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
var leftValue, rightValue any
|
||||||
|
|
||||||
@@ -38,13 +73,39 @@ func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsList(rightValue) {
|
v, err = prependToList(ctx, opTerm, leftValue, rightValue)
|
||||||
list, _ := rightValue.(*kern.ListType)
|
return
|
||||||
newList := append(kern.ListType{leftValue}, *list...)
|
|
||||||
v = &newList
|
|
||||||
if opTerm.Children[1].Symbol() == scan.SymVariable {
|
|
||||||
ctx.UnsafeSetVar(opTerm.Children[1].Source(), v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendToList(ctx kern.ExprContext, opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
|
if list, ok := leftValue.(*kern.ListType); ok {
|
||||||
|
var it kern.Iterator
|
||||||
|
if it, ok = rightValue.(kern.Iterator); !ok {
|
||||||
|
if it, err = NewIterator(ctx, rightValue, nil); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := kern.NewLinkedList()
|
||||||
|
ls.SeqPushBack(it)
|
||||||
|
|
||||||
|
newList := *list
|
||||||
|
if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) {
|
||||||
|
newList = make([]any, 0, newSize)
|
||||||
|
for _, item := range *list {
|
||||||
|
newList = append(newList, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
||||||
|
newList = append(newList, node.Data())
|
||||||
|
}
|
||||||
|
result = &newList
|
||||||
|
|
||||||
|
// ***** EVENTUALMENTE ABILITARE LA MODIFICA DELLA VARIABILE
|
||||||
|
// ***** CON UN OPERATORE SPECIFICO
|
||||||
|
// if opTerm.Children[0].Symbol() == scan.SymVariable {
|
||||||
|
// ctx.UnsafeSetVar(opTerm.Children[0].Source(), result)
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -58,16 +119,8 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsList(leftValue) {
|
v, err = appendToList(ctx, opTerm, leftValue, rightValue)
|
||||||
list, _ := leftValue.(*kern.ListType)
|
|
||||||
newList := append(*list, rightValue)
|
|
||||||
v = &newList
|
|
||||||
if opTerm.Children[0].Symbol() == scan.SymVariable {
|
|
||||||
ctx.UnsafeSetVar(opTerm.Children[0].Source(), v)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-iter-value.go
|
// operator-iter-value.go
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// operator-join.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
|
||||||
)
|
|
||||||
|
|
||||||
//-------- join term
|
|
||||||
|
|
||||||
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 *scan.Term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
var itLeft, itRight kern.Iterator
|
|
||||||
var item any
|
|
||||||
|
|
||||||
if err = opTerm.CheckOperands(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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))
|
|
||||||
}
|
|
||||||
|
|
||||||
values := kern.NewListA()
|
|
||||||
for _, it := range []kern.Iterator{itLeft, itRight} {
|
|
||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
|
||||||
values.AppendItem(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == io.EOF {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
v = values
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
func init() {
|
|
||||||
scan.RegisterTermConstructor(scan.SymKwJoin, newJoinTerm)
|
|
||||||
}
|
|
||||||
+3
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-length.go
|
// operator-length.go
|
||||||
@@ -37,6 +37,8 @@ func evalLength(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
} else if kern.IsDict(childValue) {
|
} else if kern.IsDict(childValue) {
|
||||||
m, _ := childValue.(*kern.DictType)
|
m, _ := childValue.(*kern.DictType)
|
||||||
v = int64(len(*m))
|
v = int64(len(*m))
|
||||||
|
} else if lls, ok := childValue.(*kern.LinkedList); ok {
|
||||||
|
v = int64(lls.Len())
|
||||||
} else if it, ok := childValue.(kern.Iterator); ok {
|
} else if it, ok := childValue.(kern.Iterator); ok {
|
||||||
v = int64(it.Count())
|
v = int64(it.Count())
|
||||||
// if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(CountName) {
|
// if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(CountName) {
|
||||||
|
|||||||
+30
-26
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-map.go
|
// operator-map.go
|
||||||
@@ -6,7 +6,6 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
@@ -25,9 +24,11 @@ func newMapTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
// var leftValue, rightValue any
|
||||||
|
var leftValue any
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
var item any
|
// var item any
|
||||||
|
var ok bool
|
||||||
|
|
||||||
if err = opTerm.CheckOperands(); err != nil {
|
if err = opTerm.CheckOperands(); err != nil {
|
||||||
return
|
return
|
||||||
@@ -37,31 +38,34 @@ func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if it, err = NewIterator(leftValue); err != nil {
|
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))
|
return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
values := kern.NewListA()
|
// values := kern.NewListA()
|
||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
// for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
ctx.SetVar("_", item)
|
// ctx.SetVar("_", item)
|
||||||
ctx.SetVar("__", it.Index())
|
// ctx.SetVar("__", it.Index())
|
||||||
ctx.SetVar("_#", it.Count())
|
// 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)
|
// values.AppendItem(rightValue)
|
||||||
}
|
// }
|
||||||
ctx.DeleteVar("_#")
|
// ctx.DeleteVar("_#")
|
||||||
ctx.DeleteVar("__")
|
// ctx.DeleteVar("__")
|
||||||
ctx.DeleteVar("_")
|
// ctx.DeleteVar("_")
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if err == io.EOF {
|
// if err == io.EOF {
|
||||||
err = nil
|
// err = nil
|
||||||
}
|
// }
|
||||||
if err == nil {
|
// if err == nil {
|
||||||
v = values
|
// v = values
|
||||||
}
|
// }
|
||||||
|
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-plugin.go
|
// operator-plugin.go
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-post-inc-dec.go
|
// operator-post-inc-dec.go
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-pre-inc-dec.go
|
// operator-pre-inc-dec.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-prod.go
|
// operator-prod.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-range.go
|
// operator-range.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-rel.go
|
// operator-rel.go
|
||||||
|
|||||||
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-selector.go
|
// operator-selector.go
|
||||||
|
|||||||
+7
-3
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-shift.go
|
// operator-shift.go
|
||||||
@@ -39,7 +39,9 @@ func evalRightShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err = bitRightShift(opTerm, leftValue, rightValue)
|
if v, err = bitRightShift(opTerm, leftValue, rightValue); err != nil {
|
||||||
|
v, err = prependToList(ctx, opTerm, leftValue, rightValue)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +73,9 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err = bitLeftShift(opTerm, leftValue, rightValue)
|
if v, err = bitLeftShift(opTerm, leftValue, rightValue); err != nil {
|
||||||
|
v, err = appendToList(ctx, opTerm, leftValue, rightValue)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-sign.go
|
// operator-sign.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-sum.go
|
// operator-sum.go
|
||||||
|
|||||||
+1
-1
@@ -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.
|
// All rights reserved.
|
||||||
|
|
||||||
// operator-unset.go
|
// operator-unset.go
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user