Compare commits
5 Commits
f028485caa
...
c9db4b84e3
Author | SHA1 | Date | |
---|---|---|---|
c9db4b84e3 | |||
e7e9330b71 | |||
8eb25bbc86 | |||
efc92d434b | |||
4151f3f5e2 |
@ -26,6 +26,7 @@ func TestDictParser(t *testing.T) {
|
||||
/* 3 */ {`{1:"one",2:"two",3:"three"}`, map[int64]any{int64(1): "one", int64(2): "two", int64(3): "three"}, nil},
|
||||
/* 4 */ {`{1:"one",2:"two",3:"three"}.2`, "three", nil},
|
||||
/* 5 */ {`#{1:"one",2:"two",3:"three"}`, int64(3), nil},
|
||||
/* 6 */ {`{1:"one"} + {2:"two"}`, map[any]any{1: "one", 2: "two"}, nil},
|
||||
}
|
||||
|
||||
succeeded := 0
|
||||
|
@ -68,6 +68,15 @@ func TestFuncs(t *testing.T) {
|
||||
/* 55 */ {`builtin "math.arith"; add(1,2)`, int64(3), nil},
|
||||
/* 56 */ {`fract("2.2(3)")`, newFraction(67, 30), nil},
|
||||
/* 57 */ {`fract("1.21(3)")`, newFraction(91, 75), nil},
|
||||
/* 58 */ {`fract(1.21(3))`, newFraction(91, 75), nil},
|
||||
/* 59 */ {`fract(1.21)`, newFraction(121, 100), nil},
|
||||
/* 60 */ {`dec(2)`, float64(2), nil},
|
||||
/* 61 */ {`dec(2.0)`, float64(2), nil},
|
||||
/* 62 */ {`dec("2.0")`, float64(2), nil},
|
||||
/* 63 */ {`dec(true)`, float64(1), nil},
|
||||
/* 64 */ {`dec(true")`, nil, errors.New("[1:11] missing string termination \"")},
|
||||
/* 65 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got int64 (1)`)},
|
||||
// /* 64 */ {`string(true)`, "true", nil},
|
||||
}
|
||||
|
||||
t.Setenv("EXPR_PATH", ".")
|
||||
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operand-const.go
|
||||
package expr
|
||||
|
||||
// -------- const term
|
||||
func newConstTerm(tk *Token) *term {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
parent: nil,
|
||||
children: nil,
|
||||
position: posLeaf,
|
||||
priority: priValue,
|
||||
evalFunc: evalConst,
|
||||
}
|
||||
}
|
||||
|
||||
// -------- eval func
|
||||
func evalConst(ctx ExprContext, self *term) (v any, err error) {
|
||||
v = self.tk.Value
|
||||
return
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymString, newConstTerm)
|
||||
registerTermConstructor(SymInteger, newConstTerm)
|
||||
registerTermConstructor(SymFloat, newConstTerm)
|
||||
registerTermConstructor(SymBool, newConstTerm)
|
||||
registerTermConstructor(SymKwNil, newConstTerm)
|
||||
}
|
33
operand-literal.go
Normal file
33
operand-literal.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operand-literal.go
|
||||
package expr
|
||||
|
||||
// -------- literal term
|
||||
func newLiteralTerm(tk *Token) *term {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
parent: nil,
|
||||
children: nil,
|
||||
position: posLeaf,
|
||||
priority: priValue,
|
||||
evalFunc: evalLiteral,
|
||||
}
|
||||
}
|
||||
|
||||
// -------- eval func
|
||||
func evalLiteral(ctx ExprContext, self *term) (v any, err error) {
|
||||
v = self.tk.Value
|
||||
return
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymString, newLiteralTerm)
|
||||
registerTermConstructor(SymInteger, newLiteralTerm)
|
||||
registerTermConstructor(SymFloat, newLiteralTerm)
|
||||
registerTermConstructor(SymFraction, newLiteralTerm)
|
||||
registerTermConstructor(SymBool, newLiteralTerm)
|
||||
registerTermConstructor(SymKwNil, newLiteralTerm)
|
||||
}
|
@ -61,6 +61,14 @@ func evalPlus(ctx ExprContext, self *term) (v any, err error) {
|
||||
} else {
|
||||
v, err = sumAnyFract(leftValue, rightValue)
|
||||
}
|
||||
} else if IsDict(leftValue) && IsDict(rightValue) {
|
||||
leftDict, _ := leftValue.(map[any]any)
|
||||
rightDict, _ := rightValue.(map[any]any)
|
||||
c := CloneMap(leftDict)
|
||||
for key, value := range rightDict {
|
||||
c[key] = value
|
||||
}
|
||||
v = c
|
||||
} else {
|
||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
|
43
scanner.go
43
scanner.go
@ -385,20 +385,37 @@ func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && (ch == 'e' || ch == 'E') {
|
||||
sym = SymFloat
|
||||
sb.WriteByte(ch)
|
||||
if ch, err = self.readChar(); err == nil {
|
||||
if ch == '+' || ch == '-' {
|
||||
sb.WriteByte(ch)
|
||||
ch, err = self.readChar()
|
||||
}
|
||||
if ch >= '0' && ch <= '9' {
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
||||
if err == nil {
|
||||
if ch == 'e' || ch == 'E' {
|
||||
sym = SymFloat
|
||||
sb.WriteByte(ch)
|
||||
if ch, err = self.readChar(); err == nil {
|
||||
if ch == '+' || ch == '-' {
|
||||
sb.WriteByte(ch)
|
||||
ch, err = self.readChar()
|
||||
}
|
||||
if ch >= '0' && ch <= '9' {
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
||||
sb.WriteByte(ch)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("[%d:%d] expected integer exponent, got %c", self.row, self.column, ch)
|
||||
}
|
||||
}
|
||||
} else if ch == '(' {
|
||||
sym = SymFraction
|
||||
sb.WriteByte(ch)
|
||||
ch, err = self.readChar()
|
||||
for ; err == nil && (ch >= '0' && ch <= '9'); ch, err = self.readChar() {
|
||||
sb.WriteByte(ch)
|
||||
}
|
||||
if err == nil {
|
||||
if ch != ')' {
|
||||
err = fmt.Errorf("[%d:%d] expected ')', got '%c'", self.row, self.column, ch)
|
||||
} else {
|
||||
sb.WriteByte(ch)
|
||||
_, err = self.readChar()
|
||||
}
|
||||
} else {
|
||||
err = errors.New("expected integer exponent")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,6 +429,8 @@ func (self *scanner) parseNumber(firstCh byte) (tk *Token) {
|
||||
txt := sb.String()
|
||||
if sym == SymFloat {
|
||||
value, err = strconv.ParseFloat(txt, 64)
|
||||
} else if sym == SymFraction {
|
||||
value, err = makeGeneratingFraction(txt)
|
||||
} else {
|
||||
value, err = strconv.ParseInt(txt, numBase, 64)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package expr
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -55,15 +56,18 @@ func TestScanner(t *testing.T) {
|
||||
/* 33 */ {`(`, SymOpenRound, nil, nil},
|
||||
/* 34 */ {`)`, SymClosedRound, nil, nil},
|
||||
/* 35 */ {`1E+2`, SymFloat, float64(100), nil},
|
||||
/* 36 */ {`1E+x`, SymError, errors.New("expected integer exponent"), nil},
|
||||
/* 36 */ {`1E+x`, SymError, errors.New("[1:5] expected integer exponent, got x"), nil},
|
||||
/* 37 */ {`$`, SymDollar, nil, nil},
|
||||
/* 38 */ {`\`, SymError, errors.New("incomplete escape sequence"), nil},
|
||||
/* 39 */ {`"string"`, SymString, "string", nil},
|
||||
/* 39 */ {`identifier`, SymIdentifier, "identifier", nil},
|
||||
/* 40 */ {`identifier`, SymIdentifier, "identifier", nil},
|
||||
/* 41 */ {`1.2(3)`, SymFraction, newFraction(37, 30), nil},
|
||||
}
|
||||
|
||||
for i, input := range inputs {
|
||||
|
||||
// if i != 40 {
|
||||
// continue
|
||||
// }
|
||||
if input.wantErr == nil {
|
||||
t.Log(fmt.Sprintf("[+]Test nr %2d -- %q", i+1, input.source))
|
||||
} else {
|
||||
@ -75,7 +79,8 @@ func TestScanner(t *testing.T) {
|
||||
|
||||
if tk := scanner.Next(); tk == nil {
|
||||
t.Errorf("%d: %q -> got = (nil), want %v (value %v [%T])", i+1, input.source, input.wantSym, input.wantValue, input.wantValue)
|
||||
} else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
|
||||
// } else if tk.Sym != input.wantSym || tk.Value != input.wantValue {
|
||||
} else if tk.Sym != input.wantSym || !reflect.DeepEqual(tk.Value, input.wantValue) {
|
||||
if tk.Sym == SymError && input.wantSym == tk.Sym {
|
||||
if tkErr, tkOk := tk.Value.(error); tkOk {
|
||||
if inputErr, inputOk := input.wantValue.(error); inputOk {
|
||||
@ -86,7 +91,7 @@ func TestScanner(t *testing.T) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%d: %q -> got = %v (value=%v [%T), want %v (value=%v [%T)", i+1,
|
||||
t.Errorf("%d: %q -> got = %v (value=%v [%T]), want %v (value=%v [%T])", i+1,
|
||||
input.source, tk.Sym, tk.Value, tk.Value, input.wantSym, input.wantValue, input.wantValue)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user