Basic parser
parent
32e7a46476
commit
c98550907d
|
@ -23,3 +23,8 @@ Cargo.lock
|
|||
*.scm#*
|
||||
.#*.scm
|
||||
|
||||
|
||||
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
|
|
@ -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"
|
|
@ -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)
|
|
@ -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),
|
||||
}
|
|
@ -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,
|
||||
}
|
Loading…
Reference in New Issue