tamer: asg::air: Include package in opaque identifier scope
This was the remaining of my stashed changes that I had mentioned in a previous commit, but is accomplished differently than I had prototyped. My initial approach was a bit too klugey: to accept as an argument in various scope contexts the active parser, as if it were the top stack frame. This was prototyped before the `AirPkgAggregate` parser was even created. So we've since created a Pkg parser and now an opaque parser for opaque idents. There may be other opaque objects in the future. Because of this change, the parent `AirPkgAggregate` gets stored on the stack and just naturally becomes part of the lexical scope determination, and so everything Just Works! This commit was _supposed_ to be moving the index from `Asg` onto `AirAggregateCtx`, but I wasn't able to do that because that context is re-created for each package import currently. DEV-13162main
parent
e266d42c48
commit
92214c7e05
|
@ -40,6 +40,7 @@ use super::{
|
|||
Asg, AsgError, Expr, Ident, ObjectIndex,
|
||||
};
|
||||
use crate::{
|
||||
diagnose::Annotate,
|
||||
f::Functor,
|
||||
parse::{prelude::*, StateStack},
|
||||
span::Span,
|
||||
|
@ -55,9 +56,11 @@ mod ir;
|
|||
pub use ir::Air;
|
||||
|
||||
mod expr;
|
||||
mod opaque;
|
||||
mod pkg;
|
||||
mod tpl;
|
||||
use expr::AirExprAggregate;
|
||||
use opaque::AirOpaqueAggregate;
|
||||
use pkg::AirPkgAggregate;
|
||||
use tpl::AirTplAggregate;
|
||||
|
||||
|
@ -94,6 +97,12 @@ pub enum AirAggregate {
|
|||
/// parented to this template rather than the parent [`Pkg`].
|
||||
/// See [`Air::TplStart`] for more information.
|
||||
PkgTpl(AirTplAggregate),
|
||||
|
||||
/// Parsing opaque objects.
|
||||
///
|
||||
/// This parser is intended for loading declarations from object files
|
||||
/// without loading their corresponding definitions.
|
||||
PkgOpaque(AirOpaqueAggregate),
|
||||
}
|
||||
|
||||
impl Display for AirAggregate {
|
||||
|
@ -110,7 +119,10 @@ impl Display for AirAggregate {
|
|||
write!(f, "defining a package expression: {expr}")
|
||||
}
|
||||
PkgTpl(tpl) => {
|
||||
write!(f, "building a template: {tpl}",)
|
||||
write!(f, "building a template: {tpl}")
|
||||
}
|
||||
PkgOpaque(opaque) => {
|
||||
write!(f, "loading opaque objects: {opaque}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +146,12 @@ impl From<AirTplAggregate> for AirAggregate {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AirOpaqueAggregate> for AirAggregate {
|
||||
fn from(st: AirOpaqueAggregate) -> Self {
|
||||
Self::PkgOpaque(st)
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseState for AirAggregate {
|
||||
type Token = Air;
|
||||
type Object = ();
|
||||
|
@ -164,12 +182,18 @@ impl ParseState for AirAggregate {
|
|||
(st, AirTodo(Todo(_))) => Transition(st).incomplete(),
|
||||
|
||||
// Package
|
||||
(st @ (Root(..) | PkgExpr(..) | PkgTpl(..)), tok @ AirPkg(..)) => {
|
||||
ctx.ret_or_transfer(st, tok, AirPkgAggregate::new())
|
||||
}
|
||||
//
|
||||
// Note that `ret_or_transfer` will return from the active frame
|
||||
// if it is in an accepting state,
|
||||
// and so encountering a properly nested `PkgClose` will pop
|
||||
// frames off of the stack until reaching the still-active
|
||||
// parent package frame.
|
||||
(
|
||||
st @ (Root(..) | PkgExpr(..) | PkgTpl(..) | PkgOpaque(..)),
|
||||
tok @ AirPkg(..),
|
||||
) => ctx.ret_or_transfer(st, tok, AirPkgAggregate::new()),
|
||||
(Pkg(pkg), AirPkg(etok)) => ctx.proxy(pkg, etok),
|
||||
(Pkg(pkg), AirBind(etok)) => ctx.proxy(pkg, etok),
|
||||
(Pkg(pkg), AirIdent(etok)) => ctx.proxy(pkg, etok),
|
||||
(Pkg(pkg), AirDoc(etok)) => ctx.proxy(pkg, etok),
|
||||
|
||||
// Expression
|
||||
|
@ -188,6 +212,36 @@ impl ParseState for AirAggregate {
|
|||
(PkgTpl(tplst), AirBind(ttok)) => ctx.proxy(tplst, ttok),
|
||||
(PkgTpl(tplst), AirDoc(ttok)) => ctx.proxy(tplst, ttok),
|
||||
|
||||
// Opaque
|
||||
//
|
||||
// By having opaque object loading be its _own_ child parser,
|
||||
// we ensure that the active package frame becomes held on the
|
||||
// stack before loading e.g. opaque identifiers.
|
||||
// Since scope is determined by stack frames,
|
||||
// this has the effect of ensuring that the package `st`
|
||||
// becomes included in the identifier's scope.
|
||||
(st @ Pkg(_), tok @ AirIdent(..)) => {
|
||||
ctx.ret_or_transfer(st, tok, AirOpaqueAggregate::new())
|
||||
}
|
||||
(PkgOpaque(opaque), AirIdent(otok)) => ctx.proxy(opaque, otok),
|
||||
(
|
||||
PkgOpaque(_),
|
||||
tok @ (AirExpr(..) | AirBind(..) | AirTpl(..) | AirDoc(..)),
|
||||
) => {
|
||||
// This is simply not expected at the time of writing,
|
||||
// since this is used for importing object files.
|
||||
crate::diagnostic_panic!(
|
||||
vec![
|
||||
tok.span()
|
||||
.internal_error("this is not an opaque identifier"),
|
||||
tok.span().help(
|
||||
"this may represent a problem with an object file"
|
||||
)
|
||||
],
|
||||
"expected opaque identifier, found {tok}",
|
||||
);
|
||||
}
|
||||
|
||||
(
|
||||
st @ Root(_),
|
||||
tok @ (AirExpr(..) | AirBind(..) | AirTpl(..) | AirDoc(..)),
|
||||
|
@ -226,6 +280,7 @@ impl AirAggregate {
|
|||
Pkg(st) => st.is_accepting(ctx),
|
||||
PkgExpr(st) => st.is_accepting(ctx),
|
||||
PkgTpl(st) => st.is_accepting(ctx),
|
||||
PkgOpaque(st) => st.is_accepting(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,6 +298,7 @@ impl AirAggregate {
|
|||
Pkg(st) => st.is_accepting(ctx),
|
||||
PkgExpr(st) => st.is_accepting(ctx),
|
||||
PkgTpl(st) => st.is_accepting(ctx),
|
||||
PkgOpaque(st) => st.is_accepting(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,6 +335,12 @@ impl AirAggregate {
|
|||
// Templates must therefore serve as containers for identifiers
|
||||
// bound therein.
|
||||
PkgTpl(tplst) => tplst.active_tpl_oi().map(Into::into),
|
||||
|
||||
// Loading of opaque objects happens within the context of the
|
||||
// parent frame.
|
||||
// At the time of writing,
|
||||
// that is only a package.
|
||||
PkgOpaque(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +380,10 @@ impl AirAggregate {
|
|||
// This is not an environment.
|
||||
(Uninit, kind) => kind,
|
||||
|
||||
// This is just a parsing state,
|
||||
// not an environment.
|
||||
(PkgOpaque(_), kind) => kind,
|
||||
|
||||
// Hidden is a fixpoint.
|
||||
(_, kind @ Hidden(_)) => kind,
|
||||
|
||||
|
@ -563,6 +629,11 @@ impl AirAggregateCtx {
|
|||
// since they may expand into an context where they are not
|
||||
// considered to be dangling.
|
||||
PkgTpl(tplst) => tplst.active_tpl_oi().map(Into::into),
|
||||
|
||||
// Expressions are transparent definitions,
|
||||
// not opaque,
|
||||
// and so not permitted in this context.
|
||||
PkgOpaque(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -579,6 +650,13 @@ impl AirAggregateCtx {
|
|||
Pkg(pkg_st) => pkg_st.active_pkg_oi().map(Into::into),
|
||||
PkgExpr(exprst) => exprst.active_expr_oi().map(Into::into),
|
||||
PkgTpl(tplst) => tplst.active_tpl_oi().map(Into::into),
|
||||
|
||||
// Templates _could_ conceptually expand into opaque objects,
|
||||
// but the source language of TAME provides no mechanism to do
|
||||
// such a thing,
|
||||
// and so it'd be best to leave this alone unless it's
|
||||
// actually needed.
|
||||
PkgOpaque(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -665,7 +743,6 @@ impl AirAggregateCtx {
|
|||
let Self { asg, stack, .. } = self;
|
||||
let oi_ident = asg.create(Ident::declare(name));
|
||||
|
||||
// TODO: This will need the active OI to support `AirIdent`s
|
||||
stack
|
||||
.iter()
|
||||
.rev()
|
||||
|
|
|
@ -824,13 +824,13 @@ sum_ir! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Package definitions also capable of being loaded from object files.
|
||||
/// Package definitions.
|
||||
///
|
||||
/// It is assumed that tokens that may appear as the body of a package,
|
||||
/// with the exception of [`AirIdent`],
|
||||
/// will preempt the package parser,
|
||||
/// and so are not included here.
|
||||
pub sum enum AirLoadablePkg = AirPkg | AirBind | AirIdent | AirDoc;
|
||||
pub sum enum AirBindablePkg = AirPkg | AirBind | AirDoc;
|
||||
|
||||
/// Expressions that are able to be bound to identifiers.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// ASG IR opaque object parsing
|
||||
//
|
||||
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
||||
//
|
||||
// This file is part of TAME.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! AIR opaque object parser.
|
||||
//!
|
||||
//! This parser exists primarily to ensure that the parent frame can be held
|
||||
//! on the stack and considered in lexical scoping operations.
|
||||
//!
|
||||
//! See the [parent module](super) for more information.
|
||||
|
||||
use super::{super::AsgError, ir::AirIdent, AirAggregate, AirAggregateCtx};
|
||||
use crate::parse::prelude::*;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AirOpaqueAggregate {
|
||||
Ready,
|
||||
}
|
||||
|
||||
impl Display for AirOpaqueAggregate {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Ready => {
|
||||
write!(f, "ready for opaque object")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseState for AirOpaqueAggregate {
|
||||
type Token = AirIdent;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
type Context = AirAggregateCtx;
|
||||
type Super = AirAggregate;
|
||||
|
||||
fn parse_token(
|
||||
self,
|
||||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self::Super> {
|
||||
use super::ir::AirIdent::*;
|
||||
use AirOpaqueAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
(Ready, IdentDecl(name, kind, src)) => ctx
|
||||
.lookup_lexical_or_missing(name)
|
||||
.declare(ctx.asg_mut(), name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Ready),
|
||||
|
||||
(Ready, IdentExternDecl(name, kind, src)) => ctx
|
||||
.lookup_lexical_or_missing(name)
|
||||
.declare_extern(ctx.asg_mut(), name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Ready),
|
||||
|
||||
(Ready, IdentDep(name, dep)) => {
|
||||
let oi_from = ctx.lookup_lexical_or_missing(name);
|
||||
let oi_to = ctx.lookup_lexical_or_missing(dep);
|
||||
oi_from.add_opaque_dep(ctx.asg_mut(), oi_to);
|
||||
|
||||
Transition(Ready).incomplete()
|
||||
}
|
||||
|
||||
(Ready, IdentFragment(name, text)) => ctx
|
||||
.lookup_lexical_or_missing(name)
|
||||
.set_fragment(ctx.asg_mut(), text)
|
||||
.map(|_| ())
|
||||
.transition(Ready),
|
||||
|
||||
(Ready, IdentRoot(name)) => {
|
||||
ctx.lookup_lexical_or_missing(name).root(ctx.asg_mut());
|
||||
|
||||
Transition(Ready).incomplete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_accepting(&self, _: &Self::Context) -> bool {
|
||||
matches!(self, Self::Ready)
|
||||
}
|
||||
}
|
||||
|
||||
impl AirOpaqueAggregate {
|
||||
pub(super) fn new() -> Self {
|
||||
Self::Ready
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
use super::{
|
||||
super::{graph::object::Pkg, AsgError, ObjectIndex},
|
||||
ir::AirLoadablePkg,
|
||||
ir::AirBindablePkg,
|
||||
AirAggregate, AirAggregateCtx,
|
||||
};
|
||||
use crate::{diagnose::Annotate, diagnostic_todo, parse::prelude::*};
|
||||
|
@ -59,7 +59,7 @@ impl Display for AirPkgAggregate {
|
|||
}
|
||||
|
||||
impl ParseState for AirPkgAggregate {
|
||||
type Token = AirLoadablePkg;
|
||||
type Token = AirBindablePkg;
|
||||
type Object = ();
|
||||
type Error = AsgError;
|
||||
type Context = AirAggregateCtx;
|
||||
|
@ -70,8 +70,8 @@ impl ParseState for AirPkgAggregate {
|
|||
tok: Self::Token,
|
||||
ctx: &mut Self::Context,
|
||||
) -> crate::parse::TransitionResult<Self::Super> {
|
||||
use super::ir::{AirBind::*, AirDoc::*, AirIdent::*, AirPkg::*};
|
||||
use AirLoadablePkg::*;
|
||||
use super::ir::{AirBind::*, AirDoc::*, AirPkg::*};
|
||||
use AirBindablePkg::*;
|
||||
use AirPkgAggregate::*;
|
||||
|
||||
match (self, tok) {
|
||||
|
@ -128,45 +128,12 @@ impl ParseState for AirPkgAggregate {
|
|||
.map(|_| ())
|
||||
.transition(Toplevel(oi_pkg)),
|
||||
|
||||
(Toplevel(oi_pkg), AirIdent(IdentDecl(name, kind, src))) => ctx
|
||||
.lookup_lexical_or_missing(name)
|
||||
.declare(ctx.asg_mut(), name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Toplevel(oi_pkg)),
|
||||
|
||||
(Toplevel(oi_pkg), AirIdent(IdentExternDecl(name, kind, src))) => {
|
||||
ctx.lookup_lexical_or_missing(name)
|
||||
.declare_extern(ctx.asg_mut(), name, kind, src)
|
||||
.map(|_| ())
|
||||
.transition(Toplevel(oi_pkg))
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), AirIdent(IdentDep(name, dep))) => {
|
||||
let oi_from = ctx.lookup_lexical_or_missing(name);
|
||||
let oi_to = ctx.lookup_lexical_or_missing(dep);
|
||||
oi_from.add_opaque_dep(ctx.asg_mut(), oi_to);
|
||||
|
||||
Transition(Toplevel(oi_pkg)).incomplete()
|
||||
}
|
||||
|
||||
(Toplevel(oi_pkg), AirIdent(IdentFragment(name, text))) => ctx
|
||||
.lookup_lexical_or_missing(name)
|
||||
.set_fragment(ctx.asg_mut(), text)
|
||||
.map(|_| ())
|
||||
.transition(Toplevel(oi_pkg)),
|
||||
|
||||
(Toplevel(oi_pkg), AirIdent(IdentRoot(name))) => {
|
||||
ctx.lookup_lexical_or_missing(name).root(ctx.asg_mut());
|
||||
|
||||
Transition(Toplevel(oi_pkg)).incomplete()
|
||||
}
|
||||
|
||||
(Ready, AirPkg(PkgEnd(span))) => {
|
||||
Transition(Ready).err(AsgError::InvalidPkgEndContext(span))
|
||||
}
|
||||
|
||||
// Token may refer to a parent context.
|
||||
(st @ Ready, tok @ (AirBind(..) | AirIdent(..) | AirDoc(..))) => {
|
||||
(st @ Ready, tok @ (AirBind(..) | AirDoc(..))) => {
|
||||
Transition(st).dead(tok)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,13 +361,13 @@ test_scopes! {
|
|||
#[test]
|
||||
opaque_a == [
|
||||
(Root, S0, Visible),
|
||||
// TODO: (Pkg, m(S1, S3), Visible),
|
||||
(Pkg, m(S1, S3), Visible),
|
||||
];
|
||||
|
||||
#[test]
|
||||
opaque_b == [
|
||||
(Root, S0, Visible),
|
||||
// TODO: (Pkg, m(S4, S6), Visible),
|
||||
(Pkg, m(S4, S6), Visible),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue