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 { 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 for LambdaExpression { fn collect_errors(&self, errors: &mut Vec) -> 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) ) }] ); } }