basilisp-lang / basilisp

A Clojure-compatible(-ish) Lisp dialect targeting Python 3.8+
https://basilisp.readthedocs.io
Eclipse Public License 1.0
198 stars 4 forks source link

Macroexpansion exceptions are needlessly chained #852

Closed chrisrink10 closed 5 months ago

chrisrink10 commented 5 months ago

Macroexpansion exceptions get chained at each level of macroexpansion which leads to excessively long exception chains that are are challenging to read. It would be trivially to continue raising the source exception during macroexpansion without adding another cause exception.

Take this example for instance:

(defn f [] (let [a :a] b))

There are 4 exceptions in the chain with only the last being the meaningful:


Traceback (most recent call last):
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2510, in _invoke_ast
    return __handle_macroexpanded_ast(form, expanded, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2455, in __handle_macroexpanded_ast
    expanded_ast = _analyze_form(expanded, ctx)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 712, in _analyze_form
    return cast(T_node, f(form, ctx).fix_missing_locations(form_loc))
                        ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3250, in _list_node
    return handle_special_form(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2587, in _let_ast
    stmts, ret = _body_ast(let_body, ctx)
                 ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 750, in _body_ast
    body_expr = _analyze_form(ret_form, ctx)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 712, in _analyze_form
    return cast(T_node, f(form, ctx).fix_missing_locations(form_loc))
                        ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3558, in _symbol_node
    return _resolve_sym(ctx, form)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3536, in _resolve_sym
    return __resolve_bare_symbol(ctx, form)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3509, in __resolve_bare_symbol
    raise ctx.AnalyzerException(
basilisp.lang.compiler.exception.CompilerException: unable to resolve symbol 'b' in this context {:col 24 :end-col 25 :file "<REPL Input>" :line 1 :end-line 1 :phase :analyzing :form b}

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2510, in _invoke_ast
    return __handle_macroexpanded_ast(form, expanded, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2455, in __handle_macroexpanded_ast
    expanded_ast = _analyze_form(expanded, ctx)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 710, in _analyze_form
    return f(form, ctx)
           ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3250, in _list_node
    return handle_special_form(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 839, in with_meta
    descriptor = gen_node(form, ctx)
                 ^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2136, in _fn_ast
    __fn_method_ast(
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 1963, in __fn_method_ast
    stmts, ret = _body_ast(form.rest, ctx)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 750, in _body_ast
    body_expr = _analyze_form(ret_form, ctx)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 712, in _analyze_form
    return cast(T_node, f(form, ctx).fix_missing_locations(form_loc))
                        ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3256, in _list_node
    return _invoke_ast(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2512, in _invoke_ast
    raise CompilerException(
basilisp.lang.compiler.exception.CompilerException: error occurred during macroexpansion {:col 12 :end-col 26 :file "<REPL Input>" :line 1 :end-line 1 :phase :macroexpansion :form (let [a :a] b)}

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2510, in _invoke_ast
    return __handle_macroexpanded_ast(form, expanded, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2455, in __handle_macroexpanded_ast
    expanded_ast = _analyze_form(expanded, ctx)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 712, in _analyze_form
    return cast(T_node, f(form, ctx).fix_missing_locations(form_loc))
                        ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3250, in _list_node
    return handle_special_form(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 1007, in _def_ast
    init = _analyze_form(runtime.nth(form, init_idx), ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 710, in _analyze_form
    return f(form, ctx)
           ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3256, in _list_node
    return _invoke_ast(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2512, in _invoke_ast
    raise CompilerException(
basilisp.lang.compiler.exception.CompilerException: error occurred during macroexpansion {:file "<REPL Input>" :phase :macroexpansion :form (basilisp.core/fn f [] (let [a :a] b))}

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/christopher/Projects/basilisp/src/basilisp/cli.py", line 446, in repl
    result = eval_str(lsrc, ctx, ns, eof)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/cli.py", line 46, in eval_str
    last = compiler.compile_and_exec_form(form, ctx, ns)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/__init__.py", line 168, in compile_and_exec_form
    lisp_ast = analyze_form(ctx.analyzer_context, form)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3826, in analyze_form
    return _analyze_form(form, ctx).assoc(top_level=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/.pyenv/versions/3.12.1/lib/python3.12/functools.py", line 909, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 712, in _analyze_form
    return cast(T_node, f(form, ctx).fix_missing_locations(form_loc))
                        ^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 3256, in _list_node
    return _invoke_ast(form, ctx)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/christopher/Projects/basilisp/src/basilisp/lang/compiler/analyzer.py", line 2512, in _invoke_ast
    raise CompilerException(
basilisp.lang.compiler.exception.CompilerException: error occurred during macroexpansion {:col 1 :end-col 27 :file "<REPL Input>" :line 1 :end-line 1 :phase :macroexpansion :form (defn f [] (let [a :a] b))}```