Skip to content
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

added architecture design record for enums #496

Merged
merged 3 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/tests/adr.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/// tests for Architecture Design Records (ADR)
mod enum_adr;
mod pou_adr;
146 changes: 146 additions & 0 deletions src/tests/adr/enum_adr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use crate::test_utils::tests::codegen;

/// # Architecture Design Record: Enums
/// An Enum (or Enumeration) is a special datatype in ST. An Enum datatype represents a numeric datatype (default is i32)
/// with a list of well defined values with dedicated names (e.g. `@red`, `@yellow`, `@green`).
///
/// e.g.
/// ```st
/// TYPE MyEnum: (element1, element2, element3);
/// END_TYPE
/// ```
#[test]
fn enums_generate_a_global_constants_for_each_element() {
let src = r#"
TYPE Color : (red, yellow, green);
END_TYPE;

VAR_GLOBAL
myColor : Color;
END_VAR"#;
insta::assert_snapshot!(codegen(src), @r###"
; ModuleID = 'main'
source_filename = "main"

@myColor = global i32 0
@red = unnamed_addr constant i32 0
@yellow = unnamed_addr constant i32 1
@green = unnamed_addr constant i32 2
"###);
}

/// The values of the enum constants are stored as (enum-local) unique numeric values. The values and their
/// datatype (see declaration of `State : BYTE`) can be defined by the user via an initialization statement,
/// or automatically assigned by the compiler.
/// `i32` is the default datatype for enums if no other type is specified (e.g. `Color`).
/// Values that are assigned by the compiler get unique ascending values.
#[test]
fn enums_constants_are_automatically_numbered_or_user_defined() {
let src = r#"
TYPE Color : (red := 1, yellow := 2, green := 4, blue := 8);
END_TYPE;

TYPE State : BYTE (open := 1, closed := 4, idle, running);
END_TYPE;

VAR_GLOBAL
myColor : Color;
myState : State;
END_VAR"#;

insta::assert_snapshot!(codegen(src), @r###"
; ModuleID = 'main'
source_filename = "main"

@myColor = global i32 0
@myState = global i8 0
@red = unnamed_addr constant i32 1
@yellow = unnamed_addr constant i32 2
@green = unnamed_addr constant i32 4
@blue = unnamed_addr constant i32 8
@open = unnamed_addr constant i8 1
@closed = unnamed_addr constant i8 4
@idle = unnamed_addr constant i8 5
@running = unnamed_addr constant i8 6
"###);
}

/// Enum types can be declared as dedicated DataTypes (see above) or direclty as part of a
/// variable declaration. Note that declaring the same enum twice will result in two distinct
/// enum-datatypes (and separate constant-variables - e.g. `@red` and `@red.1`).
#[test]
fn inline_declaration_of_enum_types() {
let src = r#"
VAR_GLOBAL
frontColor : (red, green, yellow);
backColor : (red, green, yellow);
END_VAR"#;

insta::assert_snapshot!(codegen(src), @r###"
; ModuleID = 'main'
source_filename = "main"

@frontColor = global i32 0
@backColor = global i32 0
@red = unnamed_addr constant i32 0
@green = unnamed_addr constant i32 1
@yellow = unnamed_addr constant i32 2
@red.1 = unnamed_addr constant i32 0
@green.2 = unnamed_addr constant i32 1
@yellow.3 = unnamed_addr constant i32 2
"###);
}

/// Enum elements can accessed like global variables. If there are mulitple candidates, one can
/// pick a specific element by qualifying it with the enum's name (note that this is not possible for inline
/// enums).
/// In this example the enum-element `open` is defined in the type `ProcessState` as well as in `Door`. We can now
/// select a specific element by qualifying it via `ProcessState#closed` or `Door#closed` to access the generated global
/// variables `@closed` or `@closed.2`.
#[test]
fn using_enums() {
let src = r#"
TYPE ProcessState : (open := 1, closed := 4, idle, running);
END_TYPE;

TYPE Door : (open := 8, closed := 16);
END_TYPE;

PROGRAM prg
VAR x, y, z : DINT; END_VAR

x := idle;
y := ProcessState#closed;
z := Door#closed;
END_PROGRAM
"#;

insta::assert_snapshot!(codegen(src), @r###"
; ModuleID = 'main'
source_filename = "main"

%prg_interface = type { i32, i32, i32 }

@prg_instance = global %prg_interface zeroinitializer
@open = unnamed_addr constant i32 1
@closed = unnamed_addr constant i32 4
@idle = unnamed_addr constant i32 5
@running = unnamed_addr constant i32 6
@open.1 = unnamed_addr constant i32 8
@closed.2 = unnamed_addr constant i32 16

define void @prg(%prg_interface* %0) {
entry:
%x = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 0
%y = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 1
%z = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 2
%load_idle = load i32, i32* @idle, align 4
store i32 %load_idle, i32* %x, align 4
%load_closed = load i32, i32* @closed, align 4
store i32 %load_closed, i32* %y, align 4
%load_closed1 = load i32, i32* @closed.2, align 4
store i32 %load_closed1, i32* %z, align 4
ret void
}
"###);
}
2 changes: 1 addition & 1 deletion src/tests/adr/pou_adr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::test_utils::tests::{annotate, codegen, index};

/// Architecture Design Record: POUs
/// # Architecture Design Record: POUs
///
/// POU = Program Organisation Unit
///
Expand Down