Compare commits

...

2 commits

Author SHA1 Message Date
Schrottkatze 3164328568
implement multiple members, member_values and trailing commata 2024-10-23 10:52:44 +02:00
Schrottkatze c564d0f24c
implement Marker::abandon 2024-10-23 10:51:43 +02:00
5 changed files with 36 additions and 28 deletions

View file

@ -33,9 +33,23 @@ mod object {
} }
member(p); member(p);
while p.at(SyntaxKind::COMMA) {
// not always an error, later configurable
let potential_unexpected_comma = p.start("potential_unexpected_comma");
p.eat(SyntaxKind::COMMA);
p.eat(SyntaxKind::BRACE_CLOSE); if member(p).is_none() {
Some(obj_start.complete(p, SyntaxKind::OBJECT)) potential_unexpected_comma.complete(p, SyntaxKind::TRAILING_COMMA);
} else {
potential_unexpected_comma.abandon(p);
}
}
Some(if !p.eat(SyntaxKind::BRACE_CLOSE) {
obj_start.error(p, SyntaxError::UnclosedObject)
} else {
obj_start.complete(p, SyntaxKind::OBJECT)
})
} }
fn member(p: &mut Parser) -> Option<CompletedMarker> { fn member(p: &mut Parser) -> Option<CompletedMarker> {
@ -56,9 +70,12 @@ mod object {
todo!("handle wrong tokens") todo!("handle wrong tokens")
} }
let member_value_start = p.start("member_value_start");
if value(p) { if value(p) {
member_value_start.complete(p, SyntaxKind::MEMBER_VALUE);
Some(member_start.complete(p, SyntaxKind::MEMBER)) Some(member_start.complete(p, SyntaxKind::MEMBER))
} else { } else {
member_value_start.abandon(p);
let e = member_start.error(p, SyntaxError::MemberMissingValue); let e = member_start.error(p, SyntaxError::MemberMissingValue);
Some( Some(
e.precede(p, "member but failed already") e.precede(p, "member but failed already")

View file

@ -1,29 +1,3 @@
mod grammar; mod grammar;
mod syntax_error; mod syntax_error;
mod syntax_kind; mod syntax_kind;
#[cfg(test)]
mod test {
use pawarser::parser::ParserBuilder;
use crate::{
grammar::{value, Parser},
syntax_kind::{lex, SyntaxKind},
};
#[test]
fn test() {
const TEST_DATA: &str = r#"{"hello_world": "meow"}"#;
let toks = lex(TEST_DATA);
let mut p: Parser = ParserBuilder::new(toks)
.add_meaningless(SyntaxKind::WHITESPACE)
.add_meaningless(SyntaxKind::NEWLINE)
.build();
value(&mut p);
let out = p.finish();
assert_eq!("", format!("{:#?}", out))
}
}

View file

@ -2,7 +2,9 @@ use crate::syntax_kind::SyntaxKind;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxError { pub enum SyntaxError {
UnclosedObject,
DisallowedKeyType(SyntaxKind), DisallowedKeyType(SyntaxKind),
MemberMissingValue, MemberMissingValue,
UnexpectedTrailingComma,
} }
impl pawarser::parser::SyntaxError for SyntaxError {} impl pawarser::parser::SyntaxError for SyntaxError {}

View file

@ -24,6 +24,9 @@ pub enum SyntaxKind {
ARRAY, ARRAY,
ELEMENT, ELEMENT,
// SyntaxKinds for future json5/etc support
TRAILING_COMMA,
// Tokens // Tokens
// Regexes adapted from [the logos handbook](https://logos.maciej.codes/examples/json_borrowed.html) // Regexes adapted from [the logos handbook](https://logos.maciej.codes/examples/json_borrowed.html)
#[token("true")] #[token("true")]

View file

@ -59,6 +59,18 @@ impl Marker {
mut self, mut self,
p: &mut Parser<SyntaxKind, SyntaxErr>, p: &mut Parser<SyntaxKind, SyntaxErr>,
) { ) {
self.bomb.defuse();
// clean up empty tombstone event from marker
if self.pos == p.events.len() - 1 {
match p.events.pop() {
Some(Event::Start {
kind: NodeKind::Tombstone,
forward_parent: None,
}) => (),
_ => unreachable!(),
}
}
} }
} }