Moved things around, removed unused stuff
This commit is contained in:
parent
45bc514a49
commit
bb50f1e450
|
@ -1,4 +1,4 @@
|
||||||
use crate::lexer::Token;
|
use crate::syntax::lexer::Token;
|
||||||
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
|
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
|
||||||
use chumsky::error::{Simple, SimpleReason};
|
use chumsky::error::{Simple, SimpleReason};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod lexer;
|
|
||||||
pub mod list;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod repl;
|
pub mod repl;
|
||||||
pub mod value;
|
pub mod syntax;
|
||||||
|
|
76
src/list.rs
76
src/list.rs
|
@ -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<Self>),
|
|
||||||
#[default]
|
|
||||||
Nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> List<'a> {
|
|
||||||
pub fn from_vec(vec: Vec<Value<'a>>) -> 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<Self::Item> {
|
|
||||||
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<Self::Item> {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Value>, 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<Value<'a>>, Error = Simple<Token<'a>>> {
|
|
||||||
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()),
|
|
||||||
]))),
|
|
||||||
])))],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
use crate::{error::Error, syntax::parser::read};
|
||||||
use rustyline::{error::ReadlineError, Editor};
|
use rustyline::{error::ReadlineError, Editor};
|
||||||
|
|
||||||
use crate::{error::Error, parser::read};
|
|
||||||
|
|
||||||
pub fn repl() -> rustyline::Result<()> {
|
pub fn repl() -> rustyline::Result<()> {
|
||||||
let prompt = "#=> ";
|
let prompt = "#=> ";
|
||||||
let mut rl = Editor::<()>::new()?;
|
let mut rl = Editor::<()>::new()?;
|
||||||
|
|
57
src/syntax/ast.rs
Normal file
57
src/syntax/ast.rs
Normal file
|
@ -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<Self>),
|
||||||
|
Vector(Vec<Self>),
|
||||||
|
Map(Vec<(Self, Self)>),
|
||||||
|
Symbol(Cow<'a, str>),
|
||||||
|
Keyword(Cow<'a, str>),
|
||||||
|
Bool(bool),
|
||||||
|
Number(OrderedFloat<f64>),
|
||||||
|
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<Item = impl Display>,
|
||||||
|
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}")
|
||||||
|
}
|
3
src/syntax/mod.rs
Normal file
3
src/syntax/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod ast;
|
||||||
|
pub mod lexer;
|
||||||
|
pub mod parser;
|
61
src/syntax/parser.rs
Normal file
61
src/syntax/parser.rs
Normal file
|
@ -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<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>>> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
114
src/value.rs
114
src/value.rs
|
@ -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<List<'a>>),
|
|
||||||
Vector(Vec<Self>),
|
|
||||||
Map(BTreeMap<Self, Self>),
|
|
||||||
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<f64>),
|
|
||||||
String(Cow<'a, str>),
|
|
||||||
Nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Module<'a> {
|
|
||||||
members: BTreeMap<u64, Rc<Value<'a>>>,
|
|
||||||
symbol_table: BTreeMap<String, u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Function<'a> {
|
|
||||||
// TODO: bytecode
|
|
||||||
captures: Box<[Capture<'a>]>,
|
|
||||||
symbol_table: BTreeMap<Symbol<'a>, SymbolMapping>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub enum Capture<'a> {
|
|
||||||
Reference(Rc<Value<'a>>),
|
|
||||||
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<Item = impl Display>,
|
|
||||||
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}")
|
|
||||||
}
|
|
Loading…
Reference in a new issue