mod matchcode;
mod names;
mod repr;
mod tokens;
mod trace;
mod visitor;
pub use proc_macro2;
pub use crate::matchcode::compile_input;
use crate::trace::Trace;
use log::trace;
use proc_macro2::TokenStream;
use syn::parse::Parse;
use crate::tokens::MetaContext;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct Error;
pub type Result<T> = std::result::Result<T, Error>;
struct Stmts(Vec<syn::Stmt>);
impl Parse for Stmts {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
Ok(Stmts(input.call(syn::Block::parse_within)?))
}
}
pub struct PatternDef{ nodes: TokenStream, ids: TokenStream }
impl PatternDef {
pub fn lex(args: TokenStream, body: TokenStream) -> PatternDef {
let (nodes, ids) = MetaContext::new(args).apply(body);
PatternDef{ nodes, ids }
}
pub fn parse(self) -> Result<Pattern> {
trace!("nodes: {}", &self.nodes);
trace!("ids: {}", &self.ids);
let nodes: Stmts = syn::parse2(self.nodes).map_err(|_| Error)?;
let ids: Stmts = syn::parse2(self.ids).expect("if <nodes> succeeded <ids> must");
let (mut nodes, mut ids) = (nodes.0, ids.0);
if nodes.len() == 1 {
if let syn::Stmt::Expr(_) = nodes[0] {
if let (syn::Stmt::Expr(nodes), syn::Stmt::Expr(ids)) = (nodes.remove(0), ids.remove(0)) {
return Ok(Pattern::Expr{ nodes, ids });
}
unreachable!();
}
}
Ok(Pattern::StmtSeq{ nodes, ids })
}
}
pub enum Pattern {
StmtSeq { nodes: Vec<syn::Stmt>, ids: Vec<syn::Stmt> },
Expr { nodes: syn::Expr, ids: syn::Expr },
}
pub enum Ir {
StmtSeq { trace: Trace },
Expr { trace: Trace },
}
enum MatchesInner<'p, 'it> {
StmtSeq { matches: crate::trace::ToplevelMatches<'p, 'it> },
Expr { matches: crate::trace::InternalMatches<'p, 'it> },
}
#[derive(Debug)]
pub struct Match {
pub context: String,
pub bindings: String,
}
pub struct Matches<'p, 'i, 'it> {
inner: MatchesInner<'p, 'it>,
pattern: &'p Trace,
input: &'i [syn::Stmt],
}
impl Iterator for Matches<'_, '_, '_> {
type Item = Match;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.inner {
MatchesInner::StmtSeq { matches } => matches.next().map(|m| {
let mut context = "[".to_owned();
let mut first = true;
for s in &self.input[..m] {
if !first {
context.push_str(",");
}
first = false;
context.push_str(&crate::matchcode::stmt_repr(s));
}
if !first { context.push_str(","); }
context.push_str("\"$1\"");
for s in &self.input[m+self.pattern.toplevel_len()..] {
context.push_str(",");
context.push_str(&crate::matchcode::stmt_repr(s));
}
context.push_str("]");
let bindings = crate::matchcode::bind_stmts(self.pattern, &self.input[m..m + self.pattern.toplevel_len()]);
let bindings = crate::matchcode::bindings_repr(&bindings);
Match { context, bindings }
}),
MatchesInner::Expr { matches } => matches.next().map(|m| {
let context = crate::matchcode::stmts_tree_repr_of(m.clone(), self.input);
let extracted = crate::matchcode::bind_expr(crate::trace::ReTracer::new(m), self.input);
let ex = if let crate::matchcode::Binding::Expr(ex) = extracted.binds[0] {
ex
} else {
unreachable!()
};
let bindings = crate::matchcode::bind_expr_expr(crate::trace::ReTracer::new(self.pattern.clone()), ex);
let bindings = crate::matchcode::bindings_repr(&bindings);
Match { context, bindings }
}),
}
}
}
impl Ir {
pub fn matches<'p, 'i, 'it>(&'p self, input: &'i [syn::Stmt], input_trace: &'it crate::trace::IndexedTrace) -> Matches<'p, 'i, 'it> {
let (inner, pattern) = match self {
Ir::StmtSeq { trace } => {
(MatchesInner::StmtSeq { matches: trace.toplevel_matches(input_trace) }, trace)
}
Ir::Expr { trace } => {
(MatchesInner::Expr { matches: trace.internal_matches(input_trace) }, trace)
}
};
Matches { inner, pattern, input }
}
}
pub struct Input { pub stmts: Vec<syn::Stmt> }
impl Input {
pub fn parse(ts: TokenStream) -> Result<Self> {
let stmts: Stmts = syn::parse2(ts).map_err(|_| Error)?;
let stmts = stmts.0;
Ok(Input { stmts })
}
pub fn compile(&self) -> crate::trace::IndexedTrace {
matchcode::compile_input(&self.stmts)
}
pub fn debug_tree_repr(&self) -> String {
matchcode::stmts_tree_repr_of(matchcode::compile_input(&self.stmts).deindex(), &self.stmts)
}
}
impl Pattern {
pub fn compile(&self) -> Ir {
match self {
Pattern::StmtSeq { nodes, ids } => Ir::StmtSeq { trace: matchcode::compile_stmts(nodes, ids) },
Pattern::Expr { nodes, ids } => Ir::Expr { trace: matchcode::compile_expr(nodes, ids) },
}
}
pub fn debug_tree_repr(&self) -> String {
match self {
Pattern::StmtSeq { nodes, ids } => matchcode::stmts_tree_repr(nodes, ids),
Pattern::Expr { nodes, ids } => matchcode::expr_tree_repr(nodes, ids),
}
}
pub fn debug_flat_repr(&self) -> String {
match self {
Pattern::StmtSeq { nodes, ids } => matchcode::stmts_flat_repr(nodes, ids),
Pattern::Expr { nodes, ids } => matchcode::expr_flat_repr(nodes, ids),
}
}
pub fn fragment(&self) -> String {
match self {
Pattern::StmtSeq { .. } => "StmtSeq".to_owned(),
Pattern::Expr { .. } => "Expr".to_owned(),
}
}
}
impl Display for PatternDef {
fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
write!(fmt, "PatternDef {{ nodes: {}, ids: {} }}", &self.nodes, &self.ids)
}
}