rtlola_hir/
modes.rs

1pub(crate) mod ast_conversion;
2pub(crate) mod dependencies;
3pub(crate) mod memory_bounds;
4pub(crate) mod ordering;
5pub(crate) mod types;
6
7use std::collections::HashMap;
8use std::time::Duration;
9
10use rtlola_reporting::RtLolaError;
11
12use self::dependencies::{
13    DependencyGraph, Origin, StreamDependencies, TransitiveDependencies, WindowDependencies,
14};
15use self::types::HirType;
16use crate::config::FrontendConfig;
17use crate::hir::{ConcretePacingType, ExprId, Hir, SRef, StreamAccessKind, WRef};
18use crate::modes::memory_bounds::MemorizationBound;
19use crate::modes::ordering::StreamLayers;
20use crate::type_check::{ConcreteValueType, StreamType};
21
22/// Defines the construct of a mode
23///
24/// This trait groups all available mode, adding different functionality to the [RtLolaHir](crate::RtLolaHir).
25/// The trait [HirStage] declares the progress function that each mode needs to implement.
26/// Each mode implements a separate trait defining the functionality that is added by the new mode, e.g., the [TypedMode] implements the [TypedTrait], providing an interface to get the types of a stream or expression.
27/// With a new mode, a compiler flag derives the functionality of the previous modes.
28/// The [RtLolaHir](crate::RtLolaHir) progesses the following modes:
29/// [BaseMode] -> [TypedMode] -> [DepAnaMode] -> [OrderedMode] -> [MemBoundMode] -> [CompleteMode]
30pub trait HirMode {}
31
32/// Defines the functionality to progress one mode to the next one
33pub trait HirStage: Sized {
34    /// Defines the next mode that is produced by the `progress` function
35    type NextStage: HirMode;
36
37    /// Returns an [RtLolaHir](crate::RtLolaHir) with additional functionality
38    fn progress(self, cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError>;
39}
40
41/// Represents the first stage in the [RtLolaHir](crate::RtLolaHir)(crate::RtLolaHir)
42///
43/// This struct represents the mode that is created with a new [RtLolaHir](crate::RtLolaHir)(crate::RtLolaHir).
44/// The mode does not provide any additonal information and is therefore empty.
45#[derive(Clone, Debug, HirMode, Copy)]
46pub struct BaseMode {}
47
48impl HirStage for Hir<BaseMode> {
49    type NextStage = TypedMode;
50
51    fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
52        let tts = crate::type_check::type_check(&self)?;
53
54        let mode = TypedMode { types: tts };
55
56        Ok(Hir {
57            inputs: self.inputs,
58            outputs: self.outputs,
59            next_output_ref: self.next_output_ref,
60            next_input_ref: self.next_input_ref,
61            expr_maps: self.expr_maps,
62            global_tags: self.global_tags,
63            mode,
64        })
65    }
66}
67
68impl Hir<BaseMode> {
69    /// Returns the [RtLolaHir](crate::RtLolaHir) with the type information for each stream and expression
70    ///
71    /// The function returns the [RtLolaHir](crate::RtLolaHir) after the type analysis.
72    /// The new mode implements the same functionality as the [BaseMode] and additionally holds for each stream and expression its [StreamType].
73    /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
74    ///
75    /// # Fails
76    /// The function fails if the type checker finds a type error in the specification and returns a string with a detailed description.
77    pub fn check_types(self, cfg: &FrontendConfig) -> Result<Hir<TypedMode>, RtLolaError> {
78        self.progress(cfg)
79    }
80}
81
82/// Represents the results of the type checker
83#[derive(Debug, Clone)]
84pub struct Typed {
85    stream_types: HashMap<SRef, StreamType>,
86    expression_types: HashMap<ExprId, StreamType>,
87    param_types: HashMap<(SRef, usize), ConcreteValueType>,
88    eval_types: HashMap<(SRef, usize), ConcretePacingType>,
89}
90
91/// Represents the mode after the type checker call
92///
93/// This struct represents the mode after the type checker call.
94/// Besides this result, this mode has the same functionality as all the previous modes.
95/// The [TypedTrait] defines the new functionality of the mode.
96#[covers_functionality(TypedTrait, types)]
97#[derive(Debug, Clone, HirMode)]
98pub struct TypedMode {
99    types: Typed,
100}
101
102impl Typed {
103    pub(crate) fn new(
104        stream_types: HashMap<SRef, StreamType>,
105        expression_types: HashMap<ExprId, StreamType>,
106        param_types: HashMap<(SRef, usize), ConcreteValueType>,
107        eval_types: HashMap<(SRef, usize), ConcretePacingType>,
108    ) -> Self {
109        Typed {
110            stream_types,
111            expression_types,
112            param_types,
113            eval_types,
114        }
115    }
116}
117
118/// Describes the functionality of a mode after checking and inferring types
119#[mode_functionality]
120pub trait TypedTrait {
121    /// Returns the [StreamType] of the given stream
122    ///
123    /// # Panic
124    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
125    fn stream_type(&self, sr: SRef) -> HirType;
126
127    /// Returns true if the given stream has a periodic evaluation pacing
128    ///
129    /// # Panic
130    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
131    fn is_periodic(&self, sr: SRef) -> bool;
132
133    /// Returns true if the given stream has a event-based evaluation pacing
134    ///
135    /// # Panic
136    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
137    fn is_event(&self, sr: SRef) -> bool;
138
139    /// Returns the [StreamType] of the given expression
140    ///
141    /// # Panic
142    /// The function panics if the [ExprId] is invalid.
143    fn expr_type(&self, eid: ExprId) -> HirType;
144
145    /// Returns the [ConcreteValueType] of the `idx` parameter of the `sr` stream template
146    ///
147    /// # Panic
148    /// The function panics if the [StreamReference](crate::hir::StreamReference) or the index is invalid.
149    fn get_parameter_type(&self, sr: SRef, idx: usize) -> ConcreteValueType;
150
151    /// Returns the [ConcretePacingType] of the given stream
152    ///
153    /// # Panic
154    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid
155    /// or the index of the eval clause is out of bounds.
156    fn eval_pacing_type(&self, sr: SRef, idx: usize) -> ConcretePacingType;
157}
158
159impl HirStage for Hir<TypedMode> {
160    type NextStage = DepAnaMode;
161
162    fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
163        let dependencies = DepAna::analyze(&self)?;
164
165        let mode = DepAnaMode {
166            dependencies,
167            types: self.mode.types,
168        };
169
170        Ok(Hir {
171            inputs: self.inputs,
172            outputs: self.outputs,
173            next_output_ref: self.next_output_ref,
174            next_input_ref: self.next_input_ref,
175            expr_maps: self.expr_maps,
176            global_tags: self.global_tags,
177            mode,
178        })
179    }
180}
181
182impl Hir<TypedMode> {
183    /// Returns the [RtLolaHir](crate::RtLolaHir) with additional information about the dependencies between streams
184    ///
185    /// The function returns the [RtLolaHir](crate::RtLolaHir) after the dependency analysis.
186    /// The new mode implements the same functionality as the [TypedMode] and additionally contains the dependencies between streams in the specification.
187    /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
188    ///
189    /// # Fails
190    /// The function returns a [RtLolaError] if the specification is not well-formed.
191    pub fn analyze_dependencies(
192        self,
193        cfg: &FrontendConfig,
194    ) -> Result<Hir<DepAnaMode>, RtLolaError> {
195        self.progress(cfg)
196    }
197}
198
199/// Represents the results of the dependency analysis
200#[derive(Debug, Clone)]
201pub struct DepAna {
202    direct_accesses: StreamDependencies,
203    transitive_accesses: TransitiveDependencies,
204    direct_accessed_by: StreamDependencies,
205    transitive_accessed_by: TransitiveDependencies,
206    aggregated_by: WindowDependencies,
207    aggregates: WindowDependencies,
208    graph: DependencyGraph,
209}
210
211/// Represents the mode after the dependency analysis
212///
213/// This struct represents the mode after the dependency analysis.
214/// Besides this result, this mode has the same functionality as all the previous modes.
215/// The [DepAnaTrait] defines the new functionality of the mode.
216#[covers_functionality(TypedTrait, types)]
217#[covers_functionality(DepAnaTrait, dependencies)]
218#[derive(Debug, Clone, HirMode)]
219pub struct DepAnaMode {
220    types: Typed,
221    dependencies: DepAna,
222}
223
224/// Describes the functionality of a mode after analyzing the dependencies
225#[mode_functionality]
226pub trait DepAnaTrait {
227    /// Returns all streams that are direct accessed by `who`
228    ///
229    /// The function returns all streams that are direct accessed by `who`.
230    /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to `res`.
231    /// Direct accesses are all accesses appearing in the expressions of the stream itself.
232    fn direct_accesses(&self, who: SRef) -> Vec<SRef>;
233
234    /// Returns all streams that are direct accessed by `who` together with the corresponding stream access kinds.
235    ///
236    /// The function returns all streams that are direct accessed by `who` with all the stream access kinds that
237    /// are used to access that stream.
238    /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to `res`.
239    /// Direct accesses are all accesses appearing in the expressions of the stream itself.
240    fn direct_accesses_with(&self, who: SRef) -> Vec<(SRef, Vec<(Origin, StreamAccessKind)>)>;
241
242    /// Returns all streams that are transitive accessed by `who`
243    ///
244    /// The function returns all streams that are transitive accessed by `who`.
245    /// A stream `who` accesses a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'who' has a stream or window lookup to 'res'.
246    /// Transitive accesses are all accesses appearing in the expressions of the stream itself or indirect by another stream lookup.
247    fn transitive_accesses(&self, who: SRef) -> Vec<SRef>;
248
249    /// Returns all streams that direct access `who`
250    ///
251    /// The function returns all streams that direct access `who`.
252    /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
253    /// Direct accesses are all accesses appearing in the expressions of the stream itself.
254    fn direct_accessed_by(&self, who: SRef) -> Vec<SRef>;
255
256    /// Returns all streams that direct access `who` together with the corresponding stream access kinds.
257    ///
258    /// The function returns all streams that direct access `who` together with all the stream access kinds
259    /// that they use to access `who`.
260    /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
261    /// Direct accesses are all accesses appearing in the expressions of the stream itself.
262    fn direct_accessed_by_with(&self, who: SRef) -> Vec<(SRef, Vec<(Origin, StreamAccessKind)>)>;
263
264    /// Returns all streams that transitive access `who`
265    ///
266    /// The function returns all streams that transitive access `who`.
267    /// A stream `who` is accessed by a stream `res`, if the stream expression, the spawn condition and definition, the evaluation condition, or the close condition of 'res' has a stream or window lookup to 'who'.
268    /// Transitive accesses are all accesses appearing in the expressions of the stream itself or indirect by another stream lookup.
269    fn transitive_accessed_by(&self, who: SRef) -> Vec<SRef>;
270
271    /// Returns all windows that aggregate `who` and the stream that uses the window
272    ///
273    /// The function returns all windows that aggregate `who` and the stream that uses the window.
274    /// The result contains only the windows that are direct.
275    fn aggregated_by(&self, who: SRef) -> Vec<(SRef, Origin, WRef)>; // (non-transitive)
276
277    /// Returns all windows that are used in `who` and the corresponding stream that is aggregated
278    ///
279    /// The function returns all windows that are used in `who` and the corresponding stream that is aggregated.
280    /// The result contains only the windows that are direct.
281    fn aggregates(&self, who: SRef) -> Vec<(SRef, Origin, WRef)>; // (non-transitive)
282
283    /// Returns the (Dependency Graph)[DependencyGraph] of the specification
284    fn graph(&self) -> &DependencyGraph;
285}
286
287impl HirStage for Hir<DepAnaMode> {
288    type NextStage = OrderedMode;
289
290    fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
291        let order = Ordered::analyze(&self);
292
293        let mode = OrderedMode {
294            dependencies: self.mode.dependencies,
295            types: self.mode.types,
296            layers: order,
297        };
298
299        Ok(Hir {
300            inputs: self.inputs,
301            outputs: self.outputs,
302            next_output_ref: self.next_output_ref,
303            next_input_ref: self.next_input_ref,
304            expr_maps: self.expr_maps,
305            global_tags: self.global_tags,
306            mode,
307        })
308    }
309}
310
311impl Hir<DepAnaMode> {
312    /// Returns the [RtLolaHir](crate::RtLolaHir) with the spawn and evaluation layer of each stream
313    ///
314    /// # Fails
315    /// The function fails if the evaluation order cannot be determined.
316    pub fn determine_evaluation_order(
317        self,
318        cfg: &FrontendConfig,
319    ) -> Result<Hir<OrderedMode>, RtLolaError> {
320        self.progress(cfg)
321    }
322}
323
324/// Represents the evaluation order
325#[derive(Debug, Clone)]
326pub struct Ordered {
327    stream_layers: HashMap<SRef, StreamLayers>,
328}
329
330/// Represents the mode after determining the evaluation order
331///
332/// This struct represents the mode after determining the evaluation order.
333/// Besides this result, this mode has the same functionality as all the previous modes.
334/// The [OrderedTrait] defines the new functionality of the mode.
335#[covers_functionality(DepAnaTrait, dependencies)]
336#[covers_functionality(TypedTrait, types)]
337#[covers_functionality(OrderedTrait, layers)]
338#[derive(Debug, Clone, HirMode)]
339pub struct OrderedMode {
340    dependencies: DepAna,
341    types: Typed,
342    layers: Ordered,
343}
344
345/// Describes the functionality of a mode after computing the evaluation order
346#[mode_functionality]
347pub trait OrderedTrait {
348    /// Returns the [StreamLayers] of the given stream
349    ///
350    /// # Panic
351    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
352    fn stream_layers(&self, sr: SRef) -> StreamLayers;
353}
354
355impl HirStage for Hir<OrderedMode> {
356    type NextStage = MemBoundMode;
357
358    fn progress(self, cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
359        let memory = MemBound::analyze(&self, cfg.memory_bound_mode());
360
361        let mode = MemBoundMode {
362            dependencies: self.mode.dependencies,
363            types: self.mode.types,
364            layers: self.mode.layers,
365            memory,
366        };
367
368        Ok(Hir {
369            inputs: self.inputs,
370            outputs: self.outputs,
371            next_output_ref: self.next_output_ref,
372            next_input_ref: self.next_input_ref,
373            expr_maps: self.expr_maps,
374            global_tags: self.global_tags,
375            mode,
376        })
377    }
378}
379
380impl Hir<OrderedMode> {
381    /// Returns the [RtLolaHir](crate::RtLolaHir) with the memory-bound for each stream
382    ///
383    /// # Fails
384    /// The function fails if the memory cannot be determined.
385    pub fn determine_memory_bounds(
386        self,
387        cfg: &FrontendConfig,
388    ) -> Result<Hir<MemBoundMode>, RtLolaError> {
389        self.progress(cfg)
390    }
391}
392
393/// Represents the results of the memory analysis
394#[derive(Debug, Clone)]
395pub struct MemBound {
396    memory_bound_per_stream: HashMap<SRef, MemorizationBound>,
397    memory_bound_per_window: HashMap<WRef, MemorizationBound>,
398    sliding_window_bucket_size: HashMap<WRef, Duration>,
399}
400
401/// Represents the mode after the memory analysis
402///
403/// This struct represents the mode after the memory analysis.
404/// Besides this result, this mode has the same functionality as all the previous modes.
405/// The [MemBoundTrait] defines the new functionality of the mode.
406#[covers_functionality(DepAnaTrait, dependencies)]
407#[covers_functionality(TypedTrait, types)]
408#[covers_functionality(OrderedTrait, layers)]
409#[covers_functionality(MemBoundTrait, memory)]
410#[derive(Debug, Clone, HirMode)]
411pub struct MemBoundMode {
412    dependencies: DepAna,
413    types: Typed,
414    layers: Ordered,
415    memory: MemBound,
416}
417
418/// Describes the functionality of a mode after computing the memory bounds
419#[mode_functionality]
420pub trait MemBoundTrait {
421    /// Returns the memory bound of the given stream
422    ///
423    /// # Panic
424    /// The function panics if the [StreamReference](crate::hir::StreamReference) is invalid.
425    fn memory_bound(&self, sr: SRef) -> MemorizationBound;
426
427    /// Returns the memory bound of the given sliding window
428    ///
429    /// # Panic
430    /// The function panics if the [WindowReference](crate::hir::WindowReference) is invalid.
431    fn num_buckets(&self, wr: WRef) -> MemorizationBound;
432
433    /// Returns the time per bucket of a sliding window.
434    ///
435    /// # Panic
436    /// The function panics if the [WindowReference](crate::hir::WindowReference) is not a valid
437    /// sliding window reference.
438    fn bucket_size(&self, wr: WRef) -> Duration;
439}
440
441impl HirStage for Hir<MemBoundMode> {
442    type NextStage = CompleteMode;
443
444    fn progress(self, _cfg: &FrontendConfig) -> Result<Hir<Self::NextStage>, RtLolaError> {
445        let mode = CompleteMode {
446            dependencies: self.mode.dependencies,
447            types: self.mode.types,
448            layers: self.mode.layers,
449            memory: self.mode.memory,
450        };
451
452        Ok(Hir {
453            inputs: self.inputs,
454            outputs: self.outputs,
455            next_output_ref: self.next_output_ref,
456            next_input_ref: self.next_input_ref,
457            expr_maps: self.expr_maps,
458            global_tags: self.global_tags,
459            mode,
460        })
461    }
462}
463
464impl Hir<MemBoundMode> {
465    /// Returns the [RtLolaHir](crate::RtLolaHir) in the last mode
466    ///
467    /// The function returns the [RtLolaHir](crate::RtLolaHir) in the [CompleteMode].
468    /// This mode indicates that the [RtLolaHir](crate::RtLolaHir) has passed all analyzes and now contains all information.
469    /// The function moves the information of the previous mode to the new one and therefore destroys the current mode.
470    pub fn finalize(self, cfg: &FrontendConfig) -> Result<Hir<CompleteMode>, RtLolaError> {
471        self.progress(cfg)
472    }
473}
474
475/// Represents the final mode.
476///
477/// This struct represents the final mode and indicates that the [RtLolaHir](crate::RtLolaHir) has passed all analyzes and now contains all information.
478/// This mode has the same functionality as all the previous modes put together.
479#[covers_functionality(DepAnaTrait, dependencies)]
480#[covers_functionality(TypedTrait, types)]
481#[covers_functionality(OrderedTrait, layers)]
482#[covers_functionality(MemBoundTrait, memory)]
483#[derive(Debug, Clone, HirMode)]
484pub struct CompleteMode {
485    dependencies: DepAna,
486    types: Typed,
487    layers: Ordered,
488    memory: MemBound,
489}