Compare commits
	
		
			No commits in common. "5809de419f19cc98824f480e0b43f21be63739e8" and "c0c2ab8b4ea1aa1c6d43c8112b9775f487087b6f" have entirely different histories.
		
	
	
		
			5809de419f
			...
			c0c2ab8b4e
		
	
		
| @ -5,10 +5,9 @@ | ||||
| package expr | ||||
| 
 | ||||
| const ( | ||||
| 	typeBoolean  = "boolean" | ||||
| 	typeFloat    = "decimal" | ||||
| 	typeFraction = "fraction" | ||||
| 	typeInt      = "integer" | ||||
| 	typeNumber   = "number" | ||||
| 	typeString   = "string" | ||||
| 	typeBoolean = "boolean" | ||||
| 	typeFloat   = "decimal" | ||||
| 	typeInt     = "integer" | ||||
| 	typeNumber  = "number" | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										87
									
								
								func-math.go
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								func-math.go
									
									
									
									
									
								
							| @ -10,17 +10,16 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| 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) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| 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 intSum int64 = 0 | ||||
| 	var fractSum *fraction | ||||
| 	var v any | ||||
| 
 | ||||
| 	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 { | ||||
| 				break | ||||
| 			} | ||||
| 			if array, ok := v.(*ListType); ok { | ||||
| 				if v, err = doAdd(ctx, name, NewFlatArrayIterator(*array)); err != nil { | ||||
| 			if array, ok := v.([]any); ok { | ||||
| 				if v, err = doAdd(ctx, name, NewFlatArrayIterator(array)); err != nil { | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !sumAsFloat { | ||||
| 			if isFloat(v) { | ||||
| 				sumAsFloat = true | ||||
| 				if sumAsFract { | ||||
| 					floatSum = fractSum.toFloat() | ||||
| 				} else { | ||||
| 					floatSum = float64(intSum) | ||||
| 				} | ||||
| 			} else if !sumAsFract && isFraction(v) { | ||||
| 				fractSum = newFraction(intSum, 1) | ||||
| 				sumAsFract = true | ||||
| 			} | ||||
| 		if !sumAsFloat && isFloat(v) { | ||||
| 			sumAsFloat = true | ||||
| 			floatSum = float64(intSum) | ||||
| 		} | ||||
| 
 | ||||
| 		if sumAsFloat { | ||||
| 			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 { | ||||
| 			iv, _ := v.(int64) | ||||
| 			intSum += iv | ||||
| @ -77,8 +58,6 @@ func doAdd(ctx ExprContext, name string, it Iterator) (result any, err error) { | ||||
| 		err = nil | ||||
| 		if sumAsFloat { | ||||
| 			result = floatSum | ||||
| 		} else if sumAsFract { | ||||
| 			result = fractSum | ||||
| 		} else { | ||||
| 			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) { | ||||
| 	var mulAsFloat, mulAsFract bool | ||||
| 	var mulAsFloat = false | ||||
| 	var floatProd float64 = 1.0 | ||||
| 	var intProd int64 = 1 | ||||
| 	var fractProd *fraction | ||||
| 	var v any | ||||
| 
 | ||||
| 	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 { | ||||
| 				break | ||||
| 			} | ||||
| 		if err = checkNumberParamExpected(name, v, it.Index()); err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 			if array, ok := v.(*ListType); ok { | ||||
| 				if v, err = doMul(ctx, name, NewFlatArrayIterator(*array)); err != nil { | ||||
| 					break | ||||
| 				} | ||||
| 		if array, ok := v.([]any); ok { | ||||
| 			if v, err = doMul(ctx, name, NewFlatArrayIterator(array)); err != nil { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if !mulAsFloat { | ||||
| 			if isFloat(v) { | ||||
| 				mulAsFloat = true | ||||
| 				if mulAsFract { | ||||
| 					floatProd = fractProd.toFloat() | ||||
| 				} else { | ||||
| 					floatProd = float64(intProd) | ||||
| 				} | ||||
| 			} else if !mulAsFract && isFraction(v) { | ||||
| 				fractProd = newFraction(intProd, 1) | ||||
| 				mulAsFract = true | ||||
| 			} | ||||
| 		if !mulAsFloat && isFloat(v) { | ||||
| 			mulAsFloat = true | ||||
| 			floatProd = float64(intProd) | ||||
| 		} | ||||
| 
 | ||||
| 		if mulAsFloat { | ||||
| 			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 { | ||||
| 			iv, _ := v.(int64) | ||||
| 			intProd *= iv | ||||
| @ -153,8 +102,6 @@ func doMul(ctx ExprContext, name string, it Iterator) (result any, err error) { | ||||
| 		err = nil | ||||
| 		if mulAsFloat { | ||||
| 			result = floatProd | ||||
| 		} else if mulAsFract { | ||||
| 			result = fractProd | ||||
| 		} else { | ||||
| 			result = intProd | ||||
| 		} | ||||
|  | ||||
| @ -7,11 +7,11 @@ package expr | ||||
| import "io" | ||||
| 
 | ||||
| type FlatArrayIterator struct { | ||||
| 	a     ListType | ||||
| 	a     []any | ||||
| 	index int | ||||
| } | ||||
| 
 | ||||
| func NewFlatArrayIterator(array ListType) *FlatArrayIterator { | ||||
| func NewFlatArrayIterator(array []any) *FlatArrayIterator { | ||||
| 	return &FlatArrayIterator{a: array, index: 0} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -4,44 +4,6 @@ | ||||
| // operand-list.go
 | ||||
| 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
 | ||||
| func newListTermA(args ...*term) *term { | ||||
| 	return newListTerm(args) | ||||
| @ -61,7 +23,7 @@ func newListTerm(args []*term) *term { | ||||
| // -------- list func
 | ||||
| func evalList(ctx ExprContext, self *term) (v any, err error) { | ||||
| 	list, _ := self.value().([]*term) | ||||
| 	items := make(ListType, len(list)) | ||||
| 	items := make([]any, len(list)) | ||||
| 	for i, tree := range list { | ||||
| 		var param any | ||||
| 		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 | ||||
| 	} | ||||
| 	if err == nil { | ||||
| 		v = &items | ||||
| 		v = items | ||||
| 	} | ||||
| 	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) | ||||
| 			v = leftInt * rightInt | ||||
| 		} | ||||
| 	} else if isFraction(leftValue) || isFraction(rightValue) { | ||||
| 		v, err = mulAnyFract(leftValue, rightValue) | ||||
| 	} else { | ||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||
| 	} | ||||
| @ -87,8 +85,6 @@ func evalDivide(ctx ExprContext, self *term) (v any, err error) { | ||||
| 				v = leftInt / rightInt | ||||
| 			} | ||||
| 		} | ||||
| 	} else if isFraction(leftValue) || isFraction(rightValue) { | ||||
| 		v, err = divAnyFract(leftValue, rightValue) | ||||
| 	} else { | ||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||
| 	} | ||||
|  | ||||
| @ -39,24 +39,22 @@ func evalPlus(ctx ExprContext, self *term) (v any, err error) { | ||||
| 			v = leftInt + rightInt | ||||
| 		} | ||||
| 	} else if isList(leftValue) || isList(rightValue) { | ||||
| 		var leftList, rightList *ListType | ||||
| 		var leftList, rightList []any | ||||
| 		var ok bool | ||||
| 		if leftList, ok = leftValue.(*ListType); !ok { | ||||
| 			leftList = &ListType{leftValue} | ||||
| 		if leftList, ok = leftValue.([]any); !ok { | ||||
| 			leftList = []any{leftValue} | ||||
| 		} | ||||
| 		if rightList, ok = rightValue.(*ListType); !ok { | ||||
| 			rightList = &ListType{rightValue} | ||||
| 		if rightList, ok = rightValue.([]any); !ok { | ||||
| 			rightList = []any{rightValue} | ||||
| 		} | ||||
| 		sumList := make(ListType, 0, len(*leftList)+len(*rightList)) | ||||
| 		for _, item := range *leftList { | ||||
| 		sumList := make([]any, 0, len(leftList)+len(rightList)) | ||||
| 		for _, item := range leftList { | ||||
| 			sumList = append(sumList, item) | ||||
| 		} | ||||
| 		for _, item := range *rightList { | ||||
| 		for _, item := range rightList { | ||||
| 			sumList = append(sumList, item) | ||||
| 		} | ||||
| 		v = &sumList | ||||
| 	} else if isFraction(leftValue) || isFraction(rightValue) { | ||||
| 		v, err = sumAnyFract(leftValue, rightValue) | ||||
| 		v = sumList | ||||
| 	} else { | ||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||
| 	} | ||||
| @ -91,17 +89,15 @@ func evalMinus(ctx ExprContext, self *term) (v any, err error) { | ||||
| 			v = leftInt - rightInt | ||||
| 		} | ||||
| 	} else if isList(leftValue) && isList(rightValue) { | ||||
| 		leftList, _ := leftValue.(*ListType) | ||||
| 		rightList, _ := rightValue.(*ListType) | ||||
| 		diffList := make(ListType, 0, len(*leftList)-len(*rightList)) | ||||
| 		for _, item := range *leftList { | ||||
| 			if slices.Index(*rightList, item) < 0 { | ||||
| 		leftList, _ := leftValue.([]any) | ||||
| 		rightList, _ := rightValue.([]any) | ||||
| 		diffList := make([]any, 0, len(leftList)-len(rightList)) | ||||
| 		for _, item := range leftList { | ||||
| 			if slices.Index(rightList, item) < 0 { | ||||
| 				diffList = append(diffList, item) | ||||
| 			} | ||||
| 		} | ||||
| 		v = &diffList | ||||
| 	} else if isFraction(leftValue) || isFraction(rightValue) { | ||||
| 		v, err = subAnyFract(leftValue, rightValue) | ||||
| 		v = diffList | ||||
| 	} else { | ||||
| 		err = self.errIncompatibleTypes(leftValue, rightValue) | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										1
									
								
								term.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								term.go
									
									
									
									
									
								
							| @ -20,7 +20,6 @@ const ( | ||||
| 	priRelational | ||||
| 	priSum | ||||
| 	priProduct | ||||
| 	priFraction | ||||
| 	priSelector | ||||
| 	priSign | ||||
| 	priFact | ||||
|  | ||||
							
								
								
									
										10
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								utils.go
									
									
									
									
									
								
							| @ -25,7 +25,7 @@ func isFloat(v any) (ok bool) { | ||||
| } | ||||
| 
 | ||||
| func isList(v any) (ok bool) { | ||||
| 	_, ok = v.(*ListType) | ||||
| 	_, ok = v.([]any) | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| @ -55,12 +55,8 @@ func isIterator(v any) (ok bool) { | ||||
| func numAsFloat(v any) (f float64) { | ||||
| 	var ok bool | ||||
| 	if f, ok = v.(float64); !ok { | ||||
| 		if fract, ok := v.(*fraction); ok { | ||||
| 			f = fract.toFloat() | ||||
| 		} else { | ||||
| 			i, _ := v.(int64) | ||||
| 			f = float64(i) | ||||
| 		} | ||||
| 		i, _ := v.(int64) | ||||
| 		f = float64(i) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user