Basic parser

trunk
Alona EM 2021-12-29 16:49:49 +00:00
parent 32e7a46476
commit c98550907d
5 changed files with 179 additions and 0 deletions

5
.gitignore vendored
View File

@ -23,3 +23,8 @@ Cargo.lock
*.scm#*
.#*.scm
# Added by cargo
/target

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "handball"
version = "0.1.0"
edition = "2021"
[features]
[dependencies]
anyhow = "1.0.52"
fs-err = "2.6.0"
logos = "0.12.0"

11
hello.scm Normal file
View File

@ -0,0 +1,11 @@
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/closed_closure_in_function.lox
(define f #f)
((lambda ()
(define local 1)
(define (f_)
(display local))
(set! f f_)))
(f)

45
src/main.rs Normal file
View File

@ -0,0 +1,45 @@
mod parser;
use fs_err as fs;
#[derive(Debug, PartialEq, logos::Logos)]
enum Kind {
#[token("(")]
Lparen,
#[token(")")]
Rparen,
#[regex(r"[A-Za-z0-9!$%&*+-./:<=>?@^_~]+")]
// Most literals are floats, and can be seperated later
Symbol,
#[regex(r"#(f|t)")]
Boolean,
#[regex(r#""(\\.|[^"\\])*""#)]
String,
#[error]
#[regex(r"[ \t\n\f\r]+", logos::skip)]
#[regex(r";.*", logos::skip)]
Error,
}
fn main() -> anyhow::Result<()> {
let arg = std::env::args()
.nth(1)
.ok_or_else(|| anyhow::anyhow!("Useage: handball sources.scm"))?;
let src = fs::read_to_string(&arg)?;
dbg!(parser::parse(&src));
Ok(())
}
#[derive(Debug)]
enum Ast<'s> {
Tree(Vec<Ast<'s>>),
Leaf(&'s str),
}

107
src/parser.rs Normal file
View File

@ -0,0 +1,107 @@
use std::iter::Peekable;
use logos::Logos;
use crate::{Ast, Kind};
type Error = String;
struct Parser<'s> {
lex: Peekable<Lexer<'s>>,
errors: Vec<Error>,
}
pub(crate) fn parse(s: &str) -> (Vec<Ast>, Vec<Error>) {
let lex = Lexer {
lex: Kind::lexer(s),
}
.peekable();
let mut parser = Parser {
lex,
errors: vec![],
};
let mut trees = Vec::new();
while parser.lex.peek().is_some() {
if let Some(t) = parser.parse() {
trees.push(t);
}
}
(trees, parser.errors)
}
impl<'s> Parser<'s> {
fn parse(&mut self) -> Option<Ast<'s>> {
let Token { kind, span, src } = self.next()?;
// match tok {
// Token::Lparen => todo!(),
// Token::Rparen => {
// self.errors.push(format!("Unexpected lparen "));
// self.parse()
// }
// Token::Symbol => Some(Ast::Leaf(self.lex.str())),
// Token::String => todo!(),
// Token::Error => todo!(),
// }
Some(match kind {
Kind::Lparen => {
let mut bits = Vec::new();
while self.lex.peek()?.kind != Kind::Rparen {
bits.push(self.parse()?);
}
let rp = self.next()?;
assert_eq!(rp.kind, Kind::Rparen);
Ast::Tree(bits)
}
Kind::Rparen => {
self.errors.push(format!("Unexpected `)` at {:?}", span));
// Keep going from the next token
return self.parse();
}
Kind::Symbol | Kind::String | Kind::Boolean => Ast::Leaf(src),
Kind::Error => unreachable!("Removed by Parser::next"),
})
}
fn next(&mut self) -> Option<Token<'s>> {
for tok in &mut self.lex {
if tok.kind == crate::Kind::Error {
self.errors
.push(format!("Bad token at {:?}: `{}`", tok.span, tok.src))
} else {
return Some(tok);
}
}
self.errors.push("Unexpected EOF".to_owned());
None
}
}
struct Lexer<'s> {
lex: logos::Lexer<'s, crate::Kind>,
}
impl<'s> Iterator for Lexer<'s> {
type Item = Token<'s>;
fn next(&mut self) -> Option<Self::Item> {
self.lex.next().map(|kind| Token {
kind,
span: self.lex.span(),
src: self.lex.slice(),
})
}
}
struct Token<'s> {
kind: Kind,
span: logos::Span,
src: &'s str,
}