diff --git a/src/index/tests/instance_resolver_tests.rs b/src/index/tests/instance_resolver_tests.rs index b2dd94b3c8..24cef3d0f2 100644 --- a/src/index/tests/instance_resolver_tests.rs +++ b/src/index/tests/instance_resolver_tests.rs @@ -87,6 +87,7 @@ fn nested_global_struct_variables_are_retrieved() { TYPE str : STRUCT a,b : str2; END_STRUCT + END_TYPE TYPE str2 : STRUCT c,d : DINT; END_STRUCT diff --git a/src/index/tests/snapshots/rusty__index__tests__instance_resolver_tests__nested_global_struct_variables_are_retrieved.snap b/src/index/tests/snapshots/rusty__index__tests__instance_resolver_tests__nested_global_struct_variables_are_retrieved.snap index e9ad383fb8..2dc2854a35 100644 --- a/src/index/tests/snapshots/rusty__index__tests__instance_resolver_tests__nested_global_struct_variables_are_retrieved.snap +++ b/src/index/tests/snapshots/rusty__index__tests__instance_resolver_tests__nested_global_struct_variables_are_retrieved.snap @@ -24,7 +24,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 154..158, + range: 167..171, }, }, ), @@ -83,7 +83,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 91..92, + range: 104..105, }, }, ), @@ -114,7 +114,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 93..94, + range: 106..107, }, }, ), @@ -173,7 +173,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 91..92, + range: 104..105, }, }, ), @@ -204,7 +204,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 93..94, + range: 106..107, }, }, ), @@ -229,7 +229,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 182..254, + range: 195..267, }, }, ), @@ -257,7 +257,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 215..219, + range: 228..232, }, }, ), @@ -322,7 +322,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 91..92, + range: 104..105, }, }, ), @@ -356,7 +356,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 93..94, + range: 106..107, }, }, ), @@ -421,7 +421,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 91..92, + range: 104..105, }, }, ), @@ -455,7 +455,7 @@ expression: "index.find_instances().collect::>>()" linkage: Internal, binding: None, source_location: SourceRange { - range: 93..94, + range: 106..107, }, }, ), diff --git a/src/parser.rs b/src/parser.rs index 5b8df237af..7de094c85a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -63,8 +63,9 @@ pub fn parse(mut lexer: ParseSession, lnk: LinkageType) -> ParsedAst { unit.implementations.append(&mut actions); } KeywordType => { - if let Some(unit_type) = parse_type(&mut lexer) { - unit.types.push(unit_type); + let unit_type = parse_type(&mut lexer); + for utype in unit_type { + unit.types.push(utype); } } KeywordEndActions | End => return (unit, lexer.diagnostics), @@ -535,26 +536,32 @@ fn parse_action( } // TYPE ... END_TYPE -fn parse_type(lexer: &mut ParseSession) -> Option { +fn parse_type(lexer: &mut ParseSession) -> Vec { lexer.advance(); // consume the TYPE - let start = lexer.location().get_start(); - let name = lexer.slice_and_advance(); - lexer.consume_or_report(KeywordColon); - let result = parse_full_data_type_definition(lexer, Some(name)); + parse_any_in_region(lexer, vec![KeywordEndType], |lexer| { + let mut declarations = vec![]; + while !lexer.closes_open_region(&lexer.token) { + let start = lexer.location().get_start(); + let name = lexer.slice_and_advance(); + lexer.consume_or_report(KeywordColon); - if let Some((DataTypeDeclaration::DataTypeDefinition { data_type, .. }, initializer)) = result { - let end = lexer.last_range.end; - lexer.consume_or_report(KeywordEndType); - Some(UserTypeDeclaration { - data_type, - initializer, - location: (start..end).into(), - scope: lexer.scope.clone(), - }) - } else { - None - } + let result = parse_full_data_type_definition(lexer, Some(name)); + + if let Some((DataTypeDeclaration::DataTypeDefinition { data_type, .. }, initializer)) = + result + { + let end = lexer.last_range.end; + declarations.push(UserTypeDeclaration { + data_type, + initializer, + location: (start..end).into(), + scope: lexer.scope.clone(), + }); + } + } + declarations + }) } type DataTypeWithInitializer = (DataTypeDeclaration, Option); diff --git a/src/parser/tests/parse_errors/parse_error_containers_tests.rs b/src/parser/tests/parse_errors/parse_error_containers_tests.rs index a2d8ea5d7a..7bafba463b 100644 --- a/src/parser/tests/parse_errors/parse_error_containers_tests.rs +++ b/src/parser/tests/parse_errors/parse_error_containers_tests.rs @@ -290,10 +290,11 @@ fn test_unexpected_type_declaration_error_message() { ), Diagnostic::unexpected_token_found( "KeywordSemicolon", - "'PROGRAM\n END_PROGRAM\n END_TYPE'", - (29..85).into(), + "'PROGRAM\n END_PROGRAM'", + (29..64).into(), ), - Diagnostic::unexpected_token_found("KeywordSemicolon", "''", (90..90).into(),), + Diagnostic::missing_token("[KeywordSemicolon]", (77..85).into(),), + Diagnostic::unexpected_token_found("KeywordSemicolon", "'END_TYPE'", (77..85).into(),), ], diagnostics ); diff --git a/src/parser/tests/snapshots/rusty__parser__tests__type_parser_tests__multi_type_declaration.snap b/src/parser/tests/snapshots/rusty__parser__tests__type_parser_tests__multi_type_declaration.snap new file mode 100644 index 0000000000..9921451e74 --- /dev/null +++ b/src/parser/tests/snapshots/rusty__parser__tests__type_parser_tests__multi_type_declaration.snap @@ -0,0 +1,64 @@ +--- +source: src/parser/tests/type_parser_tests.rs +assertion_line: 18 +expression: result +--- +CompilationUnit { + global_vars: [], + units: [], + implementations: [], + types: [ + UserTypeDeclaration { + data_type: StructType { + name: Some( + "Point2D", + ), + variables: [ + Variable { + name: "x", + data_type: DataTypeReference { + referenced_type: "INT", + }, + }, + Variable { + name: "y", + data_type: DataTypeReference { + referenced_type: "INT", + }, + }, + ], + }, + initializer: None, + scope: None, + }, + UserTypeDeclaration { + data_type: StructType { + name: Some( + "Point3D", + ), + variables: [ + Variable { + name: "x", + data_type: DataTypeReference { + referenced_type: "INT", + }, + }, + Variable { + name: "y", + data_type: DataTypeReference { + referenced_type: "INT", + }, + }, + Variable { + name: "z", + data_type: DataTypeReference { + referenced_type: "INT", + }, + }, + ], + }, + initializer: None, + scope: None, + }, + ], +} diff --git a/src/parser/tests/type_parser_tests.rs b/src/parser/tests/type_parser_tests.rs index 2456ddd380..1dfd165534 100644 --- a/src/parser/tests/type_parser_tests.rs +++ b/src/parser/tests/type_parser_tests.rs @@ -1,6 +1,23 @@ use crate::{ast::*, parser::AstStatement::LiteralInteger, test_utils::tests::parse, Diagnostic}; use pretty_assertions::*; +#[test] +fn multi_type_declaration() { + let (result, ..) = parse( + r#" + TYPE + Point2D : STRUCT + x,y : INT; + END_STRUCT + Point3D : STRUCT + x,y,z : INT; + END_STRUCT + END_TYPE + "#, + ); + insta::assert_debug_snapshot!(result); +} + #[test] fn simple_struct_type_can_be_parsed() { let (result, ..) = parse(