diff --git a/src/ast.rs b/src/ast.rs index 3adfbb3..def78ed 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,11 +1,15 @@ //! The Abstract Syntax Tree defines an interface between the parser and type checker +use crate::span::Span; + pub mod macro_matcher; pub mod visit; pub mod fold; +mod display; + /// An annotation: extra data added on to important AST nodes. pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {} impl Annotation for T {} @@ -291,13 +295,6 @@ impl std::fmt::Debug for Anno { ::fmt(&self.0, f) } } - -impl From<&str> for Path { - fn from(value: &str) -> Self { - Self { parts: vec![value.to_owned()] } - } -} - impl Default for Expr { fn default() -> Self { Self::Op(Op::Tuple, vec![]) @@ -337,337 +334,8 @@ impl Expr { } } -use crate::{fmt::FmtAdapter, span::Span}; -use std::{fmt::Display, format_args as fmt}; - -impl Display for Anno { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl Display for Expr { - 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 Display for Bind { - 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 Display for Make { - 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 Display for MakeArm { - 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 TryFrom> for Pat { - type Error = Expr; - - fn try_from(value: Expr) -> Result { - 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::, Expr>>()?, - ), - Expr::Op(Op::Tuple, exprs) => Self::Op( - PatOp::Tuple, - exprs - .into_iter() - .map(Self::try_from) - .collect::>()?, - ), - Expr::Op(Op::Array, exprs) => Self::Op( - PatOp::Slice, - exprs - .into_iter() - .map(Self::try_from) - .collect::>()?, - ), - other => Err(other)?, - }) - } -} -impl TryFrom, A>> for Pat { - type Error = Expr; - - fn try_from(value: Anno, A>) -> Result { - Self::try_from(value.0) +impl From<&str> for Path { + fn from(value: &str) -> Self { + Self { parts: vec![value.to_owned()] } } } diff --git a/src/ast/display.rs b/src/ast/display.rs new file mode 100644 index 0000000..5bc13ac --- /dev/null +++ b/src/ast/display.rs @@ -0,0 +1,284 @@ +use super::*; +use crate::fmt::FmtAdapter; +use std::{fmt::Display, format_args as fmt}; + +impl Display for Anno { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Display for Expr { + 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 Display for Bind { + 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 Display for Make { + 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 Display for MakeArm { + 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 => " | ", + }) + } +}