diff --git a/src/integration_tests/add_function.rs b/src/integration_tests/add_function.rs index ffb819d..84feaae 100644 --- a/src/integration_tests/add_function.rs +++ b/src/integration_tests/add_function.rs @@ -8,6 +8,9 @@ use crate::parsing::parser::parse; use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::span::Span; +fn ignore_error(_msg: Message, _: Span) { +} + fn panic_on_error(msg: Message, _: Span) { std::panic::panic_any(msg.stringify()); } @@ -350,4 +353,18 @@ fn integration_add_function() { } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); -} \ No newline at end of file +} +// A substring of a script should never panic, even though it might be completely invalid. +#[test] +fn integration_add_function_substring() { + let mut script = "int add(int a, int b) { + return a + b; +}".to_string(); + for _ in 0..script.len() { + script.pop(); + let lexed_tokens = lex(script.as_str(), &mut ignore_error); + let _parsed_tree = parse(lexed_tokens, &mut ignore_error); + } + +} + \ No newline at end of file diff --git a/src/integration_tests/build.rs b/src/integration_tests/build.rs index 033f7cd..65932d2 100644 --- a/src/integration_tests/build.rs +++ b/src/integration_tests/build.rs @@ -8,6 +8,14 @@ fn main() { let mod_file_path = Path::new("src/integration_tests/mod.rs"); let mut mod_file = File::create(mod_file_path).unwrap(); + write!( + mod_file, + r#"//////////////////////////// +// Automatically Generated// +////////////////////////////"# + ) + .unwrap(); + for path_opt in paths { if let Err(..) = path_opt { continue; @@ -45,6 +53,9 @@ use crate::parsing::parser::parse; use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::span::Span; +fn ignore_error(_msg: Message, _: Span) {{ +}} + fn panic_on_error(msg: Message, _: Span) {{ std::panic::panic_any(msg.stringify()); }}"# @@ -104,5 +115,25 @@ fn integration_{name}() {{ } write!(testfile, "}}").unwrap(); + + write!( + testfile, + r##" +// A substring of a script should never panic, even though it might be completely invalid. +#[test] +fn integration_{name}_substring() {{ + let mut script = "{script}".to_string(); + for _ in 0..script.len() {{ + script.pop(); + let lexed_tokens = lex(script.as_str(), &mut ignore_error); + let _parsed_tree = parse(lexed_tokens, &mut ignore_error); + }} + +}} + "##, + name = test_name, + script = script + ) + .unwrap(); } } diff --git a/src/integration_tests/empty_class_declaration.rs b/src/integration_tests/empty_class_declaration.rs index 17f0f28..5fe8482 100644 --- a/src/integration_tests/empty_class_declaration.rs +++ b/src/integration_tests/empty_class_declaration.rs @@ -8,6 +8,9 @@ use crate::parsing::parser::parse; use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::span::Span; +fn ignore_error(_msg: Message, _: Span) { +} + fn panic_on_error(msg: Message, _: Span) { std::panic::panic_any(msg.stringify()); } @@ -90,4 +93,16 @@ fn integration_empty_class_declaration() { } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); -} \ No newline at end of file +} +// A substring of a script should never panic, even though it might be completely invalid. +#[test] +fn integration_empty_class_declaration_substring() { + let mut script = "class Foo {}".to_string(); + for _ in 0..script.len() { + script.pop(); + let lexed_tokens = lex(script.as_str(), &mut ignore_error); + let _parsed_tree = parse(lexed_tokens, &mut ignore_error); + } + +} + \ No newline at end of file diff --git a/src/integration_tests/enum_definition.rs b/src/integration_tests/enum_definition.rs index e1e61fe..8340c2c 100644 --- a/src/integration_tests/enum_definition.rs +++ b/src/integration_tests/enum_definition.rs @@ -8,6 +8,9 @@ use crate::parsing::parser::parse; use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::span::Span; +fn ignore_error(_msg: Message, _: Span) { +} + fn panic_on_error(msg: Message, _: Span) { std::panic::panic_any(msg.stringify()); } @@ -436,4 +439,22 @@ fn integration_enum_definition() { } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); -} \ No newline at end of file +} +// A substring of a script should never panic, even though it might be completely invalid. +#[test] +fn integration_enum_definition_substring() { + let mut script = "enum TestEnum : uint8 { + a, + b, + c, + d = 128, + e +}".to_string(); + for _ in 0..script.len() { + script.pop(); + let lexed_tokens = lex(script.as_str(), &mut ignore_error); + let _parsed_tree = parse(lexed_tokens, &mut ignore_error); + } + +} + \ No newline at end of file diff --git a/src/integration_tests/mod.rs b/src/integration_tests/mod.rs index c36cc4f..1693cd0 100644 --- a/src/integration_tests/mod.rs +++ b/src/integration_tests/mod.rs @@ -1,4 +1,6 @@ -mod enum_definition; +//////////////////////////// +// Automatically Generated// +////////////////////////////mod enum_definition; mod multiple_inheritance_class; mod empty_class_declaration; mod add_function; diff --git a/src/integration_tests/multiple_inheritance_class.rs b/src/integration_tests/multiple_inheritance_class.rs index 4a8bbc2..7736991 100644 --- a/src/integration_tests/multiple_inheritance_class.rs +++ b/src/integration_tests/multiple_inheritance_class.rs @@ -8,6 +8,9 @@ use crate::parsing::parser::parse; use crate::parsing::parser::parsed_statement::ParsedStatement; use crate::span::Span; +fn ignore_error(_msg: Message, _: Span) { +} + fn panic_on_error(msg: Message, _: Span) { std::panic::panic_any(msg.stringify()); } @@ -170,4 +173,16 @@ fn integration_multiple_inheritance_class() { } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); -} \ No newline at end of file +} +// A substring of a script should never panic, even though it might be completely invalid. +#[test] +fn integration_multiple_inheritance_class_substring() { + let mut script = "class Foo : Zom, Aar, Bar {}".to_string(); + for _ in 0..script.len() { + script.pop(); + let lexed_tokens = lex(script.as_str(), &mut ignore_error); + let _parsed_tree = parse(lexed_tokens, &mut ignore_error); + } + +} + \ No newline at end of file diff --git a/src/parsing/parser/mod.rs b/src/parsing/parser/mod.rs index 14fd6f1..b3f8888 100644 --- a/src/parsing/parser/mod.rs +++ b/src/parsing/parser/mod.rs @@ -619,6 +619,10 @@ fn parse_class( } reader.consume(TokenType::CloseCurlyBracket, log); + if name.is_none() { + return Some(Box::new(ParsedStatement::Invalid)); + } + Some(Box::new(ParsedStatement::ClassDeclaration { modifiers, name: name.unwrap(), @@ -670,6 +674,10 @@ fn parse_funcdef( outer_reader.set_from_inner(&reader); + if identifier.is_none() || param_list.is_none() { + Some(Box::new(ParsedStatement::Invalid)); + } + Some(Box::new(ParsedStatement::FuncDefDeclaration { modifiers, returns_reference, @@ -894,7 +902,10 @@ fn parse_paramlist( break; } let param_type = parse_type(reader, log); - // FIXME: Deal with empty param_type + if param_type.is_none() { + // FIXME: Add logging + break; + } let type_mod = parse_typemod(reader, log); let identifier = parse_identifier(reader, log, true); let mut default = None; @@ -1329,9 +1340,8 @@ fn parse_expr( if let Some(..) = binary_operand { let expr_term2 = parse_exprterm(reader, log); if expr_term2.is_none() { - unimplemented!() + return Some(Box::new(ParsedStatement::Invalid)); } - // FIXME: deal with empty expr_term2 return Some(Box::new(ParsedStatement::BinaryExpr { left: expr_term.unwrap(), operator: binary_operand.unwrap(), @@ -1556,10 +1566,13 @@ fn parse_exprvalue( } fn parse_lambda( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { // lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock; + if reader.peek().token_type != TokenType::FunctionKeyword { + return None; + } unimplemented!(); }