tame/tamer/src/asg/air/meta.rs

137 lines
4.1 KiB
Rust

// ASG IR metavariable 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 metavariable parser.
//!
//! See the [parent module](super) for more information.
use super::{
super::{AsgError, ObjectIndex},
ir::AirBindableMeta,
AirAggregate, AirAggregateCtx,
};
use crate::{
asg::graph::object::Meta, diagnose::Annotate, diagnostic_todo,
parse::prelude::*,
};
/// Metasyntactic variable (metavariable) parser.
#[derive(Debug, PartialEq)]
pub enum AirMetaAggregate {
/// Ready for the start of a metavariable.
Ready,
/// Defining a metavariable.
TplMeta(ObjectIndex<Meta>),
}
impl Display for AirMetaAggregate {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use AirMetaAggregate::*;
match self {
Ready => write!(f, "ready for metavariable"),
TplMeta(_) => write!(f, "defining metavariable"),
}
}
}
impl ParseState for AirMetaAggregate {
type Token = AirBindableMeta;
type Object = ();
type Error = AsgError;
type Context = AirAggregateCtx;
type Super = AirAggregate;
fn parse_token(
self,
tok: Self::Token,
ctx: &mut Self::Context,
) -> TransitionResult<Self::Super> {
use super::ir::{AirBind::*, AirMeta::*};
use AirBindableMeta::*;
use AirMetaAggregate::*;
match (self, tok) {
(Ready, AirMeta(MetaStart(span))) => {
let oi_meta = ctx.asg_mut().create(Meta::new_required(span));
Transition(TplMeta(oi_meta)).incomplete()
}
(TplMeta(oi_meta), AirMeta(MetaEnd(cspan))) => {
oi_meta.close(ctx.asg_mut(), cspan);
Transition(Ready).incomplete()
}
(TplMeta(oi_meta), AirMeta(MetaLexeme(lexeme))) => Transition(
TplMeta(oi_meta.assign_lexeme(ctx.asg_mut(), lexeme)),
)
.incomplete(),
(TplMeta(oi_meta), AirBind(BindIdent(name))) => ctx
.defines(name)
.and_then(|oi_ident| {
oi_ident.bind_definition(ctx.asg_mut(), name, oi_meta)
})
.map(|_| ())
.transition(TplMeta(oi_meta)),
(TplMeta(..), tok @ AirBind(RefIdent(..))) => {
diagnostic_todo!(
vec![tok.note("this token")],
"AirBind in metavar context (param-value)"
)
}
(TplMeta(..), tok @ AirMeta(MetaStart(..))) => {
diagnostic_todo!(
vec![tok.note("this token")],
"AirMeta variant"
)
}
(Ready, tok @ AirMeta(MetaEnd(..))) => {
diagnostic_todo!(
vec![tok.note("this token")],
"unbalanced meta"
)
}
(Ready, tok @ AirMeta(MetaLexeme(..))) => {
diagnostic_todo!(
vec![tok.note("this token")],
"unexpected lexeme"
)
}
// Maybe the bind can be handled by the parent frame.
(Ready, tok @ AirBind(..)) => Transition(Ready).dead(tok),
}
}
fn is_accepting(&self, _: &Self::Context) -> bool {
matches!(self, Self::Ready)
}
}
impl AirMetaAggregate {
pub(super) fn new() -> Self {
Self::Ready
}
}