1use 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 #[token("+")]
178 OpPlus,
179
180 #[token("-")]
181 OpMinus,
182
183 #[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 #[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("if")]
236 KwIf,
237
238 #[token("loop")]
239 KwLoop,
240
241 #[token("LOG")]
242 KwLog,
243
244 #[token("~")]
245 DoNotCareOptim,
246
247 #[regex(r"pf!")]
249 FnPlayFrames,
250
251 #[token("reset!")]
252 FnReset,
253
254 #[token("rule!")]
255 FnRule,
256
257 #[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::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; 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 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), Type(SensorType), TopicAndType { topic: String, msg_type: SensorType }, }
548
549#[derive(Debug, PartialEq, Clone)]
550pub struct AnySensor {
551 pub name: String, pub id: SensorIdentification,
553 pub short: Option<String>, }
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 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 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 )?; 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#[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, Left, Compare, }
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), 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 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 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, Token::Variable(v) => v, }
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))), },
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 )); }
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"; 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; }
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 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 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, })
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 *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: _ } => {} }
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"), &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 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 .map(|(tok, span)| match tok {
2593 Ok(tok) => (tok, span.into()),
2596 Err(()) => (Token::Error, span.into()),
2597 });
2598
2599 let token_stream = Stream::from_iter(token_iter)
2601 .map((0..source_code_raw.len()).into(), |(t, s): (_, _)| (t, s));
2604
2605 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 let mut ast = do_pass1(owned, source_code_parent_dir)?; let mut rules = Vec::new();
2617 let mut winds = Vec::new();
2618 for expr in &ast {
2620 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 }
2631 let rules = RuleSexpr { rules };
2632 let rules = rules.eval()?;
2633
2634 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 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 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 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 let res = is_sub_namespace(&["a".to_owned()], &["a".to_owned()]); assert!(res);
2964 let res = is_sub_namespace(&["a".to_owned(), "b".to_owned()], &["a".to_owned()]); assert!(!res);
2966 let res = is_sub_namespace(&["a".to_owned()], &["a".to_owned(), "b".to_owned()]); assert!(res);
2968 let res = is_sub_namespace(&[], &["a".to_owned()]); 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]
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]
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 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 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}