Operator '@@' (export-all) added. Experimental include() function also added

This commit is contained in:
Celestino Amoroso 2024-04-06 03:06:07 +02:00
parent ce6b88ccdd
commit 7612a59757
10 changed files with 108 additions and 29 deletions

2
ast.go
View File

@ -108,7 +108,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(preset_last_result, result) ctx.SetVar(control_last_result, 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

View File

@ -14,6 +14,15 @@ import (
const ENV_EXPR_PATH = "EXPR_PATH" const ENV_EXPR_PATH = "EXPR_PATH"
func importFunc(ctx exprContext, name string, args []any) (result any, err error) { func importFunc(ctx exprContext, name string, args []any) (result any, err error) {
return importGeneral(ctx, name, args)
}
func includeFunc(ctx exprContext, name string, args []any) (result any, err error) {
enable(ctx, control_export_all)
return importGeneral(ctx, name, args)
}
func importGeneral(ctx exprContext, name string, args []any) (result any, err error) {
var dirList []string var dirList []string
dirList = addEnvImportDirs(dirList) dirList = addEnvImportDirs(dirList)
@ -42,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 := getPresetString(ctx, preset_import_path); exists { if dirSpec, exists := getControlString(ctx, control_import_path); exists {
dirs := strings.Split(dirSpec, ":") dirs := strings.Split(dirSpec, ":")
if dirList == nil { if dirList == nil {
dirList = dirs dirList = dirs
@ -105,7 +114,7 @@ func doImport(ctx exprContext, name string, dirList []string, it Iterator) (resu
scanner := NewScanner(file, DefaultTranslations()) scanner := NewScanner(file, DefaultTranslations())
parser := NewParser(ctx) parser := NewParser(ctx)
if expr, err = parser.parseGeneral(scanner, true, true); err == nil { if expr, err = parser.parseGeneral(scanner, true, true); err == nil {
_, err = expr.Eval(ctx, false) result, err = expr.Eval(ctx, false)
} }
if err != nil { if err != nil {
break break
@ -114,12 +123,17 @@ func doImport(ctx exprContext, name string, dirList []string, it Iterator) (resu
break break
} }
} }
if err != nil && err == io.EOF { if err != nil {
if err == io.EOF {
err = nil err = nil
} else {
result = nil
}
} }
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)
} }

View File

@ -36,15 +36,16 @@ func evalFuncCall(parentCtx exprContext, self *term) (v any, err error) {
} }
if err == nil { if err == nil {
if v, err = ctx.Call(name, params); err == nil { if v, err = ctx.Call(name, params); err == nil {
exportAll := isEnabled(ctx, control_export_all)
// Export variables // Export variables
for _, refName := range ctx.EnumVars(func(name string) bool { return name[0] == '@' }) { for _, refName := range ctx.EnumVars(func(name string) bool { return exportAll || name[0] == '@' }) {
refValue, _ := ctx.GetVar(refName) refValue, _ := ctx.GetVar(refName)
parentCtx.SetVar(refName[1:], refValue) exportVar(parentCtx, refName, refValue)
} }
// Export functions // Export functions
for _, refName := range ctx.EnumFuncs(func(name string) bool { return name[0] == '@' }) { for _, refName := range ctx.EnumFuncs(func(name string) bool { return exportAll || name[0] == '@' }) {
if info := ctx.GetFuncInfo(refName); info != nil { if info := ctx.GetFuncInfo(refName); info != nil {
parentCtx.RegisterFunc(refName[1:], info.Functor(), info.MinArgs(), info.MaxArgs()) exportFunc(parentCtx, refName, info)
} }
} }
} }
@ -52,6 +53,20 @@ func evalFuncCall(parentCtx exprContext, self *term) (v any, err error) {
return return
} }
func exportVar(ctx exprContext, name string, value any) {
if name[0] == '@' {
name = name[1:]
}
ctx.SetVar(name, value)
}
func exportFunc(ctx exprContext, name string, info exprFunc) {
if name[0] == '@' {
name = name[1:]
}
ctx.RegisterFunc(name, info.Functor(), info.MinArgs(), info.MaxArgs())
}
// -------- function definition term // -------- function definition term
func newFuncDefTerm(tk *Token, args []*term) *term { func newFuncDefTerm(tk *Token, args []*term) *term {
return &term{ return &term{

View File

@ -50,7 +50,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, preset_bool_shortcut) { if isEnabled(ctx, control_bool_shortcut) {
v, err = evalAndWithShortcut(ctx, self) v, err = evalAndWithShortcut(ctx, self)
} else { } else {
v, err = evalAndWithoutShortcut(ctx, self) v, err = evalAndWithoutShortcut(ctx, self)
@ -119,7 +119,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, preset_bool_shortcut) { if isEnabled(ctx, control_bool_shortcut) {
v, err = evalOrWithShortcut(ctx, self) v, err = evalOrWithShortcut(ctx, self)
} else { } else {
v, err = evalOrWithoutShortcut(ctx, self) v, err = evalOrWithoutShortcut(ctx, self)

29
operator-ctrl.go Normal file
View File

@ -0,0 +1,29 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// operator-ctrl.go
package expr
//-------- export all term
func newExportAllTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
class: classOperator,
kind: kindUnknown,
children: nil,
position: posLeaf,
priority: priValue,
evalFunc: evalExportAll,
}
}
func evalExportAll(ctx exprContext, self *term) (v any, err error) {
enable(ctx, control_export_all)
return
}
// init
func init() {
registerTermConstructor(SymDoubleAt, newExportAllTerm)
}

View File

@ -144,23 +144,18 @@ 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}, /* 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}, /* 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}, /* 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},
} }
check_env_expr_path := 113 check_env_expr_path := 113
succeeded := 0 succeeded := 0
failed := 0 failed := 0
// inputs1 := []inputType{ inputs1 := []inputType{
// {`f=func(@y){g=func(){@x=5}; g(); @z=x}; f(2)`, int64(5), nil}, {`import("./test-funcs.expr"); six()`, int64(6), nil},
// {`f=func(@y){@y=@y+1}; f(2); y`, int64(3), nil}, }
// {`import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
// {`add(1,2,3)`, int64(6), nil},
// {`a=5; a`, int64(5), nil},
// {`a=5; b=2; add(a, b*3)`, int64(11), nil},
// {`"a" < "b" AND ~ 2 == 1`, true, nil},
// }
for i, input := range inputs { for i, input := range inputs1 {
var expr *ast var expr *ast
var gotResult any var gotResult any
var gotErr error var gotErr error
@ -206,7 +201,7 @@ func TestParser(t *testing.T) {
t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed)) t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed))
} }
func TestListParser(t *testing.T) { func NoTestListParser(t *testing.T) {
type inputType struct { type inputType struct {
source string source string
wantResult any wantResult any

17
sample-export-all.expr Normal file
View File

@ -0,0 +1,17 @@
/*
sample-export-all.expr: example source file
*/
@@; // Enable export all mode
// double(x): returns 2*x
double=func(x){2*x};
// Define variable 'a' wth value 5
a=5;
// two(): returns 2
two=func() {2};
// six(): returns 6
six=func() {6};

View File

@ -199,6 +199,8 @@ func (self *scanner) fetchNextToken() (tk *Token) {
} else { } else {
tk = self.makeErrorToken(fmt.Errorf("invalid variable reference %q", tk.source)) tk = self.makeErrorToken(fmt.Errorf("invalid variable reference %q", tk.source))
} }
} else if next == '@' {
tk = self.moveOn(SymDoubleAt, ch, next)
} else { } else {
tk = self.makeToken(SymAt, ch) tk = self.makeToken(SymAt, ch)
} }

View File

@ -55,8 +55,9 @@ const (
SymOpenBrace // 44: '{' SymOpenBrace // 44: '{'
SymClosedBrace // 45: '}' SymClosedBrace // 45: '}'
SymTilde // 46: '~' SymTilde // 46: '~'
SymDoubleQuestion SymDoubleQuestion // 47: '??'
SymQuestionEqual SymQuestionEqual // 48: '?='
SymDoubleAt // 49: '@@'
SymChangeSign SymChangeSign
SymUnchangeSign SymUnchangeSign
SymIdentifier SymIdentifier
@ -64,9 +65,6 @@ const (
SymInteger SymInteger
SymFloat SymFloat
SymString SymString
SymKwAnd
SymKwNot
SymKwOr
SymOr SymOr
SymAnd SymAnd
SymNot SymNot
@ -74,12 +72,18 @@ const (
SymFuncCall SymFuncCall
SymFuncDef SymFuncDef
SymList SymList
SymKwBut
SymKwFunc
SymExpression SymExpression
// SymOpenComment // 0: '/*' // SymOpenComment // 0: '/*'
// SymClosedComment // 0: '*/' // SymClosedComment // 0: '*/'
// SymOneLineComment // 0: '//' // SymOneLineComment // 0: '//'
keywordBase
)
const (
SymKwAnd = keywordBase + iota
SymKwNot
SymKwOr
SymKwBut
SymKwFunc
) )
var keywords map[string]Symbol var keywords map[string]Symbol

View File

@ -10,3 +10,6 @@
// two(): returns 2 // two(): returns 2
@two=func() {2}; @two=func() {2};
// six(): returns 6
six=func() {6};