diff --git a/src/lowering/property.rs b/src/lowering/property.rs index 65922c0042..a92c39bd2b 100644 --- a/src/lowering/property.rs +++ b/src/lowering/property.rs @@ -42,15 +42,11 @@ impl AstVisitorMut for PropertyLowerer { } fn visit_implementation(&mut self, implementation: &mut Implementation) { - match &implementation.pou_type { - PouType::Method { property: Some(qualified_name), .. } => { - // TODO: Two things, first let's maybe introduce a `enter_method` and `exit_method` method and secondly - // I'm not entirely happy with this solution but it seemed to be the easiest way to solve for now - self.context = Some(qualified_name.clone()) - } - - _ => (), - }; + if let PouType::Method { property: Some(qualified_name), .. } = &implementation.pou_type { + // TODO: Two things, first let's maybe introduce a `enter_method` and `exit_method` method and secondly + // I'm not entirely happy with this solution but it seemed to be the easiest way to solve for now + self.context = Some(qualified_name.clone()) + } for statement in &mut implementation.statements { self.visit(statement); @@ -88,7 +84,7 @@ impl AstVisitorMut for PropertyLowerer { } fn visit_reference_expr(&mut self, node: &mut AstNode) { - if let Some(annotation) = self.annotations.as_ref().unwrap().get(&node) { + if let Some(annotation) = self.annotations.as_ref().unwrap().get(node) { if !annotation.is_property() { return; } @@ -161,7 +157,7 @@ impl PropertyLowerer { let mut implementation = Implementation { name: pou.name.clone(), type_name: pou.name.clone(), - linkage: pou.linkage.clone(), + linkage: pou.linkage, pou_type: pou.kind.clone(), statements: property_impl.statements, location: pou.location.clone(), @@ -287,7 +283,7 @@ mod tests { use crate::{lowering::property::PropertyLowerer, test_utils::tests::parse}; #[test] - fn temp() { + fn properties_are_lowered_into_methods() { let source = r" FUNCTION_BLOCK fb VAR @@ -319,455 +315,212 @@ mod tests { let (mut unit, diagnostics) = parse(source); assert_eq!(diagnostics, Vec::new()); + // Pre-Lowering + assert_eq!(unit.units.len(), 1); + assert_eq!(unit.units[0].name, "fb"); + let mut lowerer = PropertyLowerer::new(IdProvider::default()); lowerer.lower_to_methods(&mut unit); - insta::assert_debug_snapshot!(unit, @r#" - CompilationUnit { - global_vars: [], - var_config: [], - units: [ - POU { - name: "fb", - variable_blocks: [ - VariableBlock { - variables: [ - Variable { - name: "localPrivateVariable", - data_type: DataTypeReference { - referenced_type: "DINT", - }, - }, - ], - variable_block_type: Local, - }, - VariableBlock { - variables: [ - Variable { - name: "foo", - data_type: DataTypeReference { - referenced_type: "DINT", - }, - }, - Variable { - name: "bar", - data_type: DataTypeReference { - referenced_type: "DINT", - }, - }, - ], - variable_block_type: Property, - }, - ], - pou_type: FunctionBlock, - return_type: None, - interfaces: [], - }, - POU { - name: "fb.__get_foo", - variable_blocks: [], - pou_type: Method { - parent: "fb", - property: Some( - "fb.foo", - ), - }, - return_type: Some( - DataTypeReference { - referenced_type: "DINT", - }, - ), - interfaces: [], - }, - POU { - name: "fb.__set_foo", - variable_blocks: [ - VariableBlock { - variables: [ - Variable { - name: "__in", - data_type: DataTypeReference { - referenced_type: "DINT", - }, - }, - ], - variable_block_type: Input( - ByVal, - ), - }, - ], - pou_type: Method { - parent: "fb", - property: Some( - "fb.foo", - ), - }, - return_type: Some( - DataTypeReference { - referenced_type: "DINT", - }, - ), - interfaces: [], - }, - POU { - name: "fb.__get_bar", - variable_blocks: [], - pou_type: Method { - parent: "fb", - property: Some( - "fb.bar", - ), - }, - return_type: Some( - DataTypeReference { - referenced_type: "DINT", - }, - ), - interfaces: [], + // Post-Lowering + assert_eq!(unit.units.len(), 5); + assert_eq!(unit.units[0].name, "fb"); + assert_eq!(unit.units[1].name, "fb.__get_foo"); + assert_eq!(unit.units[2].name, "fb.__set_foo"); + assert_eq!(unit.units[3].name, "fb.__get_bar"); + assert_eq!(unit.units[4].name, "fb.__set_bar"); + + insta::assert_debug_snapshot!(unit.units[1], @r#" + POU { + name: "fb.__get_foo", + variable_blocks: [], + pou_type: Method { + parent: "fb", + property: Some( + "fb.foo", + ), + }, + return_type: Some( + DataTypeReference { + referenced_type: "DINT", }, - POU { - name: "fb.__set_bar", - variable_blocks: [ - VariableBlock { - variables: [ - Variable { - name: "__in", - data_type: DataTypeReference { - referenced_type: "DINT", - }, - }, - ], - variable_block_type: Input( - ByVal, - ), + ), + interfaces: [], + } + "#); + + insta::assert_debug_snapshot!(unit.units[2], @r#" + POU { + name: "fb.__set_foo", + variable_blocks: [ + VariableBlock { + variables: [ + Variable { + name: "__in", + data_type: DataTypeReference { + referenced_type: "DINT", + }, }, ], - pou_type: Method { - parent: "fb", - property: Some( - "fb.bar", - ), - }, - return_type: Some( - DataTypeReference { - referenced_type: "DINT", - }, + variable_block_type: Input( + ByVal, ), - interfaces: [], }, ], - implementations: [ - Implementation { - name: "fb", - type_name: "fb", - linkage: Internal, - pou_type: FunctionBlock, - statements: [], - location: SourceLocation { - span: Range( - TextLocation { - line: 25, - column: 8, - offset: 568, - }..TextLocation { - line: 24, - column: 24, - offset: 559, + pou_type: Method { + parent: "fb", + property: Some( + "fb.foo", + ), + }, + return_type: Some( + DataTypeReference { + referenced_type: "DINT", + }, + ), + interfaces: [], + } + "#); + + assert_eq!(unit.implementations.len(), 5); + insta::assert_debug_snapshot!(unit.implementations[1], @r#" + Implementation { + name: "fb.__get_foo", + type_name: "fb.__get_foo", + linkage: Internal, + pou_type: Method { + parent: "fb", + property: Some( + "fb.foo", + ), + }, + statements: [ + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "foo", }, ), + base: None, }, - name_location: SourceLocation { - span: Range( - TextLocation { - line: 1, - column: 23, - offset: 24, - }..TextLocation { - line: 1, - column: 25, - offset: 26, - }, - ), + right: LiteralInteger { + value: 5, }, - overriding: false, - generic: false, - access: None, }, - Implementation { - name: "fb.__get_foo", - type_name: "fb.__get_foo", - linkage: Internal, - pou_type: Method { - parent: "fb", - property: Some( - "fb.foo", - ), - }, - statements: [ - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "foo", - }, - ), - base: None, - }, - right: LiteralInteger { - value: 5, - }, - }, - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "__get_foo", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "foo", - }, - ), - base: None, - }, - }, - ], - location: SourceLocation { - span: None, - }, - name_location: SourceLocation { - span: Range( - TextLocation { - line: 6, - column: 21, - offset: 130, - }..TextLocation { - line: 6, - column: 24, - offset: 133, + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "__get_foo", }, ), + base: None, }, - overriding: false, - generic: false, - access: Some( - Public, - ), - }, - Implementation { - name: "fb.__set_foo", - type_name: "fb.__set_foo", - linkage: Internal, - pou_type: Method { - parent: "fb", - property: Some( - "fb.foo", - ), - }, - statements: [ - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "foo", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "__in", - }, - ), - base: None, - }, - }, - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "localPrivateVariable", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "foo", - }, - ), - base: None, - }, - }, - ], - location: SourceLocation { - span: None, - }, - name_location: SourceLocation { - span: Range( - TextLocation { - line: 6, - column: 21, - offset: 130, - }..TextLocation { - line: 6, - column: 24, - offset: 133, + right: ReferenceExpr { + kind: Member( + Identifier { + name: "foo", }, ), + base: None, }, - overriding: false, - generic: false, - access: Some( - Public, - ), }, - Implementation { - name: "fb.__get_bar", - type_name: "fb.__get_bar", - linkage: Internal, - pou_type: Method { - parent: "fb", - property: Some( - "fb.bar", - ), + ], + location: SourceLocation { + span: None, + }, + name_location: SourceLocation { + span: Range( + TextLocation { + line: 6, + column: 21, + offset: 130, + }..TextLocation { + line: 6, + column: 24, + offset: 133, }, - statements: [ - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "bar", - }, - ), - base: None, - }, - right: LiteralInteger { - value: 5, - }, - }, - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "__get_bar", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "bar", - }, - ), - base: None, + ), + }, + overriding: false, + generic: false, + access: Some( + Public, + ), + } + "#); + + insta::assert_debug_snapshot!(unit.implementations[2], @r#" + Implementation { + name: "fb.__set_foo", + type_name: "fb.__set_foo", + linkage: Internal, + pou_type: Method { + parent: "fb", + property: Some( + "fb.foo", + ), + }, + statements: [ + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "foo", }, - }, - ], - location: SourceLocation { - span: None, + ), + base: None, }, - name_location: SourceLocation { - span: Range( - TextLocation { - line: 16, - column: 21, - offset: 356, - }..TextLocation { - line: 16, - column: 24, - offset: 359, + right: ReferenceExpr { + kind: Member( + Identifier { + name: "__in", }, ), + base: None, }, - overriding: false, - generic: false, - access: Some( - Public, - ), }, - Implementation { - name: "fb.__set_bar", - type_name: "fb.__set_bar", - linkage: Internal, - pou_type: Method { - parent: "fb", - property: Some( - "fb.bar", - ), - }, - statements: [ - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "bar", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "__in", - }, - ), - base: None, + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "localPrivateVariable", }, - }, - Assignment { - left: ReferenceExpr { - kind: Member( - Identifier { - name: "localPrivateVariable", - }, - ), - base: None, - }, - right: ReferenceExpr { - kind: Member( - Identifier { - name: "bar", - }, - ), - base: None, - }, - }, - ], - location: SourceLocation { - span: None, + ), + base: None, }, - name_location: SourceLocation { - span: Range( - TextLocation { - line: 16, - column: 21, - offset: 356, - }..TextLocation { - line: 16, - column: 24, - offset: 359, + right: ReferenceExpr { + kind: Member( + Identifier { + name: "foo", }, ), + base: None, }, - overriding: false, - generic: false, - access: Some( - Public, - ), }, ], - interfaces: [], - user_types: [], - file_name: "test.st", - properties: [], + location: SourceLocation { + span: None, + }, + name_location: SourceLocation { + span: Range( + TextLocation { + line: 6, + column: 21, + offset: 130, + }..TextLocation { + line: 6, + column: 24, + offset: 133, + }, + ), + }, + overriding: false, + generic: false, + access: Some( + Public, + ), } "#); } diff --git a/src/lowering/validator.rs b/src/lowering/validator.rs index 0ffda9e15f..c096dc9d01 100644 --- a/src/lowering/validator.rs +++ b/src/lowering/validator.rs @@ -1,8 +1,9 @@ use std::{ops::Deref, sync::RwLock}; -use plc_ast::ast::{Property, PropertyImplementation, PropertyKind}; +use plc_ast::ast::{Property, PropertyKind}; use plc_diagnostics::{diagnostician::Diagnostician, diagnostics::Diagnostic}; +#[derive(Default)] pub struct ParticipantValidator { pub diagnostics: Vec, } @@ -45,7 +46,6 @@ impl ParticipantValidator { } } } - if implementation.kind == PropertyKind::Get {} match implementation.kind { PropertyKind::Get => { get_blocks.push(implementation.location.clone()); @@ -87,6 +87,7 @@ impl ParticipantValidator { } // ------- +#[derive(Default)] pub struct ParticipantDiagnostician { inner: RwLock, } diff --git a/src/parser.rs b/src/parser.rs index b19aaffee5..840d5b0b88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -317,7 +317,9 @@ fn parse_pou( } if lexer.token == KeywordProperty { - properties.push(parse_property(lexer, &name, &name_location, &kind)); + if let Some(property) = parse_property(lexer, &name, &name_location, &kind) { + properties.push(property); + } } else { let is_const = lexer.try_consume(PropertyConstant); if let Some((pou, implementation)) = parse_method(lexer, &name, linkage, is_const) { @@ -632,13 +634,25 @@ fn parse_property( parent_name: &str, parent_location: &SourceLocation, kind: &PouType, -) -> Property { +) -> Option { let _location = lexer.location(); lexer.advance(); // Move past `PROPERTY` keyword // TODO: Error handling - let (name, name_location) = parse_identifier(lexer).expect("property missing a name"); - let datatype = parse_return_type(lexer, &PouType::Function).expect("property missing a datatype"); // XXX: The POU type is not correct + let identifier = parse_identifier(lexer); + let datatype = parse_return_type(lexer, &PouType::Function); // XXX: The POU type is not correct + + // This is kind of common, hence we parse invalid variable blocks to have useful error messages + while lexer.token.is_var() { + let block = parse_variable_block(lexer, LinkageType::Internal); + lexer.accept_diagnostic( + Diagnostic::new( + "Variable blocks may only be defined within a GET or SET block in the context of properties", + ) + .with_location(&block.location) + .with_error_code("E007"), + ); + } let mut implementations = Vec::new(); while matches!(lexer.token, KeywordGet | KeywordSet) { @@ -655,8 +669,12 @@ fn parse_property( implementations.push(PropertyImplementation { kind, variables, statements, location }); } + let (name, name_location) = identifier?; + + let datatype = datatype?; + lexer.try_consume_or_report(Token::KeywordEndProperty); // Move past `END_PROPERTY` keyword - Property { + Some(Property { name, name_location, name_parent: parent_name.to_string(), @@ -664,7 +682,7 @@ fn parse_property( name_parent_location: parent_location.clone(), datatype, implementations, - } + }) } fn parse_access_modifier(lexer: &mut ParseSession) -> AccessModifier { diff --git a/src/parser/expressions_parser.rs b/src/parser/expressions_parser.rs index cf9a33d9ac..697dd79e7f 100644 --- a/src/parser/expressions_parser.rs +++ b/src/parser/expressions_parser.rs @@ -316,7 +316,7 @@ fn parse_atomic_leaf_expression(lexer: &mut ParseSession<'_>) -> Option } fn parse_identifier(lexer: &mut ParseSession<'_>) -> AstNode { - AstFactory::create_identifier(&lexer.slice_and_advance(), lexer.last_location(), lexer.next_id()) + AstFactory::create_identifier(lexer.slice_and_advance(), lexer.last_location(), lexer.next_id()) } fn parse_vla_range(lexer: &mut ParseSession) -> Option { diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 8e7efa2e0c..943109e905 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -17,6 +17,7 @@ mod misc_parser_tests; mod parse_errors; mod parse_generics; mod program_parser_tests; +mod property_parser_tests; mod statement_parser_tests; mod type_parser_tests; mod variable_parser_tests; diff --git a/src/parser/tests/property_parser_tests.rs b/src/parser/tests/property_parser_tests.rs new file mode 100644 index 0000000000..fdd46bdd4b --- /dev/null +++ b/src/parser/tests/property_parser_tests.rs @@ -0,0 +1,279 @@ +use crate::test_utils::tests::{parse, parse_buffered}; + +#[test] +fn properties_can_be_parsed() { + let source = r" + FUNCTION_BLOCK foo + PROPERTY bar : INT + GET + VAR + getLocalVariable : DINT; + END_VAR + + bar := 5; + END_GET + SET + VAR + setLocalVariable : DINT; + END_VAR + + localNonExistingVariable := bar; + END_SET + END_PROPERTY + END_FUNCTION_BLOCK + "; + + let (unit, diagnostics) = parse(source); + + assert_eq!(diagnostics, vec![]); + + assert_eq!(unit.units.len(), 1); + assert_eq!(unit.units[0].name, "foo"); + + assert_eq!(unit.properties.len(), 1); + assert_eq!(unit.properties[0].name, "bar"); + assert_eq!(unit.properties[0].implementations.len(), 2); + + insta::assert_debug_snapshot!(unit.properties, @r#" + [ + Property { + name: "bar", + name_location: SourceLocation { + span: Range( + TextLocation { + line: 2, + column: 21, + offset: 49, + }..TextLocation { + line: 2, + column: 24, + offset: 52, + }, + ), + }, + kind_parent: FunctionBlock, + name_parent: "foo", + name_parent_location: SourceLocation { + span: Range( + TextLocation { + line: 1, + column: 23, + offset: 24, + }..TextLocation { + line: 1, + column: 26, + offset: 27, + }, + ), + }, + datatype: DataTypeReference { + referenced_type: "INT", + }, + implementations: [ + PropertyImplementation { + kind: Get, + variables: [ + VariableBlock { + variables: [ + Variable { + name: "getLocalVariable", + data_type: DataTypeReference { + referenced_type: "DINT", + }, + }, + ], + variable_block_type: Local, + }, + ], + statements: [ + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "bar", + }, + ), + base: None, + }, + right: LiteralInteger { + value: 5, + }, + }, + ], + location: SourceLocation { + span: Range( + TextLocation { + line: 3, + column: 16, + offset: 75, + }..TextLocation { + line: 3, + column: 19, + offset: 78, + }, + ), + }, + }, + PropertyImplementation { + kind: Set, + variables: [ + VariableBlock { + variables: [ + Variable { + name: "setLocalVariable", + data_type: DataTypeReference { + referenced_type: "DINT", + }, + }, + ], + variable_block_type: Local, + }, + ], + statements: [ + Assignment { + left: ReferenceExpr { + kind: Member( + Identifier { + name: "localNonExistingVariable", + }, + ), + base: None, + }, + right: ReferenceExpr { + kind: Member( + Identifier { + name: "bar", + }, + ), + base: None, + }, + }, + ], + location: SourceLocation { + span: Range( + TextLocation { + line: 10, + column: 16, + offset: 251, + }..TextLocation { + line: 10, + column: 19, + offset: 254, + }, + ), + }, + }, + ], + }, + ] + "#); +} + +#[test] +fn property_with_missing_name() { + let source = r" + FUNCTION_BLOCK foo + PROPERTY : INT // <- Missing name + END_PROPERTY + END_FUNCTION_BLOCK + "; + + // TODO: This error message is pretty bad, however this is more of a parser issue than something property related... + let (_, diagnostics) = parse_buffered(source); + insta::assert_snapshot!(diagnostics, @r" + error[E007]: Unexpected token: expected Identifier but found : + ┌─ :3:22 + │ + 3 │ PROPERTY : INT // <- Missing name + │ ^ Unexpected token: expected Identifier but found : + + error[E007]: Unexpected token: expected Literal but found END_PROPERTY + ┌─ :4:13 + │ + 4 │ END_PROPERTY + │ ^^^^^^^^^^^^ Unexpected token: expected Literal but found END_PROPERTY + + error[E007]: Unexpected token: expected KeywordSemicolon but found 'END_PROPERTY' + ┌─ :4:13 + │ + 4 │ END_PROPERTY + │ ^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_PROPERTY' + + error[E006]: Missing expected Token [KeywordSemicolon, KeywordColon] + ┌─ :5:9 + │ + 5 │ END_FUNCTION_BLOCK + │ ^^^^^^^^^^^^^^^^^^ Missing expected Token [KeywordSemicolon, KeywordColon] + + error[E007]: Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK' + ┌─ :5:9 + │ + 5 │ END_FUNCTION_BLOCK + │ ^^^^^^^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK' + "); +} + +#[test] +fn property_with_missing_datatype() { + let source = r" + FUNCTION_BLOCK foo + PROPERTY bar // <- Missing datatype + END_PROPERTY + END_FUNCTION_BLOCK + "; + + // TODO: This error message is pretty bad, however this is more of a parser issue than something property related... + let (_, diagnostics) = parse_buffered(source); + insta::assert_snapshot!(diagnostics, @r" + error[E007]: Unexpected token: expected Literal but found END_PROPERTY + ┌─ :4:13 + │ + 4 │ END_PROPERTY + │ ^^^^^^^^^^^^ Unexpected token: expected Literal but found END_PROPERTY + + error[E007]: Unexpected token: expected KeywordSemicolon but found 'END_PROPERTY' + ┌─ :4:13 + │ + 4 │ END_PROPERTY + │ ^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_PROPERTY' + + error[E006]: Missing expected Token [KeywordSemicolon, KeywordColon] + ┌─ :5:9 + │ + 5 │ END_FUNCTION_BLOCK + │ ^^^^^^^^^^^^^^^^^^ Missing expected Token [KeywordSemicolon, KeywordColon] + + error[E007]: Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK' + ┌─ :5:9 + │ + 5 │ END_FUNCTION_BLOCK + │ ^^^^^^^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK' + "); +} + +#[test] +fn property_with_variable_block() { + let source = r" + FUNCTION_BLOCK foo + PROPERTY bar : DINT + VAR + // Invalid variable block, should be in a getter or setter + END_VAR + + GET + // ... + END_GET + END_PROPERTY + END_FUNCTION_BLOCK + "; + + // TODO: Update location + let (_, diagnostics) = parse_buffered(source); + insta::assert_snapshot!(diagnostics, @r" + error[E007]: Variable blocks may only be defined within a GET or SET block in the context of properties + ┌─ :4:17 + │ + 4 │ VAR + │ ^^^ Variable blocks may only be defined within a GET or SET block in the context of properties + "); +} diff --git a/src/test_utils.rs b/src/test_utils.rs index 7f8d539d5f..81eee4ed01 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -18,10 +18,7 @@ pub mod tests { codegen::{CodegenContext, GeneratedModule}, index::{self, FxIndexSet, Index}, lexer, - lowering::{ - calls::AggregateTypeLowerer, property::PropertyLowerer, validator::ParticipantValidator, - InitVisitor, - }, + lowering::{calls::AggregateTypeLowerer, validator::ParticipantValidator, InitVisitor}, parser, resolver::{ const_evaluator::evaluate_constants, AnnotationMapImpl, AstAnnotations, Dependency, @@ -202,11 +199,10 @@ pub mod tests { (all_annotations, full_index, annotated_units) } pub fn temp_make_me_generic_but_for_now_validate_property(src: &str) -> String { - let ids = IdProvider::default(); let mut reporter = Diagnostician::buffered(); reporter.register_file("".to_string(), src.to_string()); - let (mut unit, mut diagnostics) = parse(src); + let (unit, mut diagnostics) = parse(src); let mut validator = ParticipantValidator::new(); validator.validate_properties(&unit.properties); diff --git a/src/validation/statement.rs b/src/validation/statement.rs index 530f3a0d49..5c3ef1957d 100644 --- a/src/validation/statement.rs +++ b/src/validation/statement.rs @@ -490,8 +490,8 @@ fn validate_reference( && context .qualifier .and_then(|qualifier| context.index.find_pou(qualifier)) - .map(|pou| (pou.get_name(), pou.get_container())) // get the container pou (for actions this is the program/fb) - .map_or(false, |(pou, container)| { + .map(|pou| (pou.get_name(), pou.get_container())) + .is_some_and(|(pou, container)| { !qualified_name.starts_with(pou) && !qualified_name.starts_with(container) && !context.index.is_init_function(pou) diff --git a/src/validation/tests/.pou_validation_tests.rs.pending-snap b/src/validation/tests/.pou_validation_tests.rs.pending-snap deleted file mode 100644 index 2589eb2bd0..0000000000 --- a/src/validation/tests/.pou_validation_tests.rs.pending-snap +++ /dev/null @@ -1,47 +0,0 @@ -{"run_id":"1737976320-847550649","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737976915-701266310","line":230,"new":null,"old":null} -{"run_id":"1737976915-701266310","line":325,"new":null,"old":null} -{"run_id":"1737976915-701266310","line":270,"new":null,"old":null} -{"run_id":"1737976915-701266310","line":391,"new":null,"old":null} -{"run_id":"1737976915-701266310","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737976915-701266310","line":355,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":355,"expression":"diagnostics"},"snapshot":"error[E006]: Missing expected Token KeywordEndProperty\n ┌─ :4:15\n │\n4 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Missing expected Token KeywordEndProperty\n\nerror[E007]: Unexpected token: expected Literal but found VAR_OUTPUT\n ┌─ :4:15\n │\n4 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Unexpected token: expected Literal but found VAR_OUTPUT\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'VAR_OUTPUT\n out'\n ┌─ :4:15\n │ \n4 │ ╭ VAR_OUTPUT\n5 │ │ out : DINT;\n │ ╰───────────────────^ Unexpected token: expected KeywordSemicolon but found 'VAR_OUTPUT\n out'\n\nerror[E007]: Unexpected token: expected Literal but found END_VAR\n ┌─ :6:15\n │\n6 │ END_VAR\n │ ^^^^^^^ Unexpected token: expected Literal but found END_VAR\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'END_VAR\n GET\n END_Get\n END_PROPERTY'\n ┌─ :6:15\n │ \n6 │ ╭ END_VAR\n7 │ │ GET\n8 │ │ END_Get\n9 │ │ END_PROPERTY\n │ ╰────────────────────────^ Unexpected token: expected KeywordSemicolon but found 'END_VAR\n GET\n END_Get\n END_PROPERTY'\n\nerror[E006]: Missing expected Token [KeywordSemicolon, KeywordColon]\n ┌─ :10:9\n │\n10 │ END_FUNCTION_BLOCK\n │ ^^^^^^^^^^^^^^^^^^ Missing expected Token [KeywordSemicolon, KeywordColon]\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK'\n ┌─ :10:9\n │\n10 │ END_FUNCTION_BLOCK\n │ ^^^^^^^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK'\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737976938-152726266","line":230,"new":null,"old":null} -{"run_id":"1737976938-152726266","line":381,"new":null,"old":null} -{"run_id":"1737976938-152726266","line":270,"new":null,"old":null} -{"run_id":"1737976938-152726266","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737976938-152726266","line":345,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":345,"expression":"diagnostics"},"snapshot":"error[E006]: Missing expected Token KeywordEndProperty\n ┌─ :4:15\n │\n4 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Missing expected Token KeywordEndProperty\n\nerror[E007]: Unexpected token: expected Literal but found VAR_OUTPUT\n ┌─ :4:15\n │\n4 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Unexpected token: expected Literal but found VAR_OUTPUT\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'VAR_OUTPUT\n out'\n ┌─ :4:15\n │ \n4 │ ╭ VAR_OUTPUT\n5 │ │ out : DINT;\n │ ╰───────────────────^ Unexpected token: expected KeywordSemicolon but found 'VAR_OUTPUT\n out'\n\nerror[E007]: Unexpected token: expected Literal but found END_VAR\n ┌─ :6:15\n │\n6 │ END_VAR\n │ ^^^^^^^ Unexpected token: expected Literal but found END_VAR\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'END_VAR\n GET\n END_Get\n END_PROPERTY'\n ┌─ :6:15\n │ \n6 │ ╭ END_VAR\n7 │ │ GET\n8 │ │ END_Get\n9 │ │ END_PROPERTY\n │ ╰────────────────────────^ Unexpected token: expected KeywordSemicolon but found 'END_VAR\n GET\n END_Get\n END_PROPERTY'\n\nerror[E006]: Missing expected Token [KeywordSemicolon, KeywordColon]\n ┌─ :10:9\n │\n10 │ END_FUNCTION_BLOCK\n │ ^^^^^^^^^^^^^^^^^^ Missing expected Token [KeywordSemicolon, KeywordColon]\n\nerror[E007]: Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK'\n ┌─ :10:9\n │\n10 │ END_FUNCTION_BLOCK\n │ ^^^^^^^^^^^^^^^^^^ Unexpected token: expected KeywordSemicolon but found 'END_FUNCTION_BLOCK'\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737976938-152726266","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977068-577049174","line":230,"new":null,"old":null} -{"run_id":"1737977068-577049174","line":270,"new":null,"old":null} -{"run_id":"1737977068-577049174","line":381,"new":null,"old":null} -{"run_id":"1737977068-577049174","line":345,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":345,"expression":"diagnostics"},"snapshot":"error[E001]: Only VAR blocks are allowed for properties"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977068-577049174","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977068-577049174","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977222-827882046","line":230,"new":null,"old":null} -{"run_id":"1737977222-827882046","line":270,"new":null,"old":null} -{"run_id":"1737977222-827882046","line":381,"new":null,"old":null} -{"run_id":"1737977222-827882046","line":345,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":345,"expression":"diagnostics"},"snapshot":"error[E001]: Only VAR blocks are allowed for properties\n ┌─ :5:19\n │\n5 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Only VAR blocks are allowed for properties"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977222-827882046","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977222-827882046","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977263-664388828","line":230,"new":null,"old":null} -{"run_id":"1737977263-664388828","line":381,"new":null,"old":null} -{"run_id":"1737977263-664388828","line":270,"new":null,"old":null} -{"run_id":"1737977263-664388828","line":345,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":345,"expression":"diagnostics"},"snapshot":"error[E001]: Only VAR blocks are allowed for properties\n ┌─ :5:19\n │\n3 │ PROPERTY prop : DINT\n │ ---- see also\n4 │ GET\n5 │ VAR_OUTPUT\n │ ^^^^^^^^^^ Only VAR blocks are allowed for properties"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977263-664388828","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977263-664388828","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977333-477003727","line":230,"new":null,"old":null} -{"run_id":"1737977333-477003727","line":270,"new":null,"old":null} -{"run_id":"1737977333-477003727","line":381,"new":null,"old":null} -{"run_id":"1737977333-477003727","line":345,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":345,"expression":"diagnostics"},"snapshot":"error[E001]: Only VAR blocks are allowed for properties\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Only VAR blocks are allowed for properties\n4 │ GET\n5 │ VAR_OUTPUT\n │ ---------- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977333-477003727","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977333-477003727","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977497-805664009","line":343,"new":null,"old":null} -{"run_id":"1737977497-805664009","line":230,"new":null,"old":null} -{"run_id":"1737977497-805664009","line":399,"new":null,"old":null} -{"run_id":"1737977497-805664009","line":270,"new":null,"old":null} -{"run_id":"1737977497-805664009","line":363,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_var_output_in_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":363,"expression":"diagnostics"},"snapshot":"error[E001]: Only VAR blocks are allowed for properties\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Only VAR blocks are allowed for properties\n4 │ GET\n5 │ VAR_OUTPUT\n │ ---------- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977497-805664009","line":308,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_within_function_pou","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":308,"expression":"diagnostics"},"snapshot":"error[E001]: Methods cannot be declared in a POU of type 'Function'.\n ┌─ :2:24\n │\n2 │ FUNCTION foo : DINT\n │ ^^^^ Methods cannot be declared in a POU of type 'Function'.\n\nerror[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n ┌─ :2:18\n │\n2 │ FUNCTION foo : DINT\n │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties\n\nerror[E001]: Property has no GET or SET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has no GET or SET block"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977497-805664009","line":325,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_with_more_than_one_get_block","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":325,"expression":"diagnostics"},"snapshot":"error[E001]: Property has more than one GET block\n ┌─ :3:22\n │\n3 │ PROPERTY prop : DINT\n │ ^^^^ Property has more than one GET block\n4 │ GET\n │ --- see also\n5 │ END_Get\n6 │ GET\n │ --- see also"},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":""}} -{"run_id":"1737977528-715278181","line":343,"new":null,"old":null} -{"run_id":"1737977549-264539677","line":343,"new":{"module_name":"rusty__validation__tests__pou_validation_tests","snapshot_name":"property_TMP","metadata":{"source":"src/validation/tests/pou_validation_tests.rs","assertion_line":343,"expression":"diagnostics"},"snapshot":""},"old":{"module_name":"rusty__validation__tests__pou_validation_tests","metadata":{},"snapshot":"aa"}} -{"run_id":"1737977661-195541437","line":348,"new":null,"old":null} diff --git a/src/validation/tests/pou_validation_tests.rs b/src/validation/tests/pou_validation_tests.rs index 9ac9647065..b5debe9862 100644 --- a/src/validation/tests/pou_validation_tests.rs +++ b/src/validation/tests/pou_validation_tests.rs @@ -300,52 +300,51 @@ fn property_within_function_pou() { r" FUNCTION foo : DINT PROPERTY prop : DINT + GET + prop := 5; + END_GET END_PROPERTY END_FUNCTION ", ); - assert_snapshot!(diagnostics, @r""); -} - -#[test] -fn property_with_more_than_one_get_block() { - let diagnostics = temp_make_me_generic_but_for_now_validate_property( - r" - FUNCTION_BLOCK foo - PROPERTY prop : DINT - GET - END_Get - GET - END_Get - END_PROPERTY - END_FUNCTION_BLOCK - ", - ); assert_snapshot!(diagnostics, @r" + error[E001]: Methods cannot be declared in a POU of type 'Function'. + ┌─ :2:24 + │ + 2 │ FUNCTION foo : DINT + │ ^^^^ Methods cannot be declared in a POU of type 'Function'. + + error[E001]: Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties + ┌─ :2:18 + │ + 2 │ FUNCTION foo : DINT + │ ^^^ Only FUNCTION_BLOCK or PROGRAM are allowed as parent for properties "); } #[test] -fn property_TMP() { +fn property_with_more_than_one_get_block() { let diagnostics = temp_make_me_generic_but_for_now_validate_property( r" FUNCTION_BLOCK foo PROPERTY prop : DINT - SET - 1 + 2; - END_SET - END_PROPERTY - PROPERTY prop : DINT - SET - 1 + 2; - END_SET + GET END_GET + GET END_GET END_PROPERTY END_FUNCTION_BLOCK ", ); - assert_snapshot!(diagnostics, @r" + error[E001]: Property has more than one GET block + ┌─ :3:22 + │ + 3 │ PROPERTY prop : DINT + │ ^^^^ Property has more than one GET block + 4 │ GET END_GET + │ --- see also + 5 │ GET END_GET + │ --- see also "); } @@ -366,6 +365,14 @@ fn property_with_var_output_in_get_block() { ); assert_snapshot!(diagnostics, @r" + error[E001]: Only VAR blocks are allowed for properties + ┌─ :3:22 + │ + 3 │ PROPERTY prop : DINT + │ ^^^^ Only VAR blocks are allowed for properties + 4 │ GET + 5 │ VAR_OUTPUT + │ ---------- see also "); }