new operator "?!" (alternate value)
This commit is contained in:
parent
1e62a51c15
commit
fd8e32e12b
@ -53,3 +53,9 @@ func ErrInvalidParameterValue(funcName, paramName string, paramValue any) error
|
|||||||
func ErrWrongParamType(funcName, paramName, paramType string, paramValue any) error {
|
func ErrWrongParamType(funcName, paramName, paramType string, paramValue any) error {
|
||||||
return fmt.Errorf("%s(): the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, TypeName(paramValue), paramValue)
|
return fmt.Errorf("%s(): the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, TypeName(paramValue), paramValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Operator errors
|
||||||
|
|
||||||
|
func ErrLeftOperandMustBeVariable(leftTerm, opTerm *term) error {
|
||||||
|
return leftTerm.Errorf("left operand of %q must be a variable", opTerm.source())
|
||||||
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// operator-coalesce.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
//-------- null coalesce term
|
|
||||||
|
|
||||||
func newNullCoalesceTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priCoalesce,
|
|
||||||
evalFunc: evalNullCoalesce,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalNullCoalesce(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
var rightValue any
|
|
||||||
|
|
||||||
if err = self.checkOperands(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leftTerm := self.children[0]
|
|
||||||
if leftTerm.tk.Sym != SymVariable {
|
|
||||||
err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
|
|
||||||
v = leftValue
|
|
||||||
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
|
||||||
v = rightValue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------- coalesce assign term
|
|
||||||
|
|
||||||
func newCoalesceAssignTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priCoalesce,
|
|
||||||
evalFunc: evalAssignCoalesce,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalAssignCoalesce(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
var rightValue any
|
|
||||||
|
|
||||||
if err = self.checkOperands(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leftTerm := self.children[0]
|
|
||||||
if leftTerm.tk.Sym != SymVariable {
|
|
||||||
err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
|
|
||||||
v = leftValue
|
|
||||||
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
|
||||||
if functor, ok := rightValue.(Functor); ok {
|
|
||||||
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
|
||||||
ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, []ExprFuncParam{
|
|
||||||
NewFuncParamFlag(ParamValue, PfDefault|PfRepeat),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
v = rightValue
|
|
||||||
ctx.UnsafeSetVar(leftTerm.source(), rightValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
func init() {
|
|
||||||
registerTermConstructor(SymDoubleQuestion, newNullCoalesceTerm)
|
|
||||||
registerTermConstructor(SymQuestionEqual, newCoalesceAssignTerm)
|
|
||||||
}
|
|
124
operator-default.go
Normal file
124
operator-default.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-default.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
//-------- default term
|
||||||
|
|
||||||
|
func newDefaultTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priCoalesce,
|
||||||
|
evalFunc: evalDefault,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalDefault(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var rightValue any
|
||||||
|
|
||||||
|
if err = self.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
leftTerm := self.children[0]
|
||||||
|
if leftTerm.tk.Sym != SymVariable {
|
||||||
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
|
err = ErrLeftOperandMustBeVariable(leftTerm, self)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
|
||||||
|
v = leftValue
|
||||||
|
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||||
|
v = rightValue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------- alternate term
|
||||||
|
|
||||||
|
func newAlternateTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priCoalesce,
|
||||||
|
evalFunc: evalAlternate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalAlternate(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var rightValue any
|
||||||
|
|
||||||
|
if err = self.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
leftTerm := self.children[0]
|
||||||
|
if leftTerm.tk.Sym != SymVariable {
|
||||||
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
|
err = ErrLeftOperandMustBeVariable(leftTerm, self)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists && leftValue != nil {
|
||||||
|
if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||||
|
v = rightValue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = leftValue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------- default assign term
|
||||||
|
|
||||||
|
func newDefaultAssignTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priCoalesce,
|
||||||
|
evalFunc: evalAssignDefault,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalAssignDefault(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var rightValue any
|
||||||
|
|
||||||
|
if err = self.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
leftTerm := self.children[0]
|
||||||
|
if leftTerm.tk.Sym != SymVariable {
|
||||||
|
// err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source)
|
||||||
|
err = ErrLeftOperandMustBeVariable(leftTerm, self)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, exists := ctx.GetVar(leftTerm.source()); exists {
|
||||||
|
v = leftValue
|
||||||
|
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||||
|
if functor, ok := rightValue.(Functor); ok {
|
||||||
|
//ctx.RegisterFunc(leftTerm.source(), functor, 0, -1)
|
||||||
|
ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, []ExprFuncParam{
|
||||||
|
NewFuncParamFlag(ParamValue, PfDefault|PfRepeat),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
v = rightValue
|
||||||
|
ctx.UnsafeSetVar(leftTerm.source(), rightValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymDoubleQuestion, newDefaultTerm)
|
||||||
|
registerTermConstructor(SymQuestionEqual, newDefaultAssignTerm)
|
||||||
|
registerTermConstructor(SymQuestionExclam, newAlternateTerm)
|
||||||
|
}
|
@ -202,8 +202,10 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
|||||||
case '?':
|
case '?':
|
||||||
if next, _ := self.peek(); next == '?' {
|
if next, _ := self.peek(); next == '?' {
|
||||||
tk = self.moveOn(SymDoubleQuestion, ch, next)
|
tk = self.moveOn(SymDoubleQuestion, ch, next)
|
||||||
} else if next, _ := self.peek(); next == '=' {
|
} else if next == '=' {
|
||||||
tk = self.moveOn(SymQuestionEqual, ch, next)
|
tk = self.moveOn(SymQuestionEqual, ch, next)
|
||||||
|
} else if next == '!' {
|
||||||
|
tk = self.moveOn(SymQuestionExclam, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = self.makeToken(SymQuestion, ch)
|
tk = self.makeToken(SymQuestion, ch)
|
||||||
}
|
}
|
||||||
|
21
symbol.go
21
symbol.go
@ -57,16 +57,17 @@ const (
|
|||||||
SymTilde // 46: '~'
|
SymTilde // 46: '~'
|
||||||
SymDoubleQuestion // 47: '??'
|
SymDoubleQuestion // 47: '??'
|
||||||
SymQuestionEqual // 48: '?='
|
SymQuestionEqual // 48: '?='
|
||||||
SymDoubleAt // 49: '@@'
|
SymQuestionExclam // 49: '?!'
|
||||||
SymDoubleColon // 50: '::'
|
SymDoubleAt // 50: '@@'
|
||||||
SymInsert // 51: '>>'
|
SymDoubleColon // 51: '::'
|
||||||
SymAppend // 52: '<<'
|
SymInsert // 52: '>>'
|
||||||
SymCaret // 53: '^'
|
SymAppend // 53: '<<'
|
||||||
SymDollarRound // 54: '$('
|
SymCaret // 54: '^'
|
||||||
SymOpenClosedRound // 55: '()'
|
SymDollarRound // 55: '$('
|
||||||
SymDoubleDollar // 56: '$$'
|
SymOpenClosedRound // 56: '()'
|
||||||
SymDoubleDot // 57: '..'
|
SymDoubleDollar // 57: '$$'
|
||||||
SymTripleDot // 58: '...'
|
SymDoubleDot // 58: '..'
|
||||||
|
SymTripleDot // 59: '...'
|
||||||
SymChangeSign
|
SymChangeSign
|
||||||
SymUnchangeSign
|
SymUnchangeSign
|
||||||
SymIdentifier
|
SymIdentifier
|
||||||
|
Loading…
Reference in New Issue
Block a user