diff --git a/src/error.rs b/src/error.rs index 270f3e6..f395d03 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use crate::lexer::Token; +use crate::syntax::lexer::Token; use ariadne::{Color, Fmt, Label, Report, ReportKind, Source}; use chumsky::error::{Simple, SimpleReason}; use std::fmt::Display; diff --git a/src/lib.rs b/src/lib.rs index d015d07..96177c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,3 @@ pub mod error; -pub mod lexer; -pub mod list; -pub mod parser; pub mod repl; -pub mod value; +pub mod syntax; diff --git a/src/list.rs b/src/list.rs deleted file mode 100644 index b85c71d..0000000 --- a/src/list.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::value::{write_seq, Value}; -use std::fmt::Display; - -/// Single-linked list -#[derive(Debug, Default, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum List<'a> { - Cons(Value<'a>, Box), - #[default] - Nil, -} - -impl<'a> List<'a> { - pub fn from_vec(vec: Vec>) -> Self { - vec.into_iter() - .rev() - .fold(Self::Nil, |list, next| Self::Cons(next, Box::new(list))) - } - - pub fn iter(&self) -> Iter<'_, 'a> { - Iter(self) - } -} - -impl<'a> Display for List<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write_seq(f, self, "(", ")") - } -} - -impl<'l, 'v> IntoIterator for &'l List<'v> { - type Item = &'l Value<'v>; - type IntoIter = Iter<'l, 'v>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -pub struct Iter<'l, 'v>(&'l List<'v>); -impl<'l, 'v> Iterator for Iter<'l, 'v> { - type Item = &'l Value<'v>; - - fn next(&mut self) -> Option { - match self.0 { - List::Cons(head, rest) => { - self.0 = &**rest; - Some(head) - } - List::Nil => None, - } - } -} - -impl<'a> IntoIterator for List<'a> { - type Item = Value<'a>; - type IntoIter = IntoIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - IntoIter(self) - } -} - -pub struct IntoIter<'a>(List<'a>); -impl<'a> Iterator for IntoIter<'a> { - type Item = Value<'a>; - - fn next(&mut self) -> Option { - match std::mem::take(&mut self.0) { - List::Cons(first, mut rest) => { - std::mem::swap(&mut self.0, rest.as_mut()); - Some(first) - } - List::Nil => None, - } - } -} diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 04b9016..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::{lexer::Token, list::List, value::Value}; -use chumsky::{prelude::*, Stream}; -use logos::Logos; - -/// Parse source string into a value -pub fn read(src: &str) -> Result, Vec>>> { - 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, Vec>, Error = Simple>> { - recursive(|value| { - let atom = select! { - Token::Symbol("true") => Value::Bool(true), - Token::Symbol("false") => Value::Bool(false), - Token::Symbol("nil") => Value::Nil, - Token::Symbol(s) => Value::Symbol(s.into()), - Token::Keyword(k) => Value::Keyword(k.into()), - Token::String(s) => Value::String(s.into()), - Token::Number(n) => Value::Number(n), - }; - - let list = value - .clone() - .repeated() - .map(List::from_vec) - .map(Box::new) - .map(Value::List) - .delimited_by(just(Token::LeftParen), just(Token::RightParen)); - - let vector = value - .clone() - .repeated() - .map(Value::Vector) - .delimited_by(just(Token::LeftBracket), just(Token::RightBracket)); - - let map = value - .clone() - .then(value.clone()) - .repeated() - .collect() - .map(Value::Map) - .delimited_by(just(Token::LeftCurly), just(Token::RightCurly)); - - let quote = just(Token::Quote).ignore_then(value).map(|value| { - Value::List(Box::new(List::Cons( - Value::Symbol("quote".into()), - Box::new(List::Cons(value, Box::new(List::Nil))), - ))) - }); - - atom.or(list).or(vector).or(map).or(quote) - }) - .repeated() - .then_ignore(end()) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_parse<'a>(src: &'a str, expected: &'a [Value<'a>]) { - assert_eq!(read(src).unwrap(), expected); - } - - #[test] - fn simple_fn() { - assert_parse( - "(defn test [] (println \"Hello, world!\"))", - &[Value::List(Box::new(List::from_vec(vec![ - Value::Symbol("defn".into()), - Value::Symbol("test".into()), - Value::Vector(vec![]), - Value::List(Box::new(List::from_vec(vec![ - Value::Symbol("println".into()), - Value::String("Hello, world!".into()), - ]))), - ])))], - ) - } -} diff --git a/src/repl.rs b/src/repl.rs index d3b9bef..b8d2100 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,7 +1,6 @@ +use crate::{error::Error, syntax::parser::read}; use rustyline::{error::ReadlineError, Editor}; -use crate::{error::Error, parser::read}; - pub fn repl() -> rustyline::Result<()> { let prompt = "#=> "; let mut rl = Editor::<()>::new()?; diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs new file mode 100644 index 0000000..b6f0dcb --- /dev/null +++ b/src/syntax/ast.rs @@ -0,0 +1,57 @@ +use ordered_float::OrderedFloat; +use std::{ + borrow::Cow, + fmt::{Display, Write}, +}; + +/// A Wisp AST +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum Expr<'a> { + List(Vec), + Vector(Vec), + Map(Vec<(Self, Self)>), + Symbol(Cow<'a, str>), + Keyword(Cow<'a, str>), + Bool(bool), + Number(OrderedFloat), + String(Cow<'a, str>), + Nil, +} + +impl<'a> Display for Expr<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::List(list) => write_seq(f, list, "(", ")"), + Self::Vector(vec) => write_seq(f, vec, "[", "]"), + Self::Map(map) => write_seq( + f, + map.into_iter().map(|(k, v)| format!("{k} {v}")), + "[", + "]", + ), + Self::Symbol(sym) => write!(f, "{sym}"), + Self::Keyword(kw) => write!(f, ":{kw}"), + Self::Bool(b) => write!(f, "{b}"), + Self::Number(n) => write!(f, "{n}"), + Self::String(s) => write!(f, "\"{s}\""), + Self::Nil => write!(f, "nil"), + } + } +} + +pub(crate) fn write_seq( + f: &mut impl Write, + iterable: impl IntoIterator, + delimiter_left: &str, + delimiter_right: &str, +) -> std::fmt::Result { + let mut iter = iterable.into_iter(); + write!(f, "{delimiter_left}")?; + if let Some(x) = iter.next() { + write!(f, "{x}")?; + } + for x in iter { + write!(f, " {x}")?; + } + write!(f, "{delimiter_right}") +} diff --git a/src/lexer.rs b/src/syntax/lexer.rs similarity index 100% rename from src/lexer.rs rename to src/syntax/lexer.rs diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs new file mode 100644 index 0000000..483656f --- /dev/null +++ b/src/syntax/mod.rs @@ -0,0 +1,3 @@ +pub mod ast; +pub mod lexer; +pub mod parser; diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs new file mode 100644 index 0000000..8c0a443 --- /dev/null +++ b/src/syntax/parser.rs @@ -0,0 +1,61 @@ +use super::{ast::Expr, lexer::Token}; +use chumsky::{prelude::*, Stream}; +use logos::Logos; + +/// Parse source string into a Expr +pub fn read(src: &str) -> Result, Vec>>> { + 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, Vec>, Error = Simple>> { + recursive(|expr| { + let atom = select! { + Token::Symbol("true") => Expr::Bool(true), + Token::Symbol("false") => Expr::Bool(false), + Token::Symbol("nil") => Expr::Nil, + Token::Symbol(s) => Expr::Symbol(s.into()), + Token::Keyword(k) => Expr::Keyword(k.into()), + Token::String(s) => Expr::String(s.into()), + Token::Number(n) => Expr::Number(n), + }; + + let list = expr + .clone() + .repeated() + .map(Expr::List) + .delimited_by(just(Token::LeftParen), just(Token::RightParen)); + + let vector = expr + .clone() + .repeated() + .map(Expr::Vector) + .delimited_by(just(Token::LeftBracket), just(Token::RightBracket)); + + let map = expr + .clone() + .then(expr.clone()) + .repeated() + .collect() + .map(Expr::Map) + .delimited_by(just(Token::LeftCurly), just(Token::RightCurly)); + + let quote = just(Token::Quote) + .ignore_then(expr) + .map(|expr| Expr::List(vec![Expr::Symbol("quote".into()), expr])); + + atom.or(list).or(vector).or(map).or(quote) + }) + .repeated() + .then_ignore(end()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_parse<'a>(src: &'a str, expected: &'a [Expr<'a>]) { + assert_eq!(read(src).unwrap(), expected); + } +} diff --git a/src/value.rs b/src/value.rs deleted file mode 100644 index eff25b2..0000000 --- a/src/value.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::list::List; -use ordered_float::OrderedFloat; -use std::{ - borrow::Cow, - collections::BTreeMap, - fmt::{Debug, Display, Write}, - rc::Rc, -}; - -/// A Wisp value -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Value<'a> { - List(Box>), - Vector(Vec), - Map(BTreeMap), - Module(Module<'a>), - Function(Function<'a>), - InternalFn(fn(&'a List<'a>) -> Value<'a>), - Macro(/* TODO: Bytecode */), - Symbol(Symbol<'a>), - Keyword(Cow<'a, str>), - Bool(bool), - Number(OrderedFloat), - String(Cow<'a, str>), - Nil, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Module<'a> { - members: BTreeMap>>, - symbol_table: BTreeMap, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Function<'a> { - // TODO: bytecode - captures: Box<[Capture<'a>]>, - symbol_table: BTreeMap, SymbolMapping>, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Capture<'a> { - Reference(Rc>), - Owned(Value<'a>), -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum SymbolMapping { - Local(u64), - Capture(u64), -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Symbol<'a> { - Interned(u64), - String(Cow<'a, str>), -} - -impl<'a> From<&'a str> for Symbol<'a> { - fn from(s: &'a str) -> Self { - Self::String(Cow::Borrowed(s)) - } -} - -impl<'a> Display for Symbol<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Symbol::Interned(n) => write!(f, "#{n}"), - Symbol::String(s) => write!(f, "{s}"), - } - } -} - -impl<'a> Display for Value<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Value::List(list) => write!(f, "{list}"), - Value::Vector(vec) => write_seq(f, vec, "[", "]"), - Value::Map(map) => write_seq( - f, - map.into_iter().map(|(k, v)| format!("{k} {v}")), - "[", - "]", - ), - Value::Module(_) => write!(f, "#module#"), - Value::Symbol(sym) => write!(f, "{sym}"), - Value::Keyword(kw) => write!(f, ":{kw}"), - Value::Function { .. } => write!(f, "#fn#"), - Value::InternalFn(function) => write!(f, "#internal-fn@{function:p}"), - Value::Macro() => write!(f, "#macro#"), - Value::Bool(b) => write!(f, "{b}"), - Value::Number(n) => write!(f, "{n}"), - Value::String(s) => write!(f, "\"{s}\""), - Value::Nil => write!(f, "nil"), - } - } -} - -pub(crate) fn write_seq( - f: &mut impl Write, - iterable: impl IntoIterator, - delimiter_left: &str, - delimiter_right: &str, -) -> std::fmt::Result { - let mut iter = iterable.into_iter(); - write!(f, "{delimiter_left}")?; - if let Some(x) = iter.next() { - write!(f, "{x}")?; - } - for x in iter { - write!(f, " {x}")?; - } - write!(f, "{delimiter_right}") -}