ast: separate display impls from node decls
This commit is contained in:
346
src/ast.rs
346
src/ast.rs
@@ -1,11 +1,15 @@
|
|||||||
//! The Abstract Syntax Tree defines an interface between the parser and type checker
|
//! The Abstract Syntax Tree defines an interface between the parser and type checker
|
||||||
|
|
||||||
|
use crate::span::Span;
|
||||||
|
|
||||||
pub mod macro_matcher;
|
pub mod macro_matcher;
|
||||||
|
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
|
|
||||||
pub mod fold;
|
pub mod fold;
|
||||||
|
|
||||||
|
mod display;
|
||||||
|
|
||||||
/// An annotation: extra data added on to important AST nodes.
|
/// An annotation: extra data added on to important AST nodes.
|
||||||
pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {}
|
pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {}
|
||||||
impl<T: Clone + std::fmt::Debug + std::fmt::Display + PartialEq + Eq> Annotation for T {}
|
impl<T: Clone + std::fmt::Debug + std::fmt::Display + PartialEq + Eq> Annotation for T {}
|
||||||
@@ -291,13 +295,6 @@ impl<T: Annotation, A: Annotation> std::fmt::Debug for Anno<T, A> {
|
|||||||
<T as std::fmt::Debug>::fmt(&self.0, f)
|
<T as std::fmt::Debug>::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Path {
|
|
||||||
fn from(value: &str) -> Self {
|
|
||||||
Self { parts: vec![value.to_owned()] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> Default for Expr<A> {
|
impl<A: Annotation> Default for Expr<A> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Op(Op::Tuple, vec![])
|
Self::Op(Op::Tuple, vec![])
|
||||||
@@ -337,337 +334,8 @@ impl<A: Annotation> Expr<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::{fmt::FmtAdapter, span::Span};
|
impl From<&str> for Path {
|
||||||
use std::{fmt::Display, format_args as fmt};
|
fn from(value: &str) -> Self {
|
||||||
|
Self { parts: vec![value.to_owned()] }
|
||||||
impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> Display for Expr<A> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Omitted => "/* omitted */".fmt(f),
|
|
||||||
Self::Id(id) => id.fmt(f),
|
|
||||||
Self::MetId(id) => write!(f, "`{id}"),
|
|
||||||
Self::Lit(literal) => literal.fmt(f),
|
|
||||||
Self::Use(v) => write!(f, "use {v}"),
|
|
||||||
Self::Bind(v) => v.fmt(f),
|
|
||||||
Self::Make(v) => v.fmt(f),
|
|
||||||
|
|
||||||
Self::Op(op @ Op::Continue, exprs) => f.delimit(op, "").list(exprs, "!?,"),
|
|
||||||
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
|
||||||
[cond, pass, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => {
|
|
||||||
write!(f, "{op}{cond} {pass}")
|
|
||||||
}
|
|
||||||
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
|
||||||
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
|
||||||
},
|
|
||||||
Self::Op(op @ Op::Match, exprs) => match exprs.as_slice() {
|
|
||||||
[scrutinee, arms @ ..] => f
|
|
||||||
.delimit_indented(fmt!("{op}{scrutinee} {{"), "}")
|
|
||||||
.list_wrap("\n", arms, ",\n", ",\n"),
|
|
||||||
[] => write!(f, "{op} () {{}}"), // invalid, but whatever.
|
|
||||||
},
|
|
||||||
Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "),
|
|
||||||
Self::Op(Op::ArRep, exprs) => f.delimit("[", "]").list(exprs, "; "),
|
|
||||||
Self::Op(Op::Block, exprs) => f
|
|
||||||
.delimit_indented("{", "}")
|
|
||||||
.list_wrap("\n", exprs, "\n", "\n"),
|
|
||||||
Self::Op(Op::Tuple, exprs) => f.delimit("(", ")").list(exprs, ", "),
|
|
||||||
Self::Op(Op::Group, exprs) => f.list(exprs, ", "),
|
|
||||||
Self::Op(Op::Meta, exprs) => match exprs.as_slice() {
|
|
||||||
[meta, expr @ ..] => f.delimit(fmt!("#[{meta}]\n"), "").list(expr, ","),
|
|
||||||
[] => write!(f, "#[]"),
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
|
|
||||||
[callee, args @ ..] => f.delimit(fmt!("{callee}("), ")").list(args, ", "),
|
|
||||||
[] => write!(f, "{op}"),
|
|
||||||
},
|
|
||||||
Self::Op(op @ Op::Index, exprs) => match exprs.as_slice() {
|
|
||||||
[callee, args @ ..] => f.delimit(fmt!("{callee}["), "]").list(args, ", "),
|
|
||||||
[] => write!(f, "{op}"),
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Op(op @ Op::Do, exprs) => f.list(exprs, op),
|
|
||||||
Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "),
|
|
||||||
Self::Op(op @ Op::Try, exprs) => f.delimit("(", fmt!("){op}")).list(exprs, ", "),
|
|
||||||
Self::Op(op, exprs) => match exprs.as_slice() {
|
|
||||||
[one] => write!(f, "{op}{one}"),
|
|
||||||
many => f.delimit("(", ")").list(many, op),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Op {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_str(match self {
|
|
||||||
Op::Do => ";\n",
|
|
||||||
Op::As => " as ",
|
|
||||||
Op::Macro => "macro ",
|
|
||||||
Op::Block => "{}",
|
|
||||||
Op::Array => "[]",
|
|
||||||
Op::ArRep => "[;]",
|
|
||||||
Op::Group => "()",
|
|
||||||
Op::Tuple => "()",
|
|
||||||
Op::Meta => "#[]",
|
|
||||||
Op::Try => "?",
|
|
||||||
Op::Index => "",
|
|
||||||
Op::Call => "",
|
|
||||||
Op::Pub => "pub ",
|
|
||||||
Op::Loop => "loop ",
|
|
||||||
Op::Match => "match ",
|
|
||||||
Op::If => "if ",
|
|
||||||
Op::While => "while ",
|
|
||||||
Op::Break => "break ",
|
|
||||||
Op::Return => "return ",
|
|
||||||
Op::Continue => "continue",
|
|
||||||
Op::Dot => ".",
|
|
||||||
Op::RangeEx => "..",
|
|
||||||
Op::RangeIn => "..=",
|
|
||||||
Op::Neg => "-",
|
|
||||||
Op::Not => "!",
|
|
||||||
Op::Identity => "!!",
|
|
||||||
Op::Refer => "&",
|
|
||||||
Op::Deref => "*",
|
|
||||||
Op::Mul => " * ",
|
|
||||||
Op::Div => " / ",
|
|
||||||
Op::Rem => " % ",
|
|
||||||
Op::Add => " + ",
|
|
||||||
Op::Sub => " - ",
|
|
||||||
Op::Shl => " << ",
|
|
||||||
Op::Shr => " >> ",
|
|
||||||
Op::And => " & ",
|
|
||||||
Op::Xor => " ^ ",
|
|
||||||
Op::Or => " | ",
|
|
||||||
Op::Lt => " < ",
|
|
||||||
Op::Leq => " <= ",
|
|
||||||
Op::Eq => " == ",
|
|
||||||
Op::Neq => " != ",
|
|
||||||
Op::Geq => " >= ",
|
|
||||||
Op::Gt => " > ",
|
|
||||||
Op::LogAnd => " && ",
|
|
||||||
Op::LogXor => " ^^ ",
|
|
||||||
Op::LogOr => " || ",
|
|
||||||
Op::Set => " = ",
|
|
||||||
Op::MulSet => " *= ",
|
|
||||||
Op::DivSet => " /= ",
|
|
||||||
Op::RemSet => " %= ",
|
|
||||||
Op::AddSet => " += ",
|
|
||||||
Op::SubSet => " -= ",
|
|
||||||
Op::ShlSet => " <<= ",
|
|
||||||
Op::ShrSet => " >>= ",
|
|
||||||
Op::AndSet => " &= ",
|
|
||||||
Op::XorSet => " ^= ",
|
|
||||||
Op::OrSet => " |= ",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Path {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { parts } = self;
|
|
||||||
f.list(parts, "::")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Literal {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Bool(v) => v.fmt(f),
|
|
||||||
Self::Char(c) => write!(f, "'{}'", c.escape_debug()),
|
|
||||||
Self::Int(i, 2) => write!(f, "0b{i:b}"),
|
|
||||||
Self::Int(i, 8) => write!(f, "0o{i:o}"),
|
|
||||||
Self::Int(i, 16) => write!(f, "0x{i:x}"),
|
|
||||||
Self::Int(i, _) => i.fmt(f),
|
|
||||||
Self::Str(s) => write!(f, "\"{}\"", s.escape_debug()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Use {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Glob => "*".fmt(f),
|
|
||||||
Self::Name(name) => name.fmt(f),
|
|
||||||
Self::Path(segment, rest) => write!(f, "{segment}::{rest}"),
|
|
||||||
Self::Tree(items) => match items.len() {
|
|
||||||
0 => "{}".fmt(f),
|
|
||||||
1..=3 => f.delimit("{ ", " }").list(items, ", "),
|
|
||||||
_ => f
|
|
||||||
.delimit_indented("{", "}")
|
|
||||||
.list_wrap("\n", items, ",\n", ",\n"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> Display for Bind<A> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self(op, gens, pat, exprs) = self;
|
|
||||||
op.fmt(f)?;
|
|
||||||
if !gens.is_empty() {
|
|
||||||
f.delimit("<", "> ").list(gens, ", ")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
match op {
|
|
||||||
BindOp::Match => f.delimit(fmt!("{pat} => "), "").list(exprs, ",!? "),
|
|
||||||
BindOp::Fn | BindOp::Mod | BindOp::Impl => {
|
|
||||||
f.delimit(fmt!("{pat} "), "").list(exprs, ",!? ")
|
|
||||||
}
|
|
||||||
BindOp::Struct | BindOp::Enum => match pat {
|
|
||||||
Pat::NamedStruct(name, bind) => match bind.as_ref() {
|
|
||||||
Pat::Op(PatOp::Tuple, parts) => f
|
|
||||||
.delimit_indented(fmt!("{name} {{"), "}")
|
|
||||||
.list_wrap("\n", parts, ",\n", ",\n"),
|
|
||||||
other => write!(f, "{name} {{ {other} }}"),
|
|
||||||
},
|
|
||||||
_ => pat.fmt(f),
|
|
||||||
},
|
|
||||||
_ => match exprs.as_slice() {
|
|
||||||
[] => write!(f, "{pat}"),
|
|
||||||
[value] => write!(f, "{pat} = {value}"),
|
|
||||||
[value, fail] => write!(f, "{pat} = {value} else {fail}"),
|
|
||||||
other => f.delimit(fmt!("{pat} ("), ")").list(other, ", "),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for BindOp {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_str(match self {
|
|
||||||
Self::Let => "let ",
|
|
||||||
Self::Const => "const ",
|
|
||||||
Self::Static => "static ",
|
|
||||||
Self::Type => "type ",
|
|
||||||
Self::Struct => "struct ",
|
|
||||||
Self::Enum => "enum ",
|
|
||||||
Self::Fn => "fn ",
|
|
||||||
Self::Mod => "mod ",
|
|
||||||
Self::Impl => "impl ",
|
|
||||||
Self::Match => "",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> Display for Make<A> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self(expr, make_arms) = self;
|
|
||||||
f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> Display for MakeArm<A> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self(name, Some(body)) => write!(f, "{name}: {body}"),
|
|
||||||
Self(name, None) => write!(f, "{name}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Pat {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Ignore => "_".fmt(f),
|
|
||||||
Self::Never => "!".fmt(f),
|
|
||||||
Self::Lit(literal) => literal.fmt(f),
|
|
||||||
Self::MetId(name) => write!(f, "`{name}"),
|
|
||||||
Self::Name(name) => name.fmt(f),
|
|
||||||
Self::Path(path) => path.fmt(f),
|
|
||||||
Self::NamedStruct(name, bind) => match bind.as_ref() {
|
|
||||||
Pat::Op(PatOp::Tuple, parts) => {
|
|
||||||
f.delimit(fmt!("{name} {{ "), " }").list(parts, ", ")
|
|
||||||
}
|
|
||||||
other => write!(f, "{name} {{ {other} }}"),
|
|
||||||
},
|
|
||||||
Self::NamedTuple(name, bind) => write!(f, "{name} {bind}"),
|
|
||||||
Self::Op(PatOp::Tuple, pats) => f.delimit("(", ")").list(pats, ", "),
|
|
||||||
Self::Op(PatOp::Slice, pats) => f.delimit("[", "]").list(pats, ", "),
|
|
||||||
Self::Op(op @ PatOp::Arrep, pats) => f.delimit("[", "]").list(pats, op),
|
|
||||||
Self::Op(op @ (PatOp::Typed | PatOp::Fn), pats) => f.list(pats, op),
|
|
||||||
Self::Op(op @ PatOp::Alt, pats) => f.delimit("<", ">").list(pats, op),
|
|
||||||
Self::Op(op, pats) => match pats.as_slice() {
|
|
||||||
[] => op.fmt(f),
|
|
||||||
[rest] => write!(f, "{op}{rest}"),
|
|
||||||
_ => f.delimit("(", ")").list(pats, op),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for PatOp {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_str(match self {
|
|
||||||
Self::Pub => "pub ",
|
|
||||||
Self::Mut => "mut ",
|
|
||||||
Self::Ref => "&",
|
|
||||||
Self::Ptr => "*",
|
|
||||||
Self::Rest => "..",
|
|
||||||
Self::RangeEx => "..",
|
|
||||||
Self::RangeIn => "..=",
|
|
||||||
Self::Tuple => ", ",
|
|
||||||
Self::Slice => ", ",
|
|
||||||
Self::Arrep => "; ",
|
|
||||||
Self::Typed => ": ",
|
|
||||||
Self::Fn => " -> ",
|
|
||||||
Self::Alt => " | ",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Annotation> TryFrom<Expr<A>> for Pat {
|
|
||||||
type Error = Expr<A>;
|
|
||||||
|
|
||||||
fn try_from(value: Expr<A>) -> Result<Self, Self::Error> {
|
|
||||||
Ok(match value {
|
|
||||||
Expr::Id(Path { mut parts }) if parts.len() == 1 => {
|
|
||||||
match parts.pop().expect("parts should have len 1") {
|
|
||||||
ig if ig == "_" => Self::Ignore,
|
|
||||||
name => Self::Name(name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expr::Id(path) => Self::Path(path),
|
|
||||||
Expr::MetId(name) => Self::MetId(name),
|
|
||||||
Expr::Lit(literal) => Self::Lit(literal),
|
|
||||||
Expr::Op(Op::RangeEx, exprs) => Self::Op(
|
|
||||||
if exprs.len() > 1 {
|
|
||||||
PatOp::RangeEx
|
|
||||||
} else {
|
|
||||||
PatOp::Rest
|
|
||||||
},
|
|
||||||
exprs
|
|
||||||
.into_iter()
|
|
||||||
.map(Self::try_from)
|
|
||||||
.collect::<Result<Vec<_>, Expr<A>>>()?,
|
|
||||||
),
|
|
||||||
Expr::Op(Op::Tuple, exprs) => Self::Op(
|
|
||||||
PatOp::Tuple,
|
|
||||||
exprs
|
|
||||||
.into_iter()
|
|
||||||
.map(Self::try_from)
|
|
||||||
.collect::<Result<_, _>>()?,
|
|
||||||
),
|
|
||||||
Expr::Op(Op::Array, exprs) => Self::Op(
|
|
||||||
PatOp::Slice,
|
|
||||||
exprs
|
|
||||||
.into_iter()
|
|
||||||
.map(Self::try_from)
|
|
||||||
.collect::<Result<_, _>>()?,
|
|
||||||
),
|
|
||||||
other => Err(other)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<A: Annotation> TryFrom<Anno<Expr<A>, A>> for Pat {
|
|
||||||
type Error = Expr<A>;
|
|
||||||
|
|
||||||
fn try_from(value: Anno<Expr<A>, A>) -> Result<Self, Self::Error> {
|
|
||||||
Self::try_from(value.0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
284
src/ast/display.rs
Normal file
284
src/ast/display.rs
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::fmt::FmtAdapter;
|
||||||
|
use std::{fmt::Display, format_args as fmt};
|
||||||
|
|
||||||
|
impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Expr<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Omitted => "/* omitted */".fmt(f),
|
||||||
|
Self::Id(id) => id.fmt(f),
|
||||||
|
Self::MetId(id) => write!(f, "`{id}"),
|
||||||
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
|
Self::Use(v) => write!(f, "use {v}"),
|
||||||
|
Self::Bind(v) => v.fmt(f),
|
||||||
|
Self::Make(v) => v.fmt(f),
|
||||||
|
|
||||||
|
Self::Op(op @ Op::Continue, exprs) => f.delimit(op, "").list(exprs, "!?,"),
|
||||||
|
Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() {
|
||||||
|
[cond, pass, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => {
|
||||||
|
write!(f, "{op}{cond} {pass}")
|
||||||
|
}
|
||||||
|
[cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"),
|
||||||
|
other => f.delimit(fmt!("({op}, "), ")").list(other, ", "),
|
||||||
|
},
|
||||||
|
Self::Op(op @ Op::Match, exprs) => match exprs.as_slice() {
|
||||||
|
[scrutinee, arms @ ..] => f
|
||||||
|
.delimit_indented(fmt!("{op}{scrutinee} {{"), "}")
|
||||||
|
.list_wrap("\n", arms, ",\n", ",\n"),
|
||||||
|
[] => write!(f, "{op} () {{}}"), // invalid, but whatever.
|
||||||
|
},
|
||||||
|
Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "),
|
||||||
|
Self::Op(Op::ArRep, exprs) => f.delimit("[", "]").list(exprs, "; "),
|
||||||
|
Self::Op(Op::Block, exprs) => f
|
||||||
|
.delimit_indented("{", "}")
|
||||||
|
.list_wrap("\n", exprs, "\n", "\n"),
|
||||||
|
Self::Op(Op::Tuple, exprs) => f.delimit("(", ")").list(exprs, ", "),
|
||||||
|
Self::Op(Op::Group, exprs) => f.list(exprs, ", "),
|
||||||
|
Self::Op(Op::Meta, exprs) => match exprs.as_slice() {
|
||||||
|
[meta, expr @ ..] => f.delimit(fmt!("#[{meta}]\n"), "").list(expr, ","),
|
||||||
|
[] => write!(f, "#[]"),
|
||||||
|
},
|
||||||
|
|
||||||
|
Self::Op(op @ Op::Call, exprs) => match exprs.as_slice() {
|
||||||
|
[callee, args @ ..] => f.delimit(fmt!("{callee}("), ")").list(args, ", "),
|
||||||
|
[] => write!(f, "{op}"),
|
||||||
|
},
|
||||||
|
Self::Op(op @ Op::Index, exprs) => match exprs.as_slice() {
|
||||||
|
[callee, args @ ..] => f.delimit(fmt!("{callee}["), "]").list(args, ", "),
|
||||||
|
[] => write!(f, "{op}"),
|
||||||
|
},
|
||||||
|
|
||||||
|
Self::Op(op @ Op::Do, exprs) => f.list(exprs, op),
|
||||||
|
Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "),
|
||||||
|
Self::Op(op @ Op::Try, exprs) => f.delimit("(", fmt!("){op}")).list(exprs, ", "),
|
||||||
|
Self::Op(op, exprs) => match exprs.as_slice() {
|
||||||
|
[one] => write!(f, "{op}{one}"),
|
||||||
|
many => f.delimit("(", ")").list(many, op),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Op {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Op::Do => ";\n",
|
||||||
|
Op::As => " as ",
|
||||||
|
Op::Macro => "macro ",
|
||||||
|
Op::Block => "{}",
|
||||||
|
Op::Array => "[]",
|
||||||
|
Op::ArRep => "[;]",
|
||||||
|
Op::Group => "()",
|
||||||
|
Op::Tuple => "()",
|
||||||
|
Op::Meta => "#[]",
|
||||||
|
Op::Try => "?",
|
||||||
|
Op::Index => "",
|
||||||
|
Op::Call => "",
|
||||||
|
Op::Pub => "pub ",
|
||||||
|
Op::Loop => "loop ",
|
||||||
|
Op::Match => "match ",
|
||||||
|
Op::If => "if ",
|
||||||
|
Op::While => "while ",
|
||||||
|
Op::Break => "break ",
|
||||||
|
Op::Return => "return ",
|
||||||
|
Op::Continue => "continue",
|
||||||
|
Op::Dot => ".",
|
||||||
|
Op::RangeEx => "..",
|
||||||
|
Op::RangeIn => "..=",
|
||||||
|
Op::Neg => "-",
|
||||||
|
Op::Not => "!",
|
||||||
|
Op::Identity => "!!",
|
||||||
|
Op::Refer => "&",
|
||||||
|
Op::Deref => "*",
|
||||||
|
Op::Mul => " * ",
|
||||||
|
Op::Div => " / ",
|
||||||
|
Op::Rem => " % ",
|
||||||
|
Op::Add => " + ",
|
||||||
|
Op::Sub => " - ",
|
||||||
|
Op::Shl => " << ",
|
||||||
|
Op::Shr => " >> ",
|
||||||
|
Op::And => " & ",
|
||||||
|
Op::Xor => " ^ ",
|
||||||
|
Op::Or => " | ",
|
||||||
|
Op::Lt => " < ",
|
||||||
|
Op::Leq => " <= ",
|
||||||
|
Op::Eq => " == ",
|
||||||
|
Op::Neq => " != ",
|
||||||
|
Op::Geq => " >= ",
|
||||||
|
Op::Gt => " > ",
|
||||||
|
Op::LogAnd => " && ",
|
||||||
|
Op::LogXor => " ^^ ",
|
||||||
|
Op::LogOr => " || ",
|
||||||
|
Op::Set => " = ",
|
||||||
|
Op::MulSet => " *= ",
|
||||||
|
Op::DivSet => " /= ",
|
||||||
|
Op::RemSet => " %= ",
|
||||||
|
Op::AddSet => " += ",
|
||||||
|
Op::SubSet => " -= ",
|
||||||
|
Op::ShlSet => " <<= ",
|
||||||
|
Op::ShrSet => " >>= ",
|
||||||
|
Op::AndSet => " &= ",
|
||||||
|
Op::XorSet => " ^= ",
|
||||||
|
Op::OrSet => " |= ",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Path {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self { parts } = self;
|
||||||
|
f.list(parts, "::")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Literal {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Bool(v) => v.fmt(f),
|
||||||
|
Self::Char(c) => write!(f, "'{}'", c.escape_debug()),
|
||||||
|
Self::Int(i, 2) => write!(f, "0b{i:b}"),
|
||||||
|
Self::Int(i, 8) => write!(f, "0o{i:o}"),
|
||||||
|
Self::Int(i, 16) => write!(f, "0x{i:x}"),
|
||||||
|
Self::Int(i, _) => i.fmt(f),
|
||||||
|
Self::Str(s) => write!(f, "\"{}\"", s.escape_debug()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Use {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Glob => "*".fmt(f),
|
||||||
|
Self::Name(name) => name.fmt(f),
|
||||||
|
Self::Path(segment, rest) => write!(f, "{segment}::{rest}"),
|
||||||
|
Self::Tree(items) => match items.len() {
|
||||||
|
0 => "{}".fmt(f),
|
||||||
|
1..=3 => f.delimit("{ ", " }").list(items, ", "),
|
||||||
|
_ => f
|
||||||
|
.delimit_indented("{", "}")
|
||||||
|
.list_wrap("\n", items, ",\n", ",\n"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Bind<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(op, gens, pat, exprs) = self;
|
||||||
|
op.fmt(f)?;
|
||||||
|
if !gens.is_empty() {
|
||||||
|
f.delimit("<", "> ").list(gens, ", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match op {
|
||||||
|
BindOp::Match => f.delimit(fmt!("{pat} => "), "").list(exprs, ",!? "),
|
||||||
|
BindOp::Fn | BindOp::Mod | BindOp::Impl => {
|
||||||
|
f.delimit(fmt!("{pat} "), "").list(exprs, ",!? ")
|
||||||
|
}
|
||||||
|
BindOp::Struct | BindOp::Enum => match pat {
|
||||||
|
Pat::NamedStruct(name, bind) => match bind.as_ref() {
|
||||||
|
Pat::Op(PatOp::Tuple, parts) => f
|
||||||
|
.delimit_indented(fmt!("{name} {{"), "}")
|
||||||
|
.list_wrap("\n", parts, ",\n", ",\n"),
|
||||||
|
other => write!(f, "{name} {{ {other} }}"),
|
||||||
|
},
|
||||||
|
_ => pat.fmt(f),
|
||||||
|
},
|
||||||
|
_ => match exprs.as_slice() {
|
||||||
|
[] => write!(f, "{pat}"),
|
||||||
|
[value] => write!(f, "{pat} = {value}"),
|
||||||
|
[value, fail] => write!(f, "{pat} = {value} else {fail}"),
|
||||||
|
other => f.delimit(fmt!("{pat} ("), ")").list(other, ", "),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BindOp {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Let => "let ",
|
||||||
|
Self::Const => "const ",
|
||||||
|
Self::Static => "static ",
|
||||||
|
Self::Type => "type ",
|
||||||
|
Self::Struct => "struct ",
|
||||||
|
Self::Enum => "enum ",
|
||||||
|
Self::Fn => "fn ",
|
||||||
|
Self::Mod => "mod ",
|
||||||
|
Self::Impl => "impl ",
|
||||||
|
Self::Match => "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for Make<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self(expr, make_arms) = self;
|
||||||
|
f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Annotation> Display for MakeArm<A> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self(name, Some(body)) => write!(f, "{name}: {body}"),
|
||||||
|
Self(name, None) => write!(f, "{name}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Pat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Ignore => "_".fmt(f),
|
||||||
|
Self::Never => "!".fmt(f),
|
||||||
|
Self::Lit(literal) => literal.fmt(f),
|
||||||
|
Self::MetId(name) => write!(f, "`{name}"),
|
||||||
|
Self::Name(name) => name.fmt(f),
|
||||||
|
Self::Path(path) => path.fmt(f),
|
||||||
|
Self::NamedStruct(name, bind) => match bind.as_ref() {
|
||||||
|
Pat::Op(PatOp::Tuple, parts) => {
|
||||||
|
f.delimit(fmt!("{name} {{ "), " }").list(parts, ", ")
|
||||||
|
}
|
||||||
|
other => write!(f, "{name} {{ {other} }}"),
|
||||||
|
},
|
||||||
|
Self::NamedTuple(name, bind) => write!(f, "{name} {bind}"),
|
||||||
|
Self::Op(PatOp::Tuple, pats) => f.delimit("(", ")").list(pats, ", "),
|
||||||
|
Self::Op(PatOp::Slice, pats) => f.delimit("[", "]").list(pats, ", "),
|
||||||
|
Self::Op(op @ PatOp::Arrep, pats) => f.delimit("[", "]").list(pats, op),
|
||||||
|
Self::Op(op @ (PatOp::Typed | PatOp::Fn), pats) => f.list(pats, op),
|
||||||
|
Self::Op(op @ PatOp::Alt, pats) => f.delimit("<", ">").list(pats, op),
|
||||||
|
Self::Op(op, pats) => match pats.as_slice() {
|
||||||
|
[] => op.fmt(f),
|
||||||
|
[rest] => write!(f, "{op}{rest}"),
|
||||||
|
_ => f.delimit("(", ")").list(pats, op),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PatOp {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Pub => "pub ",
|
||||||
|
Self::Mut => "mut ",
|
||||||
|
Self::Ref => "&",
|
||||||
|
Self::Ptr => "*",
|
||||||
|
Self::Rest => "..",
|
||||||
|
Self::RangeEx => "..",
|
||||||
|
Self::RangeIn => "..=",
|
||||||
|
Self::Tuple => ", ",
|
||||||
|
Self::Slice => ", ",
|
||||||
|
Self::Arrep => "; ",
|
||||||
|
Self::Typed => ": ",
|
||||||
|
Self::Fn => " -> ",
|
||||||
|
Self::Alt => " | ",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user