#![cfg(test)] #![allow(clippy::upper_case_acronyms)] #![allow(clippy::vec_init_then_push)] use pretty_assertions::assert_eq; use std::rc::Rc; use crate::tokenizing::Location; use super::{Parser, ParseResult, tokenize}; use crate::ast::*; use super::Declaration::*; use super::Signature; use super::TypeIdentifier::*; use super::TypeSingletonName; use super::ExpressionKind::*; use super::VariantKind::*; fn make_parser(input: &str) -> Parser { let tokens: Vec = tokenize(input); let mut parser = super::Parser::new(); parser.add_new_tokens(tokens); parser } fn parse(input: &str) -> ParseResult { let mut parser = make_parser(input); parser.parse() } //TODO maybe can be const? fn make_statement(kind: StatementKind) -> Statement { Statement { location: Location::default(), id: ItemId::default(), kind, } } macro_rules! bx { ($e:expr) => { Box::new($e) }; } macro_rules! parse_test { ($string:expr, $correct:expr) => { assert_eq!(parse($string).unwrap(), $correct) }; } macro_rules! parse_test_wrap_ast { ($string:expr, $correct:expr) => { parse_test!($string, AST { id: Default::default(), statements: vec![$correct].into() }) } } macro_rules! qname { ( $( $component:expr),* ) => { { let mut components = vec![]; $( components.push(rc!($component)); )* QualifiedName { components, id: Default::default() } } }; } macro_rules! val { ($var:expr) => { Value(QualifiedName { components: vec![Rc::new($var.to_string())], id: Default::default() }) }; } macro_rules! ty { ($name:expr) => { Singleton(tys!($name)) } } macro_rules! tys { ($name:expr) => { TypeSingletonName { name: Rc::new($name.to_string()), params: vec![] } }; } macro_rules! decl { ($expr_type:expr) => { make_statement(StatementKind::Declaration($expr_type)) }; } macro_rules! ex { ($expr_type:expr) => { Expression::new(Default::default(), $expr_type) }; ($expr_type:expr, $type_anno:expr) => { Expression::with_anno(Default::default(), $expr_type, $type_anno) }; (s $expr_text:expr) => { { let mut parser = make_parser($expr_text); parser.expression().unwrap() } }; } macro_rules! exst { ($expr_type:expr) => { make_statement(StatementKind::Expression(Expression::new(Default::default(), $expr_type).into())) }; ($expr_type:expr, $type_anno:expr) => { make_statement(StatementKind::Expression(Expression::with_anno(Default::default(), $expr_type, $type_anno).into())) }; ($op:expr, $lhs:expr, $rhs:expr) => { make_statement(StatementKind::Expression(ex!(binexp!($op, $lhs, $rhs)))) }; (s $statement_text:expr) => { { let mut parser = make_parser($statement_text); parser.statement().unwrap() } } } #[test] fn parsing_block_expressions() { parse_test_wrap_ast! { "if a() then { b(); c() }", exst!( IfExpression { discriminator: Some(bx! { ex!(Call { f: bx!(ex!(val!("a"))), arguments: vec![]}) }), body: bx! { IfExpressionBody::SimpleConditional { then_case: vec![exst!(Call { f: bx!(ex!(val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(val!("c"))), arguments: vec![] })].into(), else_case: None, } } } ) }; parse_test_wrap_ast! { "if a() then { b(); c() } else { q }", exst!( IfExpression { discriminator: Some(bx! { ex!(Call { f: bx!(ex!(val!("a"))), arguments: vec![]}) }), body: bx! { IfExpressionBody::SimpleConditional { then_case: vec![exst!(Call { f: bx!(ex!(val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(val!("c"))), arguments: vec![] })].into(), else_case: Some(vec![exst!(val!("q"))].into()), } } } ) }; /* parse_test!("if a() then { b(); c() }", AST(vec![exst!( IfExpression(bx!(ex!(Call { f: bx!(ex!(val!("a"))), arguments: vec![]})), vec![exst!(Call { f: bx!(ex!(val!("b"))), arguments: vec![]}), exst!(Call { f: bx!(ex!(val!("c"))), arguments: vec![] })], None) )])); parse_test!(r#" if true then { const a = 10 b } else { c }"#, AST(vec![exst!(IfExpression(bx!(ex!(BoolLiteral(true))), vec![decl!(Binding { name: rc!(a), constant: true, expr: ex!(NatLiteral(10)) }), exst!(val!(rc!(b)))], Some(vec![exst!(val!(rc!(c)))])))]) ); parse_test!("if a { b } else { c }", AST(vec![exst!( IfExpression(bx!(ex!(val!("a"))), vec![exst!(val!("b"))], Some(vec![exst!(val!("c"))])))])); parse_test!("if (A {a: 1}) { b } else { c }", AST(vec![exst!( IfExpression(bx!(ex!(NamedStruct { name: rc!(A), fields: vec![(rc!(a), ex!(NatLiteral(1)))]})), vec![exst!(val!("b"))], Some(vec![exst!(val!("c"))])))])); parse_error!("if A {a: 1} { b } else { c }"); */ } #[test] fn parsing_impls() { }