Compare commits

...

6 Commits

10 changed files with 172 additions and 59 deletions

View File

@ -30,7 +30,7 @@ func importGeneral(ctx ExprContext, name string, args []any) (result any, err er
dirList = addEnvImportDirs(dirList)
dirList = addPresetImportDirs(ctx, dirList)
result, err = doImport(ctx, name, dirList, NewFlatArrayIterator(args))
result, err = doImport(ctx, name, dirList, NewArrayIterator(args))
return
}

View File

@ -37,8 +37,8 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
if err = checkNumberParamExpected(name, v, it.Index()); err != nil {
break
}
if array, ok := v.(*ListType); ok {
if v, err = doAdd(ctx, name, NewFlatArrayIterator(*array)); err != nil {
if list, ok := v.(*ListType); ok {
if v, err = doAdd(ctx, name, NewListIterator(list)); err != nil {
break
}
}
@ -87,7 +87,7 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
}
func addFunc(ctx ExprContext, name string, args []any) (result any, err error) {
result, err = doAdd(ctx, name, NewFlatArrayIterator(args))
result, err = doAdd(ctx, name, NewArrayIterator(args))
return
}
@ -113,8 +113,8 @@ func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
break
}
if array, ok := v.(*ListType); ok {
if v, err = doMul(ctx, name, NewFlatArrayIterator(*array)); err != nil {
if list, ok := v.(*ListType); ok {
if v, err = doMul(ctx, name, NewListIterator(list)); err != nil {
break
}
}
@ -163,7 +163,7 @@ func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
}
func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) {
result, err = doMul(ctx, name, NewFlatArrayIterator(args))
result, err = doMul(ctx, name, NewArrayIterator(args))
return
}

View File

