finish trying to write the new perser

This commit is contained in:
nora 2022-09-12 22:27:38 +02:00
parent 34155bcd48
commit a96b97f5de
4 changed files with 142 additions and 27 deletions

View file

@ -65,9 +65,9 @@ impl std::fmt::Debug for FmtPart {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Literal(arg0) => f.debug_tuple("Literal").field(arg0).finish(), Self::Literal(arg0) => f.debug_tuple("Literal").field(arg0).finish(),
Self::Debug(arg0) => f.debug_tuple("Debug").finish(), Self::Debug(_) => f.debug_tuple("Debug").finish(),
Self::Display(arg0) => f.debug_tuple("Display").finish(), Self::Display(_) => f.debug_tuple("Display").finish(),
Self::Advanced(arg0, arg1) => f.debug_tuple("Advanced").field(arg0).finish(), Self::Advanced(arg0, _) => f.debug_tuple("Advanced").field(arg0).finish(),
} }
} }
} }
@ -234,7 +234,9 @@ impl ToTokens for FmtPart {
pub fn format_args(tokens: TokenStream) -> TokenStream { pub fn format_args(tokens: TokenStream) -> TokenStream {
let input = parse_macro_input!(tokens as Input); let input = parse_macro_input!(tokens as Input);
parser::FmtSpecParser::new(&mut input.format_str.chars().peekable()).parse(); if false {
parser::FmtSpecParser::new(&mut input.format_str.chars().peekable()).parse().unwrap();
}
let formatter = Formatter { let formatter = Formatter {
string: input.format_str.chars().peekable(), string: input.format_str.chars().peekable(),

View file

@ -1,9 +1,27 @@
use std::{iter::Peekable, str::Chars}; use std::{iter::Peekable, str::Chars};
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq)]
pub enum Alignment {
Left,
Center,
Right,
}
impl Alignment {
fn from_char(char: char) -> Result<Self, ()> {
match char {
'<' => Ok(Self::Left),
'^' => Ok(Self::Center),
'>' => Ok(Self::Right),
_ => Err(()),
}
}
}
#[derive(Debug, PartialEq)]
pub struct Align { pub struct Align {
amount: usize, kind: Alignment,
char: Option<char>, fill: Option<char>,
} }
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default)]
@ -24,6 +42,12 @@ pub enum FmtType {
Other(String), Other(String),
} }
#[derive(Debug, PartialEq)]
enum Precision {
Num(usize),
Asterisk,
}
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default)]
pub struct FmtSpec { pub struct FmtSpec {
arg: Argument, arg: Argument,
@ -32,12 +56,13 @@ pub struct FmtSpec {
alternate: bool, alternate: bool,
zero: bool, zero: bool,
width: Option<usize>, width: Option<usize>,
precision: Option<usize>, precision: Option<Precision>,
kind: FmtType, kind: FmtType,
} }
pub struct FmtSpecParser<'a> { pub struct FmtSpecParser<'a> {
chars: &'a mut Peekable<Chars<'a>>, chars: &'a mut Peekable<Chars<'a>>,
/// The last state of the parser.
state: State, state: State,
argument: FmtSpec, argument: FmtSpec,
} }
@ -47,13 +72,12 @@ enum State {
Initial, Initial,
Argument, Argument,
// : here // : here
Fill,
Align, Align,
Sign, Sign,
Alternate,
Zero, Zero,
Width, Width,
Precision, Precision,
Type,
Done, Done,
} }
@ -89,21 +113,33 @@ impl<'a> FmtSpecParser<'a> {
false false
} }
fn eat_until(&mut self, char: char) -> Option<String> { fn expect(&mut self, char: char) -> Result<(), ()> {
if !self.eat(char) {
return Err(());
}
Ok(())
}
fn eat_until(&mut self, should_stop: impl Fn(char) -> bool) -> Option<String> {
let mut string = String::new(); let mut string = String::new();
let mut has_char = false; let mut has_char = false;
while self.peek() != Some(char) { // let_chains would be neat here
self.next(); while self.peek().is_some() && !should_stop(self.peek().unwrap()) {
string.push(char); let next = self.next().unwrap();
string.push(next);
has_char = true; has_char = true;
} }
has_char.then_some(string) has_char.then_some(string)
} }
fn eat_until_match(&mut self, char: char) -> Option<String> {
self.eat_until(|c| c == char)
}
fn step(&mut self) -> Result<(), ()> { fn step(&mut self) -> Result<(), ()> {
match self.state { match self.state {
State::Initial => { State::Initial => {
let argument = if let Some(arg) = self.eat_until(':') { let argument = if let Some(arg) = self.eat_until_match(':') {
if let Ok(num) = arg.parse() { if let Ok(num) = arg.parse() {
Argument::PositionalExplicit(num) Argument::PositionalExplicit(num)
} else { } else {
@ -119,18 +155,94 @@ impl<'a> FmtSpecParser<'a> {
if !self.eat(':') { if !self.eat(':') {
return Err(()); return Err(());
} }
Ok(())
} }
State::Argument => todo!(), State::Argument => match self.next().ok_or(())? {
State::Fill => todo!(), c @ ('>' | '^' | '<') => {
State::Align => todo!(), self.argument.align = Some(Align {
State::Sign => todo!(), kind: Alignment::from_char(c)?,
State::Zero => todo!(), fill: None,
State::Width => todo!(), });
State::Precision => todo!(), self.state = State::Align;
State::Type => todo!(), }
other => {
if let Some(c @ ('>' | '^' | '<')) = self.peek() {
self.argument.align = Some(Align {
kind: Alignment::from_char(c).unwrap(),
fill: Some(other),
});
}
self.state = State::Align;
}
},
State::Align => {
if let Some(c @ ('+' | '-')) = self.peek() {
self.next();
self.argument.sign = Some(c);
}
self.state = State::Sign;
}
State::Sign => {
if self.eat('#') {
self.argument.alternate = true;
}
self.state = State::Alternate;
}
State::Alternate => {
if self.eat('0') {
self.argument.zero = true;
}
self.state = State::Zero;
}
State::Zero => {
if let Some(width) = self.eat_until(|c| !c.is_ascii_digit()) {
let width = width.parse().map_err(|_| ())?;
self.argument.width = Some(width);
}
self.state = State::Width;
}
State::Width => {
if self.eat('.') {
if let Some(precision) = self.eat_until(|c| c != '*' && !c.is_ascii_digit()) {
let precision = if precision == "*" {
Precision::Asterisk
} else {
Precision::Num(precision.parse().map_err(|_| ())?)
};
self.argument.precision = Some(precision);
}
}
self.state = State::Precision;
}
State::Precision => match self.next() {
Some('?') => {
self.argument.kind = FmtType::Debug;
self.expect('}')?;
}
Some('x') => {
self.expect('?')?;
self.argument.kind = FmtType::LowerHex;
self.expect('}')?;
}
Some('X') => {
self.expect('?')?;
self.argument.kind = FmtType::UpperHex;
self.expect('}')?;
}
Some('}') | None => {}
Some(other) => {
if let Some(kind) = self.eat_until(|c| c == '}') {
self.argument.kind = FmtType::Other(format!("{other}{kind}"));
self.expect('}')?;
} else {
self.argument.kind = FmtType::Default;
self.expect('}')?;
}
}
},
State::Done => unreachable!(), State::Done => unreachable!(),
} }
Ok(())
} }
} }

View file

@ -80,7 +80,7 @@ pub fn ConstWidthArg<T, const WIDTH: usize>(value: T) -> ConstWidthArg<T, WIDTH>
} }
impl<T: Display, const WIDTH: usize> Arguments for ConstWidthArg<T, WIDTH> { impl<T: Display, const WIDTH: usize> Arguments for ConstWidthArg<T, WIDTH> {
fn fmt<W: Write, O: FmtOpts>(&self, f: &mut Formatter<W, O>) -> Result { fn fmt<W: Write, O: FmtOpts>(&self, _: &mut Formatter<W, O>) -> Result {
todo!() todo!()
} }
} }

View file

@ -1,3 +1,5 @@
#![allow(dead_code)]
// for the test macro expansion // for the test macro expansion
#[cfg(test)] #[cfg(test)]
extern crate self as mono_fmt; extern crate self as mono_fmt;
@ -7,7 +9,6 @@ mod opts;
mod write; mod write;
pub use mono_fmt_macro::format_args; pub use mono_fmt_macro::format_args;
use opts::{WithAlternate, WithCenterAlign, WithFill, WithLeftAlign, WithRightAlign, WithWidth};
pub use crate::args::Arguments; pub use crate::args::Arguments;
pub use crate::opts::FmtOpts; pub use crate::opts::FmtOpts;