Compare commits
11 Commits
95605232ab
...
b9ea96f649
Author | SHA1 | Date | |
---|---|---|---|
b9ea96f649 | |||
838ab9fd7e | |||
ad6b4b872f | |||
c75e6485e0 | |||
7b80f7f03b | |||
7f9fd570b2 | |||
b17d2250a4 | |||
dda10749d0 | |||
07ca84170e | |||
55e136e9bc | |||
e493c40c7b |
3
ast.go
3
ast.go
@ -12,6 +12,7 @@ import (
|
|||||||
type Expr interface {
|
type Expr interface {
|
||||||
Eval(ctx ExprContext) (result any, err error)
|
Eval(ctx ExprContext) (result any, err error)
|
||||||
eval(ctx ExprContext, preset bool) (result any, err error)
|
eval(ctx ExprContext, preset bool) (result any, err error)
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------- ast
|
//-------- ast
|
||||||
@ -118,7 +119,7 @@ func (self *ast) eval(ctx ExprContext, preset bool) (result any, err error) {
|
|||||||
if self.forest != nil {
|
if self.forest != nil {
|
||||||
for _, root := range self.forest {
|
for _, root := range self.forest {
|
||||||
if result, err = root.compute(ctx); err == nil {
|
if result, err = root.compute(ctx); err == nil {
|
||||||
ctx.setVar(control_last_result, result)
|
ctx.setVar(ControlLastResult, result)
|
||||||
} else {
|
} else {
|
||||||
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
|
//err = fmt.Errorf("error in expression nr %d: %v", i+1, err)
|
||||||
break
|
break
|
||||||
|
18
control.go
18
control.go
@ -5,9 +5,9 @@ import "strings"
|
|||||||
|
|
||||||
// Preset control variables
|
// Preset control variables
|
||||||
const (
|
const (
|
||||||
control_last_result = "_last"
|
ControlLastResult = "last"
|
||||||
control_bool_shortcut = "_bool_shortcut"
|
ControlBoolShortcut = "_bool_shortcut"
|
||||||
control_import_path = "_import_path"
|
ControlImportPath = "_import_path"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Other control variables
|
// Other control variables
|
||||||
@ -21,23 +21,23 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initDefaultVars(ctx ExprContext) {
|
func initDefaultVars(ctx ExprContext) {
|
||||||
ctx.setVar(control_bool_shortcut, true)
|
ctx.SetVar(ControlBoolShortcut, true)
|
||||||
ctx.setVar(control_import_path, init_import_path)
|
ctx.SetVar(ControlImportPath, init_import_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func enable(ctx ExprContext, name string) {
|
func enable(ctx ExprContext, name string) {
|
||||||
if strings.HasPrefix(name, "_") {
|
if strings.HasPrefix(name, "_") {
|
||||||
ctx.setVar(name, true)
|
ctx.SetVar(name, true)
|
||||||
} else {
|
} else {
|
||||||
ctx.setVar("_"+name, true)
|
ctx.SetVar("_"+name, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func disable(ctx ExprContext, name string) {
|
func disable(ctx ExprContext, name string) {
|
||||||
if strings.HasPrefix(name, "_") {
|
if strings.HasPrefix(name, "_") {
|
||||||
ctx.setVar(name, false)
|
ctx.SetVar(name, false)
|
||||||
} else {
|
} else {
|
||||||
ctx.setVar("_"+name, false)
|
ctx.SetVar("_"+name, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func addEnvImportDirs(dirList []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addPresetImportDirs(ctx ExprContext, dirList []string) []string {
|
func addPresetImportDirs(ctx ExprContext, dirList []string) []string {
|
||||||
if dirSpec, exists := getControlString(ctx, control_import_path); exists {
|
if dirSpec, exists := getControlString(ctx, ControlImportPath); exists {
|
||||||
dirs := strings.Split(dirSpec, ":")
|
dirs := strings.Split(dirSpec, ":")
|
||||||
if dirList == nil {
|
if dirList == nil {
|
||||||
dirList = dirs
|
dirList = dirs
|
||||||
@ -133,7 +133,7 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func importImportFunc(ctx ExprContext) {
|
func ImportImportFunc(ctx ExprContext) {
|
||||||
ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
||||||
ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1)
|
ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ func mulFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func importMathFuncs(ctx ExprContext) {
|
func ImportMathFuncs(ctx ExprContext) {
|
||||||
ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1)
|
ctx.RegisterFunc("add", &simpleFunctor{f: addFunc}, 0, -1)
|
||||||
ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1)
|
ctx.RegisterFunc("mul", &simpleFunctor{f: mulFunc}, 0, -1)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,6 @@ func TestEvalStringA(t *testing.T) {
|
|||||||
t.Errorf("Source %q got %v, want %v", source, gotResult, wantResult)
|
t.Errorf("Source %q got %v, want %v", source, gotResult, wantResult)
|
||||||
t.Errorf("Error: %v", gotErr)
|
t.Errorf("Error: %v", gotErr)
|
||||||
}
|
}
|
||||||
fmt.Println("Hello World!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEvalString(t *testing.T) {
|
func TestEvalString(t *testing.T) {
|
||||||
@ -76,5 +75,4 @@ func TestEvalString(t *testing.T) {
|
|||||||
t.Errorf("Source %q got %v, want %v", source, gotResult, wantResult)
|
t.Errorf("Source %q got %v, want %v", source, gotResult, wantResult)
|
||||||
t.Errorf("Error: %v", gotErr)
|
t.Errorf("Error: %v", gotErr)
|
||||||
}
|
}
|
||||||
fmt.Println("Hello World!")
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
// operand-selector-case.go
|
// operand-selector-case.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// -------- selector case term
|
// -------- selector case term
|
||||||
|
|
||||||
@ -13,6 +16,18 @@ type selectorCase struct {
|
|||||||
caseExpr Expr
|
caseExpr Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sc *selectorCase) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
if sc.filterList != nil {
|
||||||
|
sc.filterList.toString(&sb)
|
||||||
|
sb.WriteByte(' ')
|
||||||
|
}
|
||||||
|
sb.WriteByte('{')
|
||||||
|
sb.WriteString(sc.caseExpr.String())
|
||||||
|
sb.WriteByte('}')
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term {
|
func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term {
|
||||||
tk := NewValueToken(row, col, SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
tk := NewValueToken(row, col, SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
||||||
return &term{
|
return &term{
|
||||||
|
@ -48,7 +48,7 @@ func newAndTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func evalAnd(ctx ExprContext, self *term) (v any, err error) {
|
func evalAnd(ctx ExprContext, self *term) (v any, err error) {
|
||||||
if isEnabled(ctx, control_bool_shortcut) {
|
if isEnabled(ctx, ControlBoolShortcut) {
|
||||||
v, err = evalAndWithShortcut(ctx, self)
|
v, err = evalAndWithShortcut(ctx, self)
|
||||||
} else {
|
} else {
|
||||||
v, err = evalAndWithoutShortcut(ctx, self)
|
v, err = evalAndWithoutShortcut(ctx, self)
|
||||||
@ -117,7 +117,7 @@ func newOrTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func evalOr(ctx ExprContext, self *term) (v any, err error) {
|
func evalOr(ctx ExprContext, self *term) (v any, err error) {
|
||||||
if isEnabled(ctx, control_bool_shortcut) {
|
if isEnabled(ctx, ControlBoolShortcut) {
|
||||||
v, err = evalOrWithShortcut(ctx, self)
|
v, err = evalOrWithShortcut(ctx, self)
|
||||||
} else {
|
} else {
|
||||||
v, err = evalOrWithoutShortcut(ctx, self)
|
v, err = evalOrWithoutShortcut(ctx, self)
|
||||||
|
@ -268,7 +268,7 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
|
|||||||
currentTerm, err = tree.addToken2(tk)
|
currentTerm, err = tree.addToken2(tk)
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentTerm != nil && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
|
if currentTerm != nil && currentTerm.tk.Sym != SymSelector && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
|
||||||
selectorTerm = nil
|
selectorTerm = nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -173,8 +173,8 @@ func TestParser(t *testing.T) {
|
|||||||
ctx := NewSimpleFuncStore()
|
ctx := NewSimpleFuncStore()
|
||||||
ctx.SetVar("var1", int64(123))
|
ctx.SetVar("var1", int64(123))
|
||||||
ctx.SetVar("var2", "abc")
|
ctx.SetVar("var2", "abc")
|
||||||
importMathFuncs(ctx)
|
ImportMathFuncs(ctx)
|
||||||
importImportFunc(ctx)
|
ImportImportFunc(ctx)
|
||||||
parser := NewParser(ctx)
|
parser := NewParser(ctx)
|
||||||
|
|
||||||
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
||||||
@ -204,7 +204,7 @@ func TestParser(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
failed++
|
failed++
|
||||||
if i+1 == check_env_expr_path {
|
if i+1 == check_env_expr_path {
|
||||||
t.Logf(`NOTICE: Test nr %d requires EXPR_PATH environment variable with value "."`, check_env_expr_path)
|
t.Logf(`NOTICE: Test nr %d requires EXPR_PATH="."`, check_env_expr_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ func TestListParser(t *testing.T) {
|
|||||||
ctx := NewSimpleFuncStore()
|
ctx := NewSimpleFuncStore()
|
||||||
ctx.SetVar("var1", int64(123))
|
ctx.SetVar("var1", int64(123))
|
||||||
ctx.SetVar("var2", "abc")
|
ctx.SetVar("var2", "abc")
|
||||||
importMathFuncs(ctx)
|
ImportMathFuncs(ctx)
|
||||||
parser := NewParser(ctx)
|
parser := NewParser(ctx)
|
||||||
|
|
||||||
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
logTest(t, i+1, input.source, input.wantResult, input.wantErr)
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +15,7 @@ func TestString(t *testing.T) {
|
|||||||
|
|
||||||
tree := NewAst()
|
tree := NewAst()
|
||||||
if gotErr := tree.addTokens(tk1, tk2, tk3); gotErr == nil {
|
if gotErr := tree.addTokens(tk1, tk2, tk3); gotErr == nil {
|
||||||
fmt.Println("Tree:", tree)
|
t.Log("Tree:", tree)
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
||||||
}
|
}
|
||||||
@ -27,7 +26,7 @@ func TestGetRoom(t *testing.T) {
|
|||||||
|
|
||||||
tree := NewAst()
|
tree := NewAst()
|
||||||
if gotErr := tree.addTokens(tk1); gotErr == nil {
|
if gotErr := tree.addTokens(tk1); gotErr == nil {
|
||||||
fmt.Println("Tree-root room:", tree.root.getRoom())
|
t.Log("Tree-root room:", tree.root.getRoom())
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
||||||
}
|
}
|
||||||
@ -37,7 +36,7 @@ func TestGetChildrenCount(t *testing.T) {
|
|||||||
|
|
||||||
tree := NewAst()
|
tree := NewAst()
|
||||||
if gotErr := tree.addTokens(tk1); gotErr == nil {
|
if gotErr := tree.addTokens(tk1); gotErr == nil {
|
||||||
fmt.Println("Tree-root children count:", tree.root.getChildrenCount())
|
t.Log("Tree-root children count:", tree.root.getChildrenCount())
|
||||||
} else {
|
} else {
|
||||||
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
t.Errorf("err: got <%v>, want <nil>", gotErr)
|
||||||
}
|
}
|
||||||
|
6
token.go
6
token.go
@ -27,7 +27,11 @@ func (tk *Token) DevString() string {
|
|||||||
|
|
||||||
func (tk *Token) String() string {
|
func (tk *Token) String() string {
|
||||||
if tk.Value != nil {
|
if tk.Value != nil {
|
||||||
return fmt.Sprintf("%#v", tk.Value)
|
if s, ok := tk.Value.(string); ok {
|
||||||
|
return fmt.Sprintf("%q", s)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%v", tk.Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s", tk.source)
|
return fmt.Sprintf("%s", tk.source)
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,34 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDevString(t *testing.T) {
|
func TestDevString(t *testing.T) {
|
||||||
tk1 := NewValueToken(0, 0, SymInteger, "100", 100)
|
type inputType struct {
|
||||||
tk2 := NewToken(0, 0, SymPlus, "+")
|
source string
|
||||||
|
sym Symbol
|
||||||
|
value any
|
||||||
|
wantResult string
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Token '100':", tk1.DevString())
|
inputs := []inputType{
|
||||||
fmt.Println("Token '+':", tk2.DevString())
|
/* 1 */ {"100", SymInteger, 100, `[55]"100"{100}`},
|
||||||
|
/* 2 */ {"+", SymPlus, nil, `[6]"+"{}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, input := range inputs {
|
||||||
|
var tk *Token
|
||||||
|
if input.value == nil {
|
||||||
|
tk = NewToken(0, 0, input.sym, input.source)
|
||||||
|
} else {
|
||||||
|
tk = NewValueToken(0, 0, input.sym, input.source, input.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Test nr %2d: %q --> %q", i+1, input.source, input.wantResult)
|
||||||
|
|
||||||
|
if s := tk.DevString(); s != input.wantResult {
|
||||||
|
t.Errorf("wrong token from symbol '+': expected %q, got %q", input.wantResult, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user