tamer: asg::graph::object: New Tpl object

There's quite a bit of boilerplate here that'll eventually need factoring
out.  But it's also clear that it is somewhat onerous to add new object
types.

Note that a good chunk of this burden is _intentional_, via exhaustiveness
checks---adding a new type of object is an exceptional occurrence (well, in
principle, but we haven't added them all yet, so it'll be more common
initially), and we'd rather be safe to ensure that everything is properly
considering how that new type of object interacts with it.

Let's not confuse coupling with safety---the latter causes a burden because
of the former, not because of itself; it provides a service to us.

But, nonetheless, we'll want to reduce this burden somewhat since there are
a number more to add.

DEV-13708
main
Mike Gerwitz 2023-02-24 23:54:01 -05:00
parent 98fcb115da
commit 454b91dfce
9 changed files with 149 additions and 4 deletions

View File

@ -122,6 +122,7 @@ pub mod ident;
pub mod pkg;
mod rel;
pub mod root;
pub mod tpl;
pub use expr::Expr;
pub use ident::Ident;
@ -131,6 +132,7 @@ pub use rel::{
ObjectRelatable,
};
pub use root::Root;
pub use tpl::Tpl;
/// An object on the ASG.
///
@ -161,6 +163,9 @@ pub enum Object<T: ObjectInner = OnlyObjectInner> {
///
/// An expression may optionally be named by one or more [`Ident`]s.
Expr(T::Expr),
/// A template definition.
Tpl(T::Tpl),
}
/// The collection of potential objects of [`Object`].
@ -169,6 +174,7 @@ pub trait ObjectInner {
type Pkg;
type Ident;
type Expr;
type Tpl;
}
/// An [`ObjectInner`] where each constituent type implements [`Display`].
@ -177,7 +183,8 @@ where
<Self as ObjectInner>::Root: Display,
<Self as ObjectInner>::Pkg: Display,
<Self as ObjectInner>::Ident: Display,
<Self as ObjectInner>::Expr: Display;
<Self as ObjectInner>::Expr: Display,
<Self as ObjectInner>::Tpl: Display;
/// Concrete [`ObjectKind`]s and nothing more.
#[derive(Debug, PartialEq)]
@ -188,6 +195,7 @@ impl ObjectInner for OnlyObjectInner {
type Pkg = Pkg;
type Ident = Ident;
type Expr = Expr;
type Tpl = Tpl;
}
/// References to [`OnlyObjectInner`].
@ -202,6 +210,7 @@ impl<'a> ObjectInner for RefObjectInner<'a> {
type Pkg = &'a Pkg;
type Ident = &'a Ident;
type Expr = &'a Expr;
type Tpl = &'a Tpl;
}
/// A [`RefObjectInner`] paired with an [`ObjectIndex`] representing it.
@ -221,6 +230,7 @@ impl<'a> ObjectInner for OiPairObjectInner<'a> {
type Pkg = (&'a Pkg, ObjectIndex<Pkg>);
type Ident = (&'a Ident, ObjectIndex<Ident>);
type Expr = (&'a Expr, ObjectIndex<Expr>);
type Tpl = (&'a Tpl, ObjectIndex<Tpl>);
}
impl<T: DisplayableObjectInner> Display for Object<T> {
@ -230,6 +240,7 @@ impl<T: DisplayableObjectInner> Display for Object<T> {
Self::Pkg(pkg) => Display::fmt(pkg, f),
Self::Ident(ident) => Display::fmt(ident, f),
Self::Expr(expr) => Display::fmt(expr, f),
Self::Tpl(tpl) => Display::fmt(tpl, f),
}
}
}
@ -245,6 +256,7 @@ macro_rules! map_object {
Object::Pkg($inner) => Object::Pkg($map),
Object::Ident($inner) => Object::Ident($map),
Object::Expr($inner) => Object::Expr($map),
Object::Tpl($inner) => Object::Tpl($map),
}
};
}
@ -256,6 +268,7 @@ impl Object<OnlyObjectInner> {
Self::Pkg(pkg) => pkg.span(),
Self::Ident(ident) => ident.span(),
Self::Expr(expr) => expr.span(),
Self::Tpl(tpl) => tpl.span(),
}
}
@ -375,6 +388,12 @@ impl From<Expr> for Object {
}
}
impl From<Tpl> for Object {
fn from(tpl: Tpl) -> Self {
Self::Tpl(tpl)
}
}
impl From<Object> for Root {
/// Narrow an object into an [`Root`],
/// panicing if the object is not of that type.
@ -419,6 +438,17 @@ impl From<Object> for Expr {
}
}
impl From<Object> for Tpl {
/// Narrow an object into an [`Expr`],
/// panicing if the object is not of that type.
fn from(val: Object) -> Self {
match val {
Object::Tpl(tpl) => tpl,
_ => val.narrowing_panic("a template"),
}
}
}
impl AsRef<Object> for Object {
fn as_ref(&self) -> &Object {
self
@ -461,6 +491,15 @@ impl AsRef<Expr> for Object {
}
}
impl AsRef<Tpl> for Object {
fn as_ref(&self) -> &Tpl {
match self {
Object::Tpl(ref tpl) => tpl,
_ => self.narrowing_panic("a template"),
}
}
}
/// An [`Object`]-compatbile entity.
///
/// See [`ObjectIndex`] for more information.

View File

@ -257,6 +257,7 @@ impl ObjectRelatable for Expr {
ObjectRelTy::Pkg => None,
ObjectRelTy::Ident => Some(ExprRel::Ident(oi.must_narrow_into())),
ObjectRelTy::Expr => Some(ExprRel::Expr(oi.must_narrow_into())),
ObjectRelTy::Tpl => None,
}
}
}

