Compare commits
	
		
			11 Commits
		
	
	
		
			62e16219f7
			...
			723976b37e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 723976b37e | |||
| 361b84f31f | |||
| 70892aa980 | |||
| 10eec286fa | |||
| 894b1884eb | |||
| d2bab5fd9e | |||
| f94f369547 | |||
| 107ec4958f | |||
| a22047e84e | |||
| 80b7d5b988 | |||
| 2ab896bbac | 
							
								
								
									
										41
									
								
								context-helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								context-helpers.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | // Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | 
 | ||||||
|  | // context-helpers.go
 | ||||||
|  | package expr | ||||||
|  | 
 | ||||||
|  | func cloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) { | ||||||
|  | 	if sourceCtx != nil { | ||||||
|  | 		clonedCtx = sourceCtx.Clone() | ||||||
|  | 	} | ||||||
|  | 	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()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func exportObjects(destCtx, sourceCtx ExprContext) { | ||||||
|  | 	exportAll := isEnabled(sourceCtx, control_export_all) | ||||||
|  | 	// Export variables
 | ||||||
|  | 	for _, refName := range sourceCtx.EnumVars(func(name string) bool { return exportAll || name[0] == '@' }) { | ||||||
|  | 		refValue, _ := sourceCtx.GetVar(refName) | ||||||
|  | 		exportVar(destCtx, refName, refValue) | ||||||
|  | 	} | ||||||
|  | 	// Export functions
 | ||||||
|  | 	for _, refName := range sourceCtx.EnumFuncs(func(name string) bool { return exportAll || name[0] == '@' }) { | ||||||
|  | 		if info, _ := sourceCtx.GetFuncInfo(refName); info != nil { | ||||||
|  | 			exportFunc(destCtx, refName, info) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								data-cursor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								data-cursor.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | // Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | 
 | ||||||
|  | // data-cursors.go
 | ||||||
|  | package expr | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	initName    = "init" | ||||||
|  | 	nextName    = "next" | ||||||
|  | 	currentName = "current" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type dataCursor struct { | ||||||
|  | 	ds          map[any]*term | ||||||
|  | 	ctx         ExprContext | ||||||
|  | 	index       int | ||||||
|  | 	resource    any | ||||||
|  | 	nextFunc    Functor | ||||||
|  | 	currentFunc Functor | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newDataCursor(ctx ExprContext) (dc *dataCursor) { | ||||||
|  | 	dc = &dataCursor{ | ||||||
|  | 		index: -1, | ||||||
|  | 		ctx:   ctx.Clone(), | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dc *dataCursor) String() string { | ||||||
|  | 	return "$(...)" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
 | ||||||
|  | 	ctx := cloneContext(dc.ctx) | ||||||
|  | 	if item, err = dc.currentFunc.Invoke(ctx, currentName, []any{}); err == nil && item == nil { | ||||||
|  | 		err = io.EOF | ||||||
|  | 	} | ||||||
|  | 	exportObjects(dc.ctx, ctx) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item
 | ||||||
|  | 	ctx := cloneContext(dc.ctx) | ||||||
|  | 	if item, err = dc.nextFunc.Invoke(ctx, nextName, []any{}); err == nil { | ||||||
|  | 		if item == nil { | ||||||
|  | 			err = io.EOF | ||||||
|  | 		} else { | ||||||
|  | 			dc.index++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	exportObjects(dc.ctx, ctx) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (dc *dataCursor) Index() int { | ||||||
|  | 	return dc.index | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								expr_test.go
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								expr_test.go
									
									
									
									
									
								
							| @ -27,11 +27,22 @@ func TestExpr(t *testing.T) { | |||||||
| 	succeeded := 0 | 	succeeded := 0 | ||||||
| 	failed := 0 | 	failed := 0 | ||||||
| 
 | 
 | ||||||
| 	// inputs1 := []inputType{
 | 	inputs1 := []inputType{ | ||||||
| 	// 	/*   1 */ {`0?{}`, nil, nil},
 | 		/*   1 */ {` | ||||||
| 	// }
 | 		ds={ | ||||||
|  | 			"init":func(end){@end=end; @current=0 but true}, | ||||||
|  | 			"current":func(){current}, | ||||||
|  | 			"next":func(){ | ||||||
|  | 				((next=current+1) <= end) ? [true] {@current=next but current} :: {nil} | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 		it=$(ds,3); | ||||||
|  | 		it++; | ||||||
|  | 		it++ | ||||||
|  | `, int64(1), nil}, | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	for i, input := range inputs { | 	for i, input := range inputs1 { | ||||||
| 		var expr Expr | 		var expr Expr | ||||||
| 		var gotResult any | 		var gotResult any | ||||||
| 		var gotErr error | 		var gotErr error | ||||||
|  | |||||||
| @ -5,10 +5,6 @@ | |||||||
| package expr | package expr | ||||||
| 
 | 
 | ||||||
| // -------- dict term
 | // -------- dict term
 | ||||||
| // func newDictTermA(args ...*term) *term {
 |  | ||||||
| // 	return newDictTerm(args)
 |  | ||||||
| // }
 |  | ||||||
| 
 |  | ||||||
| func newDictTerm(args map[any]*term) *term { | func newDictTerm(args map[any]*term) *term { | ||||||
| 	return &term{ | 	return &term{ | ||||||
| 		tk:       *NewValueToken(0, 0, SymDict, "{}", args), | 		tk:       *NewValueToken(0, 0, SymDict, "{}", args), | ||||||
|  | |||||||
| @ -27,8 +27,3 @@ func evalExpr(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // init
 |  | ||||||
| // func init() {
 |  | ||||||
| // 	registerTermConstructor(SymExpression, newExprTerm)
 |  | ||||||
| // }
 |  | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ func newFuncCallTerm(tk *Token, args []*term) *term { | |||||||
| 
 | 
 | ||||||
| // -------- eval func call
 | // -------- eval func call
 | ||||||
| func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) { | func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) { | ||||||
| 	ctx := parentCtx.Clone() | 	ctx := cloneContext(parentCtx) | ||||||
| 	name, _ := self.tk.Value.(string) | 	name, _ := self.tk.Value.(string) | ||||||
| 	params := make([]any, len(self.children)) | 	params := make([]any, len(self.children)) | ||||||
| 	for i, tree := range self.children { | 	for i, tree := range self.children { | ||||||
| @ -34,37 +34,12 @@ 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) | 			exportObjects(parentCtx, ctx) | ||||||
| 			// Export variables
 |  | ||||||
| 			for _, refName := range ctx.EnumVars(func(name string) bool { return exportAll || name[0] == '@' }) { |  | ||||||
| 				refValue, _ := ctx.GetVar(refName) |  | ||||||
| 				exportVar(parentCtx, refName, refValue) |  | ||||||
| 			} |  | ||||||
| 			// Export functions
 |  | ||||||
| 			for _, refName := range ctx.EnumFuncs(func(name string) bool { return exportAll || name[0] == '@' }) { |  | ||||||
| 				if info, _ := ctx.GetFuncInfo(refName); info != nil { |  | ||||||
| 					exportFunc(parentCtx, refName, info) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	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{ | ||||||
| @ -107,12 +82,6 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 		paramList := make([]string, 0, len(self.children)) | 		paramList := make([]string, 0, len(self.children)) | ||||||
| 		for _, param := range self.children { | 		for _, param := range self.children { | ||||||
| 			paramList = append(paramList, param.source()) | 			paramList = append(paramList, param.source()) | ||||||
| 			// if paramName, ok := param.value().(string); ok {
 |  | ||||||
| 			// 	paramList = append(paramList, paramName)
 |  | ||||||
| 			// } else {
 |  | ||||||
| 			// 	err = fmt.Errorf("invalid function definition: formal param nr %d must be an identifier", i+1)
 |  | ||||||
| 			// 	break
 |  | ||||||
| 			// }
 |  | ||||||
| 		} | 		} | ||||||
| 		v = &funcDefFunctor{ | 		v = &funcDefFunctor{ | ||||||
| 			params: paramList, | 			params: paramList, | ||||||
|  | |||||||
| @ -6,58 +6,10 @@ package expr | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // -------- iterator term
 | // -------- iterator term
 | ||||||
| 
 | 
 | ||||||
| const ( |  | ||||||
| 	initName    = "init" |  | ||||||
| 	nextName    = "next" |  | ||||||
| 	currentName = "current" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type dataCursor struct { |  | ||||||
| 	ds          map[any]*term |  | ||||||
| 	ctx         ExprContext |  | ||||||
| 	index       int |  | ||||||
| 	resource    any |  | ||||||
| 	nextFunc    Functor |  | ||||||
| 	currentFunc Functor |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (dc *dataCursor) String() string { |  | ||||||
| 	var s string |  | ||||||
| 	if item, err := dc.Current(); err == nil { |  | ||||||
| 		s = fmt.Sprintf("%v", item) |  | ||||||
| 	} else { |  | ||||||
| 		s = "(nil)" |  | ||||||
| 	} |  | ||||||
| 	return s |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at the last item
 |  | ||||||
| 	if item, err = dc.currentFunc.Invoke(dc.ctx, currentName, []any{}); err == nil && item == nil { |  | ||||||
| 		err = io.EOF |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (dc *dataCursor) Next() (item any, err error) { // must return io.EOF after the last item
 |  | ||||||
| 	if item, err = dc.nextFunc.Invoke(dc.ctx, nextName, []any{}); err == nil { |  | ||||||
| 		if item == nil { |  | ||||||
| 			err = io.EOF |  | ||||||
| 		} else { |  | ||||||
| 			dc.index++ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (dc *dataCursor) Index() int { |  | ||||||
| 	return dc.index |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func newIteratorTerm(tk *Token, dsTerm *term, args []*term) *term { | func newIteratorTerm(tk *Token, dsTerm *term, args []*term) *term { | ||||||
| 	tk.Sym = SymIterator | 	tk.Sym = SymIterator | ||||||
| 
 | 
 | ||||||
| @ -125,10 +77,7 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dc := &dataCursor{ | 	dc := newDataCursor(ctx) | ||||||
| 		index: -1, |  | ||||||
| 		ctx:   ctx.Clone(), |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if initFunc, exists := ds[initName]; exists && initFunc != nil { | 	if initFunc, exists := ds[initName]; exists && initFunc != nil { | ||||||
| 		var args []any | 		var args []any | ||||||
| @ -139,9 +88,12 @@ func evalIterator(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 		} else { | 		} else { | ||||||
| 			args = []any{} | 			args = []any{} | ||||||
| 		} | 		} | ||||||
| 		if dc.resource, err = initFunc.Invoke(dc.ctx, initName, args); err != nil { | 
 | ||||||
|  | 		initCtx := dc.ctx.Clone() | ||||||
|  | 		if dc.resource, err = initFunc.Invoke(initCtx, initName, args); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  | 		exportObjects(dc.ctx, initCtx) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dc.nextFunc, _ = ds[nextName] | 	dc.nextFunc, _ = ds[nextName] | ||||||
|  | |||||||
							
								
								
									
										49
									
								
								operator-context.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								operator-context.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | // Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | 
 | ||||||
|  | // operator-context-value.go
 | ||||||
|  | package expr | ||||||
|  | 
 | ||||||
|  | //-------- context term
 | ||||||
|  | 
 | ||||||
|  | func newContextTerm(tk *Token) (inst *term) { | ||||||
|  | 	return &term{ | ||||||
|  | 		tk:       *tk, | ||||||
|  | 		children: make([]*term, 0, 1), | ||||||
|  | 		position: posPrefix, | ||||||
|  | 		priority: priPrePost, | ||||||
|  | 		evalFunc: evalContextValue, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func evalContextValue(ctx ExprContext, self *term) (v any, err error) { | ||||||
|  | 	var childValue any | ||||||
|  | 
 | ||||||
|  | 	var sourceCtx ExprContext | ||||||
|  | 	if len(self.children) == 0 { | ||||||
|  | 		sourceCtx = ctx | ||||||
|  | 	} else if childValue, err = self.evalPrefix(ctx); err == nil { | ||||||
|  | 		if dc, ok := childValue.(*dataCursor); ok { | ||||||
|  | 			sourceCtx = dc.ctx | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if sourceCtx != nil { | ||||||
|  | 		keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' }) | ||||||
|  | 		d := make(map[string]any) | ||||||
|  | 		for _, key := range keys { | ||||||
|  | 			d[key], _ = sourceCtx.GetVar(key) | ||||||
|  | 		} | ||||||
|  | 		v = d | ||||||
|  | 	} else { | ||||||
|  | 		err = self.errIncompatibleType(childValue) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // init
 | ||||||
|  | func init() { | ||||||
|  | 	registerTermConstructor(SymDoubleDollar, newContextTerm) | ||||||
|  | } | ||||||
| @ -29,9 +29,8 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 	} else if isString(rightValue) { | 	} else if isString(rightValue) { | ||||||
| 		s, _ := rightValue.(string) | 		s, _ := rightValue.(string) | ||||||
| 		v = len(s) | 		v = len(s) | ||||||
| 		// } else {
 | 	} else if it, ok := rightValue.(Iterator); ok { | ||||||
| 		// 	v = 1
 | 		v = it.Index() | ||||||
| 		// }
 |  | ||||||
| 	} else { | 	} else { | ||||||
| 		err = self.errIncompatibleType(rightValue) | 		err = self.errIncompatibleType(rightValue) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -4,65 +4,7 @@ | |||||||
| // operator-selector.go
 | // operator-selector.go
 | ||||||
| package expr | package expr | ||||||
| 
 | 
 | ||||||
| // //-------- export all term
 | //-------- selector term
 | ||||||
| 
 |  | ||||||
| // func newSelectorTerm(tk *Token) (inst *term) {
 |  | ||||||
| // 	return &term{
 |  | ||||||
| // 		tk:       *tk,
 |  | ||||||
| // 		children: make([]*term, 0, 3),
 |  | ||||||
| // 		position: posMultifix,
 |  | ||||||
| // 		priority: priSelector,
 |  | ||||||
| // 		evalFunc: evalSelector,
 |  | ||||||
| // 	}
 |  | ||||||
| // }
 |  | ||||||
| 
 |  | ||||||
| // func isSelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (selectedValue any, err error) {
 |  | ||||||
| // 	caseData, _ := caseSel.(*selectorCase)
 |  | ||||||
| // 	if caseData.filterList == nil {
 |  | ||||||
| // 		selectedValue, err = caseData.caseExpr.eval(ctx, false)
 |  | ||||||
| // 	} else {
 |  | ||||||
| // 		filterList := caseData.filterList.children
 |  | ||||||
| // 		if len(filterList) == 0 && exprValue == int64(caseIndex) {
 |  | ||||||
| // 			selectedValue, err = caseData.caseExpr.eval(ctx, false)
 |  | ||||||
| // 		} else {
 |  | ||||||
| // 			var caseValue any
 |  | ||||||
| // 			for _, caseTerm := range filterList {
 |  | ||||||
| // 				if caseValue, err = caseTerm.compute(ctx); err != nil || caseValue == exprValue {
 |  | ||||||
| // 					selectedValue, err = caseData.caseExpr.eval(ctx, false)
 |  | ||||||
| // 					break
 |  | ||||||
| // 				}
 |  | ||||||
| // 			}
 |  | ||||||
| // 		}
 |  | ||||||
| // 	}
 |  | ||||||
| // 	return
 |  | ||||||
| // }
 |  | ||||||
| 
 |  | ||||||
| // func evalSelector(ctx ExprContext, self *term) (v any, err error) {
 |  | ||||||
| // 	var exprValue any
 |  | ||||||
| // 	// var caseList []*term
 |  | ||||||
| 
 |  | ||||||
| // 	if err = self.checkOperands(); err != nil {
 |  | ||||||
| // 		return
 |  | ||||||
| // 	}
 |  | ||||||
| // 	exprTerm := self.children[0]
 |  | ||||||
| // 	if exprValue, err = exprTerm.compute(ctx); err != nil {
 |  | ||||||
| // 		return
 |  | ||||||
| // 	}
 |  | ||||||
| 
 |  | ||||||
| // 	caseList := self.children[1:]
 |  | ||||||
| // 	for i, caseTerm := range caseList {
 |  | ||||||
| // 		caseSel := caseTerm.value()
 |  | ||||||
| // 		if v, err = isSelectorCase(ctx, exprValue, caseSel, i); err != nil || v != nil {
 |  | ||||||
| // 			break
 |  | ||||||
| // 		}
 |  | ||||||
| // 	}
 |  | ||||||
| // 	if err == nil && v == nil {
 |  | ||||||
| // 		err = exprTerm.tk.Errorf("no case catches the value (%v) of the selection expression", exprValue)
 |  | ||||||
| // 	}
 |  | ||||||
| // 	return
 |  | ||||||
| // }
 |  | ||||||
| 
 |  | ||||||
| //-------- export all term
 |  | ||||||
| 
 | 
 | ||||||
| func newSelectorTerm(tk *Token) (inst *term) { | func newSelectorTerm(tk *Token) (inst *term) { | ||||||
| 	return &term{ | 	return &term{ | ||||||
| @ -74,7 +16,7 @@ func newSelectorTerm(tk *Token) (inst *term) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isSelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) { | func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) { | ||||||
| 	caseData, _ := caseSel.(*selectorCase) | 	caseData, _ := caseSel.(*selectorCase) | ||||||
| 	if caseData.filterList == nil { | 	if caseData.filterList == nil { | ||||||
| 		selectedValue, err = caseData.caseExpr.eval(ctx, false) | 		selectedValue, err = caseData.caseExpr.eval(ctx, false) | ||||||
| @ -113,7 +55,7 @@ func evalSelector(ctx ExprContext, self *term) (v any, err error) { | |||||||
| 	caseList, _ := caseListTerm.value().([]*term) | 	caseList, _ := caseListTerm.value().([]*term) | ||||||
| 	for i, caseTerm := range caseList { | 	for i, caseTerm := range caseList { | ||||||
| 		caseSel := caseTerm.value() | 		caseSel := caseTerm.value() | ||||||
| 		if match, v, err = isSelectorCase(ctx, exprValue, caseSel, i); err != nil || match { | 		if match, v, err = trySelectorCase(ctx, exprValue, caseSel, i); err != nil || match { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -242,6 +242,8 @@ func (self *scanner) fetchNextToken() (tk *Token) { | |||||||
| 			if next, _ := self.peek(); next == '(' { | 			if next, _ := self.peek(); next == '(' { | ||||||
| 				tk = self.moveOn(SymDollarRound, ch, next) | 				tk = self.moveOn(SymDollarRound, ch, next) | ||||||
| 				tk.source += ")" | 				tk.source += ")" | ||||||
|  | 			} else if next == '$' { | ||||||
|  | 				tk = self.moveOn(SymDoubleDollar, ch, next) | ||||||
| 			} else { | 			} else { | ||||||
| 				tk = self.makeToken(SymDollar, ch) | 				tk = self.makeToken(SymDollar, ch) | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -64,6 +64,7 @@ const ( | |||||||
| 	SymCaret                             //  53: '^'
 | 	SymCaret                             //  53: '^'
 | ||||||
| 	SymDollarRound                       //  54: '$('
 | 	SymDollarRound                       //  54: '$('
 | ||||||
| 	SymOpenClosedRound                   //  55: '()'
 | 	SymOpenClosedRound                   //  55: '()'
 | ||||||
|  | 	SymDoubleDollar                      //  56: '$$
 | ||||||
| 	SymChangeSign | 	SymChangeSign | ||||||
| 	SymUnchangeSign | 	SymUnchangeSign | ||||||
| 	SymIdentifier | 	SymIdentifier | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user