Skip to content

Commit 67da90a

Browse files
authored
Fix resolver bugs (#170)
* Fix resolver to ignore special forms and resolve imported files * Fix regex errors reported by Pytest * Add a test for runtime.resolve_alias
1 parent 30f8314 commit 67da90a

File tree

7 files changed

+67
-11
lines changed

7 files changed

+67
-11
lines changed

basilisp/compiler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,8 +1525,8 @@ def _resolve_sym(ctx: CompilerContext, form: sym.Symbol) -> Optional[str]: # no
15251525
# If neither resolve, then defer to a Var.find
15261526
return None
15271527
elif ns_sym in ctx.current_ns.aliases:
1528-
aliased_ns = ctx.current_ns.aliases[ns_sym]
1529-
v = Var.find(sym.symbol(form.name, ns=aliased_ns))
1528+
aliased_ns: runtime.Namespace = ctx.current_ns.aliases[ns_sym]
1529+
v = Var.find(sym.symbol(form.name, ns=aliased_ns.name))
15301530
if v is not None:
15311531
return _resolve_sym_var(ctx, v)
15321532
return None

basilisp/importer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def exec_module(self, module):
8585
ns: runtime.Namespace = runtime.set_current_ns(fullname).value
8686
ns.module = module
8787

88-
forms = reader.read_file(filename)
88+
forms = reader.read_file(filename, resolver=runtime.resolve_alias)
8989
compiler.compile_module(forms, compiler.CompilerContext(), module, filename)
9090

9191
# Because we want to (by default) add 'basilisp.core into every namespace by default,

basilisp/lang/runtime.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import basilisp.lang.list as llist
1616
import basilisp.lang.map as lmap
1717
import basilisp.lang.seq as lseq
18+
import basilisp.lang.set as lset
1819
import basilisp.lang.symbol as sym
1920
from basilisp.lang import atom
2021
from basilisp.lang.typing import LispNumber
@@ -28,6 +29,25 @@
2829
_GENERATED_PYTHON_VAR_NAME = '*generated-python*'
2930
_PRINT_GENERATED_PY_VAR_NAME = '*print-generated-python*'
3031

32+
_CATCH = sym.symbol("catch")
33+
_DEF = sym.symbol("def")
34+
_DO = sym.symbol("do")
35+
_FINALLY = sym.symbol("finally")
36+
_FN = sym.symbol("fn*")
37+
_IF = sym.symbol("if")
38+
_IMPORT = sym.symbol("import*")
39+
_INTEROP_CALL = sym.symbol(".")
40+
_INTEROP_PROP = sym.symbol(".-")
41+
_LET = sym.symbol("let*")
42+
_QUOTE = sym.symbol("quote")
43+
_RECUR = sym.symbol("recur")
44+
_THROW = sym.symbol("throw")
45+
_TRY = sym.symbol("try")
46+
_VAR = sym.symbol("var")
47+
_SPECIAL_FORMS = lset.s(_CATCH, _DEF, _DO, _FINALLY, _FN, _IF, _IMPORT,
48+
_INTEROP_CALL, _INTEROP_PROP, _LET, _QUOTE, _RECUR,
49+
_THROW, _TRY, _VAR)
50+
3151

3252
def _new_module(name: str, doc=None) -> types.ModuleType:
3353
"""Create a new empty Basilisp Python module.
@@ -671,9 +691,12 @@ def get_current_ns(ns_var_name: str = _NS_VAR_NAME,
671691
return ns
672692

673693

674-
def resolve_alias(s: sym.Symbol) -> sym.Symbol:
694+
def resolve_alias(s: sym.Symbol, ns: Optional[Namespace] = None) -> sym.Symbol:
675695
"""Resolve the aliased symbol in the current namespace."""
676-
ns = get_current_ns()
696+
if s in _SPECIAL_FORMS:
697+
return s
698+
699+
ns = Maybe(ns).or_else(get_current_ns)
677700
if s.ns is not None:
678701
aliased_ns = ns.get_alias(sym.symbol(s.ns))
679702
if aliased_ns is not None:

basilisp/reader.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
from basilisp.util import Maybe
2626

2727
ns_name_chars = re.compile(r'\w|-|\+|\*|\?|/|\=|\\|!|&|%|>|<')
28-
begin_num_chars = re.compile('[0-9\-]')
28+
begin_num_chars = re.compile(r'[0-9\-]')
2929
num_chars = re.compile('[0-9]')
30-
whitespace_chars = re.compile('[\s,]')
30+
whitespace_chars = re.compile(r'[\s,]')
3131
newline_chars = re.compile('(\r\n|\r|\n)')
3232
fn_macro_args = re.compile('(%)(&|[0-9])?')
33-
unicode_char = re.compile('u(\w+)')
33+
unicode_char = re.compile(r'u(\w+)')
3434

3535
DataReaders = Optional[lmap.Map]
3636
GenSymEnvironment = Dict[str, symbol.Symbol]

tests/compiler_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ def test_inst(ns_var: Var):
725725

726726

727727
def test_regex(ns_var: Var):
728-
assert lcompile('#"\s"') == re.compile('\s')
728+
assert lcompile(r'#"\s"') == re.compile(r'\s')
729729

730730

731731
def test_uuid(ns_var: Var):

tests/reader_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,10 +783,10 @@ def test_inst_reader_literal():
783783

784784
def test_regex_reader_literal():
785785
assert read_str_first('#"hi"') == langutil.regex_from_str("hi")
786-
assert read_str_first('#"\s"') == langutil.regex_from_str(r"\s")
786+
assert read_str_first(r'#"\s"') == langutil.regex_from_str(r"\s")
787787

788788
with pytest.raises(reader.SyntaxError):
789-
read_str_first('#"\y"')
789+
read_str_first(r'#"\y"')
790790

791791

792792
def test_uuid_reader_literal():

tests/runtime_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import basilisp.lang.runtime as runtime
88
import basilisp.lang.seq as lseq
99
import basilisp.lang.set as lset
10+
import basilisp.lang.symbol as sym
1011
import basilisp.lang.vector as vec
1112

1213

@@ -245,3 +246,35 @@ def test_trampoline_args():
245246

246247
args = runtime._TrampolineArgs(True, 1, llist.l(2, 3, 4), 5, 6)
247248
assert (1, llist.l(2, 3, 4), 5, 6) == args.args
249+
250+
251+
@pytest.fixture
252+
def core_ns():
253+
ns_var = runtime.init_ns_var(which_ns=runtime._CORE_NS)
254+
yield ns_var.value
255+
runtime.Namespace.remove(sym.symbol(runtime._CORE_NS))
256+
257+
258+
def test_resolve_alias(core_ns):
259+
for form in runtime._SPECIAL_FORMS:
260+
assert form == runtime.resolve_alias(form)
261+
262+
ns_name = 'resolve-test'
263+
ns_sym = sym.symbol(ns_name)
264+
ns: runtime.Namespace = runtime.set_current_ns(ns_name).value
265+
266+
runtime.Var.intern(ns_sym, sym.symbol('existing-var'), None)
267+
assert sym.symbol('existing-var', ns=ns_name) == runtime.resolve_alias(
268+
sym.symbol('existing-var'), ns=ns)
269+
270+
assert sym.symbol('non-existent-var', ns=ns_name) == runtime.resolve_alias(
271+
sym.symbol('non-existent-var'), ns=ns)
272+
273+
foo_ns_sym = sym.symbol('zux.bar.foo')
274+
foo_ns = runtime.Namespace.get_or_create(foo_ns_sym)
275+
ns.add_alias(sym.symbol('foo'), foo_ns)
276+
assert sym.symbol('aliased-var', ns=foo_ns_sym.name) == runtime.resolve_alias(
277+
sym.symbol('aliased-var', ns='foo'), ns=ns)
278+
279+
assert sym.symbol('non-existent-alias-var', ns='wee.woo') == runtime.resolve_alias(
280+
sym.symbol('non-existent-alias-var', ns='wee.woo'), ns=ns)

0 commit comments

Comments
 (0)