1#[derive(Debug, Clone)]
10pub struct SeqIR {
11 pub program_name: String,
12 pub options: ProgramOptions,
13 pub channels: Vec<IRChannel>,
14 pub event_flags: Vec<IREventFlag>,
15 pub variables: Vec<IRVariable>,
16 pub state_sets: Vec<IRStateSet>,
17 pub entry_block: Option<IRBlock>,
18 pub exit_block: Option<IRBlock>,
19}
20
21#[derive(Debug, Clone, Default)]
22pub struct ProgramOptions {
23 pub safe_mode: bool,
24 pub reentrant: bool,
25 pub main_flag: bool,
26}
27
28#[derive(Debug, Clone)]
29pub struct IRChannel {
30 pub id: usize,
31 pub var_name: String,
32 pub pv_name: String,
33 pub var_type: IRType,
34 pub monitored: bool,
35 pub sync_ef: Option<usize>,
36}
37
38#[derive(Debug, Clone)]
39pub struct IREventFlag {
40 pub id: usize,
41 pub name: String,
42 pub synced_channels: Vec<usize>,
43}
44
45#[derive(Debug, Clone)]
46pub struct IRVariable {
47 pub name: String,
48 pub var_type: IRType,
49 pub channel_id: Option<usize>,
51 pub init_value: Option<String>,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum IRType {
57 Int,
58 Short,
59 Long,
60 Float,
61 Double,
62 String,
63 Char,
64 Array {
65 element: Box<IRType>,
66 size: usize,
67 },
68}
69
70impl IRType {
71 pub fn rust_type(&self) -> String {
73 match self {
74 IRType::Int => "i32".into(),
75 IRType::Short => "i16".into(),
76 IRType::Long => "i32".into(),
77 IRType::Float => "f32".into(),
78 IRType::Double => "f64".into(),
79 IRType::String => "String".into(),
80 IRType::Char => "u8".into(),
81 IRType::Array { element, size } => {
82 format!("[{}; {size}]", element.rust_type())
83 }
84 }
85 }
86
87 pub fn default_value(&self) -> String {
89 match self {
90 IRType::Int | IRType::Short | IRType::Long => "0".into(),
91 IRType::Float => "0.0f32".into(),
92 IRType::Double => "0.0".into(),
93 IRType::String => "String::new()".into(),
94 IRType::Char => "0u8".into(),
95 IRType::Array { element, size } => {
96 format!("[{}; {size}]", element.default_value())
97 }
98 }
99 }
100
101 pub fn to_epics_value_expr(&self, var_expr: &str) -> String {
103 match self {
104 IRType::Double => format!("EpicsValue::Double({var_expr})"),
105 IRType::Float => format!("EpicsValue::Float({var_expr})"),
106 IRType::Int | IRType::Long => format!("EpicsValue::Long({var_expr})"),
107 IRType::Short => format!("EpicsValue::Short({var_expr})"),
108 IRType::String => format!("EpicsValue::String({var_expr}.clone())"),
109 IRType::Char => format!("EpicsValue::Char({var_expr})"),
110 IRType::Array { element, .. } => {
111 match element.as_ref() {
112 IRType::Double => format!("EpicsValue::DoubleArray({var_expr}.to_vec())"),
113 IRType::Float => format!("EpicsValue::FloatArray({var_expr}.to_vec())"),
114 IRType::Int | IRType::Long => format!("EpicsValue::LongArray({var_expr}.to_vec())"),
115 IRType::Short => format!("EpicsValue::ShortArray({var_expr}.to_vec())"),
116 _ => format!("EpicsValue::Double(0.0) /* unsupported array type */"),
117 }
118 }
119 }
120 }
121
122 pub fn from_epics_value_expr(&self, val_expr: &str) -> String {
124 match self {
125 IRType::Double => format!("{val_expr}.to_f64().unwrap_or(0.0)"),
126 IRType::Float => format!("{val_expr}.to_f64().unwrap_or(0.0) as f32"),
127 IRType::Int | IRType::Long => format!("{val_expr}.to_f64().unwrap_or(0.0) as i32"),
128 IRType::Short => format!("{val_expr}.to_f64().unwrap_or(0.0) as i16"),
129 IRType::Char => format!("{val_expr}.to_f64().unwrap_or(0.0) as u8"),
130 IRType::String => format!("format!(\"{{}}\", {val_expr})"),
131 IRType::Array { element, size } => {
132 let elem_type = element.rust_type();
133 let elem_extract = match element.as_ref() {
134 IRType::Double => format!(
135 "{{ let arr = {val_expr}.to_f64_array(); let mut out = [0.0{elem_type}; {size}]; let n = arr.len().min({size}); out[..n].copy_from_slice(&arr[..n]); out }}"
136 ),
137 _ => format!(
138 "[{default}; {size}] /* array extract not fully supported */",
139 default = element.default_value()
140 ),
141 };
142 elem_extract
143 }
144 }
145 }
146
147 pub fn element_type(&self) -> Option<&IRType> {
149 match self {
150 IRType::Array { element, .. } => Some(element),
151 _ => None,
152 }
153 }
154}
155
156#[derive(Debug, Clone)]
157pub struct IRStateSet {
158 pub name: String,
159 pub id: usize,
160 pub local_vars: Vec<IRVariable>,
161 pub states: Vec<IRState>,
162}
163
164#[derive(Debug, Clone)]
165pub struct IRState {
166 pub name: String,
167 pub id: usize,
168 pub entry: Option<IRBlock>,
169 pub transitions: Vec<IRTransition>,
170 pub exit: Option<IRBlock>,
171}
172
173#[derive(Debug, Clone)]
174pub struct IRTransition {
175 pub condition: Option<String>,
178 pub action: IRBlock,
180 pub target_state: Option<usize>,
182}
183
184#[derive(Debug, Clone)]
187pub struct IRBlock {
188 pub code: String,
189}
190
191impl IRBlock {
192 pub fn new(code: impl Into<String>) -> Self {
193 Self { code: code.into() }
194 }
195}