201 lines
7.0 KiB
Rust
201 lines
7.0 KiB
Rust
use std::rc::Rc;
|
|
|
|
use crate::vm::value::{ConsCell, Keyword, Value, ValueString};
|
|
|
|
mod binding;
|
|
mod call;
|
|
mod condition;
|
|
mod error;
|
|
mod function;
|
|
mod lambda;
|
|
mod loops;
|
|
mod macros;
|
|
|
|
pub use binding::*;
|
|
pub use call::*;
|
|
pub use condition::*;
|
|
pub use error::*;
|
|
pub use function::*;
|
|
pub use lambda::*;
|
|
pub use loops::*;
|
|
pub use macros::*;
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub enum Expression {
|
|
Nil,
|
|
BooleanLiteral(bool),
|
|
StringLiteral(ValueString),
|
|
IntegerLiteral(i64),
|
|
Identifier(Rc<str>),
|
|
Lambda(LambdaExpression),
|
|
Defun(DefunExpression),
|
|
Call(CallExpression),
|
|
If(IfExpression),
|
|
Cond(CondExpression),
|
|
Setq(SetqExpression),
|
|
Let(LetExpression),
|
|
Defmacro(DefmacroExpression),
|
|
SyntaxError(ParseError),
|
|
Quote(Rc<Value>),
|
|
While(WhileExpression),
|
|
}
|
|
|
|
impl Expression {
|
|
fn map_or<T, F: FnOnce(T) -> Self>(result: Result<T, ParseError>, map: F) -> Rc<Self> {
|
|
match result {
|
|
Ok(r) => Rc::new(map(r)),
|
|
Err(error) => Rc::new(Self::SyntaxError(error)),
|
|
}
|
|
}
|
|
|
|
pub fn parse(value: &Value) -> Result<Rc<Self>, Vec<ParseError>> {
|
|
let inner = Self::parse_inner(value);
|
|
let mut errors = vec![];
|
|
if inner.collect_errors(&mut errors) {
|
|
Err(errors)
|
|
} else {
|
|
Ok(inner)
|
|
}
|
|
}
|
|
|
|
fn parse_inner(value: &Value) -> Rc<Self> {
|
|
match value {
|
|
Value::Nil => Rc::new(Self::Nil),
|
|
Value::Boolean(value) => Rc::new(Self::BooleanLiteral(*value)),
|
|
Value::Integer(value) => Rc::new(Self::IntegerLiteral(*value)),
|
|
Value::String(value) => Rc::new(Self::StringLiteral(value.clone())),
|
|
Value::Vector(_vector) => todo!(),
|
|
Value::Identifier(value) => Rc::new(Self::Identifier(value.clone())),
|
|
Value::Quasi(_value) => todo!("{value}"),
|
|
Value::Unquote(_value) => todo!("Unquote {_value}"),
|
|
Value::Quote(value) => Rc::new(Self::Quote(value.clone())),
|
|
Value::Cons(cons) => {
|
|
let ConsCell(car, cdr) = cons.as_ref();
|
|
match car {
|
|
Value::Keyword(Keyword::Lambda) => {
|
|
Self::map_or(LambdaExpression::parse(cdr, value), Expression::Lambda)
|
|
}
|
|
Value::Keyword(Keyword::If) => {
|
|
Self::map_or(IfExpression::parse(cdr, value), Expression::If)
|
|
}
|
|
Value::Keyword(Keyword::Cond) => {
|
|
Self::map_or(CondExpression::parse(cdr, value), Expression::Cond)
|
|
}
|
|
Value::Keyword(Keyword::Defun) => {
|
|
Self::map_or(DefunExpression::parse(cdr, value), Expression::Defun)
|
|
}
|
|
Value::Keyword(keyword @ (Keyword::Let | Keyword::LetStar)) => {
|
|
Self::map_or(LetExpression::parse(cdr, value, *keyword), Expression::Let)
|
|
}
|
|
Value::Keyword(Keyword::Setq) => {
|
|
Self::map_or(SetqExpression::parse(cdr, value), Expression::Setq)
|
|
}
|
|
Value::Keyword(Keyword::Defmacro) => {
|
|
Self::map_or(DefmacroExpression::parse(cdr, value), Expression::Defmacro)
|
|
}
|
|
Value::Keyword(Keyword::Quote) => {
|
|
let value = match cdr {
|
|
Value::Cons(cons) => cons.0.clone(),
|
|
_ => Value::Nil,
|
|
};
|
|
Rc::new(Self::Quote(value.into()))
|
|
}
|
|
Value::Keyword(Keyword::While) => {
|
|
Self::map_or(WhileExpression::parse(cdr, value), Expression::While)
|
|
}
|
|
_ => Self::map_or(CallExpression::parse(cons, value), Expression::Call),
|
|
}
|
|
}
|
|
Value::Keyword(_) => todo!(),
|
|
Value::NativeFunction(_) | Value::BytecodeFunction(_) | Value::OpaqueValue(_) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CollectErrors<ParseError> for Expression {
|
|
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
|
match self {
|
|
Self::SyntaxError(error) => {
|
|
errors.push(error.clone());
|
|
true
|
|
}
|
|
Self::If(condition) => condition.collect_errors(errors),
|
|
Self::Cond(condition) => condition.collect_errors(errors),
|
|
Self::Lambda(lambda) => lambda.collect_errors(errors),
|
|
Self::Defun(defun) => defun.collect_errors(errors),
|
|
Self::Call(call) => call.collect_errors(errors),
|
|
Self::Let(let_) => let_.collect_errors(errors),
|
|
Self::Setq(setq) => setq.collect_errors(errors),
|
|
Self::Defmacro(defmacro) => defmacro.collect_errors(errors),
|
|
Self::While(cloop) => cloop.collect_errors(errors),
|
|
Self::Nil
|
|
| Self::IntegerLiteral(_)
|
|
| Self::Identifier(_)
|
|
| Self::BooleanLiteral(_)
|
|
| Self::Quote(_)
|
|
| Self::StringLiteral(_) => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{
|
|
compile::syntax::{ExpectedWhat, ExpectedWhere, Expression, ParseError, ParseErrorKind},
|
|
vm::value::{Keyword, Value},
|
|
};
|
|
|
|
#[test]
|
|
fn test_parse_basic() {
|
|
let v = Value::Nil;
|
|
let e = Expression::parse(&v).unwrap();
|
|
assert_eq!(e.as_ref(), &Expression::Nil);
|
|
|
|
let v = Value::Integer(1234);
|
|
let e = Expression::parse(&v).unwrap();
|
|
assert_eq!(e.as_ref(), &Expression::IntegerLiteral(1234));
|
|
|
|
let v = Value::Boolean(false);
|
|
let e = Expression::parse(&v).unwrap();
|
|
assert_eq!(e.as_ref(), &Expression::BooleanLiteral(false));
|
|
|
|
let v = Value::Identifier("a".into());
|
|
let e = Expression::parse(&v).unwrap();
|
|
assert_eq!(e.as_ref(), &Expression::Identifier("a".into()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_syntax_error() {
|
|
let inner_if = Value::list_or_nil([Value::Keyword(Keyword::If)]);
|
|
let inner_lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda)]);
|
|
let outer_if = Value::list_or_nil([
|
|
Value::Keyword(Keyword::If),
|
|
inner_if.clone(),
|
|
inner_lambda.clone(),
|
|
Value::Integer(3),
|
|
]);
|
|
let e = Expression::parse(&outer_if).unwrap_err();
|
|
assert_eq!(
|
|
e,
|
|
vec![
|
|
ParseError {
|
|
input: inner_if,
|
|
error: ParseErrorKind::Expected(
|
|
ExpectedWhat::Condition,
|
|
ExpectedWhere::AfterKeyword(Keyword::If)
|
|
)
|
|
},
|
|
ParseError {
|
|
input: inner_lambda,
|
|
error: ParseErrorKind::Expected(
|
|
ExpectedWhat::ArgumentList,
|
|
ExpectedWhere::AfterKeyword(Keyword::Lambda)
|
|
)
|
|
}
|
|
]
|
|
);
|
|
}
|
|
}
|