new operator dot '.' used to select an item or character from a list or a string respectively
This commit is contained in:
parent
b76481bbf2
commit
7198749063
61
operator-dot.go
Normal file
61
operator-dot.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-dot.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
// -------- dot term
|
||||||
|
func newDotTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priDot,
|
||||||
|
evalFunc: evalDot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalDot(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
indexTerm := self.children[1]
|
||||||
|
if !isInteger(rightValue) {
|
||||||
|
err = indexTerm.Errorf("index expression must be integer, got %T", rightValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
index64, _ := rightValue.(int64)
|
||||||
|
index := int(index64)
|
||||||
|
|
||||||
|
if isList(leftValue) {
|
||||||
|
list, _ := leftValue.([]any)
|
||||||
|
if index >= 0 && index < len(list) {
|
||||||
|
v = list[index]
|
||||||
|
} else if index >= -len(list) {
|
||||||
|
v = list[len(list)+index]
|
||||||
|
} else {
|
||||||
|
err = indexTerm.Errorf("index %v out of bounds", index)
|
||||||
|
}
|
||||||
|
} else if isString(leftValue) {
|
||||||
|
s, _ := leftValue.(string)
|
||||||
|
if index >= 0 && index < len(s) {
|
||||||
|
v = string(s[index])
|
||||||
|
} else if index >= -len(s) {
|
||||||
|
v = string(s[len(s)+index])
|
||||||
|
} else {
|
||||||
|
err = indexTerm.Errorf("index %v out of bounds", index)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymDot, newDotTerm)
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
// operator-insert.go
|
// operator-insert.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
|
|
||||||
//-------- insert term
|
//-------- insert term
|
||||||
|
|
||||||
func newInsertTerm(tk *Token) (inst *term) {
|
func newInsertTerm(tk *Token) (inst *term) {
|
||||||
@ -12,7 +11,7 @@ func newInsertTerm(tk *Token) (inst *term) {
|
|||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priSign,
|
priority: priAssign,
|
||||||
evalFunc: evalInsert,
|
evalFunc: evalInsert,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,7 +21,7 @@ func newAppendTerm(tk *Token) (inst *term) {
|
|||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priSign,
|
priority: priAssign,
|
||||||
evalFunc: evalAppend,
|
evalFunc: evalAppend,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,7 +37,7 @@ func evalInsert(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
list, _ := rightValue.([]any)
|
list, _ := rightValue.([]any)
|
||||||
v = append([]any{leftValue}, list...)
|
v = append([]any{leftValue}, list...)
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleType(rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -54,7 +53,7 @@ func evalAppend(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
list, _ := leftValue.([]any)
|
list, _ := leftValue.([]any)
|
||||||
v = append(list, rightValue)
|
v = append(list, rightValue)
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleType(leftValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,9 +152,10 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
|||||||
case ';':
|
case ';':
|
||||||
tk = self.makeToken(SymSemiColon, ch)
|
tk = self.makeToken(SymSemiColon, ch)
|
||||||
case '.':
|
case '.':
|
||||||
if next, _ := self.peek(); next >= '0' && next <= '9' {
|
//if next, _ := self.peek(); next >= '0' && next <= '9' {
|
||||||
tk = self.parseNumber(ch)
|
// tk = self.parseNumber(ch)
|
||||||
} else if next == '/' {
|
//} else if next == '/' {
|
||||||
|
if next, _ := self.peek(); next == '/' {
|
||||||
tk = self.moveOn(SymDotSlash, ch, next)
|
tk = self.moveOn(SymDotSlash, ch, next)
|
||||||
} else {
|
} else {
|
||||||
tk = self.makeToken(SymDot, ch)
|
tk = self.makeToken(SymDot, ch)
|
||||||
|
3
term.go
3
term.go
@ -24,6 +24,7 @@ const (
|
|||||||
priSign
|
priSign
|
||||||
priFact
|
priFact
|
||||||
priCoalesce
|
priCoalesce
|
||||||
|
priDot
|
||||||
priValue
|
priValue
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ func (self *term) checkOperands() (err error) {
|
|||||||
switch self.position {
|
switch self.position {
|
||||||
case posInfix:
|
case posInfix:
|
||||||
if self.children == nil || len(self.children) != 2 || self.anyChildrenNil() {
|
if self.children == nil || len(self.children) != 2 || self.anyChildrenNil() {
|
||||||
err = self.tk.Errorf("infix operator %q requires two not nil operands, got %d", self.source(), self.getChildrenCount())
|
err = self.tk.Errorf("infix operator %q requires two non-nil operands, got %d", self.source(), self.getChildrenCount())
|
||||||
}
|
}
|
||||||
case posPrefix:
|
case posPrefix:
|
||||||
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
|
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user