refactored data-types to reduce plugin sizes
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// list-type.go
|
||||
package array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
type ListType []any
|
||||
|
||||
func IsList(v any) (ok bool) {
|
||||
_, ok = v.(*ListType)
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewListA(listAny ...any) (list *ListType) {
|
||||
if listAny == nil {
|
||||
listAny = []any{}
|
||||
}
|
||||
return NewList(listAny)
|
||||
}
|
||||
|
||||
func NewList(listAny []any) (list *ListType) {
|
||||
if listAny != nil {
|
||||
ls := make(ListType, len(listAny))
|
||||
copy(ls, listAny)
|
||||
list = &ls
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func MakeList(length, capacity int) (list *ListType) {
|
||||
if capacity < length {
|
||||
capacity = length
|
||||
}
|
||||
ls := make(ListType, length, capacity)
|
||||
list = &ls
|
||||
return
|
||||
}
|
||||
|
||||
func ListFromStrings(stringList []string) (list *ListType) {
|
||||
list = MakeList(len(stringList), 0)
|
||||
for i, s := range stringList {
|
||||
(*list)[i] = s
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) ToString(opt kern.FmtOpt) (s string) {
|
||||
indent := kern.GetFormatIndent(opt)
|
||||
flags := kern.GetFormatFlags(opt)
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteByte('[')
|
||||
if len(*ls) > 0 {
|
||||
innerOpt := kern.MakeFormatOptions(flags, indent+1)
|
||||
nest := strings.Repeat(" ", indent+1)
|
||||
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(nest)
|
||||
}
|
||||
for i, item := range []any(*ls) {
|
||||
if i > 0 {
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteString(",\n")
|
||||
sb.WriteString(nest)
|
||||
} else {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
kern.Format(&sb, item, innerOpt)
|
||||
}
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(strings.Repeat(" ", indent))
|
||||
}
|
||||
}
|
||||
sb.WriteByte(']')
|
||||
s = sb.String()
|
||||
if flags&kern.Truncate != 0 && len(s) > kern.TruncateSize {
|
||||
s = kern.TruncateString(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) String() string {
|
||||
return ls.ToString(0)
|
||||
}
|
||||
|
||||
func (ls *ListType) TypeName() string {
|
||||
return kern.TypeArray
|
||||
}
|
||||
|
||||
func (ls *ListType) Contains(t *ListType) (answer bool) {
|
||||
if len(*ls) >= len(*t) {
|
||||
answer = true
|
||||
for _, item := range *t {
|
||||
if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) EqualTo(other kern.Equaler) (equal bool) {
|
||||
if otherList, ok := other.(*ListType); ok {
|
||||
equal = ls.Equals(*otherList)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) Equals(ls2 ListType) (answer bool) {
|
||||
if ls2 != nil && len(*ls) == len(ls2) {
|
||||
answer = true
|
||||
for index, i1 := range *ls {
|
||||
// if !reflect.DeepEqual(i1, ls2[index]) {
|
||||
// answer = false
|
||||
// break
|
||||
// }
|
||||
if !kern.Equal(i1, ls2[index]) {
|
||||
answer = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls1 *ListType) Clone() (ls2 *ListType) {
|
||||
ls := make(ListType, len(*ls1))
|
||||
for i, item := range *ls1 {
|
||||
ls[i] = kern.Clone(item)
|
||||
}
|
||||
ls2 = &ls
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) IndexDeepSameCmp(target any) (index int) {
|
||||
index = -1
|
||||
for i, item := range *ls {
|
||||
if kern.Equal(item, target) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func (ls *ListType) IndexDeepSameCmp(target any) (index int) {
|
||||
// var eq bool
|
||||
// var err error
|
||||
// index = -1
|
||||
// for i, item := range *ls {
|
||||
// if eq, err = deepSame(item, target, SameContent); err != nil {
|
||||
// break
|
||||
// } else if eq {
|
||||
// index = i
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func SameContent(a, b any) (same bool, err error) {
|
||||
la, _ := a.(*ListType)
|
||||
lb, _ := b.(*ListType)
|
||||
if len(*la) == len(*lb) {
|
||||
same = true
|
||||
for _, item := range *la {
|
||||
if pos := lb.IndexDeepSameCmp(item); pos < 0 {
|
||||
same = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func deepSame(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) {
|
||||
// if IsNumOrFract(a) && IsNumOrFract(b) {
|
||||
// if IsNumber(a) && IsNumber(b) {
|
||||
// if IsInteger(a) && IsInteger(b) {
|
||||
// li, _ := a.(int64)
|
||||
// ri, _ := b.(int64)
|
||||
// eq = li == ri
|
||||
// } else {
|
||||
// eq = NumAsFloat(a) == NumAsFloat(b)
|
||||
// }
|
||||
// } else {
|
||||
// var cmp int
|
||||
// if cmp, err = fract.CmpAnyFract(a, b); err == nil {
|
||||
// eq = cmp == 0
|
||||
// }
|
||||
// }
|
||||
// } else if deepCmp != nil && IsList(a) && IsList(b) {
|
||||
// eq, err = deepCmp(a, b)
|
||||
// } else {
|
||||
// eq = reflect.DeepEqual(a, b)
|
||||
// }
|
||||
|
||||
// return
|
||||
// }
|
||||
|
||||
func (ls *ListType) SetItem(index int64, value any) (err error) {
|
||||
if index >= 0 && index < int64(len(*ls)) {
|
||||
(*ls)[index] = value
|
||||
} else {
|
||||
err = fmt.Errorf("index %d out of bounds (0, %d)", index, len(*ls)-1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *ListType) AppendItem(value any) {
|
||||
*ls = append(*ls, value)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// bool.go
|
||||
package boolean
|
||||
|
||||
func IsBool(v any) (ok bool) {
|
||||
_, ok = v.(bool)
|
||||
return ok
|
||||
}
|
||||
|
||||
// func (b *bool) EqualTo(other kern.Equaler) (equal bool) {
|
||||
// if otherBool, ok := other.(*bool); ok {
|
||||
// equal = b == otherBool
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func ToBool(v any) (b bool, ok bool) {
|
||||
ok = true
|
||||
switch x := v.(type) {
|
||||
case string:
|
||||
b = len(x) > 0
|
||||
case float64:
|
||||
b = x != 0.0
|
||||
case int64:
|
||||
b = x != 0
|
||||
case bool:
|
||||
b = x
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// clone-value.go
|
||||
package types
|
||||
|
||||
// import (
|
||||
// "git.portale-stac.it/go-pkg/expr/types/array"
|
||||
// "git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
// "git.portale-stac.it/go-pkg/expr/types/list"
|
||||
// )
|
||||
|
||||
// func Clone(v any) (c any) {
|
||||
// if v == nil {
|
||||
// return
|
||||
// }
|
||||
// switch unboxed := v.(type) {
|
||||
// case int64:
|
||||
// c = unboxed
|
||||
// case float64:
|
||||
// c = unboxed
|
||||
// case string:
|
||||
// c = unboxed
|
||||
// case bool:
|
||||
// c = unboxed
|
||||
// case *array.ListType:
|
||||
// c = unboxed.Clone()
|
||||
// case *dict.DictType:
|
||||
// c = unboxed.Clone()
|
||||
// case *list.LinkedList:
|
||||
// c = unboxed.Clone()
|
||||
// default:
|
||||
// c = v
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// compare.go
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/types/array"
|
||||
"git.portale-stac.it/go-pkg/expr/types/boolean"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||
"git.portale-stac.it/go-pkg/expr/types/list"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
)
|
||||
|
||||
func Equal(value1, value2 any) (equal bool) {
|
||||
if value1 == nil && value2 == nil {
|
||||
equal = true
|
||||
} else if value1 == nil || value2 == nil {
|
||||
equal = false
|
||||
} else if boolean.IsBool(value1) && boolean.IsBool(value2) {
|
||||
equal = value1.(bool) == value2.(bool)
|
||||
} else if array.IsList(value1) && array.IsList(value2) {
|
||||
ls1 := value1.(*array.ListType)
|
||||
ls2 := value2.(*array.ListType)
|
||||
equal = ls1.Equals(*ls2)
|
||||
} else if dict.IsDict(value1) && dict.IsDict(value2) {
|
||||
d1 := value1.(*dict.DictType)
|
||||
d2 := value2.(*dict.DictType)
|
||||
equal = d1.Equals(*d2)
|
||||
} else if list.IsLinkedList(value1) && list.IsLinkedList(value2) {
|
||||
ll1 := value1.(*list.LinkedList)
|
||||
ll2 := value2.(*list.LinkedList)
|
||||
equal = ll1.Equals(ll2)
|
||||
} else if IsInteger(value1) && IsInteger(value2) {
|
||||
equal = value1.(int64) == value2.(int64)
|
||||
} else if str.IsString(value1) && str.IsString(value2) {
|
||||
equal = value1.(string) == value2.(string)
|
||||
} else if float.IsFloat(value1) && float.IsFloat(value2) {
|
||||
equal = value1.(float64) == value2.(float64)
|
||||
} else if IsNumOrFract(value1) && IsNumOrFract(value2) {
|
||||
if eq, err := fract.CmpAnyFract(value1, value2); err == nil {
|
||||
equal = eq == 0
|
||||
}
|
||||
} else if !reflect.DeepEqual(value1, value2) {
|
||||
equal = false
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// dict-type.go
|
||||
package dict
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
const DictTypeName = "dict"
|
||||
|
||||
type DictType map[any]any
|
||||
|
||||
func IsDict(v any) (ok bool) {
|
||||
_, ok = v.(*DictType)
|
||||
return ok
|
||||
}
|
||||
|
||||
func MakeDict() (dict *DictType) {
|
||||
d := make(DictType)
|
||||
dict = &d
|
||||
return
|
||||
}
|
||||
|
||||
func NewDict(dictAny map[any]any) (dict *DictType) {
|
||||
var d DictType
|
||||
if dictAny != nil {
|
||||
d = make(DictType, len(dictAny))
|
||||
for i, item := range dictAny {
|
||||
d[i] = item
|
||||
}
|
||||
} else {
|
||||
d = make(DictType)
|
||||
}
|
||||
dict = &d
|
||||
return
|
||||
}
|
||||
|
||||
func newDict(dictAny map[any]kern.Term) (dict *DictType) {
|
||||
// TODO Change with a call to NewDict()
|
||||
var d DictType
|
||||
if dictAny != nil {
|
||||
d = make(DictType, len(dictAny))
|
||||
for i, item := range dictAny {
|
||||
d[i] = item
|
||||
}
|
||||
} else {
|
||||
d = make(DictType)
|
||||
}
|
||||
dict = &d
|
||||
return
|
||||
}
|
||||
|
||||
func (dict *DictType) toMultiLine(sb *strings.Builder, opt kern.FmtOpt) {
|
||||
indent := kern.GetFormatIndent(opt)
|
||||
flags := kern.GetFormatFlags(opt)
|
||||
//sb.WriteString(strings.Repeat(" ", indent))
|
||||
sb.WriteByte('{')
|
||||
|
||||
if len(*dict) > 0 {
|
||||
innerOpt := kern.MakeFormatOptions(flags, indent+1)
|
||||
nest := strings.Repeat(" ", indent+1)
|
||||
sb.WriteByte('\n')
|
||||
|
||||
first := true
|
||||
for name, value := range *dict {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteByte(',')
|
||||
sb.WriteByte('\n')
|
||||
}
|
||||
|
||||
sb.WriteString(nest)
|
||||
if key, ok := name.(string); ok {
|
||||
sb.WriteByte('"')
|
||||
sb.WriteString(key)
|
||||
sb.WriteByte('"')
|
||||
} else {
|
||||
fmt.Fprintf(sb, "%v", name)
|
||||
}
|
||||
sb.WriteString(": ")
|
||||
if f, ok := value.(kern.Formatter); ok {
|
||||
sb.WriteString(f.ToString(innerOpt))
|
||||
} else if _, ok = value.(kern.Functor); ok {
|
||||
sb.WriteString("func(){}")
|
||||
} else {
|
||||
fmt.Fprintf(sb, "%v", value)
|
||||
}
|
||||
}
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(strings.Repeat(" ", indent))
|
||||
}
|
||||
sb.WriteString("}")
|
||||
}
|
||||
|
||||
func (dict *DictType) ToString(opt kern.FmtOpt) string {
|
||||
var sb strings.Builder
|
||||
flags := kern.GetFormatFlags(opt)
|
||||
if flags&kern.MultiLine != 0 {
|
||||
dict.toMultiLine(&sb, opt)
|
||||
} else {
|
||||
sb.WriteByte('{')
|
||||
first := true
|
||||
for key, value := range *dict {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
if s, ok := key.(string); ok {
|
||||
sb.WriteByte('"')
|
||||
sb.WriteString(s)
|
||||
sb.WriteByte('"')
|
||||
} else {
|
||||
fmt.Fprintf(&sb, "%v", key)
|
||||
}
|
||||
sb.WriteString(": ")
|
||||
if formatter, ok := value.(kern.Formatter); ok {
|
||||
sb.WriteString(formatter.ToString(opt))
|
||||
} else if t, ok := value.(kern.Term); ok {
|
||||
sb.WriteString(t.String())
|
||||
} else {
|
||||
fmt.Fprintf(&sb, "%#v", value)
|
||||
}
|
||||
}
|
||||
sb.WriteByte('}')
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (dict *DictType) String() string {
|
||||
return dict.ToString(0)
|
||||
}
|
||||
|
||||
func (dict *DictType) TypeName() string {
|
||||
return DictTypeName
|
||||
}
|
||||
|
||||
func (dict *DictType) HasKey(target any) (ok bool) {
|
||||
for key := range *dict {
|
||||
if ok = reflect.DeepEqual(key, target); ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dict *DictType) SetItem(key any, value any) {
|
||||
(*dict)[key] = value
|
||||
}
|
||||
|
||||
func (dict *DictType) GetItem(key any) (value any, exists bool) {
|
||||
value, exists = (*dict)[key]
|
||||
return
|
||||
}
|
||||
|
||||
func (dict *DictType) Clone() (c *DictType) {
|
||||
c = newDict(nil)
|
||||
for k, v := range *dict {
|
||||
(*c)[k] = kern.Clone(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dict *DictType) Merge(second *DictType) {
|
||||
if second != nil {
|
||||
for k, v := range *second {
|
||||
(*dict)[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dict *DictType) Equals(dict2 DictType) (answer bool) {
|
||||
if dict2 != nil && len(*dict) == len(dict2) {
|
||||
answer = true
|
||||
for key, value1 := range *dict {
|
||||
if value2, exists := dict2.GetItem(key); exists {
|
||||
if !kern.Equal(value1, value2) {
|
||||
answer = false
|
||||
break
|
||||
}
|
||||
} else {
|
||||
answer = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
////////////////
|
||||
|
||||
// type DictFormat interface {
|
||||
// ToDict() *DictType
|
||||
// }
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// float.go
|
||||
package float
|
||||
|
||||
func IsFloat(v any) (ok bool) {
|
||||
_, ok = v.(float64)
|
||||
return ok
|
||||
}
|
||||
|
||||
func AnyFloat(v any) (float float64, ok bool) {
|
||||
ok = true
|
||||
switch floatval := v.(type) {
|
||||
case float32:
|
||||
float = float64(floatval)
|
||||
case float64:
|
||||
float = floatval
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// fraction-type.go
|
||||
package fract
|
||||
|
||||
//https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
type FractionType struct {
|
||||
num, den int64
|
||||
}
|
||||
|
||||
func NewFraction(num, den int64) *FractionType {
|
||||
num, den = simplifyIntegers(num, den)
|
||||
return &FractionType{num, den}
|
||||
}
|
||||
|
||||
func (fr *FractionType) EqualTo(other kern.Equaler) (equal bool) {
|
||||
if otherFract, ok := other.(*FractionType); ok && otherFract != nil {
|
||||
equal = fr.Equals(*otherFract)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (fr *FractionType) Equals(other FractionType) bool {
|
||||
// return fr.num*other.den == other.num*fr.den
|
||||
return fr.num == other.num && fr.den == other.den
|
||||
}
|
||||
|
||||
func Float64ToFraction(f float64) (fract *FractionType, err error) {
|
||||
var sign string
|
||||
intPart, decPart := math.Modf(f)
|
||||
if decPart < 0.0 {
|
||||
sign = "-"
|
||||
intPart = -intPart
|
||||
decPart = -decPart
|
||||
}
|
||||
dec := fmt.Sprintf("%.12f", decPart)
|
||||
s := fmt.Sprintf("%s%.f%s", sign, intPart, dec[1:])
|
||||
return MakeGeneratingFraction(s)
|
||||
}
|
||||
|
||||
// Based on https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/math/big/rat.go;l=39
|
||||
func MakeGeneratingFraction(s string) (f *FractionType, err error) {
|
||||
var num, den int64
|
||||
var sign int64 = 1
|
||||
var parts []string
|
||||
if len(s) == 0 {
|
||||
goto exit
|
||||
}
|
||||
switch s[0] {
|
||||
case '-':
|
||||
sign = int64(-1)
|
||||
s = s[1:]
|
||||
case '+':
|
||||
s = s[1:]
|
||||
}
|
||||
// if strings.HasSuffix(s, "()") {
|
||||
// s = s[0 : len(s)-2]
|
||||
// }
|
||||
s = strings.TrimSuffix(s, "()")
|
||||
parts = strings.SplitN(s, ".", 2)
|
||||
if num, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
|
||||
return
|
||||
}
|
||||
if len(parts) == 1 {
|
||||
f = NewFraction(sign*num, 1)
|
||||
} else if len(parts) == 2 {
|
||||
subParts := strings.SplitN(parts[1], "(", 2)
|
||||
if len(subParts) == 1 {
|
||||
den = 1
|
||||
dec := parts[1]
|
||||
lsd := len(dec)
|
||||
for i := lsd - 1; i >= 0 && dec[i] == '0'; i-- {
|
||||
lsd--
|
||||
}
|
||||
for _, c := range dec[0:lsd] {
|
||||
if c < '0' || c > '9' {
|
||||
return nil, kern.ErrExpectedGot("fract", "digit", c)
|
||||
}
|
||||
num = num*10 + int64(c-'0')
|
||||
den = den * 10
|
||||
}
|
||||
f = NewFraction(sign*num, den)
|
||||
} else if len(subParts) == 2 {
|
||||
sub := num
|
||||
mul := int64(1)
|
||||
for _, c := range subParts[0] {
|
||||
if c < '0' || c > '9' {
|
||||
return nil, kern.ErrExpectedGot("fract", "digit", c)
|
||||
}
|
||||
num = num*10 + int64(c-'0')
|
||||
sub = sub*10 + int64(c-'0')
|
||||
mul *= 10
|
||||
}
|
||||
if len(subParts) == 2 {
|
||||
if s[len(s)-1] != ')' {
|
||||
goto exit
|
||||
}
|
||||
p := subParts[1][0 : len(subParts[1])-1]
|
||||
for _, c := range p {
|
||||
if c < '0' || c > '9' {
|
||||
return nil, kern.ErrExpectedGot("fract", "digit", c)
|
||||
}
|
||||
num = num*10 + int64(c-'0')
|
||||
den = den*10 + 9
|
||||
}
|
||||
den *= mul
|
||||
}
|
||||
num -= sub
|
||||
f = NewFraction(sign*num, den)
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if f == nil {
|
||||
err = errors.New("bad syntax")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (fr *FractionType) N() int64 {
|
||||
return fr.num
|
||||
}
|
||||
|
||||
func (fr *FractionType) D() int64 {
|
||||
return fr.den
|
||||
}
|
||||
|
||||
func (fr *FractionType) ToFloat() float64 {
|
||||
return float64(fr.num) / float64(fr.den)
|
||||
}
|
||||
|
||||
func (fr *FractionType) String() string {
|
||||
return fr.ToString(0)
|
||||
}
|
||||
|
||||
func (fr *FractionType) ToString(opt kern.FmtOpt) string {
|
||||
var sb strings.Builder
|
||||
if opt&kern.MultiLine == 0 {
|
||||
sb.WriteString(fmt.Sprintf("%d:%d", fr.num, fr.den))
|
||||
} else {
|
||||
var sign, num string
|
||||
if fr.num < 0 && opt&kern.TTY == 0 {
|
||||
num = strconv.FormatInt(-fr.num, 10)
|
||||
sign = "-"
|
||||
} else {
|
||||
num = strconv.FormatInt(fr.num, 10)
|
||||
}
|
||||
den := strconv.FormatInt(fr.den, 10)
|
||||
size := max(len(num), len(den))
|
||||
if opt&kern.TTY != 0 {
|
||||
sNum := fmt.Sprintf("\x1b[4m%[1]*s\x1b[0m\n", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, sign+num))
|
||||
sb.WriteString(sNum)
|
||||
} else {
|
||||
if len(sign) > 0 {
|
||||
sb.WriteString(" ")
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%[1]*s", -size, fmt.Sprintf("%[1]*s", (size+len(num))/2, num)))
|
||||
sb.WriteByte('\n')
|
||||
if len(sign) > 0 {
|
||||
sb.WriteString(sign)
|
||||
sb.WriteByte(' ')
|
||||
}
|
||||
sb.WriteString(strings.Repeat("-", size))
|
||||
sb.WriteByte('\n')
|
||||
if len(sign) > 0 {
|
||||
sb.WriteString(" ")
|
||||
}
|
||||
}
|
||||
sDen := fmt.Sprintf("%[1]*s", size, fmt.Sprintf("%[1]*s", (size+len(den))/2, den))
|
||||
sb.WriteString(sDen)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (fr *FractionType) TypeName() string {
|
||||
return "fraction"
|
||||
}
|
||||
|
||||
// -------- fraction utility functions
|
||||
|
||||
// greatest common divider
|
||||
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
|
||||
}
|
||||
|
||||
// lower common multiple
|
||||
func lcm(a, b int64) (l int64) {
|
||||
g := Gcd(a, b)
|
||||
l = a * b / g
|
||||
return
|
||||
}
|
||||
|
||||
// Sum two fractions
|
||||
func SumFract(f1, f2 *FractionType) (sum *FractionType) {
|
||||
m := lcm(f1.den, f2.den)
|
||||
sum = NewFraction(f1.num*(m/f1.den)+f2.num*(m/f2.den), m)
|
||||
return
|
||||
}
|
||||
|
||||
// Multiply two fractions
|
||||
func MulFract(f1, f2 *FractionType) (prod *FractionType) {
|
||||
prod = NewFraction(f1.num*f2.num, f1.den*f2.den)
|
||||
return
|
||||
}
|
||||
|
||||
func anyToFract(v any) (f *FractionType, err error) {
|
||||
var ok bool
|
||||
if f, ok = v.(*FractionType); !ok {
|
||||
if n, ok := v.(int64); ok {
|
||||
f = intToFraction(n)
|
||||
} else if dec, ok := v.(float64); ok {
|
||||
f, err = Float64ToFraction(dec)
|
||||
} else {
|
||||
err = kern.ErrExpectedGot("fract", kern.TypeFraction, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func anyPairToFract(v1, v2 any) (f1, f2 *FractionType, 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 *FractionType
|
||||
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
|
||||
}
|
||||
|
||||
// Returns
|
||||
//
|
||||
// <0 if af1 < af2
|
||||
// =0 if af1 == af2
|
||||
// >0 if af1 > af2
|
||||
// err if af1 or af2 is not convertible to fraction
|
||||
func CmpAnyFract(af1, af2 any) (result int, err error) {
|
||||
var f1, f2 *FractionType
|
||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
||||
return
|
||||
}
|
||||
result = cmpFract(f1, f2)
|
||||
return
|
||||
}
|
||||
|
||||
// Returns
|
||||
//
|
||||
// <0 if af1 < af2
|
||||
// =0 if af1 == af2
|
||||
// >0 if af1 > af2
|
||||
func cmpFract(f1, f2 *FractionType) (result int) {
|
||||
if f1 != nil && f2 != nil {
|
||||
f2.num = -f2.num
|
||||
f := SumFract(f1, f2)
|
||||
if f.num < 0 {
|
||||
result = -1
|
||||
} else if f.num > 0 {
|
||||
result = 1
|
||||
} else {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SubAnyFract(af1, af2 any) (sum any, err error) {
|
||||
var f1, f2 *FractionType
|
||||
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 *FractionType
|
||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
||||
return
|
||||
}
|
||||
if f1.num == 0 || f2.num == 0 {
|
||||
prod = 0
|
||||
} else {
|
||||
f := &FractionType{f1.num * f2.num, f1.den * f2.den}
|
||||
prod = simplifyFraction(f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DivAnyFract(af1, af2 any) (quot any, err error) {
|
||||
var f1, f2 *FractionType
|
||||
if f1, f2, err = anyPairToFract(af1, af2); err != nil {
|
||||
return
|
||||
}
|
||||
if f2.num == 0 {
|
||||
err = errors.New("division by zero")
|
||||
return
|
||||
}
|
||||
if f1.num == 0 || f2.den == 0 {
|
||||
quot = 0
|
||||
} else {
|
||||
f := &FractionType{f1.num * f2.den, f1.den * f2.num}
|
||||
quot = simplifyFraction(f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func simplifyFraction(f *FractionType) (v any) {
|
||||
f.num, f.den = simplifyIntegers(f.num, f.den)
|
||||
if f.den == 1 {
|
||||
v = f.num
|
||||
} else {
|
||||
v = &FractionType{f.num, f.den}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func simplifyIntegers(num, den int64) (a, b int64) {
|
||||
if num == 0 {
|
||||
return 0, 1
|
||||
}
|
||||
if den == 0 {
|
||||
panic("fraction with denominator == 0")
|
||||
}
|
||||
if den < 0 {
|
||||
den = -den
|
||||
num = -num
|
||||
}
|
||||
g := Gcd(num, den)
|
||||
a = num / g
|
||||
b = den / g
|
||||
return
|
||||
}
|
||||
|
||||
func intToFraction(n int64) *FractionType {
|
||||
return &FractionType{n, 1}
|
||||
}
|
||||
|
||||
func IsFraction(v any) (ok bool) {
|
||||
_, ok = v.(*FractionType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// func IsFract(v any) (ok bool) {
|
||||
// _, ok = v.(*FractionType)
|
||||
// return ok
|
||||
// }
|
||||
|
||||
func IsRational(v any) (ok bool) {
|
||||
if _, ok = v.(*FractionType); !ok {
|
||||
_, ok = v.(int64)
|
||||
}
|
||||
return ok
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// linked-list-type.go
|
||||
package list
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
const LinkedListTypeName = "lisked-list"
|
||||
|
||||
func IsLinkedList(v any) (ok bool) {
|
||||
_, ok = v.(*LinkedList)
|
||||
return ok
|
||||
}
|
||||
|
||||
func NewLinkedListA(listAny ...any) (list *LinkedList) {
|
||||
if listAny == nil {
|
||||
listAny = []any{}
|
||||
}
|
||||
list = NewLinkedList()
|
||||
for _, item := range listAny {
|
||||
list.PushBack(kern.FixAnyNumber(item))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LinkedListFromStrings(stringList []string) (list *LinkedList) {
|
||||
list = NewLinkedList()
|
||||
for _, s := range stringList {
|
||||
list.PushBack(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) ToString(opt kern.FmtOpt) (s string) {
|
||||
indent := kern.GetFormatIndent(opt)
|
||||
flags := kern.GetFormatFlags(opt)
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[<")
|
||||
if ls.Len() > 0 {
|
||||
innerOpt := kern.MakeFormatOptions(flags, indent+1)
|
||||
nest := strings.Repeat(" ", indent+1)
|
||||
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(nest)
|
||||
}
|
||||
|
||||
i := 0
|
||||
for item := ls.FirstNode(); item != nil; item = item.Next() {
|
||||
if i > 0 {
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteString(",\n")
|
||||
sb.WriteString(nest)
|
||||
} else {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
|
||||
kern.Format(&sb, item.Data(), innerOpt)
|
||||
i++
|
||||
}
|
||||
if flags&kern.MultiLine != 0 {
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(strings.Repeat(" ", indent))
|
||||
}
|
||||
}
|
||||
sb.WriteString(">]")
|
||||
s = sb.String()
|
||||
if flags&kern.Truncate != 0 && len(s) > kern.TruncateSize {
|
||||
s = kern.TruncateString(s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) String() string {
|
||||
return ls.ToString(0)
|
||||
}
|
||||
|
||||
func (ls *LinkedList) TypeName() string {
|
||||
return LinkedListTypeName
|
||||
}
|
||||
|
||||
// func (ls *LinkedList) Contains(t *ListType) (answer bool) {
|
||||
// if len(*ls) >= len(*t) {
|
||||
// answer = true
|
||||
// for _, item := range *t {
|
||||
// if answer = ls.IndexDeepSameCmp(item) >= 0; !answer {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func (ls1 *LinkedList) Equals(ls2 *LinkedList) (answer bool) {
|
||||
if ls2 != nil && ls1.Len() == ls2.Len() {
|
||||
answer = true
|
||||
i2 := ls2.FirstNode()
|
||||
for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
|
||||
if !kern.Equal(i1.Data(), i2.Data()) {
|
||||
answer = false
|
||||
break
|
||||
}
|
||||
i2 = i2.Next()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls1 *LinkedList) Clone() (ls2 *LinkedList) {
|
||||
ls2 = NewLinkedListA()
|
||||
for i1 := ls1.FirstNode(); i1 != nil; i1 = i1.Next() {
|
||||
ls2.PushBack(kern.Clone(i1.Data()))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// linked-list.go
|
||||
package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
type ListNode struct {
|
||||
data any
|
||||
next *ListNode
|
||||
}
|
||||
|
||||
func (node *ListNode) Next() *ListNode {
|
||||
return node.next
|
||||
}
|
||||
|
||||
func (self *ListNode) Data() any {
|
||||
return self.data
|
||||
}
|
||||
|
||||
type LinkedList struct {
|
||||
count int
|
||||
first *ListNode
|
||||
last *ListNode
|
||||
}
|
||||
|
||||
func NewLinkedList() (list *LinkedList) {
|
||||
list = &LinkedList{0, nil, nil}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Len() int {
|
||||
return ls.count
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Empty() bool {
|
||||
return ls.count == 0
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushFront(data any) *ListNode {
|
||||
ls.first = &ListNode{data, ls.first}
|
||||
if ls.last == nil {
|
||||
ls.last = ls.first
|
||||
}
|
||||
ls.count++
|
||||
return ls.first
|
||||
}
|
||||
|
||||
func (ls *LinkedList) SeqPushFront(data any) (result *LinkedList) {
|
||||
switch seq := data.(type) {
|
||||
case kern.Iterator:
|
||||
result = ls.IterPushFront(seq)
|
||||
default:
|
||||
ls.PushFront(data)
|
||||
result = ls
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) IterPushFront(it kern.Iterator) *LinkedList {
|
||||
for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() {
|
||||
ls.PushFront(item)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushBack(data any) (node *ListNode) {
|
||||
node = &ListNode{data, nil}
|
||||
if ls.last != nil {
|
||||
ls.last.next = node
|
||||
}
|
||||
ls.last = node
|
||||
if ls.first == nil {
|
||||
ls.first = node
|
||||
}
|
||||
ls.count++
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) SeqPushBack(data any) (result *LinkedList) {
|
||||
switch seq := data.(type) {
|
||||
case kern.Iterator:
|
||||
result = ls.IterPushBack(seq)
|
||||
default:
|
||||
ls.PushBack(data)
|
||||
result = ls
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) IterPushBack(it kern.Iterator) *LinkedList {
|
||||
for item, err1 := it.Next(); err1 == nil; item, err1 = it.Next() {
|
||||
ls.PushBack(item)
|
||||
}
|
||||
return ls
|
||||
}
|
||||
|
||||
func (ls *LinkedList) FirstNode() *ListNode {
|
||||
return ls.first
|
||||
}
|
||||
|
||||
func (ls *LinkedList) First() (data any, err error) {
|
||||
if ls.first != nil {
|
||||
data = ls.first.data
|
||||
} else {
|
||||
err = errorListEmpty()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) LastNode() *ListNode {
|
||||
return ls.last
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Last() (data interface{}, err error) {
|
||||
if ls.last != nil {
|
||||
data = ls.last.data
|
||||
} else {
|
||||
err = errorListEmpty()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) NodeAt(index int) (node *ListNode, err error) {
|
||||
if ls.count == 0 {
|
||||
err = errorListEmpty()
|
||||
} else if index > ls.count {
|
||||
err = errorOutOfRange()
|
||||
} else if index == ls.count-1 {
|
||||
node = ls.last
|
||||
} else {
|
||||
current := ls.first
|
||||
for range index {
|
||||
current = current.next
|
||||
}
|
||||
node = current
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) At(index int) (data interface{}, err error) {
|
||||
node, err := ls.NodeAt(index)
|
||||
if err == nil {
|
||||
data = node.data
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Insert(index int, data any) *ListNode {
|
||||
var prev *ListNode
|
||||
|
||||
prev = nil
|
||||
current := ls.first
|
||||
for pos := 0; current != nil && pos < index; pos++ {
|
||||
prev = current
|
||||
current = current.next
|
||||
}
|
||||
|
||||
node := &ListNode{data, current}
|
||||
|
||||
if prev != nil {
|
||||
prev.next = node
|
||||
}
|
||||
|
||||
if ls.first == current {
|
||||
ls.first = node
|
||||
}
|
||||
if node.next == nil {
|
||||
ls.last = node
|
||||
}
|
||||
ls.count++
|
||||
return node
|
||||
}
|
||||
|
||||
func (ls *LinkedList) PushBackStringArray(items []string) {
|
||||
for _, v := range items {
|
||||
ls.PushBack(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (ls *LinkedList) Sub(start, end int) (subList *LinkedList) {
|
||||
subList = NewLinkedList()
|
||||
if node, err := ls.NodeAt(start); err == nil {
|
||||
for i := start; i < end && node != nil; i++ {
|
||||
subList.PushBack(node.data)
|
||||
node = node.next
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// type TraverseOperator func(index int, elem interface{}, userData interface{}) (err error)
|
||||
|
||||
// func (self *LinkedList) Traverse(op TraverseOperator, user_data interface{}) (err error) {
|
||||
// index := int(0)
|
||||
// for current := self.first; current != nil; current = current.next {
|
||||
// err = op(index, current.data, user_data)
|
||||
// if err != nil {
|
||||
// break
|
||||
// }
|
||||
// index++
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// func (self *LinkedList) Traverse2(observer Observer, abortOnError bool) (err error) {
|
||||
// index := int(0)
|
||||
// for current := self.first; current != nil; current = current.next {
|
||||
// err = observer.Observe(current, index)
|
||||
// if err != nil && abortOnError {
|
||||
// break
|
||||
// }
|
||||
// index++
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
type EqualFunc func(current, target any) bool
|
||||
|
||||
func (ls *LinkedList) FindFirst(eqFunc EqualFunc, targetData any) (targetNode *ListNode) {
|
||||
for current := ls.first; current != nil && targetNode == nil; current = current.next {
|
||||
if eqFunc(current.data, targetData) {
|
||||
targetNode = current
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *LinkedList) FindNext(eqFunc EqualFunc, startNode *ListNode) (targetNode *ListNode) {
|
||||
if startNode != nil {
|
||||
for current := startNode.next; current != nil && targetNode == nil; current = current.next {
|
||||
if eqFunc(current.data, startNode.Data()) {
|
||||
targetNode = current
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// type DataFeeder func(user_data interface{}) interface{}
|
||||
// type NodeObserver func(node *ListNode, index int, userData interface{})
|
||||
|
||||
// func (self *LinkedList) FeedTail(feeder DataFeeder, feederUserData interface{}, observer NodeObserver, observerUserData interface{}) (count int) {
|
||||
// count = 0
|
||||
// for item := feeder(feederUserData); item != nil; item = feeder(feederUserData) {
|
||||
// // fmt.Println("Item", count, item)
|
||||
// node := self.PushBack(item)
|
||||
// if observer != nil {
|
||||
// observer(node, count, observerUserData)
|
||||
// }
|
||||
// count++
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// func (self *LinkedList) FeedTail2(feeder Feeder, observer Observer, abortOnError bool) (count int, err error) {
|
||||
// count = 0
|
||||
// // item := feeder.Next()
|
||||
// for item, err1 := feeder.Next(); item != nil; item, err1 = feeder.Next() {
|
||||
// if err1 != nil {
|
||||
// if err == nil {
|
||||
// err = err1
|
||||
// }
|
||||
// if abortOnError {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// // fmt.Println("Item", count, item)
|
||||
// node := self.PushBack(item)
|
||||
// if observer != nil {
|
||||
// observer.Observe(node, count)
|
||||
// }
|
||||
// count++
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func errorListEmpty() error {
|
||||
return fmt.Errorf("List is empty")
|
||||
}
|
||||
|
||||
func errorOutOfRange() error {
|
||||
return fmt.Errorf("Out of range")
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// number.go
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/types/float"
|
||||
"git.portale-stac.it/go-pkg/expr/types/fract"
|
||||
"git.portale-stac.it/go-pkg/expr/types/str"
|
||||
)
|
||||
|
||||
func IsInteger(v any) (ok bool) {
|
||||
_, ok = v.(int64)
|
||||
return ok
|
||||
}
|
||||
|
||||
func IsNumber(v any) (ok bool) {
|
||||
return float.IsFloat(v) || IsInteger(v)
|
||||
}
|
||||
|
||||
func IsNumOrFract(v any) (ok bool) {
|
||||
return float.IsFloat(v) || IsInteger(v) || fract.IsFraction(v)
|
||||
}
|
||||
|
||||
func IsNumberString(v any) (ok bool) {
|
||||
return str.IsString(v) || IsNumber(v)
|
||||
}
|
||||
|
||||
func NumAsFloat(v any) (f float64) {
|
||||
var ok bool
|
||||
if f, ok = v.(float64); !ok {
|
||||
if fract, ok := v.(*fract.FractionType); ok {
|
||||
f = fract.ToFloat()
|
||||
} else {
|
||||
i, _ := v.(int64)
|
||||
f = float64(i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AnyInteger(v any) (i int64, ok bool) {
|
||||
ok = true
|
||||
switch intval := v.(type) {
|
||||
case int:
|
||||
i = int64(intval)
|
||||
case uint8:
|
||||
i = int64(intval)
|
||||
case uint16:
|
||||
i = int64(intval)
|
||||
case uint64:
|
||||
i = int64(intval)
|
||||
case uint32:
|
||||
i = int64(intval)
|
||||
case int8:
|
||||
i = int64(intval)
|
||||
case int16:
|
||||
i = int64(intval)
|
||||
case int32:
|
||||
i = int64(intval)
|
||||
case int64:
|
||||
i = intval
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ToGoInt(value any, description string) (i int, err error) {
|
||||
if valueInt64, ok := value.(int64); ok {
|
||||
i = int(valueInt64)
|
||||
} else if valueInt, ok := value.(int); ok {
|
||||
i = valueInt
|
||||
} else {
|
||||
err = fmt.Errorf("%s expected integer, got %s (%v)", description, kern.TypeName(value), value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ToGoInt64(value any, description string) (i int64, err error) {
|
||||
if valueInt64, ok := value.(int64); ok {
|
||||
i = valueInt64
|
||||
} else if valueInt, ok := value.(int); ok {
|
||||
i = int64(valueInt)
|
||||
} else {
|
||||
err = fmt.Errorf("%s expected integer, got %s (%v)", description, kern.TypeName(value), value)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// string.go
|
||||
package str
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
)
|
||||
|
||||
func IsString(v any) (ok bool) {
|
||||
_, ok = v.(string)
|
||||
return ok
|
||||
}
|
||||
|
||||
func ToGoString(value any, description string) (s string, err error) {
|
||||
if s, ok := value.(string); ok {
|
||||
return s, nil
|
||||
} else {
|
||||
err = fmt.Errorf("%s expected string, got %s (%v)", description, kern.TypeName(value), value)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// types.go
|
||||
package types
|
||||
|
||||
// func TypeName(v any) (name string) {
|
||||
// if v == nil {
|
||||
// name = "nil"
|
||||
// } else if typer, ok := v.(kern.Typer); ok {
|
||||
// name = typer.TypeName()
|
||||
// } else if IsInteger(v) {
|
||||
// name = "integer"
|
||||
// } else if float.IsFloat(v) {
|
||||
// name = "float"
|
||||
// } else {
|
||||
// name = fmt.Sprintf("%T", v)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// dict-type.go
|
||||
package types
|
||||
|
||||
import (
|
||||
"git.portale-stac.it/go-pkg/expr/kern"
|
||||
"git.portale-stac.it/go-pkg/expr/types/dict"
|
||||
)
|
||||
|
||||
func ContextToDict(ctx kern.ExprContext) (dt *dict.DictType) {
|
||||
var keys []string
|
||||
// Variables
|
||||
keys = ctx.EnumVars(nil)
|
||||
vars := dict.MakeDict()
|
||||
for _, key := range keys {
|
||||
value, _ := ctx.GetVar(key)
|
||||
vars.SetItem(key, value)
|
||||
}
|
||||
|
||||
// Functions
|
||||
keys = ctx.EnumFuncs(func(name string) bool { return true })
|
||||
funcs := dict.MakeDict()
|
||||
for _, key := range keys {
|
||||
funcInfo, _ := ctx.GetFuncInfo(key)
|
||||
funcs.SetItem(key, funcInfo)
|
||||
}
|
||||
|
||||
dt = dict.MakeDict()
|
||||
dt.SetItem("vars", vars)
|
||||
dt.SetItem("funcs", funcs)
|
||||
return
|
||||
}
|
||||
|
||||
func ContextToString(ctx kern.ExprContext, opt kern.FmtOpt) string {
|
||||
if dict, ok := ctx.ToDict().(*dict.DictType); ok {
|
||||
return dict.ToString(opt)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user