7using namespace std::literals;
18 void stream(fe::Tab&, std::ostream& os)
const final { os <<
"<dummy>"; }
31 Scope&
top() {
return scopes_.back().scope(); }
34 void push() { scopes_.emplace_back(); }
35 void push(
Scope& scope) { scopes_.emplace_back(scope); }
38 assert(scopes_.size() > barrier_);
49 return {std::exchange(barrier_, scopes_.size() - 1), std::exchange(mod_barrier_, mod_stack_.size())};
54 mod_barrier_ = old.
mods;
65 void push_mod(Sym name) { mod_stack_.emplace_back(name); }
67 size_t mod_depth()
const {
return mod_stack_.size() - mod_barrier_; }
71 const Decl*
find(Dbg dbg,
bool quiet =
false) {
74 if (!quiet)
error().e(dbg.loc(),
"`_` never binds an entity and cannot be referenced");
78 for (
auto& frame : scopes_ | std::views::drop(barrier_) | std::views::reverse)
79 if (
auto bind = fe::lookup(frame.scope(), dbg.sym()))
return bind->decl;
82 auto& diag =
error().e(dbg.loc(),
"identifier `{}` not found", dbg.sym());
84 if (dbg.sym().view().starts_with(
'`'))
85 diag.n(
"an infix operator means whatever you bind its escaped name to");
94 for (
auto& frame : scopes_ | std::views::drop(barrier_) | std::views::reverse)
95 if (
auto bind = fe::lookup(frame.scope(), sym);
bind &&
bind->decl->scope())
return bind->decl;
99 void bind(Dbg dbg,
const Decl* decl,
bool rebind =
false,
bool quiet =
false) {
100 bind(dbg, decl, decl->
vis(), rebind, quiet);
104 void bind(Dbg dbg,
const Decl* decl,
Vis vis,
bool rebind =
false,
bool quiet =
false) {
105 if (dbg.is_anon())
return;
109 scope[dbg.sym()] =
Bind{decl, vis};
110 }
else if (
auto [i, ins] = scope.try_emplace(dbg.sym(),
Bind{decl, vis}); !ins) {
111 auto prev = i->second.decl;
113 error().e(dbg.loc(),
"redeclaration of `{}`", dbg).n(prev->dbg().loc(),
"previous declaration here");
114 }
else if (!quiet && !decl->
scope()) {
117 .w(dbg.loc(),
"`{}` shadows a module of the same name", dbg)
118 .n(mod->dbg().loc(),
"module declared here; a later `{}.member` would fail to resolve it",
129 : borrowed_(&scope) {}
131 Scope& scope() {
return borrowed_ ? *borrowed_ : own_; }
135 Scope* borrowed_ =
nullptr;
140 fe::Vector<Frame> scopes_;
141 fe::Vector<Sym> mod_stack_;
142 const Decl* top_decl_ =
nullptr;
144 size_t mod_barrier_ = 0;
160 auto barrier = s.push_barrier(
members());
164 s.pop_barrier(barrier);
176 s.bind(
dbg(),
this, rebind, quiet);
183 s.bind(
dbg(),
this, rebind, quiet);
196 decl_ = s.find(
front(), quiet);
199 for (
auto dbg :
dbgs() | std::views::drop(1)) {
201 auto scope = decl_->scope();
202 auto member = scope ? fe::lookup(*scope, dbg.sym()) :
nullptr;
204 if (!quiet && !decl_->isa<
DummyDecl>()) {
206 s.error().e(dbg.loc(),
"`{}` has no member `{}`", prev.sym(), dbg.sym());
208 auto& err = s.error().e(prev.loc(),
"`{}` is not a module", prev.sym());
209 if (
auto mod = s.find_shadowed_module(prev.sym()))
210 err.n(mod->dbg().loc(),
"a module `{}` exists here but is shadowed by the `{}` in scope",
211 prev.sym(), prev.sym());
217 decl_ = member->decl;
222 if (!quiet) s.error().e(dbg.loc(),
"`{}` is private to its enclosing `mod`", dbg.sym());
232void RuleExpr ::bind(
Scopes& s)
const {
dom()->bind(s); }
242 }
else if (
tag() == Tag::L_f) {
243 s.error().e(
loc(),
"floating-point literal requires a type annotation");
249 for (
auto decl :
decls() | std::views::reverse)
252 for (
auto decl :
decls())
263 if (
auto path =
op().isa(Tag::T_extract) ?
rhs()->isa<PathExpr>() :
nullptr)
264 path->path()->bind(s,
true);
278 if (
ctor->type())
ctor->type()->bind(s);
288 ptrn()->bind(s,
false, quiet);
295 if (codom()) codom()->bind(s);
313 ptrn()->bind(s,
true,
false);
320 ptrn()->bind(s,
false,
false);
344 return loc.src ?
ast.sym(fs::path(
loc.src->path()).stem().string()) :
ast.sym_error();
350 annex.
names = fe::Vector<Sym>(variant->ctors(), [](
const auto& ctor) { return ctor->dbg().sym(); });
352 }
else if (
auto sigma = type->isa<
SigmaExpr>()) {
353 auto tuple = sigma->ptrn();
354 annex.
names = fe::Vector<Sym>(tuple->num_ptrns(), [tuple](
size_t i) { return tuple->field(i); });
360 if (!dbg)
return nullptr;
362 auto depth = s.mod_depth();
364 error().e(dbg.loc(),
"`{}` sits {} `mod` levels deep; an `anx` declaration may nest at most one", dbg, depth);
369 auto tag_s = depth == 0 ? dbg.sym() : s.enclosing_mod();
370 Sym sub_s = depth == 0 ? Sym() : dbg.sym();
372 auto& sym2annex = plugin2sym2annex_[plugin_s];
373 auto tag_id = sym2annex.size();
375 if (plugin_s ==
sym_error())
error().e(dbg.loc(),
"plugin name `{}` is reserved", dbg);
376 if (tag_id > std::numeric_limits<tag_t>::max())
377 error().e(dbg.loc(),
"exceeded maximum number of annexes in current plugin");
380 error().e(dbg.loc(),
"invalid annex name `{}`", dbg);
384 auto [i, fresh] = sym2annex.try_emplace(tag_s,
AnnexInfo{plugin_s, tag_s, (
tag_t)tag_id});
385 auto annex = &i->second;
389 *sub_id = annex->subs.size();
390 auto& aliases = annex->subs.emplace_back();
391 aliases.emplace_back(sub_s);
393 error().e(dbg.loc(),
"annex `{}` must not have a subtag", dbg);
397 if (!fresh) annex->fresh =
false;
406 if (sub >= annex->
subs.size()) {
407 assert(sub == annex->
subs.size());
408 annex->
subs.emplace_back(fe::Vector<Sym>{target});
410 annex->
subs[sub].emplace_back(alias);
419 s.push_mod(mod_.sym());
422 for (
auto name :
names()) {
423 auto dbg = name->dbg();
424 auto& annex = name->annex_ = s.ast().name2annex(s,
dbg, &name->sub_);
426 if (annex && annex->fresh) {
431 s.error().e(
dbg.loc(),
432 "all declarations of annex `{}` must be function types if one of them is (they share one "
433 "annex tag - via mod-nesting or a `tag.(...)` family - and must agree in shape)",
436 if (annex->normalizer.sym() !=
normalizer().sym()) {
438 auto& err = s.error().e(l,
"normalizer mismatch for axm `{}`",
dbg);
439 if (
auto norm = annex->normalizer)
440 err.n(norm.loc(),
"previous normalizer `{}` declared here", norm);
442 err.n(
"initially no normalizer was specified");
446 s.bind(
dbg, name.get(),
vis());
447 for (
auto alias : name->aliases()) {
448 s.bind(alias, name.get(),
vis());
449 if (annex)
add_alias(annex, name->sub_,
dbg.sym(), alias.sym());
465 auto target =
path()->decl();
469 s.error().e(
loc(),
"`{}` aliases `{}`, which is itself an alias; alias chains are not supported",
dbg(),
474 std::tie(annex_, sub_) = target->annex_sub();
476 s.error().e(
loc(),
"`{}` must alias a compiler-exposed (`anx`) declaration",
dbg());
482 plugin !=
ast.sym_error() && plugin != annex_->sym.plugin && s.mod_depth() == 0) {
483 foreign_ =
ast.sym(plugin.str() +
"." +
dbg().sym().str());
484 ast.add_foreign_alias(plugin, {
dbg().sym(), annex_, sub_});
488 add_alias(annex_, sub_, target->dbg().sym(),
dbg().sym());
503 if (
id &&
is_anx())
id->annex_ = s.ast().name2annex(s, id->dbg(), &id->sub_,
value());
513 auto is_top = s.top_decl() ==
this;
514 for (
auto decl :
decls()) {
515 auto _ = s.enter_top_decl(is_top ? decl.get() : s.top_decl());
518 for (
auto decl :
decls()) {
519 auto _ = s.enter_top_decl(is_top ? decl.get() : s.top_decl());
533 .e(
body()->
loc(),
"unsupported expression in a recursive declaration")
534 .n(
"must be a sigma, a variant, or a function type; use `lam`/`con`/`fun` to declare a recursive function");
543 rep_vis_ = s.top_decl() ? s.top_decl()->vis() :
Vis::Pub;
549 if (
ret())
ret()->bind(s, quiet);
558 if (
auto filter =
doms().back()->filter()) {
560 if (pe->tag() == Tag::K_tt &&
ISA(
tag(),
C_DS))
561 s.error().w(filter->loc(),
562 "`tt`-filter superfluous as the last curried function group of a `{}` receives a "
563 "`tt`-filter by default",
565 if (pe->tag() == Tag::K_ff && !
ISA(
tag(),
C_DS))
566 s.error().w(filter->loc(),
567 "`ff`-filter superfluous as the last curried function group of a `{}` receives a "
568 "`ff`-filter by default",
574 if (
ISA(
tag(),
C_CN)) s.error().e(
codom()->
loc(),
"a continuation must not have a codomain");
595 for (
auto decl :
decls()) {
596 auto _ = s.enter_top_decl(decl.get());
603 s.push_mod(
dbg().sym());
612 if (!file())
return nullptr;
614 return file()->scope();
618 auto decl = path()->decl();
619 if (!decl)
return nullptr;
621 auto scope = decl->scope();
622 if (!scope) s.error().e(path()->
loc(),
"`{}` is not a module", path()->back().sym());
627 auto mod = module(s);
632 for (
const auto& [sym, binding] : *mod)
633 if (binding.vis ==
Vis::Pub) s.bind(Dbg(
loc(), sym), binding.decl,
vis(),
false,
true);
639 if (
auto prev = s.find(
dbg(),
true))
640 if (
auto use = prev->isa<
UseDecl>(); use && use->file() ==
file())
return;
648 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, const Expr *type=nullptr)
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
const Expr * type() const
void bind(Scopes &) const override
Dbg dbg() const override
The mod. prefix, if any.
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
Base class of all expressions.
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.
Dbg dbg() const override
The name this Decl introduces; anonymous if it has none.
void bind(Scopes &, bool quiet=false) const
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
const IdDecl * ret() const
void bind_body(Scopes &) const override
const Expr * codom() const
void bind_decl(Scopes &) const override
const NomDecl * nom_sugar() const
The nom of lam I dom+ = nom I = e; I if nom I dom+ = e desugared to this; within e,...
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.
void bind(Scopes &) const override
void bind_body(Scopes &) const override
const Path * path() const
void bind(Scopes &, bool quiet=false) const
const Expr * ret_type() const
virtual void bind(Scopes &, bool quiet=false) 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
void bind(Scopes &) const override
virtual void bind(Scopes &, bool rebind, bool quiet) const =0
virtual void bind_body(Scopes &) const
bool has_mut_body() const
Only such a body is emitted as a mutable, so only it may refer to the declaration itself.
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.
void pop_barrier(Barrier old)
const Decl * dummy() const
const Decl * top_decl() const
Sym enclosing_mod() const
auto enter_top_decl(const Decl *decl)
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)
Barrier push_barrier(Scope &scope)
A file must not see the scope of whoever imports it, so its Scope becomes the new lookup floor.
const Expr * body() const
const IdDecl * index() const
void bind(Scopes &) const override
const Expr * shape() const
Wraps a TuplePtrn as Expr.
const TuplePtrn * ptrn() const
void bind(Scopes &) const override
void bind(Scopes &) const override
const Expr * body() const
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
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).
| ctor_0: type_0 | ... | ctor_n-1: type_n-1; a constructor without a type carries [].
const Ctor * ctor(size_t i) const
void bind(Scopes &) const override
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.
static void add_names(AnnexInfo &annex, const Expr *type)
Records the constructor or field names that type - the body of an annex declaration - spells out.
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.
static Sym loc2plugin(AST &ast, Loc loc)
static void add_alias(AnnexInfo *annex, sub_t sub, Sym target, Sym alias)
Registers alias as a further name of the annex slot target introduced.
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.
fe::Vector< Sym > names
The constructor or field names its variant or sigma declares, by index; an unnamed field is the empty...
bool fields
Are AnnexInfo::names the fields of a sigma rather than the constructors of a variant?
fe::Vector< fe::Vector< Sym > > subs
List of subs which is a list of aliases.