Skip to content

Commit

Permalink
Change a lot of stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisrink10 committed Nov 30, 2019
1 parent 03582d7 commit 66ab273
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 181 deletions.
7 changes: 5 additions & 2 deletions src/basilisp/core.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,12 @@
fmeta (if (map? (first body))
(first body)
nil)
fname (if fmeta
(vary-meta name conj fmeta)
name)
fname (if doc
(vary-meta name assoc :doc doc)
(with-meta name fmeta))
(vary-meta fname assoc :doc doc)
(vary-meta fname conj fmeta))
body (if fmeta
(rest body)
body)
Expand Down
21 changes: 11 additions & 10 deletions src/basilisp/lang/compiler/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
Vector as VectorNode,
WithMeta,
)
from basilisp.lang.interfaces import IMeta, IRecord, ISeq, IType
from basilisp.lang.interfaces import IMeta, IRecord, ISeq, IType, IWithMeta
from basilisp.lang.runtime import Var
from basilisp.lang.typing import LispForm, ReaderForm
from basilisp.lang.util import count, genname, munge
Expand Down Expand Up @@ -514,15 +514,16 @@ def has_meta_prop(o: Union[IMeta, Var]) -> bool:
def _loc(form: Union[LispForm, ISeq]) -> Optional[Tuple[int, int]]:
"""Fetch the location of the form in the original filename from the
input form, if it has metadata."""
try:
meta = form.meta # type: ignore
line = meta.get(reader.READER_LINE_KW) # type: ignore
col = meta.get(reader.READER_COL_KW) # type: ignore
except AttributeError:
return None
else:
assert isinstance(line, int) and isinstance(col, int)
return line, col
# Technically, IMeta is sufficient for fetching `form.meta` but the
# reader only applies line and column metadata to IWithMeta instances
if isinstance(form, IWithMeta):
meta = form.meta
if meta is not None:
line = meta.get(reader.READER_LINE_KW)
col = meta.get(reader.READER_COL_KW)
if isinstance(line, int) and isinstance(col, int):
return line, col
return None


def _with_loc(f: AnalyzeFunction):
Expand Down
24 changes: 13 additions & 11 deletions src/basilisp/lang/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,32 @@ def cons( # type: ignore[override]
Mapping[K, V],
],
) -> "Map[K, V]":
# For now, this definition does not take the generic Mapping[K, V] type
# because Vectors are technically Mapping[int, V] types, so this would
# require restructuring of the logic.
e = self._inner.evolver()
try:
for elem in elems:
if isinstance(elem, IPersistentMap):
if isinstance(elem, (IPersistentMap, Mapping)) and not isinstance(
elem, IPersistentVector
):
# Vectors are handled in the final else block, since we
# do not want to treat them as Mapping types for this
# particular usage.
for k, v in elem.items():
e.set(k, v)
elif isinstance(elem, IMapEntry):
e.set(elem.key, elem.value)
elif isinstance(elem, IPersistentVector):
elif elem is None:
continue
else:
# This block leniently allows nearly any 2 element sequential
# type including Vectors, Python lists, and Python tuples.
entry: IMapEntry[K, V] = MapEntry.from_vec(elem)
e.set(entry.key, entry.value)
elif isinstance(elem, Mapping):
for k, v in elem.items():
e.set(k, v) # type: ignore[arg-type]
else:
raise TypeError("Invalid map cons type")
return Map(e.persistent(), meta=self.meta)
except (TypeError, ValueError):
raise ValueError(
"Argument to map conj must be another Map or castable to MapEntry"
)
else:
return Map(e.persistent(), meta=self.meta)

@staticmethod
def empty() -> "Map":
Expand Down
16 changes: 10 additions & 6 deletions src/basilisp/lang/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,10 @@ def _with_loc(f: W) -> W:

@functools.wraps(f)
def with_lineno_and_col(ctx):
line, col = ctx.reader.line, ctx.reader.col
v = f(ctx)
if isinstance(v, IWithMeta):
new_meta = lmap.map(
{READER_LINE_KW: ctx.reader.line, READER_COL_KW: ctx.reader.col}
)
new_meta = lmap.map({READER_LINE_KW: line, READER_COL_KW: col})
old_meta = v.meta
return v.with_meta(
old_meta.cons(new_meta) if old_meta is not None else new_meta
Expand Down Expand Up @@ -805,9 +804,14 @@ def _read_meta(ctx: ReaderContext) -> IMeta:
)

obj_with_meta = _read_next_consuming_comment(ctx)
try:
return obj_with_meta.with_meta(meta_map) # type: ignore
except AttributeError:
if isinstance(obj_with_meta, IWithMeta):
new_meta = (
obj_with_meta.meta.cons(meta_map)
if obj_with_meta.meta is not None
else meta_map
)
return obj_with_meta.with_meta(new_meta)
else:
raise SyntaxError(
f"Can not attach metadata to object of type {type(obj_with_meta)}"
)
Expand Down
60 changes: 20 additions & 40 deletions tests/basilisp/list_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,23 @@
import basilisp.lang.map as lmap
from basilisp.lang.interfaces import (
ILispObject,
IMeta,
IPersistentCollection,
IPersistentList,
ISeq,
ISeqable,
IWithMeta,
)
from basilisp.lang.keyword import keyword
from basilisp.lang.symbol import symbol


def test_list_collection_interface():
assert isinstance(llist.l(), IPersistentCollection)
assert issubclass(llist.List, IPersistentCollection)


def test_list_list_interface():
assert isinstance(llist.l(), IPersistentList)
assert issubclass(llist.List, IPersistentList)


def test_list_meta_interface():
assert isinstance(llist.l(), IMeta)
assert issubclass(llist.List, IMeta)


def test_map_object_interface():
assert isinstance(llist.l(), ILispObject)
assert issubclass(llist.List, ILispObject)


def test_list_seq_interface():
assert isinstance(llist.l(), ISeq)
assert issubclass(llist.List, ISeq)


def test_list_seqable_interface():
assert isinstance(llist.l(), ISeqable)
assert issubclass(llist.List, ISeqable)
@pytest.mark.parametrize(
"interface",
[IPersistentCollection, IPersistentList, IWithMeta, ILispObject, ISeq, ISeqable,],
)
def test_list_interface_membership(interface):
assert isinstance(llist.l(), interface)
assert issubclass(llist.List, interface)


def test_list_slice():
Expand Down Expand Up @@ -94,13 +73,13 @@ def test_list_with_meta():
l3 = l2.with_meta(meta2)
assert l2 is not l3
assert l2 == l3
assert l3.meta == lmap.m(type=symbol("str"), tag=keyword("async"))
assert l3.meta == lmap.m(tag=keyword("async"))

meta3 = lmap.m(tag=keyword("macro"))
l4 = l3.with_meta(meta3)
assert l3 is not l4
assert l3 == l4
assert l4.meta == lmap.m(type=symbol("str"), tag=keyword("macro"))
assert l4.meta == lmap.m(tag=keyword("macro"))


def test_list_first():
Expand All @@ -116,12 +95,13 @@ def test_list_rest():
assert llist.l(keyword("kw1"), keyword("kw2")).rest == llist.l(keyword("kw2"))


def test_list_repr():
l = llist.l()
assert repr(l) == "()"

l = llist.l(keyword("kw1"))
assert repr(l) == "(:kw1)"

l = llist.l(keyword("kw1"), keyword("kw2"))
assert repr(l) == "(:kw1 :kw2)"
@pytest.mark.parametrize(
"l,str_repr",
[
(llist.l(), "()"),
(llist.l(keyword("kw1")), "(:kw1)"),
(llist.l(keyword("kw1"), keyword("kw2")), "(:kw1 :kw2)"),
],
)
def test_list_repr(l: llist.List, str_repr: str):
assert repr(l) == str_repr
56 changes: 19 additions & 37 deletions tests/basilisp/map_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,36 @@
IAssociative,
ILispObject,
IMapEntry,
IMeta,
IPersistentCollection,
IPersistentMap,
ISeqable,
IWithMeta,
)
from basilisp.lang.keyword import keyword
from basilisp.lang.symbol import symbol
from basilisp.lang.vector import MapEntry


def test_map_entry_interface():
def test_map_entry_interface_membership():
assert isinstance(lmap.MapEntry.of("a", "b"), IMapEntry)
assert issubclass(lmap.MapEntry, IMapEntry)


def test_map_associative_interface():
assert isinstance(lmap.m(), IAssociative)
assert issubclass(lmap.Map, IAssociative)


def test_map_collection_interface():
assert isinstance(lmap.m(), IPersistentCollection)
assert issubclass(lmap.Map, IPersistentCollection)


def test_map_meta_interface():
assert isinstance(lmap.m(), IMeta)
assert issubclass(lmap.Map, IMeta)


