use std::vec; use anyhow::bail; use mclangc::{common::{Loc, loc::LocBox}, parser::{self, ast::{Ident, Keyword, Program, Punctuation, TokenType, statement::{Enum, Struct}, typ::Type}}, tokeniser::Token, validator::{self, predefined::{BuiltinType, get_builtin_from_name, load_builtin}}}; fn get_prog() -> Program { let mut prog = Program::default(); load_builtin(&mut prog); let loc = Loc::default(); prog.structs.insert(Ident::new("MyStruct"), LocBox::new(&loc, Struct { name: Ident::new("MyStruct"), fields: vec![ (Ident::new("foo"), LocBox::new(&loc, BuiltinType::usize())), (Ident::new("bar"), LocBox::new(&loc, BuiltinType::bool())), (Ident::new("baz"), LocBox::new(&loc, Type::Owned(Ident::new("str")).as_ref())), ] })); prog.enums.insert(Ident::new("MyEnum"), LocBox::new(&loc, Enum { name: Ident::new("MyEnum"), fields: vec![], })); prog.types.insert(Ident::new("MyType"), LocBox::new(&loc, Type::Owned(Ident::new("MyStruct")))); prog.types.insert(Ident::new("MyType2"), LocBox::new(&loc, Type::Owned(Ident::new("MyType")))); prog.types.insert(Ident::new("MyType3"), LocBox::new(&loc, Type::Owned(Ident::new("MyType2")).as_ref())); prog.types.insert(Ident::new("MyTypeInf"), LocBox::new(&loc, Type::Owned(Ident::new("MyTypeInf")))); prog.types.insert(Ident::new("MyTypeInfIndirect"), LocBox::new(&loc, Type::Owned(Ident::new("MyType4")))); prog.types.insert(Ident::new("MyType4"), LocBox::new(&loc, Type::Owned(Ident::new("MyType5")))); prog.types.insert(Ident::new("MyType5"), LocBox::new(&loc, Type::Owned(Ident::new("MyType4")))); prog } #[test] fn parse_type_alias_simple() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyType"))) ]; let ret = parser::typ::parse_type(&mut tokens); let mut prog = get_prog(); let ret = validator::validate_type(&mut prog, &ret.unwrap()); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), Type::Owned(Ident::new("MyStruct"))) } #[test] fn parse_type_alias_deep() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyType3"))) ]; let ret = parser::typ::parse_type(&mut tokens); let mut prog = get_prog(); let ret = validator::validate_type(&mut prog, &ret.unwrap()); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), Type::Owned(Ident::new("MyStruct"))) } #[test] fn parse_type_alias_recursive_simple() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyTypeInf"))) ]; let ret = parser::typ::parse_type(&mut tokens); let mut prog = get_prog(); let ret = validator::validate_type(&mut prog, &ret.unwrap()); assert!(ret.is_err()); } #[test] fn parse_type_alias_recursive_indirect() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyType4"))) ]; let ret = parser::typ::parse_type(&mut tokens); let mut prog = get_prog(); let ret = validator::validate_type(&mut prog, &ret.unwrap()); assert!(ret.is_err()); } #[test] fn parse_type_named_struct() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")))) } #[test] fn parse_type_named_enum() { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new("MyEnum"))) ]; let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyEnum")))) } #[test] fn parse_type_ref() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref())) } #[test] fn parse_type_ref2() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref().as_ref())) } #[test] fn parse_type_ref3() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref().as_ref().as_ref())) } #[test] fn parse_type_mut_ref() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut())) } #[test] fn parse_type_mut_ref2() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut().as_ref_mut())) } #[test] fn parse_type_mut_ref3() { let mut tokens = vec![ Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Punct(Punctuation::Ampersand)), Token::new_test(TokenType::Keyword(Keyword::Mut)), Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) ]; tokens.reverse(); let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut().as_ref_mut().as_ref_mut())) } fn test_builtin(s: &str) { let mut tokens = vec![ Token::new_test(TokenType::Ident(Ident::new(s))) ]; let ret = parser::typ::parse_type(&mut tokens); assert!(ret.is_ok()); assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), get_builtin_from_name(s).unwrap())) } #[test] fn parse_type_builtin_usize() { test_builtin("usize"); } #[test] fn parse_type_builtin_isize() { test_builtin("isize"); } #[test] fn parse_type_builtin_u8() { test_builtin("u8"); } #[test] fn parse_type_builtin_i8() { test_builtin("i8"); } #[test] fn parse_type_builtin_u16() { test_builtin("u16"); } #[test] fn parse_type_builtin_i16() { test_builtin("i16"); } #[test] fn parse_type_builtin_u32() { test_builtin("u32"); } #[test] fn parse_type_builtin_i32() { test_builtin("i32"); } #[test] fn parse_type_builtin_u64() { test_builtin("u64"); } #[test] fn parse_type_builtin_i64() { test_builtin("i64"); } #[test] fn parse_type_builtin_void() { test_builtin("void"); } #[test] fn parse_type_builtin_char() { test_builtin("char"); } #[test] fn parse_type_builtin_bool() { test_builtin("bool"); }