diff --git a/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp b/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp index c82b0ab6d..c493f559a 100644 --- a/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp +++ b/compiler+runtime/include/cpp/jank/analyze/expr/def.hpp @@ -21,12 +21,14 @@ namespace jank::analyze::expr local_frame_ptr frame, bool needs_box, runtime::obj::symbol_ref name, + jtl::option const &meta, jtl::option const &value); runtime::object_ref to_runtime_data() const override; void walk(std::function)> const &f) override; runtime::obj::symbol_ref name{}; + jtl::option meta; /* TODO: Rename to value_expr. */ jtl::option value; }; diff --git a/compiler+runtime/src/cpp/jank/analyze/expr/def.cpp b/compiler+runtime/src/cpp/jank/analyze/expr/def.cpp index ab2f14154..94990d82e 100644 --- a/compiler+runtime/src/cpp/jank/analyze/expr/def.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/expr/def.cpp @@ -9,9 +9,11 @@ namespace jank::analyze::expr local_frame_ptr const frame, bool const needs_box, runtime::obj::symbol_ref const name, + jtl::option const &meta, jtl::option const &value) : expression{ expr_kind, position, frame, needs_box } , name{ name } + , meta{ meta } , value{ value } { } diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index b219a91ee..d358b487c 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -1335,14 +1335,28 @@ namespace jank::analyze qualified_sym = qualified_sym->with_meta(meta_with_doc); } + jtl::option meta{}; + /* Lift this so it can be used during codegen. */ /* TODO: I don't think lifting meta is actually needed anymore. Verify. */ if(qualified_sym->meta.is_some()) { current_frame->lift_constant(qualified_sym->meta.unwrap()); + auto const meta_result{ analyze(qualified_sym->meta.unwrap(), + current_frame, + expression_position::value, + fn_ctx, + true) }; + + if(meta_result.is_err()) + { + return meta_result; + } + + meta = meta_result.expect_ok(); } - return jtl::make_ref(position, current_frame, true, qualified_sym, value_expr); + return jtl::make_ref(position, current_frame, true, qualified_sym, meta, value_expr); } processor::expression_result diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index d606df146..9128ae83c 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -829,16 +829,14 @@ namespace jank::codegen } } - if(expr->name->meta.is_some()) + if(expr->meta.is_some()) { auto const set_meta_fn_type( llvm::FunctionType::get(ctx->builder->getVoidTy(), { ctx->builder->getPtrTy(), ctx->builder->getPtrTy() }, false)); auto const set_meta_fn(llvm_module->getOrInsertFunction("jank_set_meta", set_meta_fn_type)); - - auto const meta_val( - gen_global_from_read_string(strip_source_from_meta(expr->name->meta.unwrap()))); + auto const meta_val(gen(expr->meta.unwrap(), arity)); ctx->builder->CreateCall(set_meta_fn, { ref, meta_val }); } diff --git a/compiler+runtime/src/cpp/jank/evaluate.cpp b/compiler+runtime/src/cpp/jank/evaluate.cpp index cfe9c7b9c..7a3c0ca81 100644 --- a/compiler+runtime/src/cpp/jank/evaluate.cpp +++ b/compiler+runtime/src/cpp/jank/evaluate.cpp @@ -276,7 +276,11 @@ namespace jank::evaluate object_ref eval(expr::def_ref const expr) { auto var(__rt_ctx->intern_var(expr->name).expect_ok()); - var->meta = expr->name->meta; + + if(expr->meta.is_some()) + { + var->meta = some(eval(expr->meta.unwrap())); + } auto const meta(var->meta.unwrap_or(jank_nil)); auto const dynamic(get(meta, __rt_ctx->intern_keyword("dynamic").expect_ok())); diff --git a/compiler+runtime/test/jank/form/def/pass-meta.jank b/compiler+runtime/test/jank/form/def/pass-meta.jank index 83bbe5b91..27b44b0c6 100644 --- a/compiler+runtime/test/jank/form/def/pass-meta.jank +++ b/compiler+runtime/test/jank/form/def/pass-meta.jank @@ -8,4 +8,14 @@ (assert (= one 'one)) (assert (= (:doc (meta #'one)) nil)) +; Analysis with global variables +(def foo 42) +(def ^{:pp #(println foo)} bar 0) +(assert (= ((-> #'bar meta :pp)) 42)) + +; Analysis with local variables. +(let* [foo 42] + (def ^{:pp #(println foo)} bar 0) + (assert (= ((-> #'bar meta :pp)) 42))) + :success