new operator dot '.' used to select an item or character from a list or a string respectively

This commit is contained in:
Celestino Amoroso 2024-04-19 09:05:26 +02:00
parent b76481bbf2
commit 7198749063
4 changed files with 71 additions and 9 deletions

61
operator-dot.go Normal file
View 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)
}

View File

@ -4,7 +4,6 @@
// operator-insert.go
package expr
//-------- insert term
func newInsertTerm(tk *Token) (inst *term) {
@ -12,7 +11,7 @@ func newInsertTerm(tk *Token) (inst *term) {
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priSign,
priority: priAssign,
evalFunc: evalInsert,
}
}
@ -22,7 +21,7 @@ func newAppendTerm(tk *Token) (inst *term) {
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priSign,
priority: priAssign,
evalFunc: evalAppend,
}
}
@ -38,7 +37,7 @@ func evalInsert(ctx ExprContext, self *term) (v any, err error) {
list, _ := rightValue.([]any)
v = append([]any{leftValue}, list...)
} else {
err = self.errIncompatibleType(rightValue)
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}
@ -54,7 +53,7 @@ func evalAppend(ctx ExprContext, self *term) (v any, err error) {
list, _ := leftValue.([]any)
v = append(list, rightValue)
} else {
err = self.errIncompatibleType(leftValue)
err = self.errIncompatibleTypes(leftValue, rightValue)
}
return
}

View File

@ -152,9 +152,10 @@ func (self *scanner) fetchNextToken() (tk *Token) {
case ';':
tk = self.makeToken(SymSemiColon, ch)
case '.':
if next, _ := self.peek(); next >= '0' && next <= '9' {
tk = self.parseNumber(ch)
} else if next == '/' {
//if next, _ := self.peek(); next >= '0' && next <= '9' {
// tk = self.parseNumber(ch)
//} else if next == '/' {
if next, _ := self.peek(); next == '/' {
tk = self.moveOn(SymDotSlash, ch, next)
} else {
tk = self.makeToken(SymDot, ch)

View File

@ -24,6 +24,7 @@ const (
priSign
priFact
priCoalesce
priDot
priValue
)
@ -166,7 +167,7 @@ func (self *term) checkOperands() (err error) {
switch self.position {
case posInfix:
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:
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {