use hashlink::{LinkedHashMap, LinkedHashSet};
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{spanned::Spanned, visit::Visit};
use crate::hash::OrderedMap;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Value {
pub id: u32,
_non_send: std::marker::PhantomData<*const ()>,
}
impl Value {
pub fn next() -> Self {
thread_local! {
static NEXT: std::cell::Cell<u32> = const { std::cell::Cell::new(0) };
}
NEXT.with(|next| {
let value = next.get();
next.set(value + 1);
Self {
id: value,
_non_send: std::marker::PhantomData,
}
})
}
}
pub struct PatVistor {
pub captures: LinkedHashSet<syn::Ident>,
}
impl PatVistor {
pub fn new() -> Self {
Self {
captures: LinkedHashSet::default(),
}
}
pub fn collect_captures(pat: &syn::Pat) -> LinkedHashSet<syn::Ident> {
let mut visitor = Self::new();
visitor.visit_pat(pat);
visitor.captures
}
}
impl Visit<'_> for PatVistor {
fn visit_pat_ident(&mut self, i: &syn::PatIdent) {
self.captures.insert(i.ident.clone());
}
}
#[derive(Clone)]
pub enum Capture {
Loud,
Slient,
Named(Box<syn::Pat>, Box<Capture>),
Tuple(Box<Capture>, Box<Capture>),
TupleVec(Vec<syn::Ident>),
}
impl Capture {
pub fn is_loud(&self) -> bool {
match self {
Capture::Loud => true,
Capture::Slient => false,
Capture::Named(_, _) => true,
Capture::Tuple(_, n) => n.is_loud(),
Capture::TupleVec(_) => true,
}
}
pub fn to_anonymous(&self) -> Capture {
if self.is_loud() {
Capture::Loud
} else {
Capture::Slient
}
}
pub fn unify(self, cap: &Capture) -> Result<Capture, TokenStream> {
match (self, cap) {
(Capture::Named(p1, c1), Capture::Named(p2, c2)) => {
if &p1 == p2 {
if let Ok(c) = c1.unify(c2) {
Ok(Capture::Named(p1, Box::new(c)))
} else {
Ok(Capture::Named(p1, Box::new(Capture::Loud)))
}
} else {
Err(quote_spanned! { p1.span() => compile_error!("pattern mismatch"); })
}
}
(Capture::Tuple(c1, c2), Capture::Tuple(c3, c4)) => {
let c1 = c1.unify(c3)?;
let c2 = c2.unify(c4)?;
Ok(Capture::Tuple(Box::new(c1), Box::new(c2)))
}
(Capture::Loud, _) => Ok(Capture::Loud),
(_, Capture::Loud) => Ok(Capture::Loud),
(Capture::Slient, Capture::Slient) => Ok(Capture::Slient),
_ => Err(quote! { compile_error!("capture mismatch"); }),
}
}
}
pub struct Parsing {
values: OrderedMap<Value, ParseOp>,
pub capture: Capture,
pub span: Span,
}
impl Parsing {
pub fn into_iter(self) -> impl Iterator<Item = (Value, ParseOp)> {
self.values.into_iter()
}
fn from_op(op: ParseOp, capture: Capture, span: Span) -> Self {
let mut values = LinkedHashMap::default();
values.insert(Value::next(), op);
Self {
values,
capture,
span,
}
}
pub fn result(&self) -> Value {
self.values
.back()
.map(|(k, _)| *k)
.expect("parser is empty")
}
fn push(mut self, op: ParseOp) -> Self {
self.values.insert(Value::next(), op);
self
}
pub fn just(c: syn::Lit, span: Span) -> Self {
Self::from_op(ParseOp::Just(c), Capture::Slient, span)
}
pub fn just_pat(p: syn::Pat, span: Span) -> Self {
let captures = PatVistor::collect_captures(&p);
let captures: Vec<syn::Ident> = captures.into_iter().collect();
Self::from_op(
ParseOp::Pat(p.clone(), captures.clone()),
Capture::TupleVec(captures),
span,
)
}
pub fn just_type(ty: syn::Type, span: Span) -> Self {
Self::from_op(ParseOp::JustType(ty), Capture::Slient, span)
}
pub fn call(name: syn::Ident, depends: Vec<ParserRef>, span: Span) -> Self {
Self::from_op(
ParseOp::Call {
parser: ParserRef::new(&name),
depends,
},
Capture::Loud,
span,
)
}
pub fn map(self, f: syn::Expr) -> Self {
let parser = self.result();
let capture = self.capture.clone();
self.push(ParseOp::Map {
parser,
cap: capture,
expr: f,
})
}
pub fn then(mut self, next: Box<Parsing>) -> Self {
let prev = self.result();
let op = match (self.capture.is_loud(), next.capture.is_loud()) {
(true, false) => ParseOp::ThenIgnore { prev, next },
(false, true) => {
self.capture = next.capture.clone();
ParseOp::IgnoreThen { prev, next }
}
_ => {
self.capture =
Capture::Tuple(Box::new(self.capture), Box::new(next.capture.clone()));
ParseOp::Then { prev, next }
}
};
self.push(op)
}
pub fn choice(
self,
rest: impl Iterator<Item = Result<Parsing, TokenStream>>,
) -> Result<Self, TokenStream> {
let span = self.span;
let mut capture = self.capture.clone();
let mut parsers = vec![self];
for item in rest {
let parser = item?;
capture = capture.unify(&parser.capture)?;
parsers.push(parser);
}
let op = ParseOp::Choice { parsers };
Ok(Self::from_op(op, capture, span))
}
pub fn choice_nocap(
parsers: impl Iterator<Item = Result<Parsing, TokenStream>>,
span: Span,
) -> Result<Self, TokenStream> {
let parsers = parsers.collect::<Result<Vec<_>, _>>()?;
let op = ParseOp::Choice { parsers };
Ok(Self::from_op(op, Capture::Loud, span))
}
pub fn repeat(self, at_least: usize) -> Self {
let span = self.span;
let cap = self.capture.to_anonymous();
let parser = Box::new(self);
Self::from_op(ParseOp::Repeat { parser, at_least }, cap, span)
}
pub fn optional(self) -> Self {
let span = self.span;
let cap = self.capture.to_anonymous();
let parser = Box::new(self);
Self::from_op(ParseOp::Optional { parser }, cap, span)
}
pub fn look_ahead(self) -> Self {
let span = self.span;
Self::from_op(
ParseOp::LookAhead {
parser: Box::new(self),
},
Capture::Slient,
span,
)
}
pub fn look_ahead_not(self) -> Self {
let span = self.span;
Self::from_op(
ParseOp::LookAheadNot {
parser: Box::new(self),
},
Capture::Slient,
span,
)
}
}
pub enum ParseOp {
Just(syn::Lit),
JustType(syn::Type),
Pat(syn::Pat, Vec<syn::Ident>),
Call {
parser: ParserRef,
depends: Vec<ParserRef>,
},
Map {
parser: Value,
cap: Capture,
expr: syn::Expr,
},
Then { prev: Value, next: Box<Parsing> },
ThenIgnore { prev: Value, next: Box<Parsing> },
IgnoreThen { prev: Value, next: Box<Parsing> },
Repeat {
parser: Box<Parsing>,
at_least: usize,
},
Optional { parser: Box<Parsing> },
LookAhead { parser: Box<Parsing> },
LookAheadNot { parser: Box<Parsing> },
Choice { parsers: Vec<Parsing> },
}
pub enum MemoKind {
None,
Memorize,
LeftRec,
}
pub struct ParserImpl {
pub name: syn::Ident,
pub curr: ParserRef,
pub parser: Parsing,
pub memo: MemoKind,
pub vis: syn::Visibility,
pub ret_ty: syn::Type,
pub depends: Vec<(ParserRef, syn::Ident)>,
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ParserRef(syn::Ident);
impl ParserRef {
pub fn new(name: &syn::Ident) -> Self {
Self(format_ident!(
"__parser_{}",
name,
span = Span::mixed_site()
))
}
pub fn curr() -> Self {
Self(format_ident!("self"))
}
pub fn as_ident(&self) -> &syn::Ident {
&self.0
}
}
pub struct Middle {
pub attrs: Vec<syn::Attribute>,
pub crate_name: TokenStream,
pub mod_name: syn::Ident,
pub items: Vec<syn::Item>,
pub parsers: Vec<ParserImpl>,
pub debug: bool,
}