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};
|
use rustyline::{error::ReadlineError, Editor};
|
||||||
|
|
||||||
pub fn repl() -> rustyline::Result<()> {
|
pub fn repl() -> rustyline::Result<()> {
|
||||||
|
@ -6,7 +6,7 @@ pub fn repl() -> rustyline::Result<()> {
|
||||||
let mut rl = Editor::<()>::new()?;
|
let mut rl = Editor::<()>::new()?;
|
||||||
loop {
|
loop {
|
||||||
match rl.readline(prompt) {
|
match rl.readline(prompt) {
|
||||||
Ok(line) => match read(&line) {
|
Ok(line) => match parse(&line) {
|
||||||
Ok(values) => values.iter().for_each(|e| println!("{e}")),
|
Ok(values) => values.iter().for_each(|e| println!("{e}")),
|
||||||
Err(e) => e.into_iter().map(Error::Parse).for_each(|e| {
|
Err(e) => e.into_iter().map(Error::Parse).for_each(|e| {
|
||||||
if let Err(e) = e.report(&line) {
|
if let Err(e) = e.report(&line) {
|
||||||
|
|
|
@ -2,14 +2,48 @@ use ordered_float::OrderedFloat;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
fmt::{Display, Write},
|
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
|
/// A Wisp AST
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Hash, PartialEq)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
List(Vec<Self>),
|
List(Vec<Spanned<Self>>),
|
||||||
Vector(Vec<Self>),
|
Vector(Vec<Spanned<Self>>),
|
||||||
Map(Vec<(Self, Self)>),
|
Map(Vec<(Spanned<Self>, Spanned<Self>)>),
|
||||||
|
Quote(Box<Spanned<Self>>),
|
||||||
Symbol(Cow<'a, str>),
|
Symbol(Cow<'a, str>),
|
||||||
Keyword(Cow<'a, str>),
|
Keyword(Cow<'a, str>),
|
||||||
Number(OrderedFloat<f64>),
|
Number(OrderedFloat<f64>),
|
||||||
|
@ -22,6 +56,7 @@ impl<'a> Display for Expr<'a> {
|
||||||
Self::List(list) => write_seq(f, list, "(", ")"),
|
Self::List(list) => write_seq(f, list, "(", ")"),
|
||||||
Self::Vector(vec) => write_seq(f, vec, "[", "]"),
|
Self::Vector(vec) => write_seq(f, vec, "[", "]"),
|
||||||
Self::Map(map) => write_seq(f, map.iter().map(|(k, v)| format!("{k} {v}")), "{", "}"),
|
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::Symbol(sym) => write!(f, "{sym}"),
|
||||||
Self::Keyword(kw) => write!(f, ":{kw}"),
|
Self::Keyword(kw) => write!(f, ":{kw}"),
|
||||||
Self::Number(n) => write!(f, "{n}"),
|
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 chumsky::{prelude::*, Stream};
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
/// Parse source string into a Expr
|
/// 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 lexer = Token::lexer(src);
|
||||||
let len = lexer.source().len();
|
let len = lexer.source().len();
|
||||||
parser().parse(Stream::from_iter(len..len + 1, lexer.spanned()))
|
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| {
|
recursive(|expr| {
|
||||||
let atom = select! {
|
let atom = select! {
|
||||||
Token::Symbol(s) => Expr::Symbol(s.into()),
|
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)
|
let quote = just(Token::Quote)
|
||||||
.ignore_then(expr)
|
.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()
|
.repeated()
|
||||||
.then_ignore(end())
|
.then_ignore(end())
|
||||||
|
@ -52,7 +60,7 @@ fn parser<'a>() -> impl Parser<Token<'a>, Vec<Expr<'a>>, Error = Simple<Token<'a
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn assert_parse<'a>(src: &'a str, expected: &'a [Expr<'a>]) {
|
fn assert_parse<'a>(src: &'a str, expected: &'a [Spanned<Expr<'a>>]) {
|
||||||
assert_eq!(read(src).unwrap(), expected);
|
assert_eq!(parse(src).unwrap(), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue