Files
lysp/src/compile/syntax/mod.rs
T
2026-05-08 17:16:32 +03:00

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)
)
}
]
);
}
}