-
Notifications
You must be signed in to change notification settings - Fork 66
feat: add typed enums and allow type-specifier to be suffixed #1544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Add support for typed enums with explicit integer type specifications, supporting both IEC 61131-3 standard syntax (TYPE NAME : TYPE (...)) and Codesys syntax (TYPE NAME : (...) TYPE).
| let (mut index, unresolvables) = plc::resolver::const_evaluator::evaluate_constants(global_index); | ||
|
|
||
| // Fix up enum defaults after constants are resolved | ||
| index.finalize_enum_defaults(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Design Question: Should finalize_enum_defaults() be integrated into evaluate_constants()?
Currently, finalize_enum_defaults() is called separately after evaluate_constants() in three places:
- Main pipeline (pipelines.rs)
- Test utilities (test_utils.rs, 2 locations)
Arguments for keeping them separate (current approach):
- Clear separation of concerns: Constant evaluation and enum initialization are conceptually distinct operations
- Modularity: Each function has a single, well-defined responsibility
- Explicit pipeline: Makes it obvious what post-resolution steps are needed
Arguments for integrating into evaluate_constants():
- Strong dependency:
finalize_enum_defaults()fundamentally requires resolved constants and cannot work without them - Simpler API: Single function call instead of remembering to call both in sequence
- Maintenance: Reduces chance of forgetting this pass in new code paths
- Logical cohesion: Both operations finalize constant-related initialization
Should we consider renaming to something like resolve_constants_and_initializers() or updating the evaluate_constants() doc comment to clarify it also handles dependent initialization steps and add this pass to evaluate_constants()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets add this to the const_evaluator or a wrapper function calling the the const evaluator and this function, up to you
7327160 to
b676e54
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1544 +/- ##
==========================================
+ Coverage 94.03% 95.01% +0.98%
==========================================
Files 174 175 +1
Lines 58611 56206 -2405
==========================================
- Hits 55112 53406 -1706
+ Misses 3499 2800 -699 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| validate_data_type(validator, data_type, location); | ||
|
|
||
| // Validate enum numeric type | ||
| if let DataType::EnumType { numeric_type, .. } = data_type { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason this is not part of the match-statement down below? Maybe you could also create a function for the the validation here? I.e. move down to match statement and call validate_enum_type?
| TYPE ValidEnum18 : SINT (a := 1, b := 2); END_TYPE | ||
| TYPE ValidEnum19 : DINT (a := 1, b := 2); END_TYPE | ||
| // Valid: Some integer types (Codesys syntax) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why just "some" integer types? Can you copy paste cases 11 to 19 and just modify the syntax here?
| PROGRAM main | ||
| myColor := red; // Unqualified variant - ok | ||
| myColor := Color; // Type itself - should be unresolvable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whats the value of this? This seems incorrect but there are no diagnostics?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is ignored and tracked in #1546
| ## Example | ||
|
|
||
| ```st | ||
| TYPE Color : STRING (red := 1, green := 2, blue := 3); | ||
| END_TYPE | ||
| ``` | ||
|
|
||
| In this example, `STRING` is not a valid base type for an enum. Only integer types are allowed. | ||
|
|
||
| ## Another example | ||
|
|
||
| ```st | ||
| TYPE Status : REAL (active := 1, inactive := 0); | ||
| END_TYPE | ||
| TYPE Timestamp : TIME (start := 0, stop := 1); | ||
| END_TYPE | ||
| ``` | ||
|
|
||
| These examples show other invalid base types: | ||
| - `REAL` is a floating-point type, not an integer type | ||
| - `TIME` is a time/date type, which although internally represented as an integer, should not be used as an enum base type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you just merge the examples instead of having two sections here?
| } | ||
|
|
||
| #[test] | ||
| fn enum_typed_varargs_get_promoted() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the purpose of this test? Are we testing whether or not an i16 gets promoted to i32 for the printf?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we are. Otherwise, printf will try to read 32 bits and display garbage unless we explicitly specify a smaller sized int in the format string. We follow the C ABI type promotion rules and therefore enums backed by integer type should do the same
| let error_range = lexer.source_range_factory.create_range(opening_location..lexer.range().end); | ||
|
|
||
| // Don't emit warnings if this looks like an enum (will be caught by validation) | ||
| let is_enum_like = matches!(size_expr.get_stmt(), AstStatement::ExpressionList(_)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give some more context here, e.g. needed because of TYPE InvalidEnum2 : STRING (a := 1, b := 2); END_TYPE
| /// For each enum without an explicit initializer, this sets the initial_value to: | ||
| /// 1. The zero-variant (if one exists), or | ||
| /// 2. The first variant (as fallback) | ||
| pub fn finalize_enum_defaults(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline, maybe add a todo for ghaith to remove this later
| let (mut index, unresolvables) = plc::resolver::const_evaluator::evaluate_constants(global_index); | ||
|
|
||
| // Fix up enum defaults after constants are resolved | ||
| index.finalize_enum_defaults(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets add this to the const_evaluator or a wrapper function calling the the const evaluator and this function, up to you
Add support for typed enums with explicit integer type specifications, supporting both IEC 61131-3 standard syntax (TYPE NAME : TYPE (...)) and Codesys syntax (TYPE NAME : (...) TYPE).
Additionally, enums are no longer blanket-zero-initialized but rather they will: