Skip to content

Commit f02c3db

Browse files
authored
Fix line and column metadata (#454)
* Fix line and column metadata * Fetch metadata from various places as needed * Format and typecheck * Allow None type in IPersistentMap.cons
1 parent 5ce4758 commit f02c3db

File tree

5 files changed

+28
-12
lines changed

5 files changed

+28
-12
lines changed

src/basilisp/core.lpy

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,11 +1279,6 @@
12791279
(throw
12801280
(python/ValueError (str "cannot coerce " (python/repr x) " to byte"))))))
12811281

1282-
(defn boolean
1283-
"Coerce x to a boolean."
1284-
[x]
1285-
(python/bool x))
1286-
12871282
(defn char
12881283
"Coerce x to a string of length 1.
12891284

src/basilisp/lang/compiler/analyzer.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,19 @@ def _def_ast( # pylint: disable=too-many-branches,too-many-locals
651651
current_ns = ctx.current_ns
652652

653653
# Attach metadata relevant for the current process below.
654-
def_loc = _loc(form) or (None, None)
654+
#
655+
# The reader line/col metadata will be attached to the form itself in the
656+
# happy path case (top-level bare def or top-level def returned from a
657+
# macro). Less commonly, we may have to rely on metadata attached to the
658+
# def symbol if, for example, the def form is returned by a macro wrapped
659+
# in a do or let form. In that case, the macroexpansion process won't have
660+
# any metadata to pass along to the expanded form, but the symbol itself
661+
# is likely to have metadata. In rare cases, we may not be able to get
662+
# any metadata. This may happen if the form and name were both generated
663+
# programmatically.
664+
def_loc = _loc(form) or _loc(name) or (None, None)
665+
if def_loc == (None, None):
666+
logger.warning(f"def line and column metadata not provided for Var {name}")
655667
def_node_env = ctx.get_node_env()
656668
def_meta = _clean_meta(
657669
name.meta.update( # type: ignore [union-attr]
@@ -1670,6 +1682,11 @@ def _invoke_ast(ctx: AnalyzerContext, form: Union[llist.List, ISeq]) -> Node:
16701682
try:
16711683
macro_env = ctx.symbol_table.as_env_map()
16721684
expanded = fn.var.value(macro_env, form, *form.rest)
1685+
if isinstance(expanded, IWithMeta) and isinstance(form, IMeta):
1686+
old_meta = expanded.meta
1687+
expanded = expanded.with_meta(
1688+
old_meta.cons(form.meta) if old_meta else form.meta
1689+
)
16731690
with ctx.macro_ns(
16741691
fn.var.ns if fn.var.ns is not ctx.current_ns else None
16751692
):

src/basilisp/lang/interfaces.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class IPersistentMap(ICounted, IAssociative[K, V]):
198198

199199
@abstractmethod
200200
def cons( # type: ignore[override]
201-
self: T_map, *elems: Union[IMapEntry[K, V], "IPersistentMap[K, V]"]
201+
self: T_map, *elems: Union[IMapEntry[K, V], "IPersistentMap[K, V]", None]
202202
) -> T_map:
203203
raise NotImplementedError()
204204

src/basilisp/test.lpy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
Tests defined by deftest will be run by default by the PyTest test
135135
runner using Basilisp's builtin PyTest hook."
136136
[name-sym & body]
137-
(let [test-name-sym (with-meta name-sym {:test true})
137+
(let [test-name-sym (vary-meta name-sym assoc :test true)
138138
test-name-str (name test-name-sym)
139139
test-ns-name `(quote ~(symbol (name *ns*)))]
140140
`(do

tests/basilisp/compiler_test.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,8 @@ def test_macroexpand_1(self, example_macro):
17761776
)
17771777

17781778
def test_macroexpand(self, example_macro):
1779+
meta = lmap.map({reader.READER_LINE_KW: 1, reader.READER_COL_KW: 1})
1780+
17791781
assert llist.l(
17801782
sym.symbol("def"),
17811783
sym.symbol("child"),
@@ -1785,16 +1787,18 @@ def test_macroexpand(self, example_macro):
17851787
vec.v(sym.symbol("&env"), sym.symbol("&form")),
17861788
llist.l(sym.symbol("fn", ns="basilisp.core"), vec.Vector.empty()),
17871789
),
1788-
) == compiler.macroexpand(llist.l(sym.symbol("parent")))
1790+
) == compiler.macroexpand(llist.l(sym.symbol("parent"), meta=meta))
17891791

17901792
assert llist.l(sym.symbol("add", ns="operator"), 1, 2) == compiler.macroexpand(
1791-
llist.l(sym.symbol("add", ns="operator"), 1, 2)
1793+
llist.l(sym.symbol("add", ns="operator"), 1, 2, meta=meta)
17921794
)
17931795
assert sym.symbol("map") == compiler.macroexpand(sym.symbol("map"))
17941796
assert llist.l(sym.symbol("map")) == compiler.macroexpand(
1795-
llist.l(sym.symbol("map"))
1797+
llist.l(sym.symbol("map"), meta=meta)
1798+
)
1799+
assert vec.Vector.empty() == compiler.macroexpand(
1800+
vec.Vector.empty().with_meta(meta)
17961801
)
1797-
assert vec.Vector.empty() == compiler.macroexpand(vec.Vector.empty())
17981802

17991803
assert sym.symbol("non-existent-symbol") == compiler.macroexpand(
18001804
sym.symbol("non-existent-symbol")

0 commit comments

Comments
 (0)