Skip to content

Commit

Permalink
Simplified/optimised various parser things
Browse files Browse the repository at this point in the history
  • Loading branch information
zesterer committed Nov 1, 2023
1 parent 6a5f8f1 commit 74ee78b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 84 deletions.
114 changes: 31 additions & 83 deletions bauble/src/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Debug;

use chumsky::{error, input::InputRef, prelude::*};
use chumsky::prelude::*;
use indexmap::IndexMap;

use crate::{
Expand Down Expand Up @@ -105,19 +105,11 @@ pub fn parser<'a>() -> impl Parser<'a, &'a str, Values, Error<'a>> {
.or_not()
.then(text::int(10))
.then(just('.').ignore_then(text::digits(10).to_slice()).or_not())
.try_map(|((sign, int), dec), span| {
Ok(Value::Num(
format!(
"{}{int}{}",
sign.as_ref()
.map(ToString::to_string)
.unwrap_or(String::default()),
dec.map(|dec| format!(".{dec}"))
.unwrap_or(String::default())
)
.parse()
.map_err(|_| Rich::custom(span, "Failed to parse number"))?,
))
.to_slice()
.try_map(|s: &str, span| {
Ok(Value::Num(s.parse().map_err(|_| {
Rich::custom(span, "Failed to parse number")
})?))
});

// A parser for strings, with escape characters
Expand Down Expand Up @@ -154,28 +146,13 @@ pub fn parser<'a>() -> impl Parser<'a, &'a str, Values, Error<'a>> {
.map(Value::Str);

let literal = just('#').ignore_then(
any()
.filter(|c: &char| {
c.is_alphanumeric()
|| matches!(
c,
'!' | '#'
| '@'
| '%'
| '&'
| '?'
| '.'
| '='
| '<'
| '>'
| '_'
| '-'
| '+'
| '*'
)
})
select! {
c if c.is_alphanumeric() => (),
'!' | '#' | '@' | '%' | '&' | '?' | '.' | '=' | '<' | '>' | '_' | '-' | '+' | '*' => (),
}
.repeated()
.collect::<String>()
.to_slice()
.map(str::to_string)
.map(Value::Raw),
);

Expand Down Expand Up @@ -267,54 +244,25 @@ pub fn parser<'a>() -> impl Parser<'a, &'a str, Values, Error<'a>> {

let path = path.map_with(|path, e| Value::Path(path.spanned(e.span())));

fn raw<'a, 'parse>(
input: &mut InputRef<'a, 'parse, &'a str, extra::Err<Rich<'a, char>>>,
) -> Result<Value, Rich<'a, char>> {
let start_brackets = {
let mut brackets = 0u32;
while let Some(c) = input.peek() {
if c != '{' {
break;
}

brackets += 1;
input.skip();
}

brackets
};

let mut brackets = 0;
let mut body = Vec::default();

loop {
let marker = input.save();
let Some(c) = input.next() else {
Err(<Rich<char> as error::Error<&'a str>>::expected_found(
[Some('}'.into())],
None,
input.span_since(input.offset()),
))?
};

match c {
'}' => {
brackets += 1;
if brackets > start_brackets {
input.rewind(marker);
return Ok(Value::Raw(body.into_iter().collect::<String>()));
}
}
c => {
body.resize(body.len() + brackets as usize, '}');
body.push(c);
brackets = 0;
}
}
}
}

let raw = just('#').ignore_then(custom(raw).delimited_by(just('{'), just('}')));
// The start of a raw string: count the number of open braces
let start_raw = just('{').repeated().at_least(1).count();
// The end of a raw string: accept only *exactly* as many close braces as that which opened it
let end_raw = just('}')
.repeated()
.configure(|repeat, ctx| repeat.exactly(*ctx));
// A raw string is then just any character that's *not* the start of the end
let raw = just('#')
.ignore_then(
start_raw.ignore_with_ctx(
any()
.and_is(end_raw.not())
.repeated()
.to_slice()
.then_ignore(end_raw),
),
)
.map(str::to_string)
.map(Value::Raw);

let value = choice((
bool_,
Expand Down
2 changes: 1 addition & 1 deletion test.bbl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
foo = [$number, $number, 2]

copy number = 1
copy number = 1

0 comments on commit 74ee78b

Please sign in to comment.