jank icon indicating copy to clipboard operation
jank copied to clipboard

Start analyzing & evaluating `meta`

Open shantanu-sardesai opened this issue 2 months ago • 1 comments

Description

We should begin analyzing the metadata as well. At present, we store the metadata source directly without proper analysis or evaluation, resulting in the following code executing despite being semantically incorrect:

user=> (def ^{:pp #(println foo)} bar 0)
#'user/bar

user=> (meta bar)
nil

user=> (meta #'bar)
{:jank/source {:file "/var/folders/xd/9v1dcg0d46l7d19830vq0lhc0000gn/T/jank-repl-fYkERF", :start {:offset 27, :line 1, :col 28}, :end {:offset 30, :line 1, :col 31}}, :pp (fn* [] (println foo))}

user=> ((-> #'bar meta :pp))
Uncaught exception: Invalid call with 0 args to: (fn* [] (println foo))

There are two issues being highlighted here:

  1. Although the foo symbol is not in scope during the definition of the bar var, jank does not emit any analysis failure warnings.
  2. Due to lack of evaluation currently the :pp key in the metadata of the bar var contains the source code instead of a compiled function, preventing us from invoking the function.

Goal

Within the scope of this PR I wish to start analyzing the metadata such that the above cases behave as would be expected:

user=> (def ^{:pp #(println foo)} bar 0)
─ analyze/unresolved-symbol ────────────────────────────────────────────────────────────────────────
error: Unable to resolve symbol 'foo'.

─────┬──────────────────────────────────────────────────────────────────────────────────────────────
     │ /var/folders/xd/9v1dcg0d46l7d19830vq0lhc0000gn/T/jank-repl-hKkVT2
─────┼──────────────────────────────────────────────────────────────────────────────────────────────
  1  │ (def ^{:pp #(println foo)} bar 0)
     │                      ^^^ Found here.
─────┴──────────────────────────────────────────────────────────────────────────────────────────────

user=> (def foo 0)
#'user/foo

user=> (def ^{:pp #(println foo)} bar 0)
#'user/bar

user=> (meta #'bar)
{:jank/source {:file "/var/folders/xd/9v1dcg0d46l7d19830vq0lhc0000gn/T/jank-repl-hKkVT2", :start {:offset 27, :line 1, :col 28}, :end {:offset 30, :line 1, :col 31}}, :pp #object [user/user-fn-53 jit_function 0x10ec383f8]}

user=> ((-> #'bar meta :pp))
0
nil

Fixes

Resolves https://github.com/jank-lang/jank/issues/197.

shantanu-sardesai avatar Nov 01 '25 11:11 shantanu-sardesai

Currently the following doesn't work:

(let* [foo 42]
  (def ^{:pp #(println foo)} bar 0)
  (assert (= ((-> #'bar meta :pp)) 42)))

But before I dive deeper I thought best align on where to store the analysis results for meta.

shantanu-sardesai avatar Nov 01 '25 13:11 shantanu-sardesai