Compare commits

...

2 Commits

5 changed files with 72 additions and 10 deletions

View File

@ -182,7 +182,7 @@ a=1; b=2; c=3; a+b+c // returns 6
=== [blue]`but` operator === [blue]`but` operator
[blue]`but` is an infixed operator. Its operands can be any type of expression. It evaluates the left expression first, then the right expression. The value of the right expression is the final result. Examples: [blue]`5 but 2` returns 2, [blue]`x=2*3 but x-1` returns 5. [blue]`but` is an infixed operator. Its operands can be any type of expression. It evaluates the left expression first, then the right expression. The value of the right expression is the final result. Examples: [blue]`5 but 2` returns 2, [blue]`x=2*3 but x-1` returns 5.
[blue]`but` is very similar to [blue]`;`. The only difference is that [blue]`;` can't be used inside parenthesis [blue]`;(` and [blue]`)`. [blue]`but` is very similar to [blue]`;`. The only difference is that [blue]`;` can't be used inside parenthesis [blue]`(` and [blue]`)`.
=== Assignment operator [blue]`=` === Assignment operator [blue]`=`
The assignment operator [blue]`=` is used to define variable in the evaluation context or to change their value (see _ExprContext_). The assignment operator [blue]`=` is used to define variable in the evaluation context or to change their value (see _ExprContext_).

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 // 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
} }

View File

@ -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)

View File

@ -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 {