Skip to content

Commit 7e08d51

Browse files
authored
Core library changes (#91)
1 parent 9f51145 commit 7e08d51

File tree

11 files changed

+1309
-30
lines changed

11 files changed

+1309
-30
lines changed

basilisp/core/__init__.lpy

Lines changed: 660 additions & 11 deletions
Large diffs are not rendered by default.

basilisp/lang/associative.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ def contains(self, k):
1717
raise NotImplementedError()
1818

1919
@abstractmethod
20-
def entry(self, k):
20+
def entry(self, k, default=None):
2121
raise NotImplementedError()

basilisp/lang/map.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ def discard(self, *ks) -> "Map":
142142
pass
143143
return Map(m.persistent())
144144

145-
def entry(self, k):
146-
return self._inner.get(k, None)
145+
def entry(self, k, default=None):
146+
return self._inner.get(k, default)
147147

148148
def update(self, *maps) -> "Map":
149149
m: PMap = self._inner.update(*maps)

basilisp/lang/runtime.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import functools
22
import itertools
3+
import math
34
import threading
45
import types
6+
from fractions import Fraction
57
from typing import Optional, Dict, Tuple
68

79
from functional import seq
@@ -15,6 +17,7 @@
1517
import basilisp.lang.seq as lseq
1618
import basilisp.lang.symbol as sym
1719
from basilisp.lang import atom
20+
from basilisp.lang.typing import LispNumber
1821
from basilisp.util import Maybe
1922

2023
_CORE_NS = 'basilisp.core'
@@ -387,7 +390,7 @@ def nthrest(coll, i: int):
387390
coll = rest(coll)
388391

389392

390-
def next(o) -> Optional[lseq.Seq]: # pylint:disable=redefined-builtin
393+
def next_(o) -> Optional[lseq.Seq]:
391394
"""Calls rest on o. If o returns an empty sequence or None, returns None.
392395
Otherwise, returns the elements after the first in o."""
393396
s = rest(o)
@@ -404,7 +407,7 @@ def nthnext(coll, i: int) -> Optional[lseq.Seq]:
404407
if i == 0:
405408
return to_seq(coll)
406409
i -= 1
407-
coll = next(coll)
410+
coll = next_(coll)
408411

409412

410413
def cons(o, seq) -> lseq.Seq:
@@ -415,7 +418,7 @@ def cons(o, seq) -> lseq.Seq:
415418
return llist.l(o)
416419
if isinstance(seq, lseq.Seq):
417420
return seq.cons(o)
418-
return to_seq(seq).cons(o) # type: ignore
421+
return Maybe(to_seq(seq)).map(lambda s: s.cons(o)).or_else(lambda: llist.l(o))
419422

420423

421424
def _seq_or_nil(s: lseq.Seq) -> Optional[lseq.Seq]:
@@ -492,7 +495,9 @@ def assoc(m, *kvs):
492495

493496

494497
def conj(coll, *xs):
495-
"""Conjoin xs to collection. """
498+
"""Conjoin xs to collection. New elements may be added in different positions
499+
depending on the type of coll. conj returns the same type as coll. If coll
500+
is None, return a list with xs conjoined."""
496501
if coll is None:
497502
l = llist.List.empty()
498503
return l.cons(*xs)
@@ -501,6 +506,16 @@ def conj(coll, *xs):
501506
raise TypeError(f"Object of type {type(coll)} does not implement Collection interface")
502507

503508

509+
def partial(f, *args):
510+
"""Return a function which is the partial application of f with args."""
511+
512+
@functools.wraps(f)
513+
def partial_f(*inner_args):
514+
return f(*itertools.chain(args, inner_args))
515+
516+
return partial_f
517+
518+
504519
def deref(o):
505520
"""Dereference a Deref object and return its contents."""
506521
if isinstance(o, lderef.Deref):
@@ -515,6 +530,52 @@ def swap(a: atom.Atom, f, *args):
515530
return a.swap(f, *args)
516531

517532

533+
def equals(v1, v2) -> bool:
534+
"""Compare two objects by value. Unlike the standard Python equality operator,
535+
this function does not consider 1 == True or 0 == False. All other equality
536+
operations are the same and performed using Python's equality operator."""
537+
if isinstance(v1, (bool, type(None))) or isinstance(v2, (bool, type(None))):
538+
return v1 is v2
539+
return v1 == v2
540+
541+
542+
def divide(x: LispNumber, y: LispNumber) -> LispNumber:
543+
"""Division reducer. If both arguments are integers, return a Fraction.
544+
Otherwise, return the true division of x and y."""
545+
if isinstance(x, int) and isinstance(y, int):
546+
return Fraction(x, y)
547+
return x / y # type: ignore
548+
549+
550+
def quotient(num, div) -> LispNumber:
551+
"""Return the integral quotient resulting from the division of num by div."""
552+
return math.trunc(num / div)
553+
554+
555+
def sort(coll, f=None) -> Optional[lseq.Seq]:
556+
"""Return a sorted sequence of the elements in coll. If a comparator
557+
function f is provided, compare elements in coll using f."""
558+
return to_seq(sorted(coll, key=Maybe(f).map(functools.cmp_to_key).value))
559+
560+
561+
def contains(coll, k):
562+
"""Return true if o contains the key k."""
563+
if isinstance(coll, lassoc.Associative):
564+
return coll.contains(k)
565+
return k in coll
566+
567+
568+
def get(m, k, default=None):
569+
"""Return the value of k in m. Return default if k not found in m."""
570+
if isinstance(m, lassoc.Associative):
571+
return m.entry(k, default=default)
572+
573+
try:
574+
return m[k]
575+
except (KeyError, IndexError):
576+
return default
577+
578+
518579
def _collect_args(args) -> lseq.Seq:
519580
"""Collect Python starred arguments into a Basilisp list."""
520581
if isinstance(args, tuple):

basilisp/lang/seq.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,25 @@
22
from abc import ABC, abstractmethod
33
from typing import Iterator, Optional, TypeVar, Iterable, Any, Callable
44

5+
from functional import seq as fseq
6+
57
from basilisp.lang.meta import Meta
68
from basilisp.lang.util import lrepr
79
from basilisp.util import Maybe
810

911
T = TypeVar('T')
1012

13+
_SEQ_MAX = 10
14+
1115

1216
class Seq(ABC, Iterable[T]):
1317
__slots__ = ()
1418

1519
def __repr__(self):
16-
return "({list})".format(list=" ".join(map(lrepr, self)))
20+
items = fseq(self).take(_SEQ_MAX + 1).map(lrepr).to_list()
21+
if len(items) == _SEQ_MAX + 1:
22+
return "({list} ...)".format(list=" ".join(fseq(items).take(_SEQ_MAX)))
23+
return "({list})".format(list=" ".join(fseq(items).take(_SEQ_MAX)))
1724

1825
@property
1926
@abstractmethod

basilisp/lang/set.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ def cons(self, *elems) -> "Set":
5858
e.add(elem)
5959
return Set(e.persistent(), meta=self.meta)
6060

61+
def disj(self, *elems) -> "Set":
62+
e = self._inner.evolver()
63+
for elem in elems:
64+
try:
65+
e.remove(elem)
66+
except KeyError:
67+
pass
68+
return Set(e.persistent(), meta=self.meta)
69+
6170
@staticmethod
6271
def empty() -> "Set":
6372
return s()

basilisp/lang/typing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import uuid
22
from datetime import datetime
3+
from fractions import Fraction
34
from typing import Union, Pattern
45

56
import basilisp.lang.keyword as kw
@@ -9,6 +10,7 @@
910
import basilisp.lang.symbol as sym
1011
import basilisp.lang.vector as vec
1112

13+
LispNumber = Union[int, float, Fraction]
1214
LispForm = Union[bool, datetime, int, float, kw.Keyword, llist.List,
1315
lmap.Map, None, Pattern, lset.Set, str, sym.Symbol,
1416
vec.Vector, uuid.UUID]

basilisp/lang/util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import keyword
44
import re
55
import uuid
6+
from fractions import Fraction
67
from typing import Pattern
78

89
import dateutil.parser as dateparser
@@ -28,6 +29,8 @@ def lrepr(f) -> str:
2829
return f'#uuid "{uuid_str}"'
2930
elif isinstance(f, Pattern):
3031
return f'#"{f.pattern}"'
32+
elif isinstance(f, Fraction):
33+
return f"{f.numerator}/{f.denominator}"
3134
else:
3235
return repr(f)
3336

basilisp/lang/vector.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ def assoc(self, *kvs):
5858
def contains(self, k):
5959
return 0 <= k < len(self._inner)
6060

61-
def entry(self, k):
61+
def entry(self, k, default=None):
6262
try:
6363
return self._inner[k]
6464
except IndexError:
65-
return None
65+
return default
6666

6767
@staticmethod
6868
def empty() -> "Vector":

0 commit comments

Comments
 (0)