Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions pkg/lang/bigdecimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ import (
"bitbucket.org/pcastools/hash"
)

// BigDec is an arbitrary-precision decimal number. It wraps and has
// the same semantics as big.Float. big.Float is not used directly
// because it is mutable, and the core BigDecimal should not be.
// BigDec is an arbitrary-precision floating point number. It wraps
// and has the same semantics as big.Float. big.Float is not used
// directly because it is mutable, and the core BigDecimal should not
// be.
//
// TODO: swap out with a *decimal* representation. The go standard
// library big.Float is a binary floating point representation,
// which means that some decimal fractions cannot be represented
// exactly. This can lead to unexpected results when doing
// arithmetic with decimal fractions. A decimal representation
// would avoid this problem.
type BigDecimal struct {
val *big.Float
}
Expand Down Expand Up @@ -107,7 +115,12 @@ func (n *BigDecimal) Quotient(other *BigDecimal) *BigDecimal {
}

func (n *BigDecimal) Remainder(other *BigDecimal) *BigDecimal {
panic("not implemented")
quotient := new(big.Float).Quo(n.val, other.val)
intQuotient, _ := quotient.Int(nil)
intQuotientFloat := new(big.Float).SetInt(intQuotient)
product := new(big.Float).Mul(intQuotientFloat, other.val)
remainder := new(big.Float).Sub(n.val, product)
return &BigDecimal{val: remainder}
}

