diff --git a/operator-dot.go b/operator-dot.go new file mode 100644 index 0000000..8b7fa0a --- /dev/null +++ b/operator-dot.go @@ -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) +} diff --git a/operator-insert.go b/operator-insert.go index 3a71c64..f752115 100644 --- a/operator-insert.go +++ b/operator-insert.go @@ -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 } diff --git a/scanner.go b/scanner.go index aaa24af..b5e1f18 100644 --- a/scanner.go +++ b/scanner.go @@ -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) diff --git a/term.go b/term.go index abecca3..e7c6c1b 100644 --- a/term.go +++ b/term.go @@ -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 {