Span everything

main
ondra05 2022-07-24 22:21:34 +02:00
parent d480c17589
commit 53ff55f52d
3 changed files with 56 additions and 13 deletions

View File

@ -1,4 +1,4 @@
use crate::{error::Error, syntax::parser::read};
use crate::{error::Error, syntax::parser::parse};
use rustyline::{error::ReadlineError, Editor};
pub fn repl() -> rustyline::Result<()> {
@ -6,7 +6,7 @@ pub fn repl() -> rustyline::Result<()> {
let mut rl = Editor::<()>::new()?;
loop {
match rl.readline(prompt) {
Ok(line) => match read(&line) {
Ok(line) => match parse(&line) {
Ok(values) => values.iter().for_each(|e| println!("{e}")),
Err(e) => e.into_iter().map(Error::Parse).for_each(|e| {
if let Err(e) = e.report(&line) {

View File

@ -2,14 +2,48 @@ use ordered_float::OrderedFloat;
use std::{
borrow::Cow,
fmt::{Display, Write},
hash::Hash,
};
pub type Span = std::ops::Range<usize>;
/// A spanned item
#[derive(Clone, Debug)]
pub struct Spanned<T> {
pub item: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub fn new(item: T, span: Span) -> Self {
Self { item, span }
}
}
impl<T: Display> Display for Spanned<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} \x1B[2m@ {:?}\x1B[22m", self.item, self.span)
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool {
self.item == other.item
}
}
impl<T: Hash> Hash for Spanned<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.item.hash(state);
}
}
/// A Wisp AST
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, Hash, PartialEq)]
pub enum Expr<'a> {
List(Vec<Self>),
Vector(Vec<Self>),
Map(Vec<(Self, Self)>),
List(Vec<Spanned<Self>>),
Vector(Vec<Spanned<Self>>),
Map(Vec<(Spanned<Self>, Spanned<Self>)>),
Quote(Box<Spanned<Self>>),
Symbol(Cow<'a, str>),
Keyword(Cow<'a, str>),
Number(OrderedFloat<f64>),
@ -22,6 +56,7 @@ impl<'a> Display for Expr<'a> {
Self::List(list) => write_seq(f, list, "(", ")"),
Self::Vector(vec) => write_seq(f, vec, "[", "]"),
Self::Map(map) => write_seq(f, map.iter().map(|(k, v)| format!("{k} {v}")), "{", "}"),
Self::Quote(expr) => write!(f, "'{expr}"),
Self::Symbol(sym) => write!(f, "{sym}"),
Self::Keyword(kw) => write!(f, ":{kw}"),
Self::Number(n) => write!(f, "{n}"),

View File

@ -1,15 +1,18 @@
use super::{ast::Expr, lexer::Token};
use super::{
ast::{Expr, Spanned},
lexer::Token,
};
use chumsky::{prelude::*, Stream};
use logos::Logos;
/// Parse source string into a Expr
pub fn read(src: &str) -> Result<Vec<Expr>, Vec<Simple<Token<'_>>>> {
pub fn parse(src: &str) -> Result<Vec<Spanned<Expr>>, Vec<Simple<Token<'_>>>> {
let lexer = Token::lexer(src);
let len = lexer.source().len();
parser().parse(Stream::from_iter(len..len + 1, lexer.spanned()))
}
fn parser<'a>() -> impl Parser<Token<'a>, Vec<Expr<'a>>, Error = Simple<Token<'a>>> {
fn parser<'a>() -> impl Parser<Token<'a>, Vec<Spanned<Expr<'a>>>, Error = Simple<Token<'a>>> {
recursive(|expr| {
let atom = select! {
Token::Symbol(s) => Expr::Symbol(s.into()),
@ -40,9 +43,14 @@ fn parser<'a>() -> impl Parser<Token<'a>, Vec<Expr<'a>>, Error = Simple<Token<'a
let quote = just(Token::Quote)
.ignore_then(expr)
.map(|expr| Expr::List(vec![Expr::Symbol("quote".into()), expr]));
.map(Box::new)
.map(Expr::Quote);
atom.or(list).or(vector).or(map).or(quote)
atom.or(list)
.or(vector)
.or(map)
.or(quote)
.map_with_span(Spanned::new)
})
.repeated()
.then_ignore(end())
@ -52,7 +60,7 @@ fn parser<'a>() -> impl Parser<Token<'a>, Vec<Expr<'a>>, Error = Simple<Token<'a
mod tests {
use super::*;
fn assert_parse<'a>(src: &'a str, expected: &'a [Expr<'a>]) {
assert_eq!(read(src).unwrap(), expected);
fn assert_parse<'a>(src: &'a str, expected: &'a [Spanned<Expr<'a>>]) {
assert_eq!(parse(src).unwrap(), expected);
}
}