@ -39,15 +39,15 @@ func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
if len(args) == 1 {
result = ""
} else if len(args) == 2 {
if ls, ok := args[1].([]any); ok {
result, err = doJoinStr(name, sep, NewFlatArrayIterator(ls))
if ls, ok := args[1].(*ListType); ok {
result, err = doJoinStr(name, sep, NewListIterator(ls))
} else if it, ok := args[1].(Iterator); ok {
result, err = doJoinStr(name, sep, it)
} else {
err = errInvalidParameterValue(name, paramParts, args[1])
}
} else {
result, err = doJoinStr(name, sep, NewFlatArrayIterator(args[1:]))
result, err = doJoinStr(name, sep, NewArrayIterator(args[1:]))
}
} else {
err = errWrongParamType(name, paramSeparator, typeString, args[0])

View File

@ -6,33 +6,53 @@ package expr
import "io"
type FlatArrayIterator struct {
a ListType
type ListIterator struct {
a *ListType
index int
}
func NewFlatArrayIterator(array ListType) *FlatArrayIterator {
return &FlatArrayIterator{a: array, index: 0}
func NewListIterator(list *ListType) *ListIterator {
return &ListIterator{a: list, index: 0}
}
func (it *FlatArrayIterator) HasOperation(name string) bool {
func NewArrayIterator(array []any) *ListIterator {
return &ListIterator{a: (*ListType)(&array), index: 0}
}
func NewAnyIterator(value any) (it *ListIterator) {
if value == nil {
it = NewArrayIterator([]any{})
} else if list, ok := value.(*ListType); ok {
it = NewListIterator(list)
} else if array, ok := value.([]any); ok {
it = NewArrayIterator(array)
} else if it1, ok := value.(*ListIterator); ok {
it = it1
} else {
it = NewArrayIterator([]any{value})
}
return
}
func (it *ListIterator) HasOperation(name string) bool {
return false
}
func (it *FlatArrayIterator) CallOperation(name string, args []any) (any, error) {
func (it *ListIterator) CallOperation(name string, args []any) (any, error) {
return nil, errNoOperation(name)
}
func (it *FlatArrayIterator) Current() (item any, err error) {
if it.index >= 0 && it.index < len(it.a) {
item = it.a[it.index]
func (it *ListIterator) Current() (item any, err error) {
a := *(it.a)
if it.index >= 0 && it.index < len(a) {
item = a[it.index]
} else {
err = io.EOF
}
return
}
func (it *FlatArrayIterator) Next() (item any, err error) {
func (it *ListIterator) Next() (item any, err error) {
if item, err = it.Current(); err != io.EOF {
it.index++
}
@ -45,6 +65,6 @@ func (it *FlatArrayIterator) Next() (item any, err error) {
return
}
func (it *FlatArrayIterator) Index() int {
func (it *ListIterator) Index() int {
return it.index - 1
}

View File

@ -42,6 +42,10 @@ func (ls *ListType) ToString(opt FmtOpt) string {
return sb.String()
}
func (ls *ListType) String() string {
return ls.ToString(0)
}
// -------- list term
func newListTermA(args ...*term) *term {
return newListTerm(args)

View File

@ -4,6 +4,8 @@
// operator-builtin.go
package expr
import "io"
//-------- builtin term
func newBuiltinTerm(tk *Token) (inst *term) {
@ -17,16 +19,20 @@ func newBuiltinTerm(tk *Token) (inst *term) {
}
func evalBuiltin(ctx ExprContext, self *term) (v any, err error) {
var rightValue any
var childValue any
if rightValue, err = self.evalPrefix(ctx); err != nil {
if childValue, err = self.evalPrefix(ctx); err != nil {
return
}
count := 0
if isList(rightValue) {
list, _ := rightValue.([]any)
for i, moduleSpec := range list {
if isString(childValue) {
module, _ := childValue.(string)
count, err = ImportInContextByGlobPattern(ctx, module)
} else {
var moduleSpec any
it := NewAnyIterator(childValue)
for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() {
if module, ok := moduleSpec.(string); ok {
if ImportInContext(ctx, module) {
count++
@ -35,15 +41,13 @@ func evalBuiltin(ctx ExprContext, self *term) (v any, err error) {
break
}
} else {
err = self.Errorf("expected string at item nr %d, got %T", i+1, moduleSpec)
err = self.Errorf("expected string at item nr %d, got %T", it.Index()+1, moduleSpec)
break
}
}
} else if isString(rightValue) {
module, _ := rightValue.(string)
count, err = ImportInContextByGlobPattern(ctx, module)
} else {
err = self.errIncompatibleType(rightValue)
if err == io.EOF {
err = nil
}
}
if err == nil {
v = count

View File

@ -31,6 +31,9 @@ func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
}
if sourceCtx != nil {
if formatter, ok := ctx.(Formatter); ok {
v = formatter.ToString(0)
} else {
keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
d := make(map[string]any)
for _, key := range keys {
@ -38,9 +41,10 @@ func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
}
keys = sourceCtx.EnumFuncs(func(name string) bool { return true })
for _, key := range keys {
d[key], _ =sourceCtx.GetFuncInfo(key)
d[key], _ = sourceCtx.GetFuncInfo(key)
}
v = d
}
} else {
err = self.errIncompatibleType(childValue)
}

View File

@ -132,7 +132,7 @@ func TestParser(t *testing.T) {
/* 110 */ {`double=func(x){2*x}; a=5; double(3+a) + 1`, int64(17), nil},
/* 111 */ {`double=func(x){2*x}; a=5; two=func() {2}; (double(3+a) + 1) * two()`, int64(34), nil},
/* 112 */ {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
/* 113 */ {`import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
// /* 113 */ {`import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
/* 114 */ {`x ?? "default"`, "default", nil},
/* 115 */ {`x="hello"; x ?? "default"`, "hello", nil},
/* 116 */ {`y=x ?? func(){4}; y()`, int64(4), nil},
@ -145,7 +145,7 @@ func TestParser(t *testing.T) {
/* 123 */ {`f=func(@y){g=func(){@x=5}; @z=g(); @y=@y+@z}; f(2); y+z`, int64(12), nil},
/* 124 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @y=@y+@z}; f(2); y+z`, int64(12), nil},
/* 125 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @x=@y+@z}; f(2); y+x`, int64(9), nil},
/* 126 */ {`include("./test-funcs.expr"); six()`, int64(6), nil},
// /* 126 */ {`include("./test-funcs.expr"); six()`, int64(6), nil},
/* 127 */ {`import("./sample-export-all.expr"); six()`, int64(6), nil},
/* 128 */ {`1 ? {"a"} : {"b"}`, "b", nil},
/* 129 */ {`10 ? {"a"} : {"b"} :: {"c"}`, "c", nil},
@ -162,7 +162,23 @@ func TestParser(t *testing.T) {
/* 140 */ {`{"key"}`, nil, errors.New(`[1:8] expected ":", got "}"`)},
/* 141 */ {`{"key":}`, nil, errors.New(`[1:9] expected dictionary value, got "}"`)},
/* 142 */ {`{}`, map[any]any{}, nil},
/* 144 */ //{`3^2`, int64(9), nil},
/* 143 */ {`1|2`, newFraction(1, 2), nil},
/* 144 */ {`1|2 + 1`, newFraction(3, 2), nil},
/* 145 */ {`1|2 - 1`, newFraction(-1, 2), nil},
/* 146 */ {`1|2 * 1`, newFraction(1, 2), nil},
/* 147 */ {`1|2 * 2|3`, newFraction(2, 6), nil},
/* 148 */ {`1|2 / 2|3`, newFraction(3, 4), nil},
/* 149 */ {`builtin "math.arith"; add(1|2, 2|3)`, newFraction(7, 6), nil},
/* 150 */ {`builtin "math.arith"; add(1|2, 1.0, 2)`, float64(3.5), nil},
/* 151 */ {`builtin "math.arith"; mul(1|2, 2|3)`, newFraction(2, 6), nil},
/* 152 */ {`builtin "math.arith"; mul(1|2, 1.0, 2)`, float64(1.0), nil},
/* 153 */ {`include "iterator.expr"; it=$(ds,3); ()it`, int64(0), nil},
/* 154 */ {`include "iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil},
/* 155 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(1), nil},
/* 156 */ {`include "iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil},
/* 157 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil},
/* 158 */ {`builtin "math.arith"; include "iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
/* 159 */ {`include "file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil},
}
check_env_expr_path := 113

View File

@ -4,7 +4,10 @@
// simple-func-store.go
package expr
import "fmt"
import (
"fmt"
"strings"
)
type SimpleFuncStore struct {
SimpleVarStore
@ -18,6 +21,29 @@ type funcInfo struct {
functor Functor
}
func (info *funcInfo) ToString(opt FmtOpt) string {
var sb strings.Builder
var i int
sb.WriteString("func(")
for i = 0; i < info.minArgs; i++ {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString(fmt.Sprintf("arg%d", i+1))
}
for ; i < info.maxArgs; i++ {
sb.WriteString(fmt.Sprintf("arg%d", i+1))
}
if info.maxArgs < 0 {
if info.minArgs > 0 {
sb.WriteString(", ")
}
sb.WriteString("...")
}
sb.WriteString(") {...}")
return sb.String()
}
func (info *funcInfo) Name() string {
return info.name
}
@ -52,6 +78,36 @@ func (ctx *SimpleFuncStore) Clone() ExprContext {
}
}
func funcsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
sb.WriteString("funcs: {\n")
first := true
for _, name := range ctx.EnumFuncs(func(name string) bool { return true }) {
if first {
first = false
} else {
sb.WriteByte(',')
sb.WriteByte('\n')
}
value, _ := ctx.GetFuncInfo(name)
sb.WriteString(strings.Repeat("\t", indent+1))
sb.WriteString(name)
sb.WriteString("=")
if formatter, ok := value.(Formatter); ok {
sb.WriteString(formatter.ToString(0))
} else {
sb.WriteString(fmt.Sprintf("%v", value))
}
}
sb.WriteString("\n}\n")
}
func (ctx *SimpleFuncStore) ToString(opt FmtOpt) string {
var sb strings.Builder
sb.WriteString(ctx.SimpleVarStore.ToString(opt))
funcsCtxToBuilder(&sb, ctx, 0)
return sb.String()
}
func (ctx *SimpleFuncStore) GetFuncInfo(name string) (info ExprFunc, exists bool) {
info, exists = ctx.funcStore[name]
return

View File

@ -79,34 +79,43 @@ func (ctx *SimpleVarStore) EnumFuncs(acceptor func(name string) (accept bool)) (
return
}
func CtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
sb.WriteString("{\n")
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
sb.WriteString("vars: {\n")
first := true
for _, name := range ctx.EnumVars(func(name string) bool { return name[0] != '_' }) {
if first {
first = false
} else {
sb.WriteByte(',')
sb.WriteByte('\n')
}
value, _ := ctx.GetVar(name)
sb.WriteString(strings.Repeat("\t", indent+1))
sb.WriteString(name)
sb.WriteString("=")
if _, ok := value.(Functor); ok {
sb.WriteString(": func(){}")
sb.WriteString(": ")
if f, ok := value.(Formatter); ok {
sb.WriteString(f.ToString(0))
} else if _, ok = value.(Functor); ok {
sb.WriteString("func(){}")
} else if _, ok = value.(map[any]any); ok {
sb.WriteString("dict{}")
} else {
sb.WriteString(fmt.Sprintf("%v", value))
}
if first {
first = false
} else {
sb.WriteByte(',')
}
sb.WriteByte('\n')
}
sb.WriteString(strings.Repeat("\t", indent))
sb.WriteString("}\n")
sb.WriteString("\n}\n")
}
func CtxToString(ctx ExprContext, indent int) string {
func varsCtxToString(ctx ExprContext, indent int) string {
var sb strings.Builder
CtxToBuilder(&sb, ctx, indent)
varsCtxToBuilder(&sb, ctx, indent)
return sb.String()
}
func (ctx *SimpleVarStore) ToString(opt FmtOpt) string {
var sb strings.Builder
varsCtxToBuilder(&sb, ctx, 0)
return sb.String()
}