mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
feat(parser): Rework S-expr printing
This commit is contained in:
+12
-2
@@ -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}\"")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-128
@@ -25,7 +25,7 @@ pub struct Rule<'a> {
|
||||
pub actions: Option<Body<'a>>,
|
||||
}
|
||||
|
||||
#[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<RulePattern<'a>, SpecialPattern>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -436,13 +437,19 @@ impl BindingPower for Ternary {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<'a, Statement<'a>>> 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<T: Debug> 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<I: Debug, T: Debug> 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)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-9
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T: Debug> 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<T: Debug> 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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user