Compare commits
	
		
			8 Commits
		
	
	
		
			24e6a293b0
			...
			866de759dd
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 866de759dd | |||
| b1d6b6de44 | |||
| 7e357eea62 | |||
| d6b4c79736 | |||
| d066344af8 | |||
| f41dba069e | |||
| 703ecf6829 | |||
| ba479a1b99 | 
@ -43,16 +43,16 @@ func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (re
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CallExprFunction(parentCtx ExprContext, funcName string, params ...any) (v any, err error) {
 | 
			
		||||
	ctx := cloneContext(parentCtx)
 | 
			
		||||
	ctx.SetParent(parentCtx)
 | 
			
		||||
// func CallExprFunction(parentCtx ExprContext, funcName string, params ...any) (v any, err error) {
 | 
			
		||||
// 	ctx := cloneContext(parentCtx)
 | 
			
		||||
// 	ctx.SetParent(parentCtx)
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		if err = checkFunctionCall(ctx, funcName, ¶ms); err == nil {
 | 
			
		||||
			if v, err = ctx.Call(funcName, params); err == nil {
 | 
			
		||||
				exportObjects(parentCtx, ctx)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
// 	if err == nil {
 | 
			
		||||
// 		if err = checkFunctionCall(ctx, funcName, ¶ms); err == nil {
 | 
			
		||||
// 			if v, err = ctx.Call(funcName, params); err == nil {
 | 
			
		||||
// 				exportObjects(parentCtx, ctx)
 | 
			
		||||
// 			}
 | 
			
		||||
// 		}
 | 
			
		||||
// 	}
 | 
			
		||||
// 	return
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ func createFileFunc(ctx ExprContext, name string, args []any) (result any, err e
 | 
			
		||||
			result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errMissingFilePath("createFile")
 | 
			
		||||
		err = errMissingFilePath(name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -80,7 +80,7 @@ func openFileFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
			
		||||
			result = &osReader{fh: fh, reader: bufio.NewReader(fh)}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errMissingFilePath("openFile")
 | 
			
		||||
		err = errMissingFilePath(name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -92,7 +92,7 @@ func appendFileFunc(ctx ExprContext, name string, args []any) (result any, err e
 | 
			
		||||
			result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = errMissingFilePath("appendFile")
 | 
			
		||||
		err = errMissingFilePath(name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -118,13 +118,13 @@ func closeFileFunc(ctx ExprContext, name string, args []any) (result any, err er
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err == nil && (handle == nil || invalidFileHandle != nil) {
 | 
			
		||||
		err = errInvalidFileHandle("closeFileFunc", handle)
 | 
			
		||||
		err = errInvalidFileHandle(name, handle)
 | 
			
		||||
	}
 | 
			
		||||
	result = err == nil
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
			
		||||
func fileWriteTextFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
			
		||||
	var handle osHandle
 | 
			
		||||
	var invalidFileHandle any
 | 
			
		||||
	var ok bool
 | 
			
		||||
@ -142,12 +142,12 @@ func writeFileFunc(ctx ExprContext, name string, args []any) (result any, err er
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil && (handle == nil || invalidFileHandle != nil) {
 | 
			
		||||
		err = errInvalidFileHandle("writeFileFunc", invalidFileHandle)
 | 
			
		||||
		err = errInvalidFileHandle(name, invalidFileHandle)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func readFileFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
			
		||||
func fileReadTextFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
			
		||||
	var handle osHandle
 | 
			
		||||
	var invalidFileHandle any
 | 
			
		||||
	var ok bool
 | 
			
		||||
@ -165,23 +165,50 @@ func readFileFunc(ctx ExprContext, name string, args []any) (result any, err err
 | 
			
		||||
				limit = s[0]
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if v, err = r.reader.ReadString(limit); err == nil {
 | 
			
		||||
				if len(v) > 0 && v[len(v)-1] == limit {
 | 
			
		||||
			v, err = r.reader.ReadString(limit)
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				err = nil
 | 
			
		||||
			}
 | 
			
		||||
			if len(v) > 0 {
 | 
			
		||||
				if v[len(v)-1] == limit {
 | 
			
		||||
					result = v[0 : len(v)-1]
 | 
			
		||||
				} else {
 | 
			
		||||
					result = v
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				err = nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			invalidFileHandle = handle
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil && (handle == nil || invalidFileHandle != nil) {
 | 
			
		||||
		err = errInvalidFileHandle("readFileFunc", invalidFileHandle)
 | 
			
		||||
		err = errInvalidFileHandle(name, invalidFileHandle)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fileReadTextAllFunc(ctx ExprContext, name string, args []any) (result any, err error) {
 | 
			
		||||
	var handle osHandle
 | 
			
		||||
	var invalidFileHandle any
 | 
			
		||||
	var ok bool
 | 
			
		||||
 | 
			
		||||
	result = nil
 | 
			
		||||
	if handle, ok = args[0].(osHandle); !ok || args[0] == nil {
 | 
			
		||||
		invalidFileHandle = args[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if handle != nil {
 | 
			
		||||
		if r, ok := handle.(*osReader); ok {
 | 
			
		||||
			var b []byte
 | 
			
		||||
			b, err = io.ReadAll(r.reader)
 | 
			
		||||
			result = string(b)
 | 
			
		||||
		} else {
 | 
			
		||||
			invalidFileHandle = handle
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil && (handle == nil || invalidFileHandle != nil) {
 | 
			
		||||
		err = errInvalidFileHandle(name, invalidFileHandle)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -190,21 +217,30 @@ func ImportOsFuncs(ctx ExprContext) {
 | 
			
		||||
	ctx.RegisterFunc("fileOpen", NewGolangFunctor(openFileFunc), TypeHandle, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(ParamFilepath),
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileAppend", NewGolangFunctor(appendFileFunc), TypeHandle, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(ParamFilepath),
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileCreate", NewGolangFunctor(createFileFunc), TypeHandle, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(ParamFilepath),
 | 
			
		||||
	})
 | 
			
		||||
	ctx.RegisterFunc("fileWrite", NewGolangFunctor(writeFileFunc), TypeInt, []ExprFuncParam{
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileClose", NewGolangFunctor(closeFileFunc), TypeBoolean, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(TypeHandle),
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileWriteText", NewGolangFunctor(fileWriteTextFunc), TypeInt, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(TypeHandle),
 | 
			
		||||
		NewFuncParamFlagDef(TypeItem, PfDefault|PfRepeat, ""),
 | 
			
		||||
	})
 | 
			
		||||
	ctx.RegisterFunc("fileRead", NewGolangFunctor(readFileFunc), TypeString, []ExprFuncParam{
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileReadText", NewGolangFunctor(fileReadTextFunc), TypeString, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(TypeHandle),
 | 
			
		||||
		NewFuncParamFlagDef("limitCh", PfDefault, "\n"),
 | 
			
		||||
	})
 | 
			
		||||
	ctx.RegisterFunc("fileClose", NewGolangFunctor(closeFileFunc), TypeBoolean, []ExprFuncParam{
 | 
			
		||||
 | 
			
		||||
	ctx.RegisterFunc("fileReadTextAll", NewGolangFunctor(fileReadTextAllFunc), TypeString, []ExprFuncParam{
 | 
			
		||||
		NewFuncParam(TypeHandle),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -41,3 +41,9 @@ func exportObjects(destCtx, sourceCtx ExprContext) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exportObjectsToParent(sourceCtx ExprContext) {
 | 
			
		||||
	if parentCtx := sourceCtx.GetParent(); parentCtx != nil {
 | 
			
		||||
		exportObjects(parentCtx, sourceCtx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ type ExprContext interface {
 | 
			
		||||
	SetParent(ctx ExprContext)
 | 
			
		||||
	GetParent() (ctx ExprContext)
 | 
			
		||||
	GetVar(varName string) (value any, exists bool)
 | 
			
		||||
	GetLast() any
 | 
			
		||||
	SetVar(varName string, value any)
 | 
			
		||||
	UnsafeSetVar(varName string, value any)
 | 
			
		||||
	EnumVars(func(name string) (accept bool)) (varNames []string)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								function.go
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								function.go
									
									
									
									
									
								
							@ -199,3 +199,42 @@ func (info *funcInfo) MaxArgs() int {
 | 
			
		||||
func (info *funcInfo) Functor() Functor {
 | 
			
		||||
	return info.functor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----- Call a function ---
 | 
			
		||||
 | 
			
		||||
func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) {
 | 
			
		||||
	if info, exists, owner := GetFuncInfo(ctx, name); exists {
 | 
			
		||||
		passedCount := len(*varParams)
 | 
			
		||||
		if info.MinArgs() > passedCount {
 | 
			
		||||
			err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
 | 
			
		||||
		}
 | 
			
		||||
		for i, p := range info.Params() {
 | 
			
		||||
			if i >= passedCount {
 | 
			
		||||
				if !p.IsDefault() {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				*varParams = append(*varParams, p.DefaultValue())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
 | 
			
		||||
			err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams))
 | 
			
		||||
		}
 | 
			
		||||
		if err == nil && owner != ctx {
 | 
			
		||||
			ctx.RegisterFuncInfo(info)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = fmt.Errorf("unknown function %s()", name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CallFunction(parentCtx ExprContext, name string, params []any) (result any, err error) {
 | 
			
		||||
	ctx := cloneContext(parentCtx)
 | 
			
		||||
	ctx.SetParent(parentCtx)
 | 
			
		||||
 | 
			
		||||
	if err = checkFunctionCall(ctx, name, ¶ms); err == nil {
 | 
			
		||||
		result, err = ctx.Call(name, params)
 | 
			
		||||
		exportObjectsToParent(ctx)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@ package expr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// -------- function call term
 | 
			
		||||
@ -22,35 +21,7 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// -------- eval func call
 | 
			
		||||
func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) {
 | 
			
		||||
	if info, exists, owner := GetFuncInfo(ctx, name); exists {
 | 
			
		||||
		passedCount := len(*varParams)
 | 
			
		||||
		if info.MinArgs() > passedCount {
 | 
			
		||||
			err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
 | 
			
		||||
		}
 | 
			
		||||
		for i, p := range info.Params() {
 | 
			
		||||
			if i >= passedCount {
 | 
			
		||||
				if !p.IsDefault() {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				*varParams = append(*varParams, p.DefaultValue())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
 | 
			
		||||
			err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams))
 | 
			
		||||
		}
 | 
			
		||||
		if err == nil && owner != ctx {
 | 
			
		||||
			ctx.RegisterFuncInfo(info)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		err = fmt.Errorf("unknown function %s()", name)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
 | 
			
		||||
	ctx := cloneContext(parentCtx)
 | 
			
		||||
	ctx.SetParent(parentCtx)
 | 
			
		||||
func evalFuncCall(ctx ExprContext, self *term) (v any, err error) {
 | 
			
		||||
	name, _ := self.tk.Value.(string)
 | 
			
		||||
	params := make([]any, len(self.children), len(self.children)+5)
 | 
			
		||||
	for i, tree := range self.children {
 | 
			
		||||
@ -62,11 +33,7 @@ func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		if err = checkFunctionCall(ctx, name, ¶ms); err == nil {
 | 
			
		||||
			if v, err = ctx.Call(name, params); err == nil {
 | 
			
		||||
				exportObjects(parentCtx, ctx)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		v, err = CallFunction(ctx, name, params)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -87,13 +87,14 @@ func evalIndex(ctx ExprContext, self *term) (v any, err error) {
 | 
			
		||||
				v = string(unboxedValue[index])
 | 
			
		||||
			}
 | 
			
		||||
		case *DictType:
 | 
			
		||||
			var ok bool
 | 
			
		||||
/* 			var ok bool
 | 
			
		||||
			var indexValue any
 | 
			
		||||
			if indexValue, err = verifyKey(indexTerm, indexList); err == nil {
 | 
			
		||||
				if v, ok = (*unboxedValue)[indexValue]; !ok {
 | 
			
		||||
					err = indexTerm.Errorf("key %v does not belong to the dictionary", rightValue)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			} */
 | 
			
		||||
			v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue)
 | 
			
		||||
		default:
 | 
			
		||||
			err = self.errIncompatibleTypes(leftValue, rightValue)
 | 
			
		||||
		}
 | 
			
		||||
@ -113,6 +114,29 @@ func evalIndex(ctx ExprContext, self *term) (v any, err error) {
 | 
			
		||||
		default:
 | 
			
		||||
			err = self.errIncompatibleTypes(leftValue, rightValue)
 | 
			
		||||
		}
 | 
			
		||||
	} else if IsDict(leftValue) {
 | 
			
		||||
		d := leftValue.(*DictType)
 | 
			
		||||
 | 
			
		||||
		/* 		var ok bool
 | 
			
		||||
		   		var indexValue any
 | 
			
		||||
		   		if indexValue, err = verifyKey(indexTerm, indexList); err == nil {
 | 
			
		||||
		   			if v, ok = (*d)[indexValue]; !ok {
 | 
			
		||||
		   				err = indexTerm.Errorf("key %v does not belong to the dictionary", rightValue)
 | 
			
		||||
		   			}
 | 
			
		||||
		   		}*/
 | 
			
		||||
		v, err = getDictItem(d, indexTerm, indexList, rightValue)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getDictItem(d *DictType, indexTerm *term, indexList *ListType, rightValue any) (v any, err error) {
 | 
			
		||||
	var ok bool
 | 
			
		||||
	var indexValue any
 | 
			
		||||
 | 
			
		||||
	if indexValue, err = verifyKey(indexTerm, indexList); err == nil {
 | 
			
		||||
		if v, ok = (*d)[indexValue]; !ok {
 | 
			
		||||
			err = indexTerm.Errorf("key %v does not belong to the dictionary", rightValue)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ func pluginExists(name string) (exists bool) {
 | 
			
		||||
 | 
			
		||||
func makePluginName(name string) (decorated string) {
 | 
			
		||||
	var template string
 | 
			
		||||
	if execName, err := os.Executable(); err != nil || !strings.HasSuffix(execName, ".debug") {
 | 
			
		||||
	if execName, err := os.Executable(); err != nil || strings.Index(execName, "debug") < 0 {
 | 
			
		||||
		template = "expr-%s-plugin.so"
 | 
			
		||||
	} else {
 | 
			
		||||
		template = "expr-%s-plugin.so.debug"
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ package expr
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"slices"
 | 
			
		||||
//	"strings"
 | 
			
		||||
	// "strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SimpleStore struct {
 | 
			
		||||
@ -50,6 +50,7 @@ func (ctx *SimpleStore) Merge(src ExprContext) {
 | 
			
		||||
		ctx.funcStore[name], _ = src.GetFuncInfo(name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
 | 
			
		||||
	sb.WriteString("vars: {\n")
 | 
			
		||||
@ -165,6 +166,11 @@ func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *SimpleStore) GetLast() (v any) {
 | 
			
		||||
	v = ctx.varStore["last"]
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *SimpleStore) UnsafeSetVar(varName string, value any) {
 | 
			
		||||
	// fmt.Printf("[%p] setVar(%v, %v)\n", ctx, varName, value)
 | 
			
		||||
	ctx.varStore[varName] = value
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,10 @@ func TestFuncOs(t *testing.T) {
 | 
			
		||||
		/*   2 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle)`, true, nil},
 | 
			
		||||
		/*   3 */ {`builtin "os.file"; handle=fileOpen("/etc/hostsX")`, nil, errors.New(`open /etc/hostsX: no such file or directory`)},
 | 
			
		||||
		/*   4 */ {`builtin "os.file"; handle=fileCreate("/tmp/dummy"); fileClose(handle)`, true, nil},
 | 
			
		||||
		/*   5 */ {`builtin "os.file"; handle=fileAppend("/tmp/dummy"); fileWrite(handle, "bye-bye"); fileClose(handle)`, true, nil},
 | 
			
		||||
		/*   6 */ {`builtin "os.file"; handle=fileOpen("/tmp/dummy"); word=fileRead(handle, "-"); fileClose(handle);word`, "bye", nil},
 | 
			
		||||
		/*   7 */ {`builtin "os.file"; word=fileRead(nil, "-")`, nil, errors.New(`readFileFunc(): invalid file handle`)},
 | 
			
		||||
		/*   7 */ {`builtin "os.file"; fileWrite(nil, "bye")`, nil, errors.New(`writeFileFunc(): invalid file handle`)},
 | 
			
		||||
		/*   5 */ {`builtin "os.file"; handle=fileAppend("/tmp/dummy"); fileWriteText(handle, "bye-bye"); fileClose(handle)`, true, nil},
 | 
			
		||||
		/*   6 */ {`builtin "os.file"; handle=fileOpen("/tmp/dummy"); word=fileReadText(handle, "-"); fileClose(handle);word`, "bye", nil},
 | 
			
		||||
		/*   7 */ {`builtin "os.file"; word=fileReadText(nil, "-")`, nil, errors.New(`fileReadText(): invalid file handle`)},
 | 
			
		||||
		/*   7 */ {`builtin "os.file"; fileWriteText(nil, "bye")`, nil, errors.New(`fileWriteText(): invalid file handle`)},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// t.Setenv("EXPR_PATH", ".")
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ func TestDictParser(t *testing.T) {
 | 
			
		||||
		/*  8 */ {`D={"a":1, "b":2}; D["a"]=9; D`, map[any]any{"a": 9, "b": 2}, nil},
 | 
			
		||||
		/*  9 */ {`D={"a":1, "b":2}; D["z"]=9; D`, map[any]any{"z": 9, "a": 1, "b": 2}, 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},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	succeeded := 0
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ func TestExpr(t *testing.T) {
 | 
			
		||||
	inputs := []inputType{
 | 
			
		||||
		/*   1 */ {`0?{}`, nil, 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=fileRead(f); fileClose(f); line`, "uno", nil},
 | 
			
		||||
		/*   3 */ {`builtin "os.file"; f=fileOpen("test-file.txt"); line=fileReadText(f); fileClose(f); line`, "uno", nil},
 | 
			
		||||
		/*   4 */ {`mynot=func(v){int(v)?{true}::{false}}; mynot(0)`, true, nil},
 | 
			
		||||
		/*   5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
 | 
			
		||||
		/*   6 */ {`
 | 
			
		||||
 | 
			
		||||
@ -14,9 +14,9 @@ func TestIteratorParser(t *testing.T) {
 | 
			
		||||
		/*   4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; ()it`, int64(0), nil},
 | 
			
		||||
		/*   5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil},
 | 
			
		||||
		/*   6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
 | 
			
		||||
		/*   7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"int.list"); mul(it)`, int64(12000), nil},
 | 
			
		||||
		/*   8 */ {`include "test-resources/file-reader.expr"; it=$(ds,"int.list"); it++; it.index`, int64(0), nil},
 | 
			
		||||
		/*  10 */ {`include "test-resources/file-reader.expr"; it=$(ds,"int.list"); it.clean`, true, nil},
 | 
			
		||||
		/*   7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},
 | 
			
		||||
		/*   8 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it++; it.index`, int64(0), nil},
 | 
			
		||||
		/*  10 */ {`include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); it.clean`, true, nil},
 | 
			
		||||
		/*  11 */ {`it=$(1,2,3); it++`, int64(1), nil},
 | 
			
		||||
	}
 | 
			
		||||
	// inputs1 := []inputType{
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,22 @@
 | 
			
		||||
builtin ["os.file", "base"];
 | 
			
		||||
 | 
			
		||||
readInt=func(fh){
 | 
			
		||||
	line=fileRead(fh);
 | 
			
		||||
	line=fileReadText(fh);
 | 
			
		||||
	line ? [nil] {nil} :: {int(line)}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ds={
 | 
			
		||||
	"init":func(filename){
 | 
			
		||||
		fh=fileOpen(filename);
 | 
			
		||||
		fh ? [nil] {nil} :: { @current=readInt(fh); @prev=@current };
 | 
			
		||||
		fh ? [nil] {nil} :: { @current=readInt(fh) };
 | 
			
		||||
		fh
 | 
			
		||||
	},
 | 
			
		||||
	"current":func(){
 | 
			
		||||
		prev
 | 
			
		||||
		current
 | 
			
		||||
	},
 | 
			
		||||
	"next":func(fh){
 | 
			
		||||
		current ? 
 | 
			
		||||
			[nil] {current}
 | 
			
		||||
			:: {@prev=current; @current=readInt(fh) but current}
 | 
			
		||||
		@current=readInt(fh);
 | 
			
		||||
		current
 | 
			
		||||
	},
 | 
			
		||||
	"clean":func(fh){
 | 
			
		||||
		fileClose(fh)
 | 
			
		||||
@ -25,9 +24,9 @@ ds={
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//;f=$(ds, "int.list")
 | 
			
		||||
/*
 | 
			
		||||
;f++
 | 
			
		||||
;f++
 | 
			
		||||
;f++
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
//;f++
 | 
			
		||||
//;f++
 | 
			
		||||
//;f++
 | 
			
		||||
//*/
 | 
			
		||||
//;add(f)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user