1use crate::dna::atp::ast::Expression;
2use crate::dna::atp::value::Value;
3use chrono::{DateTime, Utc};
4use once_cell::sync::Lazy;
5use regex::Regex;
6use serde_json;
7use std::collections::HashMap;
8use std::env;
9use std::fmt;
10use std::fs;
11use std::future::Future;
12use std::pin::Pin;
13use std::path::{Path, PathBuf};
14use std::str::Chars;
15use thiserror::Error;
16pub use crate::ops::engine::OperatorEngine;
17
18type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
20
21#[derive(Error, Debug, Clone)]
25pub enum ParseError {
26 #[error("Math parse error at position {position}: {message}")]
27 MathError { position: usize, message: String },
28
29 #[error("Syntax error at line {line}, column {column}: {message}")]
30 SyntaxError {
31 line: usize,
32 column: usize,
33 message: String,
34 },
35
36 #[error("Variable not found: {name}")]
37 VariableNotFound { name: String },
38
39 #[error("Invalid operator: {operator}")]
40 InvalidOperator { operator: String },
41
42 #[error("IO error: {0}")]
43 IoError(String),
44
45 #[error("JSON error: {0}")]
46 JsonError(String),
47
48 #[error("Operator engine error: {0}")]
49 OperatorError(String),
50
51 #[error("Invalid escape sequence at position {position}")]
52 InvalidEscape { position: usize },
53
54 #[error("Unclosed string starting at position {position}")]
55 UnclosedString { position: usize },
56
57 #[error("Multiple errors occurred: {0:?}")]
58 Multiple(Vec<ParseError>),
59}
60
61impl From<std::io::Error> for ParseError {
63 fn from(err: std::io::Error) -> Self {
64 ParseError::IoError(err.to_string())
65 }
66}
67
68impl From<serde_json::Error> for ParseError {
69 fn from(err: serde_json::Error) -> Self {
70 ParseError::JsonError(err.to_string())
71 }
72}
73
74type Result<T> = std::result::Result<T, ParseError>;
75
76#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub struct SectionName(String);
81
82impl SectionName {
83 pub fn new(s: impl Into<String>) -> Self {
84 Self(s.into())
85 }
86
87 pub fn as_str(&self) -> &str {
88 &self.0
89 }
90}
91
92impl fmt::Display for SectionName {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "{}", self.0)
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Hash)]
99pub struct VariableName(String);
100
101impl VariableName {
102 pub fn new(s: impl Into<String>) -> Self {
103 Self(s.into())
104 }
105
106 pub fn as_str(&self) -> &str {
107 &self.0
108 }
109}
110
111impl fmt::Display for VariableName {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", self.0)
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
118pub struct CacheKey(String);
119
120impl CacheKey {
121 pub fn new(file: &str, key: &str) -> Self {
122 Self(format!("{}:{}", file, key))
123 }
124}
125
126static REGEX_CACHE: Lazy<RegexCache> = Lazy::new(|| RegexCache::new());
130
131struct RegexCache {
132 global_var: Regex,
133 date: Regex,
134 env: Regex,
135 range: Regex,
136 get: Regex,
137 set: Regex,
138 query: Regex,
139 operator: Regex,
140 ternary: Regex,
141 section: Regex,
142 angle_start: Regex,
143 brace_start: Regex,
144 key_value: Regex,
145 identifier: Regex,
146}
147
148impl RegexCache {
149 fn new() -> Self {
150 Self {
151 global_var: Regex::new(r"^\$([a-zA-Z_][a-zA-Z0-9_]*)$").unwrap(),
152 date: Regex::new(r#"^@date\(["']([^"']+)["']\)$"#).unwrap(),
153 env: Regex::new(r#"^@env\(["']([^"']*)["'](?:,\s*["']([^"']*)["'])?\)$"#).unwrap(),
154 range: Regex::new(r"^(\d+)-(\d+)$").unwrap(),
155 get: Regex::new(r#"^@([a-zA-Z0-9_-]+)\.hlx\.get\(["']([^"']+)["']\)$"#).unwrap(),
156 set: Regex::new(r#"^@([a-zA-Z0-9_-]+)\.hlx\.set\(["']([^"']+)["'],\s*(.+)\)$"#).unwrap(),
157 query: Regex::new(r#"^@query\(["']([^"']+)["']\)$"#).unwrap(),
158 operator: Regex::new(r"^@([a-zA-Z_][a-zA-Z0-9_]*)\((.*)\)$").unwrap(),
159 ternary: Regex::new(r"(.+?)\s*\?\s*(.+?)\s*:\s*(.+)").unwrap(),
160 section: Regex::new(r"^\[([a-zA-Z_][a-zA-Z0-9_]*)\]$").unwrap(),
161 angle_start: Regex::new(r"^([a-zA-Z_][a-zA-Z0-9_]*)\s*>$").unwrap(),
162 brace_start: Regex::new(r"^([a-zA-Z_][a-zA-Z0-9_]*)\s*\{$").unwrap(),
163 key_value: Regex::new(r"^([\$]?[a-zA-Z_][a-zA-Z0-9_-]*)\s*[:=]\s*(.+)$").unwrap(),
164 identifier: Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap(),
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq)]
173enum MathToken {
174 Number(f64),
175 Op(char),
176 LParen,
177 RParen,
178}
179
180pub struct MathParser<'a> {
181 input: &'a str,
182 chars: Chars<'a>,
183 lookahead: Option<char>,
184 position: usize,
185}
186
187impl<'a> MathParser<'a> {
188 fn new(s: &'a str) -> Self {
189 let mut chars = s.chars();
190 let lookahead = chars.next();
191 Self {
192 input: s,
193 chars,
194 lookahead,
195 position: 0,
196 }
197 }
198
199 fn next_char(&mut self) {
200 self.lookahead = self.chars.next();
201 self.position += 1;
202 }
203
204 fn peek(&self) -> Option<char> {
205 self.lookahead
206 }
207
208 fn consume_ws(&mut self) {
209 while matches!(self.peek(), Some(c) if c.is_whitespace()) {
210 self.next_char();
211 }
212 }
213
214 fn parse_number(&mut self) -> Result<f64> {
215 let mut s = String::new();
216 let start_pos = self.position;
217
218 while let Some(c) = self.peek() {
220 if c.is_ascii_digit() || c == '.' || c == 'e' || c == 'E' {
221 s.push(c);
222 self.next_char();
223 if (c == 'e' || c == 'E') && matches!(self.peek(), Some('+') | Some('-')) {
224 s.push(self.peek().unwrap());
225 self.next_char();
226 }
227 } else {
228 break;
229 }
230 }
231
232 s.parse::<f64>().map_err(|_| ParseError::MathError {
233 position: start_pos,
234 message: format!("Invalid number: {}", s),
235 })
236 }
237
238 fn next_token(&mut self) -> Result<Option<MathToken>> {
239 self.consume_ws();
240
241 match self.peek() {
242 None => Ok(None),
243 Some(ch) if ch.is_ascii_digit() || ch == '.' => {
244 Ok(Some(MathToken::Number(self.parse_number()?)))
245 }
246 Some('+') | Some('-') | Some('*') | Some('/') | Some('%') | Some('^') => {
247 let op = self.peek().unwrap();
248 self.next_char();
249 Ok(Some(MathToken::Op(op)))
250 }
251 Some('(') => {
252 self.next_char();
253 Ok(Some(MathToken::LParen))
254 }
255 Some(')') => {
256 self.next_char();
257 Ok(Some(MathToken::RParen))
258 }
259 Some(c) => Err(ParseError::MathError {
260 position: self.position,
261 message: format!("Unexpected character: '{}'", c),
262 }),
263 }
264 }
265
266 pub fn parse(&mut self) -> Result<f64> {
267 let mut tokens = Vec::new();
268 while let Some(tok) = self.next_token()? {
269 tokens.push(tok);
270 }
271
272 if tokens.is_empty() {
273 return Err(ParseError::MathError {
274 position: 0,
275 message: "Empty expression".to_string(),
276 });
277 }
278
279 let mut pos = 0;
280 self.expr(&tokens, &mut pos)
281 }
282
283 fn expr(&self, toks: &[MathToken], pos: &mut usize) -> Result<f64> {
284 let mut lhs = self.term(toks, pos)?;
285
286 while let Some(MathToken::Op(op @ ('+' | '-'))) = toks.get(*pos) {
287 *pos += 1;
288 let rhs = self.term(toks, pos)?;
289 lhs = if *op == '+' { lhs + rhs } else { lhs - rhs };
290 }
291
292 Ok(lhs)
293 }
294
295 fn term(&self, toks: &[MathToken], pos: &mut usize) -> Result<f64> {
296 let mut lhs = self.power(toks, pos)?;
297
298 while let Some(MathToken::Op(op @ ('*' | '/' | '%'))) = toks.get(*pos) {
299 *pos += 1;
300 let rhs = self.power(toks, pos)?;
301 lhs = match op {
302 '*' => lhs * rhs,
303 '/' => {
304 if rhs == 0.0 {
305 return Err(ParseError::MathError {
306 position: *pos,
307 message: "Division by zero".to_string(),
308 });
309 }
310 lhs / rhs
311 }
312 '%' => lhs % rhs,
313 _ => unreachable!(),
314 };
315 }
316
317 Ok(lhs)
318 }
319
320 fn power(&self, toks: &[MathToken], pos: &mut usize) -> Result<f64> {
321 let mut lhs = self.factor(toks, pos)?;
322
323 while let Some(MathToken::Op('^')) = toks.get(*pos) {
324 *pos += 1;
325 let rhs = self.factor(toks, pos)?;
326 lhs = lhs.powf(rhs);
327 }
328
329 Ok(lhs)
330 }
331
332 fn factor(&self, toks: &[MathToken], pos: &mut usize) -> Result<f64> {
333 match toks.get(*pos) {
334 Some(MathToken::Number(v)) => {
335 *pos += 1;
336 Ok(*v)
337 }
338 Some(MathToken::Op('+')) => {
339 *pos += 1;
340 self.factor(toks, pos)
341 }
342 Some(MathToken::Op('-')) => {
343 *pos += 1;
344 Ok(-self.factor(toks, pos)?)
345 }
346 Some(MathToken::LParen) => {
347 *pos += 1;
348 let v = self.expr(toks, pos)?;
349 match toks.get(*pos) {
350 Some(MathToken::RParen) => {
351 *pos += 1;
352 Ok(v)
353 }
354 _ => Err(ParseError::MathError {
355 position: *pos,
356 message: "Missing closing parenthesis".to_string(),
357 }),
358 }
359 }
360 _ => Err(ParseError::MathError {
361 position: *pos,
362 message: "Unexpected end of expression".to_string(),
363 }),
364 }
365 }
366}
367
368pub struct StringParser {
372 input: String,
373 position: usize,
374}
375
376impl StringParser {
377 pub fn new(input: impl Into<String>) -> Self {
378 Self {
379 input: input.into(),
380 position: 0,
381 }
382 }
383
384 pub fn parse_quoted_string(&mut self) -> Result<String> {
385 let chars: Vec<char> = self.input.chars().collect();
386 if chars.is_empty() {
387 return Ok(String::new());
388 }
389
390 let quote = chars[0];
391 if quote != '"' && quote != '\'' {
392 return Ok(self.input.clone());
393 }
394
395 let mut result = String::new();
396 let mut i = 1;
397 let start_pos = self.position;
398
399 while i < chars.len() {
400 match chars[i] {
401 '\\' if i + 1 < chars.len() => {
402 i += 1;
403 match chars[i] {
404 'n' => result.push('\n'),
405 'r' => result.push('\r'),
406 't' => result.push('\t'),
407 '\\' => result.push('\\'),
408 '"' => result.push('"'),
409 '\'' => result.push('\''),
410 'u' if i + 4 < chars.len() => {
411 let hex = &chars[i + 1..i + 5]
413 .iter()
414 .collect::<String>();
415 match u32::from_str_radix(hex, 16) {
416 Ok(code) => {
417 if let Some(ch) = char::from_u32(code) {
418 result.push(ch);
419 i += 4;
420 } else {
421 return Err(ParseError::InvalidEscape {
422 position: self.position + i,
423 });
424 }
425 }
426 Err(_) => {
427 return Err(ParseError::InvalidEscape {
428 position: self.position + i,
429 });
430 }
431 }
432 }
433 c => result.push(c),
434 }
435 i += 1;
436 }
437 c if c == quote => {
438 if i + 1 == chars.len() {
439 return Ok(result);
440 }
441 break;
442 }
443 c => {
444 result.push(c);
445 i += 1;
446 }
447 }
448 }
449
450 if i >= chars.len() {
451 return Err(ParseError::UnclosedString {
452 position: start_pos,
453 });
454 }
455
456 Ok(result)
457 }
458}
459
460mod parser_components {
464 use super::*;
465
466 pub struct ValueParser<'a> {
467 parser: &'a mut OperatorParser,
468 }
469
470 impl<'a> ValueParser<'a> {
471 pub fn new(parser: &'a mut OperatorParser) -> Self {
472 Self { parser }
473 }
474
475 pub async fn parse_primitive(&mut self, v: &str) -> Option<Value> {
476 match v {
477 "true" => Some(Value::Bool(true)),
478 "false" => Some(Value::Bool(false)),
479 "null" => Some(Value::Null),
480 _ => {
481 if let Ok(i) = v.parse::<i64>() {
482 Some(Value::Number(i as f64))
483 } else if let Ok(f) = v.parse::<f64>() {
484 Some(Value::Number(f))
485 } else {
486 None
487 }
488 }
489 }
490 }
491
492 pub async fn parse_global_var(&mut self, v: &str) -> Option<Value> {
493 if let Some(cap) = REGEX_CACHE.global_var.captures(v) {
494 let name = cap.get(1).unwrap().as_str();
495 return self.parser.global_variables
496 .get(&VariableName::new(name))
497 .cloned()
498 .or(Some(Value::String(String::new())));
499 }
500 None
501 }
502
503 pub async fn parse_date(&mut self, v: &str, parser: &OperatorParser) -> Option<Value> {
504 if let Some(cap) = REGEX_CACHE.date.captures(v) {
505 let fmt = cap.get(1).unwrap().as_str();
506 return Some(Value::String(parser.execute_date(fmt)));
507 }
508 None
509 }
510
511 pub async fn parse_env(&mut self, v: &str) -> Option<Value> {
512 if let Some(cap) = REGEX_CACHE.env.captures(v) {
513 let var = cap.get(1).unwrap().as_str();
514 let def = cap.get(2).map_or("", |m| m.as_str());
515 return Some(Value::String(
516 env::var(var).unwrap_or_else(|_| def.to_string())
517 ));
518 }
519 None
520 }
521 }
522
523 pub struct ArrayObjectParser<'a> {
524 parser: &'a mut OperatorParser,
525 }
526
527 impl<'a> ArrayObjectParser<'a> {
528 pub fn new(parser: &'a mut OperatorParser) -> Self {
529 Self { parser }
530 }
531
532 pub async fn parse_array(&mut self, txt: &str) -> Result<Value> {
533 let inner = &txt[1..txt.len() - 1];
534 if inner.trim().is_empty() {
535 return Ok(Value::Array(vec![]));
536 }
537
538 let mut items = Vec::new();
539 let mut buf = String::new();
540 let mut depth = 0;
541 let chars: Vec<char> = inner.chars().collect();
542 let mut i = 0;
543
544 while i < chars.len() {
545 let ch = chars[i];
546
547 if (ch == '"' || ch == '\'') && (i == 0 || chars[i - 1] != '\\') {
549 let quote = ch;
550 buf.push(ch);
551 i += 1;
552
553 while i < chars.len() {
554 let c = chars[i];
555 buf.push(c);
556 if c == '\\' && i + 1 < chars.len() {
557 i += 1;
558 buf.push(chars[i]);
559 } else if c == quote {
560 break;
561 }
562 i += 1;
563 }
564 i += 1;
565 continue;
566 }
567
568 match ch {
569 '[' | '{' => {
570 depth += 1;
571 buf.push(ch);
572 }
573 ']' | '}' => {
574 depth -= 1;
575 buf.push(ch);
576 }
577 ',' if depth == 0 => {
578 items.push(self.parser.parse_value(buf.trim()).await?);
580 buf.clear();
581 }
582 _ => buf.push(ch),
583 }
584 i += 1;
585 }
586
587 if !buf.trim().is_empty() {
588 items.push(self.parser.parse_value(buf.trim()).await?);
590 }
591
592 Ok(Value::Array(items))
593 }
594
595 pub async fn parse_object(&mut self, txt: &str) -> Result<Value> {
596 let inner = &txt[1..txt.len() - 1];
597 if inner.trim().is_empty() {
598 return Ok(Value::Object(HashMap::new()));
599 }
600
601 let mut pairs = Vec::new();
602 let mut buf = String::new();
603 let mut depth = 0;
604 let chars: Vec<char> = inner.chars().collect();
605 let mut i = 0;
606
607 while i < chars.len() {
608 let ch = chars[i];
609
610 if (ch == '"' || ch == '\'') && (i == 0 || chars[i - 1] != '\\') {
612 let quote = ch;
613 buf.push(ch);
614 i += 1;
615
616 while i < chars.len() {
617 let c = chars[i];
618 buf.push(c);
619 if c == '\\' && i + 1 < chars.len() {
620 i += 1;
621 buf.push(chars[i]);
622 } else if c == quote {
623 break;
624 }
625 i += 1;
626 }
627 i += 1;
628 continue;
629 }
630
631 match ch {
632 '[' | '{' => {
633 depth += 1;
634 buf.push(ch);
635 }
636 ']' | '}' => {
637 depth -= 1;
638 buf.push(ch);
639 }
640 ',' if depth == 0 => {
641 pairs.push(buf.trim().to_string());
642 buf.clear();
643 }
644 _ => buf.push(ch),
645 }
646 i += 1;
647 }
648
649 if !buf.trim().is_empty() {
650 pairs.push(buf.trim().to_string());
651 }
652
653 let mut map = HashMap::new();
654 for p in pairs {
655 let (k, v) = if let Some(idx) = p.find(':') {
656 (&p[..idx], &p[idx + 1..])
657 } else if let Some(idx) = p.find('=') {
658 (&p[..idx], &p[idx + 1..])
659 } else {
660 continue;
661 };
662
663 let key = k.trim().trim_matches('"').trim_matches('\'');
664 let val = self.parser.parse_value(v.trim()).await?;
666 map.insert(key.to_string(), val);
667 }
668
669 Ok(Value::Object(map))
670 }
671 }
672}
673
674pub struct OperatorParser {
678 data: HashMap<String, Value>,
679 global_variables: HashMap<VariableName, Value>,
680 section_variables: HashMap<String, Value>,
681 cache: HashMap<String, Value>,
682 cross_file_cache: HashMap<CacheKey, Value>,
683 current_section: Option<SectionName>,
684 in_object: bool,
685 object_key: String,
686 hlx_loaded: bool,
687 hlx_locations: Vec<String>,
688 operator_engine: Option<OperatorEngine>,
689 errors: Vec<ParseError>, current_line: usize,
691 current_column: usize,
692}
693
694pub fn get_or_create_helix_dir() -> std::io::Result<PathBuf> {
696 let home = env::var("HOME")
697 .or_else(|_| env::var("USERPROFILE"))
698 .map(PathBuf::from)
699 .or_else(|_| {
700 #[cfg(feature = "dirs")]
701 {
702 dirs::home_dir()
703 .ok_or_else(|| std::io::Error::new(
704 std::io::ErrorKind::NotFound,
705 "home not found"
706 ))
707 }
708 #[cfg(not(feature = "dirs"))]
709 {
710 Err(std::io::Error::new(
711 std::io::ErrorKind::NotFound,
712 "HOME/USERPROFILE missing",
713 ))
714 }
715 })?;
716
717 let helix = home.join(".dna").join("hlx");
718 if !helix.exists() {
719 fs::create_dir_all(&helix)?;
720 }
721 let _ = ensure_calc_dir()?;
722 Ok(helix)
723}
724
725pub fn ensure_calc_dir() -> std::io::Result<PathBuf> {
726 let home = env::var("HOME")
727 .or_else(|_| env::var("USERPROFILE"))
728 .map(PathBuf::from)
729 .or_else(|_| {
730 #[cfg(feature = "dirs")]
731 {
732 dirs::home_dir()
733 .ok_or_else(|| std::io::Error::new(
734 std::io::ErrorKind::NotFound,
735 "home not found"
736 ))
737 }
738 #[cfg(not(feature = "dirs"))]
739 {
740 Err(std::io::Error::new(
741 std::io::ErrorKind::NotFound,
742 "HOME/USERPROFILE missing",
743 ))
744 }
745 })?;
746
747 let calc = home.join(".dna").join("calc");
748 if !calc.exists() {
749 fs::create_dir_all(&calc)?;
750 }
751 Ok(calc)
752}
753
754impl OperatorParser {
756 pub async fn new() -> Result<Self> {
763 let helix_cfg = env::var("HELIX_CONFIG").unwrap_or_else(|_| {
764 get_or_create_helix_dir()
765 .unwrap_or_default()
766 .to_string_lossy()
767 .to_string()
768 });
769
770 let operator_engine = match OperatorEngine::new().await {
772 Ok(engine) => Some(engine),
773 Err(e) => {
774 eprintln!("Warning: Failed to initialize operator engine: {:?}", e);
775 None
776 }
777 };
778
779 Ok(Self {
780 data: HashMap::new(),
781 global_variables: HashMap::new(),
782 section_variables: HashMap::new(),
783 cache: HashMap::new(),
784 cross_file_cache: HashMap::new(),
785 current_section: None,
786 in_object: false,
787 object_key: String::new(),
788 hlx_loaded: false,
789 hlx_locations: vec![
790 "./dna.hlx".into(),
791 "../dna.hlx".into(),
792 "../../dna.hlx".into(),
793 "/root/.dna/hlx/dna.hlx".into(),
794 get_or_create_helix_dir()
795 .unwrap_or_default()
796 .join("dna.hlx")
797 .to_string_lossy()
798 .to_string(),
799 helix_cfg,
800 ],
801 operator_engine,
802 errors: Vec::new(),
803 current_line: 0,
804 current_column: 0,
805 })
806 }
807
808 pub async fn load_hlx(&mut self) -> Result<()> {
810 if self.hlx_loaded {
811 return Ok(());
812 }
813 self.hlx_loaded = true;
814
815 let locations = self.hlx_locations.clone();
817
818 for loc in &locations {
819 if loc.is_empty() {
820 continue;
821 }
822 if Path::new(loc).exists() {
823 println!("# Loading universal config from: {}", loc);
824
825 match self.parse_file(loc).await {
827 Ok(_) => break,
828 Err(e) => {
829 eprintln!("Warning: Failed to parse config from {}: {:?}", loc, e);
830 self.errors.push(e);
831 }
832 }
833 }
834 }
835 Ok(())
836 }
837
838 fn try_math(&self, s: &str) -> Result<Value> {
840 let mut parser = MathParser::new(s);
841 parser.parse().map(Value::Number)
842 }
843
844 pub fn parse_value<'a>(&'a mut self, raw: &'a str) -> BoxFuture<'a, Result<Value>> {
846 Box::pin(async move {
847 let v = raw.trim().trim_end_matches(';').trim();
848
849 let current_section_copy = self.current_section.clone();
851 let global_vars_copy = self.global_variables.clone();
852
853 match v {
855 "true" => return Ok(Value::Bool(true)),
856 "false" => return Ok(Value::Bool(false)),
857 "null" => return Ok(Value::Null),
858 _ => {}
859 }
860
861 if let Ok(i) = v.parse::<i64>() {
863 return Ok(Value::Number(i as f64));
864 } else if let Ok(f) = v.parse::<f64>() {
865 return Ok(Value::Number(f));
866 }
867
868 if let Some(cap) = REGEX_CACHE.global_var.captures(v) {
870 let name = cap.get(1).unwrap().as_str();
871 if let Some(val) = global_vars_copy.get(&VariableName::new(name)) {
872 return Ok(val.clone());
873 }
874 return Ok(Value::String(String::new()));
875 }
876
877 if let Some(section) = current_section_copy {
879 if REGEX_CACHE.identifier.is_match(v) {
880 let key = format!("{}.{}", section, v);
881 if let Some(val) = self.section_variables.get(&key) {
882 return Ok(val.clone());
883 }
884 }
885 }
886
887 if let Some(cap) = REGEX_CACHE.date.captures(v) {
889 let fmt = cap.get(1).unwrap().as_str();
890 let result = self.execute_date(fmt);
891 return Ok(Value::String(result));
892 }
893
894 if let Some(cap) = REGEX_CACHE.env.captures(v) {
896 let var = cap.get(1).unwrap().as_str();
897 let def = cap.get(2).map_or("", |m| m.as_str());
898 return Ok(Value::String(env::var(var).unwrap_or_else(|_| def.to_string())));
899 }
900
901 if v.starts_with('[') && v.ends_with(']') {
904 let mut array_obj_parser = parser_components::ArrayObjectParser::new(self);
905 return array_obj_parser.parse_array(v).await;
906 }
907
908 if v.starts_with('{') && v.ends_with('}') {
909 let mut array_obj_parser = parser_components::ArrayObjectParser::new(self);
910 return array_obj_parser.parse_object(v).await;
911 }
912
913 if let Some(cap) = REGEX_CACHE.get.captures(v) {
915 return self.cross_file_get(
916 cap.get(1).unwrap().as_str(),
917 cap.get(2).unwrap().as_str(),
918 ).await;
919 }
920
921 if let Some(cap) = REGEX_CACHE.set.captures(v) {
922 return self.cross_file_set(
923 cap.get(1).unwrap().as_str(),
924 cap.get(2).unwrap().as_str(),
925 cap.get(3).unwrap().as_str(),
926 ).await;
927 }
928
929 if let Some(cap) = REGEX_CACHE.query.captures(v) {
931 return Ok(Value::String(
932 self.execute_query(cap.get(1).unwrap().as_str()).await
933 ));
934 }
935
936 if let Some(cap) = REGEX_CACHE.operator.captures(v) {
938 return self.execute_operator(
939 cap.get(1).unwrap().as_str(),
940 cap.get(2).unwrap().as_str(),
941 ).await;
942 }
943
944 if v.contains(" + ") {
946 let mut out = String::new();
947 for part in v.split(" + ") {
948 let trimmed = part.trim().trim_matches('"').trim_matches('\'');
949 let evaluated = if trimmed.starts_with('@') || trimmed.starts_with('$') {
950 self.parse_value(trimmed).await?.to_string()
951 } else {
952 trimmed.to_string()
953 };
954 out.push_str(&evaluated);
955 }
956 return Ok(Value::String(out));
957 }
958
959 if let Some(cap) = REGEX_CACHE.ternary.captures(v) {
961 let cond = cap.get(1).unwrap().as_str();
962 let t = cap.get(2).unwrap().as_str();
963 let f = cap.get(3).unwrap().as_str();
964 if self.evaluate_condition(cond).await {
965 return self.parse_value(t).await;
966 } else {
967 return self.parse_value(f).await;
968 }
969 }
970
971 if (v.starts_with('"') && v.ends_with('"')) ||
973 (v.starts_with('\'') && v.ends_with('\'')) {
974 let mut string_parser = StringParser::new(v);
975 return string_parser.parse_quoted_string().map(Value::String);
976 }
977
978 if v.chars().any(|c| "+-*/%^()".contains(c)) {
980 if let Ok(v) = self.try_math(v) {
981 return Ok(v);
982 }
983 }
984
985 Ok(Value::String(v.to_string()))
987 })
988 }
989
990 async fn evaluate_condition(&mut self, cond: &str) -> bool {
992 let c = cond.trim();
993
994 let c = if let Some(idx) = c.find("//") {
996 &c[..idx].trim()
997 } else {
998 c
999 };
1000
1001 if let Some(idx) = c.find("==") {
1002 let l = match self.parse_value(&c[..idx].trim()).await {
1003 Ok(v) => v,
1004 Err(_) => Value::Null,
1005 };
1006 let r = match self.parse_value(&c[idx + 2..].trim()).await {
1007 Ok(v) => v,
1008 Err(_) => Value::Null,
1009 };
1010 return l.to_string() == r.to_string();
1011 }
1012
1013 if let Some(idx) = c.find("!=") {
1014 let l = match self.parse_value(&c[..idx].trim()).await {
1015 Ok(v) => v,
1016 Err(_) => Value::Null,
1017 };
1018 let r = match self.parse_value(&c[idx + 2..].trim()).await {
1019 Ok(v) => v,
1020 Err(_) => Value::Null,
1021 };
1022 return l.to_string() != r.to_string();
1023 }
1024
1025 if let Some(idx) = c.find(">=") {
1026 let l = match self.parse_value(&c[..idx].trim()).await {
1027 Ok(v) => v,
1028 Err(_) => Value::Null,
1029 };
1030 let r = match self.parse_value(&c[idx + 2..].trim()).await {
1031 Ok(v) => v,
1032 Err(_) => Value::Null,
1033 };
1034 match (l, r) {
1035 (Value::Number(a), Value::Number(b)) => return a >= b,
1036 (a, b) => return a.to_string() >= b.to_string(),
1037 }
1038 }
1039
1040 if let Some(idx) = c.find("<=") {
1041 let l = match self.parse_value(&c[..idx].trim()).await {
1042 Ok(v) => v,
1043 Err(_) => Value::Null,
1044 };
1045 let r = match self.parse_value(&c[idx + 2..].trim()).await {
1046 Ok(v) => v,
1047 Err(_) => Value::Null,
1048 };
1049 match (l, r) {
1050 (Value::Number(a), Value::Number(b)) => return a <= b,
1051 (a, b) => return a.to_string() <= b.to_string(),
1052 }
1053 }
1054
1055 if let Some(idx) = c.find('>') {
1056 let l = match self.parse_value(&c[..idx].trim()).await {
1057 Ok(v) => v,
1058 Err(_) => Value::Null,
1059 };
1060 let r = match self.parse_value(&c[idx + 1..].trim()).await {
1061 Ok(v) => v,
1062 Err(_) => Value::Null,
1063 };
1064 match (l, r) {
1065 (Value::Number(a), Value::Number(b)) => return a > b,
1066 (a, b) => return a.to_string() > b.to_string(),
1067 }
1068 }
1069
1070 if let Some(idx) = c.find('<') {
1071 let l = match self.parse_value(&c[..idx].trim()).await {
1072 Ok(v) => v,
1073 Err(_) => Value::Null,
1074 };
1075 let r = match self.parse_value(&c[idx + 1..].trim()).await {
1076 Ok(v) => v,
1077 Err(_) => Value::Null,
1078 };
1079 match (l, r) {
1080 (Value::Number(a), Value::Number(b)) => return a < b,
1081 (a, b) => return a.to_string() < b.to_string(),
1082 }
1083 }
1084
1085 match self.parse_value(c).await {
1086 Ok(value) => match value {
1087 Value::Bool(b) => b,
1088 Value::String(s) => !s.is_empty() && s != "false" && s != "0",
1089 Value::Number(n) => n != 0.0,
1090 Value::Null => false,
1091 _ => true,
1092 },
1093 Err(_) => false,
1094 }
1095 }
1096
1097 async fn cross_file_get(&mut self, file: &str, key: &str) -> Result<Value> {
1099 let cache_key = CacheKey::new(file, key);
1100
1101 if let Some(v) = self.cross_file_cache.get(&cache_key) {
1102 return Ok(v.clone());
1103 }
1104
1105 let helix_dir = match get_or_create_helix_dir() {
1107 Ok(path) => path.to_string_lossy().to_string(),
1108 Err(e) => return Err(ParseError::IoError(e.to_string())),
1109 };
1110
1111 let search_dirs = [
1112 ".",
1113 &helix_dir,
1114 "./config",
1115 "..",
1116 "../config",
1117 ];
1118
1119 let mut found = None;
1120 for d in &search_dirs {
1121 let cand = Path::new(d).join(format!("{}.hlx", file));
1122 if cand.exists() {
1123 found = Some(cand);
1124 break;
1125 }
1126 }
1127
1128 if let Some(p) = found {
1129 let mut tmp = OperatorParser::new().await?;
1130 tmp.parse_file(p.to_str().unwrap()).await?;
1131 if let Some(v) = tmp.get(key) {
1132 self.cross_file_cache.insert(cache_key, v.clone());
1133 return Ok(v);
1134 }
1135 }
1136
1137 Ok(Value::String(String::new()))
1138 }
1139
1140 async fn cross_file_set(
1141 &mut self,
1142 file: &str,
1143 key: &str,
1144 val_str: &str,
1145 ) -> Result<Value> {
1146 let cache_key = CacheKey::new(file, key);
1147 let val = self.parse_value(val_str).await?;
1148 self.cross_file_cache.insert(cache_key, val.clone());
1149 Ok(val)
1150 }
1151
1152 fn execute_date(&self, fmt: &str) -> String {
1154 let now: DateTime<Utc> = Utc::now();
1155 match fmt {
1156 "Y" => now.format("%Y").to_string(),
1157 "Y-m-d" => now.format("%Y-%m-%d").to_string(),
1158 "Y-m-d H:i:s" => now.format("%Y-%m-%d %H:%M:%S").to_string(),
1159 "c" => now.to_rfc3339(),
1160 _ => now.format(fmt).to_string(),
1161 }
1162 }
1163
1164 async fn execute_query(&mut self, q: &str) -> String {
1165 let _ = self.load_hlx().await;
1166 let db_type = self
1167 .get("database.default")
1168 .map(|v| v.to_string())
1169 .unwrap_or_else(|| "sqlite".to_string());
1170
1171 if q.contains(':') {
1172 let parts: Vec<&str> = q.splitn(2, ':').collect();
1173 format!("[Cross-DB Query: {} on {}]", parts[1], parts[0])
1174 } else if q.to_lowercase().contains("insert") && q.contains('{') {
1175 format!("[Auto-Schema Insert: {} on {}]", q, db_type)
1176 } else if q.to_lowercase().contains("sync:") {
1177 format!("[Sync Operation: {} on {}]", q, db_type)
1178 } else {
1179 format!("[Query: {} on {}]", q, db_type)
1180 }
1181 }
1182
1183 async fn execute_operator(
1184 &mut self,
1185 operator: &str,
1186 params: &str,
1187 ) -> Result<Value> {
1188 match &self.operator_engine {
1189 Some(engine) => {
1190 engine
1191 .execute_operator(operator, params)
1192 .await
1193 .map_err(|e| ParseError::OperatorError(e.to_string()))
1194 }
1195 None => Ok(Value::String(format!("@{}({})", operator, params))),
1196 }
1197 }
1198
1199 pub async fn parse_line(&mut self, raw: &str) -> Result<()> {
1201 self.current_column = 0;
1202 let line = raw.trim();
1203
1204 let line = if let Some(idx) = line.find("//") {
1206 &line[..idx].trim()
1207 } else {
1208 line
1209 };
1210
1211 if line.is_empty() || line.starts_with('#') {
1212 return Ok(());
1213 }
1214
1215 let line = if line.ends_with(';') {
1216 line.trim_end_matches(';').trim()
1217 } else {
1218 line
1219 };
1220
1221 if let Some(cap) = REGEX_CACHE.section.captures(line) {
1223 let section_name = SectionName::new(cap[1].to_string());
1224 self.current_section = Some(section_name);
1225 self.in_object = false;
1226 return Ok(());
1227 }
1228
1229 if let Some(cap) = REGEX_CACHE.angle_start.captures(line) {
1231 self.in_object = true;
1232 self.object_key = cap[1].to_string();
1233 return Ok(());
1234 }
1235
1236 if line == "<" {
1238 self.in_object = false;
1239 self.object_key.clear();
1240 return Ok(());
1241 }
1242
1243 if let Some(cap) = REGEX_CACHE.brace_start.captures(line) {
1245 self.in_object = true;
1246 self.object_key = cap[1].to_string();
1247 return Ok(());
1248 }
1249
1250 if line == "}" {
1252 self.in_object = false;
1253 self.object_key.clear();
1254 return Ok(());
1255 }
1256
1257 if let Some(cap) = REGEX_CACHE.key_value.captures(line) {
1259 let key_raw = cap[1].trim();
1260 let val_raw = cap[2].trim();
1261
1262 let current_section_copy = self.current_section.clone();
1264 let is_in_object = self.in_object;
1265 let object_key_copy = self.object_key.clone();
1266
1267 let val = match self.parse_value(val_raw).await {
1269 Ok(v) => v,
1270 Err(e) => {
1271 self.errors.push(e);
1272 Value::String(val_raw.to_string()) }
1274 };
1275
1276 let full_key = if is_in_object && !object_key_copy.is_empty() {
1278 if let Some(ref section) = current_section_copy {
1279 format!("{}.{}.{}", section, object_key_copy, key_raw)
1280 } else {
1281 format!("{}.{}", object_key_copy, key_raw)
1282 }
1283 } else if let Some(ref section) = current_section_copy {
1284 format!("{}.{}", section, key_raw)
1285 } else {
1286 key_raw.to_string()
1287 };
1288
1289 self.data.insert(full_key.clone(), val.clone());
1290
1291 if key_raw.starts_with('$') {
1293 let g = &key_raw[1..];
1294 self.global_variables.insert(VariableName::new(g), val.clone());
1295 } else if let Some(section) = current_section_copy {
1296 let sec_key = format!("{}.{}", section, key_raw);
1297 self.section_variables.insert(sec_key, val);
1298 }
1299 }
1300
1301 Ok(())
1302 }
1303
1304 pub fn evaluate_expression<'a>(&'a mut self, expr: &'a Expression) -> BoxFuture<'a, Result<Value>> {
1306 Box::pin(async move {
1307 match expr {
1309 Expression::String(s) => {
1310 if s.starts_with('@') || s.contains(" + ") || s.contains('?') {
1311 self.parse_value(s).await
1312 } else {
1313 Ok(Value::String(s.clone()))
1314 }
1315 }
1316 Expression::Number(n) => Ok(Value::Number(*n)),
1317 Expression::Bool(b) => Ok(Value::Bool(*b)),
1318 Expression::Array(arr) => {
1319 let mut out = Vec::new();
1321 for e in arr {
1322 out.push(self.evaluate_expression(e).await?);
1323 }
1324 Ok(Value::Array(out))
1325 }
1326 Expression::Object(obj) => {
1327 let mut map = HashMap::new();
1328 for (k, v) in obj {
1329 map.insert(k.clone(), self.evaluate_expression(v).await?);
1330 }
1331 Ok(Value::Object(map))
1332 }
1333 Expression::AtOperatorCall(op, params) => {
1334 let json = self.params_to_json(params).await?;
1335 self.execute_operator(op, &json).await
1336 }
1337 Expression::Variable(name) => {
1338 let var_name = VariableName::new(name);
1339 if let Some(v) = self.global_variables.get(&var_name) {
1340 Ok(v.clone())
1341 } else if let Some(v) = self.section_variables.get(name) {
1342 Ok(v.clone())
1343 } else {
1344 Err(ParseError::VariableNotFound {
1345 name: name.clone(),
1346 })
1347 }
1348 }
1349 Expression::OperatorCall(_, _, _, _) => {
1350 Err(ParseError::InvalidOperator {
1351 operator: "OperatorCall".to_string(),
1352 })
1353 }
1354 _ => Ok(Value::String(format!("Unsupported: {:?}", expr))),
1355 }
1356 })
1357 }
1358
1359 async fn params_to_json(
1361 &mut self,
1362 params: &HashMap<String, Expression>,
1363 ) -> Result<String> {
1364 let mut map = serde_json::Map::new();
1365 for (k, expr) in params {
1366 let val = self.evaluate_expression(expr).await?;
1367 map.insert(k.clone(), self.value_to_json_value(&val));
1368 }
1369 Ok(serde_json::to_string(&serde_json::Value::Object(map))?)
1370 }
1371
1372 fn value_to_json_value(&self, v: &Value) -> serde_json::Value {
1373 match v {
1374 Value::String(s) => serde_json::Value::String(s.clone()),
1375 Value::Number(n) => serde_json::Number::from_f64(*n)
1376 .map_or(serde_json::Value::Null, serde_json::Value::Number),
1377 Value::Bool(b) => serde_json::Value::Bool(*b),
1378 Value::Array(a) => {
1379 serde_json::Value::Array(
1380 a.iter().map(|x| self.value_to_json_value(x)).collect()
1381 )
1382 }
1383 Value::Object(o) => serde_json::Value::Object(
1384 o.iter()
1385 .map(|(k, v)| (k.clone(), self.value_to_json_value(v)))
1386 .collect(),
1387 ),
1388 Value::Null => serde_json::Value::Null,
1389 Value::Duration(d) => {
1390 serde_json::Value::String(format!("{} {:?}", d.value, d.unit))
1391 }
1392 Value::Reference(r) => serde_json::Value::String(format!("@{}", r)),
1393 Value::Identifier(i) => serde_json::Value::String(i.clone()),
1394 }
1395 }
1396
1397 pub fn parse<'a>(&'a mut self, content: &'a str) -> BoxFuture<'a, Result<HashMap<String, Value>>> {
1399 Box::pin(async move {
1400 self.current_line = 0;
1401 self.errors.clear();
1402
1403 for line in content.lines() {
1404 self.current_line += 1;
1405 if let Err(e) = self.parse_line(line).await {
1406 self.errors.push(e);
1407 }
1409 }
1410
1411 if !self.errors.is_empty() && self.data.is_empty() {
1413 if let Some(first_error) = self.errors.first() {
1415 return Err(first_error.clone());
1416 } else {
1417 return Err(ParseError::SyntaxError {
1418 line: 0,
1419 column: 0,
1420 message: "Unknown parse error".to_string(),
1421 });
1422 }
1423 }
1424
1425 Ok(self.data.clone())
1426 })
1427 }
1428
1429 pub fn parse_file<'a>(&'a mut self, path: &'a str) -> BoxFuture<'a, Result<()>> {
1431 Box::pin(async move {
1432 let txt = fs::read_to_string(path)?;
1433 self.parse(&txt).await?;
1434 Ok(())
1435 })
1436 }
1437
1438 pub fn get(&self, key: &str) -> Option<Value> {
1440 self.data.get(key).cloned()
1441 }
1442
1443 pub fn get_ref(&self, key: &str) -> Option<&Value> {
1444 self.data.get(key)
1445 }
1446
1447 pub fn set(&mut self, key: &str, value: Value) {
1448 self.data.insert(key.to_string(), value);
1449 }
1450
1451 pub fn keys(&self) -> Vec<String> {
1452 self.data.keys().cloned().collect()
1453 }
1454
1455 pub fn items(&self) -> &HashMap<String, Value> {
1456 &self.data
1457 }
1458
1459 pub fn items_cloned(&self) -> HashMap<String, Value> {
1460 self.data.clone()
1461 }
1462
1463 pub fn get_errors(&self) -> &[ParseError] {
1464 &self.errors
1465 }
1466
1467 pub fn has_errors(&self) -> bool {
1468 !self.errors.is_empty()
1469 }
1470}
1471
1472pub async fn load_from_hlx() -> Result<OperatorParser> {
1481 let mut parser = OperatorParser::new().await?;
1482 parser.load_hlx().await?;
1483 Ok(parser)
1484}
1485
1486pub async fn parse_hlx_content(content: &str) -> Result<HashMap<String, Value>> {
1494 let mut parser = OperatorParser::new().await?;
1495 parser.parse(content).await
1496}
1497
1498pub fn eval_math_expression(expr: &str) -> Result<Value> {
1506 let mut p = MathParser::new(expr);
1507 p.parse().map(Value::Number)
1508}
1509
1510#[cfg(test)]
1512mod tests {
1513 use super::*;
1514
1515 #[test]
1516 fn test_math_parser_basic() {
1517 assert_eq!(eval_math_expression("2 + 3").unwrap(), Value::Number(5.0));
1518 assert_eq!(eval_math_expression("2 * 3").unwrap(), Value::Number(6.0));
1519 assert_eq!(eval_math_expression("10 / 2").unwrap(), Value::Number(5.0));
1520 assert_eq!(eval_math_expression("10 % 3").unwrap(), Value::Number(1.0));
1521 }
1522
1523 #[test]
1524 fn test_math_parser_precedence() {
1525 assert_eq!(eval_math_expression("2 + 3 * 4").unwrap(), Value::Number(14.0));
1526 assert_eq!(eval_math_expression("(2 + 3) * 4").unwrap(), Value::Number(20.0));
1527 }
1528
1529 #[test]
1530 fn test_math_parser_power() {
1531 assert_eq!(eval_math_expression("2 ^ 3").unwrap(), Value::Number(8.0));
1532 assert_eq!(eval_math_expression("2 ^ 3 ^ 2").unwrap(), Value::Number(512.0));
1533 }
1534
1535 #[test]
1536 fn test_math_parser_negative() {
1537 assert_eq!(eval_math_expression("-5").unwrap(), Value::Number(-5.0));
1538 assert_eq!(eval_math_expression("(-5)").unwrap(), Value::Number(-5.0));
1539 assert_eq!(eval_math_expression("-5 + 3").unwrap(), Value::Number(-2.0));
1540 }
1541
1542 #[test]
1543 fn test_math_parser_scientific() {
1544 assert_eq!(eval_math_expression("1.5e2").unwrap(), Value::Number(150.0));
1545 assert_eq!(eval_math_expression("1.5E-2").unwrap(), Value::Number(0.015));
1546 }
1547
1548 #[test]
1549 fn test_string_parser_escapes() {
1550 let mut parser = StringParser::new(r#""Hello \"World\"""#);
1551 assert_eq!(parser.parse_quoted_string().unwrap(), r#"Hello "World""#);
1552
1553 let mut parser = StringParser::new(r#""Line1\nLine2""#);
1554 assert_eq!(parser.parse_quoted_string().unwrap(), "Line1\nLine2");
1555
1556 let mut parser = StringParser::new(r#""Unicode: \u0041""#);
1557 assert_eq!(parser.parse_quoted_string().unwrap(), "Unicode: A");
1558 }
1559
1560 #[tokio::test]
1561 async fn test_parser_basic() {
1562 let mut parser = OperatorParser::new().await.unwrap();
1563 parser.parse_line("key = value").await.unwrap();
1564 assert_eq!(parser.get("key"), Some(Value::String("value".into())));
1565 }
1566
1567 #[tokio::test]
1568 async fn test_parser_sections() {
1569 let mut parser = OperatorParser::new().await.unwrap();
1570 parser.parse_line("[section]").await.unwrap();
1571 parser.parse_line("key = value").await.unwrap();
1572 assert_eq!(parser.get("section.key"), Some(Value::String("value".into())));
1573 }
1574
1575 #[tokio::test]
1576 async fn test_parser_global_vars() {
1577 let mut parser = OperatorParser::new().await.unwrap();
1578 parser.parse_line("$global = 123").await.unwrap();
1579 assert_eq!(
1580 parser.global_variables.get(&VariableName::new("global")),
1581 Some(&Value::Number(123.0))
1582 );
1583 }
1584
1585 #[tokio::test]
1586 async fn test_parser_arrays() {
1587 let mut parser = OperatorParser::new().await.unwrap();
1588 let val = parser.parse_value("[1, 2, 3]").await.unwrap();
1589 match val {
1590 Value::Array(arr) => {
1591 assert_eq!(arr.len(), 3);
1592 assert_eq!(arr[0], Value::Number(1.0));
1593 }
1594 _ => panic!("Expected array"),
1595 }
1596 }
1597
1598 #[tokio::test]
1599 async fn test_parser_objects() {
1600 let mut parser = OperatorParser::new().await.unwrap();
1601 let val = parser.parse_value(r#"{"key": "value", "num": 42}"#).await.unwrap();
1602 match val {
1603 Value::Object(map) => {
1604 assert_eq!(map.get("key"), Some(&Value::String("value".into())));
1605 assert_eq!(map.get("num"), Some(&Value::Number(42.0)));
1606 }
1607 _ => panic!("Expected object"),
1608 }
1609 }
1610
1611 #[tokio::test]
1612 async fn test_parser_comments() {
1613 let mut parser = OperatorParser::new().await.unwrap();
1614 parser.parse_line("key = value // this is a comment").await.unwrap();
1615 assert_eq!(parser.get("key"), Some(Value::String("value".into())));
1616 }
1617
1618 #[tokio::test]
1619 async fn test_error_recovery() {
1620 let mut parser = OperatorParser::new().await.unwrap();
1621 let content = r#"
1622 good_key = value
1623 bad_key = @unknown_operator()
1624 another_good = 123
1625 "#;
1626
1627 let result = parser.parse(content).await;
1628 assert!(result.is_ok());
1629 assert_eq!(parser.get("good_key"), Some(Value::String("value".into())));
1630 assert_eq!(parser.get("another_good"), Some(Value::Number(123.0)));
1631 assert!(!parser.errors.is_empty());
1632 }
1633}