Partial work toward a PEG parser library

This commit is contained in:
2025-04-30 00:12:04 -07:00
parent 58293ed625
commit b03cccb8dd
5 changed files with 110 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
use super::super::preprocess::peg::Parser;
use anyhow::Result;
fn parse_program(p: &mut Parser) -> Result<()> {
p.star(|p| parse_line(p))?;
p.eof()?;
Ok(())
}
fn parse_line(p: &mut Parser) -> Result<()> {
p.star(|p| p.char(|c| c != '\n'))?;
p.literal("\n")?;
Ok(())
}
+1
View File
@@ -0,0 +1 @@
pub mod labels;
+1
View File
@@ -1,4 +1,5 @@
mod encoding; mod encoding;
mod labels;
mod preprocess; mod preprocess;
mod world; mod world;
+1
View File
@@ -1,3 +1,4 @@
pub mod eval; pub mod eval;
pub mod parse; pub mod parse;
pub mod peg;
pub mod scan; pub mod scan;
+93
View File
@@ -0,0 +1,93 @@
use anyhow::{Result, anyhow, bail};
// TODO: Add offsets
pub enum Tag {
Open(&'static str),
Close,
}
pub struct Parser {
input: String,
offset: usize,
output: Vec<Tag>,
}
#[derive(Clone, Copy)]
pub struct Savepoint {
offset: usize,
num_tags: usize,
}
impl Parser {
pub fn new(input: &str) -> Self {
Self {
input: input.into(),
offset: 0,
output: Vec::new(),
}
}
pub fn save(&self) -> Savepoint {
Savepoint {
offset: self.offset,
num_tags: self.output.len(),
}
}
pub fn restore(&mut self, sp: Savepoint) {
self.offset = sp.offset;
self.output.truncate(sp.num_tags);
}
pub fn eof(&mut self) -> Result<()> {
if self.input.len() == self.offset {
Ok(())
} else {
bail!("No match")
}
}
pub fn literal(&mut self, str: &str) -> Result<()> {
if self.input[self.offset..].starts_with(str) {
self.offset += str.len();
Ok(())
} else {
bail!("No match")
}
}
pub fn char<F>(&mut self, f: F) -> Result<()>
where
F: Fn(char) -> bool,
{
if let Some(c) = self.input[self.offset..].chars().next() {
if f(c) {
self.offset += c.len_utf8();
return Ok(());
}
}
bail!("No match")
}
pub fn star<F>(&mut self, mut f: F) -> Result<()>
where
F: FnMut(&mut Self) -> Result<()>,
{
let mut sp = self.save();
while let Ok(_) = f(self) {
sp = self.save();
}
self.restore(sp);
Ok(())
}
}
mod test {
use super::*;
#[test]
fn test_hello() {
let mut p = Parser::new("foo");
p.literal("f").unwrap();
p.star(|p| p.literal("o")).unwrap();
}
}