Skip to content

Commit

Permalink
Merge branch 'master' into feature/json-encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisrink10 committed Jun 3, 2020
2 parents ec3c00d + 0b93497 commit fe3e7b9
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 41 deletions.
48 changes: 24 additions & 24 deletions src/basilisp/lang/keyword.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import threading
from typing import Iterable, Optional

from pyrsistent import PMap, pmap

import basilisp.lang.atom as atom
import basilisp.lang.map as lmap
from basilisp.lang.interfaces import IAssociative, ILispObject

__INTERN: atom.Atom["PMap[int, Keyword]"] = atom.Atom(pmap())
_LOCK = threading.Lock()
_INTERN: lmap.Map[int, "Keyword"] = lmap.Map.empty()


class Keyword(ILispObject):
Expand Down Expand Up @@ -48,46 +48,46 @@ def __reduce__(self):


def complete(
text: str, kw_cache: atom.Atom["PMap[int, Keyword]"] = __INTERN
text: str, kw_cache: Optional[lmap.Map[int, Keyword]] = None,
) -> Iterable[str]:
"""Return an iterable of possible completions for the given text."""
assert text.startswith(":")
interns = kw_cache.deref()
text = text[1:]

if kw_cache is None:
kw_cache = _INTERN

if "/" in text:
prefix, suffix = text.split("/", maxsplit=1)
results = filter(
lambda kw: (kw.ns is not None and kw.ns == prefix)
and kw.name.startswith(suffix),
interns.itervalues(),
kw_cache.itervalues(),
)
else:
results = filter(
lambda kw: kw.name.startswith(text)
or (kw.ns is not None and kw.ns.startswith(text)),
interns.itervalues(),
kw_cache.itervalues(),
)

return map(str, results)


def __get_or_create(
kw_cache: "PMap[int, Keyword]", h: int, name: str, ns: Optional[str]
) -> PMap:
"""Private swap function used to either get the interned keyword
instance from the input string."""
if h in kw_cache:
return kw_cache
kw = Keyword(name, ns=ns)
return kw_cache.set(h, kw)
def keyword(name: str, ns: Optional[str] = None) -> Keyword:
"""Create a new keyword with name and optional namespace.
Keywords are stored in a global cache by their hash. If a keyword with the same
hash already exists in the cache, that keyword will be returned. If no keyword
exists in the global cache, one will be created, entered into the cache, and then
returned."""
global _INTERN

def keyword(
name: str,
ns: Optional[str] = None,
kw_cache: atom.Atom["PMap[int, Keyword]"] = __INTERN,
) -> Keyword:
"""Create a new keyword."""
h = hash((name, ns))
return kw_cache.swap(__get_or_create, h, name, ns)[h]
with _LOCK:
found = _INTERN.val_at(h)
if found:
return found
kw = Keyword(name, ns=ns)
_INTERN = _INTERN.assoc(h, kw)
return kw
9 changes: 9 additions & 0 deletions src/basilisp/lang/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ def keys(self):
def values(self):
return self._inner.values()

def iteritems(self):
return self._inner.iteritems()

def iterkeys(self):
return self._inner.iterkeys()

def itervalues(self):
return self._inner.itervalues()

@property
def meta(self) -> Optional[IPersistentMap]:
return self._meta
Expand Down
3 changes: 2 additions & 1 deletion src/basilisp/lang/obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ def seq_lrepr(
return f"{start}{seq_lrepr}{end}"


# pylint: disable=unused-argument
@singledispatch
def lrepr( # pylint: disable=too-many-arguments,unused-arguments
def lrepr( # pylint: disable=too-many-arguments
o: Any,
human_readable: bool = False,
print_dup: bool = PRINT_DUP,
Expand Down
21 changes: 12 additions & 9 deletions src/basilisp/lang/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1178,17 +1178,20 @@ def _to_lisp_vec(o: Iterable, keywordize_keys: bool = True) -> vec.Vector:
)


@functools.singledispatch
def _keywordize_keys(k):
return k


@_keywordize_keys.register(str)
def _keywordize_keys_str(k):
return kw.keyword(k)


@to_lisp.register(dict)
def _to_lisp_map(o: Mapping, keywordize_keys: bool = True) -> lmap.Map:
kvs = {}
for k, v in o.items():
if isinstance(k, str) and keywordize_keys:
processed_key = kw.keyword(k)
else:
processed_key = to_lisp(k, keywordize_keys=keywordize_keys)

kvs[processed_key] = to_lisp(v, keywordize_keys=keywordize_keys)
return lmap.map(kvs)
process_key = _keywordize_keys if keywordize_keys else lambda x: x
return lmap.map({process_key(k): v for k, v in o.items()}) # type: ignore[operator]


@to_lisp.register(frozenset)
Expand Down
14 changes: 7 additions & 7 deletions tests/basilisp/keyword_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,25 @@ def test_keyword_pickleability(pickle_protocol: int, o: Keyword):

class TestKeywordCompletion:
@pytest.fixture
def empty_cache(self) -> Atom["PMap[int, Keyword]"]:
return Atom(pmap())
def empty_cache(self) -> lmap.Map[int, Keyword]:
return lmap.Map.empty()

def test_empty_cache_no_completion(self, empty_cache: Atom["PMap[int, Keyword]"]):
def test_empty_cache_no_completion(self, empty_cache: lmap.Map[int, Keyword]):
assert [] == list(complete(":", kw_cache=empty_cache))

@pytest.fixture
def cache(self) -> Atom["PMap[int, Keyword]"]:
def cache(self) -> lmap.Map[int, Keyword]:
values = [Keyword("kw"), Keyword("ns"), Keyword("kw", ns="ns")]
return Atom(pmap({hash(v): v for v in values}))
return lmap.map({hash(v): v for v in values})

def test_no_ns_completion(self, cache: Atom["PMap[int, Keyword]"]):
def test_no_ns_completion(self, cache: lmap.Map[int, Keyword]):
assert [] == list(complete(":v", kw_cache=cache))
assert {":kw", ":ns/kw"} == set(complete(":k", kw_cache=cache))
assert {":kw", ":ns/kw"} == set(complete(":kw", kw_cache=cache))
assert {":ns", ":ns/kw"} == set(complete(":n", kw_cache=cache))
assert {":ns", ":ns/kw"} == set(complete(":ns", kw_cache=cache))

def test_ns_completion(self, cache: Atom["PMap[int, Keyword]"]):
def test_ns_completion(self, cache: lmap.Map[int, Keyword]):
assert [] == list(complete(":v/", kw_cache=cache))
assert [] == list(complete(":k/", kw_cache=cache))
assert [] == list(complete(":kw/", kw_cache=cache))
Expand Down

0 comments on commit fe3e7b9

Please sign in to comment.