5using namespace std::literals;
16 void stream(fe::Tab&, std::ostream& os)
const final { os <<
"<dummy>"; }
29 Scope&
top() {
return scopes_.back().scope(); }
32 void push() { scopes_.emplace_back(); }
33 void push(
Scope& scope) { scopes_.emplace_back(scope); }
36 assert(scopes_.size() > barrier_);
43 auto old = std::exchange(barrier_, scopes_.size() - 1);
56 void push_mod(Sym name) { mod_stack_.emplace_back(name); }
58 size_t mod_depth()
const {
return mod_stack_.size(); }
59 Sym
enclosing_mod()
const {
return mod_stack_.empty() ? Sym() : mod_stack_.back(); }
62 const Decl*
find(Dbg dbg,
bool quiet =
false) {
65 if (!quiet)
error().e(dbg.loc(),
"`_` never binds an entity and cannot be referenced");
69 for (
auto& frame : scopes_ | std::views::drop(barrier_) | std::views::reverse)
70 if (
auto bind = fe::lookup(frame.scope(), dbg.sym()))
return bind->decl;
73 auto& diag =
error().e(dbg.loc(),
"identifier `{}` not found", dbg.sym());
75 if (dbg.sym().view().starts_with(
'`'))
76 diag.n(
"an infix operator means whatever you bind its escaped name to");
85 for (
auto& frame : scopes_ | std::views::drop(barrier_) | std::views::reverse)
86 if (
auto bind = fe::lookup(frame.scope(), sym);
bind &&
bind->decl->scope())
return bind->decl;
90 void bind(Dbg dbg,
const Decl* decl,
bool rebind =
false,
bool quiet =
false) {
91 bind(dbg, decl, decl->
vis(), rebind, quiet);
95 void bind(Dbg dbg,
const Decl* decl,
Vis vis,
bool rebind =
false,
bool quiet =
false) {
96 if (dbg.is_anon())
return;
100 scope[dbg.sym()] =
Bind{decl, vis};
101 }
else if (
auto [i, ins] = scope.try_emplace(dbg.sym(),
Bind{decl, vis}); !ins) {
102 auto prev = i->second.decl;
104 error().e(dbg.loc(),
"redeclaration of `{}`", dbg).n(prev->dbg().loc(),
"previous declaration here");
105 }
else if (!quiet && !decl->
scope()) {
108 .w(dbg.loc(),
"`{}` shadows a module of the same name", dbg)
109 .n(mod->dbg().loc(),
"module declared here; a later `{}.member` would fail to resolve it",
120 : borrowed_(&scope) {}
122 Scope& scope() {
return borrowed_ ? *borrowed_ : own_; }
126 Scope* borrowed_ =
nullptr;
131 fe::Vector<Frame> scopes_;
133 fe::Vector<Sym> mod_stack_;
149 auto barrier = s.push_barrier(
members());
153 s.pop_barrier(barrier);
165 s.bind(
dbg(),
this, rebind, quiet);
170 s.bind(
dbg(),
this, rebind, quiet);
183 decl_ = s.find(
front(), quiet);
186 for (
auto dbg :
dbgs() | std::views::drop(1)) {
188 auto scope = decl_->scope();
189 auto member = scope ? fe::lookup(*scope, dbg.sym()) :
nullptr;
193 s.error().e(dbg.loc(),
"`{}` has no member `{}`", prev.sym(), dbg.sym());
195 auto& err = s.error().e(prev.loc(),
"`{}` is not a module", prev.sym());
196 if (
auto mod = s.find_shadowed_module(prev.sym()))
197 err.n(mod->dbg().loc(),
"a module `{}` exists here but is shadowed by the `{}` in scope",
198 prev.sym(), prev.sym());
204 decl_ = member->decl;
209 if (!quiet) s.error().e(dbg.loc(),
"`{}` is private to its enclosing `mod`", dbg.sym());
219void RuleExpr ::bind(
Scopes& s)
const {
dom()->bind(s); }
230 if (
tag() == Tag::L_f) s.error().e(
loc(),
"floating-point literal requires a type annotation");
236 for (
auto decl :
decls() | std::views::reverse)
239 for (
auto decl :
decls())
248 if (
auto path =
op().isa(Tag::T_extract) ?
rhs()->isa<PathExpr>() :
nullptr)
249 path->path()->bind(s,
true);
268 ptrn()->bind(s,
false, quiet);
269 if (
ret())
ret()->bind(s,
false, quiet);
276 if (
ISA(tag(),
C_CN)) s.error().e(codom()->
loc(),
"a continuation must not have a codomain");
295 ptrn()->bind(s,
true,
false);
301 ptrn()->bind(s,
false,
false);
312 arity()->bind(s,
false,
false);
324 if (!dbg)
return nullptr;
326 auto depth = s.mod_depth();
328 error().e(dbg.loc(),
"`{}` sits {} `mod` levels deep; an `anx` declaration may nest at most one", dbg, depth);
332 auto plugin_s = dbg.loc().src ?
sym(fs::path(dbg.loc().src->path()).stem().string()) :
sym_error();
333 auto tag_s = depth == 0 ? dbg.sym() : s.enclosing_mod();
334 Sym sub_s = depth == 0 ? Sym() : dbg.sym();
336 auto& sym2annex = plugin2sym2annex_[plugin_s];
337 auto tag_id = sym2annex.size();
339 if (plugin_s ==
sym_error())
error().e(dbg.loc(),
"plugin name `{}` is reserved", dbg);
340 if (tag_id > std::numeric_limits<tag_t>::max())
341 error().e(dbg.loc(),
"exceeded maximum number of annexes in current plugin");
344 error().e(dbg.loc(),
"invalid annex name `{}`", dbg);
348 auto [i, fresh] = sym2annex.try_emplace(tag_s,
AnnexInfo{plugin_s, tag_s, (
tag_t)tag_id});
349 auto annex = &i->second;
353 *sub_id = annex->subs.size();
354 auto& aliases = annex->subs.emplace_back();
355 aliases.emplace_back(sub_s);
357 error().e(dbg.loc(),
"annex `{}` must not have a subtag", dbg);
361 if (!fresh) annex->fresh =
false;
368 annex_ = s.ast().name2annex(s,
dbg(), &sub_);
370 if (annex_ && annex_->fresh) {
375 if (pi ^ *annex_->pi)
377 "all declarations of annex `{}` must be function types if one of them is (they share one "
378 "annex tag - via mod-nesting or a `tag.(...)` family - and must agree in shape)",
381 if (annex_->normalizer.sym() !=
normalizer().sym()) {
383 auto& err = s.error().e(l,
"normalizer mismatch for axm `{}`",
dbg());
384 if (
auto norm = annex_->normalizer)
385 err.n(norm.loc(),
"previous normalizer `{}` declared here", norm);
387 err.n(
"initially no normalizer was specified");
395 annex_ = s.ast().name2annex(s,
dbg(), &sub_);
403 auto target =
path()->decl();
407 s.error().e(
loc(),
"`{}` aliases `{}`, which is itself an alias; alias chains are not supported",
dbg(),
412 std::tie(annex_, sub_) = target->annex_sub();
414 s.error().e(
loc(),
"`{}` must alias a compiler-exposed (`anx`) declaration",
dbg());
420 if (sub_ >= annex_->subs.size()) {
421 assert(sub_ == annex_->subs.size());
422 annex_->subs.emplace_back(fe::Vector<Sym>{target->dbg().sym()});
424 annex_->subs[sub_].emplace_back(
dbg().sym());
439 if (
id &&
is_anx())
id->annex_ = s.ast().name2annex(s, id->dbg(), &id->sub_);
443 for (
auto curr =
this; curr; curr = curr->next())
445 for (
auto curr =
this; curr; curr = curr->next())
452 .e(
body()->
loc(),
"unsupported expression in a recursive declaration")
453 .n(
"must be a sigma or a function type; use `lam`/`con`/`fun` to declare a recursive function");
456 if (
is_anx()) annex_ = s.ast().name2annex(s,
dbg(), &sub_);
468 for (
size_t i = 0, e =
num_doms(); i != e; ++i)
471 if (
auto filter =
doms().back()->filter()) {
473 if (pe->tag() == Tag::K_tt &&
ISA(
tag(),
C_DS))
474 s.error().w(filter->loc(),
475 "`tt`-filter superfluous as the last curried function group of a `{}` receives a "
476 "`tt`-filter by default",
478 if (pe->tag() == Tag::K_ff && !
ISA(
tag(),
C_DS))
479 s.error().w(filter->loc(),
480 "`ff`-filter superfluous as the last curried function group of a `{}` receives a "
481 "`ff`-filter by default",
487 if (
ISA(
tag(),
C_CN)) s.error().e(
codom()->
loc(),
"a continuation must not have a codomain");
493 if (
is_anx()) annex_ = s.ast().name2annex(s,
dbg(), &sub_);
505 for (
auto decl :
decls())
511 s.push_mod(
dbg().sym());
520 if (!file())
return nullptr;
522 return file()->scope();
526 auto decl = path()->decl();
527 if (!decl)
return nullptr;
529 auto scope = decl->scope();
530 if (!scope) s.error().e(path()->
loc(),
"`{}` is not a module", path()->back().sym());
535 auto mod = module(s);
540 for (
const auto& [sym, binding] : *mod)
541 if (binding.vis ==
Vis::Pub) s.bind(Dbg(
loc(), sym), binding.decl,
vis(),
false,
true);
547 if (
auto prev = s.find(
dbg(),
true))
548 if (
auto use = prev->isa<
UseDecl>(); use && use->file() ==
file())
return;
556 var()->bind(s,
true,
false);
Owns the arena all AST nodes live in as well as the AnnexInfos of all plugins.
AnnexInfo * name2annex(Scopes &s, Dbg dbg, sub_t *sub_id)
Sym sym_error()
"_error_".
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
void bind(Scopes &) const override
const Path * path() const
AliasDecl(Loc loc, Vis vis, Dbg dbg, Ptr< Path > path)
const Ptrn * ptrn() const
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
void bind(Scopes &, bool rebind, bool quiet) const override
void bind(Scopes &) const override
const Expr * callee() const
void bind(Scopes &) const override
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Expr * type() const
void bind(Scopes &) const override
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Expr * expr() const
void bind(Scopes &) const override
Base class of all declarations; caches the emitted Decl::def.
virtual Vis vis() const
A ValDecl's own Vis; Pub for anything else (Ptrn, Import, ...), which the priv/pub system ignores.
virtual const Scope * scope() const
Non-nullptr if this Decl is a module whose members a Path may walk into.
void stream(fe::Tab &, std::ostream &os) const final
void bind(Scopes &, bool rebind, bool quiet) const override
virtual void bind(Scopes &) const =0
auto implicit_imports() const
Imports the driver was told about via -p; they precede everything the file itself declares.
void bind(Scopes &, bool rebind, bool quiet) const override
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
void bind(Scopes &, bool rebind, bool quiet) const override
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Expr * type() const
void bind(Scopes &) const override
static const InfixExpr * isa_op(Tok::Tag tag, const Expr *expr)
const Expr * callee() const
const Expr * filter() const
void bind(Scopes &, bool quiet=false) const override
void bind_body(Scopes &) const override
const Expr * codom() const
void bind_decl(Scopes &) const override
const Dom * dom(size_t i) const
void bind(Scopes &) const override
const LamDecl * lam() const
void bind(Scopes &) const override
const Expr * value() const
const Ptrn * ptrn() const
const Expr * type() const
void bind(Scopes &) const override
const Expr * body() const
virtual void bind(Scopes &) const
const Ptrn * ptrn() const
void bind(Scopes &) const override
const Expr * scrutinee() const
const Arm * arm(size_t i) const
void bind_decls(Scopes &) const
void bind(Scopes &) const override
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Path * path() const
void bind(Scopes &, bool quiet=false) const
virtual void bind(Scopes &, bool quiet=false) const
const IdPtrn * ret() const
const Ptrn * ptrn() const
dom → codom, Cn dom, or Fn dom → codom depending on PiExpr::tag.
void bind(Scopes &) const override
void bind(Scopes &) const override
virtual void bind(Scopes &, bool rebind, bool quiet) const =0
virtual void bind_body(Scopes &) const
virtual void bind_decl(Scopes &) const
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Expr * body() const
void bind(Scopes &) const override
const Ptrn * ptrn() const
void bind(Scopes &) const override
const Expr * body() const
const Expr * callee() const
void bind(Scopes &) const override
const Expr * guard() const
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
const Decl * dummy() const
Sym enclosing_mod() const
const Decl * find(Dbg dbg, bool quiet=false)
const Decl * find_shadowed_module(Sym sym)
Diagnostic-only: is a module named sym reachable, shadowed by whatever find would actually return?
void bind(Dbg dbg, const Decl *decl, Vis vis, bool rebind=false, bool quiet=false)
Binds decl under dbg with an explicit vis - a splice re-exports under its own visibility.
void bind(Dbg dbg, const Decl *decl, bool rebind=false, bool quiet=false)
size_t push_barrier(Scope &scope)
A file must not see the scope of whoever imports it, so its Scope becomes the new lookup floor.
void pop_barrier(size_t old)
const Expr * body() const
const IdPtrn * arity() const
void bind(Scopes &) const override
const TuplePtrn * ptrn() const
void bind(Scopes &) const override
const Expr * elem(size_t i) const
void bind(Scopes &) const override
void bind(Scopes &, bool rebind, bool quiet) const override
const Ptrn * ptrn(size_t i) const
const Expr * level() const
const Expr * inhabitant() const
void bind(Scopes &) const override
Dbg dbg() const override
The name this decl introduces; anonymous if it splices instead.
UseDecl(Loc loc, Mods mods, Ptr< Path > path, Dbg alias)
use path [as alias|*];; no alias means as *.
bool is_splice() const
as *: splice the module's public members, bind no name.
void bind(Scopes &) const override
const File * file() const
Vis vis() const override
A ValDecl's own Vis; Pub for anything else (Ptrn, Import, ...), which the priv/pub system ignores.
bool is_anx() const override
Whether this decl is registered as a compiler-exposed annex (anx).
Families of Tok::Tag as reusable case labels; include this in *.cpp files only.
#define C_DS
Direct-style binders; all other binders are CPS.
#define C_LIT_TYPED
Literals that already determine their type and hence must not be ascribed one.
#define ISA(tag, family)
Turns such a family into a predicate - a case label is of no use outside of a switch.
#define C_CN
Binders whose domain binds as tight as a Cn, i.e. no codomain follows.
fe::SymMap< Bind > Scope
Maps a name to the Binding introducing it.
Vis
Visibility tier of a ValDecl.
fe::Arena::Ref< const T > Ptr
Nodes live in the AST's Arena and are never destroyed, so this merely points at one.
One name in a Scope: the Decl it introduces and the Vis of this binding.
static std::optional< plugin_t > mangle(std::string_view plugin)
Mangles s into a dense 48-bit representation.
Bookkeeping of an annex introduced by an AxmDecl.