Files
lysp/src/compile/syntax/lambda.rs
T

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