Skip to main content

mt_mtc/
lib.rs

1/// Comile compiler for .mt files and resolve variables or functions.
2use core::fmt;
3use std::{collections::HashMap, path::PathBuf, str::FromStr};
4
5use anyhow::anyhow;
6use ariadne::{Color, Label, Report, ReportKind, Source};
7use logos::{Lexer, Logos};
8
9use chumsky::{
10    container::Seq,
11    input::{Stream, ValueInput},
12    prelude::*,
13};
14use mt_net::{ActionPlan, COMPARE_NODE_NAME, Rules, VariableHuman};
15
16fn floating_millimeter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
17    let slice = lex.slice();
18    let f: f64 = slice[..slice.len() - 2].parse().ok()?;
19    Some(f)
20}
21
22fn floating_centimeter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
23    let slice = lex.slice();
24    let f: f64 = slice[..slice.len() - 2].parse().ok()?;
25    Some(f * 10.0)
26}
27
28fn floating_meter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
29    let slice = lex.slice();
30    let f: f64 = slice[..slice.len() - 1].parse().ok()?;
31    Some(f * 10.0 * 100.0)
32}
33
34fn integer_millimeter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
35    let slice = lex.slice();
36    let f: i64 = slice[..slice.len() - 2].parse().ok()?;
37    Some(f)
38}
39
40fn integer_centimeter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
41    let slice = lex.slice();
42    let f: i64 = slice[..slice.len() - 2].parse().ok()?;
43    Some(f * 10)
44}
45
46fn integer_meter<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
47    let slice = lex.slice();
48    let f: i64 = slice[..slice.len() - 1].parse().ok()?;
49    Some(f * 10 * 100)
50}
51
52fn integer_second<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
53    let slice = lex.slice();
54    let f: i64 = slice[..slice.len() - 1].parse().ok()?;
55    Some(f * 1000)
56}
57
58fn integer_minute<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
59    let slice = lex.slice();
60    let len = if slice.ends_with('s') { 4 } else { 3 };
61    let f: i64 = slice[..slice.len() - len].parse().ok()?;
62    Some(f * 60 * 1000)
63}
64
65fn integer_millisec<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
66    let slice = lex.slice();
67    let f: i64 = slice[..slice.len() - 2].parse().ok()?;
68    Some(f)
69}
70
71fn integer_hour<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<i64> {
72    let slice = lex.slice();
73    let len = if slice.ends_with('s') { 5 } else { 4 };
74    let f: i64 = slice[..slice.len() - len].parse().ok()?;
75    Some(f * 60 * 60 * 1000)
76}
77
78fn floating_second<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
79    let slice = lex.slice();
80    let f: f64 = slice[..slice.len() - 1].parse().ok()?;
81    Some(f * 1000.0)
82}
83
84fn floating_minute<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
85    let slice = lex.slice();
86    let len = if slice.ends_with('s') { 4 } else { 3 };
87    let f: f64 = slice[..slice.len() - len].parse().ok()?;
88    Some(f * 60.0 * 1000.0)
89}
90
91fn floating_millisec<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
92    let slice = lex.slice();
93    let f: f64 = slice[..slice.len() - 2].parse().ok()?;
94    Some(f)
95}
96
97fn floating_hour<'a>(lex: &mut Lexer<'a, Token<'a>>) -> Option<f64> {
98    let slice = lex.slice();
99    let len = if slice.ends_with('s') { 5 } else { 4 };
100    let f: f64 = slice[..slice.len() - len].parse().ok()?;
101    Some(f * 60.0 * 60.0 * 1000.0)
102}
103
104fn rm_first<'a>(lex: &mut Lexer<'a, Token<'a>>) -> &'a str {
105    let slice = lex.slice();
106    &slice[1..slice.len()]
107}
108
109fn rm_last<'a>(lex: &mut Lexer<'a, Token<'a>>) -> &'a str {
110    let slice = lex.slice();
111    &slice[0..slice.len() - 1]
112}
113
114fn rm_first_and_last<'a>(lex: &mut Lexer<'a, Token<'a>>) -> &'a str {
115    let slice = lex.slice();
116    &slice[1..slice.len() - 1]
117}
118
119#[derive(Debug, PartialEq, Clone, Copy)]
120pub enum SensorType {
121    Lidar,
122    Imu,
123    Odom,
124    Mixed,
125    Any,
126}
127
128impl FromStr for SensorType {
129    type Err = std::io::Error;
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        Ok(match s.to_lowercase().as_str() {
133            "cloud" => Self::Lidar,
134            "imu" => Self::Imu,
135            "odom" => Self::Odom,
136            "mixed" => Self::Mixed,
137            _ => Self::Any,
138        })
139    }
140}
141
142pub const POINTCLOUD_ROS2_TYPE: &str = "sensor_msgs/msg/PointCloud2";
143pub const IMU_ROS2_TYPE: &str = "sensor_msgs/msg/Imu";
144pub const ODOM_ROS2_TYPE: &str = "nav_msgs/msg/Odometry";
145
146impl SensorType {
147    pub fn is(&self, query: &str) -> bool {
148        match self {
149            SensorType::Lidar => query == POINTCLOUD_ROS2_TYPE,
150            SensorType::Imu => query == IMU_ROS2_TYPE,
151            SensorType::Mixed => {
152                query == POINTCLOUD_ROS2_TYPE || query == IMU_ROS2_TYPE || query == ODOM_ROS2_TYPE
153            }
154            SensorType::Any => true,
155            SensorType::Odom => query == ODOM_ROS2_TYPE,
156        }
157    }
158}
159
160#[derive(Debug, PartialEq, Clone)]
161enum PlayType {
162    SensorCount {
163        sensors: Vec<String>,
164    },
165    UntilSensorCount {
166        sending: Vec<String>,
167        until_sensors: Vec<String>,
168    },
169}
170
171#[derive(Logos, Debug, PartialEq, Clone)]
172#[logos(skip r"[ \t\f]+")]
173enum Token<'a> {
174    Error,
175
176    // -- Control --
177    #[token("+")]
178    OpPlus,
179
180    #[token("-")]
181    OpMinus,
182
183    // #[token("<")]
184    // OpInclude,
185    #[regex(".", priority = 1)]
186    Dot,
187
188    #[token(",")]
189    Comma,
190
191    #[regex(r"(#.*)?\n")]
192    NewLine,
193
194    #[token("(")]
195    BracketOpen,
196
197    #[token(")")]
198    BracketClose,
199
200    #[token("{")]
201    BlockStart,
202
203    #[token("}")]
204    BlockEnd,
205
206    #[token("[")]
207    LParen,
208
209    #[token("]")]
210    RParen,
211
212    // -- Operators --
213    #[token("==")]
214    OpCompare,
215
216    #[regex("<-|=")]
217    OpAssignToLeft,
218
219    #[regex("->", priority = 1000)]
220    OpAssignToRight,
221
222    #[token("..")]
223    OpRange,
224
225    #[regex(r"\.?\/+[^ \n]*")]
226    Path(&'a str),
227
228    #[regex(r#""[^"]+""#, rm_first_and_last)]
229    String(&'a str),
230
231    // #[token("::")]
232    // EnumDivider,
233
234    // -- Keywords --
235    #[token("if")]
236    KwIf,
237
238    #[token("loop")]
239    KwLoop,
240
241    #[token("LOG")]
242    KwLog,
243
244    #[token("~")]
245    DoNotCareOptim,
246
247    // -- Embedded functions (Wind) --
248    #[regex(r"pf!")]
249    FnPlayFrames,
250
251    #[token("reset!")]
252    FnReset,
253
254    #[token("rule!")]
255    FnRule,
256
257    // -- Expressions --
258    #[token("true")]
259    True,
260
261    #[token("false")]
262    False,
263
264    #[regex(r"[+-]?\d+", |lex| lex.slice().parse().ok())]
265    IntegerNumber(i64),
266
267    #[regex(r"[+-]?(\d+)?\.\d*", |lex| lex.slice().parse().ok())]
268    FloatingNumber(f64),
269
270    #[regex(r"[+-]?(\d+)?\.\d*mm", floating_millimeter)]
271    #[regex(r"[+-]?(\d+)?\.\d*m]", floating_meter)]
272    #[regex(r"[+-]?(\d+)?\.\d*cm", floating_centimeter)]
273    FloatingNumberMillimeter(f64),
274
275    #[regex(r"[+-]?(\d+)?\.\d*s]", floating_second)]
276    #[regex(r"[+-]?(\d+)?\.\d*ms]", floating_millisec)]
277    #[regex(r"[+-]?(\d+)?\.\d*mins?]", floating_minute)]
278    #[regex(r"[+-]?(\d+)?\.\d*hours?]", floating_hour)]
279    FloatingNumberMillisecond(f64),
280
281    #[regex(r"[+-]?(\d+cm)", integer_centimeter)]
282    #[regex(r"[+-]?(\d+mm)", integer_millimeter)]
283    #[regex(r"[+-]?(\d+m)", integer_meter)]
284    IntegerNumberMillimeter(i64),
285
286    #[regex(r"[+-]?(\d+s)", integer_second)]
287    #[regex(r"[+-]?(\d+ms)", integer_millisec)]
288    #[regex(r"[+-]?(\d+mins)", integer_minute)]
289    #[regex(r"[+-]?(\d+hours)", integer_hour)]
290    IntegerNumberMillisecond(i64),
291
292    #[regex(r"[a-zA-Z_:]+\d*[a-zA-Z_:\d]*\.", rm_last)]
293    VarNamespace(&'a str),
294
295    #[regex(r"[a-zA-Z_:]+\d*[a-zA-Z_:\d]*")]
296    Variable(&'a str),
297
298    #[regex(r"_[a-zA-Z_:]+\d*[a-zA-Z_:\d]*", rm_first)]
299    PredefVariable(&'a str),
300}
301
302impl fmt::Display for Token<'_> {
303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304        match self {
305            Self::VarNamespace(ns) => write!(f, "Namespace({:?})", ns),
306            Self::Path(path) => write!(f, "Path({:?})", path),
307            Self::String(string) => write!(f, "String({:?})", string),
308            // Self::EnumDivider => write!(f, "::"),
309            Self::FnReset => write!(f, "reset()"),
310            Self::FnRule => write!(f, "rule()"),
311            Self::Comma => write!(f, ","),
312            Self::KwLog => write!(f, "LOG"),
313            Self::OpPlus => write!(f, "+"),
314            Self::Dot => write!(f, "."),
315            Self::OpMinus => write!(f, "-"),
316            Self::Error => write!(f, "<error>"),
317            Self::NewLine => write!(f, "\\n"),
318            Self::BracketOpen => write!(f, "["),
319            Self::BracketClose => write!(f, "]"),
320            Self::BlockStart => write!(f, "{{"),
321            Self::BlockEnd => write!(f, "}}"),
322            Self::LParen => write!(f, "("),
323            Self::RParen => write!(f, ")"),
324            Self::OpCompare => write!(f, "=="),
325            Self::OpAssignToLeft => write!(f, "<-"),
326            Self::OpAssignToRight => write!(f, "->"),
327            Self::OpRange => write!(f, ".."),
328            Self::KwIf => write!(f, "if"),
329            Self::KwLoop => write!(f, "loop"),
330            Self::DoNotCareOptim => write!(f, "~"),
331            Self::FnPlayFrames => write!(f, "play_frames()"),
332            Self::True => write!(f, "true"),
333            Self::False => write!(f, "false"),
334            Self::IntegerNumber(s) => write!(f, "{}", s),
335            Self::FloatingNumber(s) => write!(f, "{}", s),
336            Self::FloatingNumberMillimeter(s) => write!(f, "{}mm", s),
337            Self::FloatingNumberMillisecond(s) => write!(f, "{}ms", s),
338            Self::IntegerNumberMillimeter(s) => write!(f, "{}mm", s),
339            Self::IntegerNumberMillisecond(s) => write!(f, "{}ms", s),
340            Self::Variable(s) => write!(f, "{}", s),
341            Self::PredefVariable(s) => write!(f, "_{}", s),
342        }
343    }
344}
345
346#[derive(Debug, Clone, Copy)]
347pub enum NumVal {
348    Floating(f64),
349    Integer(i64),
350}
351
352impl PartialEq for NumVal {
353    fn eq(&self, other: &Self) -> bool {
354        let tolerance = 1e-6; // Adjust this value as needed
355        match (self, other) {
356            (NumVal::Floating(fl), NumVal::Floating(fr)) => (fl - fr).abs() < tolerance,
357            (NumVal::Floating(_), NumVal::Integer(_)) => false,
358            (NumVal::Integer(_), NumVal::Floating(_)) => false,
359            (NumVal::Integer(il), NumVal::Integer(ir)) => il == ir,
360        }
361    }
362}
363
364impl Eq for NumVal {}
365
366impl NumVal {
367    pub fn integerize_unit_val(self) -> NumVal {
368        if let NumVal::Floating(f) = self {
369            NumVal::Integer(f.round() as i64)
370        } else {
371            self
372        }
373    }
374}
375
376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
377pub enum Unit {
378    TimeMilliseconds,
379    WayMillimeter,
380}
381
382#[derive(Debug, Clone, PartialEq, Eq)]
383pub enum Val {
384    UnitedVal(UnitVal),
385    NumVal(NumVal),
386    StringVal(String),
387    BoolVal(bool),
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq)]
391pub struct UnitVal {
392    pub val: u64,
393    pub unit: Unit,
394}
395
396#[derive(Debug, Clone, PartialEq, Eq)]
397pub enum Rhs {
398    Range { from: Option<Val>, to: Option<Val> },
399    Var(Var),
400    Path(String),
401    // Expr() TODO evaluate so in the end it becomes atomic Rhs
402    Val(Val),
403    Array(Vec<Box<Self>>),
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, Hash)]
407pub enum Var {
408    Log,
409    Predef {
410        name: String,
411        namespace: Vec<String>,
412    },
413    User {
414        name: String,
415        namespace: Vec<String>,
416    },
417}
418
419fn vec_prepend<T: Clone>(prepend: &[T], source: &[T]) -> Vec<T> {
420    let mut out = prepend.to_vec();
421    out.extend(source.iter().cloned());
422    out
423}
424
425impl Var {
426    pub fn add_namespace(self, ns: &[String]) -> Self {
427        match self {
428            Var::User { name, namespace } => Var::User {
429                name,
430                namespace: vec_prepend(ns, &namespace),
431            },
432            Var::Log => Var::Log,
433            Var::Predef { name, namespace } => Var::Predef {
434                name,
435                namespace: vec_prepend(ns, &namespace),
436            },
437        }
438    }
439}
440
441impl FromStr for Var {
442    type Err = anyhow::Error;
443
444    fn from_str(s: &str) -> Result<Self, Self::Err> {
445        let splitted = s.split(".").collect::<Vec<_>>();
446
447        let l = splitted.len();
448        if l < 1 {
449            return Err(anyhow!("Nothing to parse"));
450        }
451
452        let last = splitted[l - 1];
453
454        Ok(if last == COMPARE_NODE_NAME {
455            Self::Log
456        } else {
457            let mut v: Vec<String> = vec![];
458            if l > 1 {
459                v.extend(splitted.into_iter().take(l - 1).map(String::from));
460            }
461            if let Some(predef) = last.strip_prefix("_") {
462                Self::Predef {
463                    name: predef.to_owned(),
464                    namespace: v,
465                }
466            } else {
467                Self::User {
468                    name: last.to_owned(),
469                    namespace: v,
470                }
471            }
472        })
473    }
474}
475
476#[derive(Debug)]
477pub struct Evaluated {
478    pub rules: Rules,
479    pub wind: Vec<WindFunction>,
480    pub vars: VariableHistory,
481}
482
483impl Default for Evaluated {
484    fn default() -> Self {
485        Self::new()
486    }
487}
488
489impl Evaluated {
490    pub fn new() -> Self {
491        Self {
492            rules: Rules::new(),
493            wind: vec![],
494            vars: VariableHistory::new(vec![]),
495        }
496    }
497}
498
499#[derive(Debug)]
500pub enum WindFunction {
501    Reset(String),
502    SendFrames(PlayKindUnitedPass3),
503}
504
505#[derive(Debug, Clone)]
506pub struct Root<'a> {
507    pub rules: RuleSexpr,
508    pub wind: Vec<StatementKind<'a>>,
509    pub vardefs: Vec<Statement>,
510}
511
512pub type PlayTimeMsRange = (u64, u64);
513
514#[derive(Debug, PartialEq, Clone)]
515pub enum PlayTrigger {
516    DurationMs(u64),
517    DurationRelFactor(f64),
518    Variable(String),
519}
520
521#[derive(Debug, PartialEq, Clone, Copy)]
522pub enum PlayMode {
523    Dynamic,
524    Fix,
525}
526
527#[derive(Debug, PartialEq, Clone, Copy)]
528pub enum AbsTimeRange {
529    Open,
530    UpperOpen(u64),
531    LowerOpen(u64),
532    Closed((u64, u64)),
533}
534
535#[derive(Debug, PartialEq, Clone, Copy)]
536pub enum PlayCount {
537    TimeRelativeMs(u64),
538    TimeRangeMs(AbsTimeRange),
539    Amount(u64),
540}
541
542#[derive(Debug, PartialEq, Clone)]
543pub enum SensorIdentification {
544    Topic(String),    // no type given, compare by topics
545    Type(SensorType), // type given but no topics, check for types
546    TopicAndType { topic: String, msg_type: SensorType }, // both given but only use topics for collect until because it is more fine grained
547}
548
549#[derive(Debug, PartialEq, Clone)]
550pub struct AnySensor {
551    pub name: String, // custom name given by config
552    pub id: SensorIdentification,
553    pub short: Option<String>, // to be used while parsing to not write so much
554}
555
556#[derive(Debug, PartialEq, Clone)]
557pub enum PlayKindUnited {
558    SensorCount {
559        sensors: Vec<String>,
560        count: PlayCount,
561        trigger: Option<PlayTrigger>,
562        play_mode: PlayMode,
563    },
564    UntilSensorCount {
565        sending: Vec<String>,
566        until_sensors: Vec<String>,
567        until_count: PlayCount,
568        trigger: Option<PlayTrigger>,
569        play_mode: PlayMode,
570    },
571}
572
573#[derive(Debug, PartialEq, Clone)]
574pub enum PlayKindUnitedPass3 {
575    SensorCount {
576        sensors: Vec<AnySensor>,
577        count: PlayCount,
578        trigger: Option<PlayTrigger>,
579        play_mode: PlayMode,
580    },
581    UntilSensorCount {
582        sending: Vec<AnySensor>,
583        until_sensors: Vec<AnySensor>,
584        until_count: PlayCount,
585        trigger: Option<PlayTrigger>,
586        play_mode: PlayMode,
587    },
588}
589
590#[derive(Debug, Clone)]
591pub enum StatementKind<'a> {
592    Rule(Rule<'a>),
593    VariableDef(Statement),
594    Reset(String),
595    SendFrames { kind: PlayKindUnited, at: String },
596    VariableNamespaceBlock(Vec<Statement>),
597}
598
599#[derive(Debug, Clone)]
600pub enum StatementKindPass1<'a> {
601    Rule(Rule<'a>),
602    VariableDef(Statement),
603    Reset(String),
604    Include {
605        namespace: Vec<String>,
606        path: String,
607    },
608    SendFrames(PlayKindUnited),
609    VariableNamespaceBlock {
610        ns: Vec<&'a str>,
611        stmts: Vec<Box<StatementKindPass1<'a>>>,
612    },
613    Loop {
614        count: usize,
615        stmts: Vec<Box<StatementKindPass1<'a>>>,
616    },
617}
618
619#[derive(Debug, Clone)]
620pub enum StatementKindOwnedPass1 {
621    Rule(RuleOwned),
622    Include {
623        namespace: Vec<String>,
624        path: String,
625    },
626    VariableDef(Statement),
627    VariableNamespaceBlock {
628        ns: Vec<String>,
629        stmts: Vec<Box<StatementKindOwnedPass1>>,
630    },
631    Reset(String),
632    SendFrames(PlayKindUnited),
633    Loop {
634        count: usize,
635        stmts: Vec<Box<StatementKindOwnedPass1>>,
636    },
637}
638
639#[derive(Debug, Clone)]
640pub enum StatementKindOwned {
641    Rule(RuleOwned),
642    VariableDef(Statement),
643    Reset(String),
644    SendFrames(PlayKindUnited),
645}
646
647#[derive(Debug, Clone)]
648pub enum StatementKindOwnedPass3 {
649    Rule(RuleOwned),
650    VariableDef(Statement),
651    Reset(String),
652    SendFrames(PlayKindUnitedPass3),
653}
654
655fn do_pass1(
656    pass1: Vec<StatementKindOwnedPass1>,
657    current_parent: &std::path::Path,
658) -> anyhow::Result<Vec<StatementKindOwned>> {
659    let mut out = vec![];
660
661    for stmt in pass1 {
662        match stmt {
663            StatementKindOwnedPass1::Rule(rule_owned) => {
664                out.push(StatementKindOwned::Rule(rule_owned));
665            }
666            StatementKindOwnedPass1::VariableDef(statement) => {
667                out.push(StatementKindOwned::VariableDef(statement));
668            }
669            StatementKindOwnedPass1::VariableNamespaceBlock { ns, stmts } => {
670                let v = stmts.into_iter().map(|f| *f).collect::<Vec<_>>();
671
672                let passed = do_pass1(v, current_parent)?;
673                out.extend(
674                    passed
675                        .into_iter()
676                        .map(|t| match t {
677                            StatementKindOwned::VariableDef(statement) => Ok(
678                                StatementKindOwned::VariableDef(statement.add_namespace(&ns)),
679                            ),
680                            _ => Err(anyhow!(
681                                "Only variable statements allowed inside a namespace block."
682                            )),
683                        })
684                        .try_fold(Vec::new(), |mut acc, res| match res {
685                            Ok(ok) => {
686                                acc.push(ok);
687                                Ok(acc)
688                            }
689                            Err(e) => Err(e),
690                        })?,
691                );
692            }
693            StatementKindOwnedPass1::Reset(rs) => {
694                out.push(StatementKindOwned::Reset(rs));
695            }
696            StatementKindOwnedPass1::SendFrames(kind) => {
697                out.push(StatementKindOwned::SendFrames(kind));
698            }
699            StatementKindOwnedPass1::Loop { count, stmts } => {
700                let v = stmts.into_iter().map(|f| *f).collect::<Vec<_>>();
701                let passed = do_pass1(v, current_parent)?;
702
703                // Repeat the statements `count` times
704                for _ in 0..count {
705                    out.extend(passed.clone());
706                }
707            }
708            StatementKindOwnedPass1::Include { namespace, path } => {
709                let to_parse = PathBuf::from_str(&path)?;
710                let to_parse = if to_parse.is_relative() {
711                    if to_parse.is_dir() {
712                        return Err(anyhow!("File is a directory: {}", to_parse.display()));
713                    } else {
714                        current_parent.join(path).to_owned()
715                    }
716                } else {
717                    to_parse
718                };
719                let nast = parse_to_ast(&to_parse)?;
720                let nast = ast_add_namespace(&namespace, nast);
721                out.extend(nast);
722            }
723        }
724    }
725
726    Ok(out)
727}
728
729fn parse_to_ast(path: &std::path::Path) -> anyhow::Result<Vec<StatementKindOwned>> {
730    let file = std::fs::read_to_string(path);
731    let file = match file {
732        Ok(file) => Ok(file),
733        Err(e) => match e.kind() {
734            std::io::ErrorKind::NotFound => Err(anyhow!("Could not find file: {}", path.display())),
735            std::io::ErrorKind::PermissionDenied => {
736                Err(anyhow!("No permission to read file: {}", path.display()))
737            }
738            std::io::ErrorKind::IsADirectory => {
739                Err(anyhow!("File is a directory: {}", path.display()))
740            }
741            _ => Err(anyhow!("Unexpected error for file: {}", path.display())),
742        },
743    }?;
744
745    // parse file to be included recursively
746    let token_iter = Token::lexer(&file).spanned().map(|(tok, span)| match tok {
747        Ok(tok) => (tok, span.into()),
748        Err(()) => (Token::Error, span.into()),
749    });
750    let token_stream =
751        Stream::from_iter(token_iter).map((0..file.len()).into(), |(t, s): (_, _)| (t, s));
752    match parser().parse(token_stream).into_result() {
753        Ok(sexpr) => {
754            let mut ast: Vec<StatementKindOwnedPass1> = Vec::new();
755            for expr in sexpr {
756                ast.push(expr.into());
757            }
758
759            let ast = do_pass1(
760                ast,
761                path.parent()
762                    .ok_or(anyhow!("Can not get parent directory of file."))?,
763            )?; // recursive call
764            return Ok(ast);
765        }
766        Err(errs) => {
767            for err in errs {
768                Report::build(ReportKind::Error, (), err.span().start)
769                    .with_code(3)
770                    .with_message(err.to_string())
771                    .with_label(
772                        Label::new(err.span().into_range())
773                            .with_message(err.reason().to_string())
774                            .with_color(Color::Red),
775                    )
776                    .finish()
777                    .eprint(Source::from(&file))
778                    .unwrap();
779            }
780        }
781    }
782
783    Err(anyhow!("Could not parse ratslang code."))
784}
785
786impl<'a> From<StatementKindPass1<'a>> for StatementKindOwnedPass1 {
787    fn from(value: StatementKindPass1<'a>) -> Self {
788        match value {
789            StatementKindPass1::VariableNamespaceBlock { ns, stmts } => {
790                StatementKindOwnedPass1::VariableNamespaceBlock {
791                    ns: ns.into_iter().map(String::from).collect::<Vec<_>>(),
792                    stmts: stmts
793                        .into_iter()
794                        .map(|bstmt| Box::new(StatementKindOwnedPass1::from(*bstmt)))
795                        .collect::<Vec<_>>(),
796                }
797            }
798            StatementKindPass1::Rule(rule) => StatementKindOwnedPass1::Rule(RuleOwned::from(rule)),
799            StatementKindPass1::VariableDef(statement) => {
800                StatementKindOwnedPass1::VariableDef(statement)
801            }
802            StatementKindPass1::Reset(path) => StatementKindOwnedPass1::Reset(path),
803            StatementKindPass1::SendFrames(kind) => StatementKindOwnedPass1::SendFrames(kind),
804            StatementKindPass1::Include { namespace, path } => {
805                StatementKindOwnedPass1::Include { namespace, path }
806            }
807            StatementKindPass1::Loop { count, stmts } => StatementKindOwnedPass1::Loop {
808                count,
809                stmts: stmts
810                    .into_iter()
811                    .map(|bstmt| Box::new(StatementKindOwnedPass1::from(*bstmt)))
812                    .collect::<Vec<_>>(),
813            },
814        }
815    }
816}
817
818// --- Coordinator Rules ---
819#[derive(Debug, Clone)]
820pub struct RuleSexpr {
821    pub rules: Vec<RuleOwned>,
822}
823
824#[derive(Debug, Clone)]
825pub struct Rule<'a> {
826    pub variable: &'a str,
827    pub stmts: Vec<Statement>,
828}
829
830#[derive(Debug, Clone)]
831pub struct RuleOwned {
832    pub variable: String,
833    pub stmts: Vec<Statement>,
834}
835
836impl<'a> From<Rule<'a>> for RuleOwned {
837    fn from(value: Rule<'a>) -> Self {
838        Self {
839            variable: value.variable.to_owned(),
840            stmts: value.stmts,
841        }
842    }
843}
844
845#[derive(Debug, Clone)]
846pub enum StatementPass1 {
847    AssignLeft {
848        lhs: Vec<Var>,
849        rhs: Rhs,
850    },
851    AssignRight {
852        lhs: Rhs,
853        rhs: Vec<Var>,
854    },
855    Compare {
856        rhs: Vec<Var>,
857        lhs: Vec<Var>,
858    },
859    Include {
860        namespace: Vec<String>,
861        path: String,
862    },
863}
864
865#[derive(Debug, Clone)]
866pub enum Statement {
867    AssignLeft { lhs: Vec<Var>, rhs: Rhs },
868    AssignRight { lhs: Rhs, rhs: Vec<Var> },
869    Compare { rhs: Vec<Var>, lhs: Vec<Var> },
870}
871
872impl Statement {
873    fn add_namespace(self, ns: &[String]) -> Self {
874        match self {
875            Statement::AssignLeft { lhs, rhs } => {
876                let nlhs = lhs
877                    .into_iter()
878                    .map(|v| v.add_namespace(ns))
879                    .collect::<Vec<_>>();
880                Statement::AssignLeft { lhs: nlhs, rhs }
881            }
882            Statement::AssignRight { lhs, rhs } => {
883                let nrhs = rhs
884                    .into_iter()
885                    .map(|v| v.add_namespace(ns))
886                    .collect::<Vec<_>>();
887                Statement::AssignRight { lhs, rhs: nrhs }
888            }
889            Statement::Compare { rhs, lhs } => Statement::Compare { rhs, lhs },
890        }
891    }
892}
893
894fn ast_add_namespace(ns: &[String], ast: Vec<StatementKindOwned>) -> Vec<StatementKindOwned> {
895    ast.into_iter()
896        .map(|stmt| match stmt {
897            StatementKindOwned::VariableDef(statement) => {
898                StatementKindOwned::VariableDef(statement.add_namespace(ns))
899            }
900            _ => stmt,
901        })
902        .collect()
903}
904
905#[derive(Clone, Copy, Debug)]
906pub enum Operator {
907    Right,   // "->"
908    Left,    // "<-"
909    Compare, // "=="
910}
911
912fn parser<'a, I>()
913-> impl Parser<'a, I, Vec<StatementKindPass1<'a>>, extra::Err<Rich<'a, Token<'a>>>>
914where
915    I: ValueInput<'a, Token = Token<'a>, Span = SimpleSpan>,
916{
917    let time = select! {
918        Token::IntegerNumberMillisecond(ms) => NumVal::Integer(ms),
919        Token::FloatingNumberMillisecond(ms) => NumVal::Floating(ms).integerize_unit_val(),
920    }
921    .labelled("time");
922
923    let way = select! {
924        Token::IntegerNumberMillimeter(millis) => NumVal::Integer(millis),
925        Token::FloatingNumberMillimeter(millis) => NumVal::Floating(millis).integerize_unit_val(),
926    }
927    .labelled("way");
928
929    let timerange = time
930        .or_not()
931        .then_ignore(just(Token::OpRange))
932        .then(time)
933        .try_map(|(from, to), span| {
934            Ok(Rhs::Range {
935                from: {
936                    if let Some(from) = from {
937                        Some(Val::UnitedVal(UnitVal {
938                            val: {
939                                match from {
940                                    NumVal::Floating(_) => unreachable!("integerised before"),
941                                    NumVal::Integer(i) => {
942                                        if i < 0 {
943                                            return Err(Rich::custom(
944                                                span,
945                                                "Negative Integer Number for Timespan.",
946                                            ));
947                                        } else {
948                                            i as u64
949                                        }
950                                    }
951                                }
952                            },
953                            unit: Unit::TimeMilliseconds,
954                        }))
955                    } else {
956                        None
957                    }
958                },
959                to: Some(Val::UnitedVal(UnitVal {
960                    val: match to {
961                        NumVal::Floating(_) => unreachable!("integerised before"),
962                        NumVal::Integer(i) => {
963                            if i < 0 {
964                                return Err(Rich::custom(
965                                    span,
966                                    "Negative Integer Number for Timespan.",
967                                ));
968                            } else {
969                                i as u64
970                            }
971                        }
972                    },
973                    unit: Unit::TimeMilliseconds,
974                })),
975            })
976        })
977        .labelled("time range");
978
979    let timerange_open_upper = time
980        .then_ignore(just(Token::OpRange))
981        .then_ignore(time.not())
982        .try_map(|from, span| {
983            Ok(Rhs::Range {
984                from: Some(Val::UnitedVal(UnitVal {
985                    val: match from {
986                        NumVal::Floating(_) => unreachable!("integerised before"),
987                        NumVal::Integer(i) => {
988                            if i < 0 {
989                                return Err(Rich::custom(
990                                    span,
991                                    "Negative Integer Number for Timespan.",
992                                ));
993                            } else {
994                                i as u64
995                            }
996                        }
997                    },
998                    unit: Unit::TimeMilliseconds,
999                })),
1000                to: None,
1001            })
1002        })
1003        .labelled("upper open time range");
1004
1005    let timerange_open = time
1006        .not()
1007        .then_ignore(just(Token::OpRange))
1008        .then_ignore(time.not())
1009        .map(|_| Rhs::Range {
1010            from: None,
1011            to: None,
1012        })
1013        .labelled("open not-time range");
1014
1015    let wayrange = way
1016        .then_ignore(just(Token::OpRange))
1017        .then(way)
1018        .try_map(|(from, to), span| {
1019            Ok(Rhs::Range {
1020                from: Some(Val::UnitedVal(UnitVal {
1021                    val: match from {
1022                        NumVal::Floating(_) => unreachable!("integerised before"),
1023                        NumVal::Integer(i) => {
1024                            if i < 0 {
1025                                return Err(Rich::custom(
1026                                    span,
1027                                    "Negative Integer Number for Wayspan.",
1028                                ));
1029                            } else {
1030                                i as u64
1031                            }
1032                        }
1033                    },
1034                    unit: Unit::WayMillimeter,
1035                })),
1036                to: Some(Val::UnitedVal(UnitVal {
1037                    val: match to {
1038                        NumVal::Floating(_) => unreachable!("integerised before"),
1039                        NumVal::Integer(i) => {
1040                            if i < 0 {
1041                                return Err(Rich::custom(
1042                                    span,
1043                                    "Negative Integer Number for Wayspan.",
1044                                ));
1045                            } else {
1046                                i as u64
1047                            }
1048                        }
1049                    },
1050                    unit: Unit::WayMillimeter,
1051                })),
1052            })
1053        })
1054        .labelled("way range");
1055
1056    let numvalue = select! {
1057            Token::IntegerNumber(i) => Rhs::Val(Val::NumVal(NumVal::Integer(i))),
1058            Token::FloatingNumber(f) => Rhs::Val(Val::NumVal(NumVal::Floating(f))),
1059    }
1060    .labelled("number value");
1061
1062    let value = select! {
1063            Token::IntegerNumber(i) => Rhs::Val(Val::NumVal(NumVal::Integer(i))),
1064            Token::FloatingNumber(f) => Rhs::Val(Val::NumVal(NumVal::Floating(f))),
1065            Token::String(s) => Rhs::Val(Val::StringVal(s.to_owned())),
1066            Token::True => Rhs::Val(Val::BoolVal(true)),
1067            Token::False => Rhs::Val(Val::BoolVal(false)),
1068    }
1069    .labelled("value");
1070
1071    let numberrange = numvalue
1072        .then_ignore(just(Token::OpRange))
1073        .then(value)
1074        .try_map(|(from, to), span| match (&from, &to) {
1075            (
1076                Rhs::Val(Val::NumVal(NumVal::Floating(_))),
1077                Rhs::Val(Val::NumVal(NumVal::Integer(_))),
1078            )
1079            | (
1080                Rhs::Val(Val::NumVal(NumVal::Integer(_))),
1081                Rhs::Val(Val::NumVal(NumVal::Floating(_))),
1082            ) => Err(Rich::custom(span, "Cannot span between float and integer.")),
1083            (_, _) => Ok((from, to)),
1084        })
1085        .map(|(from, to)| {
1086            let from = match from {
1087                Rhs::Val(Val::NumVal(nv)) => nv,
1088                _ => unreachable!(),
1089            };
1090            let to = match to {
1091                Rhs::Val(Val::NumVal(nv)) => nv,
1092                _ => unreachable!(),
1093            };
1094
1095            Rhs::Range {
1096                from: Some(Val::NumVal(from)),
1097                to: Some(Val::NumVal(to)),
1098            }
1099        })
1100        .labelled("number range");
1101
1102    let variable = select! {
1103            Token::VarNamespace(ns) => ns.to_owned(),
1104        }
1105        .repeated()
1106        .collect::<Vec<_>>()
1107        .then(select! {
1108                Token::Variable(var) => Rhs::Var(Var::User { name: var.to_owned(), namespace: vec![] }),
1109                Token::PredefVariable(var) => Rhs::Var(Var::Predef { name: var.to_owned(), namespace: vec![] }),
1110            })
1111        .map(|(ns, var)| {
1112                let var = match var {
1113                    Rhs::Var(var) => match var {
1114                        Var::User { name, namespace: _} => {
1115                            Var::User { name, namespace: ns }
1116                        },
1117                        Var::Predef { name, namespace: _ } => {
1118                            Var::Predef { name, namespace: ns }
1119                        },
1120                        _ => unreachable!(),
1121                    },
1122                    _ => unreachable!(),
1123                };
1124
1125                Rhs::Var(var)
1126            });
1127
1128    let term = select! {
1129        Token::KwLog => Rhs::Var(Var::Log), // TODO maybe not rhs that can be assigned
1130        Token::Path(p) => Rhs::Path(p.to_owned()),
1131    }
1132    .or(variable)
1133    .labelled("term");
1134
1135    let range = choice((numberrange, timerange.clone(), wayrange));
1136
1137    let rhs_array = recursive(|rhs_array| {
1138        choice((term, range.clone(), value, rhs_array))
1139            .separated_by(just(Token::Comma).then_ignore(just(Token::NewLine).repeated()))
1140            .at_least(1)
1141            .collect::<Vec<_>>()
1142            .delimited_by(just(Token::LParen), just(Token::RParen))
1143            .map(|arr: Vec<Rhs>| Rhs::Array(arr.into_iter().map(Box::new).collect::<Vec<_>>()))
1144    });
1145
1146    let rhs = choice((term, range, value, rhs_array));
1147
1148    // parse a comma-separated list of terms (the left-hand side).
1149    let comma = just(Token::Comma).then_ignore(just(Token::NewLine).repeated());
1150    let multi_rhs = rhs
1151        .clone()
1152        .separated_by(comma)
1153        .at_least(1)
1154        .collect::<Vec<_>>()
1155        .labelled("rule term");
1156
1157    let op = select! {
1158        Token::OpAssignToRight => Operator::Right,
1159        Token::OpAssignToLeft => Operator::Left,
1160        Token::OpCompare => Operator::Compare,
1161    }
1162    .labelled("operator");
1163
1164    // a statement is: lhs, then an operator, then a single term (the right-hand side).
1165    let statement = multi_rhs
1166        .clone()
1167        .then(op)
1168        .then(multi_rhs)
1169        .then_ignore(just(Token::NewLine).repeated())
1170        .try_map(|((lhs, op), rhs), span| {
1171            Ok(StatementKindPass1::VariableDef(match op {
1172                Operator::Right => {
1173                    if lhs.len() > 1 {
1174                        return Err(Rich::custom(
1175                            span,
1176                            "Can only assign one term but to multiple variables.",
1177                        ));
1178                    }
1179                    if let Some(lhs) = lhs.first() {
1180                        let mut vars: Vec<Var> = Vec::new();
1181                        for r in rhs.iter() {
1182                            match r {
1183                                Rhs::Var(var) => {
1184                                    vars.push(var.clone());
1185                                }
1186                                _ => {
1187                                    return Err(Rich::custom(
1188                                        span,
1189                                        "Can only assign to variables.",
1190                                    ));
1191                                }
1192                            }
1193                        }
1194
1195                        Statement::AssignRight {
1196                            lhs: lhs.clone(),
1197                            rhs: vars,
1198                        }
1199                    } else {
1200                        return Err(Rich::custom(span, "Missing left operand."));
1201                    }
1202                }
1203                Operator::Left => {
1204                    if rhs.len() > 1 {
1205                        return Err(Rich::custom(
1206                            span,
1207                            "Can only assign one term but to multiple variables.",
1208                        ));
1209                    }
1210                    if let Some(rhs) = rhs.first() {
1211                        let mut vars: Vec<Var> = Vec::new();
1212                        for l in lhs.iter() {
1213                            match l {
1214                                Rhs::Var(var) => {
1215                                    vars.push(var.clone());
1216                                }
1217                                _ => {
1218                                    return Err(Rich::custom(
1219                                        span,
1220                                        "Can only assign to variables.",
1221                                    ));
1222                                }
1223                            }
1224                        }
1225
1226                        Statement::AssignLeft {
1227                            lhs: vars,
1228                            rhs: rhs.clone(),
1229                        }
1230                    } else {
1231                        return Err(Rich::custom(span, "Missing right operand."));
1232                    }
1233                }
1234                Operator::Compare => {
1235                    let mut lvars: Vec<Var> = Vec::new();
1236                    for l in lhs.iter() {
1237                        match l {
1238                            Rhs::Var(var) => {
1239                                lvars.push(var.clone());
1240                            }
1241                            _ => {
1242                                return Err(Rich::custom(span, "Can only compare variables."));
1243                            }
1244                        }
1245                    }
1246                    let mut rvars: Vec<Var> = Vec::new();
1247                    for r in rhs.iter() {
1248                        match r {
1249                            Rhs::Var(var) => {
1250                                rvars.push(var.clone());
1251                            }
1252                            _ => {
1253                                return Err(Rich::custom(span, "Can only compare variables."));
1254                            }
1255                        }
1256                    }
1257
1258                    Statement::Compare {
1259                        rhs: rvars,
1260                        lhs: lvars,
1261                    }
1262                }
1263            }))
1264        })
1265        .labelled("statement");
1266
1267    let rule_header = just(Token::FnRule)
1268        .ignore_then(just(Token::BracketOpen))
1269        .ignore_then(select! { Token::Variable(v) => v }.labelled("rule name"))
1270        .then_ignore(just(Token::NewLine).or_not())
1271        .labelled("rule header");
1272
1273    let rule = rule_header
1274        .then_ignore(just(Token::NewLine).repeated())
1275        .then(statement.clone().repeated().collect())
1276        .then_ignore(just(Token::NewLine).repeated())
1277        .then_ignore(just(Token::BracketClose))
1278        .map(|(variable, stmts): (&str, Vec<StatementKindPass1>)| {
1279            let stmts = stmts
1280                .into_iter()
1281                .map(|stmtk| match stmtk {
1282                    StatementKindPass1::VariableDef(var) => var,
1283                    _ => unreachable!(),
1284                })
1285                .collect::<Vec<_>>();
1286            StatementKindPass1::Rule(Rule { variable, stmts })
1287        })
1288        .labelled("rule");
1289
1290    let wind_reset_fn = just(Token::FnReset)
1291        .ignore_then(
1292            select! {
1293                Token::Path(p) => p, // prefixed with /, resolve
1294                Token::Variable(v) =>  v, // not prefixed, so implicit ./
1295            }
1296            .labelled("bagfile"),
1297        )
1298        .map(|expr| StatementKindPass1::Reset(expr.to_owned()))
1299        .labelled("reset");
1300
1301    let str_only = select! {
1302            Token::String(s) => s.to_owned(),
1303    }
1304    .or(variable.try_map(|v, span| match v {
1305        Rhs::Var(Var::User {
1306            name,
1307            namespace: ns,
1308        }) => {
1309            if !ns.is_empty() {
1310                return Err(Rich::custom(span, "Found namespace in implicit string."));
1311            }
1312            Ok(name)
1313        }
1314        _ => Err(Rich::custom(span, "Expected implicit string.")),
1315    }));
1316    let str_array = str_only
1317        .separated_by(just(Token::Comma).then_ignore(just(Token::NewLine).repeated()))
1318        .at_least(1)
1319        .collect::<Vec<_>>()
1320        .delimited_by(just(Token::LParen), just(Token::RParen));
1321
1322    let str_only_as_vec = str_only.map(|single| vec![single]).labelled("string");
1323    let one_or_more_str = choice((str_only_as_vec, str_array)).labelled("at least one string");
1324    let playfn_with_conditions = just(Token::FnPlayFrames)
1325        .labelled("play_frames")
1326        .ignore_then(one_or_more_str.clone())
1327        .then((just(Token::Comma).ignore_then(one_or_more_str)).or_not())
1328        .map(
1329            |(play_sensors, stop_sensors): (Vec<String>, Option<Vec<String>>)| match stop_sensors {
1330                Some(stop_sensors) => PlayType::UntilSensorCount {
1331                    sending: play_sensors
1332                        .into_iter()
1333                        .map(|el| el.to_owned())
1334                        .collect::<Vec<_>>(),
1335                    until_sensors: stop_sensors
1336                        .into_iter()
1337                        .map(|el| el.to_owned())
1338                        .collect::<Vec<_>>(),
1339                },
1340                None => PlayType::SensorCount {
1341                    sensors: play_sensors
1342                        .into_iter()
1343                        .map(|el| el.to_owned())
1344                        .collect::<Vec<_>>(),
1345                },
1346            },
1347        );
1348
1349    let wind_play_frames_fn = playfn_with_conditions
1350        .boxed()
1351        .then(
1352            choice((
1353                timerange_open,
1354                timerange_open_upper,
1355                timerange.clone(),
1356                time.map(|t| {
1357                    Rhs::Val(Val::UnitedVal(UnitVal {
1358                        val: match t {
1359                            NumVal::Integer(i) => i as u64,
1360                            _ => unreachable!(),
1361                        },
1362                        unit: Unit::TimeMilliseconds,
1363                    }))
1364                }),
1365                select! {
1366                    Token::IntegerNumber(i) => Rhs::Val(Val::NumVal(NumVal::Integer(i))), // (until) number of frames
1367                },
1368            ))
1369            .labelled("int number for count, relative time from now or absolute timespan")
1370            .boxed(),
1371        )
1372        .then(
1373            choice((
1374                variable.try_map(|v, span| match v {
1375                    Rhs::Var(var) => match var {
1376                        Var::Log => Err(Rich::custom(span, "Can not trigger on Log.")),
1377                        Var::Predef {
1378                            name: _,
1379                            namespace: _,
1380                        } => Err(Rich::custom(
1381                            span,
1382                            "Did not expect a predef variable as a variable name.",
1383                        )),
1384                        Var::User { name, namespace } => {
1385                            if !namespace.is_empty() {
1386                                return Err(Rich::custom(
1387                                    span,
1388                                    "Rat names should not have a namespace.",
1389                                )); // TODO needs fix when using topics with namespaces
1390                            }
1391
1392                            Ok(Rhs::Var(Var::User {
1393                                name,
1394                                namespace: vec![],
1395                            }))
1396                        }
1397                    },
1398                    _ => unreachable!(),
1399                }),
1400                time.map(|t| {
1401                    Rhs::Val(Val::UnitedVal(UnitVal {
1402                        val: match t {
1403                            NumVal::Integer(i) => i as u64,
1404                            _ => unreachable!(),
1405                        },
1406                        unit: Unit::TimeMilliseconds,
1407                    }))
1408                }),
1409                select! {
1410                    Token::FloatingNumber(f) => Rhs::Val(Val::NumVal(NumVal::Floating(f))),
1411                },
1412            ))
1413            .boxed()
1414            .or_not()
1415            .labelled("trigger"),
1416        )
1417        .then(
1418            variable
1419                .try_map(|v, span| {
1420                    let errmsg = "Only f or d allowed. f for fixed, d for dynamic.";
1421                    match v {
1422                        Rhs::Var(var) => match var {
1423                            Var::Log => Err(Rich::custom(span, errmsg)),
1424                            Var::Predef { name, namespace } => {
1425                                if !namespace.is_empty() {
1426                                    Err(Rich::custom(span, errmsg))
1427                                } else {
1428                                    if name.as_str() != "f" && name.as_str() != "d" {
1429                                        return Err(Rich::custom(span, errmsg));
1430                                    }
1431
1432                                    Ok(name)
1433                                }
1434                            }
1435                            Var::User { name, namespace } => {
1436                                if !namespace.is_empty() {
1437                                    Err(Rich::custom(span, errmsg))
1438                                } else {
1439                                    if name.as_str() != "f" && name.as_str() != "d" {
1440                                        return Err(Rich::custom(span, errmsg));
1441                                    }
1442
1443                                    Ok(name)
1444                                }
1445                            }
1446                        },
1447                        _ => unreachable!(),
1448                    }
1449                })
1450                .labelled("play mode [f|d]. f = fixed, d = dynamic")
1451                .or_not(),
1452        )
1453        .map(
1454            #[allow(clippy::type_complexity)]
1455            |(((pt, arg), trigger), mode): (((PlayType, Rhs), Option<Rhs>), Option<String>)| {
1456                let trigger = trigger.map(|trigger| match trigger {
1457                    Rhs::Val(Val::UnitedVal(UnitVal {
1458                        val,
1459                        unit: Unit::TimeMilliseconds,
1460                    })) => PlayTrigger::DurationMs(val),
1461                    Rhs::Var(Var::User { name, namespace: _ }) => PlayTrigger::Variable(name),
1462                    Rhs::Val(Val::NumVal(NumVal::Floating(f))) => PlayTrigger::DurationRelFactor(f),
1463                    _ => unreachable!(),
1464                });
1465
1466                let play_mode = mode.map(|mode| match mode.as_str() {
1467                    "f" => PlayMode::Fix,
1468                    "d" => PlayMode::Dynamic,
1469                    _ => unreachable!(),
1470                });
1471                let default_play_mode = match trigger.as_ref() {
1472                    Some(PlayTrigger::Variable(_)) => PlayMode::Dynamic,
1473                    _ => PlayMode::Fix,
1474                };
1475                let play_mode = play_mode.unwrap_or(default_play_mode);
1476
1477                let pku = match pt {
1478                    PlayType::SensorCount { sensors } => match arg {
1479                        Rhs::Range {
1480                            from:
1481                                Some(Val::UnitedVal(UnitVal {
1482                                    val: from_val,
1483                                    unit: Unit::TimeMilliseconds,
1484                                })),
1485                            to:
1486                                Some(Val::UnitedVal(UnitVal {
1487                                    val: to_val,
1488                                    unit: Unit::TimeMilliseconds,
1489                                })),
1490                        } => PlayKindUnited::SensorCount {
1491                            sensors,
1492                            count: PlayCount::TimeRangeMs(AbsTimeRange::Closed((from_val, to_val))),
1493                            trigger,
1494                            play_mode,
1495                        },
1496                        Rhs::Range {
1497                            from: None,
1498                            to:
1499                                Some(Val::UnitedVal(UnitVal {
1500                                    val: to_val,
1501                                    unit: Unit::TimeMilliseconds,
1502                                })),
1503                        } => PlayKindUnited::SensorCount {
1504                            sensors,
1505                            count: PlayCount::TimeRangeMs(AbsTimeRange::LowerOpen(to_val)),
1506                            trigger,
1507                            play_mode,
1508                        },
1509                        Rhs::Range {
1510                            from:
1511                                Some(Val::UnitedVal(UnitVal {
1512                                    val: from_val,
1513                                    unit: Unit::TimeMilliseconds,
1514                                })),
1515                            to: None,
1516                        } => PlayKindUnited::SensorCount {
1517                            sensors,
1518                            count: PlayCount::TimeRangeMs(AbsTimeRange::UpperOpen(from_val)),
1519                            trigger,
1520                            play_mode,
1521                        },
1522                        Rhs::Range {
1523                            from: None,
1524                            to: None,
1525                        } => PlayKindUnited::SensorCount {
1526                            sensors,
1527                            count: PlayCount::TimeRangeMs(AbsTimeRange::Open),
1528                            trigger,
1529                            play_mode,
1530                        },
1531                        Rhs::Val(Val::NumVal(NumVal::Integer(i))) => PlayKindUnited::SensorCount {
1532                            sensors,
1533                            count: PlayCount::Amount(i as u64),
1534                            trigger,
1535                            play_mode,
1536                        },
1537                        Rhs::Val(Val::UnitedVal(UnitVal {
1538                            val: ms,
1539                            unit: Unit::TimeMilliseconds,
1540                        })) => PlayKindUnited::SensorCount {
1541                            sensors,
1542                            count: PlayCount::TimeRelativeMs(ms),
1543                            trigger,
1544                            play_mode,
1545                        },
1546                        _ => {
1547                            unreachable!()
1548                        }
1549                    },
1550                    PlayType::UntilSensorCount {
1551                        sending,
1552                        until_sensors,
1553                    } => match arg {
1554                        Rhs::Range {
1555                            from:
1556                                Some(Val::UnitedVal(UnitVal {
1557                                    val: from_val,
1558                                    unit: Unit::TimeMilliseconds,
1559                                })),
1560                            to:
1561                                Some(Val::UnitedVal(UnitVal {
1562                                    val: to_val,
1563                                    unit: Unit::TimeMilliseconds,
1564                                })),
1565                        } => PlayKindUnited::UntilSensorCount {
1566                            sending,
1567                            until_sensors,
1568                            until_count: PlayCount::TimeRangeMs(AbsTimeRange::Closed((
1569                                from_val, to_val,
1570                            ))),
1571                            trigger,
1572                            play_mode,
1573                        },
1574                        Rhs::Range {
1575                            from: None,
1576                            to:
1577                                Some(Val::UnitedVal(UnitVal {
1578                                    val: to_val,
1579                                    unit: Unit::TimeMilliseconds,
1580                                })),
1581                        } => PlayKindUnited::UntilSensorCount {
1582                            sending,
1583                            until_sensors,
1584                            until_count: PlayCount::TimeRangeMs(AbsTimeRange::LowerOpen(to_val)),
1585                            trigger,
1586                            play_mode,
1587                        },
1588                        Rhs::Range {
1589                            from:
1590                                Some(Val::UnitedVal(UnitVal {
1591                                    val: from_val,
1592                                    unit: Unit::TimeMilliseconds,
1593                                })),
1594                            to: None,
1595                        } => PlayKindUnited::UntilSensorCount {
1596                            sending,
1597                            until_sensors,
1598                            until_count: PlayCount::TimeRangeMs(AbsTimeRange::UpperOpen(from_val)),
1599                            trigger,
1600                            play_mode,
1601                        },
1602                        Rhs::Val(Val::NumVal(NumVal::Integer(i))) => {
1603                            PlayKindUnited::UntilSensorCount {
1604                                sending,
1605                                until_sensors,
1606                                until_count: PlayCount::Amount(i as u64),
1607                                trigger,
1608                                play_mode,
1609                            }
1610                        }
1611                        Rhs::Val(Val::UnitedVal(UnitVal {
1612                            val: ms,
1613                            unit: Unit::TimeMilliseconds,
1614                        })) => PlayKindUnited::UntilSensorCount {
1615                            sending,
1616                            until_sensors,
1617                            until_count: PlayCount::TimeRelativeMs(ms),
1618                            trigger,
1619                            play_mode,
1620                        },
1621                        _ => {
1622                            unreachable!()
1623                        }
1624                    },
1625                };
1626
1627                StatementKindPass1::SendFrames(pku)
1628            },
1629        )
1630        .labelled("play_frames");
1631
1632    let include = just(Token::OpAssignToLeft)
1633        .ignore_then(select! {
1634            Token::Path(p) => p.to_owned(),
1635        })
1636        .then_ignore(just(Token::NewLine))
1637        .map(|path| StatementKindPass1::Include {
1638            namespace: vec![],
1639            path,
1640        });
1641
1642    let namespace_block = recursive(|nsb| {
1643        select! {
1644            Token::VarNamespace(ns) => ns,
1645        }
1646        .repeated()
1647        .at_least(1)
1648        .collect()
1649        .then(
1650            choice((statement.clone(), include.clone(), nsb))
1651                .repeated()
1652                .collect::<Vec<_>>()
1653                .delimited_by(
1654                    just(Token::BlockStart).then_ignore(just(Token::NewLine).repeated()),
1655                    just(Token::BlockEnd).then_ignore(just(Token::NewLine).repeated()),
1656                ),
1657        )
1658        .map(|(ns, stmts): (Vec<&'_ str>, Vec<StatementKindPass1>)| {
1659            StatementKindPass1::VariableNamespaceBlock {
1660                ns,
1661                stmts: stmts.into_iter().map(Box::new).collect::<Vec<_>>(),
1662            }
1663        })
1664    });
1665
1666    let loop_stmt = recursive(|loop_stmt_rec| {
1667        just(Token::KwLoop)
1668            .ignore_then(select! {
1669                Token::IntegerNumber(n) => n as usize,
1670            })
1671            .then(
1672                choice((
1673                    statement.clone(),
1674                    wind_play_frames_fn.clone(),
1675                    wind_reset_fn.clone(),
1676                    rule.clone(),
1677                    namespace_block.clone(),
1678                    include.clone(),
1679                    loop_stmt_rec,
1680                ))
1681                .then_ignore(just(Token::NewLine).repeated())
1682                .repeated()
1683                .collect::<Vec<_>>()
1684                .delimited_by(
1685                    just(Token::BlockStart).then_ignore(just(Token::NewLine).repeated()),
1686                    just(Token::BlockEnd).then_ignore(just(Token::NewLine).repeated()),
1687                ),
1688            )
1689            .map(
1690                |(count, stmts): (usize, Vec<StatementKindPass1>)| StatementKindPass1::Loop {
1691                    count,
1692                    stmts: stmts.into_iter().map(Box::new).collect::<Vec<_>>(),
1693                },
1694            )
1695    });
1696
1697    let one_of_wind_fns = choice((
1698        statement,
1699        wind_play_frames_fn,
1700        wind_reset_fn,
1701        rule,
1702        namespace_block,
1703        loop_stmt,
1704        include,
1705    ));
1706    let newlines = just(Token::NewLine).repeated();
1707
1708    newlines
1709        .clone()
1710        .ignore_then((one_of_wind_fns.then_ignore(newlines)).repeated().collect())
1711        .then_ignore(end())
1712}
1713
1714impl RuleSexpr {
1715    fn eval(&self) -> anyhow::Result<Rules> {
1716        let mut rules = Rules::new();
1717        for rule in self.rules.iter() {
1718            for stmt in rule.stmts.iter() {
1719                match &stmt {
1720                    Statement::AssignLeft { lhs, rhs } => {
1721                        let plan = ActionPlan::Shoot {
1722                            target: lhs
1723                                .iter()
1724                                .map(|part| match part {
1725                                    Var::User { name, namespace: _ } => name.clone(),
1726                                    Var::Log => COMPARE_NODE_NAME.to_owned(),
1727                                    Var::Predef {
1728                                        name: _,
1729                                        namespace: _,
1730                                    } => unreachable!(),
1731                                })
1732                                .collect(),
1733                            id: rules.new_id(),
1734                        };
1735
1736                        let ship = match rhs {
1737                            Rhs::Var(var) => match var {
1738                                Var::User { name, namespace: _ } => name.clone(),
1739                                Var::Log => COMPARE_NODE_NAME.to_owned(),
1740                                Var::Predef {
1741                                    name: _,
1742                                    namespace: _,
1743                                } => unreachable!(),
1744                            },
1745                            _ => continue,
1746                        };
1747                        let varh = VariableHuman {
1748                            ship,
1749                            strategy: Some(plan.clone()),
1750                        };
1751                        rules.insert(rule.variable.to_owned(), vec![varh]);
1752                    }
1753                    Statement::AssignRight { lhs, rhs } => {
1754                        let plan = ActionPlan::Shoot {
1755                            target: rhs
1756                                .iter()
1757                                .map(|part| match part {
1758                                    Var::User { name, namespace: _ } => name.clone(),
1759                                    Var::Log => COMPARE_NODE_NAME.to_owned(),
1760                                    Var::Predef {
1761                                        name: _,
1762                                        namespace: _,
1763                                    } => unreachable!(),
1764                                })
1765                                .collect(),
1766                            id: rules.new_id(),
1767                        };
1768
1769                        let ship = match lhs {
1770                            Rhs::Var(var) => match var {
1771                                Var::User { name, namespace: _ } => name.clone(),
1772                                Var::Log => COMPARE_NODE_NAME.to_owned(),
1773                                Var::Predef {
1774                                    name: _,
1775                                    namespace: _,
1776                                } => unreachable!(),
1777                            },
1778                            _ => continue,
1779                        };
1780                        let varh = VariableHuman {
1781                            ship,
1782                            strategy: Some(plan.clone()),
1783                        };
1784                        rules.insert(rule.variable.to_owned(), vec![varh]);
1785                    }
1786                    Statement::Compare { rhs, lhs } => {
1787                        let plan = ActionPlan::Shoot {
1788                            target: vec![COMPARE_NODE_NAME.to_owned()],
1789                            id: rules.new_id(),
1790                        };
1791
1792                        let mut merged: Vec<String> = rhs
1793                            .iter()
1794                            .map(|var| match var {
1795                                Var::User { name, namespace: _ } => name.clone(),
1796                                Var::Log => COMPARE_NODE_NAME.to_owned(),
1797                                _ => unreachable!(),
1798                            })
1799                            .collect();
1800
1801                        merged.extend(lhs.iter().map(|var| match var {
1802                            Var::User { name, namespace: _ } => name.clone(),
1803                            Var::Log => COMPARE_NODE_NAME.to_owned(),
1804                            _ => unreachable!(),
1805                        }));
1806
1807                        merged.iter().for_each(|ex| {
1808                            let varh = VariableHuman {
1809                                ship: ex.clone(),
1810                                strategy: Some(plan.clone()),
1811                            };
1812                            rules.insert(rule.variable.to_owned(), vec![varh]);
1813                        });
1814                    }
1815                };
1816            }
1817        }
1818        Ok(rules)
1819    }
1820}
1821
1822pub fn compile_file(
1823    path: &std::path::Path,
1824    start_line: Option<usize>,
1825    end_line: Option<usize>,
1826) -> anyhow::Result<Evaluated> {
1827    compile_file_with_state(path, start_line, end_line, None, std::io::stderr(), true)
1828}
1829
1830pub fn compile_file_with_state(
1831    path: &std::path::Path,
1832    start_line: Option<usize>,
1833    end_line: Option<usize>,
1834    var_state: Option<HashMap<Var, Rhs>>,
1835    out: impl std::io::Write,
1836    rich_out: bool,
1837) -> anyhow::Result<Evaluated> {
1838    let file = std::fs::read_to_string(path);
1839    let file = match file {
1840        Ok(file) => Ok(file),
1841        Err(e) => match e.kind() {
1842            std::io::ErrorKind::NotFound => Err(anyhow!("Could not find file: {}", path.display())),
1843            std::io::ErrorKind::PermissionDenied => {
1844                Err(anyhow!("No permission to read file: {}", path.display()))
1845            }
1846            std::io::ErrorKind::IsADirectory => {
1847                Err(anyhow!("File is a directory: {}", path.display()))
1848            }
1849            _ => Err(anyhow!("Unexpected error for file: {}", path.display())),
1850        },
1851    }?;
1852    let start_line = start_line.map(|l| l.saturating_sub(1)).unwrap_or_default();
1853    let lines = file.lines();
1854    let end_line = end_line.unwrap_or(lines.clone().count()).saturating_sub(1);
1855    let selected_lines = lines
1856        .skip(start_line)
1857        .take(end_line + 1 - start_line)
1858        .collect::<Vec<_>>()
1859        .join("\n")
1860        + "\n"; // append newline as funny hack to fix one-line problems
1861
1862    let dir = path.parent().ok_or(anyhow!(
1863        "Could not get parent directory of source code file."
1864    ))?;
1865    compile_code_with_state(&selected_lines, dir, var_state, out, rich_out)
1866}
1867
1868#[derive(Debug)]
1869pub struct VariableHistory {
1870    ast: Vec<StatementKindOwned>,
1871    pub var_cache: HashMap<Var, Rhs>,
1872}
1873
1874fn is_sub_namespace(sub: &[String], super_namespace: &[String]) -> bool {
1875    if sub.len() > super_namespace.len() {
1876        return false;
1877    }
1878
1879    if sub.is_empty() {
1880        return false; // Empty is not a sub-namespace
1881    }
1882
1883    if super_namespace.is_empty() {
1884        return false;
1885    }
1886
1887    for i in 0..sub.len() {
1888        if sub[i] != super_namespace[i] {
1889            return false;
1890        }
1891    }
1892
1893    true
1894}
1895
1896fn remove_prefix_from_target(prefix_definer: &[String], target: &[String]) -> Vec<String> {
1897    let prefix_len = prefix_definer.len();
1898    let target_len = target.len();
1899    let compare_len = std::cmp::min(prefix_len, target_len);
1900
1901    let mut common_prefix_len = 0;
1902    for i in 0..compare_len {
1903        if prefix_definer[i] == target[i] {
1904            common_prefix_len += 1;
1905        } else {
1906            break;
1907        }
1908    }
1909
1910    target[common_prefix_len..].to_vec()
1911}
1912
1913fn truncate_namespace_var(ns: &[String], var: &Var) -> Var {
1914    match var {
1915        Var::User { name, namespace } => Var::User {
1916            name: name.clone(),
1917            namespace: { remove_prefix_from_target(ns, namespace) },
1918        },
1919        Var::Log => Var::Log,
1920        Var::Predef { name, namespace } => Var::Predef {
1921            name: name.clone(),
1922            namespace: { remove_prefix_from_target(ns, namespace) },
1923        },
1924    }
1925}
1926
1927fn truncate_namespace_rhs(ns: &[String], rhs: &Rhs) -> Rhs {
1928    match rhs {
1929        Rhs::Array(items) => Rhs::Array(
1930            items
1931                .iter()
1932                .map(|arr_item| Box::new(truncate_namespace_rhs(ns, arr_item)))
1933                .collect::<Vec<_>>(),
1934        ),
1935        Rhs::Range { from: _, to: _ } => rhs.clone(),
1936        Rhs::Var(var) => Rhs::Var(truncate_namespace_var(ns, var)),
1937        Rhs::Path(_) => rhs.clone(),
1938        Rhs::Val(_) => rhs.clone(),
1939    }
1940}
1941
1942fn truncate_namespace_stmt(ns: &[String], stmt: &Statement) -> Statement {
1943    match stmt {
1944        Statement::AssignLeft { lhs, rhs } => {
1945            let l = lhs
1946                .iter()
1947                .filter(|v| match v {
1948                    Var::Log => false,
1949                    Var::Predef {
1950                        name: _,
1951                        namespace: var_ns,
1952                    } => is_sub_namespace(ns, var_ns),
1953                    Var::User {
1954                        name: _,
1955                        namespace: var_ns,
1956                    } => is_sub_namespace(ns, var_ns),
1957                })
1958                .map(|l| truncate_namespace_var(ns, l))
1959                .collect::<Vec<_>>();
1960            let r = truncate_namespace_rhs(ns, rhs);
1961
1962            Statement::AssignLeft { lhs: l, rhs: r }
1963        }
1964        Statement::AssignRight { lhs, rhs } => {
1965            let r = rhs
1966                .iter()
1967                .filter(|v| match v {
1968                    Var::Log => false,
1969                    Var::Predef {
1970                        name: _,
1971                        namespace: var_ns,
1972                    } => is_sub_namespace(ns, var_ns),
1973                    Var::User {
1974                        name: _,
1975                        namespace: var_ns,
1976                    } => is_sub_namespace(ns, var_ns),
1977                })
1978                .map(|l| truncate_namespace_var(ns, l))
1979                .collect::<Vec<_>>();
1980            let l = truncate_namespace_rhs(ns, lhs);
1981
1982            Statement::AssignRight { lhs: l, rhs: r }
1983        }
1984        Statement::Compare { rhs, lhs } => Statement::Compare {
1985            rhs: rhs.to_vec(),
1986            lhs: lhs.to_vec(),
1987        },
1988    }
1989}
1990
1991fn truncate_namespace_rule(ns: &[String], rule: &RuleOwned) -> RuleOwned {
1992    let stmts = rule
1993        .stmts
1994        .iter()
1995        .map(|stmt| truncate_namespace_stmt(ns, stmt))
1996        .collect::<Vec<_>>();
1997    RuleOwned {
1998        variable: rule.variable.clone(),
1999        stmts,
2000    }
2001}
2002
2003fn truncate_namespace(ns: &[String], stmt: &StatementKindOwned) -> StatementKindOwned {
2004    match stmt {
2005        StatementKindOwned::Rule(rule_owned) => {
2006            StatementKindOwned::Rule(truncate_namespace_rule(ns, rule_owned))
2007        }
2008        StatementKindOwned::VariableDef(statement) => {
2009            StatementKindOwned::VariableDef(truncate_namespace_stmt(ns, statement))
2010        }
2011        StatementKindOwned::Reset(path) => StatementKindOwned::Reset(path.clone()),
2012        StatementKindOwned::SendFrames(kind) => StatementKindOwned::SendFrames(kind.clone()),
2013    }
2014}
2015
2016fn stmt_in_ns(namespace: &[String], stmt: &Statement) -> bool {
2017    match stmt {
2018        Statement::AssignLeft { lhs, rhs: _ } => lhs.iter().any(|r| match r {
2019            Var::Log => false,
2020            Var::Predef {
2021                name: _,
2022                namespace: var_ns,
2023            } => is_sub_namespace(namespace, var_ns),
2024            Var::User {
2025                name: _,
2026                namespace: var_ns,
2027            } => is_sub_namespace(namespace, var_ns),
2028        }),
2029        Statement::AssignRight { lhs: _, rhs } => rhs.iter().any(|r| match r {
2030            Var::Log => false,
2031            Var::Predef {
2032                name: _,
2033                namespace: var_ns,
2034            } => is_sub_namespace(namespace, var_ns),
2035            Var::User {
2036                name: _,
2037                namespace: var_ns,
2038            } => is_sub_namespace(namespace, var_ns),
2039        }),
2040
2041        Statement::Compare { rhs: _, lhs: _ } => false,
2042    }
2043}
2044
2045impl VariableHistory {
2046    pub fn new(ast: Vec<StatementKindOwned>) -> Self {
2047        VariableHistory {
2048            ast,
2049            var_cache: HashMap::new(),
2050        }
2051    }
2052
2053    pub fn with_state(mut self, state: HashMap<Var, Rhs>) -> Self {
2054        self.var_cache = state;
2055        self
2056    }
2057
2058    pub fn populate_cache(&mut self) {
2059        self.ast.iter().for_each(|f| {
2060            if let StatementKindOwned::VariableDef(statement) = f {
2061                match statement {
2062                    Statement::AssignLeft { lhs, rhs } => {
2063                        for l in lhs {
2064                            self.var_cache.insert(l.clone(), rhs.clone());
2065                        }
2066                    }
2067                    Statement::AssignRight { lhs, rhs } => {
2068                        for r in rhs {
2069                            self.var_cache.insert(r.clone(), lhs.clone());
2070                        }
2071                    }
2072                    Statement::Compare { rhs: _, lhs: _ } => {}
2073                }
2074            }
2075        });
2076    }
2077
2078    fn filter_by_namespace(
2079        &self,
2080        namespace: &[String],
2081        up_to: Option<usize>,
2082        trunc_ns: bool,
2083    ) -> Vec<StatementKindOwned> {
2084        let mut vars_in_ns = vec![];
2085
2086        // use previous cached vars as well
2087        for (var, rhs) in self.var_cache.iter() {
2088            let mut wvar = var.clone();
2089            if is_sub_namespace(
2090                namespace,
2091                match var {
2092                    Var::Log => unreachable!(),
2093                    Var::Predef { name: _, namespace } => namespace,
2094                    Var::User { name: _, namespace } => namespace,
2095                },
2096            ) {
2097                if trunc_ns {
2098                    wvar = truncate_namespace_var(namespace, &wvar);
2099                }
2100
2101                vars_in_ns.push(StatementKindOwned::VariableDef(Statement::AssignLeft {
2102                    lhs: vec![wvar],
2103                    rhs: rhs.clone(),
2104                }));
2105            }
2106        }
2107
2108        for stmt in self.ast.iter().take(up_to.unwrap_or(usize::MAX)) {
2109            match &stmt {
2110                StatementKindOwned::Rule(rule_owned) => {
2111                    let filtered_rules = rule_owned
2112                        .stmts
2113                        .iter()
2114                        .filter(|stmt| stmt_in_ns(namespace, stmt))
2115                        .map(|s| {
2116                            if trunc_ns {
2117                                truncate_namespace_stmt(namespace, s)
2118                            } else {
2119                                s.clone()
2120                            }
2121                        })
2122                        .collect::<Vec<_>>();
2123
2124                    if !filtered_rules.is_empty() {
2125                        let rule = RuleOwned {
2126                            variable: rule_owned.variable.clone(),
2127                            stmts: filtered_rules,
2128                        };
2129                        vars_in_ns.push(StatementKindOwned::Rule(rule));
2130                    }
2131                }
2132                StatementKindOwned::VariableDef(rstmt) => {
2133                    if stmt_in_ns(namespace, rstmt) {
2134                        let rhs = if trunc_ns {
2135                            truncate_namespace(namespace, stmt)
2136                        } else {
2137                            stmt.clone()
2138                        };
2139                        vars_in_ns.push(rhs);
2140                    }
2141                }
2142                StatementKindOwned::Reset(_) => {}
2143                StatementKindOwned::SendFrames(_) => {}
2144            }
2145        }
2146
2147        vars_in_ns
2148    }
2149
2150    fn resolve_recursive(&self, var: &Var, up_to: Option<usize>) -> anyhow::Result<Option<Rhs>> {
2151        // use previous state if already resolved there
2152        if let Some(cache_hit) = self.var_cache.get(var) {
2153            return Ok(Some(cache_hit.clone()));
2154        }
2155
2156        let mut val = None;
2157        for (i, stmt) in self
2158            .ast
2159            .iter()
2160            .enumerate()
2161            .take(up_to.unwrap_or(usize::MAX))
2162        {
2163            match stmt {
2164                StatementKindOwned::Rule(rule) => {
2165                    for rstmt in rule.stmts.iter() {
2166                        match rstmt {
2167                            Statement::AssignLeft { lhs, rhs } => {
2168                                if lhs.contains(var) {
2169                                    val = Some(match rhs {
2170                                        Rhs::Var(var) => {
2171                                            match self.resolve_recursive(var, Some(i))? {
2172                                                None => Rhs::Val(Val::StringVal(match var {
2173                                                    Var::User { name, namespace: _ } => {
2174                                                        name.clone()
2175                                                    }
2176                                                    Var::Log => {
2177                                                        return Err(anyhow!(
2178                                                            "Log can not be assigned."
2179                                                        ));
2180                                                    }
2181                                                    Var::Predef {
2182                                                        name: _,
2183                                                        namespace: _,
2184                                                    } => {
2185                                                        return Err(anyhow!(
2186                                                            "Predef variables can not be assigned."
2187                                                        ));
2188                                                    }
2189                                                })),
2190                                                Some(rhs) => rhs,
2191                                            }
2192                                        }
2193                                        _ => rhs.clone(),
2194                                    });
2195                                }
2196                            }
2197                            Statement::AssignRight { lhs, rhs } => {
2198                                if rhs.contains(var) {
2199                                    val = Some(match lhs {
2200                                        Rhs::Var(var) => {
2201                                            match self.resolve_recursive(var, Some(i))? {
2202                                                None => Rhs::Val(Val::StringVal(match var {
2203                                                    Var::User { name, namespace: _ } => {
2204                                                        name.clone()
2205                                                    }
2206                                                    Var::Log => {
2207                                                        return Err(anyhow!(
2208                                                            "Log can not be assigned."
2209                                                        ));
2210                                                    }
2211                                                    Var::Predef {
2212                                                        name: _,
2213                                                        namespace: _,
2214                                                    } => {
2215                                                        return Err(anyhow!(
2216                                                            "Predef variables can not be assigned."
2217                                                        ));
2218                                                    }
2219                                                })),
2220                                                Some(lhs) => lhs,
2221                                            }
2222                                        }
2223                                        _ => lhs.clone(),
2224                                    });
2225                                }
2226                            }
2227                            Statement::Compare { rhs: _, lhs: _ } => {}
2228                        }
2229                    }
2230                }
2231                StatementKindOwned::VariableDef(statement) => match statement {
2232                    Statement::AssignLeft { lhs, rhs } => {
2233                        if lhs.contains(var) {
2234                            val = Some(match rhs {
2235                                Rhs::Var(var) => match self.resolve_recursive(var, Some(i))? {
2236                                    None => Rhs::Val(Val::StringVal(match var {
2237                                        Var::User { name, namespace: _ } => name.clone(),
2238                                        Var::Log => {
2239                                            return Err(anyhow!("Log can not be assigned."));
2240                                        }
2241                                        Var::Predef {
2242                                            name: _,
2243                                            namespace: _,
2244                                        } => {
2245                                            return Err(anyhow!(
2246                                                "Predef variables can not be assigned."
2247                                            ));
2248                                        }
2249                                    })),
2250                                    Some(rhs) => rhs,
2251                                },
2252                                _ => rhs.clone(),
2253                            });
2254                        }
2255                    }
2256                    Statement::AssignRight { lhs, rhs } => {
2257                        if rhs.contains(var) {
2258                            val = Some(match lhs {
2259                                Rhs::Var(var) => match self.resolve_recursive(var, Some(i))? {
2260                                    None => Rhs::Val(Val::StringVal(match var {
2261                                        Var::User { name, namespace: _ } => name.clone(),
2262                                        Var::Log => {
2263                                            return Err(anyhow!("Log can not be assigned."));
2264                                        }
2265                                        Var::Predef {
2266                                            name: _,
2267                                            namespace: _,
2268                                        } => {
2269                                            return Err(anyhow!(
2270                                                "Predef variables can not be assigned."
2271                                            ));
2272                                        }
2273                                    })),
2274                                    Some(lhs) => lhs,
2275                                },
2276                                _ => lhs.clone(),
2277                            });
2278                        }
2279                    }
2280                    Statement::Compare { rhs: _, lhs: _ } => {}
2281                },
2282                StatementKindOwned::Reset(_) => {}
2283                StatementKindOwned::SendFrames(_) => {}
2284            }
2285        }
2286        Ok(val)
2287    }
2288
2289    fn prepend_ns(var: &Var, ns: &[String]) -> Var {
2290        match var {
2291            Var::Log => Var::Log,
2292            Var::Predef {
2293                name,
2294                namespace: var_ns,
2295            } => {
2296                let v = vec_prepend(ns, var_ns);
2297
2298                Var::Predef {
2299                    name: name.clone(),
2300                    namespace: v,
2301                }
2302            }
2303            Var::User {
2304                name,
2305                namespace: var_ns,
2306            } => {
2307                let v = vec_prepend(ns, var_ns);
2308
2309                Var::User {
2310                    name: name.clone(),
2311                    namespace: v,
2312                }
2313            }
2314        }
2315    }
2316
2317    pub fn resolve_ns(&self, namespace: &[&str]) -> Vec<(Var, Rhs)> {
2318        let owned_ns = namespace
2319            .iter()
2320            .map(|s| (*s).to_owned())
2321            .collect::<Vec<_>>();
2322        self.filter_by_namespace(&owned_ns, None, true)
2323            .iter()
2324            .flat_map(|stmt| match stmt {
2325                StatementKindOwned::Rule(rule_owned) => rule_owned
2326                    .stmts
2327                    .iter()
2328                    .flat_map(|st| match st {
2329                        Statement::AssignLeft { lhs, rhs: _ } => Some(
2330                            lhs.iter()
2331                                .map(|lh| {
2332                                    (
2333                                        lh,
2334                                        self.resolve_var(&Self::prepend_ns(lh, &owned_ns))
2335                                            .expect("Should have failed in Pass 2"),
2336                                    )
2337                                })
2338                                .collect::<Vec<_>>(),
2339                        ),
2340                        Statement::AssignRight { lhs: _, rhs } => Some(
2341                            rhs.iter()
2342                                .map(|lh| {
2343                                    (
2344                                        lh,
2345                                        self.resolve_var(&Self::prepend_ns(lh, &owned_ns))
2346                                            .expect("Should have failed in Pass 2"),
2347                                    )
2348                                })
2349                                .collect::<Vec<_>>(),
2350                        ),
2351                        Statement::Compare { rhs: _, lhs: _ } => None,
2352                    })
2353                    .flatten()
2354                    .collect::<Vec<_>>(),
2355                StatementKindOwned::VariableDef(statement) => match statement {
2356                    Statement::AssignLeft { lhs, rhs: _ } => lhs
2357                        .iter()
2358                        .map(|lh| {
2359                            (
2360                                lh,
2361                                self.resolve_var(&Self::prepend_ns(lh, &owned_ns))
2362                                    .expect("Should have failed in Pass 2"),
2363                            )
2364                        })
2365                        .collect::<Vec<_>>(),
2366
2367                    Statement::AssignRight { lhs: _, rhs } => rhs
2368                        .iter()
2369                        .map(|lh| {
2370                            (
2371                                lh,
2372                                self.resolve_var(&Self::prepend_ns(lh, &owned_ns))
2373                                    .expect("Should have failed in Pass 2"),
2374                            )
2375                        })
2376                        .collect::<Vec<_>>(),
2377
2378                    Statement::Compare { rhs: _, lhs: _ } => vec![],
2379                },
2380                StatementKindOwned::Reset(_) => vec![],
2381                StatementKindOwned::SendFrames(_) => vec![],
2382            })
2383            .fold(Vec::new(), |mut acc, res| match res {
2384                (var, Some(rhs)) => {
2385                    acc.push((truncate_namespace_var(&owned_ns, var), rhs));
2386                    acc
2387                }
2388                (_, None) => acc, // skip if not set to anything
2389            })
2390    }
2391
2392    pub fn filter_ns(&self, namespace: &[&str]) -> Self {
2393        let owned_ns = namespace
2394            .iter()
2395            .map(|s| (*s).to_owned())
2396            .collect::<Vec<_>>();
2397        let filtered = self.filter_by_namespace(&owned_ns, None, true);
2398        Self::new(filtered)
2399    }
2400
2401    pub fn resolve(&self, var: &str) -> anyhow::Result<Option<Rhs>> {
2402        self.resolve_var(&Var::from_str(var)?)
2403    }
2404
2405    fn resolve_var(&self, var: &Var) -> anyhow::Result<Option<Rhs>> {
2406        self.resolve_recursive(var, None)
2407    }
2408}
2409
2410fn resolve_rhs_recursive(
2411    rhs: &mut Rhs,
2412    var_history: &VariableHistory,
2413    i: usize,
2414) -> anyhow::Result<()> {
2415    match rhs {
2416        Rhs::Array(items) => {
2417            for rhs_item in items.iter_mut() {
2418                resolve_rhs_recursive(&mut *rhs_item, var_history, i)?;
2419            }
2420        }
2421        Rhs::Var(var) => {
2422            // implicit strings when mentioned but not found in context earlier
2423            *rhs = match var_history.resolve_recursive(var, Some(i))? {
2424                None => Rhs::Val(Val::StringVal(match var {
2425                    Var::User { name, namespace: _ } => name.clone(),
2426                    Var::Log => {
2427                        return Err(anyhow!("Log can not be assigned."));
2428                    }
2429                    Var::Predef {
2430                        name: _,
2431                        namespace: _,
2432                    } => {
2433                        return Err(anyhow!("Predef variables can not be assigned."));
2434                    }
2435                })),
2436                Some(rhs) => rhs,
2437            };
2438        }
2439        _ => {}
2440    };
2441
2442    Ok(())
2443}
2444
2445fn resolve_stmt(
2446    stmt: &mut Statement,
2447    var_history: &VariableHistory,
2448    i: usize,
2449) -> anyhow::Result<()> {
2450    match stmt {
2451        Statement::AssignLeft { lhs: _, rhs } => {
2452            resolve_rhs_recursive(rhs, var_history, i)?;
2453        }
2454        Statement::AssignRight { lhs, rhs: _ } => {
2455            resolve_rhs_recursive(lhs, var_history, i)?;
2456        }
2457        Statement::Compare { rhs: _, lhs: _ } => {} // keep compare since only applicable to rules that are parsed as variables
2458    }
2459
2460    Ok(())
2461}
2462
2463pub fn compile_code(source_code_raw: &str) -> anyhow::Result<Evaluated> {
2464    let currdir = std::env::current_dir()?;
2465    compile_code_with_state(
2466        &(source_code_raw.to_owned() + "\n"), // hack to fix one-line token problems
2467        &currdir,
2468        None,
2469        std::io::stderr(),
2470        true,
2471    )
2472}
2473
2474fn resolve_struct_in_ns(user_ns: &[(Var, Rhs)], var: &str) -> Option<AnySensor> {
2475    // var is the first namespace for the vars, so gather all and find _name, _type and _short in them.
2476    let name = var.to_owned();
2477    let mut short = None;
2478    let mut topic: Option<String> = None;
2479    let mut msg_type = None;
2480    let mut short_lookup: HashMap<String, String> = HashMap::new();
2481
2482    for (v, rhs) in user_ns.iter() {
2483        if let Var::Predef { name, namespace } = v {
2484            if (*name).as_str() == "short" {
2485                let val = match rhs {
2486                    Rhs::Val(Val::StringVal(s)) => s.clone(),
2487                    _ => {
2488                        return None;
2489                    }
2490                };
2491                short_lookup.insert(val, namespace.first()?.clone());
2492            }
2493        }
2494    }
2495    for (v, rhs) in user_ns.iter() {
2496        match v {
2497            Var::Log => {}
2498            Var::Predef {
2499                name: predef_var_name,
2500                namespace,
2501            } => {
2502                let found_by_name = namespace
2503                    .first()
2504                    .map(|s| {
2505                        let long_name = (*s).as_str() == var;
2506                        if long_name {
2507                            return true;
2508                        }
2509                        let found_by_short = short_lookup.get(var);
2510                        if let Some(short_name) = found_by_short {
2511                            (*short_name).as_str() == (*s).as_str()
2512                        } else {
2513                            false
2514                        }
2515                    })
2516                    .unwrap_or_default();
2517
2518                if !found_by_name {
2519                    continue;
2520                }
2521
2522                match predef_var_name.as_str() {
2523                    "short" => match rhs {
2524                        Rhs::Val(Val::StringVal(s)) => {
2525                            short = Some((*s).clone());
2526                        }
2527                        _ => {
2528                            return None;
2529                        }
2530                    },
2531                    "topic" => match rhs {
2532                        Rhs::Val(Val::StringVal(s)) | Rhs::Path(s) => {
2533                            topic = Some((*s).clone());
2534                        }
2535                        _ => {
2536                            return None;
2537                        }
2538                    },
2539                    "type" => match rhs {
2540                        Rhs::Val(Val::StringVal(s)) => {
2541                            let typed = SensorType::from_str(s.as_str())
2542                                .expect("No error in impl, falls back to any");
2543                            msg_type = Some(typed);
2544                        }
2545                        _ => {
2546                            return None;
2547                        }
2548                    },
2549                    _ => {}
2550                }
2551            }
2552            Var::User {
2553                name: _,
2554                namespace: _,
2555            } => {}
2556        }
2557    }
2558
2559    let id = match (topic, msg_type) {
2560        (Some(t), None) => SensorIdentification::Topic(t),
2561        (None, Some(t)) => SensorIdentification::Type(t),
2562        (Some(topic), Some(msg_type)) => SensorIdentification::TopicAndType { topic, msg_type },
2563        _ => {
2564            return None;
2565        }
2566    };
2567
2568    Some(AnySensor { name, id, short })
2569}
2570
2571fn resolve_sensors(user_ns: &[(Var, Rhs)], sensors: &[String]) -> anyhow::Result<Vec<AnySensor>> {
2572    let mut mapped = vec![];
2573    for sensor in sensors {
2574        let any = resolve_struct_in_ns(user_ns, sensor)
2575            .ok_or(anyhow!("Could not find sensor: {}", &sensor))?;
2576        mapped.push(any);
2577    }
2578    Ok(mapped)
2579}
2580
2581pub fn compile_code_with_state(
2582    source_code_raw: &str,
2583    source_code_parent_dir: &std::path::Path,
2584    var_state: Option<HashMap<Var, Rhs>>,
2585    mut out: impl std::io::Write,
2586    rich_out: bool,
2587) -> anyhow::Result<Evaluated> {
2588    let token_iter = Token::lexer(source_code_raw)
2589        .spanned()
2590        // Convert logos errors into tokens. We want parsing to be recoverable and not fail at the lexing stage, so
2591        // we have a dedicated `Token::Error` variant that represents a token error that was previously encountered
2592        .map(|(tok, span)| match tok {
2593            // Turn the `Range<usize>` spans logos gives us into chumsky's `SimpleSpan` via `Into`, because it's easier
2594            // to work with
2595            Ok(tok) => (tok, span.into()),
2596            Err(()) => (Token::Error, span.into()),
2597        });
2598
2599    // Turn the token iterator into a stream that chumsky can use for things like backtracking
2600    let token_stream = Stream::from_iter(token_iter)
2601        // Tell chumsky to split the (Token, SimpleSpan) stream into its parts so that it can handle the spans for us
2602        // This involves giving chumsky an 'end of input' span: we just use a zero-width span at the end of the string
2603        .map((0..source_code_raw.len()).into(), |(t, s): (_, _)| (t, s));
2604
2605    // Parse the token stream with our chumsky parser
2606    match parser().parse(token_stream).into_result() {
2607        Ok(sexpr) => {
2608            let owned = sexpr
2609                .into_iter()
2610                .map(|kind| kind.into())
2611                .collect::<Vec<StatementKindOwnedPass1>>();
2612
2613            // Pass 1 -- parsing included files and expanding namespaces
2614            let mut ast = do_pass1(owned, source_code_parent_dir)?; // could print parse errors from included files
2615
2616            let mut rules = Vec::new();
2617            let mut winds = Vec::new();
2618            // let mut ast: Vec<StatementKindOwnedPass1> = Vec::new();
2619            for expr in &ast {
2620                // clone for ease of use, but normally just use AST
2621                match expr {
2622                    StatementKindOwned::Rule(rule) => {
2623                        rules.push(rule.clone());
2624                    }
2625                    StatementKindOwned::Reset(_) => winds.push(expr.clone()),
2626                    StatementKindOwned::SendFrames(_) => winds.push(expr.clone()),
2627                    StatementKindOwned::VariableDef(_) => {}
2628                }
2629                // ast.push(expr.into());
2630            }
2631            let rules = RuleSexpr { rules };
2632            let rules = rules.eval()?;
2633
2634            // Pass 2 -- needs entire ast for resolving. TODO could still be combined to Pass 1 with a subset of the ast to t-1.
2635            // Resolve all variables here, else implicit strings in nested assigns are handled as variables.
2636            // Use the repl state in case the user already run some variables from before which we want to build upon
2637            let var_history =
2638                VariableHistory::new(ast.clone()).with_state(var_state.clone().unwrap_or_default());
2639            for (i, node) in ast.iter_mut().enumerate() {
2640                match node {
2641                    StatementKindOwned::Rule(rule_owned) => {
2642                        for stmt in rule_owned.stmts.iter_mut() {
2643                            resolve_stmt(stmt, &var_history, i)?;
2644                        }
2645                    }
2646                    StatementKindOwned::VariableDef(statement) => {
2647                        resolve_stmt(statement, &var_history, i)?;
2648                    }
2649                    StatementKindOwned::Reset(_) => {}
2650                    StatementKindOwned::SendFrames(_) => {}
2651                }
2652            }
2653
2654            // Ext. Pass 3 -- resolve the wind fns to anysensor to check if short or long form etc.
2655            let vars = VariableHistory::new(ast.clone()).with_state(var_state.unwrap_or_default());
2656            let bag_ns = vars.resolve_ns(&["_bag"]);
2657            let mut wind = Vec::new();
2658            for node in ast.into_iter() {
2659                match node {
2660                    StatementKindOwned::SendFrames(sf) => match sf {
2661                        PlayKindUnited::SensorCount {
2662                            sensors,
2663                            count,
2664                            trigger,
2665                            play_mode,
2666                        } => {
2667                            let sensors = resolve_sensors(&bag_ns, &sensors)?;
2668                            wind.push(WindFunction::SendFrames(PlayKindUnitedPass3::SensorCount {
2669                                sensors,
2670                                count,
2671                                trigger,
2672                                play_mode,
2673                            }));
2674                        }
2675                        PlayKindUnited::UntilSensorCount {
2676                            sending,
2677                            until_sensors,
2678                            until_count,
2679                            trigger,
2680                            play_mode,
2681                        } => {
2682                            let until_sensors = resolve_sensors(&bag_ns, &until_sensors)?;
2683                            let sending = resolve_sensors(&bag_ns, &sending)?;
2684                            wind.push(WindFunction::SendFrames(
2685                                PlayKindUnitedPass3::UntilSensorCount {
2686                                    sending,
2687                                    until_sensors,
2688                                    until_count,
2689                                    trigger,
2690                                    play_mode,
2691                                },
2692                            ));
2693                        }
2694                    },
2695                    StatementKindOwned::Reset(p) => {
2696                        wind.push(WindFunction::Reset(p));
2697                    }
2698                    _ => {}
2699                };
2700            }
2701
2702            return Ok(Evaluated { rules, wind, vars });
2703        }
2704        Err(errs) => {
2705            let src = Source::from(source_code_raw);
2706            for err in errs {
2707                if rich_out {
2708                    let e = Report::build(ReportKind::Error, (), err.span().start)
2709                        .with_code(3)
2710                        .with_message(err.to_string())
2711                        .with_label(
2712                            Label::new(err.span().into_range())
2713                                .with_message(err.reason().to_string())
2714                                .with_color(Color::Red),
2715                        )
2716                        .finish();
2717
2718                    e.write(src.clone(), &mut out).unwrap();
2719                } else {
2720                    let msg = format!(
2721                        "<{}-{}>  {}",
2722                        err.span().start,
2723                        err.span().end,
2724                        err.reason(),
2725                    );
2726                    out.write_all(msg.as_bytes()).unwrap();
2727                }
2728            }
2729        }
2730    }
2731
2732    Err(anyhow!("Could not parse ratslang code."))
2733}
2734
2735#[cfg(test)]
2736mod tests {
2737    use super::*;
2738
2739    #[test]
2740    fn minimal_wind() {
2741        const SRC: &str = r#"
2742        reset! ./bag_file_name
2743
2744        _bag.{
2745            lidar.{
2746                _short = l
2747                _type = Pointcloud2
2748            }
2749            imu.{
2750                _short = i
2751                _type = Imu
2752            }
2753        }
2754
2755        pf! l 10s var1
2756        pf! i, l 5 var1
2757        pf! l 10 var1
2758
2759        rule!(var1
2760            testRat1 -> testRat2
2761        )
2762        pf! l 10s var1
2763        "#;
2764
2765        let eval = compile_code(SRC);
2766        assert!(eval.is_ok());
2767        let eval = eval.unwrap();
2768        assert!(!eval.rules.raw().is_empty());
2769        assert!(!eval.wind.is_empty());
2770    }
2771
2772    #[test]
2773    fn single_line_rule() {
2774        const SRC: &str = r"
2775        rule!(var1 testRat1 -> testRat2)
2776        ";
2777
2778        let eval = compile_code(SRC);
2779        assert!(eval.is_ok());
2780        let eval = eval.unwrap();
2781        assert!(!eval.rules.raw().is_empty());
2782    }
2783
2784    #[test]
2785    fn comments() {
2786        const SRC: &str = r"
2787        # bla,.
2788        # ups /// \masd
2789        a = 1 # yo
2790        ";
2791
2792        let eval = compile_code(SRC);
2793        assert!(eval.is_ok());
2794        let eval = eval.unwrap();
2795        assert!(eval.rules.raw().is_empty());
2796        assert!(eval.wind.is_empty());
2797    }
2798
2799    #[test]
2800    fn var_declare() {
2801        const SRC: &str = r"
2802         a <- 7
2803         b <- a
2804         a <- 6
2805         _l <- /cloud
2806        ";
2807
2808        // let mut a = Token::lexer(SRC);
2809        // let b = a.next();
2810        // dbg!(b);
2811
2812        let eval = compile_code(SRC);
2813        assert!(eval.is_ok());
2814        let eval = eval.unwrap();
2815
2816        let res = eval.vars.resolve("_l");
2817        assert!(res.is_ok());
2818        let res = res.unwrap();
2819        assert!(res.is_some());
2820        let res = res.unwrap();
2821        assert_eq!(res, Rhs::Path("/cloud".to_owned()));
2822
2823        let res = eval.vars.resolve("a");
2824        assert!(res.is_ok());
2825        let res = res.unwrap();
2826        assert!(res.is_some());
2827        let res = res.unwrap();
2828        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(6))));
2829
2830        let res = eval.vars.resolve("b");
2831        assert!(res.is_ok());
2832        let res = res.unwrap();
2833        assert!(res.is_some());
2834        let res = res.unwrap();
2835        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(7))));
2836    }
2837
2838    #[test]
2839    fn var_declare_nested() {
2840        const SRC: &str = r"
2841         a.b.c = 7
2842         a.b = a.b.c
2843         a.b.c = 6
2844         wind._l = /cloud
2845        ";
2846
2847        // let mut a = Token::lexer(SRC);
2848        // let b = a.next();
2849        // dbg!(b);
2850
2851        let eval = compile_code(SRC);
2852        assert!(eval.is_ok());
2853        let eval = eval.unwrap();
2854
2855        let res = eval.vars.resolve("wind._l");
2856        assert!(res.is_ok());
2857        let res = res.unwrap();
2858        assert!(res.is_some());
2859        let res = res.unwrap();
2860        assert_eq!(res, Rhs::Path("/cloud".to_owned()));
2861
2862        let res = eval.vars.resolve("a.b.c");
2863        assert!(res.is_ok());
2864        let res = res.unwrap();
2865        assert!(res.is_some());
2866        let res = res.unwrap();
2867        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(6))));
2868
2869        let res = eval.vars.resolve("a.b");
2870        assert!(res.is_ok());
2871        let res = res.unwrap();
2872        assert!(res.is_some());
2873        let res = res.unwrap();
2874        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(7))));
2875    }
2876
2877    #[test]
2878    fn include() {
2879        const SRC: &str = r"
2880        # like assigning a file to the current namespace
2881        <- ./../mt/test.mt
2882
2883        # including in namespace blocks will prepend the namespaces to the included AST
2884        # (excluding rules, they are always global)
2885        c.{
2886            <- ./../mt/test.mt
2887        }
2888        ";
2889
2890        let eval = compile_code(SRC);
2891        assert!(eval.is_ok());
2892        let eval = eval.unwrap();
2893
2894        let res = eval.vars.resolve("test");
2895        assert!(res.is_ok());
2896        let res = res.unwrap();
2897        assert!(res.is_some());
2898        let res = res.unwrap();
2899        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(4))));
2900
2901        let res = eval.vars.resolve("c.test");
2902        assert!(res.is_ok());
2903        let res = res.unwrap();
2904        assert!(res.is_some());
2905        let res = res.unwrap();
2906        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(4))));
2907    }
2908
2909    #[test]
2910    fn var_declare_blocks() {
2911        const SRC: &str = r"
2912        a.{
2913            b = 7
2914        }
2915
2916        c.{
2917            t = 5
2918
2919            d.{
2920                1 -> o
2921            }
2922            i = 95
2923        }
2924        ";
2925
2926        let eval = compile_code(SRC);
2927        assert!(eval.is_ok());
2928        let eval = eval.unwrap();
2929
2930        let res = eval.vars.resolve("a.b");
2931        assert!(res.is_ok());
2932        let res = res.unwrap();
2933        assert!(res.is_some());
2934        let res = res.unwrap();
2935        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(7))));
2936
2937        let res = eval.vars.resolve("c.t");
2938        assert!(res.is_ok());
2939        let res = res.unwrap();
2940        assert!(res.is_some());
2941        let res = res.unwrap();
2942        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(5))));
2943
2944        let res = eval.vars.resolve("c.d.o");
2945        assert!(res.is_ok());
2946        let res = res.unwrap();
2947        assert!(res.is_some());
2948        let res = res.unwrap();
2949        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(1))));
2950
2951        let res = eval.vars.resolve("c.i");
2952        assert!(res.is_ok());
2953        let res = res.unwrap();
2954        assert!(res.is_some());
2955        let res = res.unwrap();
2956        assert_eq!(res, Rhs::Val(Val::NumVal(NumVal::Integer(95))));
2957    }
2958
2959    #[test]
2960    fn in_ns() {
2961        // other, me
2962        let res = is_sub_namespace(&["a".to_owned()], &["a".to_owned()]); // true
2963        assert!(res);
2964        let res = is_sub_namespace(&["a".to_owned(), "b".to_owned()], &["a".to_owned()]); // a.b is deeper than a, so a.b can not be a sub namespace. false
2965        assert!(!res);
2966        let res = is_sub_namespace(&["a".to_owned()], &["a".to_owned(), "b".to_owned()]); // a is in a.b, true
2967        assert!(res);
2968        let res = is_sub_namespace(&[], &["a".to_owned()]); // empty is not in a.b, false
2969        assert!(!res);
2970    }
2971
2972    #[test]
2973    fn resolve_ns() {
2974        const SRC: &str = r"
2975        rule! (var1
2976            testRat1 -> testRat2
2977            testRat1 -> testRat2, a.c
2978            a.b <- 5
2979        )
2980
2981        _bag.{
2982            lidar.{
2983                short = l
2984                type = Pointcloud2
2985            }
2986            imu.{
2987                _short = i
2988                _type = Imu
2989            }
2990        }
2991        ";
2992
2993        let eval = compile_code(SRC);
2994        assert!(eval.is_ok());
2995        let eval = eval.unwrap();
2996        let e = eval.vars.resolve_ns(&["a"]);
2997        assert_eq!(e.len(), 2);
2998        let (var, rhs) = &e[1];
2999        assert_eq!(*var, Var::from_str("b").unwrap());
3000        assert_eq!(*rhs, Rhs::Val(Val::NumVal(NumVal::Integer(5))));
3001
3002        let e = eval.vars.resolve_ns(&["_bag"]);
3003        assert_eq!(e.len(), 4);
3004    }
3005
3006    #[test]
3007    fn strings() {
3008        const SRC: &str = r#"
3009        a = "bla with space"
3010        b = Blub
3011        c = Lidar::Ouster
3012            
3013        "#;
3014
3015        let eval = compile_code(SRC);
3016        assert!(eval.is_ok());
3017        let eval = eval.unwrap();
3018
3019        let e = eval.vars.resolve("a");
3020        assert!(e.is_ok());
3021        let e = e.unwrap();
3022        assert!(e.is_some());
3023        let rhs = e.unwrap();
3024        assert_eq!(rhs, Rhs::Val(Val::StringVal("bla with space".to_owned())));
3025
3026        let e = eval.vars.resolve("b");
3027        assert!(e.is_ok());
3028        let e = e.unwrap();
3029        assert!(e.is_some());
3030        let rhs = e.unwrap();
3031        assert_eq!(rhs, Rhs::Val(Val::StringVal("Blub".to_owned())));
3032
3033        let e = eval.vars.resolve("c");
3034        assert!(e.is_ok());
3035        let e = e.unwrap();
3036        assert!(e.is_some());
3037        let rhs = e.unwrap();
3038        assert_eq!(rhs, Rhs::Val(Val::StringVal("Lidar::Ouster".to_owned())));
3039    }
3040
3041    #[test]
3042    fn arrays() {
3043        const SRC: &str = r#"
3044        a = [ "bla with space", Blub ]
3045        "#;
3046
3047        let eval = compile_code(SRC);
3048        assert!(eval.is_ok());
3049        let eval = eval.unwrap();
3050
3051        let e = eval.vars.resolve("a");
3052        assert!(e.is_ok());
3053        let e = e.unwrap();
3054        assert!(e.is_some());
3055        let rhs = e.unwrap();
3056        assert_eq!(
3057            rhs,
3058            Rhs::Array(vec![
3059                Box::new(Rhs::Val(Val::StringVal("bla with space".to_owned()))),
3060                Box::new(Rhs::Val(Val::StringVal("Blub".to_owned()))),
3061            ])
3062        );
3063    }
3064
3065    // #[test]
3066    // fn enums() {
3067    //     // in your code
3068    //     #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
3069    //     enum Lidar {
3070    //         Ouster,
3071    //         Sick,
3072    //     }
3073
3074    //     #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
3075    //     enum Sensor {
3076    //         Lidar(Lidar),
3077    //         Imu,
3078    //     }
3079
3080    //     // for rl
3081    //     #[derive(Debug)]
3082    //     enum Enums {
3083    //         Sensor(Sensor),
3084    //     }
3085    //     let a = Enums::Sensor(Sensor::Lidar(Lidar::Ouster));
3086    //     let b = format!("{:?}", a);
3087    //     let r = convert_to_path(&b);
3088    //     println!("{:?}", r);
3089    //     const SRC: &str = "a = Sensor::Lidar";
3090
3091    // TODO Give Enum to parser function that has all possible variants as trait. so fn variants(self--impl display) -> [impl FromStr]. Then call that in parser and pass type through to AST. If parser finds Sensor type, that has the same name as one of the enums in display. so it calls the parse function on that variant.
3092    #[test]
3093    fn vec_mat_vals() {
3094        const SRC: &str = r"
3095        vec = [3, 2, 4]
3096
3097        mat = [ [3, 1, 1],
3098                [3, 2, 4] ]
3099        ";
3100
3101        let eval = compile_code(SRC);
3102        assert!(eval.is_ok());
3103        let eval = eval.unwrap();
3104        let vec = eval.vars.resolve("vec").unwrap().unwrap();
3105        assert_eq!(
3106            vec,
3107            Rhs::Array(vec![
3108                Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(3)))),
3109                Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(2)))),
3110                Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(4)))),
3111            ])
3112        );
3113        let mat = eval.vars.resolve("mat").unwrap().unwrap();
3114        assert_eq!(
3115            mat,
3116            Rhs::Array(vec![
3117                Box::new(Rhs::Array(vec![
3118                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(3)))),
3119                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(1)))),
3120                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(1)))),
3121                ])),
3122                Box::new(Rhs::Array(vec![
3123                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(3)))),
3124                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(2)))),
3125                    Box::new(Rhs::Val(Val::NumVal(NumVal::Integer(4)))),
3126                ])),
3127            ])
3128        );
3129    }
3130
3131    //     #[test]
3132    //     fn resolve_struct() {
3133    //         const SRC: &str = r"
3134    // _bag.{
3135    // 	lidar.{
3136    // 		_short = l
3137    // 		_topic = /ouster/points
3138    // 		_type = Pointcloud2
3139    // 	}
3140    // }
3141
3142    //         ";
3143
3144    //         let eval = compile_code(SRC);
3145    //         assert!(eval.is_ok());
3146    //         let eval = eval.unwrap();
3147
3148    //         resolve_struct_in_ns(user_ns, var)
3149
3150    //     }
3151    #[test]
3152    fn advanced_wind() {
3153        const SRC: &str = r"
3154        reset! ./bag_file_name
3155
3156        _bag.{
3157            lidar.{
3158                _short = l
3159                _type = Pointcloud2
3160            }
3161            imu.{
3162                _short = i
3163                _type = Imu
3164            }
3165        }
3166
3167        # send all lidar frames between the absolute 10s and 20s of the bagfile immediately
3168        pf! l 10s..20s
3169
3170        # send all lidar frames between the absolute 10s and 20s of the bagfile when reaching var1
3171        pf! l 10s..20s var1
3172
3173        # send all lidar frames between the absolute 10s and 20s of the bagfile but slow down time so it sends it over 1 minute
3174        pf! l 10s..20s 2mins
3175
3176        # send imu frames until 2 lidar frames are encountered
3177        pf! i,l 2
3178
3179        # send imu frames until 2 lidar frames are encountered but spread over 8s real time
3180        pf! i,l 2 8s
3181
3182        # send 10 lidar frames but spread them out over 20s
3183        pf! l 10 20s
3184
3185        # send the next(!) 10 seconds of lidar frames every time it reaches var1
3186        pf! l 10s var1
3187
3188        # fixed var
3189        pf! l 10s..20s var1 f
3190
3191        # dynamic var
3192        pf! l 10s..20s var1 d
3193
3194        # implicit dynamic var
3195        pf! l 10s..20s var1
3196
3197        # relative play time
3198        pf! l 10s..20s 1.
3199
3200        pf! l, i 2 1.
3201        ";
3202
3203        let eval = compile_code(SRC);
3204        assert!(eval.is_ok());
3205        let eval = eval.unwrap();
3206        assert!(!eval.wind.is_empty());
3207    }
3208
3209    #[test]
3210    fn test_loop_basic() {
3211        const SRC: &str = r"
3212        loop 3 {
3213            x = 1
3214            y = 2
3215        }
3216        ";
3217
3218        let eval = compile_code(SRC);
3219        assert!(eval.is_ok());
3220        let eval = eval.unwrap();
3221
3222        // The loop should expand to 3 copies of x=1 and y=2
3223        // So we should have x=1 defined 3 times (last one wins)
3224        let x = eval.vars.resolve("x").unwrap().unwrap();
3225        assert_eq!(x, Rhs::Val(Val::NumVal(NumVal::Integer(1))));
3226        let y = eval.vars.resolve("y").unwrap().unwrap();
3227        assert_eq!(y, Rhs::Val(Val::NumVal(NumVal::Integer(2))));
3228    }
3229
3230    #[test]
3231    fn test_loop_nested() {
3232        const SRC: &str = r"
3233        loop 2 {
3234            a = 10
3235            loop 2 {
3236                b = 20
3237            }
3238        }
3239        ";
3240
3241        let eval = compile_code(SRC);
3242        assert!(eval.is_ok());
3243        let eval = eval.unwrap();
3244
3245        let a = eval.vars.resolve("a").unwrap().unwrap();
3246        assert_eq!(a, Rhs::Val(Val::NumVal(NumVal::Integer(10))));
3247        let b = eval.vars.resolve("b").unwrap().unwrap();
3248        assert_eq!(b, Rhs::Val(Val::NumVal(NumVal::Integer(20))));
3249    }
3250
3251    #[test]
3252    fn test_loop_token() {
3253        // Test that "loop" is recognized as a keyword token, not a variable
3254        let mut lex = Token::lexer("loop 2");
3255        assert_eq!(lex.next(), Some(Ok(Token::KwLoop)));
3256        assert_eq!(lex.next(), Some(Ok(Token::IntegerNumber(2))));
3257    }
3258}