diff --git a/lexer/src/lib.rs b/lexer/src/lib.rs
index fff11a5..8340291 100644
--- a/lexer/src/lib.rs
+++ b/lexer/src/lib.rs
@@ -2,7 +2,11 @@
mod tests;
use core::str;
-use std::{borrow::Cow, fmt::Debug, slice::SliceIndex};
+use std::{
+ borrow::Cow,
+ fmt::{Debug, Display},
+ slice::SliceIndex,
+};
use logos::Skip;
pub use logos::{Logos, Span, SpannedIter};
@@ -396,9 +400,15 @@ fn accept_operator(lex: &mut Lexer<'_>) {
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Slice<'a>(Cow<'a, [u8]>);
+impl Display for Slice<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", String::from_utf8_lossy(&self.0).as_ref())
+ }
+}
+
impl Debug for Slice<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "\"{}\"", String::from_utf8_lossy(&self.0).as_ref())
+ write!(f, "\"{self}\"")
}
}
diff --git a/parser/src/ast.rs b/parser/src/ast.rs
index f426f26..9ba3523 100644
--- a/parser/src/ast.rs
+++ b/parser/src/ast.rs
@@ -25,7 +25,7 @@ pub struct Rule<'a> {
pub actions: Option
>,
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub enum Atom<'a> {
Variable(Variable<'a>),
String(Slice<'a>),
@@ -55,7 +55,7 @@ pub struct Identifier<'a> {
pub literal: &'a str,
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Clone, Copy)]
pub enum Variable<'a> {
User(Identifier<'a>),
Nr,
@@ -82,7 +82,8 @@ pub enum Expr<'a> {
Node(&'a ExprNode<'a>),
}
-pub type Body<'a> = Vec<'a, Statement<'a>>;
+#[derive(Clone)]
+pub struct Body<'a>(pub Vec<'a, Statement<'a>>);
pub type Pattern<'a> = Either, SpecialPattern>;
#[derive(Debug, Clone)]
@@ -436,13 +437,19 @@ impl BindingPower for Ternary {
}
}
+impl<'a> From>> for Body<'a> {
+ fn from(value: Vec<'a, Statement<'a>>) -> Self {
+ Self(value)
+ }
+}
+
impl Debug for Expr<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Leaf(atom) => write!(f, "{atom:?}"),
Self::Node(expr) => match expr {
ExprNode::FunctionCall(ident, args) => {
- write!(f, "(call Identifier({ident:?})")?;
+ write!(f, "({ident:?}")?;
for arg in args {
write!(f, " {arg:?}")?;
}
@@ -456,127 +463,3 @@ impl Debug for Expr<'_> {
}
}
}
-
-struct ListLispFmt<'a, T: Debug>(&'a [T]);
-struct ListLispCasesFmt<'a, I: Debug, T: Debug>(&'a [(I, Vec<'a, T>)]);
-
-impl Debug for Statement<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Statement::Expression(expr) => write!(f, "{expr:?}"),
- Self::Command {
- name,
- args,
- redirection,
- } => {
- if let Some(rx) = redirection {
- write!(f, "(redir {rx:?} ({name:?}{:?}))", ListLispFmt(args))
- } else {
- write!(f, "({name:?}{:?})", ListLispFmt(args))
- }
- }
- Self::If {
- condition,
- then_body,
- else_body,
- } => {
- if let Some(else_body) = else_body {
- write!(
- f,
- "(if {condition:?} (body{:?}) Some(body{:?}))",
- ListLispFmt(then_body),
- ListLispFmt(else_body)
- )
- } else {
- write!(
- f,
- "(if {condition:?} (body{:?}) None)",
- ListLispFmt(then_body)
- )
- }
- }
- Self::While {
- condition,
- then_body,
- } => write!(
- f,
- "(while {condition:?} (body{:?}))",
- ListLispFmt(then_body)
- ),
- Self::DoWhile {
- then_body,
- condition,
- } => write!(
- f,
- "(do-while (body{:?}) {condition:?})",
- ListLispFmt(then_body)
- ),
- Self::For {
- init,
- condition,
- update,
- body,
- } => {
- write!(
- f,
- "(for {init:?} {condition:?} {update:?} (body{:?}))",
- ListLispFmt(body)
- )
- }
- Self::ForEach { place, array, body } => {
- write!(
- f,
- "(for-each {place:?} {array:?} (body{:?}))",
- ListLispFmt(body)
- )
- }
- Self::Switch {
- scrutinee,
- branches,
- default,
- } => {
- if let Some((dx, i)) = default {
- write!(
- f,
- "(switch {scrutinee:?} (cases{:?}) (body{:?}) {i})",
- ListLispCasesFmt(branches),
- ListLispFmt(dx)
- )
- } else {
- write!(
- f,
- "(switch {scrutinee:?} (cases{:?}))",
- ListLispCasesFmt(branches)
- )
- }
- }
- Self::Continue => write!(f, "(continue)"),
- Self::Break => write!(f, "(break)"),
- Self::Return(expr) => write!(f, "(return {expr:?})"),
- }
- }
-}
-
-impl Debug for ListLispFmt<'_, T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- for e in self.0 {
- write!(f, " {e:?}")?;
- }
- Ok(())
- }
-}
-
-impl Debug for ListLispCasesFmt<'_, I, T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- for (i, e) in self.0 {
- write!(f, " (case {i:?} (eval{:?})", ListLispFmt(e))?;
- }
- Ok(())
- }
-}
-
-impl Debug for Identifier<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}::{}", self.namespace, self.literal)
- }
-}
diff --git a/parser/src/lib.rs b/parser/src/lib.rs
index c645574..1097d78 100644
--- a/parser/src/lib.rs
+++ b/parser/src/lib.rs
@@ -1,5 +1,6 @@
mod ast;
mod lex;
+mod sexpr;
use std::{fmt::Debug, mem::replace};
@@ -173,7 +174,7 @@ impl<'a> Parser<'a> {
match lex.expect_next()? {
Token::ClosedBrace => {
if depth == 0 {
- break Ok(body);
+ break Ok(Body(body));
}
depth -= 1;
}
@@ -238,7 +239,7 @@ impl<'a> Parser<'a> {
return Err(ParsingError::UnexpectedToken);
};
lex.expect(&Token::ClosedParent)?;
- let body: Vec<'_, Statement<'_>> = self.parse_statement_body(lex)?;
+ let body = self.parse_statement_body(lex)?;
Statement::ForEach {
place: *place,
array: *array,
@@ -259,12 +260,14 @@ impl<'a> Parser<'a> {
match case.take() {
Some(Right(())) => {
default = Some((
- replace(&mut body, Vec::new_in(self.arena)),
+ replace(&mut body, Vec::new_in(self.arena)).into(),
branches.len(),
));
}
- Some(Left(atom)) => branches
- .push((atom, replace(&mut body, Vec::new_in(self.arena)))),
+ Some(Left(atom)) => branches.push((
+ atom,
+ replace(&mut body, Vec::new_in(self.arena)).into(),
+ )),
_ => {}
}
case = Some(Left(self.parse_case(lex)?));
@@ -273,7 +276,10 @@ impl<'a> Parser<'a> {
if default.is_some() || matches!(case, Some(Right(()))) {
return Err(ParsingError::UnexpectedToken);
} else if let Some(Left(atom)) = case {
- branches.push((atom, replace(&mut body, Vec::new_in(self.arena))));
+ branches.push((
+ atom,
+ replace(&mut body, Vec::new_in(self.arena)).into(),
+ ));
}
case = Some(Right(()));
} else {
@@ -285,8 +291,8 @@ impl<'a> Parser<'a> {
}
}
match case.take() {
- Some(Right(())) => default = Some((body, branches.len())),
- Some(Left(atom)) => branches.push((atom, body)),
+ Some(Right(())) => default = Some((body.into(), branches.len())),
+ Some(Left(atom)) => branches.push((atom, body.into())),
_ => {}
}
@@ -360,7 +366,7 @@ impl<'a> Parser<'a> {
if lex.peek_is(&Token::OpenBrace) {
self.parse_body(lex)
} else {
- Ok(vec![in self.arena; self.parse_statement(lex)?])
+ Ok(vec![in self.arena; self.parse_statement(lex)?].into())
}
}
diff --git a/parser/src/sexpr.rs b/parser/src/sexpr.rs
new file mode 100644
index 0000000..31d1926
--- /dev/null
+++ b/parser/src/sexpr.rs
@@ -0,0 +1,249 @@
+use std::fmt::{Debug, Formatter, Result};
+
+use crate::ast::{Atom, Body, Identifier, Statement, Variable};
+
+const PRETTY_PRINT_INDENT: usize = 2;
+
+fn fmt_vars(f: &mut Formatter<'_>) -> (bool, usize, String) {
+ let ni = f.width().unwrap_or(0) + PRETTY_PRINT_INDENT;
+ (f.alternate(), ni, " ".repeat(ni))
+}
+
+impl Debug for Statement<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let (alt, ni, pad) = fmt_vars(f);
+
+ match self {
+ Statement::Expression(expr) => {
+ if alt {
+ write!(f, "{expr:#ni$?}")
+ } else {
+ write!(f, "{expr:?}")
+ }
+ }
+ Self::Command {
+ name,
+ args,
+ redirection,
+ } => {
+ if let Some(rx) = redirection {
+ if alt {
+ write!(
+ f,
+ "(redir {rx:?}\n{pad}({name:?}{:#width$?}))",
+ ListLispFmt(args),
+ width = ni
+ )
+ } else {
+ write!(f, "(redir {rx:?} ({name:?}{:?}))", ListLispFmt(args))
+ }
+ } else {
+ if alt {
+ write!(f, "({name:?}{:#width$?})", ListLispFmt(args), width = ni)
+ } else {
+ write!(f, "({name:?}{:?}", ListLispFmt(args))
+ }
+ }
+ }
+ Self::If {
+ condition,
+ then_body,
+ else_body,
+ } => {
+ if alt {
+ write!(f, "(if {condition:?}\n{pad}")?;
+ write!(f, "{then_body:#ni$?}")?;
+ if let Some(else_body) = else_body {
+ write!(f, "\n{pad}Some({else_body:#ni$?})")
+ } else {
+ write!(f, "\n{pad}None)")
+ }
+ } else if let Some(else_body) = else_body {
+ write!(f, "(if {condition:?} {then_body:?} Some({else_body:?})")
+ } else {
+ write!(f, "(if {condition:?} {then_body:?} None)")
+ }
+ }
+ Self::While {
+ condition,
+ then_body,
+ } => {
+ if alt {
+ write!(f, "(while {condition:?}\n{pad}{then_body:#ni$?})")
+ } else {
+ write!(f, "(while {condition:?} {then_body:?})")
+ }
+ }
+ Self::DoWhile {
+ then_body,
+ condition,
+ } => {
+ if alt {
+ write!(f, "(do-while\n{pad}{then_body:#ni$?}\n{pad}{condition:?})")
+ } else {
+ write!(f, "(do-while {then_body:?} {condition:?})")
+ }
+ }
+ Self::For {
+ init,
+ condition,
+ update,
+ body,
+ } => {
+ if alt {
+ write!(
+ f,
+ "(for\n{pad}{init:?}\n{pad}{condition:?}\n{pad}{update:?}\n{pad}{body:#ni$?})"
+ )
+ } else {
+ write!(f, "(for {init:?} {condition:?} {update:?} {body:?})")
+ }
+ }
+ Self::ForEach { place, array, body } => {
+ if alt {
+ write!(f, "(for-each {place:?} {array:?}\n{pad}{body:#ni$?})")
+ } else {
+ write!(f, "(for-each {place:?} {array:?} {body:?})")
+ }
+ }
+ Self::Switch {
+ scrutinee,
+ branches,
+ default,
+ } => {
+ if alt {
+ if let Some((dx, i)) = default {
+ write!(
+ f,
+ "(switch {scrutinee:?}\n{pad}(cases{:#width$?})\n{pad}Some({dx:?}) {i})",
+ ListLispCasesFmt(branches.as_slice()),
+ width = ni
+ )
+ } else {
+ write!(
+ f,
+ "(switch {scrutinee:?}\n{pad}(cases{:#width$?}))",
+ ListLispCasesFmt(branches),
+ width = ni
+ )
+ }
+ } else {
+ if let Some((dx, i)) = default {
+ write!(
+ f,
+ "(switch {scrutinee:?} (cases{:?}) Some({dx:?}) {i})",
+ ListLispCasesFmt(branches.as_slice())
+ )
+ } else {
+ write!(
+ f,
+ "(switch {scrutinee:?} (cases{:?}))",
+ ListLispCasesFmt(branches)
+ )
+ }
+ }
+ }
+ Self::Continue => write!(f, "(continue)"),
+ Self::Break => write!(f, "(break)"),
+ Self::Return(expr) => {
+ if alt {
+ write!(f, "(return {expr:#ni$?})")
+ } else {
+ write!(f, "(return {expr:?})")
+ }
+ }
+ }
+ }
+}
+
+struct ListLispFmt<'a, T: Debug>(&'a [T]);
+impl Debug for ListLispFmt<'_, T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let (alt, ni, pad) = fmt_vars(f);
+ for e in self.0 {
+ if alt {
+ write!(f, "\n{pad}{e:#ni$?}")?;
+ } else {
+ write!(f, " {e:?}")?;
+ }
+ }
+ Ok(())
+ }
+}
+
+struct ListLispCasesFmt<'a, T: Debug>(&'a [(T, Body<'a>)]);
+impl Debug for ListLispCasesFmt<'_, T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let (alt, ni, pad) = fmt_vars(f);
+ for (i, e) in self.0 {
+ if alt {
+ write!(
+ f,
+ "\n{pad}(case {i:?}\n{pad} {:#width$?})",
+ e,
+ width = ni + PRETTY_PRINT_INDENT
+ )?;
+ } else {
+ write!(f, " (case {i:?} {e:?}")?;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl Debug for Identifier<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ write!(f, "{}::{}", self.namespace, self.literal)
+ }
+}
+
+impl Debug for Body<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let (alt, ni, pad) = fmt_vars(f);
+ write!(f, "(body")?;
+ for e in &self.0 {
+ if alt {
+ write!(f, "\n{pad}{e:#ni$?}")?;
+ } else {
+ write!(f, " {e:?}")?;
+ }
+ }
+ write!(f, ")")
+ }
+}
+
+impl Debug for Atom<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ match self {
+ Self::Variable(var) => write!(f, "{var:?}"),
+ Self::String(str) => write!(f, "{str:?}"),
+ Self::Number(num) => write!(f, "{num}"),
+ Self::Regex(rgx) => write!(f, "/{rgx}/"),
+ Self::BigInt() | Self::BigFloat() => unimplemented!(),
+ }
+ }
+}
+
+impl Debug for Variable<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ match self {
+ Self::User(ident) => ident.fmt(f),
+ Self::Nr => write!(f, "NR"),
+ Self::Nf => write!(f, "NF"),
+ Self::Fs => write!(f, "FS"),
+ Self::Rs => write!(f, "RS"),
+ Self::Ofs => write!(f, "OFS"),
+ Self::Ors => write!(f, "ORS"),
+ Self::Filename => write!(f, "FILENAME"),
+ Self::Argc => write!(f, "ARGC"),
+ Self::Argv => write!(f, "ARGV"),
+ Self::Subsep => write!(f, "SUBSEP"),
+ Self::Fnr => write!(f, "FNR"),
+ Self::Argind => write!(f, "ARGIND"),
+ Self::Ofmt => write!(f, "OFMT"),
+ Self::Rstart => write!(f, "RSTART"),
+ Self::Rlength => write!(f, "RLENGTH"),
+ Self::Environ => write!(f, "ENVIRON"),
+ }
+ }
+}