use std::rc::Rc; use crate::{ compile::{ function::FunctionSignature, syntax::{ CollectErrors, ExpectedWhat, ExpectedWhere, Expression, ParseError, ParseErrorKind, maybe_docstring, }, }, vm::value::{ConsCell, IdentifierValue, Keyword, StringValue, Value}, }; #[derive(Debug, PartialEq)] pub struct FunctionBody { pub head: Vec>, pub tail: Rc, } #[derive(Debug, PartialEq)] pub struct LambdaExpression { pub docstring: Option, pub signature: FunctionSignature, pub body: FunctionBody, } #[derive(Debug, PartialEq)] pub struct DefunExpression { pub name: IdentifierValue, pub docstring: Option, pub signature: FunctionSignature, pub body: FunctionBody, } #[derive(Debug, PartialEq)] pub struct PrognExpression { pub body: FunctionBody, } impl FunctionSignature { pub(super) fn parse(mut value: &Value, input: &Value) -> Result { enum Mode { Required, Optional, Rest, } let mut required_arguments = vec![]; let mut optional_arguments = vec![]; let mut rest_argument = None; let mut mode = Mode::Required; while !value.is_nil() { let Value::Cons(cons) = value else { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ArgumentSpec, ExpectedWhere::InArgumentList, ), }); }; let ConsCell(car, cdr) = cons.as_ref(); match (&mode, car) { (Mode::Required, Value::Identifier(arg)) => { required_arguments.push(arg.clone()); } (Mode::Optional, Value::Identifier(arg)) => { optional_arguments.push(arg.clone()); } (Mode::Rest, Value::Identifier(arg)) => { if rest_argument.is_some() { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ExactlyOneArgument, ExpectedWhere::AfterKeyword(Keyword::Rest), ), }); } rest_argument = Some(arg.clone()); } (Mode::Required, Value::Keyword(Keyword::Optional)) => { mode = Mode::Optional; } (Mode::Required, Value::Keyword(Keyword::Rest)) => { mode = Mode::Rest; } (Mode::Optional, Value::Keyword(Keyword::Rest)) => { if optional_arguments.is_empty() { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::AtLeastOneArgument, ExpectedWhere::AfterKeyword(Keyword::Optional), ), }); } mode = Mode::Rest; } _ => { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ArgumentSpec, ExpectedWhere::InArgumentList, ), }); } } value = cdr; } match mode { Mode::Required => (), Mode::Optional => { if optional_arguments.is_empty() { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::AtLeastOneArgument, ExpectedWhere::AfterKeyword(Keyword::Optional), ), }); } } Mode::Rest => { if rest_argument.is_none() { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ExactlyOneArgument, ExpectedWhere::AfterKeyword(Keyword::Rest), ), }); } } } Ok(Self { required_arguments, optional_arguments, rest_argument, }) } } impl FunctionBody { pub(super) fn parse( mut value: &Value, input: &Value, inside: Keyword, ) -> Result { let mut expressions = vec![]; while !value.is_nil() { let Value::Cons(cons) = value else { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ProperList, ExpectedWhere::AfterArgumentList(inside), ), }); }; let ConsCell(car, cdr) = cons.as_ref(); let expression = Expression::parse_inner(car); expressions.push(expression); value = cdr; } let Some(tail) = expressions.pop() else { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::Expression, ExpectedWhere::AfterArgumentList(inside), ), }); }; Ok(Self { head: expressions, tail, }) } } impl PrognExpression { pub(super) fn parse(value: &Value, input: &Value) -> Result { let body = FunctionBody::parse(value, input, Keyword::Progn)?; Ok(Self { body }) } } 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 (cdr, docstring) = maybe_docstring(cdr); let body = FunctionBody::parse(cdr, input, Keyword::Lambda)?; Ok(Self { docstring, signature, body, }) } } impl DefunExpression { 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::ProperList, ExpectedWhere::InFunctionDefinition, ), }); }; let ConsCell(identifier, cdr) = value.as_ref(); let Value::Identifier(identifier) = identifier else { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::Identifier, ExpectedWhere::AfterKeyword(Keyword::Defun), ), }); }; let Value::Cons(cdr) = cdr else { return Err(ParseError { input: input.clone(), error: ParseErrorKind::Expected( ExpectedWhat::ProperList, ExpectedWhere::InFunctionDefinition, ), }); }; let ConsCell(car, cdr) = cdr.as_ref(); let signature = FunctionSignature::parse(car, input)?; let (cdr, docstring) = maybe_docstring(cdr); let body = FunctionBody::parse(cdr, input, Keyword::Lambda)?; Ok(Self { name: identifier.clone(), docstring, signature, body, }) } } impl CollectErrors for FunctionBody { fn collect_errors(&self, errors: &mut Vec) -> bool { let mut r = false; for expr in self.head.iter() { r |= expr.collect_errors(errors); } r |= self.tail.collect_errors(errors); r } } impl CollectErrors for LambdaExpression { fn collect_errors(&self, errors: &mut Vec) -> bool { self.body.collect_errors(errors) } } impl CollectErrors for DefunExpression { fn collect_errors(&self, errors: &mut Vec) -> bool { self.body.collect_errors(errors) } } impl CollectErrors for PrognExpression { 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) ) }] ); } #[test] fn test_parse_function_body() { let v = Value::list_or_nil([Value::Number(1.into())]); let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap(); assert_eq!( e, FunctionBody { head: vec![], tail: Rc::new(Expression::IntegerLiteral(1.into())) } ); let v = Value::list_or_nil([ Value::Number(1.into()), Value::Number(2.into()), Value::Number(3.into()), ]); let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap(); assert_eq!( e, FunctionBody { head: vec![ Rc::new(Expression::IntegerLiteral(1.into())), Rc::new(Expression::IntegerLiteral(2.into())) ], tail: Rc::new(Expression::IntegerLiteral(3.into())) } ); // syntax error let v = Value::list_or_nil([]); let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap_err(); assert_eq!( e, ParseError { input: v, error: ParseErrorKind::Expected( ExpectedWhat::Expression, ExpectedWhere::AfterArgumentList(Keyword::Lambda) ), } ); let v = Value::Identifier("a".into()).cons(Value::Identifier("b".into())); let e = FunctionBody::parse(&v, &v, Keyword::Lambda).unwrap_err(); assert_eq!( e, ParseError { input: v, error: ParseErrorKind::Expected( ExpectedWhat::ProperList, ExpectedWhere::AfterArgumentList(Keyword::Lambda) ), } ); } #[test] fn test_parse_function_signature() { let args = Value::list_or_nil([]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec![], optional_arguments: vec![], rest_argument: None } ); let args = Value::list_or_nil([Value::Identifier("a".into()), Value::Identifier("b".into())]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec!["a".into(), "b".into()], optional_arguments: vec![], rest_argument: None } ); let args = Value::list_or_nil([ Value::Identifier("a".into()), Value::Keyword(Keyword::Optional), Value::Identifier("b".into()), ]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec!["a".into()], optional_arguments: vec!["b".into()], rest_argument: None } ); let args = Value::list_or_nil([ Value::Identifier("a".into()), Value::Keyword(Keyword::Rest), Value::Identifier("b".into()), ]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec!["a".into()], optional_arguments: vec![], rest_argument: Some("b".into()) } ); let args = Value::list_or_nil([Value::Keyword(Keyword::Rest), Value::Identifier("c".into())]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec![], optional_arguments: vec![], rest_argument: Some("c".into()) } ); let args = Value::list_or_nil([ Value::Keyword(Keyword::Optional), Value::Identifier("b".into()), Value::Keyword(Keyword::Rest), Value::Identifier("c".into()), ]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec![], optional_arguments: vec!["b".into()], rest_argument: Some("c".into()) } ); let args = Value::list_or_nil([ Value::Identifier("a".into()), Value::Keyword(Keyword::Rest), Value::Identifier("c".into()), ]); let v = FunctionSignature::parse(&args, &args).unwrap(); assert_eq!( v, FunctionSignature { required_arguments: vec!["a".into()], optional_arguments: vec![], rest_argument: Some("c".into()) } ); // syntax errors let args = Value::list_or_nil([Value::Keyword(Keyword::Optional)]); let e = FunctionSignature::parse(&args, &args).unwrap_err(); assert_eq!( e, ParseError { input: args, error: ParseErrorKind::Expected( ExpectedWhat::AtLeastOneArgument, ExpectedWhere::AfterKeyword(Keyword::Optional) ) } ); let args = Value::list_or_nil([ Value::Keyword(Keyword::Rest), Value::Identifier("a".into()), Value::Identifier("b".into()), ]); let e = FunctionSignature::parse(&args, &args).unwrap_err(); assert_eq!( e, ParseError { input: args, error: ParseErrorKind::Expected( ExpectedWhat::ExactlyOneArgument, ExpectedWhere::AfterKeyword(Keyword::Rest) ) } ); let args = Value::list_or_nil([Value::Boolean(false.into())]); let e = FunctionSignature::parse(&args, &args).unwrap_err(); assert_eq!( e, ParseError { input: args, error: ParseErrorKind::Expected( ExpectedWhat::ArgumentSpec, ExpectedWhere::InArgumentList ) } ); } }