def test_map_map_interface():
assert isinstance(lmap.m(), IPersistentMap)
assert issubclass(lmap.Map, IPersistentMap)


def test_map_mapping_interface():
assert isinstance(lmap.m(), Mapping)
assert issubclass(lmap.Map, Mapping)


def test_map_object_interface():
assert isinstance(lmap.m(), ILispObject)
assert issubclass(lmap.Map, ILispObject)


def test_map_seqable_interface():
assert isinstance(lmap.m(), ISeqable)
assert issubclass(lmap.Map, ISeqable)
@pytest.mark.parametrize(
"interface",
[
IAssociative,
IPersistentCollection,
IWithMeta,
IPersistentMap,
Mapping,
ILispObject,
ISeqable,
],
)
def test_map_interface_membership(interface):
assert isinstance(lmap.m(), interface)
assert issubclass(lmap.Map, interface)


def test_assoc():
Expand Down Expand Up @@ -172,13 +154,13 @@ def test_map_with_meta():
m3 = m2.with_meta(meta2)
assert m2 is not m3
assert m2 == m3
assert m3.meta == lmap.m(type=symbol("str"), tag=keyword("async"))
assert m3.meta == lmap.m(tag=keyword("async"))

meta3 = lmap.m(tag=keyword("macro"))
m4 = m3.with_meta(meta3)
assert m3 is not m4
assert m3 == m4
assert m4.meta == lmap.m(type=symbol("str"), tag=keyword("macro"))
assert m4.meta == lmap.m(tag=keyword("macro"))


def test_map_repr():
Expand Down
59 changes: 24 additions & 35 deletions tests/basilisp/set_test.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,27 @@
import typing

import pytest

import basilisp.lang.map as lmap
import basilisp.lang.set as lset
from basilisp.lang.interfaces import (
ILispObject,
IMeta,
IPersistentCollection,
IPersistentSet,
ISeqable,
IWithMeta,
)
from basilisp.lang.keyword import keyword
from basilisp.lang.symbol import symbol


def test_list_collection_interface():
assert isinstance(lset.s(), IPersistentCollection)
assert issubclass(lset.Set, IPersistentCollection)


def test_list_meta_interface():
assert isinstance(lset.s(), IMeta)
assert issubclass(lset.Set, IMeta)


def test_set_object_interface():
assert isinstance(lset.s(), ILispObject)
assert issubclass(lset.Set, ILispObject)


def test_set_seqable_interface():
assert isinstance(lset.s(), ISeqable)
assert issubclass(lset.Set, ISeqable)


def test_set_set_interface():
assert isinstance(lset.s(), IPersistentSet)
assert issubclass(lset.Set, IPersistentSet)
@pytest.mark.parametrize(
"interface",
[IPersistentCollection, IWithMeta, ILispObject, ISeqable, IPersistentSet],
)
def test_set_interface_membership(interface):
assert isinstance(lset.s(), interface)
assert issubclass(lset.Set, interface)


def test_set_conj():
Expand Down Expand Up @@ -65,21 +53,22 @@ def test_set_with_meta():
s3 = s2.with_meta(meta2)
assert s2 is not s3
assert s2 == s3
assert s3.meta == lmap.m(type=symbol("str"), tag=keyword("async"))
assert s3.meta == lmap.m(tag=keyword("async"))

meta3 = lmap.m(tag=keyword("macro"))
s4 = s3.with_meta(meta3)
assert s3 is not s4
assert s3 == s4
assert s4.meta == lmap.m(type=symbol("str"), tag=keyword("macro"))
assert s4.meta == lmap.m(tag=keyword("macro"))


def test_set_repr():
s = lset.s()
assert repr(s) == "#{}"

s = lset.s(keyword("kw1"))
assert repr(s) == "#{:kw1}"

s = lset.s(keyword("kw1"), keyword("kw2"))
assert repr(s) in ["#{:kw1 :kw2}", "#{:kw2 :kw1}"]
@pytest.mark.parametrize(
"l,str_repr",
[
(lset.s(), {"#{}"}),
(lset.s(keyword("kw1")), {"#{:kw1}"}),
(lset.s(keyword("kw1"), keyword("kw2")), {"#{:kw1 :kw2}", "#{:kw2 :kw1}"}),
],
)
def test_set_repr(l: lset.Set, str_repr: typing.Set[str]):
assert repr(l) in str_repr
Loading

0 comments on commit 66ab273

Please sign in to comment.