View File

@ -1022,6 +1022,7 @@ impl ObjectRelatable for Ident {
ObjectRelTy::Pkg => None,
ObjectRelTy::Ident => Some(IdentRel::Ident(oi.must_narrow_into())),
ObjectRelTy::Expr => Some(IdentRel::Expr(oi.must_narrow_into())),
ObjectRelTy::Tpl => None,
}
}
}

View File

@ -100,6 +100,7 @@ impl ObjectRelatable for Pkg {
ObjectRelTy::Pkg => None,
ObjectRelTy::Ident => Some(PkgRel::Ident(oi.must_narrow_into())),
ObjectRelTy::Expr => None,
ObjectRelTy::Tpl => None,
}
}
}

View File

@ -23,7 +23,11 @@
use super::{
Expr, Ident, Object, ObjectIndex, ObjectKind, OiPairObjectInner, Pkg, Root,
};
use crate::{asg::Asg, f::Functor, span::Span};
use crate::{
asg::{graph::object::Tpl, Asg},
f::Functor,
span::Span,
};
use std::fmt::Display;
/// Object types corresponding to variants in [`Object`].
@ -41,6 +45,7 @@ pub enum ObjectRelTy {
Pkg,
Ident,
Expr,
Tpl,
}
impl Display for ObjectRelTy {
@ -177,7 +182,7 @@ impl<S> DynObjectRel<S, ObjectIndex<Object>> {
}
}
ty_cross_edge!(Root, Pkg, Ident, Expr)
ty_cross_edge!(Root, Pkg, Ident, Expr, Tpl)
}
}

View File

@ -84,6 +84,7 @@ impl ObjectRelatable for Root {
ObjectRelTy::Pkg => Some(RootRel::Pkg(oi.must_narrow_into())),
ObjectRelTy::Ident => Some(RootRel::Ident(oi.must_narrow_into())),
ObjectRelTy::Expr => None,
ObjectRelTy::Tpl => None,
}
}
}

View File

@ -0,0 +1,95 @@
// Templates represented on the ASG
//
// 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/>.
//! Templates on the ASG.
use std::fmt::Display;
use super::{
Object, ObjectIndex, ObjectRel, ObjectRelFrom, ObjectRelTy, ObjectRelatable,
};
use crate::span::Span;
/// Template.
#[derive(Debug, PartialEq, Eq)]
pub struct Tpl;
impl Tpl {
pub fn span(&self) -> Span {
todo!("Tpl::span")
}
}
impl Display for Tpl {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "template")
}
}
/// Subset of [`ObjectKind`]s that are valid targets for edges from
/// [`Tpl`].
///
/// See [`ObjectRel`] for more information.
#[derive(Debug, PartialEq, Eq)]
pub enum TplRel {
// TODO
}
impl ObjectRel<Tpl> for TplRel {
fn narrow<OB: ObjectRelFrom<Tpl> + ObjectRelatable>(
self,
) -> Option<ObjectIndex<OB>> {
None
}
/// Whether this is a cross edge to another tree.
///
/// An expression is inherently a tree,
/// however it may contain references to other identifiers which
/// represent their own trees.
/// Any [`Ident`] reference is a cross edge.
fn is_cross_edge(&self) -> bool {
false
}
}
impl ObjectRelatable for Tpl {
type Rel = TplRel;
fn rel_ty() -> ObjectRelTy {
ObjectRelTy::Tpl
}
fn new_rel_dyn(
ty: ObjectRelTy,
_oi: ObjectIndex<Object>,
) -> Option<TplRel> {
match ty {
ObjectRelTy::Root => None,
ObjectRelTy::Pkg => None,
ObjectRelTy::Ident => None,
ObjectRelTy::Expr => None,
ObjectRelTy::Tpl => None,
}
}
}
impl ObjectIndex<Tpl> {
// TODO
}

View File

@ -185,6 +185,8 @@ impl<'a> TreeContext<'a> {
self.emit_expr(expr, paired_rel.source(), depth)
}
Object::Tpl((tpl, oi)) => todo!("tpl: {tpl:?}, {oi:?}"),
Object::Root(..) => diagnostic_unreachable!(
vec![],
"tree walk is not expected to emit Root",

View File

@ -72,7 +72,7 @@ where
Object::Root(_) => (),
Object::Ident(ident) => dest.push(ident)?,
obj @ (Object::Pkg(_) | Object::Expr(_)) => {
obj @ (Object::Pkg(_) | Object::Expr(_) | Object::Tpl(_)) => {
diagnostic_unreachable!(
obj.internal_error(
"this object should not be present on the graph"