tamer: asg::graph::object::xir: POC use of token stack
Just some final POC setup for how this'll work; it's nothing significant. This just emits an `@xmlns` on the `package` element to demonstrate use of the stack. With that, it's time to formalize this. I also need to document at some point why I choose to use `ArrayVec` still over `Vec`---it's not a microoptimization. It's intended to simplify the runtime to keep execution simple with fewer code paths and make it more amenable to analysis. Memory allocation is a pretty complex thing and muddies execution. It's also another point of failure, though practically speaking, I'm not worried about that---this is replacing a system that consumes many GiB of memory (XSLT-based compiler) with one that consumes 10s of MiB. DEV-13708main
parent
7efd08a699
commit
716247483f
|
@ -29,21 +29,22 @@
|
||||||
//! but may be useful in the future for concrete code suggestions/fixes,
|
//! but may be useful in the future for concrete code suggestions/fixes,
|
||||||
//! or observing template expansions.
|
//! or observing template expansions.
|
||||||
|
|
||||||
use std::{convert::Infallible, fmt::Display, marker::PhantomData};
|
use super::ObjectRelTy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
asg::{visit::TreeWalkRel, Asg},
|
asg::{visit::TreeWalkRel, Asg},
|
||||||
diagnose::Annotate,
|
diagnose::Annotate,
|
||||||
diagnostic_unreachable,
|
diagnostic_unreachable,
|
||||||
parse::prelude::*,
|
parse::prelude::*,
|
||||||
|
sym::st::raw::URI_LV_RATER,
|
||||||
xir::{
|
xir::{
|
||||||
|
attr::Attr,
|
||||||
flat::{Text, XirfToken},
|
flat::{Text, XirfToken},
|
||||||
st::qname::QN_PACKAGE,
|
st::qname::{QN_PACKAGE, QN_XMLNS},
|
||||||
OpenSpan,
|
OpenSpan,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
use super::ObjectRelTy;
|
use std::{convert::Infallible, fmt::Display, marker::PhantomData};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum AsgTreeToXirf<'a> {
|
pub enum AsgTreeToXirf<'a> {
|
||||||
|
@ -71,23 +72,34 @@ impl<'a> ParseState for AsgTreeToXirf<'a> {
|
||||||
fn parse_token(
|
fn parse_token(
|
||||||
self,
|
self,
|
||||||
tok: Self::Token,
|
tok: Self::Token,
|
||||||
TreeContext(_, asg): &mut TreeContext,
|
TreeContext(tok_stack, asg): &mut TreeContext,
|
||||||
) -> TransitionResult<Self::Super> {
|
) -> TransitionResult<Self::Super> {
|
||||||
use ObjectRelTy as Ty;
|
use ObjectRelTy as Ty;
|
||||||
|
|
||||||
|
if let Some(emit) = tok_stack.pop() {
|
||||||
|
return Transition(self).ok(emit).with_lookahead(tok);
|
||||||
|
}
|
||||||
|
|
||||||
let tok_span = tok.span();
|
let tok_span = tok.span();
|
||||||
let TreeWalkRel(dyn_rel, depth) = tok;
|
let TreeWalkRel(dyn_rel, depth) = tok;
|
||||||
|
|
||||||
// POC: Read-only access to the ASG for resolving edge refs.
|
|
||||||
let obj = dyn_rel.target().resolve(asg);
|
let obj = dyn_rel.target().resolve(asg);
|
||||||
let obj_span = obj.span();
|
let obj_span = obj.span();
|
||||||
|
|
||||||
match dyn_rel.target_ty() {
|
match dyn_rel.target_ty() {
|
||||||
Ty::Pkg => Transition(self).ok(XirfToken::Open(
|
Ty::Pkg => {
|
||||||
|
tok_stack.push(XirfToken::Attr(Attr::new(
|
||||||
|
QN_XMLNS,
|
||||||
|
URI_LV_RATER,
|
||||||
|
(obj_span, obj_span),
|
||||||
|
)));
|
||||||
|
|
||||||
|
Transition(self).ok(XirfToken::Open(
|
||||||
QN_PACKAGE,
|
QN_PACKAGE,
|
||||||
OpenSpan::without_name_span(obj_span),
|
OpenSpan::without_name_span(obj_span),
|
||||||
depth,
|
depth,
|
||||||
)),
|
))
|
||||||
|
}
|
||||||
|
|
||||||
Ty::Ident | Ty::Expr => Transition(self).incomplete(),
|
Ty::Ident | Ty::Expr => Transition(self).incomplete(),
|
||||||
|
|
||||||
|
@ -103,10 +115,28 @@ impl<'a> ParseState for AsgTreeToXirf<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Size of the token stack.
|
||||||
pub struct TreeContext<'a>(StackPlaceholder, &'a Asg);
|
///
|
||||||
|
/// See [`TokenStack`] for more information.
|
||||||
|
const TOK_STACK_SIZE: usize = 8;
|
||||||
|
|
||||||
type StackPlaceholder = ();
|
/// Token stack to hold generated tokens between [`AsgTreeToXirf`]
|
||||||
|
/// iterations.
|
||||||
|
///
|
||||||
|
/// The token stack is used to avoid having to create separate states for
|
||||||
|
/// emitting each individual token.
|
||||||
|
/// It is populated by [`AsgTreeToXirf`] if more than a single [`XirfToken`]
|
||||||
|
/// needs to be emitted,
|
||||||
|
/// and tokens are removed on each subsequent iteration until empty.
|
||||||
|
///
|
||||||
|
/// This need only be big enough to accommodate [`AsgTreeToXirf`]'s
|
||||||
|
/// implementation;
|
||||||
|
/// the size is independent of user input.
|
||||||
|
type TokenStack<'a> =
|
||||||
|
ArrayVec<<AsgTreeToXirf<'a> as ParseState>::Object, TOK_STACK_SIZE>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TreeContext<'a>(TokenStack<'a>, &'a Asg);
|
||||||
|
|
||||||
impl<'a> From<&'a Asg> for TreeContext<'a> {
|
impl<'a> From<&'a Asg> for TreeContext<'a> {
|
||||||
fn from(asg: &'a Asg) -> Self {
|
fn from(asg: &'a Asg) -> Self {
|
||||||
|
|
Loading…
Reference in New Issue