Span everything
This commit is contained in:
parent
08d032998c
commit
6cc1b5013a
|
@ -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) {
|
||||
|
|
|
@ -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}"),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue