Compare commits
23 Commits
6a6c897268
...
7430e9bdf7
| Author | SHA1 | Date | |
|---|---|---|---|
| 7430e9bdf7 | |||
| 8084ffbc19 | |||
| e896e06a93 | |||
| 7df7d1463f | |||
| 948bad6f96 | |||
| 1c4ba5ef0b | |||
| 648533cbe3 | |||
| 8e596d5979 | |||
| 07aecfc4e7 | |||
| 2f616f349b | |||
| 8c55f4ac4b | |||
| bf2c7df0f0 | |||
| 6b561fea45 | |||
| daca05e637 | |||
| 4df222496d | |||
| 072fd9af39 | |||
| 77f36642b4 | |||
| b6da9bcad4 | |||
| fec7cc546c | |||
| d8dc2939b4 | |||
| dba8e01aa0 | |||
| 6e868b568d | |||
| 73e4ad7b87 |
@@ -10,10 +10,12 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListIterator struct {
|
type ListIterator struct {
|
||||||
a *kern.ListType
|
a *array.ArrayType
|
||||||
count int64
|
count int64
|
||||||
index int64
|
index int64
|
||||||
start int64
|
start int64
|
||||||
@@ -21,7 +23,7 @@ type ListIterator struct {
|
|||||||
step int64
|
step int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewListIterator(list *kern.ListType, args []any) (it *ListIterator) {
|
func NewListIterator(list *array.ArrayType, args []any) (it *ListIterator) {
|
||||||
var argc int = 0
|
var argc int = 0
|
||||||
listLen := int64(len(([]any)(*list)))
|
listLen := int64(len(([]any)(*list)))
|
||||||
if args != nil {
|
if args != nil {
|
||||||
@@ -29,21 +31,21 @@ func NewListIterator(list *kern.ListType, args []any) (it *ListIterator) {
|
|||||||
}
|
}
|
||||||
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
|
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
|
||||||
if argc >= 1 {
|
if argc >= 1 {
|
||||||
if i, err := kern.ToGoInt64(args[0], "start index"); err == nil {
|
if i, err := types.ToGoInt64(args[0], "start index"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = listLen + i
|
i = listLen + i
|
||||||
}
|
}
|
||||||
it.start = i
|
it.start = i
|
||||||
}
|
}
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
if i, err := kern.ToGoInt64(args[1], "stop index"); err == nil {
|
if i, err := types.ToGoInt64(args[1], "stop index"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = listLen + i
|
i = listLen + i
|
||||||
}
|
}
|
||||||
it.stop = i
|
it.stop = i
|
||||||
}
|
}
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
if i, err := kern.ToGoInt64(args[2], "step"); err == nil {
|
if i, err := types.ToGoInt64(args[2], "step"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = -i
|
i = -i
|
||||||
}
|
}
|
||||||
@@ -60,8 +62,8 @@ func NewListIterator(list *kern.ListType, args []any) (it *ListIterator) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArrayIterator(array []any) (it *ListIterator) {
|
func NewArrayIterator(a []any) (it *ListIterator) {
|
||||||
it = &ListIterator{a: (*kern.ListType)(&array), count: 0, index: -1, start: 0, stop: int64(len(array)) - 1, step: 1}
|
it = &ListIterator{a: (*array.ArrayType)(&a), count: 0, index: -1, start: 0, stop: int64(len(a)) - 1, step: 1}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
+39
-25
@@ -12,6 +12,14 @@ 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/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -24,42 +32,47 @@ func isNilFunc(ctx kern.ExprContext, name string, args map[string]any) (result a
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isIntFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isIntFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsInteger(args[kern.ParamValue])
|
result = types.IsInteger(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isFloatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isFloatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsFloat(args[kern.ParamValue])
|
result = float.IsFloat(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBoolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isBoolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsBool(args[kern.ParamValue])
|
result = boolean.IsBool(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isStringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isStringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsString(args[kern.ParamValue])
|
result = str.IsString(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isFractionFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isFractionFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsFraction(args[kern.ParamValue])
|
result = fract.IsFraction(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRationalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isRationalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsRational(args[kern.ParamValue])
|
result = fract.IsRational(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isListFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isArrayFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsList(args[kern.ParamValue])
|
result = array.IsArray(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isDictionaryFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func isDictionaryFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
result = kern.IsDict(args[kern.ParamValue])
|
result = dict.IsDict(args[kern.ParamValue])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func isListFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
|
result = list.IsLinkedList(args[kern.ParamValue])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +80,7 @@ func boolFunc(ctx kern.ExprContext, name string, args map[string]any) (result an
|
|||||||
switch v := args[kern.ParamValue].(type) {
|
switch v := args[kern.ParamValue].(type) {
|
||||||
case int64:
|
case int64:
|
||||||
result = (v != 0)
|
result = (v != 0)
|
||||||
case *kern.FractionType:
|
case *fract.FractionType:
|
||||||
result = v.N() != 0
|
result = v.N() != 0
|
||||||
case float64:
|
case float64:
|
||||||
result = v != 0.0
|
result = v != 0.0
|
||||||
@@ -75,9 +88,9 @@ func boolFunc(ctx kern.ExprContext, name string, args map[string]any) (result an
|
|||||||
result = v
|
result = v
|
||||||
case string:
|
case string:
|
||||||
result = len(v) > 0
|
result = len(v) > 0
|
||||||
case *kern.ListType:
|
case *array.ArrayType:
|
||||||
result = len(*v) > 0
|
result = len(*v) > 0
|
||||||
case *kern.DictType:
|
case *dict.DictType:
|
||||||
result = len(*v) > 0
|
result = len(*v) > 0
|
||||||
default:
|
default:
|
||||||
err = kern.ErrCantConvert(name, v, "bool")
|
err = kern.ErrCantConvert(name, v, "bool")
|
||||||
@@ -102,7 +115,7 @@ func intFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
if i, err = strconv.Atoi(v); err == nil {
|
if i, err = strconv.Atoi(v); err == nil {
|
||||||
result = int64(i)
|
result = int64(i)
|
||||||
}
|
}
|
||||||
case *kern.FractionType:
|
case *fract.FractionType:
|
||||||
result = int64(v.N() / v.D())
|
result = int64(v.N() / v.D())
|
||||||
default:
|
default:
|
||||||
err = kern.ErrCantConvert(name, v, "int")
|
err = kern.ErrCantConvert(name, v, "int")
|
||||||
@@ -110,7 +123,7 @@ func intFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func decFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func floatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
switch v := args[kern.ParamValue].(type) {
|
switch v := args[kern.ParamValue].(type) {
|
||||||
case int64:
|
case int64:
|
||||||
result = float64(v)
|
result = float64(v)
|
||||||
@@ -127,7 +140,7 @@ func decFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
if f, err = strconv.ParseFloat(v, 64); err == nil {
|
if f, err = strconv.ParseFloat(v, 64); err == nil {
|
||||||
result = f
|
result = f
|
||||||
}
|
}
|
||||||
case *kern.FractionType:
|
case *fract.FractionType:
|
||||||
result = v.ToFloat()
|
result = v.ToFloat()
|
||||||
default:
|
default:
|
||||||
err = kern.ErrCantConvert(name, v, "float")
|
err = kern.ErrCantConvert(name, v, "float")
|
||||||
@@ -149,7 +162,7 @@ func stringFunc(ctx kern.ExprContext, name string, args map[string]any) (result
|
|||||||
}
|
}
|
||||||
case string:
|
case string:
|
||||||
result = v
|
result = v
|
||||||
case *kern.FractionType:
|
case *fract.FractionType:
|
||||||
result = v.ToString(0)
|
result = v.ToString(0)
|
||||||
case kern.Formatter:
|
case kern.Formatter:
|
||||||
result = v.ToString(0)
|
result = v.ToString(0)
|
||||||
@@ -174,19 +187,19 @@ func fractFunc(ctx kern.ExprContext, name string, args map[string]any) (result a
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result = kern.NewFraction(v, den)
|
result = fract.NewFraction(v, den)
|
||||||
}
|
}
|
||||||
case float64:
|
case float64:
|
||||||
result, err = kern.Float64ToFraction(v)
|
result, err = fract.Float64ToFraction(v)
|
||||||
case bool:
|
case bool:
|
||||||
if v {
|
if v {
|
||||||
result = kern.NewFraction(1, 1)
|
result = fract.NewFraction(1, 1)
|
||||||
} else {
|
} else {
|
||||||
result = kern.NewFraction(0, 1)
|
result = fract.NewFraction(0, 1)
|
||||||
}
|
}
|
||||||
case string:
|
case string:
|
||||||
result, err = kern.MakeGeneratingFraction(v)
|
result, err = fract.MakeGeneratingFraction(v)
|
||||||
case *kern.FractionType:
|
case *fract.FractionType:
|
||||||
result = v
|
result = v
|
||||||
default:
|
default:
|
||||||
err = kern.ErrCantConvert(name, v, "float")
|
err = kern.ErrCantConvert(name, v, "float")
|
||||||
@@ -276,7 +289,7 @@ func charFunc(ctx kern.ExprContext, name string, args map[string]any) (result an
|
|||||||
}
|
}
|
||||||
|
|
||||||
func seqFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func seqFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
list := kern.NewLinkedList()
|
list := list.NewLinkedList()
|
||||||
items := args[kern.ParamValue].([]any)
|
items := args[kern.ParamValue].([]any)
|
||||||
for _, arg := range items {
|
for _, arg := range items {
|
||||||
list.PushBack(arg)
|
list.PushBack(arg)
|
||||||
@@ -299,12 +312,13 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) {
|
|||||||
ctx.RegisterFunc("isString", kern.NewGolangFunctor(isStringFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isString", kern.NewGolangFunctor(isStringFunc), kern.TypeBoolean, anyParams)
|
||||||
ctx.RegisterFunc("isFract", kern.NewGolangFunctor(isFractionFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isFract", kern.NewGolangFunctor(isFractionFunc), kern.TypeBoolean, anyParams)
|
||||||
ctx.RegisterFunc("isRational", kern.NewGolangFunctor(isRationalFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isRational", kern.NewGolangFunctor(isRationalFunc), kern.TypeBoolean, anyParams)
|
||||||
ctx.RegisterFunc("isList", kern.NewGolangFunctor(isListFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isArray", kern.NewGolangFunctor(isArrayFunc), kern.TypeBoolean, anyParams)
|
||||||
ctx.RegisterFunc("isDict", kern.NewGolangFunctor(isDictionaryFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("isDict", kern.NewGolangFunctor(isDictionaryFunc), kern.TypeBoolean, anyParams)
|
||||||
|
ctx.RegisterFunc("isList", kern.NewGolangFunctor(isListFunc), kern.TypeBoolean, anyParams)
|
||||||
|
|
||||||
ctx.RegisterFunc("bool", kern.NewGolangFunctor(boolFunc), kern.TypeBoolean, anyParams)
|
ctx.RegisterFunc("bool", kern.NewGolangFunctor(boolFunc), kern.TypeBoolean, anyParams)
|
||||||
ctx.RegisterFunc("int", kern.NewGolangFunctor(intFunc), kern.TypeInt, anyParams)
|
ctx.RegisterFunc("int", kern.NewGolangFunctor(intFunc), kern.TypeInt, anyParams)
|
||||||
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
|
ctx.RegisterFunc("float", kern.NewGolangFunctor(floatFunc), 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{
|
||||||
kern.NewFuncParam(kern.ParamValue),
|
kern.NewFuncParam(kern.ParamValue),
|
||||||
|
|||||||
+2
-1
@@ -10,6 +10,7 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
@@ -47,7 +48,7 @@ func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Itera
|
|||||||
var expr *scan.Ast
|
var expr *scan.Ast
|
||||||
scanner := scan.NewScanner(file, scan.DefaultTranslations())
|
scanner := scan.NewScanner(file, scan.DefaultTranslations())
|
||||||
parser := NewParser()
|
parser := NewParser()
|
||||||
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymEos); err == nil {
|
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, sym.SymEos); err == nil {
|
||||||
result, err = expr.Eval(ctx)
|
result, err = expr.Eval(ctx)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+36
-14
@@ -9,32 +9,39 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
iterParamOperator = "operator"
|
iterParamOperator = "operator"
|
||||||
iterParamVars = "vars"
|
iterParamVars = "vars"
|
||||||
iterVarStatus = "status"
|
iterVarStatus = "status"
|
||||||
|
iterParamStatus = "status"
|
||||||
|
iterVarAbort = "__abort"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Iterator, op kern.Functor, err error) {
|
func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Iterator, op kern.Functor, err error) {
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if it, ok = args[kern.ParamIterator].(kern.Iterator); !ok {
|
if it, ok = args[kern.ParamIterator].(kern.Iterator); !ok {
|
||||||
err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator]))
|
// err = fmt.Errorf("parameter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator]))
|
||||||
|
err = errBadParamType(kern.ParamIterator, kern.TypeIterator, args[kern.ParamIterator])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if args[iterParamOperator] != nil {
|
if args[iterParamOperator] != nil {
|
||||||
if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil {
|
if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil {
|
||||||
err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator]))
|
// err = fmt.Errorf("parameter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator]))
|
||||||
|
err = errBadParamType(iterParamOperator, "function", args[iterParamOperator])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars *kern.DictType
|
var vars *dict.DictType
|
||||||
if vars, ok = args[iterParamVars].(*kern.DictType); !ok && args[iterParamVars] != nil {
|
if vars, ok = args[iterParamVars].(*dict.DictType); !ok && args[iterParamVars] != nil {
|
||||||
err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars]))
|
// err = fmt.Errorf("parameter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars]))
|
||||||
|
err = errBadParamType(iterParamVars, kern.TypeDict, args[iterParamVars])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,12 +57,21 @@ func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Itera
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func errBadParamType(paramName, wantedType string, wantedValue any) error {
|
||||||
|
return fmt.Errorf("type of %q must be %s, passed %v [%s]", paramName, wantedType, wantedValue, kern.TypeName(wantedValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
func abortFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
|
if status, provided := args[iterParamStatus]; provided {
|
||||||
|
ctx.UnsafeSetVar("@"+iterVarStatus, status)
|
||||||
|
}
|
||||||
|
ctx.UnsafeSetVar("@"+iterVarAbort, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
var ok bool
|
|
||||||
var op kern.Functor
|
var op kern.Functor
|
||||||
var v any
|
|
||||||
// var usingDefaultOp = false
|
|
||||||
var params map[string]any
|
var params map[string]any
|
||||||
var item any
|
var item any
|
||||||
|
|
||||||
@@ -66,14 +82,20 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localCtx.RegisterFunc("abort", kern.NewGolangFunctor(abortFunc), kern.TypeAny, []kern.ExprFuncParam{
|
||||||
|
kern.NewFuncParamFlagDef(iterParamStatus, kern.PfOptional, "aborted"),
|
||||||
|
})
|
||||||
|
|
||||||
|
params = map[string]any{kern.ParamIndex: 0, kern.ParamItem: nil}
|
||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
if op != nil {
|
if op != nil {
|
||||||
params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item}
|
// params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item}
|
||||||
if v, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
|
params[kern.ParamIndex] = it.Index()
|
||||||
|
params[kern.ParamItem] = item
|
||||||
|
if _, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil {
|
||||||
break
|
break
|
||||||
} else {
|
} else if abortAny, exists := localCtx.GetVar(iterVarAbort); exists {
|
||||||
var success bool
|
if abort, ok := boolean.ToBool(abortAny); ok && abort {
|
||||||
if success, ok = kern.ToBool(v); !success || !ok {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +107,7 @@ func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
|
|||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if op == nil {
|
if op == nil {
|
||||||
ctx.UnsafeSetVar(iterVarStatus, it.Count())
|
localCtx.UnsafeSetVar(iterVarStatus, it.Count())
|
||||||
}
|
}
|
||||||
result, _ = localCtx.GetVar(iterVarStatus)
|
result, _ = localCtx.GetVar(iterVarStatus)
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-21
@@ -9,10 +9,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkNumberParamExpected(funcName string, paramValue any, paramPos, level, subPos int) (err error) {
|
func checkNumberParamExpected(funcName string, paramValue any, paramPos, level, subPos int) (err error) {
|
||||||
if !(kern.IsNumber(paramValue) || kern.IsFraction(paramValue)) /*|| isList(paramValue)*/ {
|
if !(types.IsNumber(paramValue) || fract.IsFraction(paramValue)) /*|| isArray(paramValue)*/ {
|
||||||
err = fmt.Errorf("%s(): param nr %d (%d in %d) has wrong type %T, number expected",
|
err = fmt.Errorf("%s(): param nr %d (%d in %d) has wrong type %T, number expected",
|
||||||
funcName, paramPos+1, subPos+1, level, paramValue)
|
funcName, paramPos+1, subPos+1, level, paramValue)
|
||||||
}
|
}
|
||||||
@@ -23,13 +27,13 @@ func doAdd(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
|
|||||||
var sumAsFloat, sumAsFract bool
|
var sumAsFloat, sumAsFract bool
|
||||||
var floatSum float64 = 0.0
|
var floatSum float64 = 0.0
|
||||||
var intSum int64 = 0
|
var intSum int64 = 0
|
||||||
var fractSum *kern.FractionType
|
var fractSum *fract.FractionType
|
||||||
var v any
|
var v any
|
||||||
|
|
||||||
level++
|
level++
|
||||||
|
|
||||||
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
||||||
if list, ok := v.(*kern.ListType); ok {
|
if list, ok := v.(*array.ArrayType); ok {
|
||||||
v = NewListIterator(list, nil)
|
v = NewListIterator(list, nil)
|
||||||
}
|
}
|
||||||
if subIter, ok := v.(kern.Iterator); ok {
|
if subIter, ok := v.(kern.Iterator); ok {
|
||||||
@@ -47,29 +51,29 @@ func doAdd(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
|
|||||||
count++
|
count++
|
||||||
|
|
||||||
if !sumAsFloat {
|
if !sumAsFloat {
|
||||||
if kern.IsFloat(v) {
|
if float.IsFloat(v) {
|
||||||
sumAsFloat = true
|
sumAsFloat = true
|
||||||
if sumAsFract {
|
if sumAsFract {
|
||||||
floatSum = fractSum.ToFloat()
|
floatSum = fractSum.ToFloat()
|
||||||
} else {
|
} else {
|
||||||
floatSum = float64(intSum)
|
floatSum = float64(intSum)
|
||||||
}
|
}
|
||||||
} else if !sumAsFract && kern.IsFraction(v) {
|
} else if !sumAsFract && fract.IsFraction(v) {
|
||||||
fractSum = kern.NewFraction(intSum, 1)
|
fractSum = fract.NewFraction(intSum, 1)
|
||||||
sumAsFract = true
|
sumAsFract = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sumAsFloat {
|
if sumAsFloat {
|
||||||
floatSum += kern.NumAsFloat(v)
|
floatSum += types.NumAsFloat(v)
|
||||||
} else if sumAsFract {
|
} else if sumAsFract {
|
||||||
var item *kern.FractionType
|
var item *fract.FractionType
|
||||||
var ok bool
|
var ok bool
|
||||||
if item, ok = v.(*kern.FractionType); !ok {
|
if item, ok = v.(*fract.FractionType); !ok {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
item = kern.NewFraction(iv, 1)
|
item = fract.NewFraction(iv, 1)
|
||||||
}
|
}
|
||||||
fractSum = kern.SumFract(fractSum, item)
|
fractSum = fract.SumFract(fractSum, item)
|
||||||
} else {
|
} else {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
intSum += iv
|
intSum += iv
|
||||||
@@ -98,12 +102,12 @@ func doMul(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
|
|||||||
var mulAsFloat, mulAsFract bool
|
var mulAsFloat, mulAsFract bool
|
||||||
var floatProd float64 = 1.0
|
var floatProd float64 = 1.0
|
||||||
var intProd int64 = 1
|
var intProd int64 = 1
|
||||||
var fractProd *kern.FractionType
|
var fractProd *fract.FractionType
|
||||||
var v any
|
var v any
|
||||||
|
|
||||||
level++
|
level++
|
||||||
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
||||||
if list, ok := v.(*kern.ListType); ok {
|
if list, ok := v.(*array.ArrayType); ok {
|
||||||
v = NewListIterator(list, nil)
|
v = NewListIterator(list, nil)
|
||||||
}
|
}
|
||||||
if subIter, ok := v.(kern.Iterator); ok {
|
if subIter, ok := v.(kern.Iterator); ok {
|
||||||
@@ -123,29 +127,29 @@ func doMul(ctx kern.ExprContext, name string, it kern.Iterator, count, level int
|
|||||||
count++
|
count++
|
||||||
|
|
||||||
if !mulAsFloat {
|
if !mulAsFloat {
|
||||||
if kern.IsFloat(v) {
|
if float.IsFloat(v) {
|
||||||
mulAsFloat = true
|
mulAsFloat = true
|
||||||
if mulAsFract {
|
if mulAsFract {
|
||||||
floatProd = fractProd.ToFloat()
|
floatProd = fractProd.ToFloat()
|
||||||
} else {
|
} else {
|
||||||
floatProd = float64(intProd)
|
floatProd = float64(intProd)
|
||||||
}
|
}
|
||||||
} else if !mulAsFract && kern.IsFraction(v) {
|
} else if !mulAsFract && fract.IsFraction(v) {
|
||||||
fractProd = kern.NewFraction(intProd, 1)
|
fractProd = fract.NewFraction(intProd, 1)
|
||||||
mulAsFract = true
|
mulAsFract = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mulAsFloat {
|
if mulAsFloat {
|
||||||
floatProd *= kern.NumAsFloat(v)
|
floatProd *= types.NumAsFloat(v)
|
||||||
} else if mulAsFract {
|
} else if mulAsFract {
|
||||||
var item *kern.FractionType
|
var item *fract.FractionType
|
||||||
var ok bool
|
var ok bool
|
||||||
if item, ok = v.(*kern.FractionType); !ok {
|
if item, ok = v.(*fract.FractionType); !ok {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
item = kern.NewFraction(iv, 1)
|
item = fract.NewFraction(iv, 1)
|
||||||
}
|
}
|
||||||
fractProd = kern.MulFract(fractProd, item)
|
fractProd = fract.MulFract(fractProd, item)
|
||||||
} else {
|
} else {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
intProd *= iv
|
intProd *= iv
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ func (it *fileFileByteIterator) Clean() (err error) {
|
|||||||
it.reader = nil
|
it.reader = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.reset()
|
// it.reset()
|
||||||
it.b = 0
|
// it.b = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ func (it *fileFileLineIterator) Clean() (err error) {
|
|||||||
it.reader = nil
|
it.reader = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.reset()
|
// it.reset()
|
||||||
it.line = ""
|
// it.line = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-7
@@ -10,6 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -43,8 +45,8 @@ func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result
|
|||||||
if v, exists := args[kern.ParamItem]; exists {
|
if v, exists := args[kern.ParamItem]; exists {
|
||||||
argv := v.([]any)
|
argv := v.([]any)
|
||||||
if len(argv) == 1 {
|
if len(argv) == 1 {
|
||||||
if ls, ok := argv[0].(*kern.ListType); ok {
|
if a, ok := argv[0].(*array.ArrayType); ok {
|
||||||
result, err = doJoinStr(name, sep, NewListIterator(ls, nil))
|
result, err = doJoinStr(name, sep, NewListIterator(a, nil))
|
||||||
} else if it, ok := argv[0].(kern.Iterator); ok {
|
} else if it, ok := argv[0].(kern.Iterator); ok {
|
||||||
result, err = doJoinStr(name, sep, it)
|
result, err = doJoinStr(name, sep, it)
|
||||||
} else if s, ok := argv[0].(string); ok {
|
} else if s, ok := argv[0].(string); ok {
|
||||||
@@ -72,11 +74,11 @@ func subStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result
|
|||||||
return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
|
return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource])
|
||||||
}
|
}
|
||||||
|
|
||||||
if start, err = kern.ToGoInt(args[kern.ParamStart], name+"()"); err != nil {
|
if start, err = types.ToGoInt(args[kern.ParamStart], name+"()"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if count, err = kern.ToGoInt(args[kern.ParamCount], name+"()"); err != nil {
|
if count, err = types.ToGoInt(args[kern.ParamCount], name+"()"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,11 +196,11 @@ func splitStrFunc(ctx kern.ExprContext, name string, args map[string]any) (resul
|
|||||||
} else {
|
} else {
|
||||||
parts = []string{}
|
parts = []string{}
|
||||||
}
|
}
|
||||||
list := make(kern.ListType, len(parts))
|
a := make(array.ArrayType, len(parts))
|
||||||
for i, part := range parts {
|
for i, part := range parts {
|
||||||
list[i] = part
|
a[i] = part
|
||||||
}
|
}
|
||||||
result = &list
|
result = &a
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
-18
@@ -34,6 +34,7 @@ Expression Calculator Interactive Tool
|
|||||||
The tool combines the expression evaluation capabilities of the Expr package with an interactive shell environment, making it ideal for:
|
The tool combines the expression evaluation capabilities of the Expr package with an interactive shell environment, making it ideal for:
|
||||||
|
|
||||||
- Interactive expression testing and prototyping
|
- Interactive expression testing and prototyping
|
||||||
|
- Command history survival across sessions
|
||||||
- Batch expression evaluation from scripts
|
- Batch expression evaluation from scripts
|
||||||
- Data processing and transformation
|
- Data processing and transformation
|
||||||
- Mathematical computations with fractions and complex operators
|
- Mathematical computations with fractions and complex operators
|
||||||
@@ -89,11 +90,14 @@ Within the REPL, you can use the following commands:
|
|||||||
|===
|
|===
|
||||||
| Command | Description
|
| Command | Description
|
||||||
|
|
||||||
| `help` | Display available commands and command-line options
|
| `base [2\|8\|10\|16]` | Set the integer output base. Use without arguments to show current base
|
||||||
| `exit` | Exit the REPL
|
| `exit` | Exit the REPL
|
||||||
| `multiline` | Toggle multi-line input mode for complex expressions
|
| `help` | Display available commands and command-line options
|
||||||
| `tty` | Toggle TTY mode
|
| `ml` | Enable/Disable multi-line input mode for complex expressions
|
||||||
| `source <file>` | Execute expressions from a file
|
| `mods` | List all builtin modules (with `*` marking imported ones)
|
||||||
|
| `output [on\|off\|status]` | Enable/Disable printing of expression results
|
||||||
|
| `source <file>` | Load and execute expressions from a file
|
||||||
|
| `tty` | Enable/Disable ANSI terminal output
|
||||||
|===
|
|===
|
||||||
|
|
||||||
== Features
|
== Features
|
||||||
@@ -160,8 +164,16 @@ hello world
|
|||||||
|
|
||||||
[source,bash]
|
[source,bash]
|
||||||
----
|
----
|
||||||
>>> [1, 2, 3, 4, 5] | map(. * 2)
|
>>> it = [1, 2, 3, 4, 5] map $_ * 2
|
||||||
[2, 4, 6, 8, 10]
|
$($([#5]))
|
||||||
|
>>> $$(it)
|
||||||
|
[<
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
10
|
||||||
|
>]
|
||||||
----
|
----
|
||||||
|
|
||||||
=== Evaluating from Command Line
|
=== Evaluating from Command Line
|
||||||
@@ -192,7 +204,7 @@ Or from command line:
|
|||||||
|
|
||||||
[source,bash]
|
[source,bash]
|
||||||
----
|
----
|
||||||
./ecli -e '@include "expressions.expr"'
|
./ecli -e "@expressions.expr"
|
||||||
----
|
----
|
||||||
|
|
||||||
== Configuration
|
== Configuration
|
||||||
@@ -233,16 +245,16 @@ The build process generates:
|
|||||||
|
|
||||||
=== Multi-line Input
|
=== Multi-line Input
|
||||||
|
|
||||||
For complex expressions, toggle multi-line mode:
|
For complex expressions, split operations across multiple lines terminating with a backslash (`\`):
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
>>> multiline
|
>>> ml
|
||||||
>>> result = [1, 2, 3, 4, 5]
|
>>> result = [1, 2, 3, 4, 5] \
|
||||||
... | filter(. > 2)
|
... filter $_ > 2 \
|
||||||
... | map(. * 2)
|
... map $_ * 2
|
||||||
>>> result
|
>>> $$(result)
|
||||||
[6, 8, 10]
|
[<6, 8, 10>
|
||||||
----
|
----
|
||||||
|
|
||||||
=== Script Execution
|
=== Script Execution
|
||||||
@@ -260,16 +272,29 @@ Execute it:
|
|||||||
|
|
||||||
[source,bash]
|
[source,bash]
|
||||||
----
|
----
|
||||||
./ecli -e '@source "calculations.expr"' -e 'result'
|
./ecli -e '@calculations.expr' -e 'result'
|
||||||
|
50
|
||||||
----
|
----
|
||||||
|
|
||||||
=== Chaining Operations
|
=== Other Iterator Examples
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
>>> data = [{"name": "alice", "age": 30}, {"name": "bob", "age": 25}]
|
>>> data = [{"name": "alice", "age": 30}, {"name": "bob", "age": 25}]
|
||||||
>>> data | map(.name)
|
|
||||||
[alice, bob]
|
// Extract names using map iterator
|
||||||
|
>>> $$(data map ($_).name)
|
||||||
|
[<
|
||||||
|
"alice",
|
||||||
|
"bob"
|
||||||
|
>]
|
||||||
|
|
||||||
|
// Filter ages greater than 28
|
||||||
|
>>> $$(data filter ($_).age > 28 map ($_).name)
|
||||||
|
[<
|
||||||
|
"alice"
|
||||||
|
>]
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
== Troubleshooting
|
== Troubleshooting
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
//go:build graph
|
//go:build graph
|
||||||
|
|
||||||
|
// NOTE: Enable this build tag to print the graph of the expression instead of evaluating it.
|
||||||
|
// go run -tags graph cmd/ecli/main.go
|
||||||
|
|
||||||
// graph.go
|
// graph.go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -14,6 +14,9 @@ import (
|
|||||||
"git.portale-stac.it/go-pkg/expr"
|
"git.portale-stac.it/go-pkg/expr"
|
||||||
"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/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
"git.portale-stac.it/go-pkg/utils"
|
"git.portale-stac.it/go-pkg/utils"
|
||||||
|
|
||||||
// https://pkg.go.dev/github.com/ergochat/readline#section-readme
|
// https://pkg.go.dev/github.com/ergochat/readline#section-readme
|
||||||
@@ -225,10 +228,10 @@ func compute(opt *Options, ctx kern.ExprContext, r io.Reader, outputEnabled bool
|
|||||||
func printResult(opt *Options, result any) {
|
func printResult(opt *Options, result any) {
|
||||||
if f, ok := result.(kern.Formatter); ok {
|
if f, ok := result.(kern.Formatter); ok {
|
||||||
fmt.Println(f.ToString(opt.formOpt))
|
fmt.Println(f.ToString(opt.formOpt))
|
||||||
} else if kern.IsInteger(result) {
|
} else if types.IsInteger(result) {
|
||||||
fmt.Printf(opt.baseVerb, result)
|
fmt.Printf(opt.baseVerb, result)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
} else if kern.IsString(result) {
|
} else if str.IsString(result) {
|
||||||
fmt.Printf("\"%s\"\n", result)
|
fmt.Printf("\"%s\"\n", result)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
@@ -257,7 +260,7 @@ func registerLocalFunctions(ctx kern.ExprContext) {
|
|||||||
vars := ctx.EnumVars(func(name string) bool {
|
vars := ctx.EnumVars(func(name string) bool {
|
||||||
return len(name) > 0 && name[0] == '_'
|
return len(name) > 0 && name[0] == '_'
|
||||||
})
|
})
|
||||||
result = kern.ListFromStrings(vars)
|
result = array.ArrayFromStrings(vars)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +312,7 @@ func registerLocalFunctions(ctx kern.ExprContext) {
|
|||||||
name, _, _ := strings.Cut(e, "=")
|
name, _, _ := strings.Cut(e, "=")
|
||||||
vars = append(vars, name)
|
vars = append(vars, name)
|
||||||
}
|
}
|
||||||
result = kern.ListFromStrings(vars)
|
result = array.ArrayFromStrings(vars)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -11,6 +11,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dictIterMode int
|
type dictIterMode int
|
||||||
@@ -22,7 +25,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DictIterator struct {
|
type DictIterator struct {
|
||||||
a *kern.DictType
|
a *dict.DictType
|
||||||
count int64
|
count int64
|
||||||
index int64
|
index int64
|
||||||
keys []any
|
keys []any
|
||||||
@@ -67,7 +70,7 @@ func (it *DictIterator) makeKeys(m map[any]any, sort sortType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err error) {
|
func NewDictIterator(dict *dict.DictType, args []any) (it *DictIterator, err error) {
|
||||||
var sortType = sortTypeNone
|
var sortType = sortTypeNone
|
||||||
var s string
|
var s string
|
||||||
var argAny any
|
var argAny any
|
||||||
@@ -78,7 +81,7 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err
|
|||||||
} else {
|
} else {
|
||||||
argAny = "default"
|
argAny = "default"
|
||||||
}
|
}
|
||||||
if s, err = kern.ToGoString(argAny, "sort type"); err == nil {
|
if s, err = str.ToGoString(argAny, "sort type"); err == nil {
|
||||||
switch strings.ToLower(s) {
|
switch strings.ToLower(s) {
|
||||||
case "a", "asc":
|
case "a", "asc":
|
||||||
sortType = sortTypeAsc
|
sortType = sortTypeAsc
|
||||||
@@ -99,7 +102,7 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err
|
|||||||
argAny = "default"
|
argAny = "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, err = kern.ToGoString(argAny, "iteration mode"); err == nil {
|
if s, err = str.ToGoString(argAny, "iteration mode"); err == nil {
|
||||||
switch strings.ToLower(s) {
|
switch strings.ToLower(s) {
|
||||||
case "k", "key", "keys":
|
case "k", "key", "keys":
|
||||||
dictIt.iterMode = dictIterModeKeys
|
dictIt.iterMode = dictIterModeKeys
|
||||||
@@ -124,7 +127,7 @@ func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewMapIterator(m map[any]any) (it *DictIterator) {
|
func NewMapIterator(m map[any]any) (it *DictIterator) {
|
||||||
it = &DictIterator{a: (*kern.DictType)(&m), count: 0, index: -1, keys: nil}
|
it = &DictIterator{a: (*dict.DictType)(&m), count: 0, index: -1, keys: nil}
|
||||||
it.makeKeys(m, sortTypeNone)
|
it.makeKeys(m, sortTypeNone)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -190,7 +193,7 @@ func (it *DictIterator) Current() (item any, err error) {
|
|||||||
case dictIterModeItems:
|
case dictIterModeItems:
|
||||||
a := *(it.a)
|
a := *(it.a)
|
||||||
pair := []any{it.keys[it.index], a[it.keys[it.index]]}
|
pair := []any{it.keys[it.index], a[it.keys[it.index]]}
|
||||||
item = kern.NewList(pair)
|
item = array.NewArray(pair)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
|
|||||||
+345
-162
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
)
|
)
|
||||||
|
|
||||||
//var globalCtx *SimpleStore
|
//var globalCtx *SimpleStore
|
||||||
@@ -68,7 +69,7 @@ func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) {
|
|||||||
|
|
||||||
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
|
||||||
name = fixCtrlVar(name)
|
name = fixCtrlVar(name)
|
||||||
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
if v, exists := ctx.GetVar(name); exists && boolean.IsBool(v) {
|
||||||
currentStatus, _ = v.(bool)
|
currentStatus, _ = v.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +79,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) {
|
||||||
name = fixCtrlVar(name)
|
name = fixCtrlVar(name)
|
||||||
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
|
if v, exists := ctx.GetVar(name); exists && boolean.IsBool(v) {
|
||||||
currentStatus, _ = v.(bool)
|
currentStatus, _ = v.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -12,6 +12,8 @@ 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/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,9 +52,9 @@ func EvalStringV(source string, args []Arg) (result any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("invalid function specification: %q", arg.Name)
|
err = fmt.Errorf("invalid function specification: %q", arg.Name)
|
||||||
}
|
}
|
||||||
} else if integer, ok := kern.AnyInteger(arg.Value); ok {
|
} else if integer, ok := types.AnyInteger(arg.Value); ok {
|
||||||
ctx.SetVar(arg.Name, integer)
|
ctx.SetVar(arg.Name, integer)
|
||||||
} else if float, ok := kern.AnyFloat(arg.Value); ok {
|
} else if float, ok := float.AnyFloat(arg.Value); ok {
|
||||||
ctx.SetVar(arg.Name, float)
|
ctx.SetVar(arg.Name, float)
|
||||||
} else if _, ok := arg.Value.(string); ok {
|
} else if _, ok := arg.Value.(string); ok {
|
||||||
ctx.SetVar(arg.Name, arg.Value)
|
ctx.SetVar(arg.Name, arg.Value)
|
||||||
|
|||||||
+2
-1
@@ -13,6 +13,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) {
|
func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) {
|
||||||
if !(kern.IsString(paramValue) /*|| isList(paramValue)*/) {
|
if !(str.IsString(paramValue) /*|| isArray(paramValue)*/) {
|
||||||
err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, kern.TypeName(paramValue))
|
err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, kern.TypeName(paramValue))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
+15
-3
@@ -10,6 +10,8 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IntIterator struct {
|
type IntIterator struct {
|
||||||
@@ -20,6 +22,16 @@ type IntIterator struct {
|
|||||||
step int64
|
step int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewIntIteratorFromInterval(p *interval.IntervalType) (it *IntIterator, err error) {
|
||||||
|
b := p.Begin()
|
||||||
|
e := p.End()
|
||||||
|
s := p.Step()
|
||||||
|
if b > e {
|
||||||
|
s = -s
|
||||||
|
}
|
||||||
|
return NewIntIteratorA(b, e, s)
|
||||||
|
}
|
||||||
|
|
||||||
func NewIntIteratorA(args ...any) (it *IntIterator, err error) {
|
func NewIntIteratorA(args ...any) (it *IntIterator, err error) {
|
||||||
return NewIntIterator(args)
|
return NewIntIterator(args)
|
||||||
}
|
}
|
||||||
@@ -31,16 +43,16 @@ func NewIntIterator(args []any) (it *IntIterator, err error) {
|
|||||||
}
|
}
|
||||||
it = &IntIterator{count: 0, index: -1, start: 0, stop: 0, step: 1}
|
it = &IntIterator{count: 0, index: -1, start: 0, stop: 0, step: 1}
|
||||||
if argc >= 1 {
|
if argc >= 1 {
|
||||||
if it.stop, err = kern.ToGoInt64(args[0], "start index"); err != nil {
|
if it.stop, err = types.ToGoInt64(args[0], "start index"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
it.start = it.stop
|
it.start = it.stop
|
||||||
if it.stop, err = kern.ToGoInt64(args[1], "stop index"); err != nil {
|
if it.stop, err = types.ToGoInt64(args[1], "stop index"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
if it.step, err = kern.ToGoInt64(args[2], "step"); err != nil {
|
if it.step, err = types.ToGoInt64(args[2], "step"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if it.start > it.stop {
|
} else if it.start > it.stop {
|
||||||
|
|||||||
+6
-3
@@ -9,6 +9,9 @@ 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/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewFormalIterator(value any) (it kern.Iterator) {
|
func NewFormalIterator(value any) (it kern.Iterator) {
|
||||||
@@ -26,11 +29,11 @@ func NewIterator(ctx kern.ExprContext, value any, ops []*scan.Term) (it kern.Ite
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case *kern.ListType:
|
case *array.ArrayType:
|
||||||
it = NewListIterator(v, nil)
|
it = NewListIterator(v, nil)
|
||||||
case *kern.LinkedList:
|
case *list.LinkedList:
|
||||||
it = NewLinkedListIterator(v, nil)
|
it = NewLinkedListIterator(v, nil)
|
||||||
case *kern.DictType:
|
case *dict.DictType:
|
||||||
it, err = NewDictIterator(v, nil)
|
it, err = NewDictIterator(v, nil)
|
||||||
case []any:
|
case []any:
|
||||||
it = NewArrayIterator(v)
|
it = NewArrayIterator(v)
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// cloner.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
type Cloner interface {
|
||||||
|
Clone() Cloner
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCloner(v any) (ok bool) {
|
||||||
|
_, ok = v.(Cloner)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clone(a any) (clone any) {
|
||||||
|
if IsCloner(a) {
|
||||||
|
clone = a.(Cloner).Clone()
|
||||||
|
} else {
|
||||||
|
clone = a
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ package kern
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
TypeAny = "any"
|
TypeAny = "any"
|
||||||
|
TypeArray = "array"
|
||||||
TypeNil = "nil"
|
TypeNil = "nil"
|
||||||
TypeBoolean = "boolean"
|
TypeBoolean = "boolean"
|
||||||
TypeFloat = "float"
|
TypeFloat = "float"
|
||||||
@@ -15,7 +16,7 @@ const (
|
|||||||
TypeItem = "item"
|
TypeItem = "item"
|
||||||
TypeIterator = "iterator"
|
TypeIterator = "iterator"
|
||||||
TypeNumber = "number"
|
TypeNumber = "number"
|
||||||
TypePair = "pair"
|
TypeIntPair = "int-pair"
|
||||||
TypeString = "string"
|
TypeString = "string"
|
||||||
TypeDict = "dict"
|
TypeDict = "dict"
|
||||||
TypeListOf = "list-of-"
|
TypeListOf = "list-of-"
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
package kern
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
func Equal(value1, value2 any) (equal bool) {
|
|
||||||
if value1 == nil && value2 == nil {
|
|
||||||
equal = true
|
|
||||||
} else if value1 == nil || value2 == nil {
|
|
||||||
equal = false
|
|
||||||
} else if IsBool(value1) && IsBool(value2) {
|
|
||||||
equal = value1.(bool) == value2.(bool)
|
|
||||||
} else if IsList(value1) && IsList(value2) {
|
|
||||||
ls1 := value1.(*ListType)
|
|
||||||
ls2 := value2.(*ListType)
|
|
||||||
equal = ls1.Equals(*ls2)
|
|
||||||
} else if IsDict(value1) && IsDict(value2) {
|
|
||||||
d1 := value1.(*DictType)
|
|
||||||
d2 := value2.(*DictType)
|
|
||||||
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) {
|
|
||||||
equal = value1.(int64) == value2.(int64)
|
|
||||||
} else if IsString(value1) && IsString(value2) {
|
|
||||||
equal = value1.(string) == value2.(string)
|
|
||||||
} else if IsFloat(value1) && IsFloat(value2) {
|
|
||||||
equal = value1.(float64) == value2.(float64)
|
|
||||||
} else if IsNumOrFract(value1) && IsNumOrFract(value2) {
|
|
||||||
if eq, err := CmpAnyFract(value1, value2); err == nil {
|
|
||||||
equal = eq == 0
|
|
||||||
}
|
|
||||||
} else if !reflect.DeepEqual(value1, value2) {
|
|
||||||
equal = false
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// consts.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
const MaxUint64Allowed = uint64(9_223_372_036_854_775_807)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// equaler.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
type Equaler interface {
|
||||||
|
EqualTo(other Equaler) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsEqualer(v any) (ok bool) {
|
||||||
|
_, ok = v.(Equaler)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Equal(a, b any) (equal bool) {
|
||||||
|
if IsEqualer(a) && IsEqualer(b) {
|
||||||
|
equal = a.(Equaler).EqualTo(b.(Equaler))
|
||||||
|
} else {
|
||||||
|
equal = a == b
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
+1
-30
@@ -29,35 +29,6 @@ type ExprContext interface {
|
|||||||
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)
|
ToDict() (dict any) // must be a *DictType
|
||||||
ToString(opt FmtOpt) string
|
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)
|
|
||||||
}
|
|
||||||
|
|||||||
+4
-23
@@ -21,6 +21,10 @@ const (
|
|||||||
Base16
|
Base16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Formatter interface {
|
||||||
|
ToString(options FmtOpt) string
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TruncateEllipsis = "(...)"
|
TruncateEllipsis = "(...)"
|
||||||
MinTruncateSize = 10
|
MinTruncateSize = 10
|
||||||
@@ -45,10 +49,6 @@ func GetFormatIndent(opt FmtOpt) int {
|
|||||||
return int(opt >> 16)
|
return int(opt >> 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Formatter interface {
|
|
||||||
ToString(options FmtOpt) string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Format(sb *strings.Builder, item any, opt FmtOpt) {
|
func Format(sb *strings.Builder, item any, opt FmtOpt) {
|
||||||
if s, ok := item.(string); ok {
|
if s, ok := item.(string); ok {
|
||||||
sb.WriteByte('"')
|
sb.WriteByte('"')
|
||||||
@@ -73,22 +73,3 @@ func GetFormatted(v any, opt FmtOpt) (text string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Typer interface {
|
|
||||||
TypeName() string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TypeName(v any) (name string) {
|
|
||||||
if v == nil {
|
|
||||||
name = "nil"
|
|
||||||
} else if typer, ok := v.(Typer); ok {
|
|
||||||
name = typer.TypeName()
|
|
||||||
} else if IsInteger(v) {
|
|
||||||
name = "integer"
|
|
||||||
} else if IsFloat(v) {
|
|
||||||
name = "float"
|
|
||||||
} else {
|
|
||||||
name = fmt.Sprintf("%T", v)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// list-type.go
|
|
||||||
package kern
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ListType []any
|
|
||||||
|
|
||||||
func IsList(v any) (ok bool) {
|
|
||||||
_, ok = v.(*ListType)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewListA(listAny ...any) (list *ListType) {
|
|
||||||
if listAny == nil {
|
|
||||||
listAny = []any{}
|
|
||||||
}
|
|
||||||
return NewList(listAny)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewList(listAny []any) (list *ListType) {
|
|
||||||
if listAny != nil {
|
|
||||||
ls := make(ListType, len(listAny))
|
|
||||||
copy(ls, listAny)
|
|
||||||
list = &ls
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeList(length, capacity int) (list *ListType) {
|
|
||||||
if capacity < length {
|
|
||||||
capacity = length
|
|
||||||
}
|
|
||||||
ls := make(ListType, length, capacity)
|
|
||||||
list = &ls
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListFromStrings(stringList []string) (list *ListType) {
|
|
||||||
list = MakeList(len(stringList), 0)
|
|
||||||
for i, s := range stringList {
|
|
||||||
(*list)[i] = s
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) ToString(opt FmtOpt) (s string) {
|
|
||||||
indent := GetFormatIndent(opt)
|
|
||||||
flags := GetFormatFlags(opt)
|
|
||||||
|
|
||||||
var sb strings.Builder
|
|
||||||
sb.WriteByte('[')
|
|
||||||
if len(*ls) > 0 {
|
|
||||||
innerOpt := MakeFormatOptions(flags, indent+1)
|
|
||||||
nest := strings.Repeat(" ", indent+1)
|
|
||||||
|
|
||||||
if flags&MultiLine != 0 {
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
sb.WriteString(nest)
|
|
||||||
}
|
|
||||||
for i, item := range []any(*ls) {
|
|
||||||
if i > 0 {
|
|
||||||
if flags&MultiLine != 0 {
|
|
||||||
sb.WriteString(",\n")
|
|
||||||
sb.WriteString(nest)
|
|
||||||
} else {
|
|
||||||
sb.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Format(&sb, item, innerOpt)
|
|
||||||
}
|
|
||||||
if flags&MultiLine != 0 {
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
sb.WriteString(strings.Repeat(" ", indent))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.WriteByte(']')
|
|
||||||
s = sb.String()
|
|
||||||
if flags&Truncate != 0 && len(s) > TruncateSize {
|
|
||||||
s = TruncateString(s)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) String() string {
|
|
||||||
return ls.ToString(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) TypeName() string {
|
|
||||||
return "list"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) 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 (ls *ListType) Equals(ls2 ListType) (answer bool) {
|
|
||||||
if ls2 != nil && len(*ls) == len(ls2) {
|
|
||||||
answer = true
|
|
||||||
for index, i1 := range *ls {
|
|
||||||
// if !reflect.DeepEqual(i1, ls2[index]) {
|
|
||||||
// answer = false
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
if !Equal(i1, ls2[index]) {
|
|
||||||
answer = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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 err error
|
|
||||||
index = -1
|
|
||||||
for i, item := range *ls {
|
|
||||||
if eq, err = deepSame(item, target, SameContent); err != nil {
|
|
||||||
break
|
|
||||||
} else if eq {
|
|
||||||
index = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func SameContent(a, b any) (same bool, err error) {
|
|
||||||
la, _ := a.(*ListType)
|
|
||||||
lb, _ := b.(*ListType)
|
|
||||||
if len(*la) == len(*lb) {
|
|
||||||
same = true
|
|
||||||
for _, item := range *la {
|
|
||||||
if pos := lb.IndexDeepSameCmp(item); pos < 0 {
|
|
||||||
same = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func deepSame(a, b any, deepCmp DeepFuncTemplate) (eq bool, err error) {
|
|
||||||
if IsNumOrFract(a) && IsNumOrFract(b) {
|
|
||||||
if IsNumber(a) && IsNumber(b) {
|
|
||||||
if IsInteger(a) && IsInteger(b) {
|
|
||||||
li, _ := a.(int64)
|
|
||||||
ri, _ := b.(int64)
|
|
||||||
eq = li == ri
|
|
||||||
} else {
|
|
||||||
eq = NumAsFloat(a) == NumAsFloat(b)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var cmp int
|
|
||||||
if cmp, err = CmpAnyFract(a, b); err == nil {
|
|
||||||
eq = cmp == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if deepCmp != nil && IsList(a) && IsList(b) {
|
|
||||||
eq, err = deepCmp(a, b)
|
|
||||||
} else {
|
|
||||||
eq = reflect.DeepEqual(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) SetItem(index int64, value any) (err error) {
|
|
||||||
if index >= 0 && index < int64(len(*ls)) {
|
|
||||||
(*ls)[index] = value
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*ls)-1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *ListType) AppendItem(value any) {
|
|
||||||
*ls = append(*ls, value)
|
|
||||||
}
|
|
||||||
+12
-1
@@ -6,6 +6,8 @@ package kern
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Term interface {
|
type Term interface {
|
||||||
@@ -15,7 +17,16 @@ type Term interface {
|
|||||||
GetChildCount() (count int)
|
GetChildCount() (count int)
|
||||||
GetChild(index int) Term
|
GetChild(index int) Term
|
||||||
GetChildSource(index int) string
|
GetChildSource(index int) string
|
||||||
Compute(ctx ExprContext) (result any, err error)
|
GetLeftChild() (c Term)
|
||||||
|
GetRightChild() (c Term)
|
||||||
|
Symbol() (symbol sym.Symbol)
|
||||||
|
IsSymbol(symbol sym.Symbol) bool
|
||||||
|
IsOneOf(symbols ...sym.Symbol) bool
|
||||||
IsAssign() bool
|
IsAssign() bool
|
||||||
|
IsVar() bool
|
||||||
|
SetSymbol(symbol sym.Symbol)
|
||||||
|
Compute(ctx ExprContext) (result any, err error)
|
||||||
|
EvalInfix(ctx ExprContext) (leftValue, rightValue any, err error)
|
||||||
Errorf(template string, args ...any) (err error)
|
Errorf(template string, args ...any) (err error)
|
||||||
|
ErrIncompatibleTypes(leftValue, rightValue any) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// typer.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Typer interface {
|
||||||
|
TypeName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TypeName(v any) (name string) {
|
||||||
|
if v == nil {
|
||||||
|
name = "nil"
|
||||||
|
} else if typer, ok := v.(Typer); ok {
|
||||||
|
name = typer.TypeName()
|
||||||
|
} else if _, ok := v.(int64); ok {
|
||||||
|
name = "integer"
|
||||||
|
} else if _, ok := v.(float64); ok {
|
||||||
|
name = "float"
|
||||||
|
} else {
|
||||||
|
name = fmt.Sprintf("%T", v)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// util.go
|
||||||
|
package kern
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -10,16 +10,17 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LinkedListIterator struct {
|
type LinkedListIterator struct {
|
||||||
a *kern.LinkedList
|
a *list.LinkedList
|
||||||
count int64
|
count int64
|
||||||
index int64
|
index int64
|
||||||
current *kern.ListNode
|
current *list.ListNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLinkedListIterator(list *kern.LinkedList, args []any) (it *LinkedListIterator) {
|
func NewLinkedListIterator(list *list.LinkedList, args []any) (it *LinkedListIterator) {
|
||||||
it = &LinkedListIterator{a: list, count: 0, index: -1, current: list.FirstNode()}
|
it = &LinkedListIterator{a: list, count: 0, index: -1, current: list.FirstNode()}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -7,12 +7,16 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- dict term
|
// -------- dict term
|
||||||
func newDictTerm(args map[any]*scan.Term) *scan.Term {
|
func newDictTerm(args map[any]*scan.Term) *scan.Term {
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *scan.NewValueToken(0, 0, scan.SymDict, "{}", args),
|
Tk: *scan.NewValueToken(0, 0, sym.SymDict, "{}", args),
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
Children: nil,
|
Children: nil,
|
||||||
Position: scan.PosLeaf,
|
Position: scan.PosLeaf,
|
||||||
@@ -23,16 +27,16 @@ func newDictTerm(args map[any]*scan.Term) *scan.Term {
|
|||||||
|
|
||||||
// -------- dict func
|
// -------- dict func
|
||||||
func evalDict(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalDict(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
dict, _ := opTerm.Value().(map[any]*scan.Term)
|
dt, _ := opTerm.Value().(map[any]*scan.Term)
|
||||||
items := make(kern.DictType, len(dict))
|
items := make(dict.DictType, len(dt))
|
||||||
for key, tree := range dict {
|
for key, tree := range dt {
|
||||||
var param any
|
var param any
|
||||||
if param, err = tree.Compute(ctx); err != nil {
|
if param, err = tree.Compute(ctx); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var keyValue any
|
var keyValue any
|
||||||
if keyValue, err = (key.(*scan.Term)).Compute(ctx); err == nil {
|
if keyValue, err = (key.(*scan.Term)).Compute(ctx); err == nil {
|
||||||
if kern.IsInteger(keyValue) || kern.IsString(keyValue) {
|
if types.IsInteger(keyValue) || str.IsString(keyValue) {
|
||||||
items[keyValue] = param
|
items[keyValue] = param
|
||||||
} else {
|
} else {
|
||||||
err = key.(*scan.Term).Errorf("dict key can be integer or string, got %s", kern.TypeName(keyValue))
|
err = key.(*scan.Term).Errorf("dict key can be integer or string, got %s", kern.TypeName(keyValue))
|
||||||
|
|||||||
+2
-1
@@ -9,11 +9,12 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- expr term
|
// -------- expr term
|
||||||
func newExprTerm(root *scan.Term) *scan.Term {
|
func newExprTerm(root *scan.Term) *scan.Term {
|
||||||
tk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymExpression, root.Source(), root)
|
tk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), sym.SymExpression, root.Source(), root)
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *tk,
|
Tk: *tk,
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
|
|||||||
+19
-12
@@ -10,12 +10,17 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- iterator term
|
// -------- iterator term
|
||||||
|
|
||||||
func newIteratorTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
|
func newIteratorTerm(tk *scan.Token, args []*scan.Term) *scan.Term {
|
||||||
tk.Sym = scan.SymIterator
|
tk.Sym = sym.SymIterator
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *tk,
|
Tk: *tk,
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
@@ -52,7 +57,7 @@ func evalFirstChild(ctx kern.ExprContext, iteratorTerm *scan.Term) (value any, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getDataSourceDict(iteratorTerm *scan.Term, firstChildValue any) (ds map[string]kern.Functor, err error) {
|
func getDataSourceDict(iteratorTerm *scan.Term, firstChildValue any) (ds map[string]kern.Functor, err error) {
|
||||||
if dictAny, ok := firstChildValue.(*kern.DictType); ok {
|
if dictAny, ok := firstChildValue.(*dict.DictType); ok {
|
||||||
requiredFields := []string{kern.NextName}
|
requiredFields := []string{kern.NextName}
|
||||||
fieldsMask := 0b1
|
fieldsMask := 0b1
|
||||||
foundFields := 0
|
foundFields := 0
|
||||||
@@ -123,7 +128,7 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
v = dc
|
v = dc
|
||||||
} else {
|
} else {
|
||||||
if dictIt, ok := firstChildValue.(*kern.DictType); ok {
|
if dictIt, ok := firstChildValue.(*dict.DictType); ok {
|
||||||
var args []any
|
var args []any
|
||||||
if args, err = evalSiblings(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)
|
||||||
@@ -132,21 +137,23 @@ func evalIterator(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
err = opTerm.Children[0].Errorf("the data-source must be a dictionary")
|
err = opTerm.Children[0].Errorf("the data-source must be a dictionary")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if list, ok := firstChildValue.(*kern.ListType); ok {
|
} else if a, ok := firstChildValue.(*array.ArrayType); ok {
|
||||||
var args []any
|
var args []any
|
||||||
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
|
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
|
||||||
v = NewListIterator(list, args)
|
v = NewListIterator(a, args)
|
||||||
}
|
}
|
||||||
} else if list, ok := firstChildValue.(*kern.LinkedList); ok {
|
} else if ll, ok := firstChildValue.(*list.LinkedList); ok {
|
||||||
var args []any
|
var args []any
|
||||||
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
|
if args, err = evalSiblings(ctx, opTerm.Children, nil); err == nil {
|
||||||
v = NewLinkedListIterator(list, args)
|
v = NewLinkedListIterator(ll, args)
|
||||||
}
|
|
||||||
} else if intVal, ok := firstChildValue.(int64); ok {
|
|
||||||
var args []any
|
|
||||||
if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil {
|
|
||||||
v, err = NewIntIterator(args)
|
|
||||||
}
|
}
|
||||||
|
} else if intervalVal, ok := firstChildValue.(*interval.IntervalType); ok {
|
||||||
|
v, err = NewIntIteratorFromInterval(intervalVal)
|
||||||
|
// } else if intVal, ok := firstChildValue.(int64); ok {
|
||||||
|
// var args []any
|
||||||
|
// if args, err = evalSiblings(ctx, opTerm.Children, intVal); err == nil {
|
||||||
|
// v, err = NewIntIterator(args)
|
||||||
|
// }
|
||||||
} else if it, ok := firstChildValue.(kern.Iterator); ok {
|
} else if it, ok := firstChildValue.(kern.Iterator); ok {
|
||||||
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- list term
|
// -------- list term
|
||||||
@@ -16,7 +18,7 @@ import (
|
|||||||
|
|
||||||
func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term {
|
func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term {
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *scan.NewValueToken(row, col, scan.SymLinkedList, "[<>]", args),
|
Tk: *scan.NewValueToken(row, col, sym.SymLinkedList, "[<>]", args),
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
Children: nil,
|
Children: nil,
|
||||||
Position: scan.PosLeaf,
|
Position: scan.PosLeaf,
|
||||||
@@ -27,9 +29,9 @@ func newLinkedListTerm(row, col int, args []*scan.Term) *scan.Term {
|
|||||||
|
|
||||||
// -------- list func
|
// -------- list func
|
||||||
func evalLinkedList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalLinkedList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
list, _ := opTerm.Value().([]*scan.Term)
|
listTerm, _ := opTerm.Value().([]*scan.Term)
|
||||||
items := kern.NewLinkedList()
|
items := list.NewLinkedList()
|
||||||
for _, tree := range list {
|
for _, tree := range listTerm {
|
||||||
var param any
|
var param any
|
||||||
if param, err = tree.Compute(ctx); err != nil {
|
if param, err = tree.Compute(ctx); err != nil {
|
||||||
break
|
break
|
||||||
|
|||||||
+4
-2
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- list term
|
// -------- list term
|
||||||
@@ -16,7 +18,7 @@ func newListTermA(args ...*scan.Term) *scan.Term {
|
|||||||
|
|
||||||
func newListTerm(row, col int, args []*scan.Term) *scan.Term {
|
func newListTerm(row, col int, args []*scan.Term) *scan.Term {
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *scan.NewValueToken(row, col, scan.SymList, "[]", args),
|
Tk: *scan.NewValueToken(row, col, sym.SymList, "[]", args),
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
Children: nil,
|
Children: nil,
|
||||||
Position: scan.PosLeaf,
|
Position: scan.PosLeaf,
|
||||||
@@ -28,7 +30,7 @@ func newListTerm(row, col int, args []*scan.Term) *scan.Term {
|
|||||||
// -------- list func
|
// -------- list func
|
||||||
func evalList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalList(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
list, _ := opTerm.Value().([]*scan.Term)
|
list, _ := opTerm.Value().([]*scan.Term)
|
||||||
items := make(kern.ListType, len(list))
|
items := make(array.ArrayType, len(list))
|
||||||
for i, tree := range list {
|
for i, tree := range list {
|
||||||
var param any
|
var param any
|
||||||
if param, err = tree.Compute(ctx); err != nil {
|
if param, err = tree.Compute(ctx); err != nil {
|
||||||
|
|||||||
+18
-6
@@ -7,10 +7,22 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- literal term
|
// -------- literal term
|
||||||
func newLiteralTerm(tk *scan.Token) *scan.Term {
|
func newLiteralTerm(tk *scan.Token) *scan.Term {
|
||||||
|
|
||||||
|
if tk.Sym == sym.SymFraction {
|
||||||
|
if v, isString := tk.Value.(string); isString {
|
||||||
|
var err error
|
||||||
|
if tk.Value, err = fract.MakeGeneratingFraction(v); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *tk,
|
Tk: *tk,
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
@@ -29,10 +41,10 @@ func evalLiteral(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymString, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymString, newLiteralTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymInteger, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymInteger, newLiteralTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymFloat, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymFloat, newLiteralTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymFraction, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymFraction, newLiteralTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymBool, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymBool, newLiteralTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymKwNil, newLiteralTerm)
|
scan.RegisterTermConstructor(sym.SymKwNil, newLiteralTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-19
@@ -5,11 +5,9 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- selector case term
|
// -------- selector case term
|
||||||
@@ -19,20 +17,20 @@ type selectorCase struct {
|
|||||||
caseExpr kern.Expr
|
caseExpr kern.Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *selectorCase) String() string {
|
// func (sc *selectorCase) String() string {
|
||||||
var sb strings.Builder
|
// var sb strings.Builder
|
||||||
if sc.filterList != nil {
|
// if sc.filterList != nil {
|
||||||
sc.filterList.ToString(&sb)
|
// sc.filterList.ToString(&sb)
|
||||||
sb.WriteByte(' ')
|
// sb.WriteByte(' ')
|
||||||
}
|
// }
|
||||||
sb.WriteByte('{')
|
// sb.WriteByte('{')
|
||||||
sb.WriteString(sc.caseExpr.String())
|
// sb.WriteString(sc.caseExpr.String())
|
||||||
sb.WriteByte('}')
|
// sb.WriteByte('}')
|
||||||
return sb.String()
|
// return sb.String()
|
||||||
}
|
// }
|
||||||
|
|
||||||
func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr) *scan.Term {
|
func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr) *scan.Term {
|
||||||
tk := scan.NewValueToken(row, col, scan.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
tk := scan.NewValueToken(row, col, sym.SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
||||||
return &scan.Term{
|
return &scan.Term{
|
||||||
Tk: *tk,
|
Tk: *tk,
|
||||||
Parent: nil,
|
Parent: nil,
|
||||||
@@ -45,9 +43,14 @@ func newSelectorCaseTerm(row, col int, filterList *scan.Term, caseExpr kern.Expr
|
|||||||
|
|
||||||
// -------- eval selector case
|
// -------- eval selector case
|
||||||
func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var ok bool
|
v, _ = opTerm.Value().(*selectorCase)
|
||||||
if v, ok = opTerm.Value().(*selectorCase); !ok {
|
|
||||||
err = fmt.Errorf("selector-case expected, got %T", opTerm.Value())
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func evalSelectorCase(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
// var ok bool
|
||||||
|
// if v, ok = opTerm.Value().(*selectorCase); !ok {
|
||||||
|
// err = fmt.Errorf("selector-case expected, got %T", opTerm.Value())
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|||||||
+3
-2
@@ -9,6 +9,7 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- variable term
|
// -------- variable term
|
||||||
@@ -21,7 +22,7 @@ func newVarTerm(tk *scan.Token) *scan.Term {
|
|||||||
Priority: scan.PriValue,
|
Priority: scan.PriValue,
|
||||||
EvalFunc: evalVar,
|
EvalFunc: evalVar,
|
||||||
}
|
}
|
||||||
t.Tk.Sym = scan.SymVariable
|
t.Tk.Sym = sym.SymVariable
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,5 +42,5 @@ func evalVar(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymIdentifier, newVarTerm)
|
scan.RegisterTermConstructor(sym.SymIdentifier, newVarTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-41
@@ -7,6 +7,10 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ func evalDeepCopyAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err err
|
|||||||
|
|
||||||
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 *array.ArrayType
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
|
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
|
||||||
@@ -53,7 +57,7 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
|
|||||||
|
|
||||||
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
|
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
} else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 {
|
} else if keyList, ok = keyListValue.(*array.ArrayType); !ok || len(*keyList) != 1 {
|
||||||
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
|
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -63,14 +67,20 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch collection := collectionValue.(type) {
|
switch collection := collectionValue.(type) {
|
||||||
case *kern.ListType:
|
case *array.ArrayType:
|
||||||
if index, ok := keyValue.(int64); ok {
|
if index, ok := keyValue.(int64); ok {
|
||||||
err = collection.SetItem(index, value)
|
err = collection.SetItem(index, value)
|
||||||
} else {
|
} else {
|
||||||
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
|
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
|
||||||
}
|
}
|
||||||
case *kern.DictType:
|
case *dict.DictType:
|
||||||
collection.SetItem(keyValue, value)
|
collection.SetItem(keyValue, value)
|
||||||
|
case *list.LinkedList:
|
||||||
|
if index, ok := keyValue.(int64); ok {
|
||||||
|
err = collection.SetItem(index, value)
|
||||||
|
} else {
|
||||||
|
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
err = collectionTerm.Errorf("collection expected")
|
err = collectionTerm.Errorf("collection expected")
|
||||||
}
|
}
|
||||||
@@ -78,7 +88,7 @@ func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *sca
|
|||||||
}
|
}
|
||||||
|
|
||||||
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any, deepCopy bool) (err error) {
|
func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any, deepCopy bool) (err error) {
|
||||||
if leftTerm.Symbol() == scan.SymIndex {
|
if leftTerm.Symbol() == sym.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 {
|
if deepCopy {
|
||||||
@@ -92,7 +102,7 @@ func assignValue(ctx kern.ExprContext, leftTerm *scan.Term, v any, deepCopy bool
|
|||||||
func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern.Term) (v any, err error) {
|
func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern.Term) (v any, err error) {
|
||||||
var ok bool
|
var ok bool
|
||||||
var dictAny, dotKey any
|
var dictAny, dotKey any
|
||||||
var dict *kern.DictType
|
var dt *dict.DictType
|
||||||
|
|
||||||
if err = dotTerm.CheckOperands(); err != nil {
|
if err = dotTerm.CheckOperands(); err != nil {
|
||||||
return
|
return
|
||||||
@@ -102,14 +112,14 @@ func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern
|
|||||||
if dictAny, err = dotLeftTerm.Compute(ctx); err != nil {
|
if dictAny, err = dotLeftTerm.Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if dict, ok = dictAny.(*kern.DictType); !ok {
|
if dt, ok = dictAny.(*dict.DictType); !ok {
|
||||||
err = dotTerm.Tk.ErrorExpectedGot(kern.DictTypeName)
|
err = dotTerm.Tk.ErrorExpectedGot(dict.DictTypeName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dotRightTerm := dotTerm.Children[1]
|
dotRightTerm := dotTerm.Children[1]
|
||||||
dotRightSym := dotRightTerm.Symbol()
|
dotRightSym := dotRightTerm.Symbol()
|
||||||
if dotRightSym == scan.SymVariable || dotRightSym == scan.SymString {
|
if dotRightSym == sym.SymVariable || dotRightSym == sym.SymString {
|
||||||
dotKey = util.UnquoteString(dotRightTerm.Source())
|
dotKey = util.UnquoteString(dotRightTerm.Source())
|
||||||
} else if dotKey, err = dotRightTerm.Compute(ctx); err != nil {
|
} else if dotKey, err = dotRightTerm.Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
@@ -119,7 +129,7 @@ func evalAssignDictItem(ctx kern.ExprContext, dotTerm *scan.Term, valueTerm kern
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dict.SetItem(dotKey, v)
|
dt.SetItem(dotKey, v)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,9 +140,9 @@ func generalEvalAssign(ctx kern.ExprContext, opTerm *scan.Term, deepCopy bool) (
|
|||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
leftSym := leftTerm.Symbol()
|
leftSym := leftTerm.Symbol()
|
||||||
if leftSym == scan.SymDot {
|
if leftSym == sym.SymDot {
|
||||||
return evalAssignDictItem(ctx, opTerm.Children[0], opTerm.GetChild(1))
|
return evalAssignDictItem(ctx, opTerm.Children[0], opTerm.GetChild(1))
|
||||||
} else if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
|
} else if leftSym != sym.SymVariable && leftSym != sym.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
|
||||||
}
|
}
|
||||||
@@ -141,7 +151,7 @@ func generalEvalAssign(ctx kern.ExprContext, opTerm *scan.Term, deepCopy bool) (
|
|||||||
|
|
||||||
if v, err = rightChild.Compute(ctx); err == nil {
|
if v, err = rightChild.Compute(ctx); err == nil {
|
||||||
if functor, ok := v.(kern.Functor); ok {
|
if functor, ok := v.(kern.Functor); ok {
|
||||||
if leftSym == scan.SymVariable {
|
if leftSym == sym.SymVariable {
|
||||||
if info := functor.GetFunc(); info != nil {
|
if info := functor.GetFunc(); info != nil {
|
||||||
ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params())
|
ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params())
|
||||||
} else if funcDef, ok := functor.(*exprFunctor); ok {
|
} else if funcDef, ok := functor.(*exprFunctor); ok {
|
||||||
@@ -178,7 +188,7 @@ func newOpAssignTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
|
|
||||||
func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *scan.Term) (value any, err error) {
|
func getCollectionItemValue(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 *array.ArrayType
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
|
if collectionValue, err = collectionTerm.Compute(ctx); err != nil {
|
||||||
@@ -187,7 +197,7 @@ func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *s
|
|||||||
|
|
||||||
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
|
if keyListValue, err = keyListTerm.Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
} else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 {
|
} else if keyList, ok = keyListValue.(*array.ArrayType); !ok || len(*keyList) != 1 {
|
||||||
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
|
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -197,13 +207,13 @@ func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *s
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch collection := collectionValue.(type) {
|
switch collection := collectionValue.(type) {
|
||||||
case *kern.ListType:
|
case *array.ArrayType:
|
||||||
if index, ok := keyValue.(int64); ok {
|
if index, ok := keyValue.(int64); ok {
|
||||||
value = (*collection)[index]
|
value = (*collection)[index]
|
||||||
} else {
|
} else {
|
||||||
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
|
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue))
|
||||||
}
|
}
|
||||||
case *kern.DictType:
|
case *dict.DictType:
|
||||||
value = (*collection)[keyValue]
|
value = (*collection)[keyValue]
|
||||||
default:
|
default:
|
||||||
err = collectionTerm.Errorf("collection expected")
|
err = collectionTerm.Errorf("collection expected")
|
||||||
@@ -212,7 +222,7 @@ func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getAssignValue(ctx kern.ExprContext, leftTerm *scan.Term) (value any, err error) {
|
func getAssignValue(ctx kern.ExprContext, leftTerm *scan.Term) (value any, err error) {
|
||||||
if leftTerm.Symbol() == scan.SymIndex {
|
if leftTerm.Symbol() == sym.SymIndex {
|
||||||
value, err = getCollectionItemValue(ctx, leftTerm.Children[0], leftTerm.Children[1])
|
value, err = getCollectionItemValue(ctx, leftTerm.Children[0], leftTerm.Children[1])
|
||||||
} else {
|
} else {
|
||||||
value, _ = ctx.GetVar(leftTerm.Source())
|
value, _ = ctx.GetVar(leftTerm.Source())
|
||||||
@@ -228,7 +238,7 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
leftSym := leftTerm.Symbol()
|
leftSym := leftTerm.Symbol()
|
||||||
if leftSym != scan.SymVariable && leftSym != scan.SymIndex {
|
if leftSym != sym.SymVariable && leftSym != sym.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
|
||||||
}
|
}
|
||||||
@@ -238,25 +248,25 @@ func evalOpAssign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
if rightValue, err = rightChild.Compute(ctx); err == nil {
|
if rightValue, err = rightChild.Compute(ctx); err == nil {
|
||||||
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
|
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
|
||||||
switch opTerm.Symbol() {
|
switch opTerm.Symbol() {
|
||||||
case scan.SymPlusEqual:
|
case sym.SymPlusEqual:
|
||||||
v, err = sumValues(opTerm, leftValue, rightValue)
|
v, err = sumValues(opTerm, leftValue, rightValue)
|
||||||
case scan.SymMinusEqual:
|
case sym.SymMinusEqual:
|
||||||
v, err = diffValues(opTerm, leftValue, rightValue)
|
v, err = diffValues(opTerm, leftValue, rightValue)
|
||||||
case scan.SymStarEqual:
|
case sym.SymStarEqual:
|
||||||
v, err = mulValues(opTerm, leftValue, rightValue)
|
v, err = mulValues(opTerm, leftValue, rightValue)
|
||||||
case scan.SymSlashEqual:
|
case sym.SymSlashEqual:
|
||||||
v, err = divValues(opTerm, leftValue, rightValue)
|
v, err = divValues(opTerm, leftValue, rightValue)
|
||||||
case scan.SymPercEqual:
|
case sym.SymPercEqual:
|
||||||
v, err = remainderValues(opTerm, leftValue, rightValue)
|
v, err = remainderValues(opTerm, leftValue, rightValue)
|
||||||
case scan.SymAmpersandEqual:
|
case sym.SymAmpersandEqual:
|
||||||
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
|
v, err = bitwiseAnd(opTerm, leftValue, rightValue)
|
||||||
case scan.SymVertBarEqual:
|
case sym.SymVertBarEqual:
|
||||||
v, err = bitwiseOr(opTerm, leftValue, rightValue)
|
v, err = bitwiseOr(opTerm, leftValue, rightValue)
|
||||||
case scan.SymCaretEqual:
|
case sym.SymCaretEqual:
|
||||||
v, err = bitwiseXor(opTerm, leftValue, rightValue)
|
v, err = bitwiseXor(opTerm, leftValue, rightValue)
|
||||||
case scan.SymDoubleLessEqual:
|
case sym.SymDoubleLessEqual:
|
||||||
v, err = bitLeftShift(opTerm, leftValue, rightValue)
|
v, err = bitLeftShift(opTerm, leftValue, rightValue)
|
||||||
case scan.SymDoubleGreaterEqual:
|
case sym.SymDoubleGreaterEqual:
|
||||||
v, err = bitRightShift(opTerm, leftValue, rightValue)
|
v, err = bitRightShift(opTerm, leftValue, rightValue)
|
||||||
default:
|
default:
|
||||||
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
|
err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source())
|
||||||
@@ -271,16 +281,16 @@ 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(sym.SymEqual, newAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymColonEqual, newDeepCopyAssignTerm)
|
scan.RegisterTermConstructor(sym.SymColonEqual, newDeepCopyAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymPlusEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymPlusEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymMinusEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymMinusEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymStarEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymStarEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymSlashEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymSlashEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymPercEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymPercEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleLessEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleLessEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleGreaterEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleGreaterEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymAmpersandEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymAmpersandEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymVertBarEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymVertBarEqual, newOpAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymCaretEqual, newOpAssignTerm)
|
scan.RegisterTermConstructor(sym.SymCaretEqual, newOpAssignTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-at.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------- at term
|
||||||
|
|
||||||
|
func newAtTerm(tk *scan.Token) (inst *scan.Term) {
|
||||||
|
return &scan.Term{
|
||||||
|
Tk: *tk,
|
||||||
|
Children: make([]*scan.Term, 0, 2),
|
||||||
|
Position: scan.PosInfix,
|
||||||
|
Priority: scan.PriRelational,
|
||||||
|
EvalFunc: evalAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func hasKey(d map[any]any, target any) (ok bool) {
|
||||||
|
// _, ok = d[target]
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
func evalAt(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v = int64(-1) // default value if not found
|
||||||
|
if array.IsArray(rightValue) {
|
||||||
|
a, _ := rightValue.(*array.ArrayType)
|
||||||
|
if index := a.IndexDeepSameCmp(leftValue); index >= 0 {
|
||||||
|
v = index
|
||||||
|
}
|
||||||
|
} else if dict.IsDict(rightValue) {
|
||||||
|
dict, _ := rightValue.(*dict.DictType)
|
||||||
|
if k, exists := dict.FindKey(leftValue); exists {
|
||||||
|
v = k
|
||||||
|
} else {
|
||||||
|
v = nil
|
||||||
|
}
|
||||||
|
} else if list.IsLinkedList(rightValue) {
|
||||||
|
ls, _ := rightValue.(*list.LinkedList)
|
||||||
|
if index := ls.Index(leftValue); index >= 0 {
|
||||||
|
v = index
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = nil
|
||||||
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
scan.RegisterTermConstructor(sym.SymKwAt, newAtTerm)
|
||||||
|
}
|
||||||
+7
-5
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- Bitwise NOT term
|
//-------- Bitwise NOT term
|
||||||
@@ -28,7 +30,7 @@ func evalBitwiseNot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsInteger(value) {
|
if types.IsInteger(value) {
|
||||||
i, _ := value.(int64)
|
i, _ := value.(int64)
|
||||||
v = ^i
|
v = ^i
|
||||||
} else {
|
} else {
|
||||||
@@ -152,8 +154,8 @@ func evalBitwiseXor(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error)
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymTilde, newBitwiseNotTerm)
|
scan.RegisterTermConstructor(sym.SymTilde, newBitwiseNotTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymAmpersand, newBitwiseAndTerm)
|
scan.RegisterTermConstructor(sym.SymAmpersand, newBitwiseAndTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymVertBar, newBitwiseOrTerm)
|
scan.RegisterTermConstructor(sym.SymVertBar, newBitwiseOrTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymCaret, newBitwiseXorTerm)
|
scan.RegisterTermConstructor(sym.SymCaret, newBitwiseXorTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-12
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- NOT term
|
//-------- NOT term
|
||||||
@@ -30,7 +32,7 @@ func evalNot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if b, ok := kern.ToBool(rightValue); ok {
|
if b, ok := boolean.ToBool(rightValue); ok {
|
||||||
v = !b
|
v = !b
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatiblePrefixPostfixType(rightValue)
|
err = opTerm.ErrIncompatiblePrefixPostfixType(rightValue)
|
||||||
@@ -68,8 +70,8 @@ func evalAndWithoutShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBool, lok = kern.ToBool(leftValue)
|
leftBool, lok = boolean.ToBool(leftValue)
|
||||||
rightBool, rok = kern.ToBool(rightValue)
|
rightBool, rok = boolean.ToBool(rightValue)
|
||||||
|
|
||||||
if lok && rok {
|
if lok && rok {
|
||||||
v = leftBool && rightBool
|
v = leftBool && rightBool
|
||||||
@@ -90,14 +92,14 @@ func evalAndWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err erro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftBool, lok := kern.ToBool(leftValue); !lok {
|
if leftBool, lok := boolean.ToBool(leftValue); !lok {
|
||||||
// err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", expr.TypeName(leftValue))
|
// err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", expr.TypeName(leftValue))
|
||||||
// return
|
// return
|
||||||
err = self.ErrIncompatibleType(leftValue, "left")
|
err = self.ErrIncompatibleType(leftValue, "left")
|
||||||
} else if !leftBool {
|
} else if !leftBool {
|
||||||
v = false
|
v = false
|
||||||
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
|
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
|
||||||
if rightBool, rok := kern.ToBool(rightValue); rok {
|
if rightBool, rok := boolean.ToBool(rightValue); rok {
|
||||||
v = rightBool
|
v = rightBool
|
||||||
} else {
|
} else {
|
||||||
err = self.ErrIncompatibleTypes(leftValue, rightValue)
|
err = self.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
@@ -136,8 +138,8 @@ func evalOrWithoutShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBool, lok = kern.ToBool(leftValue)
|
leftBool, lok = boolean.ToBool(leftValue)
|
||||||
rightBool, rok = kern.ToBool(rightValue)
|
rightBool, rok = boolean.ToBool(rightValue)
|
||||||
|
|
||||||
if lok && rok {
|
if lok && rok {
|
||||||
v = leftBool || rightBool
|
v = leftBool || rightBool
|
||||||
@@ -158,13 +160,13 @@ func evalOrWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftBool, lok := kern.ToBool(leftValue); !lok {
|
if leftBool, lok := boolean.ToBool(leftValue); !lok {
|
||||||
err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", kern.TypeName(leftValue))
|
err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", kern.TypeName(leftValue))
|
||||||
return
|
return
|
||||||
} else if leftBool {
|
} else if leftBool {
|
||||||
v = true
|
v = true
|
||||||
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
|
} else if rightValue, err = self.Children[1].Compute(ctx); err == nil {
|
||||||
if rightBool, rok := kern.ToBool(rightValue); rok {
|
if rightBool, rok := boolean.ToBool(rightValue); rok {
|
||||||
v = rightBool
|
v = rightBool
|
||||||
} else {
|
} else {
|
||||||
err = self.ErrIncompatibleTypes(leftValue, rightValue)
|
err = self.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
@@ -175,7 +177,7 @@ func evalOrWithShortcut(ctx kern.ExprContext, self *scan.Term) (v any, err error
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymNot, newNotTerm)
|
scan.RegisterTermConstructor(sym.SymNot, newNotTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymAnd, newAndTerm)
|
scan.RegisterTermConstructor(sym.SymAnd, newAndTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymOr, newOrTerm)
|
scan.RegisterTermConstructor(sym.SymOr, newOrTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- builtin term
|
//-------- builtin term
|
||||||
@@ -31,7 +33,7 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
if kern.IsString(childValue) {
|
if str.IsString(childValue) {
|
||||||
module, _ := childValue.(string)
|
module, _ := childValue.(string)
|
||||||
count, err = ImportInContextByGlobPattern(ctx, module)
|
count, err = ImportInContextByGlobPattern(ctx, module)
|
||||||
} else {
|
} else {
|
||||||
@@ -65,5 +67,5 @@ func evalBuiltin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwBuiltin, newBuiltinTerm)
|
scan.RegisterTermConstructor(sym.SymKwBuiltin, newBuiltinTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- but term
|
//-------- but term
|
||||||
@@ -28,5 +29,5 @@ func evalBut(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwBut, newButTerm)
|
scan.RegisterTermConstructor(sym.SymKwBut, newButTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -10,6 +10,7 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- cat term
|
//-------- cat term
|
||||||
@@ -147,5 +148,5 @@ func (it *catIterator) CallOperation(name string, args map[string]any) (v any, e
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwCat, newCatTerm)
|
scan.RegisterTermConstructor(sym.SymKwCat, newCatTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- context term
|
//-------- context term
|
||||||
@@ -29,7 +31,7 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
|||||||
|
|
||||||
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() == sym.SymVariable && opTerm.Children[0].Source() == "global" {
|
||||||
sourceCtx = ctx.GetGlobal()
|
sourceCtx = ctx.GetGlobal()
|
||||||
} else if childValue, err = opTerm.EvalPrefix(ctx); err == nil {
|
} else if childValue, err = opTerm.EvalPrefix(ctx); err == nil {
|
||||||
if dc, ok := childValue.(*dataCursor); ok {
|
if dc, ok := childValue.(*dataCursor); ok {
|
||||||
@@ -48,7 +50,7 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
|||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var item any
|
var item any
|
||||||
values := kern.NewLinkedListA()
|
values := list.NewLinkedListA()
|
||||||
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
values.PushBack(item)
|
values.PushBack(item)
|
||||||
}
|
}
|
||||||
@@ -65,5 +67,5 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleDollar, newContextTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleDollar, newContextTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- export all term
|
//-------- export all term
|
||||||
@@ -28,5 +29,5 @@ func evalExportAll(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleAt, newExportAllTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleAt, newExportAllTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- default term
|
//-------- default term
|
||||||
@@ -29,7 +30,7 @@ func evalDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||||
return
|
return
|
||||||
@@ -63,7 +64,7 @@ func evalAlternate(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||||
return
|
return
|
||||||
@@ -99,7 +100,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
leftTerm := opTerm.Children[0]
|
leftTerm := opTerm.Children[0]
|
||||||
if leftTerm.Tk.Sym != scan.SymVariable {
|
if leftTerm.Tk.Sym != sym.SymVariable {
|
||||||
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm)
|
||||||
return
|
return
|
||||||
@@ -123,7 +124,7 @@ func evalAssignDefault(ctx kern.ExprContext, opTerm *scan.Term) (v any, err erro
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleQuestion, newDefaultTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleQuestion, newDefaultTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymQuestionEqual, newDefaultAssignTerm)
|
scan.RegisterTermConstructor(sym.SymQuestionEqual, newDefaultAssignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymQuestionExclam, newAlternateTerm)
|
scan.RegisterTermConstructor(sym.SymQuestionExclam, newAlternateTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -10,6 +10,7 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- digest term
|
//-------- digest term
|
||||||
@@ -48,9 +49,10 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
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 {
|
||||||
if rightValue == nil {
|
if rightValue == nil {
|
||||||
break
|
err = io.EOF
|
||||||
} else {
|
} else {
|
||||||
lastValue = rightValue
|
lastValue = rightValue
|
||||||
|
ctx.SetVar(kern.ControlLastResult, lastValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.DeleteVar("#")
|
ctx.DeleteVar("#")
|
||||||
@@ -69,5 +71,5 @@ func evalDigest(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwDigest, newDigestTerm)
|
scan.RegisterTermConstructor(sym.SymKwDigest, newDigestTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-20
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +37,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.Symbol() == scan.SymVariable /*|| indexTerm.Tk.Sym == scan.SymString */ {
|
if indexTerm.Symbol() == sym.SymVariable /*|| indexTerm.Tk.Sym == sym.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,22 +48,7 @@ func evalDot(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
err = indexTerm.Tk.ErrorExpectedGot("identifier")
|
err = indexTerm.Tk.ErrorExpectedGot("identifier")
|
||||||
}
|
}
|
||||||
case *kern.DictType:
|
case *dict.DictType:
|
||||||
// var ok bool
|
|
||||||
// s := opTerm.Children[1].Symbol()
|
|
||||||
// if s == scan.SymVariable || s == scan.SymString {
|
|
||||||
// src := opTerm.Children[1].Source()
|
|
||||||
// if len(src) > 1 && src[0] == '"' && src[len(src)-1] == '"' {
|
|
||||||
// src = src[1 : len(src)-1]
|
|
||||||
// }
|
|
||||||
// if v, ok = unboxedValue.GetItem(src); !ok {
|
|
||||||
// err = opTerm.Errorf("key %q not found", src)
|
|
||||||
// }
|
|
||||||
// } else if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
|
||||||
// if v, ok = unboxedValue.GetItem(rightValue); !ok {
|
|
||||||
// err = opTerm.Errorf("key %q not found", rightValue)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
v, err = dotGetDictItemValue(ctx, unboxedValue, opTerm.Children[1])
|
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 {
|
||||||
@@ -71,11 +58,11 @@ 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) {
|
func dotGetDictItemValue(ctx kern.ExprContext, d *dict.DictType, rightTerm *scan.Term) (v any, err error) {
|
||||||
var ok bool
|
var ok bool
|
||||||
var rightValue any
|
var rightValue any
|
||||||
s := rightTerm.Symbol()
|
s := rightTerm.Symbol()
|
||||||
if s == scan.SymVariable || s == scan.SymString {
|
if s == sym.SymVariable || s == sym.SymString {
|
||||||
// src := rightTerm.Source()
|
// src := rightTerm.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]
|
||||||
@@ -101,5 +88,5 @@ func errDictKeyNotFound(term *scan.Term, key any) error {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDot, newDotTerm)
|
scan.RegisterTermConstructor(sym.SymDot, newDotTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- fact term
|
//-------- fact term
|
||||||
@@ -30,7 +32,7 @@ func evalFact(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsInteger(leftValue) {
|
if types.IsInteger(leftValue) {
|
||||||
if i, _ := leftValue.(int64); i >= 0 {
|
if i, _ := leftValue.(int64); i >= 0 {
|
||||||
f := int64(1)
|
f := int64(1)
|
||||||
for k := int64(1); k <= i; k++ {
|
for k := int64(1); k <= i; k++ {
|
||||||
@@ -48,5 +50,5 @@ func evalFact(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymExclamation, newFactTerm)
|
scan.RegisterTermConstructor(sym.SymExclamation, newFactTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- map term
|
//-------- map term
|
||||||
@@ -117,7 +119,7 @@ func (it *filterIterator) Next() (item any, err error) {
|
|||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if success, valid := kern.ToBool(result); valid {
|
if success, valid := boolean.ToBool(result); valid {
|
||||||
if success {
|
if success {
|
||||||
item = attempt
|
item = attempt
|
||||||
break
|
break
|
||||||
@@ -163,5 +165,5 @@ func (it *filterIterator) CallOperation(name string, args map[string]any) (v any
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwFilter, newFilterTerm)
|
scan.RegisterTermConstructor(sym.SymKwFilter, newFilterTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- fraction term
|
// -------- fraction term
|
||||||
@@ -51,7 +53,7 @@ func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
num = -num
|
num = -num
|
||||||
}
|
}
|
||||||
if num != 0 {
|
if num != 0 {
|
||||||
if g := kern.Gcd(num, den); g != 1 {
|
if g := fract.Gcd(num, den); g != 1 {
|
||||||
num = num / g
|
num = num / g
|
||||||
den = den / g
|
den = den / g
|
||||||
}
|
}
|
||||||
@@ -59,11 +61,11 @@ func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
v = num
|
v = num
|
||||||
} else {
|
} else {
|
||||||
// v = &expr.FractionType{num, den}
|
// v = &expr.FractionType{num, den}
|
||||||
v = kern.NewFraction(num, den)
|
v = fract.NewFraction(num, den)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// v = &FractionType{0, den}
|
// v = &FractionType{0, den}
|
||||||
v = kern.NewFraction(0, den)
|
v = fract.NewFraction(0, den)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -71,5 +73,5 @@ func evalFraction(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
// registerTermConstructor(SymVertBar, newFractionTerm)
|
// registerTermConstructor(SymVertBar, newFractionTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymColon, newFractionTerm)
|
scan.RegisterTermConstructor(sym.SymColon, newFractionTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -11,6 +11,10 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- group by term
|
//-------- group by term
|
||||||
@@ -48,17 +52,17 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rightTk := opTerm.Children[1].Tk
|
rightTk := opTerm.Children[1].Tk
|
||||||
if rightTk.IsSymbol(scan.SymVariable) && rightTk.Source() == "__" {
|
if rightTk.IsSymbol(sym.SymVariable) && rightTk.Source() == "__" {
|
||||||
keyByIndex = true
|
keyByIndex = true
|
||||||
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
|
} else if rightValue, err = opTerm.Children[1].Compute(ctx); err != nil {
|
||||||
return
|
return
|
||||||
} else if kern.IsString(rightValue) {
|
} else if str.IsString(rightValue) {
|
||||||
sKey = rightValue.(string)
|
sKey = rightValue.(string)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("right operand of GROUPBY must be a string or identifier '__'; got %s", kern.TypeName(rightValue))
|
return nil, fmt.Errorf("right operand of GROUPBY must be a string or identifier '__'; got %s", kern.TypeName(rightValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
values := kern.MakeDict()
|
values := dict.MakeDict()
|
||||||
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())
|
||||||
@@ -66,7 +70,7 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
var sItemKey string
|
var sItemKey string
|
||||||
|
|
||||||
if d, ok := item.(*kern.DictType); ok {
|
if d, ok := item.(*dict.DictType); ok {
|
||||||
if keyByIndex || len(sKey) == 0 {
|
if keyByIndex || len(sKey) == 0 {
|
||||||
sItemKey = strconv.Itoa(int(it.Index()))
|
sItemKey = strconv.Itoa(int(it.Index()))
|
||||||
} else if d.HasKey(sKey) {
|
} else if d.HasKey(sKey) {
|
||||||
@@ -86,12 +90,12 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
sItemKey = strconv.Itoa(int(it.Index()))
|
sItemKey = strconv.Itoa(int(it.Index()))
|
||||||
}
|
}
|
||||||
|
|
||||||
var ls *kern.ListType
|
var ls *array.ArrayType
|
||||||
if lsAny, exists := values.GetItem(sItemKey); exists && lsAny != nil {
|
if lsAny, exists := values.GetItem(sItemKey); exists && lsAny != nil {
|
||||||
ls = lsAny.(*kern.ListType)
|
ls = lsAny.(*array.ArrayType)
|
||||||
}
|
}
|
||||||
if ls == nil {
|
if ls == nil {
|
||||||
ls = kern.NewListA()
|
ls = array.NewArrayA()
|
||||||
}
|
}
|
||||||
ls.AppendItem(item)
|
ls.AppendItem(item)
|
||||||
values.SetItem(sItemKey, ls)
|
values.SetItem(sItemKey, ls)
|
||||||
@@ -109,5 +113,5 @@ func evalGroupBy(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwGroupBy, newGroupByTerm)
|
scan.RegisterTermConstructor(sym.SymKwGroupBy, newGroupByTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-6
@@ -7,6 +7,10 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- in term
|
//-------- in term
|
||||||
@@ -33,12 +37,15 @@ func evalIn(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsList(rightValue) {
|
if array.IsArray(rightValue) {
|
||||||
list, _ := rightValue.(*kern.ListType)
|
a, _ := rightValue.(*array.ArrayType)
|
||||||
v = list.IndexDeepSameCmp(leftValue) >= 0
|
v = a.IndexDeepSameCmp(leftValue) >= 0
|
||||||
} else if kern.IsDict(rightValue) {
|
} else if dict.IsDict(rightValue) {
|
||||||
dict, _ := rightValue.(*kern.DictType)
|
dict, _ := rightValue.(*dict.DictType)
|
||||||
v = dict.HasKey(leftValue)
|
v = dict.HasKey(leftValue)
|
||||||
|
} else if list.IsLinkedList(rightValue) {
|
||||||
|
ls, _ := rightValue.(*list.LinkedList)
|
||||||
|
v = ls.HasValue(leftValue)
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -47,5 +54,5 @@ func evalIn(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwIn, newInTerm)
|
scan.RegisterTermConstructor(sym.SymKwIn, newInTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -7,6 +7,9 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- include term
|
//-------- include term
|
||||||
@@ -29,9 +32,9 @@ func evalInclude(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
if kern.IsList(childValue) {
|
if array.IsArray(childValue) {
|
||||||
list, _ := childValue.(*kern.ListType)
|
a, _ := childValue.(*array.ArrayType)
|
||||||
for i, filePathSpec := range *list {
|
for i, filePathSpec := range *a {
|
||||||
if filePath, ok := filePathSpec.(string); ok {
|
if filePath, ok := filePathSpec.(string); ok {
|
||||||
if v, err = EvalFile(ctx, filePath); err == nil {
|
if v, err = EvalFile(ctx, filePath); err == nil {
|
||||||
count++
|
count++
|
||||||
@@ -44,7 +47,7 @@ func evalInclude(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if kern.IsString(childValue) {
|
} else if str.IsString(childValue) {
|
||||||
filePath, _ := childValue.(string)
|
filePath, _ := childValue.(string)
|
||||||
if v, err = EvalFile(ctx, filePath); err == nil {
|
if v, err = EvalFile(ctx, filePath); err == nil {
|
||||||
count++
|
count++
|
||||||
@@ -61,5 +64,5 @@ func evalInclude(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwInclude, newIncludeTerm)
|
scan.RegisterTermConstructor(sym.SymKwInclude, newIncludeTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+163
-75
@@ -5,8 +5,16 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- index term
|
// -------- index term
|
||||||
@@ -20,15 +28,15 @@ func newIndexTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyKey(indexList *kern.ListType) (index any, err error) {
|
func verifyKey(indexList *array.ArrayType) (index any, err error) {
|
||||||
index = (*indexList)[0]
|
index = (*indexList)[0]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyIndex(indexTerm *scan.Term, indexList *kern.ListType, maxValue int) (index int, err error) {
|
func verifyIndex(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (index int64, err error) {
|
||||||
var v int
|
var v int64
|
||||||
|
|
||||||
if v, err = kern.ToGoInt((*indexList)[0], "index expression"); err == nil {
|
if v, err = types.ToGoInt64((*indexList)[0], "index expression"); err == nil {
|
||||||
if v < 0 && v >= -maxValue {
|
if v < 0 && v >= -maxValue {
|
||||||
v = maxValue + v
|
v = maxValue + v
|
||||||
}
|
}
|
||||||
@@ -41,32 +49,32 @@ func verifyIndex(indexTerm *scan.Term, indexList *kern.ListType, maxValue int) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyRange(indexTerm *scan.Term, indexList *kern.ListType, maxValue int) (startIndex, endIndex int, err error) {
|
// func verifyInterval(indexTerm kern.Term, indexList *array.ArrayType, maxValue int64) (startIndex, endIndex int64, err error) {
|
||||||
v, _ := ((*indexList)[0]).(*intPair)
|
// v, _ := ((*indexList)[0]).(*interval.IntervalType)
|
||||||
startIndex = v.a
|
// startIndex = v.Begin()
|
||||||
endIndex = v.b
|
// endIndex = v.End()
|
||||||
if endIndex == kern.ConstLastIndex {
|
// if endIndex == kern.ConstLastIndex {
|
||||||
endIndex = maxValue
|
// endIndex = int64(maxValue)
|
||||||
}
|
// }
|
||||||
if startIndex < 0 && startIndex >= -maxValue {
|
// if startIndex < 0 && startIndex >= -maxValue {
|
||||||
startIndex = maxValue + startIndex
|
// startIndex = int64(maxValue) + startIndex
|
||||||
}
|
// }
|
||||||
if endIndex < 0 && endIndex >= -maxValue {
|
// if endIndex < 0 && endIndex >= -maxValue {
|
||||||
endIndex = maxValue + endIndex
|
// endIndex = int64(maxValue) + endIndex
|
||||||
}
|
// }
|
||||||
if startIndex < 0 || startIndex > maxValue {
|
// if startIndex < 0 || startIndex > maxValue {
|
||||||
err = indexTerm.Errorf("range start-index %d is out of bounds", startIndex)
|
// err = indexTerm.Errorf("%s start-index %d is out of bounds", interval.TypeName, startIndex)
|
||||||
} else if endIndex < 0 || endIndex > maxValue {
|
// } else if endIndex < 0 || endIndex > maxValue {
|
||||||
err = indexTerm.Errorf("range end-index %d is out of bounds", endIndex)
|
// err = indexTerm.Errorf("%s end-index %d is out of bounds", interval.TypeName, endIndex)
|
||||||
} else if startIndex > endIndex {
|
// } else if startIndex > endIndex {
|
||||||
err = indexTerm.Errorf("range start-index %d must not be greater than end-index %d", startIndex, endIndex)
|
// err = indexTerm.Errorf("%s start-index %d must not be greater than end-index %d", interval.TypeName, startIndex, endIndex)
|
||||||
}
|
// }
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
var leftValue, rightValue any
|
||||||
var indexList *kern.ListType
|
var indexList *array.ArrayType
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
|
if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
|
||||||
@@ -74,7 +82,7 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
indexTerm := opTerm.Children[1]
|
indexTerm := opTerm.Children[1]
|
||||||
if indexList, ok = rightValue.(*kern.ListType); !ok {
|
if indexList, ok = rightValue.(*array.ArrayType); !ok {
|
||||||
err = opTerm.Errorf("invalid index expression")
|
err = opTerm.Errorf("invalid index expression")
|
||||||
return
|
return
|
||||||
} else if len(*indexList) != 1 {
|
} else if len(*indexList) != 1 {
|
||||||
@@ -82,51 +90,12 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsInteger((*indexList)[0]) {
|
if types.IsInteger((*indexList)[0]) {
|
||||||
switch unboxedValue := leftValue.(type) {
|
v, err = collectionItemByIndex(opTerm, leftValue, rightValue, indexList)
|
||||||
case *kern.ListType:
|
} else if interval.IsInterval((*indexList)[0]) {
|
||||||
var index int
|
v, err = subCollectionByIndex(opTerm, leftValue, rightValue, indexList)
|
||||||
if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil {
|
} else if dict.IsDict(leftValue) {
|
||||||
v = (*unboxedValue)[index]
|
d := leftValue.(*dict.DictType)
|
||||||
}
|
|
||||||
case *kern.LinkedList:
|
|
||||||
var index int
|
|
||||||
if index, err = verifyIndex(indexTerm, indexList, unboxedValue.Len()); err == nil {
|
|
||||||
v, err = unboxedValue.At(index)
|
|
||||||
}
|
|
||||||
case string:
|
|
||||||
var index int
|
|
||||||
if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil {
|
|
||||||
v = string(unboxedValue[index])
|
|
||||||
}
|
|
||||||
case *kern.DictType:
|
|
||||||
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
|
||||||
default:
|
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
|
||||||
}
|
|
||||||
} else if isIntPair((*indexList)[0]) {
|
|
||||||
switch unboxedValue := leftValue.(type) {
|
|
||||||
case *kern.ListType:
|
|
||||||
var start, end int
|
|
||||||
if start, end, err = verifyRange(indexTerm, indexList, len(*unboxedValue)); err == nil {
|
|
||||||
sublist := kern.ListType((*unboxedValue)[start:end])
|
|
||||||
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:
|
|
||||||
var start, end int
|
|
||||||
if start, end, err = verifyRange(indexTerm, indexList, len(unboxedValue)); err == nil {
|
|
||||||
v = unboxedValue[start:end]
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
|
||||||
}
|
|
||||||
} else if kern.IsDict(leftValue) {
|
|
||||||
d := leftValue.(*kern.DictType)
|
|
||||||
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
||||||
} else {
|
} else {
|
||||||
rightChild := opTerm.Children[1]
|
rightChild := opTerm.Children[1]
|
||||||
@@ -135,7 +104,126 @@ func evalIndex(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDictItem(d *kern.DictType, indexTerm *scan.Term, indexList *kern.ListType, rightValue any) (v any, err error) {
|
func collectionItemByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||||
|
indexTerm := opTerm.GetChild(1)
|
||||||
|
switch unboxedValue := leftValue.(type) {
|
||||||
|
case *array.ArrayType:
|
||||||
|
var index int64
|
||||||
|
if index, err = verifyIndex(indexTerm, indexList, int64(len(*unboxedValue))); err == nil {
|
||||||
|
v = (*unboxedValue)[index]
|
||||||
|
}
|
||||||
|
case *list.LinkedList:
|
||||||
|
var index int64
|
||||||
|
if index, err = verifyIndex(indexTerm, indexList, int64(unboxedValue.Len())); err == nil {
|
||||||
|
v, err = unboxedValue.At(index)
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
var index int64
|
||||||
|
if index, err = verifyIndex(indexTerm, indexList, int64(len(unboxedValue))); err == nil {
|
||||||
|
v = string(unboxedValue[index])
|
||||||
|
}
|
||||||
|
case *dict.DictType:
|
||||||
|
v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
|
||||||
|
default:
|
||||||
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func subCollectionByIndex(opTerm kern.Term, leftValue, rightValue any, indexList *array.ArrayType) (v any, err error) {
|
||||||
|
triple := (*indexList)[0].(*interval.IntervalType)
|
||||||
|
switch unboxedValue := leftValue.(type) {
|
||||||
|
case *array.ArrayType:
|
||||||
|
v = intervalSubArray(unboxedValue, triple)
|
||||||
|
case *list.LinkedList:
|
||||||
|
v = intervalSubLinkedList(unboxedValue, triple)
|
||||||
|
case string:
|
||||||
|
v = intervalSubString(unboxedValue, triple)
|
||||||
|
default:
|
||||||
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixInterval(p *interval.IntervalType, maxLength int) (b, e, s int) {
|
||||||
|
b, e, s = p.ToIntTriple()
|
||||||
|
if b < 0 {
|
||||||
|
b = maxLength + b
|
||||||
|
}
|
||||||
|
if e < 0 {
|
||||||
|
e = maxLength + e //+ 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func intervalSubString(source string, p *interval.IntervalType) (result string) {
|
||||||
|
b, e, s := fixInterval(p, len(source))
|
||||||
|
if b <= e {
|
||||||
|
e = min(e, len(source))
|
||||||
|
if s == 1 {
|
||||||
|
result = source[b:e]
|
||||||
|
} else {
|
||||||
|
var sb strings.Builder
|
||||||
|
for i := b; i < e; i += s {
|
||||||
|
sb.WriteByte(source[i])
|
||||||
|
}
|
||||||
|
result = sb.String()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var sb strings.Builder
|
||||||
|
for i := b; i >= e; i -= s {
|
||||||
|
sb.WriteByte(source[i])
|
||||||
|
}
|
||||||
|
result = sb.String()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func intervalSubArray(source *array.ArrayType, p *interval.IntervalType) (result *array.ArrayType) {
|
||||||
|
var a array.ArrayType
|
||||||
|
b, e, s := fixInterval(p, len(*source))
|
||||||
|
if b <= e {
|
||||||
|
e = min(e, len(*source))
|
||||||
|
if s == 1 {
|
||||||
|
a = (*source)[b:e]
|
||||||
|
} else {
|
||||||
|
size := (e-b)/s + 1
|
||||||
|
a = make(array.ArrayType, 0, size)
|
||||||
|
for i := b; i < e; i += s {
|
||||||
|
a = append(a, (*source)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size := (b-e)/s + 1
|
||||||
|
a = make(array.ArrayType, 0, size)
|
||||||
|
for i := b; i > e; i -= s {
|
||||||
|
a = append(a, (*source)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = &a
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func intervalSubLinkedList(source *list.LinkedList, p *interval.IntervalType) (result *list.LinkedList) {
|
||||||
|
b, e, s := fixInterval(p, source.Len())
|
||||||
|
revert := b > e
|
||||||
|
if revert {
|
||||||
|
b, e = e, b
|
||||||
|
source = source.Revert()
|
||||||
|
}
|
||||||
|
e = min(e, source.Len())
|
||||||
|
if s == 1 {
|
||||||
|
result = source.Sub(int64(b), int64(e))
|
||||||
|
} else {
|
||||||
|
result = source.SubStep(int64(b), int64(e), int64(s))
|
||||||
|
}
|
||||||
|
if revert {
|
||||||
|
source = source.Revert()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDictItem(d *dict.DictType, indexTerm kern.Term, indexList *array.ArrayType, rightValue any) (v any, err error) {
|
||||||
var ok bool
|
var ok bool
|
||||||
var indexValue any
|
var indexValue any
|
||||||
|
|
||||||
@@ -149,5 +237,5 @@ func getDictItem(d *kern.DictType, indexTerm *scan.Term, indexList *kern.ListTyp
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymIndex, newIndexTerm)
|
scan.RegisterTermConstructor(sym.SymIndex, newIndexTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-44
@@ -7,6 +7,9 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- prepend term
|
//-------- prepend term
|
||||||
@@ -31,34 +34,38 @@ func newAppendTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prependToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
func prependToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
if list, ok := rightValue.(*kern.ListType); ok {
|
if a, ok := rightValue.(*array.ArrayType); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = leftValue.(kern.Iterator); !ok {
|
if it, ok = leftValue.(kern.Iterator); !ok {
|
||||||
it = NewFormalIterator(leftValue)
|
it = NewFormalIterator(leftValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := kern.NewLinkedList()
|
ls := list.NewLinkedList()
|
||||||
ls.SeqPushBack(it)
|
ls.SeqPushBack(it)
|
||||||
|
|
||||||
newList := kern.ListType(nil)
|
newArray := array.ArrayType(nil)
|
||||||
if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) {
|
if newSize := len(*a) + int(ls.Len()); newSize > cap(*a) {
|
||||||
newList = make([]any, 0, newSize)
|
newArray = make([]any, 0, newSize)
|
||||||
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
||||||
newList = append(newList, node.Data())
|
newArray = append(newArray, node.Data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, item := range *list {
|
for _, item := range *a {
|
||||||
newList = append(newList, item)
|
newArray = append(newArray, item)
|
||||||
}
|
}
|
||||||
result = &newList
|
if opTerm.GetRightChild().IsVar() {
|
||||||
} else if list, ok := rightValue.(*kern.LinkedList); ok {
|
// Update the original array if the right operand is a variable
|
||||||
|
*a = newArray
|
||||||
|
}
|
||||||
|
result = &newArray
|
||||||
|
} else if ll, ok := rightValue.(*list.LinkedList); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = leftValue.(kern.Iterator); !ok {
|
if it, ok = leftValue.(kern.Iterator); !ok {
|
||||||
it = NewFormalIterator(leftValue)
|
it = NewFormalIterator(leftValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = list.SeqPushBack(it)
|
result = ll.SeqPushBack(it)
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -76,34 +83,38 @@ func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
|
func appendToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) {
|
||||||
if list, ok := leftValue.(*kern.ListType); ok {
|
if a, ok := leftValue.(*array.ArrayType); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = rightValue.(kern.Iterator); !ok {
|
if it, ok = rightValue.(kern.Iterator); !ok {
|
||||||
it = NewFormalIterator(rightValue)
|
it = NewFormalIterator(rightValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := kern.NewLinkedList()
|
ls := list.NewLinkedList()
|
||||||
ls.SeqPushBack(it)
|
ls.SeqPushBack(it)
|
||||||
|
|
||||||
newList := *list
|
newArray := *a
|
||||||
if newSize := len(*list) + int(ls.Len()); newSize > cap(*list) {
|
if newSize := len(*a) + int(ls.Len()); newSize > cap(*a) {
|
||||||
newList = make([]any, 0, newSize)
|
newArray = make([]any, 0, newSize)
|
||||||
for _, item := range *list {
|
for _, item := range *a {
|
||||||
newList = append(newList, item)
|
newArray = append(newArray, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
for node := ls.FirstNode(); node != nil; node = node.Next() {
|
||||||
newList = append(newList, node.Data())
|
newArray = append(newArray, node.Data())
|
||||||
}
|
}
|
||||||
result = &newList
|
if opTerm.GetLeftChild().IsVar() {
|
||||||
} else if list, ok := leftValue.(*kern.LinkedList); ok {
|
// Update the original array if the left operand is a variable
|
||||||
|
*a = newArray
|
||||||
|
}
|
||||||
|
result = &newArray
|
||||||
|
} else if ll, ok := leftValue.(*list.LinkedList); ok {
|
||||||
var it kern.Iterator
|
var it kern.Iterator
|
||||||
if it, ok = rightValue.(kern.Iterator); !ok {
|
if it, ok = rightValue.(kern.Iterator); !ok {
|
||||||
it = NewFormalIterator(rightValue)
|
it = NewFormalIterator(rightValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = list.SeqPushBack(it)
|
result = ll.SeqPushBack(it)
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -122,26 +133,8 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func evalAssignAppend(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
// var leftValue, rightValue any
|
|
||||||
|
|
||||||
// if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if IsList(leftValue) {
|
|
||||||
// list, _ := leftValue.(*ListType)
|
|
||||||
// newList := append(*list, rightValue)
|
|
||||||
// v = &newList
|
|
||||||
// if
|
|
||||||
// } else {
|
|
||||||
// err = self.errIncompatibleTypes(leftValue, rightValue)
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymPlusGreater, newPrependTerm)
|
scan.RegisterTermConstructor(sym.SymPlusGreater, newPrependTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymLessPlus, newAppendTerm)
|
scan.RegisterTermConstructor(sym.SymLessPlus, newAppendTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-interval.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/interval"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------- interval term
|
||||||
|
|
||||||
|
func newIntervalTerm(tk *scan.Token) (inst *scan.Term) {
|
||||||
|
return &scan.Term{
|
||||||
|
Tk: *tk,
|
||||||
|
Children: make([]*scan.Term, 0, 2),
|
||||||
|
Position: scan.PosInfix,
|
||||||
|
Priority: scan.PriInterval,
|
||||||
|
EvalFunc: evalInterval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeColonToInterval(t *scan.Term) {
|
||||||
|
if t.IsSymbol(sym.SymDoubleDot) {
|
||||||
|
t.SetSymbol(sym.SymInterval)
|
||||||
|
t.EvalFunc = evalInterval
|
||||||
|
if child := t.GetLeftChild(); child != nil && child.IsSymbol(sym.SymDoubleDot) {
|
||||||
|
child.SetSymbol(sym.SymInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalInterval(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
|
var begin, end int64
|
||||||
|
|
||||||
|
step := int64(1)
|
||||||
|
switch opTerm.GetChildCount() {
|
||||||
|
case 0:
|
||||||
|
begin = 0
|
||||||
|
end = int64(kern.ConstLastIndex)
|
||||||
|
case 1:
|
||||||
|
var leftValue any
|
||||||
|
if leftValue, err = opTerm.GetChild(0).Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if begin, err = checkIntervalComponent(opTerm, leftValue); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
end = int64(kern.ConstLastIndex)
|
||||||
|
default:
|
||||||
|
var beginValue, endValue, stepValue any
|
||||||
|
subTerm := opTerm.GetLeftChild()
|
||||||
|
if subTerm.IsOneOf(sym.SymInterval, sym.SymDoubleDot) {
|
||||||
|
if beginValue, endValue, err = subTerm.EvalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if stepValue, err = opTerm.GetRightChild().Compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
step, err = checkIntervalComponent(opTerm.GetRightChild(), stepValue)
|
||||||
|
} else if beginValue, endValue, err = opTerm.EvalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if begin, err = checkIntervalComponent(opTerm, beginValue); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if end, err = checkIntervalComponent(opTerm, endValue); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if step <= 0 {
|
||||||
|
err = opTerm.Errorf("invalid %s specification: step must be positive", interval.TypeName)
|
||||||
|
} else {
|
||||||
|
v = interval.NewInterval(begin, end, step)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkIntervalComponent(t kern.Term, value any) (component int64, err error) {
|
||||||
|
if component, err = types.ToGoInt64(value, "%s expression"); err != nil {
|
||||||
|
err = t.Errorf(err.Error(), interval.TypeName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func errIntervalInvalidSpecification(t kern.Term) error {
|
||||||
|
// return t.Errorf("invalid %s specification", interval.TypeName)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func errIntervalUnexpectedExpression(t *scan.Term) error {
|
||||||
|
return t.Errorf("unexpected %s expression", interval.TypeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
scan.RegisterTermConstructor(sym.SymInterval, newIntervalTerm)
|
||||||
|
scan.RegisterTermConstructor(sym.SymDoubleDot, newIntervalTerm)
|
||||||
|
}
|
||||||
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- iter value term
|
//-------- iter value term
|
||||||
@@ -39,5 +40,5 @@ func evalIterValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
|
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDereference, newIterValueTerm)
|
scan.RegisterTermConstructor(sym.SymDereference, newIterValueTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-13
@@ -7,6 +7,11 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- length term
|
//-------- length term
|
||||||
@@ -28,25 +33,19 @@ func evalLength(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsList(childValue) {
|
if array.IsArray(childValue) {
|
||||||
ls, _ := childValue.(*kern.ListType)
|
ls, _ := childValue.(*array.ArrayType)
|
||||||
v = int64(len(*ls))
|
v = int64(len(*ls))
|
||||||
} else if kern.IsString(childValue) {
|
} else if str.IsString(childValue) {
|
||||||
s, _ := childValue.(string)
|
s, _ := childValue.(string)
|
||||||
v = int64(len(s))
|
v = int64(len(s))
|
||||||
} else if kern.IsDict(childValue) {
|
} else if dict.IsDict(childValue) {
|
||||||
m, _ := childValue.(*kern.DictType)
|
m, _ := childValue.(*dict.DictType)
|
||||||
v = int64(len(*m))
|
v = int64(len(*m))
|
||||||
} else if lls, ok := childValue.(*kern.LinkedList); ok {
|
} else if lls, ok := childValue.(*list.LinkedList); ok {
|
||||||
v = int64(lls.Len())
|
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) {
|
|
||||||
// count, _ := extIt.CallOperation(CountName, nil)
|
|
||||||
// v, _ = ToGoInt(count, "")
|
|
||||||
// } else {
|
|
||||||
// v = int64(it.Index() + 1)
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
|
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
|
||||||
}
|
}
|
||||||
@@ -55,5 +54,5 @@ func evalLength(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymHash, newLengthTerm)
|
scan.RegisterTermConstructor(sym.SymHash, newLengthTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-22
@@ -9,6 +9,7 @@ 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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- map term
|
//-------- map term
|
||||||
@@ -44,32 +45,11 @@ func evalMap(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// values := kern.NewListA()
|
|
||||||
// for item, err = it.Next(); err == nil; item, err = it.Next() {
|
|
||||||
// ctx.SetVar("_", item)
|
|
||||||
// ctx.SetVar("__", it.Index())
|
|
||||||
// ctx.SetVar("_#", it.Count())
|
|
||||||
// if rightValue, err = opTerm.Children[1].Compute(ctx); err == nil {
|
|
||||||
// values.AppendItem(rightValue)
|
|
||||||
// }
|
|
||||||
// ctx.DeleteVar("_#")
|
|
||||||
// ctx.DeleteVar("__")
|
|
||||||
// ctx.DeleteVar("_")
|
|
||||||
// if err != nil {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if err == io.EOF {
|
|
||||||
// err = nil
|
|
||||||
// }
|
|
||||||
// if err == nil {
|
|
||||||
// v = values
|
|
||||||
// }
|
|
||||||
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
v, err = NewIterIter(it, ctx, opTerm.Children[1:])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwMap, newMapTerm)
|
scan.RegisterTermConstructor(sym.SymKwMap, newMapTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- plugin term
|
//-------- plugin term
|
||||||
@@ -37,5 +38,5 @@ func evalPlugin(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwPlugin, newPluginTerm)
|
scan.RegisterTermConstructor(sym.SymKwPlugin, newPluginTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- post increment term
|
// -------- post increment term
|
||||||
@@ -31,7 +33,7 @@ func evalPostInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
var namePrefix string
|
var namePrefix string
|
||||||
v, err = it.Next()
|
v, err = it.Next()
|
||||||
|
|
||||||
if opTerm.Children[0].Symbol() == scan.SymVariable {
|
if opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||||
namePrefix = opTerm.Children[0].Source()
|
namePrefix = opTerm.Children[0].Source()
|
||||||
}
|
}
|
||||||
ctx.UnsafeSetVar(namePrefix+"_index", it.Index())
|
ctx.UnsafeSetVar(namePrefix+"_index", it.Index())
|
||||||
@@ -49,7 +51,7 @@ func evalPostInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
ctx.UnsafeSetVar(namePrefix+"_value", v1)
|
ctx.UnsafeSetVar(namePrefix+"_value", v1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
} else if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||||
v = childValue
|
v = childValue
|
||||||
i, _ := childValue.(int64)
|
i, _ := childValue.(int64)
|
||||||
ctx.SetVar(opTerm.Children[0].Source(), i+1)
|
ctx.SetVar(opTerm.Children[0].Source(), i+1)
|
||||||
@@ -79,7 +81,7 @@ func evalPostDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
/* if it, ok := childValue.(Iterator); ok {
|
/* if it, ok := childValue.(Iterator); ok {
|
||||||
v, err = it.Next()
|
v, err = it.Next()
|
||||||
} else */if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
} else */if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||||
v = childValue
|
v = childValue
|
||||||
i, _ := childValue.(int64)
|
i, _ := childValue.(int64)
|
||||||
ctx.SetVar(opTerm.Children[0].Source(), i-1)
|
ctx.SetVar(opTerm.Children[0].Source(), i-1)
|
||||||
@@ -91,6 +93,6 @@ func evalPostDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoublePlus, newPostIncTerm)
|
scan.RegisterTermConstructor(sym.SymDoublePlus, newPostIncTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleMinus, newPostDecTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleMinus, newPostDecTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -------- pre increment term
|
// -------- pre increment term
|
||||||
@@ -27,7 +29,7 @@ func evalPreInc(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||||
i := childValue.(int64) + 1
|
i := childValue.(int64) + 1
|
||||||
ctx.SetVar(opTerm.Children[0].Source(), i)
|
ctx.SetVar(opTerm.Children[0].Source(), i)
|
||||||
v = i
|
v = i
|
||||||
@@ -56,7 +58,7 @@ func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsInteger(childValue) && opTerm.Children[0].Symbol() == scan.SymVariable {
|
if types.IsInteger(childValue) && opTerm.Children[0].Symbol() == sym.SymVariable {
|
||||||
i := childValue.(int64) - 1
|
i := childValue.(int64) - 1
|
||||||
ctx.SetVar(opTerm.Children[0].Source(), i)
|
ctx.SetVar(opTerm.Children[0].Source(), i)
|
||||||
v = i
|
v = i
|
||||||
@@ -68,6 +70,6 @@ func evalPreDec(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymPreInc, newPreIncTerm)
|
scan.RegisterTermConstructor(sym.SymPreInc, newPreIncTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymPreDec, newPreDecTerm)
|
scan.RegisterTermConstructor(sym.SymPreDec, newPreDecTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-24
@@ -9,6 +9,12 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- multiply term
|
//-------- multiply term
|
||||||
@@ -24,15 +30,15 @@ func newMultiplyTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mulValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func mulValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsString(leftValue) && kern.IsInteger(rightValue) {
|
if str.IsString(leftValue) && types.IsInteger(rightValue) {
|
||||||
s, _ := leftValue.(string)
|
s, _ := leftValue.(string)
|
||||||
n, _ := rightValue.(int64)
|
n, _ := rightValue.(int64)
|
||||||
v = strings.Repeat(s, int(n))
|
v = strings.Repeat(s, int(n))
|
||||||
} else if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
|
} else if types.IsNumOrFract(leftValue) && types.IsNumOrFract(rightValue) {
|
||||||
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
|
if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
|
||||||
v = kern.NumAsFloat(leftValue) * kern.NumAsFloat(rightValue)
|
v = types.NumAsFloat(leftValue) * types.NumAsFloat(rightValue)
|
||||||
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
|
} else if fract.IsFraction(leftValue) || fract.IsFraction(rightValue) {
|
||||||
v, err = kern.MulAnyFract(leftValue, rightValue)
|
v, err = fract.MulAnyFract(leftValue, rightValue)
|
||||||
} else {
|
} else {
|
||||||
leftInt, _ := leftValue.(int64)
|
leftInt, _ := leftValue.(int64)
|
||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
@@ -67,16 +73,16 @@ func newDivideTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func divValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func divValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
|
if types.IsNumOrFract(leftValue) && types.IsNumOrFract(rightValue) {
|
||||||
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
|
if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
|
||||||
d := kern.NumAsFloat(rightValue)
|
d := types.NumAsFloat(rightValue)
|
||||||
if d == 0.0 {
|
if d == 0.0 {
|
||||||
err = opTerm.ErrDivisionByZero()
|
err = opTerm.ErrDivisionByZero()
|
||||||
} else {
|
} else {
|
||||||
v = kern.NumAsFloat(leftValue) / d
|
v = types.NumAsFloat(leftValue) / d
|
||||||
}
|
}
|
||||||
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
|
} else if fract.IsFraction(leftValue) || fract.IsFraction(rightValue) {
|
||||||
v, err = kern.DivAnyFract(leftValue, rightValue)
|
v, err = fract.DivAnyFract(leftValue, rightValue)
|
||||||
} else {
|
} else {
|
||||||
leftInt, _ := leftValue.(int64)
|
leftInt, _ := leftValue.(int64)
|
||||||
if rightInt, _ := rightValue.(int64); rightInt == 0 {
|
if rightInt, _ := rightValue.(int64); rightInt == 0 {
|
||||||
@@ -85,11 +91,11 @@ func divValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error)
|
|||||||
v = leftInt / rightInt
|
v = leftInt / rightInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if kern.IsString(leftValue) && kern.IsString(rightValue) {
|
} else if str.IsString(leftValue) && str.IsString(rightValue) {
|
||||||
source := leftValue.(string)
|
source := leftValue.(string)
|
||||||
sep := rightValue.(string)
|
sep := rightValue.(string)
|
||||||
v = kern.ListFromStrings(strings.Split(source, sep))
|
v = array.ArrayFromStrings(strings.Split(source, sep))
|
||||||
} else if kern.IsString(leftValue) && kern.IsInteger(rightValue) {
|
} else if str.IsString(leftValue) && types.IsInteger(rightValue) {
|
||||||
source := leftValue.(string)
|
source := leftValue.(string)
|
||||||
partSize := int(rightValue.(int64))
|
partSize := int(rightValue.(int64))
|
||||||
if partSize == 0 {
|
if partSize == 0 {
|
||||||
@@ -108,7 +114,7 @@ func divValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error)
|
|||||||
if remainder > 0 {
|
if remainder > 0 {
|
||||||
parts = append(parts, source[len(source)-remainder:])
|
parts = append(parts, source[len(source)-remainder:])
|
||||||
}
|
}
|
||||||
v = kern.NewList(parts)
|
v = array.NewArray(parts)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
@@ -145,12 +151,12 @@ func evalDivideAsFloat(ctx kern.ExprContext, floatDivTerm *scan.Term) (v any, er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
|
if types.IsNumOrFract(leftValue) && types.IsNumOrFract(rightValue) {
|
||||||
d := kern.NumAsFloat(rightValue)
|
d := types.NumAsFloat(rightValue)
|
||||||
if d == 0.0 {
|
if d == 0.0 {
|
||||||
err = floatDivTerm.ErrDivisionByZero()
|
err = floatDivTerm.ErrDivisionByZero()
|
||||||
} else {
|
} else {
|
||||||
v = kern.NumAsFloat(leftValue) / d
|
v = types.NumAsFloat(leftValue) / d
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = floatDivTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = floatDivTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
@@ -170,7 +176,7 @@ func newRemainderTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func remainderValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func remainderValues(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
|
if types.IsInteger(leftValue) && types.IsInteger(rightValue) {
|
||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
if rightInt == 0 {
|
if rightInt == 0 {
|
||||||
err = opTerm.ErrDivisionByZero()
|
err = opTerm.ErrDivisionByZero()
|
||||||
@@ -196,8 +202,8 @@ func evalRemainder(ctx kern.ExprContext, remainderTerm *scan.Term) (v any, err e
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymStar, newMultiplyTerm)
|
scan.RegisterTermConstructor(sym.SymStar, newMultiplyTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymSlash, newDivideTerm)
|
scan.RegisterTermConstructor(sym.SymSlash, newDivideTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDotSlash, newDivideAsFloatTerm)
|
scan.RegisterTermConstructor(sym.SymDotSlash, newDivideAsFloatTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymPercent, newRemainderTerm)
|
scan.RegisterTermConstructor(sym.SymPercent, newRemainderTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// operator-range.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
|
||||||
)
|
|
||||||
|
|
||||||
// -------- range term
|
|
||||||
type intPair struct {
|
|
||||||
a, b int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *intPair) TypeName() string {
|
|
||||||
return kern.TypePair
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *intPair) ToString(opt kern.FmtOpt) string {
|
|
||||||
return fmt.Sprintf("(%d, %d)", p.a, p.b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIntPair(v any) bool {
|
|
||||||
_, ok := v.(*intPair)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRangeTerm(tk *scan.Token) (inst *scan.Term) {
|
|
||||||
return &scan.Term{
|
|
||||||
Tk: *tk,
|
|
||||||
Children: make([]*scan.Term, 0, 2),
|
|
||||||
Position: scan.PosInfix,
|
|
||||||
Priority: scan.PriRange,
|
|
||||||
EvalFunc: evalRange,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func changeColonToRange(t *scan.Term) {
|
|
||||||
if t.Tk.IsSymbol(scan.SymColon) {
|
|
||||||
t.Tk.Sym = scan.SymRange
|
|
||||||
t.EvalFunc = evalRange
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalRange(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if len(opTerm.Children) == 0 {
|
|
||||||
leftValue = int64(0)
|
|
||||||
rightValue = int64(-1)
|
|
||||||
} else if len(opTerm.Children) == 1 {
|
|
||||||
if leftValue, err = opTerm.Children[0].Compute(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rightValue = int64(kern.ConstLastIndex)
|
|
||||||
} else if leftValue, rightValue, err = opTerm.EvalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !(kern.IsInteger(leftValue) && kern.IsInteger(rightValue)) {
|
|
||||||
// err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
|
||||||
err = errRangeInvalidSpecification(opTerm)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
startIndex, _ := leftValue.(int64)
|
|
||||||
endIndex, _ := rightValue.(int64)
|
|
||||||
|
|
||||||
v = &intPair{int(startIndex), int(endIndex)}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func errRangeInvalidSpecification(t *scan.Term) error {
|
|
||||||
return t.Errorf("invalid range specification")
|
|
||||||
}
|
|
||||||
|
|
||||||
func errRangeUnexpectedExpression(t *scan.Term) error {
|
|
||||||
return t.Errorf("unexpected range expression")
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
func init() {
|
|
||||||
scan.RegisterTermConstructor(scan.SymRange, newRangeTerm)
|
|
||||||
}
|
|
||||||
+30
-24
@@ -9,6 +9,12 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- equal term
|
//-------- equal term
|
||||||
@@ -26,22 +32,22 @@ func newEqualTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
// type deepFuncTemplate func(a, b any) (eq bool, err error)
|
// type deepFuncTemplate func(a, b any) (eq bool, err error)
|
||||||
|
|
||||||
func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) {
|
func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) {
|
||||||
if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) {
|
if types.IsNumOrFract(a) && types.IsNumOrFract(b) {
|
||||||
if kern.IsNumber(a) && kern.IsNumber(b) {
|
if types.IsNumber(a) && types.IsNumber(b) {
|
||||||
if kern.IsInteger(a) && kern.IsInteger(b) {
|
if types.IsInteger(a) && types.IsInteger(b) {
|
||||||
li, _ := a.(int64)
|
li, _ := a.(int64)
|
||||||
ri, _ := b.(int64)
|
ri, _ := b.(int64)
|
||||||
eq = li == ri
|
eq = li == ri
|
||||||
} else {
|
} else {
|
||||||
eq = kern.NumAsFloat(a) == kern.NumAsFloat(b)
|
eq = types.NumAsFloat(a) == types.NumAsFloat(b)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var cmp int
|
var cmp int
|
||||||
if cmp, err = kern.CmpAnyFract(a, b); err == nil {
|
if cmp, err = fract.CmpAnyFract(a, b); err == nil {
|
||||||
eq = cmp == 0
|
eq = cmp == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if deepCmp != nil && kern.IsList(a) && kern.IsList(b) {
|
} else if deepCmp != nil && array.IsArray(a) && array.IsArray(b) {
|
||||||
eq, err = deepCmp(a, b)
|
eq, err = deepCmp(a, b)
|
||||||
} else {
|
} else {
|
||||||
eq = reflect.DeepEqual(a, b)
|
eq = reflect.DeepEqual(a, b)
|
||||||
@@ -75,7 +81,7 @@ func newNotEqualTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
|
|
||||||
func evalNotEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
func evalNotEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
||||||
if v, err = evalEqual(ctx, opTerm); err == nil {
|
if v, err = evalEqual(ctx, opTerm); err == nil {
|
||||||
b, _ := kern.ToBool(v)
|
b, _ := boolean.ToBool(v)
|
||||||
v = !b
|
v = !b
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -94,29 +100,29 @@ func newLessTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lessThan(self *scan.Term, a, b any) (isLess bool, err error) {
|
func lessThan(self *scan.Term, a, b any) (isLess bool, err error) {
|
||||||
if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) {
|
if types.IsNumOrFract(a) && types.IsNumOrFract(b) {
|
||||||
if kern.IsNumber(a) && kern.IsNumber(b) {
|
if types.IsNumber(a) && types.IsNumber(b) {
|
||||||
if kern.IsInteger(a) && kern.IsInteger(b) {
|
if types.IsInteger(a) && types.IsInteger(b) {
|
||||||
li, _ := a.(int64)
|
li, _ := a.(int64)
|
||||||
ri, _ := b.(int64)
|
ri, _ := b.(int64)
|
||||||
isLess = li < ri
|
isLess = li < ri
|
||||||
} else {
|
} else {
|
||||||
isLess = kern.NumAsFloat(a) < kern.NumAsFloat(b)
|
isLess = types.NumAsFloat(a) < types.NumAsFloat(b)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var cmp int
|
var cmp int
|
||||||
if cmp, err = kern.CmpAnyFract(a, b); err == nil {
|
if cmp, err = fract.CmpAnyFract(a, b); err == nil {
|
||||||
isLess = cmp < 0
|
isLess = cmp < 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if kern.IsString(a) && kern.IsString(b) {
|
} else if str.IsString(a) && str.IsString(b) {
|
||||||
ls, _ := a.(string)
|
ls, _ := a.(string)
|
||||||
rs, _ := b.(string)
|
rs, _ := b.(string)
|
||||||
isLess = ls < rs
|
isLess = ls < rs
|
||||||
// Inclusion test
|
// Inclusion test
|
||||||
} else if kern.IsList(a) && kern.IsList(b) {
|
} else if array.IsArray(a) && array.IsArray(b) {
|
||||||
aList, _ := a.(*kern.ListType)
|
aList, _ := a.(*array.ArrayType)
|
||||||
bList, _ := b.(*kern.ListType)
|
bList, _ := b.(*array.ArrayType)
|
||||||
isLess = len(*aList) < len(*bList) && bList.Contains(aList)
|
isLess = len(*aList) < len(*bList) && bList.Contains(aList)
|
||||||
} else {
|
} else {
|
||||||
err = self.ErrIncompatibleTypes(a, b)
|
err = self.ErrIncompatibleTypes(a, b)
|
||||||
@@ -149,8 +155,8 @@ func newLessEqualTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
func lessThanOrEqual(self *scan.Term, a, b any) (isLessEq bool, err error) {
|
func lessThanOrEqual(self *scan.Term, a, b any) (isLessEq bool, err error) {
|
||||||
if isLessEq, err = lessThan(self, a, b); err == nil {
|
if isLessEq, err = lessThan(self, a, b); err == nil {
|
||||||
if !isLessEq {
|
if !isLessEq {
|
||||||
if kern.IsList(a) && kern.IsList(b) {
|
if array.IsArray(a) && array.IsArray(b) {
|
||||||
isLessEq, err = kern.SameContent(a, b)
|
isLessEq, err = array.SameContent(a, b)
|
||||||
} else {
|
} else {
|
||||||
isLessEq, err = equals(a, b, nil)
|
isLessEq, err = equals(a, b, nil)
|
||||||
}
|
}
|
||||||
@@ -219,10 +225,10 @@ func evalGreaterEqual(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleEqual, newEqualTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleEqual, newEqualTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymNotEqual, newNotEqualTerm)
|
scan.RegisterTermConstructor(sym.SymNotEqual, newNotEqualTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymLess, newLessTerm)
|
scan.RegisterTermConstructor(sym.SymLess, newLessTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymLessOrEqual, newLessEqualTerm)
|
scan.RegisterTermConstructor(sym.SymLessOrEqual, newLessEqualTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymGreater, newGreaterTerm)
|
scan.RegisterTermConstructor(sym.SymGreater, newGreaterTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymGreaterOrEqual, newGreaterEqualTerm)
|
scan.RegisterTermConstructor(sym.SymGreaterOrEqual, newGreaterEqualTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- selector term
|
//-------- selector term
|
||||||
@@ -82,5 +83,5 @@ func evalSelector(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymSelector, newSelectorTerm)
|
scan.RegisterTermConstructor(sym.SymSelector, newSelectorTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -7,6 +7,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- bit right shift term
|
//-------- bit right shift term
|
||||||
@@ -22,7 +24,7 @@ func newRightShiftTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bitRightShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func bitRightShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
|
if types.IsInteger(leftValue) && types.IsInteger(rightValue) {
|
||||||
leftInt := leftValue.(int64)
|
leftInt := leftValue.(int64)
|
||||||
rightInt := rightValue.(int64)
|
rightInt := rightValue.(int64)
|
||||||
v = leftInt >> rightInt
|
v = leftInt >> rightInt
|
||||||
@@ -56,7 +58,7 @@ func newLeftShiftTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bitLeftShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func bitLeftShift(opTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) {
|
if types.IsInteger(leftValue) && types.IsInteger(rightValue) {
|
||||||
leftInt := leftValue.(int64)
|
leftInt := leftValue.(int64)
|
||||||
rightInt := rightValue.(int64)
|
rightInt := rightValue.(int64)
|
||||||
v = leftInt << rightInt
|
v = leftInt << rightInt
|
||||||
@@ -81,6 +83,6 @@ func evalLeftShift(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleGreater, newRightShiftTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleGreater, newRightShiftTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymDoubleLess, newLeftShiftTerm)
|
scan.RegisterTermConstructor(sym.SymDoubleLess, newLeftShiftTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-6
@@ -7,6 +7,9 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- plus sign term
|
//-------- plus sign term
|
||||||
@@ -38,15 +41,15 @@ func evalSign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if kern.IsFloat(rightValue) {
|
if float.IsFloat(rightValue) {
|
||||||
if opTerm.Tk.Sym == scan.SymChangeSign {
|
if opTerm.Tk.Sym == sym.SymChangeSign {
|
||||||
f, _ := rightValue.(float64)
|
f, _ := rightValue.(float64)
|
||||||
v = -f
|
v = -f
|
||||||
} else {
|
} else {
|
||||||
v = rightValue
|
v = rightValue
|
||||||
}
|
}
|
||||||
} else if kern.IsInteger(rightValue) {
|
} else if types.IsInteger(rightValue) {
|
||||||
if opTerm.Tk.Sym == scan.SymChangeSign {
|
if opTerm.Tk.Sym == sym.SymChangeSign {
|
||||||
i, _ := rightValue.(int64)
|
i, _ := rightValue.(int64)
|
||||||
v = -i
|
v = -i
|
||||||
} else {
|
} else {
|
||||||
@@ -60,6 +63,6 @@ func evalSign(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymUnchangeSign, newPlusSignTerm)
|
scan.RegisterTermConstructor(sym.SymUnchangeSign, newPlusSignTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymChangeSign, newMinusSignTerm)
|
scan.RegisterTermConstructor(sym.SymChangeSign, newMinusSignTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-30
@@ -10,6 +10,14 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- plus term
|
//-------- plus term
|
||||||
@@ -25,39 +33,46 @@ func newPlusTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sumValues(plusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func sumValues(plusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if (kern.IsString(leftValue) && kern.IsNumberString(rightValue)) || (kern.IsString(rightValue) && kern.IsNumberString(leftValue)) {
|
if (str.IsString(leftValue) && types.IsNumberString(rightValue)) || (str.IsString(rightValue) && types.IsNumberString(leftValue)) {
|
||||||
v = fmt.Sprintf("%v%v", leftValue, rightValue)
|
v = fmt.Sprintf("%v%v", leftValue, rightValue)
|
||||||
} else if kern.IsNumber(leftValue) && kern.IsNumber(rightValue) {
|
} else if types.IsNumber(leftValue) && types.IsNumber(rightValue) {
|
||||||
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
|
if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
|
||||||
v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue)
|
v = types.NumAsFloat(leftValue) + types.NumAsFloat(rightValue)
|
||||||
} else {
|
} else {
|
||||||
leftInt, _ := leftValue.(int64)
|
leftInt, _ := leftValue.(int64)
|
||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
v = leftInt + rightInt
|
v = leftInt + rightInt
|
||||||
}
|
}
|
||||||
} else if kern.IsList(leftValue) && kern.IsList(rightValue) {
|
} else if array.IsArray(leftValue) && array.IsArray(rightValue) {
|
||||||
var leftList, rightList *kern.ListType
|
var leftList, rightList *array.ArrayType
|
||||||
leftList, _ = leftValue.(*kern.ListType)
|
leftList, _ = leftValue.(*array.ArrayType)
|
||||||
rightList, _ = rightValue.(*kern.ListType)
|
rightList, _ = rightValue.(*array.ArrayType)
|
||||||
|
|
||||||
sumList := make(kern.ListType, 0, len(*leftList)+len(*rightList))
|
sumList := make(array.ArrayType, 0, len(*leftList)+len(*rightList))
|
||||||
sumList = append(sumList, *leftList...)
|
sumList = append(sumList, *leftList...)
|
||||||
sumList = append(sumList, *rightList...)
|
sumList = append(sumList, *rightList...)
|
||||||
v = &sumList
|
v = &sumList
|
||||||
} else if (kern.IsFraction(leftValue) && kern.IsNumber(rightValue)) || (kern.IsFraction(rightValue) && kern.IsNumber(leftValue)) {
|
} else if list.IsLinkedList(leftValue) && list.IsLinkedList(rightValue) {
|
||||||
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
|
lsLeft := leftValue.(*list.LinkedList)
|
||||||
v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue)
|
lsRight := rightValue.(*list.LinkedList)
|
||||||
|
ls := lsLeft.Clone()
|
||||||
|
ls.SeqClonePushBack(NewLinkedListIterator(lsRight, nil))
|
||||||
|
v = ls
|
||||||
|
} else if (fract.IsFraction(leftValue) && types.IsNumber(rightValue)) || (fract.IsFraction(rightValue) && types.IsNumber(leftValue)) {
|
||||||
|
if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
|
||||||
|
v = types.NumAsFloat(leftValue) + types.NumAsFloat(rightValue)
|
||||||
} else {
|
} else {
|
||||||
v, err = kern.SumAnyFract(leftValue, rightValue)
|
v, err = fract.SumAnyFract(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
} else if kern.IsDict(leftValue) && kern.IsDict(rightValue) {
|
} else if dict.IsDict(leftValue) && dict.IsDict(rightValue) {
|
||||||
leftDict, _ := leftValue.(*kern.DictType)
|
leftDict, _ := leftValue.(*dict.DictType)
|
||||||
rightDict, _ := rightValue.(*kern.DictType)
|
rightDict, _ := rightValue.(*dict.DictType)
|
||||||
c := leftDict.Clone()
|
clone := leftDict.Clone()
|
||||||
|
c := clone.(*dict.DictType)
|
||||||
c.Merge(rightDict)
|
c.Merge(rightDict)
|
||||||
v = c
|
v = c
|
||||||
} else if kern.IsFraction(leftValue) && kern.IsFraction(rightValue) {
|
} else if fract.IsFraction(leftValue) && fract.IsFraction(rightValue) {
|
||||||
v, err = kern.SumAnyFract(leftValue, rightValue)
|
v, err = fract.SumAnyFract(leftValue, rightValue)
|
||||||
} else {
|
} else {
|
||||||
err = plusTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
err = plusTerm.ErrIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@@ -87,20 +102,20 @@ func newMinusTerm(tk *scan.Token) (inst *scan.Term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func diffValues(minusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
func diffValues(minusTerm *scan.Term, leftValue, rightValue any) (v any, err error) {
|
||||||
if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) {
|
if types.IsNumOrFract(leftValue) && types.IsNumOrFract(rightValue) {
|
||||||
if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) {
|
if float.IsFloat(leftValue) || float.IsFloat(rightValue) {
|
||||||
v = kern.NumAsFloat(leftValue) - kern.NumAsFloat(rightValue)
|
v = types.NumAsFloat(leftValue) - types.NumAsFloat(rightValue)
|
||||||
} else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) {
|
} else if fract.IsFraction(leftValue) || fract.IsFraction(rightValue) {
|
||||||
v, err = kern.SubAnyFract(leftValue, rightValue)
|
v, err = fract.SubAnyFract(leftValue, rightValue)
|
||||||
} else {
|
} else {
|
||||||
leftInt, _ := leftValue.(int64)
|
leftInt, _ := leftValue.(int64)
|
||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
v = leftInt - rightInt
|
v = leftInt - rightInt
|
||||||
}
|
}
|
||||||
} else if kern.IsList(leftValue) && kern.IsList(rightValue) {
|
} else if array.IsArray(leftValue) && array.IsArray(rightValue) {
|
||||||
leftList, _ := leftValue.(*kern.ListType)
|
leftList, _ := leftValue.(*array.ArrayType)
|
||||||
rightList, _ := rightValue.(*kern.ListType)
|
rightList, _ := rightValue.(*array.ArrayType)
|
||||||
diffList := make(kern.ListType, 0, len(*leftList)-len(*rightList))
|
diffList := make(array.ArrayType, 0, len(*leftList)-len(*rightList))
|
||||||
for _, item := range *leftList {
|
for _, item := range *leftList {
|
||||||
if slices.Index(*rightList, item) < 0 {
|
if slices.Index(*rightList, item) < 0 {
|
||||||
diffList = append(diffList, item)
|
diffList = append(diffList, item)
|
||||||
@@ -125,6 +140,6 @@ func evalMinus(ctx kern.ExprContext, minusTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymPlus, newPlusTerm)
|
scan.RegisterTermConstructor(sym.SymPlus, newPlusTerm)
|
||||||
scan.RegisterTermConstructor(scan.SymMinus, newMinusTerm)
|
scan.RegisterTermConstructor(sym.SymMinus, newMinusTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -9,6 +9,8 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- unset term
|
//-------- unset term
|
||||||
@@ -50,8 +52,8 @@ func evalUnset(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
if kern.IsList(childValue) {
|
if array.IsArray(childValue) {
|
||||||
list, _ := childValue.(*kern.ListType)
|
list, _ := childValue.(*array.ArrayType)
|
||||||
for _, item := range *list {
|
for _, item := range *list {
|
||||||
if deleted, err = deleteContextItem(ctx, opTerm, item); err != nil {
|
if deleted, err = deleteContextItem(ctx, opTerm, item); err != nil {
|
||||||
break
|
break
|
||||||
@@ -70,5 +72,5 @@ func evalUnset(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
scan.RegisterTermConstructor(scan.SymKwUnset, newUnsetTerm)
|
scan.RegisterTermConstructor(sym.SymKwUnset, newUnsetTerm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ func NewParser() (p *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
|
func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
|
||||||
for tk = scanner.Next(); tk.IsSymbol(scan.SymComment); tk = scanner.Next() {
|
for tk = scanner.Next(); tk.IsSymbol(sym.SymComment); tk = scanner.Next() {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -66,10 +67,10 @@ func (parser *parser) Next(scanner *scan.Scanner) (tk *scan.Token) {
|
|||||||
func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk *scan.Token) (tree *scan.Term, err error) {
|
func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk *scan.Token) (tree *scan.Term, err error) {
|
||||||
args := make([]*scan.Term, 0, 10)
|
args := make([]*scan.Term, 0, 10)
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
lastSym := scan.SymUnknown
|
lastSym := sym.SymUnknown
|
||||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||||
var subTree *scan.Ast
|
var subTree *scan.Ast
|
||||||
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err != nil {
|
if subTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedRound); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
prev := scanner.Previous()
|
prev := scanner.Previous()
|
||||||
@@ -80,11 +81,11 @@ func (parser *parser) parseFuncCall(scanner *scan.Scanner, ctx parserContext, tk
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
itemExpected = prev.Sym == scan.SymComma
|
itemExpected = prev.Sym == sym.SymComma
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastSym != scan.SymClosedRound {
|
if lastSym != sym.SymClosedRound {
|
||||||
err = errors.New("unterminated arguments list")
|
err = errors.New("unterminated arguments list")
|
||||||
} else {
|
} else {
|
||||||
tree = newFuncCallTerm(tk, args)
|
tree = newFuncCallTerm(tk, args)
|
||||||
@@ -97,13 +98,13 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
|||||||
// Example: "add = func(x,y) {x+y}
|
// Example: "add = func(x,y) {x+y}
|
||||||
var body *scan.Ast
|
var body *scan.Ast
|
||||||
args := make([]*scan.Term, 0)
|
args := make([]*scan.Term, 0)
|
||||||
lastSym := scan.SymUnknown
|
lastSym := sym.SymUnknown
|
||||||
defaultParamsStarted := false
|
defaultParamsStarted := false
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
tk := scanner.Previous()
|
tk := scanner.Previous()
|
||||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
if tk.IsSymbol(scan.SymIdentifier) {
|
if tk.IsSymbol(sym.SymIdentifier) {
|
||||||
param := scan.NewTerm(tk)
|
param := scan.NewTerm(tk)
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
if pos := paramAlreadyDefined(args, param); pos > 0 {
|
if pos := paramAlreadyDefined(args, param); pos > 0 {
|
||||||
@@ -113,10 +114,10 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
|||||||
}
|
}
|
||||||
args = append(args, param)
|
args = append(args, param)
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
if tk.Sym == scan.SymEqual {
|
if tk.Sym == sym.SymEqual {
|
||||||
var paramExpr *scan.Ast
|
var paramExpr *scan.Ast
|
||||||
defaultParamsStarted = true
|
defaultParamsStarted = true
|
||||||
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, scan.SymComma, scan.SymClosedRound); err != nil {
|
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, sym.SymComma, sym.SymClosedRound); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
param.ForceChild(paramExpr.Root())
|
param.ForceChild(paramExpr.Root())
|
||||||
@@ -130,25 +131,25 @@ func (parser *parser) parseFuncDef(scanner *scan.Scanner) (tree *scan.Term, err
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
itemExpected = lastSym == scan.SymComma
|
itemExpected = lastSym == sym.SymComma
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && lastSym != scan.SymClosedRound {
|
if err == nil && lastSym != sym.SymClosedRound {
|
||||||
err = tk.ErrorExpectedGot(")")
|
err = tk.ErrorExpectedGot(")")
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
if tk.IsSymbol(scan.SymOpenBrace) {
|
if tk.IsSymbol(sym.SymOpenBrace) {
|
||||||
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, scan.SymClosedBrace)
|
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, sym.SymClosedBrace)
|
||||||
} else {
|
} else {
|
||||||
err = tk.ErrorExpectedGot("{")
|
err = tk.ErrorExpectedGot("{")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if scanner.Previous().Sym != scan.SymClosedBrace {
|
if scanner.Previous().Sym != sym.SymClosedBrace {
|
||||||
err = scanner.Previous().ErrorExpectedGot("}")
|
err = scanner.Previous().ErrorExpectedGot("}")
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeValueToken(scan.SymExpression, "", body)
|
tk = scanner.MakeValueToken(sym.SymExpression, "", body)
|
||||||
tree = newFuncDefTerm(tk, args)
|
tree = newFuncDefTerm(tk, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,40 +166,35 @@ func paramAlreadyDefined(args []*scan.Term, param *scan.Term) (position int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSym scan.Symbol) (listTerm *scan.Term, err error) {
|
func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSym sym.Symbol) (listTerm *scan.Term, err error) {
|
||||||
r, c := scanner.LastPos()
|
r, c := scanner.LastPos()
|
||||||
args := make([]*scan.Term, 0)
|
args := make([]*scan.Term, 0)
|
||||||
lastSym := scan.SymUnknown
|
lastSym := sym.SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
itemCtx := remFlags(ctx, allowIndex)
|
itemCtx := remFlags(ctx, allowIndex)
|
||||||
for lastSym != termSym && lastSym != scan.SymEos {
|
for lastSym != termSym && lastSym != sym.SymEos {
|
||||||
zeroRequired := scanner.Current().Sym == scan.SymColon
|
|
||||||
var itemTree *scan.Ast
|
var itemTree *scan.Ast
|
||||||
if itemTree, err = parser.parseItem(scanner, itemCtx, scan.SymComma, termSym); err == nil {
|
if itemTree, err = parser.parseItem(scanner, itemCtx, sym.SymComma, termSym); err == nil {
|
||||||
root := itemTree.Root()
|
root := itemTree.Root()
|
||||||
if root != nil {
|
if root != nil {
|
||||||
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymColon {
|
if root.Symbol() == sym.SymDoubleDot {
|
||||||
changeColonToRange(root)
|
if hasFlag(ctx, allowIndex) {
|
||||||
}
|
changeColonToInterval(root)
|
||||||
if !hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange {
|
} else {
|
||||||
// err = root.Errorf("unexpected range expression")
|
// err = root.Errorf("unexpected range expression")
|
||||||
err = errRangeUnexpectedExpression(root)
|
err = errIntervalUnexpectedExpression(root)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// if hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymDoubleDot {
|
||||||
|
// changeColonToInterval(root)
|
||||||
|
// }
|
||||||
|
// if !hasFlag(ctx, allowIndex) && root.Symbol() == sym.SymInterval {
|
||||||
|
// // err = root.Errorf("unexpected range expression")
|
||||||
|
// err = errIntervalUnexpectedExpression(root)
|
||||||
|
// break
|
||||||
|
// }
|
||||||
args = append(args, root)
|
args = append(args, root)
|
||||||
if hasFlag(ctx, allowIndex) && root.Symbol() == scan.SymRange && zeroRequired { //len(root.children) == 0 {
|
|
||||||
if len(root.Children) == 1 {
|
|
||||||
root.Children = append(root.Children, root.Children[0])
|
|
||||||
} else if len(root.Children) > 1 {
|
|
||||||
// err = root.Errorf("invalid range specification")
|
|
||||||
err = errRangeInvalidSpecification(root)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
zeroTk := scan.NewValueToken(root.Tk.Row(), root.Tk.Col(), scan.SymInteger, "0", int64(0))
|
|
||||||
zeroTerm := scan.NewTerm(zeroTk)
|
|
||||||
zeroTerm.SetParent(root)
|
|
||||||
root.Children[0] = zeroTerm
|
|
||||||
}
|
|
||||||
} else if itemExpected {
|
} else if itemExpected {
|
||||||
prev := scanner.Previous()
|
prev := scanner.Previous()
|
||||||
err = prev.ErrorExpectedGot("list-item")
|
err = prev.ErrorExpectedGot("list-item")
|
||||||
@@ -208,16 +204,16 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSy
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
if itemExpected = lastSym == scan.SymComma; itemExpected {
|
if itemExpected = lastSym == sym.SymComma; itemExpected {
|
||||||
remFlags(ctx, allowIndex)
|
remFlags(ctx, allowIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastSym != termSym {
|
if lastSym != termSym {
|
||||||
err = scanner.Previous().ErrorExpectedGot("]")
|
err = scanner.Previous().ErrorExpectedGot("]")
|
||||||
} else if termSym == scan.SymClosedSquare {
|
} else if termSym == sym.SymClosedSquare {
|
||||||
listTerm = newListTerm(r, c, args)
|
listTerm = newListTerm(r, c, args)
|
||||||
} else if termSym == scan.SymGreaterClosedSquare {
|
} else if termSym == sym.SymGreaterClosedSquare {
|
||||||
listTerm = newLinkedListTerm(r, c, args)
|
listTerm = newLinkedListTerm(r, c, args)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("[%d:%d] unknown list type", r, c)
|
err = fmt.Errorf("[%d:%d] unknown list type", r, c)
|
||||||
@@ -229,11 +225,11 @@ func (parser *parser) parseList(scanner *scan.Scanner, ctx parserContext, termSy
|
|||||||
func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
||||||
tk := scanner.Previous()
|
tk := scanner.Previous()
|
||||||
args := make([]*scan.Term, 0)
|
args := make([]*scan.Term, 0)
|
||||||
lastSym := scan.SymUnknown
|
lastSym := sym.SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
for lastSym != scan.SymClosedRound && lastSym != scan.SymEos {
|
for lastSym != sym.SymClosedRound && lastSym != sym.SymEos {
|
||||||
var subTree *scan.Ast
|
var subTree *scan.Ast
|
||||||
if subTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedRound); err == nil {
|
if subTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedRound); err == nil {
|
||||||
if subTree.Root() != nil {
|
if subTree.Root() != nil {
|
||||||
args = append(args, subTree.Root())
|
args = append(args, subTree.Root())
|
||||||
} else if itemExpected {
|
} else if itemExpected {
|
||||||
@@ -245,10 +241,10 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
itemExpected = lastSym == scan.SymComma
|
itemExpected = lastSym == sym.SymComma
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastSym != scan.SymClosedRound {
|
if lastSym != sym.SymClosedRound {
|
||||||
err = scanner.Previous().ErrorExpectedGot(")")
|
err = scanner.Previous().ErrorExpectedGot(")")
|
||||||
} else {
|
} else {
|
||||||
subtree = newIteratorTerm(tk, args)
|
subtree = newIteratorTerm(tk, args)
|
||||||
@@ -259,16 +255,16 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
|||||||
|
|
||||||
// func (parser *parser) parseDictKey(scanner *scan.Scanner) (key any, err error) {
|
// func (parser *parser) parseDictKey(scanner *scan.Scanner) (key any, err error) {
|
||||||
// tk := parser.Next(scanner)
|
// tk := parser.Next(scanner)
|
||||||
// if tk.Sym == scan.SymError {
|
// if tk.Sym == sym.SymError {
|
||||||
// err = tk.Error()
|
// err = tk.Error()
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// if tk.Sym == scan.SymClosedBrace || tk.Sym == scan.SymEos {
|
// if tk.Sym == sym.SymClosedBrace || tk.Sym == sym.SymEos {
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// if tk.Sym == scan.SymInteger || tk.Sym == scan.SymString || tk.Sym == scan.SymIdentifier {
|
// if tk.Sym == sym.SymInteger || tk.Sym == sym.SymString || tk.Sym == sym.SymIdentifier {
|
||||||
// tkSep := parser.Next(scanner)
|
// tkSep := parser.Next(scanner)
|
||||||
// if tkSep.Sym != scan.SymColon {
|
// if tkSep.Sym != sym.SymColon {
|
||||||
// err = tkSep.ErrorExpectedGot(":")
|
// err = tkSep.ErrorExpectedGot(":")
|
||||||
// } else {
|
// } else {
|
||||||
// key = tk.Value
|
// key = tk.Value
|
||||||
@@ -281,15 +277,15 @@ func (parser *parser) parseIterDef(scanner *scan.Scanner, ctx parserContext) (su
|
|||||||
|
|
||||||
func (parser *parser) parseDictKey(scanner *scan.Scanner) (key *scan.Term, err error) {
|
func (parser *parser) parseDictKey(scanner *scan.Scanner) (key *scan.Term, err error) {
|
||||||
var keyTree *scan.Ast
|
var keyTree *scan.Ast
|
||||||
if keyTree, err = parser.parseItem(scanner, parserNoFlags, scan.SymColon, scan.SymClosedBrace); err == nil {
|
if keyTree, err = parser.parseItem(scanner, parserNoFlags, sym.SymColon, sym.SymClosedBrace); err == nil {
|
||||||
key = keyTree.Root()
|
key = keyTree.Root()
|
||||||
tkSep := scanner.Previous()
|
tkSep := scanner.Previous()
|
||||||
sym := tkSep.Sym
|
symbol := tkSep.Sym
|
||||||
if sym == scan.SymClosedBrace || sym == scan.SymEos {
|
if symbol == sym.SymClosedBrace || symbol == sym.SymEos {
|
||||||
if key != nil {
|
if key != nil {
|
||||||
err = tkSep.ErrorExpectedGot(":")
|
err = tkSep.ErrorExpectedGot(":")
|
||||||
}
|
}
|
||||||
} else if sym != scan.SymColon {
|
} else if symbol != sym.SymColon {
|
||||||
err = tkSep.ErrorExpectedGot(":")
|
err = tkSep.ErrorExpectedGot(":")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,9 +294,9 @@ func (parser *parser) parseDictKey(scanner *scan.Scanner) (key *scan.Term, err e
|
|||||||
|
|
||||||
func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext) (subtree *scan.Term, err error) {
|
||||||
args := make(map[any]*scan.Term, 0)
|
args := make(map[any]*scan.Term, 0)
|
||||||
lastSym := scan.SymUnknown
|
lastSym := sym.SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
for lastSym != scan.SymClosedBrace && lastSym != scan.SymEos {
|
for lastSym != sym.SymClosedBrace && lastSym != sym.SymEos {
|
||||||
var valueTree *scan.Ast
|
var valueTree *scan.Ast
|
||||||
var key any
|
var key any
|
||||||
if key, err = parser.parseDictKey(scanner); err != nil {
|
if key, err = parser.parseDictKey(scanner); err != nil {
|
||||||
@@ -313,7 +309,7 @@ func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext)
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if valueTree, err = parser.parseItem(scanner, ctx, scan.SymComma, scan.SymClosedBrace); err == nil {
|
if valueTree, err = parser.parseItem(scanner, ctx, sym.SymComma, sym.SymClosedBrace); err == nil {
|
||||||
if valueTree.Root() != nil {
|
if valueTree.Root() != nil {
|
||||||
args[key] = valueTree.Root()
|
args[key] = valueTree.Root()
|
||||||
} else /*if key != nil*/ {
|
} else /*if key != nil*/ {
|
||||||
@@ -325,10 +321,10 @@ func (parser *parser) parseDictionary(scanner *scan.Scanner, ctx parserContext)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
itemExpected = lastSym == scan.SymComma
|
itemExpected = lastSym == sym.SymComma
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastSym != scan.SymClosedBrace {
|
if lastSym != sym.SymClosedBrace {
|
||||||
err = scanner.Previous().ErrorExpectedGot("}")
|
err = scanner.Previous().ErrorExpectedGot("}")
|
||||||
} else {
|
} else {
|
||||||
subtree = newDictTerm(args)
|
subtree = newDictTerm(args)
|
||||||
@@ -344,12 +340,12 @@ func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext
|
|||||||
tk := parser.Next(scanner)
|
tk := parser.Next(scanner)
|
||||||
startRow := tk.Row()
|
startRow := tk.Row()
|
||||||
startCol := tk.Col()
|
startCol := tk.Col()
|
||||||
if tk.Sym == scan.SymOpenSquare {
|
if tk.Sym == sym.SymOpenSquare {
|
||||||
if defaultCase {
|
if defaultCase {
|
||||||
err = tk.Errorf("case list in default clause")
|
err = tk.Errorf("case list in default clause")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex), scan.SymClosedSquare); err != nil {
|
if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex), sym.SymClosedSquare); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
@@ -359,8 +355,8 @@ func (parser *parser) parseSelectorCase(scanner *scan.Scanner, ctx parserContext
|
|||||||
filterList = newListTerm(startRow, startCol, make([]*scan.Term, 0))
|
filterList = newListTerm(startRow, startCol, make([]*scan.Term, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tk.Sym == scan.SymOpenBrace {
|
if tk.Sym == sym.SymOpenBrace {
|
||||||
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, scan.SymClosedBrace); err != nil {
|
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, sym.SymClosedBrace); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -390,7 +386,7 @@ func (parser *parser) parseSelector(scanner *scan.Scanner, tree *scan.Ast, ctx p
|
|||||||
var caseTerm *scan.Term
|
var caseTerm *scan.Term
|
||||||
|
|
||||||
ctx = remFlags(ctx, allowIndex)
|
ctx = remFlags(ctx, allowIndex)
|
||||||
tk := scanner.MakeToken(scan.SymSelector, '?')
|
tk := scanner.MakeToken(sym.SymSelector, '?')
|
||||||
if selectorTerm, err = tree.AddToken(tk); err != nil {
|
if selectorTerm, err = tree.AddToken(tk); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -401,11 +397,11 @@ func (parser *parser) parseSelector(scanner *scan.Scanner, tree *scan.Ast, ctx p
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseItem(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
func (parser *parser) parseItem(scanner *scan.Scanner, ctx parserContext, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||||
return parser.parseGeneral(scanner, ctx|allowVarRef, termSymbols...)
|
return parser.parseGeneral(scanner, ctx|allowVarRef, termSymbols...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if errVal, ok := r.(error); ok {
|
if errVal, ok := r.(error); ok {
|
||||||
@@ -415,23 +411,23 @@ func (parser *parser) Parse(scanner *scan.Scanner, termSymbols ...scan.Symbol) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
termSymbols = append(termSymbols, scan.SymEos)
|
termSymbols = append(termSymbols, sym.SymEos)
|
||||||
return parser.parseGeneral(scanner, allowMultiExpr, termSymbols...)
|
return parser.parseGeneral(scanner, allowMultiExpr, termSymbols...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func couldBeACollection(t *scan.Term) bool {
|
func couldBeACollection(t *scan.Term) bool {
|
||||||
var sym = scan.SymUnknown
|
var symbol = sym.SymUnknown
|
||||||
if t != nil {
|
if t != nil {
|
||||||
sym = t.Symbol()
|
symbol = t.Symbol()
|
||||||
}
|
}
|
||||||
// return sym == scan.SymList || sym == scan.SymString || sym == scan.SymDict || sym == scan.SymExpression || sym == scan.SymVariable
|
// return sym == sym.SymList || sym == sym.SymString || sym == sym.SymDict || sym == sym.SymExpression || sym == sym.SymVariable
|
||||||
return slices.Contains([]scan.Symbol{scan.SymList, scan.SymLinkedList, scan.SymString, scan.SymDict, scan.SymExpression, scan.SymVariable, scan.SymIndex}, sym)
|
return slices.Contains([]sym.Symbol{sym.SymList, sym.SymLinkedList, sym.SymString, sym.SymDict, sym.SymExpression, sym.SymVariable, sym.SymIndex}, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *scan.Term, err error) {
|
func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *scan.Term, err error) {
|
||||||
var tk *scan.Token
|
var tk *scan.Token
|
||||||
if allowIndeces {
|
if allowIndeces {
|
||||||
tk = scan.NewToken(listTerm.Tk.Row(), listTerm.Tk.Col(), scan.SymIndex, listTerm.Source())
|
tk = scan.NewToken(listTerm.Tk.Row(), listTerm.Tk.Col(), sym.SymIndex, listTerm.Source())
|
||||||
root = scan.NewTerm(tk)
|
root = scan.NewTerm(tk)
|
||||||
if err = tree.AddTerm(root); err == nil {
|
if err = tree.AddTerm(root); err == nil {
|
||||||
err = tree.AddTerm(listTerm)
|
err = tree.AddTerm(listTerm)
|
||||||
@@ -445,22 +441,22 @@ func listSubTree(tree *scan.Ast, listTerm *scan.Term, allowIndeces bool) (root *
|
|||||||
|
|
||||||
func changePrefix(tk *scan.Token) {
|
func changePrefix(tk *scan.Token) {
|
||||||
switch tk.Sym {
|
switch tk.Sym {
|
||||||
case scan.SymMinus:
|
case sym.SymMinus:
|
||||||
tk.SetSymbol(scan.SymChangeSign)
|
tk.SetSymbol(sym.SymChangeSign)
|
||||||
case scan.SymPlus:
|
case sym.SymPlus:
|
||||||
tk.SetSymbol(scan.SymUnchangeSign)
|
tk.SetSymbol(sym.SymUnchangeSign)
|
||||||
case scan.SymStar:
|
case sym.SymStar:
|
||||||
tk.SetSymbol(scan.SymDereference)
|
tk.SetSymbol(sym.SymDereference)
|
||||||
case scan.SymExclamation:
|
case sym.SymExclamation:
|
||||||
tk.SetSymbol(scan.SymNot)
|
tk.SetSymbol(sym.SymNot)
|
||||||
case scan.SymDoublePlus:
|
case sym.SymDoublePlus:
|
||||||
tk.SetSymbol(scan.SymPreInc)
|
tk.SetSymbol(sym.SymPreInc)
|
||||||
case scan.SymDoubleMinus:
|
case sym.SymDoubleMinus:
|
||||||
tk.SetSymbol(scan.SymPreDec)
|
tk.SetSymbol(sym.SymPreDec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, termSymbols ...scan.Symbol) (tree *scan.Ast, err error) {
|
func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, termSymbols ...sym.Symbol) (tree *scan.Ast, err error) {
|
||||||
var selectorTerm *scan.Term = nil
|
var selectorTerm *scan.Term = nil
|
||||||
var currentTerm *scan.Term = nil
|
var currentTerm *scan.Term = nil
|
||||||
var tk *scan.Token
|
var tk *scan.Token
|
||||||
@@ -473,7 +469,7 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
|||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if tk.Sym == scan.SymSemiColon {
|
if tk.Sym == sym.SymSemiColon {
|
||||||
if hasFlag(ctx, allowMultiExpr) {
|
if hasFlag(ctx, allowMultiExpr) {
|
||||||
tree.ToForest()
|
tree.ToForest()
|
||||||
firstToken = true
|
firstToken = true
|
||||||
@@ -493,9 +489,9 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch tk.Sym {
|
switch tk.Sym {
|
||||||
case scan.SymOpenRound:
|
case sym.SymOpenRound:
|
||||||
var subTree *scan.Ast
|
var subTree *scan.Ast
|
||||||
if subTree, err = parser.parseGeneral(scanner, ctx, scan.SymClosedRound); err == nil {
|
if subTree, err = parser.parseGeneral(scanner, ctx, sym.SymClosedRound); err == nil {
|
||||||
if subTree.Root() == nil {
|
if subTree.Root() == nil {
|
||||||
err = tk.ErrorExpectedGotString("expression", "()")
|
err = tk.ErrorExpectedGotString("expression", "()")
|
||||||
} else {
|
} else {
|
||||||
@@ -504,26 +500,26 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
|||||||
currentTerm = exprTerm
|
currentTerm = exprTerm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case scan.SymFuncCall:
|
case sym.SymFuncCall:
|
||||||
var funcCallTerm *scan.Term
|
var funcCallTerm *scan.Term
|
||||||
if funcCallTerm, err = parser.parseFuncCall(scanner, ctx, tk); err == nil {
|
if funcCallTerm, err = parser.parseFuncCall(scanner, ctx, tk); err == nil {
|
||||||
err = tree.AddTerm(funcCallTerm)
|
err = tree.AddTerm(funcCallTerm)
|
||||||
currentTerm = funcCallTerm
|
currentTerm = funcCallTerm
|
||||||
}
|
}
|
||||||
case scan.SymOpenSquare:
|
case sym.SymOpenSquare:
|
||||||
var listTerm *scan.Term
|
var listTerm *scan.Term
|
||||||
newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm))
|
newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm))
|
||||||
if listTerm, err = parser.parseList(scanner, newCtx, scan.SymClosedSquare); err == nil {
|
if listTerm, err = parser.parseList(scanner, newCtx, sym.SymClosedSquare); err == nil {
|
||||||
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
||||||
}
|
}
|
||||||
case scan.SymOpenSquareLess:
|
case sym.SymOpenSquareLess:
|
||||||
var listTerm *scan.Term
|
var listTerm *scan.Term
|
||||||
newCtx := addFlagsCond(addFlags(ctx, listContext), allowIndex, false)
|
newCtx := addFlagsCond(addFlags(ctx, listContext), allowIndex, false)
|
||||||
if listTerm, err = parser.parseList(scanner, newCtx, scan.SymGreaterClosedSquare); err == nil {
|
if listTerm, err = parser.parseList(scanner, newCtx, sym.SymGreaterClosedSquare); err == nil {
|
||||||
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
||||||
}
|
}
|
||||||
case scan.SymOpenBrace:
|
case sym.SymOpenBrace:
|
||||||
if currentTerm != nil && currentTerm.Symbol() == scan.SymColon {
|
if currentTerm != nil && currentTerm.Symbol() == sym.SymColon {
|
||||||
err = currentTerm.Errorf(`selector-case outside of a selector context`)
|
err = currentTerm.Errorf(`selector-case outside of a selector context`)
|
||||||
} else {
|
} else {
|
||||||
var mapTerm *scan.Term
|
var mapTerm *scan.Term
|
||||||
@@ -532,54 +528,61 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
|||||||
currentTerm = mapTerm
|
currentTerm = mapTerm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case scan.SymEqual, scan.SymPlusEqual, scan.SymMinusEqual, scan.SymStarEqual, scan.SymSlashEqual, scan.SymPercEqual, scan.SymAmpersandEqual, scan.SymVertBarEqual, scan.SymDoubleLessEqual, scan.SymDoubleGreaterEqual, scan.SymCaretEqual:
|
case sym.SymEqual, sym.SymPlusEqual, sym.SymMinusEqual, sym.SymStarEqual, sym.SymSlashEqual, sym.SymPercEqual, sym.SymAmpersandEqual, sym.SymVertBarEqual, sym.SymDoubleLessEqual, sym.SymDoubleGreaterEqual, sym.SymCaretEqual:
|
||||||
currentTerm, err = tree.AddToken(tk)
|
currentTerm, err = tree.AddToken(tk)
|
||||||
firstToken = true
|
firstToken = true
|
||||||
case scan.SymFuncDef:
|
case sym.SymFuncDef:
|
||||||
var funcDefTerm *scan.Term
|
var funcDefTerm *scan.Term
|
||||||
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
|
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
|
||||||
err = tree.AddTerm(funcDefTerm)
|
err = tree.AddTerm(funcDefTerm)
|
||||||
currentTerm = funcDefTerm
|
currentTerm = funcDefTerm
|
||||||
}
|
}
|
||||||
case scan.SymDollarRound:
|
case sym.SymDollarRound:
|
||||||
var iterDefTerm *scan.Term
|
var iterDefTerm *scan.Term
|
||||||
if iterDefTerm, err = parser.parseIterDef(scanner, ctx); err == nil {
|
if iterDefTerm, err = parser.parseIterDef(scanner, ctx); err == nil {
|
||||||
err = tree.AddTerm(iterDefTerm)
|
err = tree.AddTerm(iterDefTerm)
|
||||||
currentTerm = iterDefTerm
|
currentTerm = iterDefTerm
|
||||||
}
|
}
|
||||||
case scan.SymIdentifier:
|
case sym.SymIdentifier:
|
||||||
if tk.Source()[0] == '@' && !hasFlag(ctx, allowVarRef) {
|
if tk.Source()[0] == '@' && !hasFlag(ctx, allowVarRef) {
|
||||||
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.Source())
|
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.Source())
|
||||||
} else {
|
} else {
|
||||||
currentTerm, err = tree.AddToken(tk)
|
currentTerm, err = tree.AddToken(tk)
|
||||||
}
|
}
|
||||||
case scan.SymQuestion:
|
case sym.SymQuestion:
|
||||||
if selectorTerm, err = parser.parseSelector(scanner, tree, ctx); err == nil {
|
if selectorTerm, err = parser.parseSelector(scanner, tree, ctx); err == nil {
|
||||||
currentTerm = selectorTerm
|
currentTerm = selectorTerm
|
||||||
addFlags(ctx, selectorContext)
|
addFlags(ctx, selectorContext)
|
||||||
}
|
}
|
||||||
case scan.SymColon, scan.SymDoubleColon:
|
case sym.SymColon, sym.SymDoubleColon:
|
||||||
var caseTerm *scan.Term
|
var caseTerm *scan.Term
|
||||||
if selectorTerm != nil {
|
if selectorTerm != nil {
|
||||||
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == scan.SymDoubleColon); err == nil {
|
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == sym.SymDoubleColon); err == nil {
|
||||||
addSelectorCase(selectorTerm, caseTerm)
|
addSelectorCase(selectorTerm, caseTerm)
|
||||||
currentTerm = caseTerm
|
currentTerm = caseTerm
|
||||||
if tk.Sym == scan.SymDoubleColon {
|
if tk.Sym == sym.SymDoubleColon {
|
||||||
selectorTerm = nil
|
selectorTerm = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// err = tk.Errorf("colon outside a selector context")
|
||||||
currentTerm, err = tree.AddToken(tk)
|
currentTerm, err = tree.AddToken(tk)
|
||||||
if tk.IsOneOfA(scan.SymColon, scan.SymRange) {
|
|
||||||
// Colon outside a selector term acts like a separator
|
// Colon outside a selector term acts like a separator
|
||||||
firstToken = true
|
firstToken = tk.IsOneOfA(sym.SymColon, sym.SymInterval)
|
||||||
}
|
}
|
||||||
|
case sym.SymDoubleDot:
|
||||||
|
currentTerm, err = tree.AddToken(tk)
|
||||||
|
if currentTerm.GetLeftChild() == nil {
|
||||||
|
zeroTk := scan.NewValueToken(tk.Row(), tk.Col(), sym.SymInteger, "0", int64(0))
|
||||||
|
tree.AddToken(zeroTk)
|
||||||
}
|
}
|
||||||
|
// Double dot acts like a separator
|
||||||
|
firstToken = tk.IsOneOfA(sym.SymDoubleDot, sym.SymInterval)
|
||||||
default:
|
default:
|
||||||
currentTerm, err = tree.AddToken(tk)
|
currentTerm, err = tree.AddToken(tk)
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentTerm != nil && currentTerm.Tk.Sym != scan.SymSelector && currentTerm.Parent != nil && currentTerm.Parent.Tk.Sym != scan.SymSelector {
|
if currentTerm != nil && currentTerm.Tk.Sym != sym.SymSelector && currentTerm.Parent != nil && currentTerm.Parent.Tk.Sym != sym.SymSelector {
|
||||||
selectorTerm = nil
|
selectorTerm = nil
|
||||||
remFlags(ctx, selectorContext)
|
remFlags(ctx, selectorContext)
|
||||||
}
|
}
|
||||||
@@ -589,7 +592,7 @@ func (parser *parser) parseGeneral(scanner *scan.Scanner, ctx parserContext, ter
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
if !tk.IsOneOf(termSymbols) {
|
if !tk.IsOneOf(termSymbols) {
|
||||||
var symDesc string
|
var symDesc string
|
||||||
if tk.IsSymbol(scan.SymError) {
|
if tk.IsSymbol(sym.SymError) {
|
||||||
symDesc = tk.ErrorText()
|
symDesc = tk.ErrorText()
|
||||||
} else {
|
} else {
|
||||||
symDesc = scan.SymToString(tk.Sym)
|
symDesc = scan.SymToString(tk.Sym)
|
||||||
|
|||||||
+150
-122
@@ -12,7 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,10 +23,12 @@ type Scanner struct {
|
|||||||
stream *bufio.Reader
|
stream *bufio.Reader
|
||||||
row int
|
row int
|
||||||
column int
|
column int
|
||||||
translations map[Symbol]Symbol
|
translations map[sym.Symbol]sym.Symbol
|
||||||
|
unreadByte byte
|
||||||
|
prevRowLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *Scanner) {
|
func NewScanner(s io.Reader, translations map[sym.Symbol]sym.Symbol) (inst *Scanner) {
|
||||||
inst = &Scanner{
|
inst = &Scanner{
|
||||||
stream: bufio.NewReader(s),
|
stream: bufio.NewReader(s),
|
||||||
row: 1,
|
row: 1,
|
||||||
@@ -37,15 +39,15 @@ func NewScanner(s io.Reader, translations map[Symbol]Symbol) (inst *Scanner) {
|
|||||||
return inst
|
return inst
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultTranslations() map[Symbol]Symbol {
|
func DefaultTranslations() map[sym.Symbol]sym.Symbol {
|
||||||
return map[Symbol]Symbol{
|
return map[sym.Symbol]sym.Symbol{
|
||||||
SymDoubleAmpersand: SymAnd,
|
sym.SymDoubleAmpersand: sym.SymAnd,
|
||||||
SymKwAnd: SymAnd,
|
sym.SymKwAnd: sym.SymAnd,
|
||||||
SymDoubleVertBar: SymOr,
|
sym.SymDoubleVertBar: sym.SymOr,
|
||||||
SymKwOr: SymOr,
|
sym.SymKwOr: sym.SymOr,
|
||||||
// SymTilde: SymNot,
|
sym.SymKwNot: sym.SymNot,
|
||||||
SymKwNot: SymNot,
|
sym.SymLessGreater: sym.SymNotEqual,
|
||||||
SymLessGreater: SymNotEqual,
|
// SymTilde: sym.SymNot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +59,25 @@ func (scanner *Scanner) Current() *Token {
|
|||||||
return scanner.current
|
return scanner.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (scanner *Scanner) setUnreadChar(ch byte) {
|
||||||
|
scanner.column--
|
||||||
|
if scanner.column == 0 {
|
||||||
|
scanner.column = scanner.prevRowLength
|
||||||
|
scanner.row--
|
||||||
|
}
|
||||||
|
scanner.unreadByte = ch
|
||||||
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) readChar() (ch byte, err error) {
|
func (scanner *Scanner) readChar() (ch byte, err error) {
|
||||||
if ch, err = scanner.stream.ReadByte(); err == nil {
|
if scanner.unreadByte != 0 {
|
||||||
|
ch = scanner.unreadByte
|
||||||
|
scanner.unreadByte = 0
|
||||||
|
} else {
|
||||||
|
ch, err = scanner.stream.ReadByte()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
|
scanner.prevRowLength = scanner.column
|
||||||
scanner.row++
|
scanner.row++
|
||||||
scanner.column = 0
|
scanner.column = 0
|
||||||
} else {
|
} else {
|
||||||
@@ -128,237 +146,237 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) {
|
|||||||
switch ch {
|
switch ch {
|
||||||
case '+':
|
case '+':
|
||||||
if next, _ := scanner.peek(); next == '+' {
|
if next, _ := scanner.peek(); next == '+' {
|
||||||
tk = scanner.moveOn(SymDoublePlus, ch, next)
|
tk = scanner.moveOn(sym.SymDoublePlus, ch, next)
|
||||||
} else if next == '=' {
|
} else if next == '=' {
|
||||||
tk = scanner.moveOn(SymPlusEqual, ch, next)
|
tk = scanner.moveOn(sym.SymPlusEqual, ch, next)
|
||||||
} else if next == '>' {
|
} else if next == '>' {
|
||||||
tk = scanner.moveOn(SymPlusGreater, ch, next)
|
tk = scanner.moveOn(sym.SymPlusGreater, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymPlus, ch)
|
tk = scanner.MakeToken(sym.SymPlus, ch)
|
||||||
}
|
}
|
||||||
case '-':
|
case '-':
|
||||||
if next, _ := scanner.peek(); next == '-' {
|
if next, _ := scanner.peek(); next == '-' {
|
||||||
tk = scanner.moveOn(SymDoubleMinus, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleMinus, ch, next)
|
||||||
} else if next == '=' {
|
} else if next == '=' {
|
||||||
tk = scanner.moveOn(SymMinusEqual, ch, next)
|
tk = scanner.moveOn(sym.SymMinusEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymMinus, ch)
|
tk = scanner.MakeToken(sym.SymMinus, ch)
|
||||||
}
|
}
|
||||||
case '*':
|
case '*':
|
||||||
if next, _ := scanner.peek(); next == '*' {
|
if next, _ := scanner.peek(); next == '*' {
|
||||||
tk = scanner.moveOn(SymDoubleStar, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleStar, ch, next)
|
||||||
// } else if next == '/' {
|
// } else if next == '/' {
|
||||||
// tk = self.moveOn(SymClosedComment, ch, next)
|
// tk = self.moveOn(SymClosedComment, ch, next)
|
||||||
} else if next, _ = scanner.peek(); next == '=' {
|
} else if next, _ = scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymStarEqual, ch, next)
|
tk = scanner.moveOn(sym.SymStarEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymStar, ch)
|
tk = scanner.MakeToken(sym.SymStar, ch)
|
||||||
}
|
}
|
||||||
case '/':
|
case '/':
|
||||||
if next, _ := scanner.peek(); next == '*' {
|
if next, _ := scanner.peek(); next == '*' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.fetchBlockComment()
|
tk = scanner.fetchBlockComment()
|
||||||
} else if next, _ = scanner.peek(); next == '=' {
|
} else if next, _ = scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymSlashEqual, ch, next)
|
tk = scanner.moveOn(sym.SymSlashEqual, ch, next)
|
||||||
} else if next == '/' {
|
} else if next == '/' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.fetchOnLineComment()
|
tk = scanner.fetchOnLineComment()
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymSlash, ch)
|
tk = scanner.MakeToken(sym.SymSlash, ch)
|
||||||
}
|
}
|
||||||
case '\\':
|
case '\\':
|
||||||
if escape {
|
if escape {
|
||||||
tk = scanner.MakeToken(SymBackSlash, ch)
|
tk = scanner.MakeToken(sym.SymBackSlash, ch)
|
||||||
escape = false
|
escape = false
|
||||||
} else {
|
} else {
|
||||||
escape = true
|
escape = true
|
||||||
}
|
}
|
||||||
case '|':
|
case '|':
|
||||||
if next, _ := scanner.peek(); next == '|' {
|
if next, _ := scanner.peek(); next == '|' {
|
||||||
tk = scanner.moveOn(SymDoubleVertBar, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleVertBar, ch, next)
|
||||||
} else if next, _ = scanner.peek(); next == '=' {
|
} else if next, _ = scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymVertBarEqual, ch, next)
|
tk = scanner.moveOn(sym.SymVertBarEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymVertBar, ch)
|
tk = scanner.MakeToken(sym.SymVertBar, ch)
|
||||||
}
|
}
|
||||||
case ',':
|
case ',':
|
||||||
tk = scanner.MakeToken(SymComma, ch)
|
tk = scanner.MakeToken(sym.SymComma, ch)
|
||||||
case '^':
|
case '^':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymCaretEqual, ch, next)
|
tk = scanner.moveOn(sym.SymCaretEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymCaret, ch)
|
tk = scanner.MakeToken(sym.SymCaret, ch)
|
||||||
}
|
}
|
||||||
case ':':
|
case ':':
|
||||||
if next, _ := scanner.peek(); next == ':' {
|
if next, _ := scanner.peek(); next == ':' {
|
||||||
tk = scanner.moveOn(SymDoubleColon, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleColon, ch, next)
|
||||||
} else if next == '=' {
|
} else if next == '=' {
|
||||||
tk = scanner.moveOn(SymColonEqual, ch, next)
|
tk = scanner.moveOn(sym.SymColonEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymColon, ch)
|
tk = scanner.MakeToken(sym.SymColon, ch)
|
||||||
}
|
}
|
||||||
case ';':
|
case ';':
|
||||||
tk = scanner.MakeToken(SymSemiColon, ch)
|
tk = scanner.MakeToken(sym.SymSemiColon, ch)
|
||||||
case '.':
|
case '.':
|
||||||
//if next, _ := self.peek(); next >= '0' && next <= '9' {
|
//if next, _ := self.peek(); next >= '0' && next <= '9' {
|
||||||
// tk = self.parseNumber(ch)
|
// tk = self.parseNumber(ch)
|
||||||
//} else if next == '/' {
|
//} else if next == '/' {
|
||||||
if next, _ := scanner.peek(); next == '/' {
|
if next, _ := scanner.peek(); next == '/' {
|
||||||
tk = scanner.moveOn(SymDotSlash, ch, next)
|
tk = scanner.moveOn(sym.SymDotSlash, ch, next)
|
||||||
} else if next == '.' {
|
} else if next == '.' {
|
||||||
|
tk = scanner.moveOn(sym.SymDoubleDot, ch, next)
|
||||||
|
// TODO: this section needs verification
|
||||||
if next1, _ := scanner.peek(); next1 == '.' {
|
if next1, _ := scanner.peek(); next1 == '.' {
|
||||||
tk = scanner.moveOn(SymTripleDot, ch, next, next1)
|
tk = scanner.moveOn(sym.SymTripleDot, next, next1)
|
||||||
} else {
|
|
||||||
tk = scanner.moveOn(SymDoubleDot, ch, next)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymDot, ch)
|
tk = scanner.MakeToken(sym.SymDot, ch)
|
||||||
}
|
}
|
||||||
case '\'':
|
case '\'':
|
||||||
if escape {
|
if escape {
|
||||||
tk = scanner.MakeToken(SymQuote, ch)
|
tk = scanner.MakeToken(sym.SymQuote, ch)
|
||||||
escape = false
|
escape = false
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.fetchString(ch, true)
|
tk = scanner.fetchString(ch, true)
|
||||||
}
|
}
|
||||||
case '"':
|
case '"':
|
||||||
if escape {
|
if escape {
|
||||||
tk = scanner.MakeToken(SymDoubleQuote, ch)
|
tk = scanner.MakeToken(sym.SymDoubleQuote, ch)
|
||||||
escape = false
|
escape = false
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.fetchString(ch, true)
|
tk = scanner.fetchString(ch, true)
|
||||||
}
|
}
|
||||||
case '`':
|
case '`':
|
||||||
tk = scanner.MakeToken(SymBackTick, ch)
|
tk = scanner.MakeToken(sym.SymBackTick, ch)
|
||||||
case '!':
|
case '!':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymNotEqual, ch, next)
|
tk = scanner.moveOn(sym.SymNotEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymExclamation, ch)
|
tk = scanner.MakeToken(sym.SymExclamation, ch)
|
||||||
}
|
}
|
||||||
case '?':
|
case '?':
|
||||||
if next, _ := scanner.peek(); next == '?' {
|
if next, _ := scanner.peek(); next == '?' {
|
||||||
tk = scanner.moveOn(SymDoubleQuestion, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleQuestion, ch, next)
|
||||||
} else if next == '=' {
|
} else if next == '=' {
|
||||||
tk = scanner.moveOn(SymQuestionEqual, ch, next)
|
tk = scanner.moveOn(sym.SymQuestionEqual, ch, next)
|
||||||
} else if next == '!' {
|
} else if next == '!' {
|
||||||
tk = scanner.moveOn(SymQuestionExclam, ch, next)
|
tk = scanner.moveOn(sym.SymQuestionExclam, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymQuestion, ch)
|
tk = scanner.MakeToken(sym.SymQuestion, ch)
|
||||||
}
|
}
|
||||||
case '&':
|
case '&':
|
||||||
if next, _ := scanner.peek(); next == '&' {
|
if next, _ := scanner.peek(); next == '&' {
|
||||||
tk = scanner.moveOn(SymDoubleAmpersand, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleAmpersand, ch, next)
|
||||||
} else if next, _ = scanner.peek(); next == '=' {
|
} else if next, _ = scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymAmpersandEqual, ch, next)
|
tk = scanner.moveOn(sym.SymAmpersandEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymAmpersand, ch)
|
tk = scanner.MakeToken(sym.SymAmpersand, ch)
|
||||||
}
|
}
|
||||||
case '%':
|
case '%':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymPercEqual, ch, next)
|
tk = scanner.moveOn(sym.SymPercEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymPercent, ch)
|
tk = scanner.MakeToken(sym.SymPercent, ch)
|
||||||
}
|
}
|
||||||
case '#':
|
case '#':
|
||||||
tk = scanner.MakeToken(SymHash, ch)
|
tk = scanner.MakeToken(sym.SymHash, ch)
|
||||||
case '@':
|
case '@':
|
||||||
if next, _ := scanner.peek(); (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
if next, _ := scanner.peek(); (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
if tk = scanner.fetchIdentifier(next); tk.Sym == SymIdentifier {
|
if tk = scanner.fetchIdentifier(next); tk.Sym == sym.SymIdentifier {
|
||||||
//tk.Sym = SymIdRef
|
//tk.Sym = SymIdRef
|
||||||
tk.source = "@" + tk.source
|
tk.source = "@" + tk.source
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.makeErrorToken(fmt.Errorf("invalid variable reference %q", tk.source))
|
tk = scanner.makeErrorToken(fmt.Errorf("invalid variable reference %q", tk.source))
|
||||||
}
|
}
|
||||||
} else if next == '@' {
|
} else if next == '@' {
|
||||||
tk = scanner.moveOn(SymDoubleAt, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleAt, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymAt, ch)
|
tk = scanner.MakeToken(sym.SymAt, ch)
|
||||||
}
|
}
|
||||||
case '_':
|
case '_':
|
||||||
tk = scanner.MakeToken(SymUndescore, ch)
|
tk = scanner.MakeToken(sym.SymUndescore, ch)
|
||||||
case '=':
|
case '=':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymDoubleEqual, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleEqual, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymEqual, ch)
|
tk = scanner.MakeToken(sym.SymEqual, ch)
|
||||||
}
|
}
|
||||||
case '<':
|
case '<':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymLessOrEqual, ch, next)
|
tk = scanner.moveOn(sym.SymLessOrEqual, ch, next)
|
||||||
} else if next == '<' {
|
} else if next == '<' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
next2, _ := scanner.readChar()
|
next2, _ := scanner.readChar()
|
||||||
scanner.unreadChar()
|
scanner.unreadChar()
|
||||||
if next2 == '=' {
|
if next2 == '=' {
|
||||||
tk = scanner.moveOn(SymDoubleLessEqual, ch, next, next2)
|
tk = scanner.moveOn(sym.SymDoubleLessEqual, ch, next, next2)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.accept(SymDoubleLess, ch, next)
|
tk = scanner.accept(sym.SymDoubleLess, ch, next)
|
||||||
}
|
}
|
||||||
} else if next == '>' {
|
} else if next == '>' {
|
||||||
tk = scanner.moveOn(SymLessGreater, ch, next)
|
tk = scanner.moveOn(sym.SymLessGreater, ch, next)
|
||||||
} else if next == '+' {
|
} else if next == '+' {
|
||||||
tk = scanner.moveOn(SymLessPlus, ch, next)
|
tk = scanner.moveOn(sym.SymLessPlus, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymLess, ch)
|
tk = scanner.MakeToken(sym.SymLess, ch)
|
||||||
}
|
}
|
||||||
case '>':
|
case '>':
|
||||||
if next, _ := scanner.peek(); next == '=' {
|
if next, _ := scanner.peek(); next == '=' {
|
||||||
tk = scanner.moveOn(SymGreaterOrEqual, ch, next)
|
tk = scanner.moveOn(sym.SymGreaterOrEqual, ch, next)
|
||||||
} else if next == '>' {
|
} else if next == '>' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
next2, _ := scanner.readChar()
|
next2, _ := scanner.readChar()
|
||||||
scanner.unreadChar()
|
scanner.unreadChar()
|
||||||
if next2 == '=' {
|
if next2 == '=' {
|
||||||
tk = scanner.moveOn(SymDoubleGreaterEqual, ch, next, next2)
|
tk = scanner.moveOn(sym.SymDoubleGreaterEqual, ch, next, next2)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.accept(SymDoubleGreater, ch, next)
|
tk = scanner.accept(sym.SymDoubleGreater, ch, next)
|
||||||
}
|
}
|
||||||
} else if next == ']' {
|
} else if next == ']' {
|
||||||
tk = scanner.moveOn(SymGreaterClosedSquare, ch, next)
|
tk = scanner.moveOn(sym.SymGreaterClosedSquare, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymGreater, ch)
|
tk = scanner.MakeToken(sym.SymGreater, ch)
|
||||||
}
|
}
|
||||||
case '$':
|
case '$':
|
||||||
if next, _ := scanner.peek(); next == '(' {
|
if next, _ := scanner.peek(); next == '(' {
|
||||||
tk = scanner.moveOn(SymDollarRound, ch, next)
|
tk = scanner.moveOn(sym.SymDollarRound, ch, next)
|
||||||
tk.source += ")"
|
tk.source += ")"
|
||||||
} else if next == '$' {
|
} else if next == '$' {
|
||||||
tk = scanner.moveOn(SymDoubleDollar, ch, next)
|
tk = scanner.moveOn(sym.SymDoubleDollar, ch, next)
|
||||||
} else if next == '{' {
|
} else if next == '{' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
if tk = scanner.fetchString('}', false); tk != nil {
|
if tk = scanner.fetchString('}', false); tk != nil {
|
||||||
tk.Sym = SymIdentifier
|
tk.Sym = sym.SymIdentifier
|
||||||
}
|
}
|
||||||
} else if next == '_' || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
} else if next == '_' || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.fetchIdentifier(next)
|
tk = scanner.fetchIdentifier(next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymDollar, ch)
|
tk = scanner.MakeToken(sym.SymDollar, ch)
|
||||||
}
|
}
|
||||||
case '(':
|
case '(':
|
||||||
// if next, _ := scanner.peek(); next == ')' {
|
// if next, _ := scanner.peek(); next == ')' {
|
||||||
// tk = scanner.moveOn(SymOpenClosedRound, ch, next)
|
// tk = scanner.moveOn(SymOpenClosedRound, ch, next)
|
||||||
// } else {
|
// } else {
|
||||||
tk = scanner.MakeToken(SymOpenRound, ch)
|
tk = scanner.MakeToken(sym.SymOpenRound, ch)
|
||||||
// }
|
// }
|
||||||
case ')':
|
case ')':
|
||||||
tk = scanner.MakeToken(SymClosedRound, ch)
|
tk = scanner.MakeToken(sym.SymClosedRound, ch)
|
||||||
case '[':
|
case '[':
|
||||||
if next, _ := scanner.peek(); next == '<' {
|
if next, _ := scanner.peek(); next == '<' {
|
||||||
tk = scanner.moveOn(SymOpenSquareLess, ch, next)
|
tk = scanner.moveOn(sym.SymOpenSquareLess, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeToken(SymOpenSquare, ch)
|
tk = scanner.MakeToken(sym.SymOpenSquare, ch)
|
||||||
}
|
}
|
||||||
case ']':
|
case ']':
|
||||||
tk = scanner.MakeToken(SymClosedSquare, ch)
|
tk = scanner.MakeToken(sym.SymClosedSquare, ch)
|
||||||
case '{':
|
case '{':
|
||||||
tk = scanner.MakeToken(SymOpenBrace, ch)
|
tk = scanner.MakeToken(sym.SymOpenBrace, ch)
|
||||||
case '}':
|
case '}':
|
||||||
tk = scanner.MakeToken(SymClosedBrace, ch)
|
tk = scanner.MakeToken(sym.SymClosedBrace, ch)
|
||||||
case '~':
|
case '~':
|
||||||
tk = scanner.MakeToken(SymTilde, ch)
|
tk = scanner.MakeToken(sym.SymTilde, ch)
|
||||||
case 0:
|
case 0:
|
||||||
if escape {
|
if escape {
|
||||||
tk = scanner.makeErrorToken(errors.New("incomplete escape sequence"))
|
tk = scanner.makeErrorToken(errors.New("incomplete escape sequence"))
|
||||||
@@ -366,9 +384,9 @@ func (scanner *Scanner) fetchNextToken() (tk *Token) {
|
|||||||
escape = false
|
escape = false
|
||||||
default:
|
default:
|
||||||
if /*ch == '_' ||*/ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
|
if /*ch == '_' ||*/ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
|
||||||
if tk = scanner.fetchIdentifier(ch); tk.Sym == SymKwFunc {
|
if tk = scanner.fetchIdentifier(ch); tk.Sym == sym.SymKwFunc {
|
||||||
if next, _ := scanner.peek(); next == '(' {
|
if next, _ := scanner.peek(); next == '(' {
|
||||||
tk = scanner.moveOn(SymFuncDef, ch, next)
|
tk = scanner.moveOn(sym.SymFuncDef, ch, next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ch >= '0' && ch <= '9' {
|
} else if ch >= '0' && ch <= '9' {
|
||||||
@@ -416,19 +434,20 @@ func (scanner *Scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int
|
|||||||
numBase = 10
|
numBase = 10
|
||||||
|
|
||||||
if ch, err = scanner.peek(); err == nil {
|
if ch, err = scanner.peek(); err == nil {
|
||||||
if ch == 'b' || ch == 'B' {
|
switch ch {
|
||||||
|
case 'b', 'B':
|
||||||
numBase = 2
|
numBase = 2
|
||||||
digitType = "binary"
|
digitType = "binary"
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
digitFunc = isBinaryDigit
|
digitFunc = isBinaryDigit
|
||||||
firstCh, err = scanner.readChar()
|
firstCh, err = scanner.readChar()
|
||||||
} else if ch == 'o' || ch == 'O' {
|
case 'o', 'O':
|
||||||
numBase = 8
|
numBase = 8
|
||||||
digitType = "octal"
|
digitType = "octal"
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
digitFunc = isOctalDigit
|
digitFunc = isOctalDigit
|
||||||
firstCh, err = scanner.readChar()
|
firstCh, err = scanner.readChar()
|
||||||
} else if ch == 'x' || ch == 'X' {
|
case 'x', 'X':
|
||||||
numBase = 16
|
numBase = 16
|
||||||
digitType = "hex"
|
digitType = "hex"
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
@@ -450,7 +469,7 @@ func (scanner *Scanner) initBase(currentFirstCh byte) (firstCh byte, numBase int
|
|||||||
func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||||
var err error
|
var err error
|
||||||
var ch byte
|
var ch byte
|
||||||
var sym Symbol = SymInteger
|
var symbol sym.Symbol = sym.SymInteger
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
var isDigit func(byte) bool = isDecimalDigit
|
var isDigit func(byte) bool = isDecimalDigit
|
||||||
var numBase = 10
|
var numBase = 10
|
||||||
@@ -464,7 +483,11 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
|||||||
|
|
||||||
if numBase == 10 {
|
if numBase == 10 {
|
||||||
if err == nil && ch == '.' {
|
if err == nil && ch == '.' {
|
||||||
sym = SymFloat
|
if next, _ := scanner.peek(); next == '.' {
|
||||||
|
// do nothing, this is an interval operator
|
||||||
|
scanner.setUnreadChar('.')
|
||||||
|
} else {
|
||||||
|
symbol = sym.SymFloat
|
||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
ch, err = scanner.readChar()
|
ch, err = scanner.readChar()
|
||||||
if ch >= '0' && ch <= '9' {
|
if ch >= '0' && ch <= '9' {
|
||||||
@@ -473,9 +496,11 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if ch == 'e' || ch == 'E' {
|
switch ch {
|
||||||
sym = SymFloat
|
case 'e', 'E':
|
||||||
|
symbol = sym.SymFloat
|
||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
if ch, err = scanner.readChar(); err == nil {
|
if ch, err = scanner.readChar(); err == nil {
|
||||||
if ch == '+' || ch == '-' {
|
if ch == '+' || ch == '-' {
|
||||||
@@ -490,8 +515,8 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
|||||||
err = fmt.Errorf("[%d:%d] expected integer exponent, got %c", scanner.row, scanner.column, ch)
|
err = fmt.Errorf("[%d:%d] expected integer exponent, got %c", scanner.row, scanner.column, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ch == '(' {
|
case '(':
|
||||||
sym = SymFraction
|
symbol = sym.SymFraction
|
||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
ch, err = scanner.readChar()
|
ch, err = scanner.readChar()
|
||||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = scanner.readChar() {
|
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = scanner.readChar() {
|
||||||
@@ -515,18 +540,21 @@ func (scanner *Scanner) parseNumber(firstCh byte) (tk *Token) {
|
|||||||
var value any
|
var value any
|
||||||
_ = scanner.sync(err) // TODO: Check this function
|
_ = scanner.sync(err) // TODO: Check this function
|
||||||
txt := sb.String()
|
txt := sb.String()
|
||||||
if sym == SymFloat {
|
switch symbol {
|
||||||
|
case sym.SymFloat:
|
||||||
value, err = strconv.ParseFloat(txt, 64)
|
value, err = strconv.ParseFloat(txt, 64)
|
||||||
} else if sym == SymFraction {
|
case sym.SymFraction:
|
||||||
value, err = kern.MakeGeneratingFraction(txt)
|
// value, err = kern.MakeGeneratingFraction(txt)
|
||||||
} else {
|
value = txt
|
||||||
|
default:
|
||||||
value, err = strconv.ParseInt(txt, numBase, 64)
|
value, err = strconv.ParseInt(txt, numBase, 64)
|
||||||
}
|
}
|
||||||
if err == nil {
|
tk = scanner.MakeValueToken(symbol, txt, value)
|
||||||
tk = scanner.MakeValueToken(sym, txt, value)
|
// if err == nil {
|
||||||
} else {
|
// tk = scanner.MakeValueToken(sym, txt, value)
|
||||||
tk = scanner.makeErrorToken(err)
|
// } else {
|
||||||
}
|
// tk = scanner.makeErrorToken(err)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -545,17 +573,17 @@ func (scanner *Scanner) fetchIdentifier(firstCh byte) (tk *Token) {
|
|||||||
} else {
|
} else {
|
||||||
txt := sb.String()
|
txt := sb.String()
|
||||||
uptxt := strings.ToUpper(txt)
|
uptxt := strings.ToUpper(txt)
|
||||||
if sym, ok := keywords[uptxt]; ok {
|
if symbol, ok := sym.Keywords[uptxt]; ok {
|
||||||
tk = scanner.makeKeywordToken(sym, uptxt)
|
tk = scanner.makeKeywordToken(symbol, uptxt)
|
||||||
} else if uptxt == `TRUE` {
|
} else if uptxt == `TRUE` {
|
||||||
tk = scanner.MakeValueToken(SymBool, txt, true)
|
tk = scanner.MakeValueToken(sym.SymBool, txt, true)
|
||||||
} else if uptxt == `FALSE` {
|
} else if uptxt == `FALSE` {
|
||||||
tk = scanner.MakeValueToken(SymBool, txt, false)
|
tk = scanner.MakeValueToken(sym.SymBool, txt, false)
|
||||||
} else if ch, _ := scanner.peek(); ch == '(' {
|
} else if ch, _ := scanner.peek(); ch == '(' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.MakeValueToken(SymFuncCall, txt+"(", txt)
|
tk = scanner.MakeValueToken(sym.SymFuncCall, txt+"(", txt)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeValueToken(SymIdentifier, txt, txt)
|
tk = scanner.MakeValueToken(sym.SymIdentifier, txt, txt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,14 +604,14 @@ func (scanner *Scanner) fetchIdentifier(firstCh byte) (tk *Token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) fetchBlockComment() *Token {
|
func (scanner *Scanner) fetchBlockComment() *Token {
|
||||||
return scanner.fetchUntil(SymComment, false, '*', '/')
|
return scanner.fetchUntil(sym.SymComment, false, '*', '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) fetchOnLineComment() *Token {
|
func (scanner *Scanner) fetchOnLineComment() *Token {
|
||||||
return scanner.fetchUntil(SymComment, true, '\n')
|
return scanner.fetchUntil(sym.SymComment, true, '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (tk *Token) {
|
func (scanner *Scanner) fetchUntil(sym sym.Symbol, allowEos bool, endings ...byte) (tk *Token) {
|
||||||
var err error
|
var err error
|
||||||
var ch byte
|
var ch byte
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
@@ -652,9 +680,9 @@ func (scanner *Scanner) fetchString(termCh byte, addQuote bool) (tk *Token) {
|
|||||||
} else {
|
} else {
|
||||||
txt := sb.String()
|
txt := sb.String()
|
||||||
if addQuote {
|
if addQuote {
|
||||||
tk = scanner.MakeValueToken(SymString, `"`+txt+`"`, txt)
|
tk = scanner.MakeValueToken(sym.SymString, `"`+txt+`"`, txt)
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.MakeValueToken(SymString, txt, txt)
|
tk = scanner.MakeValueToken(sym.SymString, txt, txt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -676,7 +704,7 @@ func (scanner *Scanner) skipBlanks() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) translate(sym Symbol) Symbol {
|
func (scanner *Scanner) translate(sym sym.Symbol) sym.Symbol {
|
||||||
if scanner.translations != nil {
|
if scanner.translations != nil {
|
||||||
if translatedSym, ok := scanner.translations[sym]; ok {
|
if translatedSym, ok := scanner.translations[sym]; ok {
|
||||||
return translatedSym
|
return translatedSym
|
||||||
@@ -685,7 +713,7 @@ func (scanner *Scanner) translate(sym Symbol) Symbol {
|
|||||||
return sym
|
return sym
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
|
func (scanner *Scanner) moveOn(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||||
// for i := 1; i < len(chars); i++ {
|
// for i := 1; i < len(chars); i++ {
|
||||||
if len(chars) > 1 {
|
if len(chars) > 1 {
|
||||||
@@ -695,22 +723,22 @@ func (scanner *Scanner) moveOn(sym Symbol, chars ...byte) (tk *Token) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) accept(sym Symbol, chars ...byte) (tk *Token) {
|
func (scanner *Scanner) accept(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) MakeToken(sym Symbol, chars ...byte) (tk *Token) {
|
func (scanner *Scanner) MakeToken(sym sym.Symbol, chars ...byte) (tk *Token) {
|
||||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), string(chars))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) makeKeywordToken(sym Symbol, upperCaseKeyword string) (tk *Token) {
|
func (scanner *Scanner) makeKeywordToken(sym sym.Symbol, upperCaseKeyword string) (tk *Token) {
|
||||||
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), upperCaseKeyword)
|
tk = NewToken(scanner.row, scanner.column, scanner.translate(sym), upperCaseKeyword)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scanner *Scanner) MakeValueToken(sym Symbol, source string, value any) (tk *Token) {
|
func (scanner *Scanner) MakeValueToken(sym sym.Symbol, source string, value any) (tk *Token) {
|
||||||
tk = NewValueToken(scanner.row, scanner.column, scanner.translate(sym), source, value)
|
tk = NewValueToken(scanner.row, scanner.column, scanner.translate(sym), source, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+132
-129
@@ -1,14 +1,16 @@
|
|||||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// Symbol.go
|
// symbol-map.go
|
||||||
package scan
|
package scan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
var symbolMap map[Symbol]symbolSpec
|
var symbolMap map[sym.Symbol]symbolSpec
|
||||||
|
|
||||||
type SymbolClass int16
|
type SymbolClass int16
|
||||||
|
|
||||||
@@ -31,138 +33,139 @@ type symbolSpec struct {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
symbolMap = map[Symbol]symbolSpec{
|
symbolMap = map[sym.Symbol]symbolSpec{
|
||||||
SymUnknown: {"<unknown>", SymClassOther, PosLeaf}, // -1: Unknown symbol
|
sym.SymUnknown: {"<unknown>", SymClassOther, PosLeaf}, // -1: Unknown symbol
|
||||||
SymNone: {"<null>", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol
|
sym.SymNone: {"<null>", SymClassOther, PosLeaf}, // 0: Null value for variable of type symbol
|
||||||
SymError: {"<error>", SymClassOther, PosLeaf}, // 1: Error reading from stream
|
sym.SymError: {"<error>", SymClassOther, PosLeaf}, // 1: Error reading from stream
|
||||||
SymEos: {"<eos>", SymClassOther, PosLeaf}, // 2: End of stream
|
sym.SymEos: {"<eos>", SymClassOther, PosLeaf}, // 2: End of stream
|
||||||
SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-'
|
sym.SymMinus: {"-", SymClassOperator, PosInfix}, // 3: '-'
|
||||||
SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-='
|
sym.SymMinusEqual: {"-=", SymClassOperator, PosInfix}, // 4: '-='
|
||||||
SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--'
|
sym.SymDoubleMinus: {"--", SymClassOperator, PosPostfix}, // 5: '--'
|
||||||
SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+'
|
sym.SymPlus: {"+", SymClassOperator, PosInfix}, // 6: '+'
|
||||||
SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+='
|
sym.SymPlusEqual: {"+=", SymClassOperator, PosInfix}, // 7: '+='
|
||||||
SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++'
|
sym.SymDoublePlus: {"++", SymClassOperator, PosPostfix}, // 8: '++'
|
||||||
SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*'
|
sym.SymStar: {"*", SymClassOperator, PosInfix}, // 9: '*'
|
||||||
SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**'
|
sym.SymDoubleStar: {"**", SymClassOperator, PosInfix}, // 10: '**'
|
||||||
SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/'
|
sym.SymSlash: {"/", SymClassOperator, PosInfix}, // 11: '/'
|
||||||
SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\'
|
sym.SymBackSlash: {"\\", SymClassOperator, PosLeaf}, // 12: '\'
|
||||||
SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|'
|
sym.SymVertBar: {"|", SymClassOperator, PosInfix}, // 13: '|'
|
||||||
SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||'
|
sym.SymDoubleVertBar: {"||", SymClassOperator, PosInfix}, // 14: '||'
|
||||||
SymComma: {",", SymClassOperator, PosInfix}, // 15: ','
|
sym.SymComma: {",", SymClassOperator, PosInfix}, // 15: ','
|
||||||
SymColon: {":", SymClassOperator, PosInfix}, // 16: ':'
|
sym.SymColon: {":", SymClassOperator, PosInfix}, // 16: ':'
|
||||||
SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';'
|
sym.SymSemiColon: {";", SymClassOperator, PosInfix}, // 17: ';'
|
||||||
SymDot: {".", SymClassOperator, PosInfix}, // 18: '.'
|
sym.SymDot: {".", SymClassOperator, PosInfix}, // 18: '.'
|
||||||
SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './'
|
sym.SymDotSlash: {"./", SymClassOperator, PosInfix}, // 19: './'
|
||||||
SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\''
|
sym.SymQuote: {"'", SymClassDelimiter, PosLeaf}, // 20: '\''
|
||||||
SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"'
|
sym.SymDoubleQuote: {"\"", SymClassDelimiter, PosLeaf}, // 21: '"'
|
||||||
SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`'
|
sym.SymBackTick: {"`", SymClassDelimiter, PosLeaf}, // 22: '`'
|
||||||
SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!'
|
sym.SymExclamation: {"!", SymClassOperator, PosPostfix}, // 23: '!'
|
||||||
SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?'
|
sym.SymQuestion: {"?", SymClassOperator, PosInfix}, // 24: '?'
|
||||||
SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&'
|
sym.SymAmpersand: {"&", SymClassOperator, PosInfix}, // 25: '&'
|
||||||
SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&'
|
sym.SymDoubleAmpersand: {"&&", SymClassOperator, PosInfix}, // 26: '&&'
|
||||||
SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%'
|
sym.SymPercent: {"%", SymClassOperator, PosInfix}, // 27: '%'
|
||||||
SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@'
|
sym.SymAt: {"@", SymClassOperator, PosPrefix}, // 28: '@'
|
||||||
SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_'
|
sym.SymUndescore: {"_", SymClassIdentifier, PosLeaf}, // 29: '_'
|
||||||
SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '='
|
sym.SymEqual: {"=", SymClassOperator, PosInfix}, // 30: '='
|
||||||
SymColonEqual: {":=", SymClassOperator, PosInfix}, // 31: ':='
|
sym.SymColonEqual: {":=", SymClassOperator, PosInfix}, // 31: ':='
|
||||||
SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 32: '=='
|
sym.SymDoubleEqual: {"==", SymClassOperator, PosInfix}, // 32: '=='
|
||||||
SymLess: {"<", SymClassOperator, PosInfix}, // 33: '<'
|
sym.SymLess: {"<", SymClassOperator, PosInfix}, // 33: '<'
|
||||||
SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 34: '<='
|
sym.SymLessOrEqual: {"<=", SymClassOperator, PosInfix}, // 34: '<='
|
||||||
SymGreater: {">", SymClassOperator, PosInfix}, // 35: '>'
|
sym.SymGreater: {">", SymClassOperator, PosInfix}, // 35: '>'
|
||||||
SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 36: '>='
|
sym.SymGreaterOrEqual: {">=", SymClassOperator, PosInfix}, // 36: '>='
|
||||||
SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 37: '<>'
|
sym.SymLessGreater: {"<>", SymClassOperator, PosInfix}, // 37: '<>'
|
||||||
SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 38: '!='
|
sym.SymNotEqual: {"!=", SymClassOperator, PosInfix}, // 38: '!='
|
||||||
SymDollar: {"$", SymClassOperator, PosPrefix}, // 39: '$'
|
sym.SymDollar: {"$", SymClassOperator, PosPrefix}, // 39: '$'
|
||||||
SymHash: {"#", SymClassOperator, PosPrefix}, // 40: '#'
|
sym.SymHash: {"#", SymClassOperator, PosPrefix}, // 40: '#'
|
||||||
SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 41: '('
|
sym.SymOpenRound: {"(", SymClassParenthesis, PosPrefix}, // 41: '('
|
||||||
SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 42: ')'
|
sym.SymClosedRound: {")", SymClassParenthesis, PosPostfix}, // 42: ')'
|
||||||
SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 43: '['
|
sym.SymOpenSquare: {"[", SymClassParenthesis, PosPrefix}, // 43: '['
|
||||||
SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 44: ']'
|
sym.SymClosedSquare: {"]", SymClassParenthesis, PosPostfix}, // 44: ']'
|
||||||
SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 45: '{'
|
sym.SymOpenBrace: {"{", SymClassParenthesis, PosPrefix}, // 45: '{'
|
||||||
SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 46: '}'
|
sym.SymClosedBrace: {"}", SymClassParenthesis, PosPostfix}, // 46: '}'
|
||||||
SymTilde: {"~", SymClassOperator, PosPrefix}, // 47: '~'
|
sym.SymTilde: {"~", SymClassOperator, PosPrefix}, // 47: '~'
|
||||||
SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 48: '??'
|
sym.SymDoubleQuestion: {"??", SymClassOperator, PosInfix}, // 48: '??'
|
||||||
SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 49: '?='
|
sym.SymQuestionEqual: {"?=", SymClassOperator, PosInfix}, // 49: '?='
|
||||||
SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 50: '?!'
|
sym.SymQuestionExclam: {"?!", SymClassOperator, PosInfix}, // 50: '?!'
|
||||||
SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 51: '@@'
|
sym.SymDoubleAt: {"@@", SymClassCommand, PosLeaf}, // 51: '@@'
|
||||||
SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 52: '::'
|
sym.SymDoubleColon: {"::", SymClassOperator, PosInfix}, // 52: '::'
|
||||||
SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 53: '>>'
|
sym.SymDoubleGreater: {">>", SymClassOperator, PosInfix}, // 53: '>>'
|
||||||
SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 54: '<<'
|
sym.SymDoubleLess: {"<<", SymClassOperator, PosInfix}, // 54: '<<'
|
||||||
SymCaret: {"^", SymClassOperator, PosInfix}, // 55: '^'
|
sym.SymCaret: {"^", SymClassOperator, PosInfix}, // 55: '^'
|
||||||
SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 56: '$('
|
sym.SymDollarRound: {"$(", SymClassOperator, PosPrefix}, // 56: '$('
|
||||||
SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 57: '()'
|
sym.SymOpenClosedRound: {"()", SymClassOperator, PosPostfix}, // 57: '()'
|
||||||
SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 58: '$$'
|
sym.SymDoubleDollar: {"$$", SymClassCommand, PosLeaf}, // 58: '$$'
|
||||||
SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 59: '..'
|
sym.SymDoubleDot: {"..", SymClassOperator, PosInfix}, // 59: '..'
|
||||||
SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 60: '...'
|
sym.SymTripleDot: {"...", SymClassOperator, PosPostfix}, // 60: '...'
|
||||||
SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 61: '*='
|
sym.SymStarEqual: {"*=", SymClassOperator, PosInfix}, // 61: '*='
|
||||||
SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 62: '/='
|
sym.SymSlashEqual: {"/=", SymClassOperator, PosInfix}, // 62: '/='
|
||||||
SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 63: '%='
|
sym.SymPercEqual: {"%=", SymClassOperator, PosInfix}, // 63: '%='
|
||||||
SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 64: '<<='
|
sym.SymDoubleLessEqual: {"<<=", SymClassOperator, PosInfix}, // 64: '<<='
|
||||||
SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 65: '>>='
|
sym.SymDoubleGreaterEqual: {">>=", SymClassOperator, PosInfix}, // 65: '>>='
|
||||||
SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 66: '&='
|
sym.SymAmpersandEqual: {"&=", SymClassOperator, PosInfix}, // 66: '&='
|
||||||
SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 67: '|='
|
sym.SymVertBarEqual: {"|=", SymClassOperator, PosInfix}, // 67: '|='
|
||||||
SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 68: '^='
|
sym.SymCaretEqual: {"^=", SymClassOperator, PosInfix}, // 68: '^='
|
||||||
SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 69: '+>'
|
sym.SymPlusGreater: {"+>", SymClassOperator, PosInfix}, // 69: '+>'
|
||||||
SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 70: '<+'
|
sym.SymLessPlus: {"<+", SymClassOperator, PosInfix}, // 70: '<+'
|
||||||
SymPreInc: {"++", SymClassOperator, PosPrefix}, // 71: '++'
|
sym.SymPreInc: {"++", SymClassOperator, PosPrefix}, // 71: '++'
|
||||||
SymPreDec: {"--", SymClassOperator, PosPrefix}, // 72: '--'
|
sym.SymPreDec: {"--", SymClassOperator, PosPrefix}, // 72: '--'
|
||||||
SymOpenSquareLess: {"[<", SymClassOperator, PosPrefix}, // 97: '[<'
|
sym.SymOpenSquareLess: {"[<", SymClassOperator, PosPrefix}, // 97: '[<'
|
||||||
SymGreaterClosedSquare: {">]", SymClassOperator, PosPostfix}, // 98: '>]'
|
sym.SymGreaterClosedSquare: {">]", SymClassOperator, PosPostfix}, // 98: '>]'
|
||||||
// SymChangeSign
|
// sym.SymChangeSign
|
||||||
// SymUnchangeSign
|
// sym.SymUnchangeSign
|
||||||
// SymIdentifier
|
// sym.SymIdentifier
|
||||||
// SymBool
|
// sym.SymBool
|
||||||
// SymInteger
|
// sym.SymInteger
|
||||||
// SymVariable
|
// sym.SymVariable
|
||||||
// SymFloat
|
// sym.SymFloat
|
||||||
// SymFraction
|
// sym.SymFraction
|
||||||
// SymString
|
// sym.SymString
|
||||||
// SymIterator
|
// sym.SymIterator
|
||||||
// SymOr: "or",
|
// sym.SymOr: "or",
|
||||||
// SymAnd: "and",
|
// sym.SymAnd: "and",
|
||||||
// SymNot: "not",
|
// sym.SymNot: "not",
|
||||||
// SymComment
|
// sym.SymComment
|
||||||
// SymFuncCall
|
// sym.SymFuncCall
|
||||||
// SymFuncDef
|
// sym.SymFuncDef
|
||||||
// SymList
|
// sym.SymList
|
||||||
// SymLinkedList
|
// sym.SymLinkedList
|
||||||
// SymDict
|
// sym.SymDict
|
||||||
// SymIndex
|
// sym.SymIndex
|
||||||
// SymExpression
|
// sym.SymExpression
|
||||||
// SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
// sym.SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||||
// SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
// sym.SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||||
// // SymOpenComment // 0: '/*'
|
// // sym.SymOpenComment // 0: '/*'
|
||||||
// // SymClosedComment // 0: '*/'
|
// // sym.SymClosedComment // 0: '*/'
|
||||||
// // SymOneLineComment // 0: '//'
|
// // sym.SymOneLineComment // 0: '//'
|
||||||
// keywordBase
|
// keywordBase
|
||||||
SymKwAnd: {"and", SymClassOperator, PosInfix},
|
sym.SymKwAnd: {"and", SymClassOperator, PosInfix},
|
||||||
SymKwNot: {"not", SymClassOperator, PosInfix},
|
sym.SymKwNot: {"not", SymClassOperator, PosInfix},
|
||||||
SymKwOr: {"or", SymClassOperator, PosInfix},
|
sym.SymKwOr: {"or", SymClassOperator, PosInfix},
|
||||||
SymKwBut: {"but", SymClassOperator, PosInfix},
|
sym.SymKwBut: {"but", SymClassOperator, PosInfix},
|
||||||
SymKwMap: {"map", SymClassOperator, PosInfix},
|
sym.SymKwMap: {"map", SymClassOperator, PosInfix},
|
||||||
SymKwFilter: {"filter", SymClassOperator, PosInfix},
|
sym.SymKwFilter: {"filter", SymClassOperator, PosInfix},
|
||||||
SymKwDigest: {"digest", SymClassOperator, PosInfix},
|
sym.SymKwDigest: {"digest", SymClassOperator, PosInfix},
|
||||||
SymKwCat: {"cat", SymClassOperator, PosInfix},
|
sym.SymKwCat: {"cat", SymClassOperator, PosInfix},
|
||||||
SymKwJoin: {"join", SymClassOperator, PosInfix},
|
sym.SymKwJoin: {"join", SymClassOperator, PosInfix},
|
||||||
SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
|
sym.SymKwGroupBy: {"groupby", SymClassOperator, PosInfix},
|
||||||
SymKwFunc: {"func(", SymClassDeclaration, PosPrefix},
|
sym.SymKwFunc: {"func(", SymClassDeclaration, PosPrefix},
|
||||||
SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
|
sym.SymKwBuiltin: {"builtin", SymClassOperator, PosPrefix},
|
||||||
SymKwPlugin: {"plugin", SymClassOperator, PosPrefix},
|
sym.SymKwPlugin: {"plugin", SymClassOperator, PosPrefix},
|
||||||
SymKwIn: {"in", SymClassOperator, PosInfix},
|
sym.SymKwIn: {"in", SymClassOperator, PosInfix},
|
||||||
SymKwInclude: {"include", SymClassOperator, PosPrefix},
|
sym.SymKwAt: {"at", SymClassOperator, PosInfix},
|
||||||
SymKwNil: {"nil", SymClassValue, PosLeaf},
|
sym.SymKwInclude: {"include", SymClassOperator, PosPrefix},
|
||||||
SymKwUnset: {"unset", SymClassOperator, PosPrefix},
|
sym.SymKwNil: {"nil", SymClassValue, PosLeaf},
|
||||||
|
sym.SymKwUnset: {"unset", SymClassOperator, PosPrefix},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SymToString(sym Symbol) string {
|
func SymToString(sym sym.Symbol) string {
|
||||||
if s, ok := symbolMap[sym]; ok {
|
if s, ok := symbolMap[sym]; ok {
|
||||||
return s.repr
|
return s.repr
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func SymListToString(symList []Symbol, quote bool) string {
|
func SymListToString(symList []sym.Symbol, quote bool) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
if len(symList) == 0 {
|
if len(symList) == 0 {
|
||||||
sb.WriteString("<nothing>")
|
sb.WriteString("<nothing>")
|
||||||
@@ -185,13 +188,13 @@ func SymListToString(symList []Symbol, quote bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StringEndsWithOperator(s string) bool {
|
func StringEndsWithOperator(s string) bool {
|
||||||
return endingOperator(s) != SymNone
|
return endingOperator(s) != sym.SymNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func endingOperator(s string) (sym Symbol) {
|
func endingOperator(s string) (resultSym sym.Symbol) {
|
||||||
var matchLength = 0
|
var matchLength = 0
|
||||||
var repr string
|
var repr string
|
||||||
sym = SymNone
|
resultSym = sym.SymNone
|
||||||
lower := strings.TrimRight(strings.ToLower(s), " \t")
|
lower := strings.TrimRight(strings.ToLower(s), " \t")
|
||||||
for symbol, spec := range symbolMap {
|
for symbol, spec := range symbolMap {
|
||||||
if len(spec.repr) > matchLength || repr == spec.repr {
|
if len(spec.repr) > matchLength || repr == spec.repr {
|
||||||
@@ -199,9 +202,9 @@ func endingOperator(s string) (sym Symbol) {
|
|||||||
if isNotEndingSymbol(spec) && repr != spec.repr {
|
if isNotEndingSymbol(spec) && repr != spec.repr {
|
||||||
repr = spec.repr
|
repr = spec.repr
|
||||||
matchLength = len(spec.repr)
|
matchLength = len(spec.repr)
|
||||||
sym = symbol
|
resultSym = symbol
|
||||||
} else {
|
} else {
|
||||||
sym = SymNone
|
resultSym = sym.SymNone
|
||||||
break
|
break
|
||||||
// matchLength = 0
|
// matchLength = 0
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-44
@@ -10,59 +10,58 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScanner(t *testing.T) {
|
func TestScanner(t *testing.T) {
|
||||||
type inputType struct {
|
type inputType struct {
|
||||||
source string
|
source string
|
||||||
wantSym Symbol
|
wantSym sym.Symbol
|
||||||
wantValue any
|
wantValue any
|
||||||
wantErr error
|
wantErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`123`, SymInteger, int64(123), nil},
|
/* 1 */ {`123`, sym.SymInteger, int64(123), nil},
|
||||||
/* 2 */ {"=", SymEqual, nil, nil},
|
/* 2 */ {"=", sym.SymEqual, nil, nil},
|
||||||
/* 3 */ {`--`, SymDoubleMinus, nil, nil},
|
/* 3 */ {`--`, sym.SymDoubleMinus, nil, nil},
|
||||||
/* 4 */ {`++`, SymDoublePlus, nil, nil},
|
/* 4 */ {`++`, sym.SymDoublePlus, nil, nil},
|
||||||
/* 5 */ {`**`, SymDoubleStar, nil, nil},
|
/* 5 */ {`**`, sym.SymDoubleStar, nil, nil},
|
||||||
/* 6 */ {`&&`, SymDoubleAmpersand, nil, nil},
|
/* 6 */ {`&&`, sym.SymDoubleAmpersand, nil, nil},
|
||||||
/* 7 */ {`||`, SymDoubleVertBar, nil, nil},
|
/* 7 */ {`||`, sym.SymDoubleVertBar, nil, nil},
|
||||||
/* 8 */ {`NOT`, SymKwNot, nil, nil},
|
/* 8 */ {`NOT`, sym.SymKwNot, nil, nil},
|
||||||
/* 9 */ {`AND`, SymKwAnd, nil, nil},
|
/* 9 */ {`AND`, sym.SymKwAnd, nil, nil},
|
||||||
/* 10 */ {`or`, SymKwOr, nil, nil},
|
/* 10 */ {`or`, sym.SymKwOr, nil, nil},
|
||||||
/* 11 */ {`+=`, SymPlusEqual, nil, nil},
|
/* 11 */ {`+=`, sym.SymPlusEqual, nil, nil},
|
||||||
/* 12 */ {`-=`, SymMinusEqual, nil, nil},
|
/* 12 */ {`-=`, sym.SymMinusEqual, nil, nil},
|
||||||
/* 13 */ {`|`, SymVertBar, nil, nil},
|
/* 13 */ {`|`, sym.SymVertBar, nil, nil},
|
||||||
/* 14 */ {`:`, SymColon, nil, nil},
|
/* 14 */ {`:`, sym.SymColon, nil, nil},
|
||||||
/* 15 */ {`;`, SymSemiColon, nil, nil},
|
/* 15 */ {`;`, sym.SymSemiColon, nil, nil},
|
||||||
/* 16 */ {`.`, SymDot, nil, nil},
|
/* 16 */ {`.`, sym.SymDot, nil, nil},
|
||||||
/* 17 */ {`0.5`, SymFloat, float64(0.5), nil},
|
/* 17 */ {`0.5`, sym.SymFloat, float64(0.5), nil},
|
||||||
/* 18 */ {`\\`, SymBackSlash, nil, nil},
|
/* 18 */ {`\\`, sym.SymBackSlash, nil, nil},
|
||||||
/* 19 */ {"`", SymBackTick, nil, nil},
|
/* 19 */ {"`", sym.SymBackTick, nil, nil},
|
||||||
/* 20 */ {"?", SymQuestion, nil, nil},
|
/* 20 */ {"?", sym.SymQuestion, nil, nil},
|
||||||
/* 21 */ {"&", SymAmpersand, nil, nil},
|
/* 21 */ {"&", sym.SymAmpersand, nil, nil},
|
||||||
/* 22 */ {"@", SymAt, nil, nil},
|
/* 22 */ {"@", sym.SymAt, nil, nil},
|
||||||
/* 23 */ {`#`, SymHash, nil, nil},
|
/* 23 */ {`#`, sym.SymHash, nil, nil},
|
||||||
/* 24 */ {`%`, SymPercent, nil, nil},
|
/* 24 */ {`%`, sym.SymPercent, nil, nil},
|
||||||
/* 25 */ {`\'`, SymQuote, nil, nil},
|
/* 25 */ {`\'`, sym.SymQuote, nil, nil},
|
||||||
/* 26 */ {`\"`, SymDoubleQuote, nil, nil},
|
/* 26 */ {`\"`, sym.SymDoubleQuote, nil, nil},
|
||||||
/* 27 */ {`_`, SymUndescore, nil, nil},
|
/* 27 */ {`_`, sym.SymUndescore, nil, nil},
|
||||||
/* 28 */ {`<>`, SymLessGreater, nil, nil},
|
/* 28 */ {`<>`, sym.SymLessGreater, nil, nil},
|
||||||
/* 29 */ {`[`, SymOpenSquare, nil, nil},
|
/* 29 */ {`[`, sym.SymOpenSquare, nil, nil},
|
||||||
/* 30 */ {`]`, SymClosedSquare, nil, nil},
|
/* 30 */ {`]`, sym.SymClosedSquare, nil, nil},
|
||||||
/* 31 */ {`{`, SymOpenBrace, nil, nil},
|
/* 31 */ {`{`, sym.SymOpenBrace, nil, nil},
|
||||||
/* 32 */ {`}`, SymClosedBrace, nil, nil},
|
/* 32 */ {`}`, sym.SymClosedBrace, nil, nil},
|
||||||
/* 33 */ {`(`, SymOpenRound, nil, nil},
|
/* 33 */ {`(`, sym.SymOpenRound, nil, nil},
|
||||||
/* 34 */ {`)`, SymClosedRound, nil, nil},
|
/* 34 */ {`)`, sym.SymClosedRound, nil, nil},
|
||||||
/* 35 */ {`1E+2`, SymFloat, float64(100), nil},
|
/* 35 */ {`1E+2`, sym.SymFloat, float64(100), nil},
|
||||||
/* 36 */ {`1E+x`, SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
|
/* 36 */ {`1E+x`, sym.SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
|
||||||
/* 37 */ {`$`, SymDollar, nil, nil},
|
/* 37 */ {`$`, sym.SymDollar, nil, nil},
|
||||||
/* 38 */ {`\`, SymError, errors.New("incomplete escape sequence"), nil},
|
/* 38 */ {`\`, sym.SymError, errors.New("incomplete escape sequence"), nil},
|
||||||
/* 39 */ {`"string"`, SymString, "string", nil},
|
/* 39 */ {`"string"`, sym.SymString, "string", nil},
|
||||||
/* 40 */ {`identifier`, SymIdentifier, "identifier", nil},
|
/* 40 */ {`identifier`, sym.SymIdentifier, "identifier", nil},
|
||||||
/* 41 */ {`1.2(3)`, SymFraction, kern.NewFraction(37, 30), nil},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, input := range inputs {
|
for i, input := range inputs {
|
||||||
@@ -82,7 +81,7 @@ func TestScanner(t *testing.T) {
|
|||||||
t.Errorf("%d: %q -> got = (nil), want %v (value %v [%T])", i+1, input.source, input.wantSym, input.wantValue, input.wantValue)
|
t.Errorf("%d: %q -> got = (nil), want %v (value %v [%T])", i+1, input.source, input.wantSym, input.wantValue, input.wantValue)
|
||||||
// } else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
|
// } else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
|
||||||
} else if tk.Sym != input.wantSym || !reflect.DeepEqual(tk.Value, input.wantValue) {
|
} else if tk.Sym != input.wantSym || !reflect.DeepEqual(tk.Value, input.wantValue) {
|
||||||
if tk.Sym == SymError && input.wantSym == tk.Sym {
|
if tk.Sym == sym.SymError && input.wantSym == tk.Sym {
|
||||||
if tkErr, tkOk := tk.Value.(error); tkOk {
|
if tkErr, tkOk := tk.Value.(error); tkOk {
|
||||||
if inputErr, inputOk := input.wantValue.(error); inputOk {
|
if inputErr, inputOk := input.wantValue.(error); inputOk {
|
||||||
if tkErr.Error() != inputErr.Error() {
|
if tkErr.Error() != inputErr.Error() {
|
||||||
|
|||||||
@@ -4,17 +4,19 @@
|
|||||||
// term-constructor-registry.go
|
// term-constructor-registry.go
|
||||||
package scan
|
package scan
|
||||||
|
|
||||||
|
import "git.portale-stac.it/go-pkg/expr/sym"
|
||||||
|
|
||||||
const initialRegistryCapacity = 10
|
const initialRegistryCapacity = 10
|
||||||
|
|
||||||
type termContructor func(tk *Token) *Term
|
type termContructor func(tk *Token) *Term
|
||||||
|
|
||||||
var constructorRegistry map[Symbol]termContructor = nil
|
var constructorRegistry map[sym.Symbol]termContructor = nil
|
||||||
|
|
||||||
func RegisterTermConstructor(sym Symbol, constructor termContructor) {
|
func RegisterTermConstructor(symmbol sym.Symbol, constructor termContructor) {
|
||||||
if constructorRegistry == nil {
|
if constructorRegistry == nil {
|
||||||
constructorRegistry = make(map[Symbol]termContructor, initialRegistryCapacity)
|
constructorRegistry = make(map[sym.Symbol]termContructor, initialRegistryCapacity)
|
||||||
}
|
}
|
||||||
constructorRegistry[sym] = constructor
|
constructorRegistry[symmbol] = constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTerm(tk *Token) (inst *Term) {
|
func NewTerm(tk *Token) (inst *Term) {
|
||||||
|
|||||||
+39
-13
@@ -8,13 +8,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TermPriority uint32
|
type TermPriority uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PriNone TermPriority = iota
|
PriNone TermPriority = iota
|
||||||
PriRange
|
PriInterval
|
||||||
PriBut
|
PriBut
|
||||||
PriAssign
|
PriAssign
|
||||||
PriIterOp // map, filter, digest, etc
|
PriIterOp // map, filter, digest, etc
|
||||||
@@ -160,7 +161,7 @@ func (t *Term) SetParent(parent *Term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Term) Symbol() Symbol {
|
func (t *Term) Symbol() sym.Symbol {
|
||||||
return t.Tk.Sym
|
return t.Tk.Sym
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,9 +187,43 @@ func (t *Term) GetChildSource(index int) (s string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Term) IsAssign() bool {
|
func (t *Term) GetLeftChild() (c kern.Term) {
|
||||||
return t.Symbol() == SymEqual
|
if t.Position == PosInfix && len(t.Children) > 0 {
|
||||||
|
c = t.Children[0]
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) GetRightChild() (c kern.Term) {
|
||||||
|
if t.Position == PosInfix && len(t.Children) > 1 {
|
||||||
|
c = t.Children[1]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) IsSymbol(symbol sym.Symbol) bool {
|
||||||
|
return t.Symbol() == symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) IsOneOf(symbols ...sym.Symbol) bool {
|
||||||
|
return t.Tk.IsOneOf(symbols)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) IsAssign() bool {
|
||||||
|
return t.Symbol() == sym.SymEqual
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) IsVar() bool {
|
||||||
|
return t.Symbol() == sym.SymVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Term) SetSymbol(symbol sym.Symbol) {
|
||||||
|
t.Tk.SetSymbol(symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (t *Term) IsFunc() bool {
|
||||||
|
// return t.Symbol() == SymFunction
|
||||||
|
// }
|
||||||
|
|
||||||
func (t *Term) Compute(ctx kern.ExprContext) (v any, err error) {
|
func (t *Term) Compute(ctx kern.ExprContext) (v any, err error) {
|
||||||
if t.EvalFunc == nil {
|
if t.EvalFunc == nil {
|
||||||
@@ -199,15 +234,6 @@ func (t *Term) Compute(ctx kern.ExprContext) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (term *term) toInt(computedValue any, valueDescription string) (i int, err error) {
|
|
||||||
// if index64, ok := computedValue.(int64); ok {
|
|
||||||
// i = int(index64)
|
|
||||||
// } else {
|
|
||||||
// err = term.Errorf("%s, got %s (%v)", valueDescription, TypeName(computedValue), computedValue)
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (t *Term) ErrIncompatibleTypes(leftValue, rightValue any) error {
|
func (t *Term) ErrIncompatibleTypes(leftValue, rightValue any) error {
|
||||||
leftType := kern.TypeName(leftValue)
|
leftType := kern.TypeName(leftValue)
|
||||||
leftText := kern.GetFormatted(leftValue, kern.Truncate)
|
leftText := kern.GetFormatted(leftValue, kern.Truncate)
|
||||||
|
|||||||
+24
-22
@@ -8,12 +8,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
row int
|
row int
|
||||||
col int
|
col int
|
||||||
Sym Symbol
|
Sym sym.Symbol
|
||||||
source string
|
source string
|
||||||
Value any
|
Value any
|
||||||
}
|
}
|
||||||
@@ -36,19 +38,19 @@ func (tk *Token) String() string {
|
|||||||
return tk.source
|
return tk.source
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewToken(row, col int, sym Symbol, source string) *Token {
|
func NewToken(row, col int, symbol sym.Symbol, source string) *Token {
|
||||||
return &Token{row: row, col: col, Sym: sym, source: source}
|
return &Token{row: row, col: col, Sym: symbol, source: source}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewValueToken(row, col int, sym Symbol, source string, value any) *Token {
|
func NewValueToken(row, col int, symbol sym.Symbol, source string, value any) *Token {
|
||||||
return &Token{row: row, col: col, Sym: sym, source: source, Value: value}
|
return &Token{row: row, col: col, Sym: symbol, source: source, Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewErrorToken(row, col int, err error) *Token {
|
func NewErrorToken(row, col int, err error) *Token {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return NewToken(row, col, SymEos, "<EOF>")
|
return NewToken(row, col, sym.SymEos, "<EOF>")
|
||||||
}
|
}
|
||||||
return NewValueToken(row, col, SymError, fmt.Sprintf("[%d:%d]", row, col), err)
|
return NewValueToken(row, col, sym.SymError, fmt.Sprintf("[%d:%d]", row, col), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) Source() string {
|
func (tk *Token) Source() string {
|
||||||
@@ -68,31 +70,31 @@ func (tk *Token) Clone() (c *Token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsEos() bool {
|
func (tk *Token) IsEos() bool {
|
||||||
return tk.Sym == SymEos
|
return tk.Sym == sym.SymEos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsError() bool {
|
func (tk *Token) IsError() bool {
|
||||||
return tk.Sym == SymError
|
return tk.Sym == sym.SymError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsTerm(termSymbols []Symbol) bool {
|
func (tk *Token) IsTerm(symbols []sym.Symbol) bool {
|
||||||
return tk.IsEos() || tk.IsError() || tk.IsOneOf(termSymbols)
|
return tk.IsEos() || tk.IsError() || tk.IsOneOf(symbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsOneOf(termSymbols []Symbol) bool {
|
func (tk *Token) IsOneOf(symbols []sym.Symbol) bool {
|
||||||
return termSymbols != nil && slices.Index(termSymbols, tk.Sym) >= 0
|
return symbols != nil && slices.Index(symbols, tk.Sym) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsOneOfA(termSymbols ...Symbol) bool {
|
func (tk *Token) IsOneOfA(symbols ...sym.Symbol) bool {
|
||||||
return slices.Index(termSymbols, tk.Sym) >= 0
|
return slices.Index(symbols, tk.Sym) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) IsSymbol(sym Symbol) bool {
|
func (tk *Token) IsSymbol(symbol sym.Symbol) bool {
|
||||||
return tk.Sym == sym
|
return tk.Sym == symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) SetSymbol(sym Symbol) {
|
func (tk *Token) SetSymbol(symbol sym.Symbol) {
|
||||||
tk.Sym = sym
|
tk.Sym = symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) Errorf(template string, args ...any) (err error) {
|
func (tk *Token) Errorf(template string, args ...any) (err error) {
|
||||||
@@ -101,7 +103,7 @@ func (tk *Token) Errorf(template string, args ...any) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) Error() (err error) {
|
func (tk *Token) Error() (err error) {
|
||||||
if tk.Sym == SymError {
|
if tk.Sym == sym.SymError {
|
||||||
if msg, ok := tk.Value.(error); ok {
|
if msg, ok := tk.Value.(error); ok {
|
||||||
err = fmt.Errorf("[%d:%d] %v", tk.row, tk.col, msg)
|
err = fmt.Errorf("[%d:%d] %v", tk.row, tk.col, msg)
|
||||||
}
|
}
|
||||||
@@ -110,7 +112,7 @@ func (tk *Token) Error() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) ErrorText() (err string) {
|
func (tk *Token) ErrorText() (err string) {
|
||||||
if tk.Sym == SymError {
|
if tk.Sym == sym.SymError {
|
||||||
if msg, ok := tk.Value.(error); ok {
|
if msg, ok := tk.Value.(error); ok {
|
||||||
err = msg.Error()
|
err = msg.Error()
|
||||||
}
|
}
|
||||||
@@ -137,6 +139,6 @@ func (tk *Token) ErrorExpectedGotStringWithPrefix(prefix, symbol, got string) (e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) ErrorExpectedOneOfGot(expected ...Symbol) (err error) {
|
func (tk *Token) ErrorExpectedOneOfGot(expected ...sym.Symbol) (err error) {
|
||||||
return tk.ErrorExpectedGotStringWithPrefix("expected one of ", SymListToString(expected, true), SymToString(tk.Sym))
|
return tk.ErrorExpectedGotStringWithPrefix("expected one of ", SymListToString(expected, true), SymToString(tk.Sym))
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types"
|
||||||
"git.portale-stac.it/go-pkg/expr/util"
|
"git.portale-stac.it/go-pkg/expr/util"
|
||||||
// "strings"
|
// "strings"
|
||||||
)
|
)
|
||||||
@@ -76,12 +77,12 @@ func (ctx *SimpleStore) Clone() kern.ExprContext {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (ctx *SimpleStore) ToDict() (dict *kern.DictType) {
|
func (ctx *SimpleStore) ToDict() any {
|
||||||
return kern.ContextToDict(ctx)
|
return types.ContextToDict(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string {
|
func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string {
|
||||||
return kern.ContextToString(ctx, opt)
|
return types.ContextToString(ctx, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string {
|
// func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// symbol.go
|
// symbol.go
|
||||||
package scan
|
package sym
|
||||||
|
|
||||||
type Symbol int16
|
type Symbol int16
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ const (
|
|||||||
SymList // 90: list
|
SymList // 90: list
|
||||||
SymDict // 91: dict
|
SymDict // 91: dict
|
||||||
SymIndex // 92: index
|
SymIndex // 92: index
|
||||||
SymRange // 93: range [index : index]
|
SymInterval // 93: range [index : index]
|
||||||
SymExpression // 94: expression
|
SymExpression // 94: expression
|
||||||
SymSelector // 95: selector <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
SymSelector // 95: selector <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||||
SymSelectorCase // 96: <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
SymSelectorCase // 96: <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||||
@@ -122,6 +122,7 @@ const (
|
|||||||
SymKwBuiltin
|
SymKwBuiltin
|
||||||
SymKwPlugin
|
SymKwPlugin
|
||||||
SymKwIn
|
SymKwIn
|
||||||
|
SymKwAt
|
||||||
SymKwInclude
|
SymKwInclude
|
||||||
SymKwMap
|
SymKwMap
|
||||||
SymKwFilter
|
SymKwFilter
|
||||||
@@ -133,17 +134,18 @@ const (
|
|||||||
SymKwUnset
|
SymKwUnset
|
||||||
)
|
)
|
||||||
|
|
||||||
var keywords map[string]Symbol
|
var Keywords map[string]Symbol
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
//keywords = make(map[string]Symbol)
|
//keywords = make(map[string]Symbol)
|
||||||
keywords = map[string]Symbol{
|
Keywords = map[string]Symbol{
|
||||||
"AND": SymKwAnd,
|
"AND": SymKwAnd,
|
||||||
"BUILTIN": SymKwBuiltin,
|
"BUILTIN": SymKwBuiltin,
|
||||||
"PLUGIN": SymKwPlugin,
|
"PLUGIN": SymKwPlugin,
|
||||||
"BUT": SymKwBut,
|
"BUT": SymKwBut,
|
||||||
"FUNC": SymKwFunc,
|
"FUNC": SymKwFunc,
|
||||||
"IN": SymKwIn,
|
"IN": SymKwIn,
|
||||||
|
"AT": SymKwAt,
|
||||||
"INCLUDE": SymKwInclude,
|
"INCLUDE": SymKwInclude,
|
||||||
"MAP": SymKwMap,
|
"MAP": SymKwMap,
|
||||||
"CAT": SymKwCat,
|
"CAT": SymKwCat,
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// t_array_test.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArray(t *testing.T) {
|
||||||
|
section := "Array"
|
||||||
|
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`[]`, array.NewArrayA(), nil},
|
||||||
|
/* 2 */ {`[1,2,3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 3 */ {`[1,2,"hello"]`, array.NewArrayA(int64(1), int64(2), "hello"), nil},
|
||||||
|
/* 4 */ {`[1+2, not true, "hello"]`, array.NewArrayA(int64(3), false, "hello"), nil},
|
||||||
|
/* 5 */ {`[1,2]+[3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 6 */ {`[1,4,3,2]-[3]`, array.NewArrayA(int64(1), int64(4), int64(2)), nil},
|
||||||
|
/* 7 */ {`builtin "math.arith"; add([1,4,3,2])`, int64(10), nil},
|
||||||
|
/* 8 */ {`builtin "math.arith"; add([1,[2,2],3,2])`, int64(10), nil},
|
||||||
|
/* 9 */ {`builtin "math.arith"; mul([1,4,3.0,2])`, float64(24.0), nil},
|
||||||
|
/* 10 */ {`builtin "math.arith"; add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`},
|
||||||
|
/* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
|
||||||
|
/* 12 */ {`[1,2,3] <+ 2+2`, array.ArrayFromIntsA(1, 2, 3, 4), nil},
|
||||||
|
/* 13 */ {`2-1 +> [2,3]`, array.ArrayFromIntsA(1, 2, 3), nil},
|
||||||
|
/* 14 */ {`[1,2,3][1]`, int64(2), nil},
|
||||||
|
/* 15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil},
|
||||||
|
/* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
|
||||||
|
/* 17 */ {`list=["one","two","three"]; list[10]`, nil, `[1:34] index 10 out of bounds`},
|
||||||
|
/* 18 */ {`["a", "b", "c"]`, array.NewArrayA("a", "b", "c"), nil},
|
||||||
|
/* 19 */ {`["a", "b", "c"]`, array.NewArray([]any{"a", "b", "c"}), nil},
|
||||||
|
/* 20 */ {`#["a", "b", "c"]`, int64(3), nil},
|
||||||
|
/* 21 */ {`"b" in ["a", "b", "c"]`, true, nil},
|
||||||
|
/* 22 */ {`a=[1,2]; (a)<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 23 */ {`a=[1,2]; (a)<+3; a`, array.NewArrayA(int64(1), int64(2)), nil},
|
||||||
|
/* 24 */ {`["a","b","c","d"][1]`, "b", nil},
|
||||||
|
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
|
||||||
|
/* 26 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`},
|
||||||
|
/* 27 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
|
||||||
|
/* 28 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 29 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil},
|
||||||
|
/* 30 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil},
|
||||||
|
/* 31 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
|
||||||
|
/* 32 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`},
|
||||||
|
/* 33 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
|
||||||
|
/* 34 */ {`2 IN [1,2,3]`, true, nil},
|
||||||
|
/* 35 */ {`2 AT [1,2,3]`, int64(1), nil},
|
||||||
|
/* 36 */ {`4 AT [1,2,3]`, int64(-1), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
|
// RunTestSuiteSpec(t, section, inputs, 43)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrayInsert(t *testing.T) {
|
||||||
|
section := "Array-Insert"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`["a", "b"] << nil`, array.NewArrayA("a", "b"), nil},
|
||||||
|
/* 2 */ {`["a", "b"] << []`, array.NewArrayA("a", "b", array.NewArrayA()), nil},
|
||||||
|
/* 3 */ {`["a", "b"] << $([])`, array.NewArrayA("a", "b"), nil},
|
||||||
|
/* 4 */ {`["a", "b"] << 3`, array.NewArrayA("a", "b", int64(3)), nil},
|
||||||
|
/* 5 */ {`3 << ["a", "b"]`, nil, `[1:5] left operand '3' [integer] and right operand '["a", "b"]' [array] are not compatible with operator "<<"`},
|
||||||
|
/* 6 */ {`nil >> ["a", "b"]`, array.NewArrayA("a", "b"), nil},
|
||||||
|
/* 7 */ {`[] >> ["a", "b"]`, array.NewArrayA(array.NewArrayA(), "a", "b"), nil},
|
||||||
|
/* 8 */ {`$([]) >> ["a", "b"]`, array.NewArrayA("a", "b"), nil},
|
||||||
|
/* 9 */ {`["a", "b"] << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 10 */ {`L=["a", "b"]; L << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 11 */ {`L=["a", "b"]; L << $([1,2,3]); L`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
|
||||||
|
/* 12 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`},
|
||||||
|
/* 13 */ {`[0] << $([1,2,3,4])`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||||
|
/* 14 */ {`L=[]; [1] >> L; L`, array.NewArrayA(array.ArrayFromIntsA(1)), nil},
|
||||||
|
/* 15 */ {`L=[]; L << [1]; L`, array.NewArrayA(array.ArrayFromIntsA(1)), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTestSuiteSpec(t, section, inputs, 14)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrayDeepAssign(t *testing.T) {
|
||||||
|
section := "Array-DeepAssign"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`LL=["a", "b"]; L=LL; L[0]="x"; LL`, array.NewArrayA("x", "b"), nil},
|
||||||
|
/* 2 */ {`LL=["a", "b"]; L:=LL; L[0]="x"; LL`, array.NewArrayA("a", "b"), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
// runTestSuiteSpec(t, section, inputs, 4)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
|
}
|
||||||
+9
-8
@@ -9,6 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/scan"
|
"git.portale-stac.it/go-pkg/expr/scan"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/sym"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAstString(t *testing.T) {
|
func TestAstString(t *testing.T) {
|
||||||
@@ -19,9 +20,9 @@ func TestAstString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAddTokensGood(t *testing.T) {
|
func TestAddTokensGood(t *testing.T) {
|
||||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||||
tk2 := scan.NewToken(0, 0, scan.SymPlus, "+")
|
tk2 := scan.NewToken(0, 0, sym.SymPlus, "+")
|
||||||
tk3 := scan.NewValueToken(0, 0, scan.SymInteger, "50", 500)
|
tk3 := scan.NewValueToken(0, 0, sym.SymInteger, "50", 500)
|
||||||
|
|
||||||
tree := scan.NewAst()
|
tree := scan.NewAst()
|
||||||
if gotErr := tree.AddTokens(tk1, tk2, tk3); gotErr != nil {
|
if gotErr := tree.AddTokens(tk1, tk2, tk3); gotErr != nil {
|
||||||
@@ -30,10 +31,10 @@ func TestAddTokensGood(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAddTokensBad(t *testing.T) {
|
func TestAddTokensBad(t *testing.T) {
|
||||||
tk0 := scan.NewValueToken(0, 0, scan.SymInteger, "200", 200)
|
tk0 := scan.NewValueToken(0, 0, sym.SymInteger, "200", 200)
|
||||||
tk1 := scan.NewValueToken(0, 0, scan.SymInteger, "100", 100)
|
tk1 := scan.NewValueToken(0, 0, sym.SymInteger, "100", 100)
|
||||||
tk2 := scan.NewToken(0, 0, scan.SymPlus, "+")
|
tk2 := scan.NewToken(0, 0, sym.SymPlus, "+")
|
||||||
tk3 := scan.NewValueToken(0, 0, scan.SymInteger, "50", 500)
|
tk3 := scan.NewValueToken(0, 0, sym.SymInteger, "50", 500)
|
||||||
|
|
||||||
wantErr := errors.New(`[0:0] two adjacent operators: "200" and "100"`)
|
wantErr := errors.New(`[0:0] two adjacent operators: "200" and "100"`)
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ func TestAddTokensBad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAddUnknownTokens(t *testing.T) {
|
func TestAddUnknownTokens(t *testing.T) {
|
||||||
tk0 := scan.NewToken(0, 0, scan.SymPercent, "%")
|
tk0 := scan.NewToken(0, 0, sym.SymPercent, "%")
|
||||||
|
|
||||||
wantErr := errors.New(`unexpected token "%"`)
|
wantErr := errors.New(`unexpected token "%"`)
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -21,21 +21,21 @@ func TestBool(t *testing.T) {
|
|||||||
/* 5 */ {`not "true"`, false, nil},
|
/* 5 */ {`not "true"`, false, nil},
|
||||||
/* 6 */ {`not "false"`, false, nil},
|
/* 6 */ {`not "false"`, false, nil},
|
||||||
/* 7 */ {`not ""`, true, nil},
|
/* 7 */ {`not ""`, true, nil},
|
||||||
/* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`)},
|
/* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" does not support operand '[]' [array]`)},
|
||||||
/* 9 */ {`true and false`, false, nil},
|
/* 9 */ {`true and false`, false, nil},
|
||||||
/* 10 */ {`true and []`, nil, errors.New(`[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`)},
|
/* 10 */ {`true and []`, nil, errors.New(`[1:9] left operand 'true' [bool] and right operand '[]' [array] are not compatible with operator "AND"`)},
|
||||||
/* 11 */ {`[] and false`, nil, errors.New(`[1:7] operator "AND" does not support operand '[]' [list] on its left side`)},
|
/* 11 */ {`[] and false`, nil, errors.New(`[1:7] operator "AND" does not support operand '[]' [array] on its left side`)},
|
||||||
/* 12 */ {`true or false`, true, nil},
|
/* 12 */ {`true or false`, true, nil},
|
||||||
/* 13 */ {`true or []`, true, nil},
|
/* 13 */ {`true or []`, true, nil},
|
||||||
/* 14 */ {`[] or false`, nil, errors.New(`got list as left operand type of 'OR' operator, it must be bool`)},
|
/* 14 */ {`[] or false`, nil, errors.New(`got array as left operand type of 'OR' operator, it must be bool`)},
|
||||||
/* 15 */ {`!true`, false, nil},
|
/* 15 */ {`!true`, false, nil},
|
||||||
/* 13 */ //{`true or []`, nil, errors.New(`[1:8] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "OR"`)},
|
/* 13 */ //{`true or []`, nil, errors.New(`[1:8] left operand 'true' [bool] and right operand '[]' [array] are not compatible with operator "OR"`)},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 13)
|
// runTestSuiteSpec(t, section, inputs, 13)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBoolNoShortcut(t *testing.T) {
|
func TestBoolNoShortcut(t *testing.T) {
|
||||||
@@ -48,13 +48,13 @@ func TestBoolNoShortcut(t *testing.T) {
|
|||||||
/* 5 */ {`not "true"`, false, nil},
|
/* 5 */ {`not "true"`, false, nil},
|
||||||
/* 6 */ {`not "false"`, false, nil},
|
/* 6 */ {`not "false"`, false, nil},
|
||||||
/* 7 */ {`not ""`, true, nil},
|
/* 7 */ {`not ""`, true, nil},
|
||||||
/* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`},
|
/* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" does not support operand '[]' [array]`},
|
||||||
/* 9 */ {`true and false`, false, nil},
|
/* 9 */ {`true and false`, false, nil},
|
||||||
/* 10 */ {`true and []`, nil, `[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`},
|
/* 10 */ {`true and []`, nil, `[1:9] left operand 'true' [bool] and right operand '[]' [array] are not compatible with operator "AND"`},
|
||||||
/* 11 */ {`[] and false`, nil, `[1:7] left operand '[]' [list] and right operand 'false' [bool] are not compatible with operator "AND"`},
|
/* 11 */ {`[] and false`, nil, `[1:7] left operand '[]' [array] and right operand 'false' [bool] are not compatible with operator "AND"`},
|
||||||
/* 12 */ {`true or false`, true, nil},
|
/* 12 */ {`true or false`, true, nil},
|
||||||
/* 13 */ {`true or []`, nil, `[1:8] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "OR"`},
|
/* 13 */ {`true or []`, nil, `[1:8] left operand 'true' [bool] and right operand '[]' [array] are not compatible with operator "OR"`},
|
||||||
/* 14 */ {`[] or false`, nil, `[1:6] left operand '[]' [list] and right operand 'false' [bool] are not compatible with operator "OR"`},
|
/* 14 */ {`[] or false`, nil, `[1:6] left operand '[]' [array] and right operand 'false' [bool] are not compatible with operator "OR"`},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
@@ -63,7 +63,7 @@ func TestBoolNoShortcut(t *testing.T) {
|
|||||||
current := kern.SetCtrl(ctx, kern.ControlBoolShortcut, false)
|
current := kern.SetCtrl(ctx, kern.ControlBoolShortcut, false)
|
||||||
|
|
||||||
// runCtxTestSuiteSpec(t, ctx, section, inputs, 1)
|
// runCtxTestSuiteSpec(t, ctx, section, inputs, 1)
|
||||||
runCtxTestSuite(t, ctx, section, inputs)
|
RunCtxTestSuite(t, ctx, section, inputs)
|
||||||
|
|
||||||
kern.SetCtrl(ctx, kern.ControlBoolShortcut, current)
|
kern.SetCtrl(ctx, kern.ControlBoolShortcut, current)
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-32
@@ -7,7 +7,8 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncBase(t *testing.T) {
|
func TestFuncBase(t *testing.T) {
|
||||||
@@ -30,25 +31,25 @@ func TestFuncBase(t *testing.T) {
|
|||||||
/* 14 */ {`isFloat(3.1)`, true, nil},
|
/* 14 */ {`isFloat(3.1)`, true, nil},
|
||||||
/* 15 */ {`isString("3.1")`, true, nil},
|
/* 15 */ {`isString("3.1")`, true, nil},
|
||||||
/* 16 */ {`isString("3" + 1)`, true, nil},
|
/* 16 */ {`isString("3" + 1)`, true, nil},
|
||||||
/* 17 */ {`isList(["3", 1])`, true, nil},
|
/* 17 */ {`isArray(["3", 1])`, true, nil},
|
||||||
/* 18 */ {`isDict({"a":"3", "b":1})`, true, nil},
|
/* 18 */ {`isDict({"a":"3", "b":1})`, true, nil},
|
||||||
/* 19 */ {`isFract(1:3)`, true, nil},
|
/* 19 */ {`isFract(1:3)`, true, nil},
|
||||||
/* 20 */ {`isFract(3:1)`, false, nil},
|
/* 20 */ {`isFract(3:1)`, false, nil},
|
||||||
/* 21 */ {`isRational(3:1)`, true, nil},
|
/* 21 */ {`isRational(3:1)`, true, nil},
|
||||||
/* 22 */ {`fract("2.2(3)")`, kern.NewFraction(67, 30), nil},
|
/* 22 */ {`fract("2.2(3)")`, fract.NewFraction(67, 30), nil},
|
||||||
/* 23 */ {`fract("1.21(3)")`, kern.NewFraction(91, 75), nil},
|
/* 23 */ {`fract("1.21(3)")`, fract.NewFraction(91, 75), nil},
|
||||||
/* 24 */ {`fract(1.21(3))`, kern.NewFraction(91, 75), nil},
|
/* 24 */ {`fract(1.21(3))`, fract.NewFraction(91, 75), nil},
|
||||||
/* 25 */ {`fract(1.21)`, kern.NewFraction(121, 100), nil},
|
/* 25 */ {`fract(1.21)`, fract.NewFraction(121, 100), nil},
|
||||||
/* 26 */ {`dec(2)`, float64(2), nil},
|
/* 26 */ {`float(2)`, float64(2), nil},
|
||||||
/* 27 */ {`dec(2.0)`, float64(2), nil},
|
/* 27 */ {`float(2.0)`, float64(2), nil},
|
||||||
/* 28 */ {`dec("2.0")`, float64(2), nil},
|
/* 28 */ {`float("2.0")`, float64(2), nil},
|
||||||
/* 29 */ {`dec(true)`, float64(1), nil},
|
/* 29 */ {`float(true)`, float64(1), nil},
|
||||||
/* 30 */ {`dec(true")`, nil, "[1:11] expected one of `,`, `)`, got `\"`"},
|
/* 30 */ {`float(true")`, nil, "[1:13] expected one of `,`, `)`, got `\"`"},
|
||||||
/* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`},
|
/* 31 */ {`float()`, nil, `float(): too few params -- expected 1, got 0`},
|
||||||
/* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`},
|
/* 32 */ {`float(1,2,3)`, nil, `float(): too many params -- expected 1, got 3`},
|
||||||
/* 33 */ {`isBool(false)`, true, nil},
|
/* 33 */ {`isBool(false)`, true, nil},
|
||||||
/* 34 */ {`fract(1:2)`, kern.NewFraction(1, 2), nil},
|
/* 34 */ {`fract(1:2)`, fract.NewFraction(1, 2), nil},
|
||||||
/* 35 */ {`fract(12,2)`, kern.NewFraction(6, 1), nil},
|
/* 35 */ {`fract(12,2)`, fract.NewFraction(6, 1), nil},
|
||||||
/* 36 */ {`bool(2)`, true, nil},
|
/* 36 */ {`bool(2)`, true, nil},
|
||||||
/* 37 */ {`bool(1:2)`, true, nil},
|
/* 37 */ {`bool(1:2)`, true, nil},
|
||||||
/* 38 */ {`bool(1.0)`, true, nil},
|
/* 38 */ {`bool(1.0)`, true, nil},
|
||||||
@@ -58,9 +59,9 @@ func TestFuncBase(t *testing.T) {
|
|||||||
/* 42 */ {`bool([])`, false, nil},
|
/* 42 */ {`bool([])`, false, nil},
|
||||||
/* 43 */ {`bool({})`, false, nil},
|
/* 43 */ {`bool({})`, false, nil},
|
||||||
/* 44 */ {`bool({1:"one"})`, true, nil},
|
/* 44 */ {`bool({1:"one"})`, true, nil},
|
||||||
/* 45 */ {`dec(false)`, float64(0), nil},
|
/* 45 */ {`float(false)`, float64(0), nil},
|
||||||
/* 46 */ {`dec(1:2)`, float64(0.5), nil},
|
/* 46 */ {`float(1:2)`, float64(0.5), nil},
|
||||||
/* 47 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
|
/* 47 */ {`float([1])`, nil, `float(): can't convert array to float`},
|
||||||
/* 48 */ {`eval("a=3"); a`, int64(3), nil},
|
/* 48 */ {`eval("a=3"); a`, int64(3), nil},
|
||||||
/* 49 */ {`int(5:2)`, int64(2), nil},
|
/* 49 */ {`int(5:2)`, int64(2), nil},
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ func TestFuncBase(t *testing.T) {
|
|||||||
t.Setenv("EXPR_PATH", ".")
|
t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 49)
|
// runTestSuiteSpec(t, section, inputs, 49)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuncBaseString(t *testing.T) {
|
func TestFuncBaseString(t *testing.T) {
|
||||||
@@ -88,28 +89,29 @@ func TestFuncBaseString(t *testing.T) {
|
|||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 49)
|
// runTestSuiteSpec(t, section, inputs, 49)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuncBaseFraction(t *testing.T) {
|
func TestFuncBaseFraction(t *testing.T) {
|
||||||
section := "Builtin-Base-Fraction"
|
section := "Builtin-Base-Fraction"
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`fract(-0.5)`, kern.NewFraction(-1, 2), nil},
|
/* 1 */ {`fract(-0.5)`, fract.NewFraction(-1, 2), nil},
|
||||||
/* 2 */ {`fract("")`, (*kern.FractionType)(nil), `bad syntax`},
|
/* 2 */ {`fract("")`, (*fract.FractionType)(nil), `bad syntax`},
|
||||||
/* 3 */ {`fract("-1")`, kern.NewFraction(-1, 1), nil},
|
/* 3 */ {`fract("-1")`, fract.NewFraction(-1, 1), nil},
|
||||||
/* 4 */ {`fract("+1")`, kern.NewFraction(1, 1), nil},
|
/* 4 */ {`fract("+1")`, fract.NewFraction(1, 1), nil},
|
||||||
/* 5 */ {`fract("1a")`, (*kern.FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`},
|
/* 5 */ {`fract("1a")`, (*fract.FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`},
|
||||||
/* 6 */ {`fract(1,0)`, nil, `fract(): division by zero`},
|
/* 6 */ {`fract(1,0)`, nil, `fract(): division by zero`},
|
||||||
/* 7 */ {`fract(5, "1")`, nil, `fract(): expected integer, got string ("1")`},
|
/* 7 */ {`fract(5, "1")`, nil, `fract(): expected integer, got string ("1")`},
|
||||||
/* 8 */ {`fract(true)`, kern.NewFraction(1, 1), nil},
|
/* 8 */ {`fract(true)`, fract.NewFraction(1, 1), nil},
|
||||||
/* 9 */ {`fract(false)`, kern.NewFraction(0, 1), nil},
|
/* 9 */ {`fract(false)`, fract.NewFraction(0, 1), nil},
|
||||||
|
/* 10 */ {`1.2(3)`, fract.NewFraction(37, 30), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 8)
|
// RunTestSuiteSpec(t, section, inputs, 10)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuncBaseOthers(t *testing.T) {
|
func TestFuncBaseOthers(t *testing.T) {
|
||||||
@@ -118,10 +120,10 @@ func TestFuncBaseOthers(t *testing.T) {
|
|||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`set("a", 3); a`, int64(3), nil},
|
/* 1 */ {`set("a", 3); a`, int64(3), nil},
|
||||||
/* 2 */ {`set(true, 3)`, nil, `set(): the "name" parameter must be a string, got a bool (true)`},
|
/* 2 */ {`set(true, 3)`, nil, `set(): the "name" parameter must be a string, got a bool (true)`},
|
||||||
/* 3 */ {`seq(1,2,3)`, kern.NewLinkedListA(int64(1), int64(2), int64(3)), nil},
|
/* 3 */ {`seq(1,2,3)`, list.NewLinkedListA(int64(1), int64(2), int64(3)), nil},
|
||||||
// /* 4 */ {`seq(1,2,4)`, kern.NewLinkedListA(int64(1), int64(2), int64(3)), nil},
|
// /* 4 */ {`seq(1,2,4)`, kern.NewLinkedListA(int64(1), int64(2), int64(3)), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 4)
|
// RunTestSuiteSpec(t, section, inputs, 3)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func TestFuncFmt(t *testing.T) {
|
|||||||
//t.Setenv("EXPR_PATH", ".")
|
//t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 1)
|
// runTestSuiteSpec(t, section, inputs, 1)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFmt(t *testing.T) {
|
func TestFmt(t *testing.T) {
|
||||||
@@ -41,7 +41,7 @@ func TestFmt(t *testing.T) {
|
|||||||
ctx := NewSimpleStore()
|
ctx := NewSimpleStore()
|
||||||
currentStdout := kern.SetCtrl(ctx, kern.ControlStdout, &b)
|
currentStdout := kern.SetCtrl(ctx, kern.ControlStdout, &b)
|
||||||
|
|
||||||
runCtxTestSuite(t, ctx, section, inputs)
|
RunCtxTestSuite(t, ctx, section, inputs)
|
||||||
|
|
||||||
kern.SetCtrl(ctx, kern.ControlStdout, currentStdout)
|
kern.SetCtrl(ctx, kern.ControlStdout, currentStdout)
|
||||||
if b.String() != text+"\n" {
|
if b.String() != text+"\n" {
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ func TestFuncImport(t *testing.T) {
|
|||||||
t.Setenv("EXPR_PATH", "test-resources")
|
t.Setenv("EXPR_PATH", "test-resources")
|
||||||
|
|
||||||
//runTestSuiteSpec(t, section, inputs, 1)
|
//runTestSuiteSpec(t, section, inputs, 1)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,27 +5,102 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testFilePath = "/tmp/.go-test.txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncRun(t *testing.T) {
|
func TestFuncRun(t *testing.T) {
|
||||||
section := "Builtin-Iterator"
|
section := "Builtin-Iterator"
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`builtin "iterator"; it=$(1,2,3); run(it)`, nil, nil},
|
/* 1 */ {`builtin "iterator"; it=$(1,2,3); run(it)`, int64(3), nil},
|
||||||
/* 2 */ {`builtin "iterator"; run($(1,2,3), func(index,item){item+10})`, nil, nil},
|
/* 2 */ {`builtin "iterator"; run($(1,2,3), func(index,item){item+10})`, nil, nil},
|
||||||
/* 3 */ {`builtin "iterator"; run($(4), func(index,item){status=status+item; true}, {"status":0})`, int64(6), nil},
|
/* 3 */ {`builtin "iterator"; run($(..4), func(index,item){status=status+item; true}, {"status":0})`, int64(6), nil},
|
||||||
/* 4 */ {`builtin ["iterator", "fmt"]; run($(1,2,3), func(index,item){println(item+10)})`, nil, nil},
|
/* 4 */ {`builtin ["iterator", "fmt"]; run($(1,2,3), func(index,item){println(item+10)})`, nil, nil},
|
||||||
/* 5 */ {`builtin "iterator"; run(nil)`, nil, `paramter "iterator" must be an iterator, passed <nil> [nil]`},
|
/* 5 */ {`builtin "iterator"; run(nil)`, nil, `type of "iterator" must be iterator, passed <nil> [nil]`},
|
||||||
/* 6 */ {`builtin "iterator"; run($(1,2,3), nil)`, nil, nil},
|
/* 6 */ {`builtin "iterator"; run($(1,2,3), nil)`, int64(3), nil},
|
||||||
/* 7 */ {`builtin "iterator"; run($(1,2,3), func(){1}, "prrr")`, nil, `paramter "vars" must be a dictionary, passed prrr [string]`},
|
/* 7 */ {`builtin "iterator"; run($(1,2,3), func(){1}, "prrr")`, nil, `type of "vars" must be dict, passed prrr [string]`},
|
||||||
/* 8 */ {`builtin "iterator"; run($(1,2,3), operator=nil)`, nil, nil},
|
/* 8 */ {`builtin "iterator"; run($(1,2,3), operator=nil)`, int64(3), nil},
|
||||||
/* 9 */ {`builtin "iterator"; run($(1,2,3), operatorx=nil)`, nil, `run(): unknown param "operatorx"`},
|
/* 9 */ {`builtin "iterator"; run($(1,2,3), operatorx=nil)`, nil, `run(): unknown param "operatorx"`},
|
||||||
/* 10 */ {`builtin ["os.file", "iterator"]; it = fileLineIterator("test-file.txt"); run(it)`, nil, nil},
|
/* 10 */ {`builtin "iterator"; op = func(index, item){ (index > 2) ? {abort("aborted")} :: {status="ok"} }; run($(..5), op)`, "aborted", nil},
|
||||||
|
/* 11 */ {`builtin "iterator"; op = func(index, item){ (index > 2) ? {abort("aborted")} :: {status="ok"} }; run($(..1), op)`, "ok", nil},
|
||||||
|
}
|
||||||
|
//t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
|
// RunTestSuiteSpec(t, section, inputs, 10)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
|
|
||||||
|
cleanupBuiltinIterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncOsLineIter(t *testing.T) {
|
||||||
|
section := "Builtin-OS-File-Line-Iter"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {fmt.Sprintf(`builtin ["os.file", "iterator"]; it = fileLineIterator(%q); run(it)`, testFilePath), int64(2), nil},
|
||||||
|
/* 2 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it++`, testFilePath), "uno", nil},
|
||||||
|
/* 3 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it++;it++;it++`, testFilePath), nil, io.EOF.Error()},
|
||||||
|
/* 4 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); it.clean`, testFilePath), nil, nil},
|
||||||
|
/* 5 */ {fmt.Sprintf(`builtin "os.file"; it=fileLineIterator(%q); string(it)`, testFilePath),
|
||||||
|
fmt.Sprintf(`$(fileLineIterator@%q)`, testFilePath), nil},
|
||||||
|
/* 6 */ {fmt.Sprintf(`builtin "os.file"; #$$(fileLineIterator(%q) filter (#${_} == 2))`, testFilePath), int64(0), nil},
|
||||||
|
/* 7 */ {fmt.Sprintf(`builtin "os.file"; #$$(fileLineIterator(%q) filter (#${_} == 3))`, testFilePath), int64(2), nil},
|
||||||
|
/* 8 */ {fmt.Sprintf(`builtin "os.file"; $$(fileLineIterator(%q) map ${__})`, testFilePath), list.NewLinkedListA(0, 1), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setupBuiltinIterator(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTestSuiteSpec(t, section, inputs, 1)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
|
|
||||||
|
cleanupBuiltinIterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncOsByteIter(t *testing.T) {
|
||||||
|
section := "Builtin-OS-File-Byte-Iter"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {fmt.Sprintf(`builtin "os.file"; it=fileByteIterator(%q); string(it)`, testFilePath),
|
||||||
|
fmt.Sprintf(`$(fileByteIterator@%q)`, testFilePath), nil},
|
||||||
|
/* 2 */ {fmt.Sprintf(`builtin ["os.file", "string"]; it=fileByteIterator(%q); char(it++)`, testFilePath), `u`, nil},
|
||||||
|
/* 3 */ {fmt.Sprintf(`builtin ["os.file", "string"]; it=fileByteIterator(%q); it++; it.reset; char(it++)`, testFilePath), `u`, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := setupBuiltinIterator(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 3)
|
// RunTestSuiteSpec(t, section, inputs, 24)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
|
|
||||||
|
cleanupBuiltinIterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupBuiltinIterator() (err error) {
|
||||||
|
var fh *os.File
|
||||||
|
// Create test file
|
||||||
|
if fh, err = os.Create(testFilePath); err == nil {
|
||||||
|
defer fh.Close()
|
||||||
|
fmt.Fprintln(fh, "uno")
|
||||||
|
fmt.Fprintln(fh, "due")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupBuiltinIterator() {
|
||||||
|
if fileExists(testFilePath) {
|
||||||
|
os.Remove(testFilePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,5 @@ func TestFuncMathArith(t *testing.T) {
|
|||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
//runTestSuiteSpec(t, section, inputs, 10)
|
//runTestSuiteSpec(t, section, inputs, 10)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-21
@@ -5,10 +5,13 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// const (
|
||||||
|
// builtinOsFile_dummyFile = "/tmp/.go-test_dummy.txt"
|
||||||
|
// )
|
||||||
|
|
||||||
func TestFuncOs(t *testing.T) {
|
func TestFuncOs(t *testing.T) {
|
||||||
section := "Builtin-OS-File"
|
section := "Builtin-OS-File"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
@@ -27,30 +30,29 @@ func TestFuncOs(t *testing.T) {
|
|||||||
/* 13 */ {`builtin "os.file"; handle=fileClose(123)`, nil, `fileClose(): invalid file handle`},
|
/* 13 */ {`builtin "os.file"; handle=fileClose(123)`, nil, `fileClose(): invalid file handle`},
|
||||||
/* 14 */ {`builtin "os.file"; handle=fileOpen("/tmp/dummy"); c=fileReadTextAll(handle); fileClose(handle); c`, "bye-bye", nil},
|
/* 14 */ {`builtin "os.file"; handle=fileOpen("/tmp/dummy"); c=fileReadTextAll(handle); fileClose(handle); c`, "bye-bye", nil},
|
||||||
/* 15 */ {`builtin "os.file"; c=fileReadTextAll(123)`, nil, `fileReadTextAll(): invalid file handle 123 [int64]`},
|
/* 15 */ {`builtin "os.file"; c=fileReadTextAll(123)`, nil, `fileReadTextAll(): invalid file handle 123 [int64]`},
|
||||||
/* 16 */ {`builtin "os.file"; it=fileLineIterator("test-file.txt"); it++`, "uno", nil},
|
/* 16 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle); string(handle)`, `reader`, nil},
|
||||||
/* 17 */ {`builtin "os.file"; it=fileLineIterator("test-file.txt"); it++;it++;it++`, nil, io.EOF.Error()},
|
/* 17 */ {`builtin "os.file"; handle=fileCreate("/tmp/dummy"); fileClose(handle); string(handle)`, `writer`, nil},
|
||||||
/* 18 */ {`builtin "os.file"; it=fileLineIterator("test-file.txt"); it.clean`, nil, nil},
|
|
||||||
/* 19 */ {`builtin "os.file"; it=fileLineIterator("test-file.txt"); string(it)`, `$(fileLineIterator@"test-file.txt")`, nil},
|
|
||||||
/* 20 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle); string(handle)`, `reader`, nil},
|
|
||||||
/* 21 */ {`builtin "os.file"; handle=fileCreate("/tmp/dummy"); fileClose(handle); string(handle)`, `writer`, nil},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 24)
|
// RunTestSuiteSpec(t, section, inputs, 17)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuncOsByteIter(t *testing.T) {
|
// func setupBuiltinOsFile() (err error) {
|
||||||
section := "Builtin-OS-File-Byte-Iter"
|
// var fh *os.File
|
||||||
inputs := []inputType{
|
// // Create test file
|
||||||
/* 1 */ {`builtin "os.file"; it=fileByteIterator("test-file.txt"); string(it)`, `$(fileByteIterator@"test-file.txt")`, nil},
|
// if fh, err = os.Create(builtinOsFile_dummyFile); err == nil {
|
||||||
/* 2 */ {`builtin ["os.file", "string"]; it=fileByteIterator("test-file.txt"); char(it++)`, `u`, nil},
|
// defer fh.Close()
|
||||||
/* 3 */ {`builtin ["os.file", "string"]; it=fileByteIterator("test-file.txt"); it++; it.reset; char(it++)`, `u`, nil},
|
// fmt.Fprintln(fh, "uno")
|
||||||
}
|
// fmt.Fprintln(fh, "due")
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// func cleanupBuiltinOsFile() {
|
||||||
|
// if fileExists(builtinOsFile_dummyFile) {
|
||||||
// runTestSuiteSpec(t, section, inputs, 24)
|
// os.Remove(builtinOsFile_dummyFile)
|
||||||
runTestSuite(t, section, inputs)
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncString(t *testing.T) {
|
func TestFuncString(t *testing.T) {
|
||||||
@@ -30,7 +30,7 @@ func TestFuncString(t *testing.T) {
|
|||||||
/* 14 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "789")`, true, nil},
|
/* 14 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "789")`, true, nil},
|
||||||
/* 15 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "0125")`, false, nil},
|
/* 15 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "0125")`, false, nil},
|
||||||
/* 16 */ {`builtin "string"; strEndsWith("0123456789")`, nil, `strEndsWith(): too few params -- expected 2 or more, got 1`},
|
/* 16 */ {`builtin "string"; strEndsWith("0123456789")`, nil, `strEndsWith(): too few params -- expected 2 or more, got 1`},
|
||||||
/* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, kern.NewListA("one", "two", "three"), nil},
|
/* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, array.NewArrayA("one", "two", "three"), nil},
|
||||||
/* 18 */ {`builtin "string"; strJoin("-", [1, "two", "three"])`, nil, `strJoin(): expected string, got integer (1)`},
|
/* 18 */ {`builtin "string"; strJoin("-", [1, "two", "three"])`, nil, `strJoin(): expected string, got integer (1)`},
|
||||||
/* 19 */ {`builtin "string"; strJoin()`, nil, `strJoin(): too few params -- expected 1 or more, got 0`},
|
/* 19 */ {`builtin "string"; strJoin()`, nil, `strJoin(): too few params -- expected 1 or more, got 0`},
|
||||||
/* 20 */ {`builtin "string"; strUpper("StOp")`, "STOP", nil},
|
/* 20 */ {`builtin "string"; strUpper("StOp")`, "STOP", nil},
|
||||||
@@ -52,7 +52,7 @@ func TestFuncString(t *testing.T) {
|
|||||||
isFloat(any) -> boolean,
|
isFloat(any) -> boolean,
|
||||||
isFract(any) -> boolean,
|
isFract(any) -> boolean,
|
||||||
isInt(any) -> boolean,
|
isInt(any) -> boolean,
|
||||||
isList(any) -> boolean,
|
isArray(any) -> boolean,
|
||||||
isNil(any) -> boolean,
|
isNil(any) -> boolean,
|
||||||
isString(any) -> boolean,
|
isString(any) -> boolean,
|
||||||
joinStr(separator, item="" ...) -> string,
|
joinStr(separator, item="" ...) -> string,
|
||||||
@@ -68,5 +68,5 @@ func TestFuncString(t *testing.T) {
|
|||||||
//t.Setenv("EXPR_PATH", ".")
|
//t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 19)
|
// runTestSuiteSpec(t, section, inputs, 19)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-7
@@ -6,6 +6,9 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -19,9 +22,27 @@ type inputType struct {
|
|||||||
wantErr any
|
wantErr any
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCtxTestSuiteSpec(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType, spec ...int) {
|
func getSourceName(startFrame int) (sourcename string) {
|
||||||
|
for i := startFrame; i < 10; i++ {
|
||||||
|
_, sourcepath, _, ok := runtime.Caller(i)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sourcename = path.Base(sourcepath)
|
||||||
|
if sourcename != "t_common_test.go" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunCtxTestSuiteSpec(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType, spec ...int) {
|
||||||
succeeded := 0
|
succeeded := 0
|
||||||
failed := 0
|
failed := 0
|
||||||
|
|
||||||
|
sourcename := getSourceName(2)
|
||||||
|
t.Logf("Test suite %s from file %s", section, sourcename)
|
||||||
|
|
||||||
for _, count := range spec {
|
for _, count := range spec {
|
||||||
index := count - 1
|
index := count - 1
|
||||||
if index >= 0 && index < len(inputs) {
|
if index >= 0 && index < len(inputs) {
|
||||||
@@ -40,15 +61,19 @@ func runCtxTestSuiteSpec(t *testing.T, ctx kern.ExprContext, section string, inp
|
|||||||
t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(spec), succeeded, failed)
|
t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(spec), succeeded, failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestSuiteSpec(t *testing.T, section string, inputs []inputType, spec ...int) {
|
func RunTestSuiteSpec(t *testing.T, section string, inputs []inputType, spec ...int) {
|
||||||
runCtxTestSuiteSpec(t, nil, section, inputs, spec...)
|
RunCtxTestSuiteSpec(t, nil, section, inputs, spec...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCtxTestSuite(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType) {
|
func RunCtxTestSuite(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType) {
|
||||||
|
|
||||||
succeeded := 0
|
succeeded := 0
|
||||||
failed := 0
|
failed := 0
|
||||||
|
|
||||||
|
sourcename := getSourceName(2)
|
||||||
|
|
||||||
|
t.Logf("Test suite %s from file %s", section, sourcename)
|
||||||
|
|
||||||
for i, input := range inputs {
|
for i, input := range inputs {
|
||||||
// fmt.Printf("%3d: %s\n", i+1, input.source)
|
// fmt.Printf("%3d: %s\n", i+1, input.source)
|
||||||
|
|
||||||
@@ -61,8 +86,8 @@ func runCtxTestSuite(t *testing.T, ctx kern.ExprContext, section string, inputs
|
|||||||
}
|
}
|
||||||
t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
|
t.Logf("%s -- test count: %d, succeeded: %d, failed: %d", section, len(inputs), succeeded, failed)
|
||||||
}
|
}
|
||||||
func runTestSuite(t *testing.T, section string, inputs []inputType) {
|
func RunTestSuite(t *testing.T, section string, inputs []inputType) {
|
||||||
runCtxTestSuite(t, nil, section, inputs)
|
RunCtxTestSuite(t, nil, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getWantedError(input *inputType) error {
|
func getWantedError(input *inputType) error {
|
||||||
@@ -98,14 +123,21 @@ func doTest(t *testing.T, ctx kern.ExprContext, section string, input *inputType
|
|||||||
gotResult, gotErr = ast.Eval(ctx)
|
gotResult, gotErr = ast.Eval(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if gotErr == nil {
|
||||||
|
if wantErr == nil {
|
||||||
eq := kern.Equal(gotResult, input.wantResult)
|
eq := kern.Equal(gotResult, input.wantResult)
|
||||||
|
|
||||||
if !eq /*gotResult != input.wantResult*/ {
|
if !eq /*gotResult != input.wantResult*/ {
|
||||||
t.Errorf(">>>%s/%d: `%s` -> result = %v [%s], want = %v [%s]", section, count, input.source, gotResult, kern.TypeName(gotResult), input.wantResult, kern.TypeName(input.wantResult))
|
t.Errorf(">>>%s/%d: `%s` -> result = %v [%s], want = %v [%s]", section, count, input.source, gotResult, kern.TypeName(gotResult), input.wantResult, kern.TypeName(input.wantResult))
|
||||||
good = false
|
good = false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf(">>>%s/%d: `%s` -> result = %v [%s], got-err = <nil>, expected-err = %v", section, count, input.source, gotResult, kern.TypeName(gotResult), wantErr)
|
||||||
|
good = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if gotErr != wantErr {
|
if good && gotErr != wantErr {
|
||||||
if wantErr == nil || gotErr == nil || (gotErr.Error() != wantErr.Error()) {
|
if wantErr == nil || gotErr == nil || (gotErr.Error() != wantErr.Error()) {
|
||||||
t.Errorf(">>>%s/%d: %s -> got-err = <%v>, expected-err = <%v>", section, count, input.source, gotErr, wantErr)
|
t.Errorf(">>>%s/%d: %s -> got-err = <%v>, expected-err = <%v>", section, count, input.source, gotErr, wantErr)
|
||||||
good = false
|
good = false
|
||||||
@@ -145,3 +177,10 @@ func testIteratorCallOp(t *testing.T, section string, it kern.Iterator) {
|
|||||||
t.Errorf(`%s -- CallOperation("fake") should return error`, section)
|
t.Errorf(`%s -- CallOperation("fake") should return error`, section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test utilities
|
||||||
|
|
||||||
|
func fileExists(filePath string) bool {
|
||||||
|
_, err := os.Stat(filePath)
|
||||||
|
return !errors.Is(err, os.ErrNotExist)
|
||||||
|
}
|
||||||
|
|||||||
+4
-4
@@ -7,7 +7,7 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCtrlSet(t *testing.T) {
|
func TestCtrlSet(t *testing.T) {
|
||||||
@@ -82,12 +82,12 @@ func TestList(t *testing.T) {
|
|||||||
section := "Context"
|
section := "Context"
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`$$(5)`, kern.NewLinkedListA(5), nil},
|
/* 1 */ {`$$(5)`, list.NewLinkedListA(5), nil},
|
||||||
/* 2 */ {`$$($(2))`, kern.NewLinkedListA(0, 1), nil},
|
/* 2 */ {`$$($(..2))`, list.NewLinkedListA(0, 1), nil},
|
||||||
/* 3 */ {`string(($$global).funcs.bool)`, `bool(value):boolean{}`, nil},
|
/* 3 */ {`string(($$global).funcs.bool)`, `bool(value):boolean{}`, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 3)
|
// runTestSuiteSpec(t, section, inputs, 3)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-20
@@ -11,44 +11,63 @@ 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/sym"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDictParser(t *testing.T) {
|
func TestDictParser(t *testing.T) {
|
||||||
section := "Dict"
|
section := "Dict"
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`{}`, kern.NewDict(nil), nil},
|
/* 1 */ {`{}`, dict.NewDict(nil), nil},
|
||||||
/* 2 */ {`{123}`, nil, errors.New("[1:6] expected `:`, got `}`")},
|
/* 2 */ {`{123}`, nil, errors.New("[1:6] expected `:`, got `}`")},
|
||||||
/* 3 */ {`{1:"one",2:"two",3:"three"}`, kern.NewDict(map[any]any{int64(1): "one", int64(2): "two", int64(3): "three"}), nil},
|
/* 3 */ {`{1:"one",2:"two",3:"three"}`, dict.NewDict(map[any]any{int64(1): "one", int64(2): "two", int64(3): "three"}), nil},
|
||||||
/* 4 */ {`{1:"one",2:"two",3:"three"}[3]`, "three", nil},
|
/* 4 */ {`{1:"one",2:"two",3:"three"}[3]`, "three", nil},
|
||||||
/* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
|
/* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
|
||||||
/* 6 */ {`{1:"one"} + {2:"two"}`, kern.NewDict(map[any]any{int64(1): "one", int64(2): "two"}), nil},
|
/* 6 */ {`{1:"one"} + {2:"two"}`, dict.NewDict(map[any]any{int64(1): "one", int64(2): "two"}), nil},
|
||||||
/* 7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
|
/* 7 */ {`2 in {1:"one", 2:"two"}`, true, nil},
|
||||||
/* 8 */ {`D={"a":1, "b":2}; D["a"]=9; D`, kern.NewDict(map[any]any{"a": int64(9), "b": int64(2)}), nil},
|
/* 8 */ {`D={"a":1, "b":2}; D["a"]=9; D`, dict.NewDict(map[any]any{"a": int64(9), "b": int64(2)}), nil},
|
||||||
/* 9 */ {`D={"a":1, "b":2}; D["z"]=9; D`, kern.NewDict(map[any]any{"z": int64(9), "a": int64(1), "b": int64(2)}), nil},
|
/* 9 */ {`D={"a":1, "b":2}; D["z"]=9; D`, dict.NewDict(map[any]any{"z": int64(9), "a": int64(1), "b": int64(2)}), nil},
|
||||||
/* 10 */ {`D={"a":1, "b":2}; D[nil]=9`, nil, errors.New(`[1:21] index/key is nil`)},
|
/* 10 */ {`D={"a":1, "b":2}; D[nil]=9`, nil, errors.New(`[1:21] index/key is nil`)},
|
||||||
/* 11 */ {`D={"a":1, "b":2}; D["a"]`, int64(1), nil},
|
/* 11 */ {`D={"a":1, "b":2}; D["a"]`, int64(1), nil},
|
||||||
/* 12 */ {`m={
|
/* 12 */ {`m={
|
||||||
"a":1,
|
"a":1,
|
||||||
//"b":2,
|
//"b":2,
|
||||||
"c":3
|
"c":3
|
||||||
}`, kern.NewDict(map[any]any{"a": int64(1), "c": int64(3)}), nil},
|
}`, dict.NewDict(map[any]any{"a": int64(1), "c": int64(3)}), nil},
|
||||||
/* 13 */ {`D={"a":1, "b":2}; D."a"`, int64(1), nil},
|
/* 13 */ {`D={"a":1, "b":2}; D."a"`, int64(1), nil},
|
||||||
/* 14 */ {`D={"a":1, "b":2}; D.a`, int64(1), nil},
|
/* 14 */ {`D={"a":1, "b":2}; D.a`, int64(1), nil},
|
||||||
/* 15 */ {`D={1:"a", 2:"b", 3:"c"}; D.(1+2)`, "c", nil},
|
/* 15 */ {`D={1:"a", 2:"b", 3:"c"}; D.(1+2)`, "c", nil},
|
||||||
/* 16 */ {`D={1:"a"}; D.2`, nil, `[1:15] key 2 not found`},
|
/* 16 */ {`D={1:"a"}; D.2`, nil, `[1:15] key 2 not found`},
|
||||||
/* 17 */ {`D={1:"a"}; D."2"`, nil, `[1:17] key "2" not found`},
|
/* 17 */ {`D={1:"a"}; D."2"`, nil, `[1:17] key "2" not found`},
|
||||||
/* 18 */ {`D={"a":1, "b":2}; D.a = 10; D.a`, int64(10), nil},
|
/* 18 */ {`D={"a":1, "b":2}; D.a = 10; D.a`, int64(10), nil},
|
||||||
/* 19 */ {`k="a"; D={k: 10}`, kern.NewDict(map[any]any{"a": int64(10)}), nil},
|
/* 19 */ {`k="a"; D={k: 10}`, dict.NewDict(map[any]any{"a": int64(10)}), nil},
|
||||||
/* 20 */ {`k=[<1,2>]; D={k: 10}`, nil, `[1:16] dict key can be integer or string, got lisked-list`},
|
/* 20 */ {`k=[<1,2>]; D={k: 10}`, nil, `[1:16] dict key can be integer or string, got lisked-list`},
|
||||||
/* 21 */ {`f=func(n){"x"+n}; d{f(5):10}`, nil, `[0:0] two adjacent operators: "d" and "{}"`},
|
/* 21 */ {`f=func(n){"x"+n}; d{f(5):10}`, nil, `[0:0] two adjacent operators: "d" and "{}"`},
|
||||||
/* 22 */ {`f=func(n){"x"+n}; d={f(5):10}`, kern.NewDict(map[any]any{"x5": int64(10)}), nil},
|
/* 22 */ {`f=func(n){"x"+n}; d={f(5):10}`, dict.NewDict(map[any]any{"x5": int64(10)}), nil},
|
||||||
/* 23 */ {`f=func(n){"x"+n}; d={f(5); "z":10}`, nil, "[1:27] expected one of `:`, `}`, got `;`"},
|
/* 23 */ {`f=func(n){"x"+n}; d={f(5); "z":10}`, nil, "[1:27] expected one of `:`, `}`, got `;`"},
|
||||||
/* 24 */ {`f=func(n){"x"+n}; d={f(5) but "z":10}`, kern.NewDict(map[any]any{"z": int64(10)}), nil},
|
/* 24 */ {`f=func(n){"x"+n}; d={f(5) but "z":10}`, dict.NewDict(map[any]any{"z": int64(10)}), nil},
|
||||||
|
/* 25 */ {`3 in {1:"one", 2:"two"}`, false, nil},
|
||||||
|
/* 26 */ {`1 at {"a":2, "b":3, "c":1}`, "c", nil},
|
||||||
|
/* 27 */ {`10 at {"a":2, "b":3, "c":1}`, nil, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 23, 24)
|
// RunTestSuiteSpec(t, section, inputs, 1)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOperations(t *testing.T) {
|
||||||
|
section := "Dict-Operations"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`{"a":1} + {"b":2}`, dict.NewDict(map[any]any{"a": int64(1), "b": int64(2)}), nil},
|
||||||
|
/* 2 */ {`D={"a":1}; C={"b":2}; X=D+C; C."b" = 3; X`, dict.NewDict(map[any]any{"a": int64(1), "b": int64(2)}), nil},
|
||||||
|
/* 3 */ {`D={"a":1}; C={"b":2}; X=D+C; D."a" = 3; X`, dict.NewDict(map[any]any{"a": int64(1), "b": int64(2)}), nil},
|
||||||
|
/* 4 */ {`L=[8,9]; D={"a":L}; L[0]=11; D."a"[0]`, int64(11), nil},
|
||||||
|
/* 5 */ {`L=[8,9]; D:={"a":L}; L[0]=11; D."a"[0]`, int64(8), nil},
|
||||||
|
}
|
||||||
|
// runTestSuiteSpec(t, section, inputs, 1)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccessSubFields(t *testing.T) {
|
func TestAccessSubFields(t *testing.T) {
|
||||||
@@ -56,9 +75,9 @@ func TestAccessSubFields(t *testing.T) {
|
|||||||
ctx := NewSimpleStore()
|
ctx := NewSimpleStore()
|
||||||
ctx.UnsafeSetVar(
|
ctx.UnsafeSetVar(
|
||||||
"D",
|
"D",
|
||||||
kern.NewDict(map[any]any{
|
dict.NewDict(map[any]any{
|
||||||
"a": kern.NewDict(map[any]any{"uno": int64(10)}),
|
"a": dict.NewDict(map[any]any{"uno": int64(10)}),
|
||||||
"b": kern.NewListA(1, 2, 3),
|
"b": list.NewLinkedListA(1, 2, 3),
|
||||||
}),
|
}),
|
||||||
) // D={"a": {"uno":1}}
|
) // D={"a": {"uno":1}}
|
||||||
|
|
||||||
@@ -67,9 +86,21 @@ func TestAccessSubFields(t *testing.T) {
|
|||||||
/* 2 */ {`D.a.uno = 111; D.a."uno"`, int64(111), nil},
|
/* 2 */ {`D.a.uno = 111; D.a."uno"`, int64(111), nil},
|
||||||
/* 3 */ {`D.a.uno = 111; D["a"]["uno"]`, int64(111), nil},
|
/* 3 */ {`D.a.uno = 111; D["a"]["uno"]`, int64(111), nil},
|
||||||
/* 4 */ {`D.b[1] = 22; D["b"][1]`, int64(22), nil},
|
/* 4 */ {`D.b[1] = 22; D["b"][1]`, int64(22), nil},
|
||||||
|
// /* 4 */ {`D.b[1] = 22; D["b"][1]`, nil, `[1:3] collection expected`},
|
||||||
}
|
}
|
||||||
// runCtxTestSuiteSpec(t, ctx, section, inputs, 4)
|
RunCtxTestSuiteSpec(t, ctx, section, inputs, 4)
|
||||||
runCtxTestSuite(t, ctx, section, inputs)
|
// runCtxTestSuite(t, ctx, section, inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDictDeepAssign(t *testing.T) {
|
||||||
|
section := "Dict-DeepAssign"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`DD={"uno": 1, "due": 2}; D=DD; D["uno"]=11; DD`, dict.NewDict(map[any]any{"uno": int64(11), "due": int64(2)}), nil},
|
||||||
|
/* 2 */ {`DD={"uno": 1, "due": 2}; D:=DD; D["uno"]=11; DD`, dict.NewDict(map[any]any{"uno": int64(1), "due": int64(2)}), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
// runTestSuiteSpec(t, section, inputs, 4)
|
||||||
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDictToStringMultiLine(t *testing.T) {
|
func TestDictToStringMultiLine(t *testing.T) {
|
||||||
@@ -79,9 +110,9 @@ func TestDictToStringMultiLine(t *testing.T) {
|
|||||||
"first": 1
|
"first": 1
|
||||||
}`
|
}`
|
||||||
args := map[any]any{
|
args := map[any]any{
|
||||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, scan.SymInteger, "1", 1)),
|
"first": newLiteralTerm(scan.NewValueToken(0, 0, sym.SymInteger, "1", 1)),
|
||||||
}
|
}
|
||||||
dict := kern.NewDict(args)
|
dict := dict.NewDict(args)
|
||||||
got := dict.ToString(kern.MultiLine)
|
got := dict.ToString(kern.MultiLine)
|
||||||
// fmt.Printf("got=%q\n", got)
|
// fmt.Printf("got=%q\n", got)
|
||||||
|
|
||||||
@@ -101,9 +132,9 @@ func TestDictToString(t *testing.T) {
|
|||||||
section := "dict-ToString-SL"
|
section := "dict-ToString-SL"
|
||||||
want := `{"first": 1}`
|
want := `{"first": 1}`
|
||||||
args := map[any]any{
|
args := map[any]any{
|
||||||
"first": newLiteralTerm(scan.NewValueToken(0, 0, scan.SymInteger, "1", 1)),
|
"first": newLiteralTerm(scan.NewValueToken(0, 0, sym.SymInteger, "1", 1)),
|
||||||
}
|
}
|
||||||
dict := kern.NewDict(args)
|
dict := dict.NewDict(args)
|
||||||
got := dict.ToString(0)
|
got := dict.ToString(0)
|
||||||
// fmt.Printf("got=%q\n", got)
|
// fmt.Printf("got=%q\n", got)
|
||||||
|
|
||||||
|
|||||||
+23
-22
@@ -7,7 +7,7 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExpr(t *testing.T) {
|
func TestExpr(t *testing.T) {
|
||||||
@@ -16,23 +16,26 @@ func TestExpr(t *testing.T) {
|
|||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`0?{}`, nil, nil},
|
/* 1 */ {`0?{}`, nil, nil},
|
||||||
/* 2 */ {`fact=func(n){(n)?{1}::{n*fact(n-1)}}; fact(5)`, int64(120), nil},
|
/* 2 */ {`fact=func(n){(n)?{1}::{n*fact(n-1)}}; fact(5)`, int64(120), nil},
|
||||||
/* 3 */ {`builtin "os.file"; f=fileOpen("test-file.txt"); line=fileReadText(f); fileClose(f); line`, "uno", nil},
|
/* 3 */ {`mynot=func(v){int(v)?{true}::{false}}; mynot(0)`, true, nil},
|
||||||
/* 4 */ {`mynot=func(v){int(v)?{true}::{false}}; mynot(0)`, true, nil},
|
/* 4 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
|
||||||
/* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
|
/* 5 */ {`a=3; a+=1; a`, int64(4), nil},
|
||||||
/* 6 */ {`a=3; a+=1; a`, int64(4), nil},
|
/* 6 */ {`a=3; a-=1; a`, int64(2), nil},
|
||||||
/* 7 */ {`a=3; a-=1; a`, int64(2), nil},
|
/* 7 */ {`a=3; a*=2; a`, int64(6), nil},
|
||||||
/* 8 */ {`a=3; a*=2; a`, int64(6), nil},
|
/* 8 */ {`v=[10,20,30]; v[0]+=1; v[0]`, int64(11), nil},
|
||||||
/* 9 */ {`v=[10,20,30]; v[0]+=1; v[0]`, int64(11), nil},
|
/* 9 */ {`r={"a":10}; r["a"]+=1; r["a"]`, int64(11), nil},
|
||||||
/* 10 */ {`r={"a":10}; r["a"]+=1; r["a"]`, int64(11), nil},
|
/* 10 */ {`a=3; a/=2`, int64(1), nil},
|
||||||
/* 11 */ {`a=3; a/=2`, int64(1), nil},
|
/* 11 */ {`*=2`, nil, `[1:2] infix operator "*=" requires two non-nil operands, got 1`},
|
||||||
/* 12 */ {`*=2`, nil, `[1:2] infix operator "*=" requires two non-nil operands, got 1`},
|
/* 12 */ {`a=3; a*=2+1; a`, int64(9), nil},
|
||||||
/* 13 */ {`a=3; a*=2+1; a`, int64(9), nil},
|
/* 13 */ {`a=3; (a*=2)+1; a`, int64(6), nil},
|
||||||
/* 14 */ {`a=3; (a*=2)+1; a`, int64(6), nil},
|
/* 14 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
|
||||||
/* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
|
/* 15 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil},
|
||||||
/* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil},
|
/* 16 */ {`true ? {"a"} :: {"b"}`, "a", nil},
|
||||||
/* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil},
|
/* 17 */ {`2 ? {"a"}`, nil, `[1:2] no case catches the value (2) of the selection expression`},
|
||||||
/* 18 */ {`$$`, kern.NewDict(map[any]any{"vars": kern.NewDict(nil), "funcs": kern.NewDict(nil)}), nil},
|
/* 18 */ {`2 ? 5`, nil, "[1:6] expected `{`, got `5`"},
|
||||||
/* 19 */ {`
|
/* 19 */ {`a=2; ${a}`, int64(2), nil},
|
||||||
|
/* 20 */ {`$_=2; $_`, int64(2), nil},
|
||||||
|
/* 21 */ {`$$`, dict.NewDict(map[any]any{"vars": dict.NewDict(nil), "funcs": dict.NewDict(nil)}), nil},
|
||||||
|
/* 22 */ {`
|
||||||
ds={
|
ds={
|
||||||
"init":func(@end){@current=0 but true},
|
"init":func(@end){@current=0 but true},
|
||||||
//"current":func(){current},
|
//"current":func(){current},
|
||||||
@@ -44,11 +47,9 @@ func TestExpr(t *testing.T) {
|
|||||||
it++;
|
it++;
|
||||||
it++
|
it++
|
||||||
`, int64(1), nil},
|
`, int64(1), nil},
|
||||||
/* 20 */ {`a=2; ${a}`, int64(2), nil},
|
|
||||||
/* 21 */ {`$_=2; $_`, int64(2), nil},
|
|
||||||
}
|
}
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 21)
|
// RunTestSuiteSpec(t, section, inputs, 19)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-15
@@ -8,37 +8,38 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/kern"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFractionsParser(t *testing.T) {
|
func TestFractionsParser(t *testing.T) {
|
||||||
section := "Fraction"
|
section := "Fraction"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`1:2`, kern.NewFraction(1, 2), nil},
|
/* 1 */ {`1:2`, fract.NewFraction(1, 2), nil},
|
||||||
/* 2 */ {`1:2 + 1`, kern.NewFraction(3, 2), nil},
|
/* 2 */ {`1:2 + 1`, fract.NewFraction(3, 2), nil},
|
||||||
/* 3 */ {`1:2 - 1`, kern.NewFraction(-1, 2), nil},
|
/* 3 */ {`1:2 - 1`, fract.NewFraction(-1, 2), nil},
|
||||||
/* 4 */ {`1:2 * 1`, kern.NewFraction(1, 2), nil},
|
/* 4 */ {`1:2 * 1`, fract.NewFraction(1, 2), nil},
|
||||||
/* 5 */ {`1:2 * 2:3`, kern.NewFraction(2, 6), nil},
|
/* 5 */ {`1:2 * 2:3`, fract.NewFraction(2, 6), nil},
|
||||||
/* 6 */ {`1:2 / 2:3`, kern.NewFraction(3, 4), nil},
|
/* 6 */ {`1:2 / 2:3`, fract.NewFraction(3, 4), nil},
|
||||||
/* 7 */ {`1:"5"`, nil, `denominator must be integer, got string (5)`},
|
/* 7 */ {`1:"5"`, nil, `denominator must be integer, got string (5)`},
|
||||||
/* 8 */ {`"1":5`, nil, `numerator must be integer, got string (1)`},
|
/* 8 */ {`"1":5`, nil, `numerator must be integer, got string (1)`},
|
||||||
/* 9 */ {`1:+5`, kern.NewFraction(1, 5), nil},
|
/* 9 */ {`1:+5`, fract.NewFraction(1, 5), nil},
|
||||||
/* 10 */ {`1:(-2)`, kern.NewFraction(-1, 2), nil},
|
/* 10 */ {`1:(-2)`, fract.NewFraction(-1, 2), nil},
|
||||||
/* 11 */ {`builtin "math.arith"; add(1:2, 2:3)`, kern.NewFraction(7, 6), nil},
|
/* 11 */ {`builtin "math.arith"; add(1:2, 2:3)`, fract.NewFraction(7, 6), nil},
|
||||||
/* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil},
|
/* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil},
|
||||||
/* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, kern.NewFraction(2, 6), nil},
|
/* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, fract.NewFraction(2, 6), nil},
|
||||||
/* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil},
|
/* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil},
|
||||||
/* 15 */ {`1:0`, nil, `[1:3] division by zero`},
|
/* 15 */ {`1:0`, nil, `[1:3] division by zero`},
|
||||||
/* 16 */ {`1+1:2+0.5`, float64(2), nil},
|
/* 16 */ {`1+1:2+0.5`, float64(2), nil},
|
||||||
/* 17 */ {`1:(2-2)`, nil, `[1:3] division by zero`},
|
/* 17 */ {`1:(2-2)`, nil, `[1:3] division by zero`},
|
||||||
/* 18 */ {`[0,1][1-1]:1`, kern.NewFraction(0, 1), nil},
|
/* 18 */ {`[0,1][1-1]:1`, fract.NewFraction(0, 1), nil},
|
||||||
/* 19 */ {`1:2 == 0.5`, true, nil},
|
/* 19 */ {`1:2 == 0.5`, true, nil},
|
||||||
}
|
}
|
||||||
// runTestSuiteSpec(t, section, inputs, 26)
|
// runTestSuiteSpec(t, section, inputs, 26)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFractionToStringSimple(t *testing.T) {
|
func TestFractionToStringSimple(t *testing.T) {
|
||||||
source := kern.NewFraction(1, 2)
|
source := fract.NewFraction(1, 2)
|
||||||
want := "1:2"
|
want := "1:2"
|
||||||
got := source.ToString(0)
|
got := source.ToString(0)
|
||||||
if got != want {
|
if got != want {
|
||||||
@@ -47,7 +48,7 @@ func TestFractionToStringSimple(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFractionToStringMultiline(t *testing.T) {
|
func TestFractionToStringMultiline(t *testing.T) {
|
||||||
source := kern.NewFraction(1, 2)
|
source := fract.NewFraction(1, 2)
|
||||||
want := "1\n-\n2"
|
want := "1\n-\n2"
|
||||||
got := source.ToString(kern.MultiLine)
|
got := source.ToString(kern.MultiLine)
|
||||||
if got != want {
|
if got != want {
|
||||||
@@ -56,7 +57,7 @@ func TestFractionToStringMultiline(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestToStringMultilineTty(t *testing.T) {
|
func TestToStringMultilineTty(t *testing.T) {
|
||||||
source := kern.NewFraction(-1, 2)
|
source := fract.NewFraction(-1, 2)
|
||||||
want := "\x1b[4m-1\x1b[0m\n 2"
|
want := "\x1b[4m-1\x1b[0m\n 2"
|
||||||
got := source.ToString(kern.MultiLine | kern.TTY)
|
got := source.ToString(kern.MultiLine | kern.TTY)
|
||||||
if got != want {
|
if got != want {
|
||||||
|
|||||||
+3
-3
@@ -46,7 +46,7 @@ func TestFuncs(t *testing.T) {
|
|||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
//runTestSuiteSpec(t, section, inputs, 19)
|
//runTestSuiteSpec(t, section, inputs, 19)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuncs2(t *testing.T) {
|
func TestFuncs2(t *testing.T) {
|
||||||
@@ -57,7 +57,7 @@ func TestFuncs2(t *testing.T) {
|
|||||||
/* 3 */ {`builtin "iterator"; times=func(a,b){a*b}; run($(["1", "2", "3"]), times)`, nil, `operator(): missing params -- a, b`},
|
/* 3 */ {`builtin "iterator"; times=func(a,b){a*b}; run($(["1", "2", "3"]), times)`, nil, `operator(): missing params -- a, b`},
|
||||||
}
|
}
|
||||||
// runTestSuiteSpec(t, section, inputs, 4)
|
// runTestSuiteSpec(t, section, inputs, 4)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dummy(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
func dummy(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
|
||||||
@@ -102,6 +102,6 @@ func TestGoFunction(t *testing.T) {
|
|||||||
kern.NewFuncParamFlagDef("name", kern.PfOptional|kern.PfDefault, "Celestino Amoroso"),
|
kern.NewFuncParamFlagDef("name", kern.PfOptional|kern.PfDefault, "Celestino Amoroso"),
|
||||||
})
|
})
|
||||||
|
|
||||||
runCtxTestSuite(t, ctx, section, inputs)
|
RunCtxTestSuite(t, ctx, section, inputs)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-11
@@ -7,24 +7,48 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.portale-stac.it/go-pkg/expr/kern"
|
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||||
|
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCollections(t *testing.T) {
|
func TestCollections(t *testing.T) {
|
||||||
section := "Index"
|
section := "Index"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`"abcdef"[1:3]`, "bc", nil},
|
/* 1 */ {`"abcdef"[1..3]`, "bc", nil},
|
||||||
/* 2 */ {`"abcdef"[:3]`, "abc", nil},
|
/* 2 */ {`"abcdef"[..3]`, "abc", nil},
|
||||||
/* 3 */ {`"abcdef"[1:]`, "bcdef", nil},
|
/* 3 */ {`"abcdef"[1..]`, "bcdef", nil},
|
||||||
/* 4 */ {`"abcdef"[:]`, "abcdef", nil},
|
/* 4 */ {`"abcdef"[..]`, "abcdef", nil},
|
||||||
/* 5 */ {`"abcdef"[1:2:3]`, nil, `[1:14] invalid range specification`},
|
/* 5 */ {`"abcdef"[1..2..3]`, `b`, nil},
|
||||||
/* 6 */ {`"abcdef"[((1>0)?{1}:{0}):3]`, "bc", nil},
|
/* 6 */ {`"abcdef"[((1>0)?{1}:{0})..3]`, "bc", nil},
|
||||||
/* 7 */ {`"abcdef"[[0,1][0]:1]`, "a", nil},
|
/* 7 */ {`"abcdef"[[0,1][0]..1]`, "a", nil},
|
||||||
/* 8 */ {`[0,1,2,3,4][:]`, kern.NewListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
/* 8 */ {`"abcdef"[..1]`, "a", nil},
|
||||||
|
/* 9 */ {`"abcdef"[..-1]`, "abcde", nil},
|
||||||
|
/* 10 */ {`"abcdef"[..-1..2]`, "ace", nil},
|
||||||
|
/* 11 */ {`"abcdef"[-3..-1..2]`, "d", nil},
|
||||||
|
/* 12 */ {`"abcdef"[3..0]`, "dcba", nil},
|
||||||
|
/* 13 */ {`"abcdef"[-1..0..2]`, "fdb", nil},
|
||||||
|
/* 14 */ {`[0,1,2,3,4][..]`, array.NewIntArrayA(0, 1, 2, 3, 4), nil},
|
||||||
|
/* 15 */ {`[0,1,2,3,4][2..3]`, array.NewIntArrayA(2), nil},
|
||||||
|
/* 16 */ {`[0,1,2,3,4][3..-1]`, array.NewIntArrayA(3), nil},
|
||||||
|
/* 17 */ {`[0,1,2,3,4][-3..-1]`, array.NewIntArrayA(2, 3), nil},
|
||||||
|
/* 18 */ {`[0,1,2,3,4][0..]`, array.NewIntArrayA(0, 1, 2, 3, 4), nil},
|
||||||
|
/* 19 */ {`[0,1,2,3,4][0..-1..2]`, array.NewIntArrayA(0, 2), nil},
|
||||||
|
/* 20 */ {`[0,1,2,3,4][-1..0..2]`, array.NewIntArrayA(4, 2), nil},
|
||||||
|
/* 21 */ {`[<0,1,2,3,4>][..]`, list.NewLinkedListA(0, 1, 2, 3, 4), nil},
|
||||||
|
/* 22 */ {`[<0,1,2,3,4>][2..3]`, list.NewLinkedListA(2), nil},
|
||||||
|
/* 23 */ {`[<0,1,2,3,4>][3..-1]`, list.NewLinkedListA(3), nil},
|
||||||
|
/* 24 */ {`[<0,1,2,3,4>][-3..-1]`, list.NewLinkedListA(2, 3), nil},
|
||||||
|
/* 25 */ {`[<0,1,2,3,4>][0..]`, list.NewLinkedListA(0, 1, 2, 3, 4), nil},
|
||||||
|
/* 26 */ {`[<0,1,2,3,4>][0..-1..2]`, list.NewLinkedListA(0, 2), nil},
|
||||||
|
/* 27 */ {`[<0,1,2,3,4>][-1..0..2]`, list.NewLinkedListA(4, 2), nil},
|
||||||
|
/* 28 */ {`[-1..0..2]`, nil, `[1:8] unexpected interval expression`},
|
||||||
|
/* 29 */ {`"abcdef"['x'..]`, nil, `[1:14] interval expression expected integer, got string (x)`},
|
||||||
|
/* 30 */ {`"abcdef"[1+..]`, nil, `[1:12] infix operator "+" requires two non-nil operands, got 1`},
|
||||||
|
/* 31 */ {`"abcdef"[1..4+]`, nil, `[1:15] infix operator "+" requires two non-nil operands, got 1`},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("EXPR_PATH", ".")
|
t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 5)
|
// RunTestSuiteSpec(t, section, inputs, 30)
|
||||||
runTestSuite(t, section, inputs)
|
RunTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user