Skip to content

Commit

Permalink
added architecture design record for enums
Browse files Browse the repository at this point in the history
  • Loading branch information
riederm committed May 31, 2022
1 parent ef95187 commit 684ad86
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 1 deletion.
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;
144 changes: 144 additions & 0 deletions src/tests/adr/enum_adr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use crate::test_utils::tests::codegen;

/// # Architecture Design Record: Enums
/// An Enum (or Enumeration) is a special datatype in ST. An Enum datatype represents an 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 i32 values. They can be
/// defined by the user via an initialization statement, or automatically assigned by the compiler.
/// 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 : (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 i32 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 i32 1
@closed = unnamed_addr constant i32 4
@idle = unnamed_addr constant i32 5
@running = unnamed_addr constant i32 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

0 comments on commit 684ad86

Please sign in to comment.