func (n *BigDecimal) Cmp(other *BigDecimal) int {
Expand Down
1 change: 1 addition & 0 deletions pkg/lang/equals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestEquiv(t *testing.T) {
{NewMap(1, 2).Seq(), NewVector(NewList(1, 2)), NewList(NewVector(1, 2))},
// empty lazy seqs are equal
{NewLazySeq(func() interface{} { return nil }), NewLazySeq(func() interface{} { return nil })},
{NewList(1, 2), NewLongRange(0, 3, 1).Next()},
}

for _, els := range equivs {
Expand Down
10 changes: 6 additions & 4 deletions pkg/lang/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,12 +486,14 @@ func Count(coll any) int {
return count
}

func Keys(m Associative) ISeq {
return NewMapKeySeq(Seq(m))
func Keys(x any) ISeq {
// TODO: optimize for map case
return NewMapKeySeq(Seq(x))
}

func Vals(m Associative) ISeq {
return NewMapValSeq(Seq(m))
func Vals(x any) ISeq {
// TODO: optimize for map case
return NewMapValSeq(Seq(x))
}

func Subvec(v IPersistentVector, start, end int) IPersistentVector {
Expand Down
160 changes: 7 additions & 153 deletions pkg/lang/iteration.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ func MustNth(x interface{}, i int) interface{} {

func Nth(x interface{}, n int) (interface{}, bool) {
switch x := x.(type) {
// Deprecate this
case Nther:
return x.Nth(n)
case Indexed:
val := x.NthDefault(n, notFound)
if val == notFound {
return nil, false
}
return val, true
case ISeq:
x = Seq(x)
for i := 0; i <= n; i++ {
Expand Down Expand Up @@ -61,156 +68,3 @@ func Nth(x interface{}, n int) (interface{}, bool) {

return nil, false
}

// // NewIterator returns a lazy sequence of x, f(x), f(f(x)), ....
// func NewIterator(f func(interface{}) interface{}, x interface{}) ISeq {
// return iterator{f: f, x: x}
// }

// type iterator struct {
// f func(interface{}) interface{}
// x interface{}
// }

// func (i iterator) xxx_sequential() {}

// func (i iterator) Seq() ISeq {
// return i
// }

// func (i iterator) First() interface{} {
// return i.x
// }

// func (i iterator) Next() ISeq {
// return NewIterator(i.f, i.f(i.x))
// }

// func (i iterator) More() ISeq {
// nxt := i.Next()
// if nxt == nil {
// return emptyList
// }
// return nxt
// }

// // NewValueIterator returns a lazy sequence of the values of x.
// func NewVectorIterator(x IPersistentVector, start, step int) ISeq {
// if x.Count() == 0 {
// return emptyList
// }
// return vectorIterator{v: x, start: start, step: step}
// }

// type vectorIterator struct {
// v IPersistentVector
// start int
// step int
// }

// func (it vectorIterator) xxx_sequential() {}

// func (it vectorIterator) Seq() ISeq {
// return it
// }

// func (it vectorIterator) First() interface{} {
// return it.v.Nth(it.start)
// }

// func (it vectorIterator) Next() ISeq {
// next := it.start + it.step
// if next >= it.v.Count() || next < 0 {
// return nil
// }
// return &vectorIterator{v: it.v, start: next, step: it.step}
// }

// func (it vectorIterator) More() ISeq {
// nxt := it.Next()
// if nxt == nil {
// return emptyList
// }
// return nxt
// }

// // NewConcatIterator returns a sequence concatenating the given
// // sequences.
// func NewConcatIterator(colls ...interface{}) ISeq {
// var it *concatIterator
// for i := len(colls) - 1; i >= 0; i-- {
// iseq := Seq(colls[i])
// if iseq == nil {
// continue
// }
// it = &concatIterator{seq: iseq, next: it}
// }
// if it == nil {
// return emptyList
// }
// return it
// }

// type concatIterator struct {
// seq ISeq
// next *concatIterator
// }

// func (i *concatIterator) xxx_sequential() {}

// func (i *concatIterator) Seq() ISeq {
// return i
// }

// func (i *concatIterator) First() interface{} {
// return i.seq.First()
// }

// func (i *concatIterator) Next() ISeq {
// i = &concatIterator{seq: i.seq.Next(), next: i.next}
// for i.seq == nil {
// i = i.next
// if i == nil {
// return nil
// }
// }
// return i
// }

// func (i *concatIterator) More() ISeq {
// nxt := i.Next()
// if nxt == nil {
// return emptyList
// }
// return nxt
// }

// ////////////////////////////////////////////////////////////////////////////////

// func chunkIteratorSeq(iter *reflect.MapIter) ISeq {
// const chunkSize = 32

// return NewLazySeq(func() interface{} {
// chunk := make([]interface{}, 0, chunkSize)
// exhausted := false
// for n := 0; n < chunkSize; n++ {
// chunk = append(chunk, NewMapEntry(iter.Key().Interface(), iter.Value().Interface()))
// if !iter.Next() {
// exhausted = true
// break
// }
// }
// if exhausted {
// return NewChunkedCons(NewSliceChunk(chunk), nil)
// }
// return NewChunkedCons(NewSliceChunk(chunk), chunkIteratorSeq(iter))
// })
// }

// func NewGoMapSeq(x interface{}) ISeq {
// rng := reflect.ValueOf(x).MapRange()
// if !rng.Next() {
// return nil
// }
// return chunkIteratorSeq(rng)
// }
23 changes: 14 additions & 9 deletions pkg/lang/keyword.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ func (k Keyword) value() string {
return k.kw.Get().(string)
}

func (k Keyword) Namespace() string {
// Return the namespace of the keyword, or the empty string if it
// doesn't have one.
func (k Keyword) Namespace() any {
// Return the namespace of the keyword, or nil if it doesn't have
// one.
// TODO: support both nil and empty string namespace as clojure does
if i := strings.Index(k.value(), "/"); i != -1 {
return k.value()[:i]
}
return ""
return nil
}

func (k Keyword) Name() string {
Expand All @@ -61,6 +62,10 @@ func (k Keyword) Name() string {
return k.value()
}

func (k Keyword) Sym() *Symbol {
return InternSymbol(k.Namespace(), k.Name())
}

func (k Keyword) String() string {
return ":" + k.value()
}
Expand Down Expand Up @@ -106,14 +111,14 @@ func (k Keyword) Compare(other any) int {
if s == os {
return 0
}
ns := k.Namespace()
if ns == "" {
if otherKw.Namespace() != "" {
ns, ok := k.Namespace().(string)
if !ok {
if otherKw.Namespace() != nil {
return -1
}
} else {
ons := otherKw.Namespace()
if ons == "" {
ons, ok := otherKw.Namespace().(string)
if !ok {
return 1
}
nsc := strings.Compare(ns, ons)
Expand Down
2 changes: 1 addition & 1 deletion pkg/lang/longrange.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (r *LongRange) Next() ISeq {
if next >= r.end {
return nil
}
return &LongRange{start: next, end: r.end, step: r.step}
return &LongRange{start: next, end: r.end, step: r.step, count: r.count - 1}
}

func (r *LongRange) More() ISeq {
Expand Down
18 changes: 11 additions & 7 deletions pkg/lang/numberops.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,16 +427,20 @@ func (o ratioOps) Quotient(x, y any) any {
return AsRatio(x).Quotient(AsRatio(y))
}
func (o ratioOps) Remainder(x, y any) any {
xRat := AsRatio(x)
yRat := AsRatio(y)
xRat := AsRatio(x).val
yRat := AsRatio(y).val

q := new(big.Int)
q.Mul(xRat.val.Num(), yRat.val.Denom())
// BigInteger q = rx.numerator.multiply(ry.denominator).divide(
// rx.denominator.multiply(ry.numerator));
// Number ret = Numbers.minus(x, Numbers.multiply(q, y));
// return ret

qd := new(big.Int)
qd.Mul(xRat.val.Denom(), yRat.val.Num())
// result should be a BigInt
qn := new(big.Int).Mul(xRat.Num(), yRat.Denom())
qd := new(big.Int).Mul(xRat.Denom(), yRat.Num())
rem := new(big.Int)
q, rem := qn.QuoRem(qn, qd, rem)

q.Div(q, qd)
return Sub(x, Multiply(q, y))
}
func (o ratioOps) LT(x, y any) bool {
Expand Down
20 changes: 20 additions & 0 deletions pkg/lang/numbers.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ func (nm *NumberMethods) Remainder(x, y any) any {
return Ops(x).Combine(yops).Remainder(x, y)
}

func (nm *NumberMethods) Rationalize(x any) any {
switch x := x.(type) {
case float32:
return nm.Rationalize(NewBigDecimalFromFloat64(float64(x)))
case float64:
return nm.Rationalize(NewBigDecimalFromFloat64(x))
case *BigDecimal:
bx := x.val
rat, _ := bx.Rat(nil)
if rat.IsInt() {
return NewBigIntFromGoBigInt(rat.Num())
}
return &Ratio{val: rat}
}
if !IsNumber(x) {
panic(fmt.Errorf("cannot rationalize %T", x))
}
return x
}

func (nm *NumberMethods) And(x, y any) any {
return bitOpsCast(x) & bitOpsCast(y)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/lang/persistentarraymap.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ func (s *MapSeq) Drop(n int) Sequential {
////////////////////////////////////////////////////////////////////////////////

func NewMapKeySeq(s ISeq) ISeq {
if s == nil {
if IsNil(s) {
return nil
}
return &MapKeySeq{s: s}
Expand Down Expand Up @@ -566,7 +566,7 @@ func (s *MapKeySeq) HashEq() uint32 {
////////////////////////////////////////////////////////////////////////////////

func NewMapValSeq(s ISeq) ISeq {
if s == nil {
if IsNil(s) {
return nil
}
return &MapValSeq{s: s}
Expand Down
4 changes: 3 additions & 1 deletion pkg/lang/ratio.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ func (r *Ratio) Denominator() *big.Int {
}

func (r *Ratio) BigIntegerValue() *big.Int {
return new(big.Int).Div(r.val.Num(), r.val.Denom())
var tmp big.Int
res, _ := new(big.Int).QuoRem(r.val.Num(), r.val.Denom(), &tmp)
return res
}

func (r *Ratio) String() string {
Expand Down
8 changes: 6 additions & 2 deletions pkg/lang/stringseq.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ func NewStringSeq(s string, i int) *StringSeq {
if len(s) == 0 {
return nil
}
return &StringSeq{str: []rune(s), i: i}
runes := []rune(s)
if i >= len(runes) {
return nil
}
return &StringSeq{str: runes, i: i}
}

func newStringSeq(s []rune, i int) *StringSeq {
if len(s) == 0 {
if len(s) == 0 || i >= len(s) {
return nil
}
return &StringSeq{str: s, i: i}
Expand Down
Loading