use super::parse; use super::parsed_statement::ParsedStatement; use crate::modifiers::TypeModifier; use crate::parsing::lexer::lex_tokens::{LexToken, TokenType}; use crate::parsing::parser::parsed_statement::ParsedStatement::DataTypeAuto; use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator}; use crate::span::Span; use enumflags2::BitFlags; fn create_tokens(types: Vec) -> Vec { let mut v = Vec::with_capacity(types.len()); for t in types { v.push(LexToken { token_type: t, span: Span::new(0, 0), }); } v } #[test] fn test_empty_namespace() { let script = parse( create_tokens(vec![ TokenType::NamespaceKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::OpenCurlyBracket, TokenType::CloseCurlyBracket, TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Namespace { identifier, script } = &statements[0] { assert_eq!(identifier, "foo"); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(0, statements.len()); } else { unreachable!(); } } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_empty_interface() { let script = parse( create_tokens(vec![ TokenType::InterfaceKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::OpenCurlyBracket, TokenType::CloseCurlyBracket, TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Interface { type_mod, identifier, inherits, statements, } = &statements[0] { assert!(type_mod.is_empty()); assert_eq!(identifier, "foo"); assert_eq!(inherits.len(), 0); assert_eq!(statements.len(), 0); } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_empty_external_shared_interface() { let script = parse( create_tokens(vec![ TokenType::ExternalKeyword, TokenType::SharedKeyword, TokenType::InterfaceKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::OpenCurlyBracket, TokenType::CloseCurlyBracket, TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Interface { type_mod, identifier, inherits, statements, } = &statements[0] { assert!(!type_mod.is_empty()); assert!(type_mod.contains(TypeModifier::External)); assert!(type_mod.contains(TypeModifier::Shared)); assert_eq!(identifier, "foo"); assert_eq!(inherits.len(), 0); assert_eq!(statements.len(), 0); } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_interface_with_virtprop() { let script = parse( create_tokens(vec![ TokenType::InterfaceKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::OpenCurlyBracket, TokenType::Identifier("bar".to_string()), TokenType::Identifier("get_bar".to_string()), TokenType::OpenCurlyBracket, TokenType::GetKeyword, TokenType::Semicolon, TokenType::SetKeyword, TokenType::Semicolon, TokenType::CloseCurlyBracket, TokenType::CloseCurlyBracket, TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Interface { type_mod, identifier, inherits, statements, } = &statements[0] { assert!(type_mod.is_empty()); assert_eq!(identifier, "foo"); assert_eq!(inherits.len(), 0); assert_eq!(statements.len(), 1); if let ParsedStatement::VirtProp { field_mod, property_type, identifier, is_handle, has_get, is_get_const, get_statement, has_set, is_set_const, set_statement, } = &statements[0] { assert_eq!(*field_mod, BitFlags::empty()); if let ParsedStatement::Type { is_const, datatype, .. } = property_type.as_ref() { assert!(!is_const); if let ParsedStatement::DataTypeIdentifier { identifier, .. } = datatype.as_ref() { assert_eq!(identifier, "bar"); } else { unreachable!() } } else { unreachable!() } assert_eq!(identifier, "get_bar"); assert!(has_get); assert!(!is_get_const); assert!(has_set); assert!(!is_set_const); assert!(get_statement.is_none()); assert!(set_statement.is_none()); assert!(!is_handle); } else { unreachable!() } } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_assign_to_global_variable() { let script = parse( create_tokens(vec![ TokenType::AutoKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::Equals, TokenType::WhiteSpace, TokenType::IntegerLiteral(100), TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Var { modifier, var_type, identifier, assignment, } = &statements[0] { assert!(modifier.is_empty()); assert_eq!( *var_type.as_ref(), ParsedStatement::Type { is_const: false, scope: None, datatype: Box::from(DataTypeAuto {}), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( *(assignment.as_ref().unwrap().as_ref()), ParsedStatement::IntegerLiteral(100) ); } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_assign_negative_to_global_variable() { let script = parse( create_tokens(vec![ TokenType::AutoKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::Equals, TokenType::WhiteSpace, TokenType::Minus, TokenType::IntegerLiteral(100), TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Var { modifier, var_type, identifier, assignment, } = &statements[0] { assert!(modifier.is_empty()); assert_eq!( *var_type.as_ref(), ParsedStatement::Type { is_const: false, scope: None, datatype: Box::from(DataTypeAuto {}), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( *(assignment.as_ref().unwrap().as_ref()), ParsedStatement::ExprPreOp { operator: PreOperator::Negative, operand: Box::from(ParsedStatement::IntegerLiteral(100)), } ); } else { unreachable!() } } else { unreachable!(); } } #[test] fn test_assign_addition_to_global_variable() { let script = parse( create_tokens(vec![ TokenType::AutoKeyword, TokenType::WhiteSpace, TokenType::Identifier("foo".to_string()), TokenType::WhiteSpace, TokenType::Equals, TokenType::WhiteSpace, TokenType::IntegerLiteral(100), TokenType::Plus, TokenType::Minus, TokenType::IntegerLiteral(20), TokenType::EndOfFile, ]), &mut |_message, _span| { std::panic::panic_any(_message.stringify()); }, ); if let ParsedStatement::Script { statements } = script.as_ref() { assert_eq!(1, statements.len()); if let ParsedStatement::Var { modifier, var_type, identifier, assignment, } = &statements[0] { assert!(modifier.is_empty()); assert_eq!( *var_type.as_ref(), ParsedStatement::Type { is_const: false, scope: None, datatype: Box::from(DataTypeAuto {}), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( *(assignment.as_ref().unwrap().as_ref()), ParsedStatement::BinaryExpr { left: Box::new(ParsedStatement::IntegerLiteral(100)), operator: BinaryOperator::Addition, right: Box::new(ParsedStatement::ExprPreOp { operator: PreOperator::Negative, operand: Box::new(ParsedStatement::IntegerLiteral(20)), }), } ); } else { unreachable!() } } else { unreachable!(); } }