122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
use crate::{
|
|
compile::{
|
|
function::FunctionSignature,
|
|
syntax::{
|
|
CollectErrors, ExpectedWhat, ExpectedWhere, FunctionBody, ParseError, ParseErrorKind,
|
|
},
|
|
},
|
|
vm::value::{ConsCell, Keyword, Value},
|
|
};
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub struct LambdaExpression {
|
|
pub signature: FunctionSignature,
|
|
pub body: FunctionBody,
|
|
}
|
|
|
|
impl LambdaExpression {
|
|
pub(super) fn parse(value: &Value, input: &Value) -> Result<Self, ParseError> {
|
|
let Value::Cons(value) = value else {
|
|
return Err(ParseError {
|
|
input: input.clone(),
|
|
error: ParseErrorKind::Expected(
|
|
ExpectedWhat::ArgumentList,
|
|
ExpectedWhere::AfterKeyword(Keyword::Lambda),
|
|
),
|
|
});
|
|
};
|
|
let ConsCell(car, cdr) = value.as_ref();
|
|
let signature = FunctionSignature::parse(car, input)?;
|
|
let body = FunctionBody::parse(cdr, input, Keyword::Lambda)?;
|
|
Ok(Self { signature, body })
|
|
}
|
|
}
|
|
|
|
impl CollectErrors<ParseError> for LambdaExpression {
|
|
fn collect_errors(&self, errors: &mut Vec<ParseError>) -> bool {
|
|
self.body.collect_errors(errors)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::rc::Rc;
|
|
|
|
use crate::{
|
|
compile::{
|
|
function::FunctionSignature,
|
|
syntax::{
|
|
CallExpression, ExpectedWhat, ExpectedWhere, Expression, FunctionBody,
|
|
LambdaExpression, ParseError, ParseErrorKind,
|
|
},
|
|
},
|
|
vm::value::{Keyword, Value},
|
|
};
|
|
|
|
#[test]
|
|
fn test_parse_lambda() {
|
|
let args = Value::list_or_nil([
|
|
Value::Identifier("a".into()),
|
|
Value::Keyword(Keyword::Optional),
|
|
Value::Identifier("b".into()),
|
|
Value::Keyword(Keyword::Rest),
|
|
Value::Identifier("c".into()),
|
|
]);
|
|
let body = Value::list_or_nil([
|
|
Value::Identifier("+".into()),
|
|
Value::Identifier("a".into()),
|
|
Value::Number(1.into()),
|
|
]);
|
|
let lambda = Value::Keyword(Keyword::Lambda).cons(args.cons(body.cons(Value::Nil)));
|
|
let expr = Expression::parse(&lambda).unwrap();
|
|
|
|
assert_eq!(
|
|
expr.as_ref(),
|
|
&Expression::Lambda(LambdaExpression {
|
|
signature: FunctionSignature {
|
|
required_arguments: vec!["a".into()],
|
|
optional_arguments: vec!["b".into()],
|
|
rest_argument: Some("c".into())
|
|
},
|
|
body: FunctionBody {
|
|
head: vec![],
|
|
tail: Expression::Call(CallExpression {
|
|
callee: Expression::Identifier("+".into()).into(),
|
|
arguments: vec![
|
|
Rc::new(Expression::Identifier("a".into())),
|
|
Rc::new(Expression::IntegerLiteral(1.into()))
|
|
]
|
|
})
|
|
.into()
|
|
}
|
|
})
|
|
);
|
|
|
|
// syntax errors
|
|
let lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda)]);
|
|
let e = Expression::parse(&lambda).unwrap_err();
|
|
assert_eq!(
|
|
e,
|
|
vec![ParseError {
|
|
input: lambda,
|
|
error: ParseErrorKind::Expected(
|
|
ExpectedWhat::ArgumentList,
|
|
ExpectedWhere::AfterKeyword(Keyword::Lambda)
|
|
)
|
|
}]
|
|
);
|
|
let lambda = Value::list_or_nil([Value::Keyword(Keyword::Lambda), Value::Nil]);
|
|
let e = Expression::parse(&lambda).unwrap_err();
|
|
assert_eq!(
|
|
e,
|
|
vec![ParseError {
|
|
input: lambda,
|
|
error: ParseErrorKind::Expected(
|
|
ExpectedWhat::Expression,
|
|
ExpectedWhere::AfterArgumentList(Keyword::Lambda)
|
|
)
|
|
}]
|
|
);
|
|
}
|
|
}
|