Compare commits
No commits in common. "5809de419f19cc98824f480e0b43f21be63739e8" and "c0c2ab8b4ea1aa1c6d43c8112b9775f487087b6f" have entirely different histories.
5809de419f
...
c0c2ab8b4e
@ -7,7 +7,6 @@ package expr
|
|||||||
const (
|
const (
|
||||||
typeBoolean = "boolean"
|
typeBoolean = "boolean"
|
||||||
typeFloat = "decimal"
|
typeFloat = "decimal"
|
||||||
typeFraction = "fraction"
|
|
||||||
typeInt = "integer"
|
typeInt = "integer"
|
||||||
typeNumber = "number"
|
typeNumber = "number"
|
||||||
typeString = "string"
|
typeString = "string"
|
||||||
|
16
formatter.go
16
formatter.go
@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// formatter.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
type FmtOpt uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
TTY FmtOpt = 1 << iota
|
|
||||||
MultiLine
|
|
||||||
)
|
|
||||||
|
|
||||||
type Formatter interface {
|
|
||||||
ToString(options FmtOpt) string
|
|
||||||
}
|
|
71
func-math.go
71
func-math.go
@ -10,17 +10,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func checkNumberParamExpected(funcName string, paramValue any, paramPos int) (err error) {
|
func checkNumberParamExpected(funcName string, paramValue any, paramPos int) (err error) {
|
||||||
if !(isNumber(paramValue) || isList(paramValue) || isFraction(paramValue)) {
|
if !(isNumber(paramValue) || isList(paramValue) || isIterator(paramValue)) {
|
||||||
err = fmt.Errorf("%s(): param nr %d has wrong type %T, number expected", funcName, paramPos+1, paramValue)
|
err = fmt.Errorf("%s(): param nr %d has wrong type %T, number expected", funcName, paramPos+1, paramValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
||||||
var sumAsFloat, sumAsFract bool
|
var sumAsFloat = false
|
||||||
var floatSum float64 = 0.0
|
var floatSum float64 = 0.0
|
||||||
var intSum int64 = 0
|
var intSum int64 = 0
|
||||||
var fractSum *fraction
|
|
||||||
var v any
|
var v any
|
||||||
|
|
||||||
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
||||||
@ -37,37 +36,19 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
|||||||
if err = checkNumberParamExpected(name, v, it.Index()); err != nil {
|
if err = checkNumberParamExpected(name, v, it.Index()); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if array, ok := v.(*ListType); ok {
|
if array, ok := v.([]any); ok {
|
||||||
if v, err = doAdd(ctx, name, NewFlatArrayIterator(*array)); err != nil {
|
if v, err = doAdd(ctx, name, NewFlatArrayIterator(array)); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sumAsFloat {
|
if !sumAsFloat && isFloat(v) {
|
||||||
if isFloat(v) {
|
|
||||||
sumAsFloat = true
|
sumAsFloat = true
|
||||||
if sumAsFract {
|
|
||||||
floatSum = fractSum.toFloat()
|
|
||||||
} else {
|
|
||||||
floatSum = float64(intSum)
|
floatSum = float64(intSum)
|
||||||
}
|
}
|
||||||
} else if !sumAsFract && isFraction(v) {
|
|
||||||
fractSum = newFraction(intSum, 1)
|
|
||||||
sumAsFract = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sumAsFloat {
|
if sumAsFloat {
|
||||||
floatSum += numAsFloat(v)
|
floatSum += numAsFloat(v)
|
||||||
} else if sumAsFract {
|
|
||||||
var item *fraction
|
|
||||||
var ok bool
|
|
||||||
if item, ok = v.(*fraction); !ok {
|
|
||||||
iv, _ := v.(int64)
|
|
||||||
item = newFraction(iv, 1)
|
|
||||||
}
|
|
||||||
fractSum = sumFract(fractSum, item)
|
|
||||||
} else {
|
} else {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
intSum += iv
|
intSum += iv
|
||||||
@ -77,8 +58,6 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
|||||||
err = nil
|
err = nil
|
||||||
if sumAsFloat {
|
if sumAsFloat {
|
||||||
result = floatSum
|
result = floatSum
|
||||||
} else if sumAsFract {
|
|
||||||
result = fractSum
|
|
||||||
} else {
|
} else {
|
||||||
result = intSum
|
result = intSum
|
||||||
}
|
}
|
||||||
@ -92,58 +71,28 @@ func addFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
||||||
var mulAsFloat, mulAsFract bool
|
var mulAsFloat = false
|
||||||
var floatProd float64 = 1.0
|
var floatProd float64 = 1.0
|
||||||
var intProd int64 = 1
|
var intProd int64 = 1
|
||||||
var fractProd *fraction
|
|
||||||
var v any
|
var v any
|
||||||
|
|
||||||
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
||||||
if subIter, ok := v.(Iterator); ok {
|
|
||||||
if v, err = doAdd(ctx, name, subIter); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if subIter.HasOperation(cleanName) {
|
|
||||||
if _, err = subIter.CallOperation(cleanName, nil); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err = checkNumberParamExpected(name, v, it.Index()); err != nil {
|
if err = checkNumberParamExpected(name, v, it.Index()); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if array, ok := v.(*ListType); ok {
|
if array, ok := v.([]any); ok {
|
||||||
if v, err = doMul(ctx, name, NewFlatArrayIterator(*array)); err != nil {
|
if v, err = doMul(ctx, name, NewFlatArrayIterator(array)); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !mulAsFloat {
|
if !mulAsFloat && isFloat(v) {
|
||||||
if isFloat(v) {
|
|
||||||
mulAsFloat = true
|
mulAsFloat = true
|
||||||
if mulAsFract {
|
|
||||||
floatProd = fractProd.toFloat()
|
|
||||||
} else {
|
|
||||||
floatProd = float64(intProd)
|
floatProd = float64(intProd)
|
||||||
}
|
}
|
||||||
} else if !mulAsFract && isFraction(v) {
|
|
||||||
fractProd = newFraction(intProd, 1)
|
|
||||||
mulAsFract = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if mulAsFloat {
|
if mulAsFloat {
|
||||||
floatProd *= numAsFloat(v)
|
floatProd *= numAsFloat(v)
|
||||||
} else if mulAsFract {
|
|
||||||
var item *fraction
|
|
||||||
var ok bool
|
|
||||||
if item, ok = v.(*fraction); !ok {
|
|
||||||
iv, _ := v.(int64)
|
|
||||||
item = newFraction(iv, 1)
|
|
||||||
}
|
|
||||||
fractProd = mulFract(fractProd, item)
|
|
||||||
} else {
|
} else {
|
||||||
iv, _ := v.(int64)
|
iv, _ := v.(int64)
|
||||||
intProd *= iv
|
intProd *= iv
|
||||||
@ -153,8 +102,6 @@ func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) {
|
|||||||
err = nil
|
err = nil
|
||||||
if mulAsFloat {
|
if mulAsFloat {
|
||||||
result = floatProd
|
result = floatProd
|
||||||
} else if mulAsFract {
|
|
||||||
result = fractProd
|
|
||||||
} else {
|
} else {
|
||||||
result = intProd
|
result = intProd
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ package expr
|
|||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
type FlatArrayIterator struct {
|
type FlatArrayIterator struct {
|
||||||
a ListType
|
a []any
|
||||||
index int
|
index int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFlatArrayIterator(array ListType) *FlatArrayIterator {
|
func NewFlatArrayIterator(array []any) *FlatArrayIterator {
|
||||||
return &FlatArrayIterator{a: array, index: 0}
|
return &FlatArrayIterator{a: array, index: 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,44 +4,6 @@
|
|||||||
// operand-list.go
|
// operand-list.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ListType []any
|
|
||||||
|
|
||||||
func (ls *ListType) ToString(opt FmtOpt) string {
|
|
||||||
var sb strings.Builder
|
|
||||||
sb.WriteByte('[')
|
|
||||||
if len(*ls) > 0 {
|
|
||||||
if opt&MultiLine != 0 {
|
|
||||||
sb.WriteString("\n ")
|
|
||||||
}
|
|
||||||
for i, item := range []any(*ls) {
|
|
||||||
if i > 0 {
|
|
||||||
if opt&MultiLine != 0 {
|
|
||||||
sb.WriteString(",\n ")
|
|
||||||
} else {
|
|
||||||
sb.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s, ok := item.(string); ok {
|
|
||||||
sb.WriteByte('"')
|
|
||||||
sb.WriteString(s)
|
|
||||||
sb.WriteByte('"')
|
|
||||||
} else {
|
|
||||||
sb.WriteString(fmt.Sprintf("%v", item))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if opt&MultiLine != 0 {
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.WriteByte(']')
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------- list term
|
// -------- list term
|
||||||
func newListTermA(args ...*term) *term {
|
func newListTermA(args ...*term) *term {
|
||||||
return newListTerm(args)
|
return newListTerm(args)
|
||||||
@ -61,7 +23,7 @@ func newListTerm(args []*term) *term {
|
|||||||
// -------- list func
|
// -------- list func
|
||||||
func evalList(ctx ExprContext, self *term) (v any, err error) {
|
func evalList(ctx ExprContext, self *term) (v any, err error) {
|
||||||
list, _ := self.value().([]*term)
|
list, _ := self.value().([]*term)
|
||||||
items := make(ListType, len(list))
|
items := make([]any, len(list))
|
||||||
for i, tree := range list {
|
for i, tree := range list {
|
||||||
var param any
|
var param any
|
||||||
if param, err = tree.compute(ctx); err != nil {
|
if param, err = tree.compute(ctx); err != nil {
|
||||||
@ -70,7 +32,35 @@ func evalList(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
items[i] = param
|
items[i] = param
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
v = &items
|
v = items
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // -------- list term
|
||||||
|
// func newListTerm(args []*term) *term {
|
||||||
|
// return &term{
|
||||||
|
// tk: *NewToken(0, 0, SymList, "[]"),
|
||||||
|
// parent: nil,
|
||||||
|
// children: args,
|
||||||
|
// position: posLeaf,
|
||||||
|
// priority: priValue,
|
||||||
|
// evalFunc: evalList,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // -------- list func
|
||||||
|
// func evalList(ctx ExprContext, self *term) (v any, err error) {
|
||||||
|
// items := make([]any, len(self.children))
|
||||||
|
// for i, tree := range self.children {
|
||||||
|
// var param any
|
||||||
|
// if param, err = tree.compute(ctx); err != nil {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// items[i] = param
|
||||||
|
// }
|
||||||
|
// if err == nil {
|
||||||
|
// v = items
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
@ -1,274 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// operand-fraction.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fraction struct {
|
|
||||||
num, den int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFraction(num, den int64) *fraction {
|
|
||||||
if den < 0 {
|
|
||||||
den = -den
|
|
||||||
num = -num
|
|
||||||
}
|
|
||||||
return &fraction{num, den}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fraction) toFloat() float64 {
|
|
||||||
return float64(f.num) / float64(f.den)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fraction) String() string {
|
|
||||||
return f.ToString(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fraction) ToString(opt FmtOpt) string {
|
|
||||||
var sb strings.Builder
|
|
||||||
if opt&MultiLine == 0 {
|
|
||||||
sb.WriteString(fmt.Sprintf("%d|%d", f.num, f.den))
|
|
||||||
} else {
|
|
||||||
var s, num string
|
|
||||||
if f.num < 0 && opt&TTY == 0 {
|
|
||||||
num = strconv.FormatInt(-f.num, 10)
|
|
||||||
s = "-"
|
|
||||||
} else {
|
|
||||||
num = strconv.FormatInt(f.num, 10)
|
|
||||||
}
|
|
||||||
den := strconv.FormatInt(f.den, 10)
|
|
||||||
size := max(len(num), len(den))
|
|
||||||
if opt&TTY != 0 {
|
|
||||||
sb.WriteString(fmt.Sprintf("\x1b[4m%[1]*s\x1b[0m\n", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, s+num)))
|
|
||||||
} else {
|
|
||||||
if len(s) > 0 {
|
|
||||||
sb.WriteString(" ")
|
|
||||||
}
|
|
||||||
sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, num)))
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
if len(s) > 0 {
|
|
||||||
sb.WriteString(s)
|
|
||||||
sb.WriteByte(' ')
|
|
||||||
}
|
|
||||||
sb.WriteString(strings.Repeat("-", size))
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
if len(s) > 0 {
|
|
||||||
sb.WriteString(" ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(den))/2, den)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------- fraction term
|
|
||||||
func newFractionTerm(tk *Token) *term {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
parent: nil,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priFraction,
|
|
||||||
evalFunc: evalFraction,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------- eval func
|
|
||||||
func evalFraction(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
var numValue, denValue any
|
|
||||||
var num, den int64
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
if numValue, denValue, err = self.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if num, ok = numValue.(int64); !ok {
|
|
||||||
err = fmt.Errorf("numerator must be integer, got %T (%v)", numValue, numValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if den, ok = denValue.(int64); !ok {
|
|
||||||
err = fmt.Errorf("denominator must be integer, got %T (%v)", denValue, denValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if den == 0 {
|
|
||||||
err = errors.New("division by zero")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if den < 0 {
|
|
||||||
den = -den
|
|
||||||
num = -num
|
|
||||||
}
|
|
||||||
g := gcd(num, den)
|
|
||||||
num = num / g
|
|
||||||
den = den / g
|
|
||||||
if den == 1 {
|
|
||||||
v = num
|
|
||||||
} else {
|
|
||||||
v = &fraction{num, den}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func gcd(a, b int64) (g int64) {
|
|
||||||
if a < 0 {
|
|
||||||
a = -a
|
|
||||||
}
|
|
||||||
if b < 0 {
|
|
||||||
b = -b
|
|
||||||
}
|
|
||||||
if a < b {
|
|
||||||
a, b = b, a
|
|
||||||
}
|
|
||||||
r := a % b
|
|
||||||
for r > 0 {
|
|
||||||
a, b = b, r
|
|
||||||
r = a % b
|
|
||||||
}
|
|
||||||
g = b
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func lcm(a, b int64) (l int64) {
|
|
||||||
g := gcd(a, b)
|
|
||||||
l = a * b / g
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func sumFract(f1, f2 *fraction) (sum *fraction) {
|
|
||||||
m := lcm(f1.den, f2.den)
|
|
||||||
sum = &fraction{f1.num*(m/f1.den) + f2.num*(m/f2.den), m}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func mulFract(f1, f2 *fraction) (prod *fraction) {
|
|
||||||
prod = &fraction{f1.num * f2.num, f1.den * f2.den}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func anyToFract(v any) (f *fraction, err error) {
|
|
||||||
var ok bool
|
|
||||||
if f, ok = v.(*fraction); !ok {
|
|
||||||
if n, ok := v.(int64); ok {
|
|
||||||
f = intToFraction(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if f == nil {
|
|
||||||
err = errExpectedGot("fract", typeFraction, v)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func anyPairToFract(v1, v2 any) (f1, f2 *fraction, err error) {
|
|
||||||
if f1, err = anyToFract(v1); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f2, err = anyToFract(v2); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func sumAnyFract(af1, af2 any) (sum any, err error) {
|
|
||||||
var f1, f2 *fraction
|
|
||||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f := sumFract(f1, f2)
|
|
||||||
if f.num == 0 {
|
|
||||||
sum = 0
|
|
||||||
} else {
|
|
||||||
sum = simplifyFraction(f)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func subAnyFract(af1, af2 any) (sum any, err error) {
|
|
||||||
var f1, f2 *fraction
|
|
||||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f2.num = -f2.num
|
|
||||||
f := sumFract(f1, f2)
|
|
||||||
if f.num == 0 {
|
|
||||||
sum = 0
|
|
||||||
} else {
|
|
||||||
sum = simplifyFraction(f)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func mulAnyFract(af1, af2 any) (prod any, err error) {
|
|
||||||
var f1, f2 *fraction
|
|
||||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f1.num == 0 || f2.num == 0 {
|
|
||||||
prod = 0
|
|
||||||
} else {
|
|
||||||
f := &fraction{f1.num * f2.num, f1.den * f2.den}
|
|
||||||
prod = simplifyFraction(f)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func divAnyFract(af1, af2 any) (quot any, err error) {
|
|
||||||
var f1, f2 *fraction
|
|
||||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f2.num == 0 {
|
|
||||||
err = errors.New("division by zero")
|
|
||||||
return
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if f1.num == 0 || f2.den == 0 {
|
|
||||||
quot = 0
|
|
||||||
} else {
|
|
||||||
f := &fraction{f1.num * f2.den, f1.den * f2.num}
|
|
||||||
quot = simplifyFraction(f)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func simplifyFraction(f *fraction) any {
|
|
||||||
return simplifyIntegers(f.num, f.den)
|
|
||||||
}
|
|
||||||
|
|
||||||
func simplifyIntegers(num, den int64) (v any) {
|
|
||||||
if den < 0 {
|
|
||||||
den = -den
|
|
||||||
num = -num
|
|
||||||
}
|
|
||||||
g := gcd(num, den)
|
|
||||||
num = num / g
|
|
||||||
den = den / g
|
|
||||||
if den == 1 {
|
|
||||||
v = num
|
|
||||||
} else {
|
|
||||||
v = &fraction{num, den}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func intToFraction(n int64) *fraction {
|
|
||||||
return &fraction{n, 1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isFraction(v any) (ok bool) {
|
|
||||||
_, ok = v.(*fraction)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
func init() {
|
|
||||||
registerTermConstructor(SymVertBar, newFractionTerm)
|
|
||||||
}
|
|
@ -42,8 +42,6 @@ func evalMultiply(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
v = leftInt * rightInt
|
v = leftInt * rightInt
|
||||||
}
|
}
|
||||||
} else if isFraction(leftValue) || isFraction(rightValue) {
|
|
||||||
v, err = mulAnyFract(leftValue, rightValue)
|
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@ -87,8 +85,6 @@ func evalDivide(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
v = leftInt / rightInt
|
v = leftInt / rightInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if isFraction(leftValue) || isFraction(rightValue) {
|
|
||||||
v, err = divAnyFract(leftValue, rightValue)
|
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
|
@ -39,24 +39,22 @@ func evalPlus(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
v = leftInt + rightInt
|
v = leftInt + rightInt
|
||||||
}
|
}
|
||||||
} else if isList(leftValue) || isList(rightValue) {
|
} else if isList(leftValue) || isList(rightValue) {
|
||||||
var leftList, rightList *ListType
|
var leftList, rightList []any
|
||||||
var ok bool
|
var ok bool
|
||||||
if leftList, ok = leftValue.(*ListType); !ok {
|
if leftList, ok = leftValue.([]any); !ok {
|
||||||
leftList = &ListType{leftValue}
|
leftList = []any{leftValue}
|
||||||
}
|
}
|
||||||
if rightList, ok = rightValue.(*ListType); !ok {
|
if rightList, ok = rightValue.([]any); !ok {
|
||||||
rightList = &ListType{rightValue}
|
rightList = []any{rightValue}
|
||||||
}
|
}
|
||||||
sumList := make(ListType, 0, len(*leftList)+len(*rightList))
|
sumList := make([]any, 0, len(leftList)+len(rightList))
|
||||||
for _, item := range *leftList {
|
for _, item := range leftList {
|
||||||
sumList = append(sumList, item)
|
sumList = append(sumList, item)
|
||||||
}
|
}
|
||||||
for _, item := range *rightList {
|
for _, item := range rightList {
|
||||||
sumList = append(sumList, item)
|
sumList = append(sumList, item)
|
||||||
}
|
}
|
||||||
v = &sumList
|
v = sumList
|
||||||
} else if isFraction(leftValue) || isFraction(rightValue) {
|
|
||||||
v, err = sumAnyFract(leftValue, rightValue)
|
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@ -91,17 +89,15 @@ func evalMinus(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
v = leftInt - rightInt
|
v = leftInt - rightInt
|
||||||
}
|
}
|
||||||
} else if isList(leftValue) && isList(rightValue) {
|
} else if isList(leftValue) && isList(rightValue) {
|
||||||
leftList, _ := leftValue.(*ListType)
|
leftList, _ := leftValue.([]any)
|
||||||
rightList, _ := rightValue.(*ListType)
|
rightList, _ := rightValue.([]any)
|
||||||
diffList := make(ListType, 0, len(*leftList)-len(*rightList))
|
diffList := make([]any, 0, len(leftList)-len(rightList))
|
||||||
for _, item := range *leftList {
|
for _, item := range leftList {
|
||||||
if slices.Index(*rightList, item) < 0 {
|
if slices.Index(rightList, item) < 0 {
|
||||||
diffList = append(diffList, item)
|
diffList = append(diffList, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v = &diffList
|
v = diffList
|
||||||
} else if isFraction(leftValue) || isFraction(rightValue) {
|
|
||||||
v, err = subAnyFract(leftValue, rightValue)
|
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
|
1
term.go
1
term.go
@ -20,7 +20,6 @@ const (
|
|||||||
priRelational
|
priRelational
|
||||||
priSum
|
priSum
|
||||||
priProduct
|
priProduct
|
||||||
priFraction
|
|
||||||
priSelector
|
priSelector
|
||||||
priSign
|
priSign
|
||||||
priFact
|
priFact
|
||||||
|
6
utils.go
6
utils.go
@ -25,7 +25,7 @@ func isFloat(v any) (ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isList(v any) (ok bool) {
|
func isList(v any) (ok bool) {
|
||||||
_, ok = v.(*ListType)
|
_, ok = v.([]any)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,13 +55,9 @@ func isIterator(v any) (ok bool) {
|
|||||||
func numAsFloat(v any) (f float64) {
|
func numAsFloat(v any) (f float64) {
|
||||||
var ok bool
|
var ok bool
|
||||||
if f, ok = v.(float64); !ok {
|
if f, ok = v.(float64); !ok {
|
||||||
if fract, ok := v.(*fraction); ok {
|
|
||||||
f = fract.toFloat()
|
|
||||||
} else {
|
|
||||||
i, _ := v.(int64)
|
i, _ := v.(int64)
|
||||||
f = float64(i)
|
f = float64(i)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user