use rustyfi_backend::Length;
use rustyfi_syntax::{RustyfiVersion, Span};
use std::rc::Rc;
pub mod branded {
use crate::symbol::Symbol;
pub type Ast<'s> = super::Ast<Symbol<'s>>;
pub type BText<'s> = super::BText<Symbol<'s>>;
pub type CmdArg<'s> = super::CmdArg<Symbol<'s>>;
pub type IText<'s> = super::IText<Symbol<'s>>;
pub type MatchArm<'s> = super::MatchArm<Symbol<'s>>;
pub type MathElem<'s> = super::MathElem<Symbol<'s>>;
pub type Pattern<'s> = super::Pattern<Symbol<'s>>;
}
#[derive(Clone, Debug, PartialEq)]
pub enum Ast<I = String> {
Unit,
Bool(bool),
Int(i64),
Float(f64),
Length(Length),
Str(String),
Var(I, Span),
Apply(Box<Ast<I>>, Box<Ast<I>>),
Lambda(I, Rc<Ast<I>>),
LetIn(I, Box<Ast<I>>, Box<Ast<I>>),
LetRecIn(Vec<(I, Rc<Ast<I>>)>, Box<Ast<I>>),
LetMathIn(I, Box<Ast<I>>, Box<Ast<I>>),
IfThenElse(Box<Ast<I>>, Box<Ast<I>>, Box<Ast<I>>),
Match(Box<Ast<I>>, Vec<MatchArm<I>>),
Tuple(Vec<Ast<I>>),
Ctor(String, Option<Box<Ast<I>>>),
Record(Vec<(String, Ast<I>)>),
List(Vec<Ast<I>>),
InlineText(Rc<Vec<IText<I>>>),
BlockText(Rc<Vec<BText<I>>>),
MathText(Rc<Vec<MathElem<I>>>),
LetMutableIn(I, Box<Ast<I>>, Box<Ast<I>>),
Overwrite(I, Span, Box<Ast<I>>),
WhileDo(Box<Ast<I>>, Box<Ast<I>>),
Sequential(Box<Ast<I>>, Box<Ast<I>>),
AccessField(Box<Ast<I>>, String, Span),
UpdateField(Box<Ast<I>>, String, Box<Ast<I>>),
ApplyOpt {
func: Box<Ast<I>>,
opts: Vec<(String, Ast<I>)>,
arg: Box<Ast<I>>,
},
LambdaOpt {
opts: Vec<(String, I)>,
param: I,
body: Rc<Ast<I>>,
},
VersionScope(RustyfiVersion, Box<Ast<I>>),
ModuleScope(Vec<String>, Box<Ast<I>>),
StageScope(crate::types::Stage, Box<Ast<I>>),
Next(Box<Ast<I>>),
Prev(Box<Ast<I>>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct CmdArg<I = String> {
pub opts: Vec<(String, Ast<I>)>,
pub arg: Ast<I>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum MathElem<I = String> {
Chars(String),
Group(Vec<MathElem<I>>),
Sub(Box<MathElem<I>>, Vec<MathElem<I>>),
Sup(Box<MathElem<I>>, Vec<MathElem<I>>),
Primes(Box<MathElem<I>>, usize),
Cmd {
name: I,
span: Span,
args: Vec<CmdArg<I>>,
},
Embed { expr: Ast<I>, span: Span },
}
#[derive(Clone, Debug, PartialEq)]
pub struct MatchArm<I = String> {
pub pat: Pattern<I>,
pub guard: Option<Ast<I>>,
pub body: Ast<I>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern<I = String> {
Wild,
Var(I),
Unit,
Bool(bool),
Int(i64),
Str(String),
Tuple(Vec<Pattern<I>>),
EmptyList,
Cons(Box<Pattern<I>>, Box<Pattern<I>>),
Ctor(String, Option<Box<Pattern<I>>>),
As(Box<Pattern<I>>, I),
}
#[derive(Clone, Debug, PartialEq)]
pub enum IText<I = String> {
Text(String),
CodeText(String),
Cmd {
name: I,
span: Span,
args: Vec<CmdArg<I>>,
},
Embed {
expr: Ast<I>,
span: Span,
},
EmbedMath {
elems: Rc<Vec<MathElem<I>>>,
span: Span,
},
}
#[derive(Clone, Debug, PartialEq)]
pub enum BText<I = String> {
Cmd {
name: I,
span: Span,
args: Vec<CmdArg<I>>,
},
Embed { expr: Ast<I>, span: Span },
}
impl<I> Ast<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> Ast<J> {
let go = |a: &Ast<I>| a.map_idents(f);
match self {
Ast::Unit => Ast::Unit,
Ast::Bool(b) => Ast::Bool(*b),
Ast::Int(n) => Ast::Int(*n),
Ast::Float(x) => Ast::Float(*x),
Ast::Length(l) => Ast::Length(*l),
Ast::Str(s) => Ast::Str(s.clone()),
Ast::Var(n, sp) => Ast::Var(f(n), *sp),
Ast::Apply(g, a) => Ast::Apply(Box::new(go(g)), Box::new(go(a))),
Ast::Lambda(p, b) => Ast::Lambda(f(p), Rc::new(go(b))),
Ast::LetIn(n, v, r) => Ast::LetIn(f(n), Box::new(go(v)), Box::new(go(r))),
Ast::LetRecIn(bs, body) => Ast::LetRecIn(
bs.iter().map(|(n, v)| (f(n), Rc::new(go(v)))).collect(),
Box::new(go(body)),
),
Ast::LetMathIn(n, v, r) => Ast::LetMathIn(f(n), Box::new(go(v)), Box::new(go(r))),
Ast::IfThenElse(c, t, e) => {
Ast::IfThenElse(Box::new(go(c)), Box::new(go(t)), Box::new(go(e)))
}
Ast::Match(s, arms) => Ast::Match(
Box::new(go(s)),
arms.iter().map(|a| a.map_idents(f)).collect(),
),
Ast::Tuple(items) => Ast::Tuple(items.iter().map(go).collect()),
Ast::Ctor(tag, arg) => Ast::Ctor(tag.clone(), arg.as_ref().map(|a| Box::new(go(a)))),
Ast::Record(fields) => {
Ast::Record(fields.iter().map(|(l, e)| (l.clone(), go(e))).collect())
}
Ast::List(items) => Ast::List(items.iter().map(go).collect()),
Ast::InlineText(elems) => {
Ast::InlineText(Rc::new(elems.iter().map(|e| e.map_idents(f)).collect()))
}
Ast::BlockText(elems) => {
Ast::BlockText(Rc::new(elems.iter().map(|e| e.map_idents(f)).collect()))
}
Ast::MathText(elems) => {
Ast::MathText(Rc::new(elems.iter().map(|e| e.map_idents(f)).collect()))
}
Ast::LetMutableIn(n, i, b) => Ast::LetMutableIn(f(n), Box::new(go(i)), Box::new(go(b))),
Ast::Overwrite(n, sp, v) => Ast::Overwrite(f(n), *sp, Box::new(go(v))),
Ast::WhileDo(c, b) => Ast::WhileDo(Box::new(go(c)), Box::new(go(b))),
Ast::Sequential(a, b) => Ast::Sequential(Box::new(go(a)), Box::new(go(b))),
Ast::AccessField(e, l, sp) => Ast::AccessField(Box::new(go(e)), l.clone(), *sp),
Ast::UpdateField(e, l, v) => {
Ast::UpdateField(Box::new(go(e)), l.clone(), Box::new(go(v)))
}
Ast::ApplyOpt { func, opts, arg } => Ast::ApplyOpt {
func: Box::new(go(func)),
opts: opts.iter().map(|(l, e)| (l.clone(), go(e))).collect(),
arg: Box::new(go(arg)),
},
Ast::LambdaOpt { opts, param, body } => Ast::LambdaOpt {
opts: opts.iter().map(|(l, b)| (l.clone(), f(b))).collect(),
param: f(param),
body: Rc::new(go(body)),
},
Ast::VersionScope(v, b) => Ast::VersionScope(*v, Box::new(go(b))),
Ast::ModuleScope(path, b) => Ast::ModuleScope(path.clone(), Box::new(go(b))),
Ast::StageScope(st, b) => Ast::StageScope(*st, Box::new(go(b))),
Ast::Next(e) => Ast::Next(Box::new(go(e))),
Ast::Prev(e) => Ast::Prev(Box::new(go(e))),
}
}
}
impl<I> MatchArm<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> MatchArm<J> {
MatchArm {
pat: self.pat.map_idents(f),
guard: self.guard.as_ref().map(|g| g.map_idents(f)),
body: self.body.map_idents(f),
}
}
}
impl<I> Pattern<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> Pattern<J> {
match self {
Pattern::Wild => Pattern::Wild,
Pattern::Var(n) => Pattern::Var(f(n)),
Pattern::Unit => Pattern::Unit,
Pattern::Bool(b) => Pattern::Bool(*b),
Pattern::Int(n) => Pattern::Int(*n),
Pattern::Str(s) => Pattern::Str(s.clone()),
Pattern::Tuple(ps) => Pattern::Tuple(ps.iter().map(|p| p.map_idents(f)).collect()),
Pattern::EmptyList => Pattern::EmptyList,
Pattern::Cons(h, t) => {
Pattern::Cons(Box::new(h.map_idents(f)), Box::new(t.map_idents(f)))
}
Pattern::Ctor(tag, p) => {
Pattern::Ctor(tag.clone(), p.as_ref().map(|p| Box::new(p.map_idents(f))))
}
Pattern::As(p, n) => Pattern::As(Box::new(p.map_idents(f)), f(n)),
}
}
}
impl<I> CmdArg<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> CmdArg<J> {
CmdArg {
opts: self
.opts
.iter()
.map(|(l, e)| (l.clone(), e.map_idents(f)))
.collect(),
arg: self.arg.map_idents(f),
}
}
}
impl<I> IText<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> IText<J> {
match self {
IText::Text(s) => IText::Text(s.clone()),
IText::CodeText(s) => IText::CodeText(s.clone()),
IText::Cmd { name, span, args } => IText::Cmd {
name: f(name),
span: *span,
args: args.iter().map(|a| a.map_idents(f)).collect(),
},
IText::Embed { expr, span } => IText::Embed {
expr: expr.map_idents(f),
span: *span,
},
IText::EmbedMath { elems, span } => IText::EmbedMath {
elems: Rc::new(elems.iter().map(|e| e.map_idents(f)).collect()),
span: *span,
},
}
}
}
impl<I> BText<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> BText<J> {
match self {
BText::Cmd { name, span, args } => BText::Cmd {
name: f(name),
span: *span,
args: args.iter().map(|a| a.map_idents(f)).collect(),
},
BText::Embed { expr, span } => BText::Embed {
expr: expr.map_idents(f),
span: *span,
},
}
}
}
impl<I> MathElem<I> {
pub fn map_idents<J>(&self, f: &impl Fn(&I) -> J) -> MathElem<J> {
match self {
MathElem::Chars(s) => MathElem::Chars(s.clone()),
MathElem::Group(es) => MathElem::Group(es.iter().map(|e| e.map_idents(f)).collect()),
MathElem::Sub(b, s) => MathElem::Sub(
Box::new(b.map_idents(f)),
s.iter().map(|e| e.map_idents(f)).collect(),
),
MathElem::Sup(b, s) => MathElem::Sup(
Box::new(b.map_idents(f)),
s.iter().map(|e| e.map_idents(f)).collect(),
),
MathElem::Primes(b, n) => MathElem::Primes(Box::new(b.map_idents(f)), *n),
MathElem::Cmd { name, span, args } => MathElem::Cmd {
name: f(name),
span: *span,
args: args.iter().map(|a| a.map_idents(f)).collect(),
},
MathElem::Embed { expr, span } => MathElem::Embed {
expr: expr.map_idents(f),
span: *span,
},
}
}
}
pub fn debrand(ast: &branded::Ast<'_>, store: &crate::symbol::SymbolStore) -> Ast {
ast.map_idents(&|sym| store.resolve(*sym).to_string())
}