use crate::spans::*; use std::fmt; #[derive(Clone, Debug, PartialEq, Eq)] pub enum StringPart { Data(String), Word(&'static str), Inline(String), } impl fmt::Display for StringPart { fn fmt(self: &StringPart, f: &mut fmt::Formatter) -> fmt::Result { let rep = match self { StringPart::Word(s) => format!("{{{s}}}"), StringPart::Data(s) => s.to_string(), StringPart::Inline(s) => s.to_string(), }; write!(f, "{}", rep) } } #[derive(Clone, Debug, PartialEq)] pub enum Ast { // a special Error node // may come in handy? Error, And, Or, // expression nodes Placeholder, Nil, Boolean(bool), Number(f64), Keyword(&'static str), Method(&'static str, Box>), Word(&'static str), String(&'static str), Interpolated(Vec>), Block(Vec>), If(Box>, Box>, Box>), Tuple(Vec>), Arguments(Vec>), List(Vec>), Dict(Vec>), Let(Box>, Box>), LBox(&'static str, Box>), Synthetic(Box>, Box>, Vec>), When(Vec>), WhenClause(Box>, Box>), Match(Box>, Vec>), Receive(Vec>), MatchClause( Box>, Box>>, Box>, ), Fn(&'static str, Box>, Option<&'static str>), FnBody(Vec>), FnDeclaration(&'static str), Panic(Box>), Do(Vec>), Repeat(Box>, Box>), Splat(&'static str), StringPair(&'static str, Box>), KeywordPair(&'static str, Box>), Loop(Box>, Vec>), Recur(Vec>), // pattern nodes NilPattern, BooleanPattern(bool), NumberPattern(f64), StringPattern(&'static str), InterpolatedPattern(Vec>), KeywordPattern(&'static str), WordPattern(&'static str), AsPattern(&'static str, &'static str), Splattern(Box>), PlaceholderPattern, TuplePattern(Vec>), ListPattern(Vec>), StrPairPattern(&'static str, Box>), KeyPairPattern(&'static str, Box>), DictPattern(Vec>), } impl Ast { pub fn show(&self) -> String { use Ast::*; match self { And => "and".to_string(), Or => "or".to_string(), Error => unreachable!(), Nil | NilPattern => "nil".to_string(), String(s) | StringPattern(s) => format!("\"{s}\""), Interpolated(strs) | InterpolatedPattern(strs) => { let mut out = "".to_string(); out = format!("\"{out}"); for (part, _) in strs { out = format!("{out}{part}"); } format!("{out}\"") } Boolean(b) | BooleanPattern(b) => b.to_string(), Number(n) | NumberPattern(n) => n.to_string(), Keyword(k) | KeywordPattern(k) => format!(":{k}"), Method(m, args) => format!("::{m} {}", args.0), Word(w) | WordPattern(w) => w.to_string(), Block(lines) => { let mut out = "{\n".to_string(); for (line, _) in lines { out = format!("{out}\n {}", line.show()); } format!("{out}\n}}") } If(cond, then, r#else) => format!( "if {}\n then {}\n else {}", cond.0.show(), then.0.show(), r#else.0.show() ), Let(pattern, expression) => { format!("let {} = {}", pattern.0.show(), expression.0.show()) } Dict(entries) | DictPattern(entries) => { format!( "#{{{}}}", entries .iter() .map(|(pair, _)| pair.show()) .collect::>() .join(", ") ) } List(members) | ListPattern(members) => format!( "[{}]", members .iter() .map(|(member, _)| member.show()) .collect::>() .join(", ") ), Arguments(members) => format!( "({})", members .iter() .map(|(member, _)| member.show()) .collect::>() .join(", ") ), Tuple(members) | TuplePattern(members) => format!( "({})", members .iter() .map(|(member, _)| member.show()) .collect::>() .join(", ") ), Synthetic(root, first, rest) => format!( "{} {} {}", root.0.show(), first.0.show(), rest.iter() .map(|(term, _)| term.show()) .collect::>() .join(" ") ), When(clauses) | Receive(clauses) => format!( "when {{\n {}\n}}", clauses .iter() .map(|(clause, _)| clause.show()) .collect::>() .join("\n ") ), Placeholder | PlaceholderPattern => "_".to_string(), LBox(name, rhs) => format!("box {name} = {}", rhs.0.show()), Match(scrutinee, clauses) => format!( "match {} with {{\n {}\n}}", scrutinee.0.show(), clauses .iter() .map(|(clause, _)| clause.show()) .collect::>() .join("\n ") ), FnBody(clauses) => clauses .iter() .map(|(clause, _)| clause.show()) .collect::>() .join("\n "), Fn(name, body, doc) => { let mut out = format!("fn {name} {{\n"); if let Some(doc) = doc { out = format!("{out} {doc}\n"); } format!("{out} {}\n}}", body.0.show()) } FnDeclaration(name) => format!("fn {name}"), Panic(expr) => format!("panic! {}", expr.0.show()), Do(terms) => { format!( "do {}", terms .iter() .map(|(term, _)| term.show()) .collect::>() .join(" > ") ) } Repeat(times, body) => format!("repeat {} {{\n{}\n}}", times.0.show(), body.0.show()), Splat(word) => format!("...{}", word), Splattern(pattern) => format!("...{}", pattern.0.show()), AsPattern(word, type_keyword) => format!("{word} as :{type_keyword}"), KeywordPair(key, value) | KeyPairPattern(key, value) => { format!(":{key} {}", value.0.show()) } StringPair(key, value) | StrPairPattern(key, value) => { format!("\"{key}\" {}", value.0.show()) } Loop(init, body) => format!( "loop {} with {{\n {}\n}}", init.0.show(), body.iter() .map(|(clause, _)| clause.show()) .collect::>() .join("\n ") ), Recur(args) => format!( "recur ({})", args.iter() .map(|(arg, _)| arg.show()) .collect::>() .join(", ") ), MatchClause(pattern, guard, body) => { let mut out = pattern.0.show(); if let Some(guard) = guard.as_ref() { out = format!("{out} if {}", guard.0.show()); } format!("{out} -> {}", body.0.show()) } WhenClause(cond, body) => format!("{} -> {}", cond.0.show(), body.0.show()), } } } impl fmt::Display for Ast { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use Ast::*; match self { And => write!(f, "And"), Or => write!(f, "Or"), Error => write!(f, "Error"), Nil => write!(f, "nil"), String(s) => write!(f, "String: \"{}\"", s), Interpolated(strs) => { write!( f, "Interpolated: \"{}\"", strs.iter() .map(|(s, _)| s.to_string()) .collect::>() .join("") ) } Boolean(b) => write!(f, "Boolean: {}", b), Number(n) => write!(f, "Number: {}", n), Keyword(k) => write!(f, "Keyword: :{}", k), Method(m, args) => write!(f, "Method: ::{m} ({})", args.0), Word(w) => write!(f, "Word: {}", w), Block(b) => write!( f, "Block: <{}>", b.iter() .map(|(line, _)| line.to_string()) .collect::>() .join("\n") ), If(cond, then_branch, else_branch) => write!( f, "If: {} Then: {} Else: {}", cond.0, then_branch.0, else_branch.0 ), Let(pattern, expression) => { write!(f, "Let: {} = {}", pattern.0, expression.0) } Dict(entries) => write!( f, "#{{{}}}", entries .iter() .map(|pair| pair.0.to_string()) .collect::>() .join(", ") ), List(l) => write!( f, "List: [{}]", l.iter() .map(|(line, _)| line.to_string()) .collect::>() .join("\n") ), Arguments(a) => write!( f, "Arguments: ({})", a.iter() .map(|(line, _)| line.to_string()) .collect::>() .join("\n") ), Tuple(t) => write!( f, "Tuple: ({})", t.iter() .map(|(line, _)| line.to_string()) .collect::>() .join("\n") ), Synthetic(root, first, rest) => write!( f, "Synth: [{}, {}, {}]", root.0, first.0, rest.iter() .map(|(term, _)| term.to_string()) .collect::>() .join("\n") ), When(clauses) | Receive(clauses) => write!( f, "When: [{}]", clauses .iter() .map(|clause| clause.0.to_string()) .collect::>() .join("\n") ), Placeholder => write!(f, "Placeholder"), LBox(_name, _rhs) => todo!(), Match(value, clauses) => { write!( f, "match: {} with {}", &value.0.to_string(), clauses .iter() .map(|clause| clause.0.to_string()) .collect::>() .join("\n") ) } FnBody(clauses) => { write!( f, "{}", clauses .iter() .map(|clause| clause.0.to_string()) .collect::>() .join("\n") ) } Fn(name, body, ..) => { write!(f, "fn: {name}\n{}", body.0) } FnDeclaration(_name) => todo!(), Panic(_expr) => todo!(), Do(terms) => { write!( f, "do: {}", terms .iter() .map(|(term, _)| term.to_string()) .collect::>() .join(" > ") ) } Repeat(_times, _body) => todo!(), Splat(word) => { write!(f, "splat: {}", word) } KeywordPair(k, v) | KeyPairPattern(k, v) => { write!(f, "key_pair: {} {}", k, v.0) } StringPair(k, v) | StrPairPattern(k, v) => { write!(f, "str_pair: {k} {}", v.0) } Loop(init, body) => { write!( f, "loop: {} with {}", init.0, body.iter() .map(|clause| clause.0.to_string()) .collect::>() .join("\n") ) } Recur(args) => { write!( f, "recur: {}", args.iter() .map(|(arg, _)| arg.to_string()) .collect::>() .join(", ") ) } MatchClause(pattern, guard, body) => { write!( f, "match clause: {} if {:?} -> {}", pattern.0, guard, body.0 ) } WhenClause(cond, body) => { write!(f, "when clause: {} -> {}", cond.0, body.0) } NilPattern => write!(f, "nil"), BooleanPattern(b) => write!(f, "{}", b), NumberPattern(n) => write!(f, "{}", n), StringPattern(s) => write!(f, "{}", s), KeywordPattern(k) => write!(f, ":{}", k), WordPattern(w) => write!(f, "{}", w), AsPattern(w, t) => write!(f, "{} as :{}", w, t), Splattern(p) => write!(f, "...{}", p.0), PlaceholderPattern => write!(f, "_"), TuplePattern(t) => write!( f, "({})", t.iter() .map(|x| x.0.to_string()) .collect::>() .join(", ") ), ListPattern(l) => write!( f, "({})", l.iter() .map(|x| x.0.to_string()) .collect::>() .join(", ") ), DictPattern(entries) => write!( f, "#{{{}}}", entries .iter() .map(|(pair, _)| pair.to_string()) .collect::>() .join(", ") ), InterpolatedPattern(strprts) => write!( f, "interpolated: \"{}\"", strprts .iter() .map(|part| part.0.to_string()) .collect::>() .join("") ), } } }