helix/dna/atp/
ast.rs

1use std::collections::HashMap;
2use crate::atp::types::Value;
3use crate::atp::types::{TimeUnit, Duration, SecretRef};
4#[derive(Debug, Clone)]
5pub struct SectionDecl {
6    pub name: String,
7    pub properties: HashMap<String, Expression>,
8}
9#[derive(Debug, Clone)]
10pub struct HelixAst {
11    pub declarations: Vec<Declaration>,
12}
13#[derive(Debug, Clone)]
14pub enum Declaration {
15    Project(ProjectDecl),
16    Agent(AgentDecl),
17    Workflow(WorkflowDecl),
18    Memory(MemoryDecl),
19    Context(ContextDecl),
20    Crew(CrewDecl),
21    Pipeline(PipelineDecl),
22    Plugin(PluginDecl),
23    Database(DatabaseDecl),
24    Task(TaskDecl),
25    Load(LoadDecl),
26    Section(SectionDecl),
27}
28#[derive(Debug, Clone)]
29pub struct ProjectDecl {
30    pub name: String,
31    pub properties: HashMap<String, Expression>,
32}
33#[derive(Debug, Clone)]
34pub struct AgentDecl {
35    pub name: String,
36    pub properties: HashMap<String, Expression>,
37    pub capabilities: Option<Vec<String>>,
38    pub backstory: Option<BackstoryBlock>,
39    pub tools: Option<Vec<String>>,
40}
41#[derive(Debug, Clone)]
42pub struct WorkflowDecl {
43    pub name: String,
44    pub trigger: Option<Expression>,
45    pub steps: Vec<StepDecl>,
46    pub pipeline: Option<PipelineDecl>,
47    pub properties: HashMap<String, Expression>,
48}
49#[derive(Debug, Clone)]
50pub struct StepDecl {
51    pub name: String,
52    pub agent: Option<String>,
53    pub crew: Option<Vec<String>>,
54    pub task: Option<String>,
55    pub properties: HashMap<String, Expression>,
56}
57#[derive(Debug, Clone)]
58pub struct PipelineDecl {
59    pub flow: Vec<PipelineNode>,
60}
61#[derive(Debug, Clone)]
62pub enum PipelineNode {
63    Step(String),
64    Parallel(Vec<PipelineNode>),
65    Conditional {
66        condition: Expression,
67        then_branch: Box<PipelineNode>,
68        else_branch: Option<Box<PipelineNode>>,
69    },
70}
71#[derive(Debug, Clone)]
72pub struct MemoryDecl {
73    pub provider: String,
74    pub connection: String,
75    pub embeddings: Option<EmbeddingsDecl>,
76    pub properties: HashMap<String, Expression>,
77}
78#[derive(Debug, Clone)]
79pub struct EmbeddingsDecl {
80    pub model: String,
81    pub dimensions: u32,
82    pub properties: HashMap<String, Expression>,
83}
84#[derive(Debug, Clone)]
85pub struct ContextDecl {
86    pub name: String,
87    pub environment: String,
88    pub secrets: Option<HashMap<String, SecretRef>>,
89    pub variables: Option<HashMap<String, Expression>>,
90    pub properties: HashMap<String, Expression>,
91}
92#[derive(Debug, Clone)]
93pub struct CrewDecl {
94    pub name: String,
95    pub agents: Vec<String>,
96    pub process_type: Option<String>,
97    pub properties: HashMap<String, Expression>,
98}
99#[derive(Debug, Clone)]
100pub struct PluginDecl {
101    pub name: String,
102    pub source: String,
103    pub version: Option<String>,
104    pub config: HashMap<String, Expression>,
105}
106#[derive(Debug, Clone)]
107pub struct DatabaseDecl {
108    pub name: String,
109    pub path: Option<String>,
110    pub shards: Option<i64>,
111    pub compression: Option<bool>,
112    pub cache_size: Option<i64>,
113    pub vector_index: Option<VectorIndexConfig>,
114    pub properties: HashMap<String, Expression>,
115}
116#[derive(Debug, Clone)]
117pub struct TaskDecl {
118    pub name: String,
119    pub properties: HashMap<String, Expression>,
120}
121#[derive(Debug, Clone)]
122pub struct VectorIndexConfig {
123    pub index_type: String,
124    pub dimensions: i64,
125    pub m: Option<i64>,
126    pub ef_construction: Option<i64>,
127    pub distance_metric: Option<String>,
128    pub properties: HashMap<String, Expression>,
129}
130#[derive(Debug, Clone)]
131pub struct LoadDecl {
132    pub file_name: String,
133    pub properties: HashMap<String, Expression>,
134}
135#[derive(Debug, Clone)]
136pub struct BackstoryBlock {
137    pub lines: Vec<String>,
138}
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum BinaryOperator {
141    Eq,
142    Ne,
143    Lt,
144    Le,
145    Gt,
146    Ge,
147    And,
148    Or,
149    Add,
150    Sub,
151    Mul,
152    Div,
153}
154#[derive(Debug, Clone)]
155pub enum Expression {
156    String(String),
157    Number(f64),
158    Bool(bool),
159    Null,
160    Duration(Duration),
161    Array(Vec<Expression>),
162    Object(HashMap<String, Expression>),
163    Variable(String),
164    Reference(String),
165    IndexedReference(String, String),
166    Identifier(String),
167    Pipeline(Vec<String>),
168    BinaryOp(Box<Expression>, BinaryOperator, Box<Expression>),
169    Block(Vec<Statement>),
170    TextBlock(Vec<String>),
171    OperatorCall(String, String, Option<String>, Option<String>),
172    AtOperatorCall(String, HashMap<String, Expression>),
173}
174#[derive(Debug, Clone)]
175pub enum Statement {
176    Assignment(String, Expression),
177    Declaration(Declaration),
178    Expression(Expression),
179}
180impl HelixAst {
181    pub fn new() -> Self {
182        HelixAst {
183            declarations: Vec::new(),
184        }
185    }
186    pub fn add_declaration(&mut self, decl: Declaration) {
187        self.declarations.push(decl);
188    }
189    pub fn get_projects(&self) -> Vec<&ProjectDecl> {
190        self.declarations
191            .iter()
192            .filter_map(|d| {
193                if let Declaration::Project(p) = d { Some(p) } else { None }
194            })
195            .collect()
196    }
197    pub fn get_agents(&self) -> Vec<&AgentDecl> {
198        self.declarations
199            .iter()
200            .filter_map(|d| {
201                if let Declaration::Agent(a) = d { Some(a) } else { None }
202            })
203            .collect()
204    }
205    pub fn get_workflows(&self) -> Vec<&WorkflowDecl> {
206        self.declarations
207            .iter()
208            .filter_map(|d| {
209                if let Declaration::Workflow(w) = d { Some(w) } else { None }
210            })
211            .collect()
212    }
213    pub fn get_contexts(&self) -> Vec<&ContextDecl> {
214        self.declarations
215            .iter()
216            .filter_map(|d| {
217                if let Declaration::Context(c) = d { Some(c) } else { None }
218            })
219            .collect()
220    }
221}
222#[allow(dead_code)]
223pub trait AstVisitor {
224    type Result;
225    fn visit_ast(&mut self, ast: &HelixAst) -> Self::Result;
226    fn visit_declaration(&mut self, decl: &Declaration) -> Self::Result;
227    fn visit_project(&mut self, project: &ProjectDecl) -> Self::Result;
228    fn visit_agent(&mut self, agent: &AgentDecl) -> Self::Result;
229    fn visit_workflow(&mut self, workflow: &WorkflowDecl) -> Self::Result;
230    fn visit_memory(&mut self, memory: &MemoryDecl) -> Self::Result;
231    fn visit_context(&mut self, context: &ContextDecl) -> Self::Result;
232    fn visit_crew(&mut self, crew: &CrewDecl) -> Self::Result;
233    fn visit_section(&mut self, section: &SectionDecl) -> Self::Result;
234    fn visit_expression(&mut self, expr: &Expression) -> Self::Result;
235}
236pub struct AstPrettyPrinter {
237    indent: usize,
238    indent_str: String,
239}
240impl AstPrettyPrinter {
241    pub fn new() -> Self {
242        AstPrettyPrinter {
243            indent: 0,
244            indent_str: "  ".to_string(),
245        }
246    }
247    fn write_indent(&self) -> String {
248        self.indent_str.repeat(self.indent)
249    }
250    pub fn print(&mut self, ast: &HelixAst) -> String {
251        let mut result = String::new();
252        result.push_str("# HELIX Language AST\n\n");
253        for decl in &ast.declarations {
254            result.push_str(&self.print_declaration(decl));
255            result.push_str("\n");
256        }
257        result
258    }
259    fn print_declaration(&mut self, decl: &Declaration) -> String {
260        match decl {
261            Declaration::Project(p) => self.print_project(p),
262            Declaration::Agent(a) => self.print_agent(a),
263            Declaration::Workflow(w) => self.print_workflow(w),
264            Declaration::Memory(m) => self.print_memory(m),
265            Declaration::Context(c) => self.print_context(c),
266            Declaration::Crew(cr) => self.print_crew(cr),
267            Declaration::Pipeline(p) => self.print_pipeline(p),
268            Declaration::Plugin(p) => self.print_plugin(p),
269            Declaration::Database(d) => self.print_database(d),
270            Declaration::Task(t) => self.print_task(t),
271            Declaration::Load(l) => self.print_load(l),
272            Declaration::Section(s) => self.print_section(s),
273        }
274    }
275    fn print_project(&mut self, project: &ProjectDecl) -> String {
276        let mut result = format!(
277            "{}project \"{}\" {{\n", self.write_indent(), project.name
278        );
279        self.indent += 1;
280        let mut keys: Vec<_> = project.properties.keys().collect();
281        keys.sort();
282        for key in keys {
283            let value = &project.properties[key];
284            result
285                .push_str(
286                    &format!(
287                        "{}{} = {}\n", self.write_indent(), key, self
288                        .print_expression(value)
289                    ),
290                );
291        }
292        self.indent -= 1;
293        result.push_str(&format!("{}}}\n", self.write_indent()));
294        result
295    }
296    fn print_agent(&mut self, agent: &AgentDecl) -> String {
297        let mut result = format!("{}agent \"{}\" {{\n", self.write_indent(), agent.name);
298        self.indent += 1;
299        let mut keys: Vec<_> = agent.properties.keys().collect();
300        keys.sort();
301        for key in keys {
302            let value = &agent.properties[key];
303            result
304                .push_str(
305                    &format!(
306                        "{}{} = {}\n", self.write_indent(), key, self
307                        .print_expression(value)
308                    ),
309                );
310        }
311        if let Some(capabilities) = &agent.capabilities {
312            result.push_str(&format!("{}capabilities [\n", self.write_indent()));
313            self.indent += 1;
314            for cap in capabilities {
315                result.push_str(&format!("{}\"{}\"\n", self.write_indent(), cap));
316            }
317            self.indent -= 1;
318            result.push_str(&format!("{}]\n", self.write_indent()));
319        }
320        if let Some(backstory) = &agent.backstory {
321            result.push_str(&format!("{}backstory {{\n", self.write_indent()));
322            self.indent += 1;
323            for line in &backstory.lines {
324                result.push_str(&format!("{}{}\n", self.write_indent(), line));
325            }
326            self.indent -= 1;
327            result.push_str(&format!("{}}}\n", self.write_indent()));
328        }
329        self.indent -= 1;
330        result.push_str(&format!("{}}}\n", self.write_indent()));
331        result
332    }
333    fn print_workflow(&mut self, workflow: &WorkflowDecl) -> String {
334        let mut result = format!(
335            "{}workflow \"{}\" {{\n", self.write_indent(), workflow.name
336        );
337        self.indent += 1;
338        if let Some(trigger) = &workflow.trigger {
339            result
340                .push_str(
341                    &format!(
342                        "{}trigger = {}\n", self.write_indent(), self
343                        .print_expression(trigger)
344                    ),
345                );
346        }
347        for step in &workflow.steps {
348            result.push_str(&self.print_step(step));
349        }
350        if let Some(pipeline) = &workflow.pipeline {
351            result.push_str(&self.print_pipeline(pipeline));
352        }
353        for (key, value) in &workflow.properties {
354            result
355                .push_str(
356                    &format!(
357                        "{}{} = {}\n", self.write_indent(), key, self
358                        .print_expression(value)
359                    ),
360                );
361        }
362        self.indent -= 1;
363        result.push_str(&format!("{}}}\n", self.write_indent()));
364        result
365    }
366    fn print_step(&mut self, step: &StepDecl) -> String {
367        let mut result = format!("{}step \"{}\" {{\n", self.write_indent(), step.name);
368        self.indent += 1;
369        if let Some(agent) = &step.agent {
370            result.push_str(&format!("{}agent = \"{}\"\n", self.write_indent(), agent));
371        }
372        if let Some(crew) = &step.crew {
373            result.push_str(&format!("{}crew = [", self.write_indent()));
374            result
375                .push_str(
376                    &crew
377                        .iter()
378                        .map(|c| format!("\"{}\"", c))
379                        .collect::<Vec<_>>()
380                        .join(", "),
381                );
382            result.push_str("]\n");
383        }
384        if let Some(task) = &step.task {
385            result.push_str(&format!("{}task = \"{}\"\n", self.write_indent(), task));
386        }
387        for (key, value) in &step.properties {
388            result
389                .push_str(
390                    &format!(
391                        "{}{} = {}\n", self.write_indent(), key, self
392                        .print_expression(value)
393                    ),
394                );
395        }
396        self.indent -= 1;
397        result.push_str(&format!("{}}}\n", self.write_indent()));
398        result
399    }
400    fn print_memory(&mut self, memory: &MemoryDecl) -> String {
401        let mut result = format!("{}memory {{\n", self.write_indent());
402        self.indent += 1;
403        result
404            .push_str(
405                &format!("{}provider = \"{}\"\n", self.write_indent(), memory.provider),
406            );
407        result
408            .push_str(
409                &format!(
410                    "{}connection = \"{}\"\n", self.write_indent(), memory.connection
411                ),
412            );
413        if let Some(embeddings) = &memory.embeddings {
414            result.push_str(&self.print_embeddings(embeddings));
415        }
416        for (key, value) in &memory.properties {
417            result
418                .push_str(
419                    &format!(
420                        "{}{} = {}\n", self.write_indent(), key, self
421                        .print_expression(value)
422                    ),
423                );
424        }
425        self.indent -= 1;
426        result.push_str(&format!("{}}}\n", self.write_indent()));
427        result
428    }
429    fn print_embeddings(&mut self, embeddings: &EmbeddingsDecl) -> String {
430        let mut result = format!("{}embeddings {{\n", self.write_indent());
431        self.indent += 1;
432        result
433            .push_str(
434                &format!("{}model = \"{}\"\n", self.write_indent(), embeddings.model),
435            );
436        result
437            .push_str(
438                &format!(
439                    "{}dimensions = {}\n", self.write_indent(), embeddings.dimensions
440                ),
441            );
442        for (key, value) in &embeddings.properties {
443            result
444                .push_str(
445                    &format!(
446                        "{}{} = {}\n", self.write_indent(), key, self
447                        .print_expression(value)
448                    ),
449                );
450        }
451        self.indent -= 1;
452        result.push_str(&format!("{}}}\n", self.write_indent()));
453        result
454    }
455    fn print_context(&mut self, context: &ContextDecl) -> String {
456        let mut result = format!(
457            "{}context \"{}\" {{\n", self.write_indent(), context.name
458        );
459        self.indent += 1;
460        result
461            .push_str(
462                &format!(
463                    "{}environment = \"{}\"\n", self.write_indent(), context.environment
464                ),
465            );
466        if let Some(secrets) = &context.secrets {
467            result.push_str(&format!("{}secrets {{\n", self.write_indent()));
468            self.indent += 1;
469            let mut keys: Vec<_> = secrets.keys().collect();
470            keys.sort();
471            for key in keys {
472                let secret_ref = &secrets[key];
473                result
474                    .push_str(
475                        &format!(
476                            "{}{} = {}\n", self.write_indent(), key, self
477                            .print_secret_ref(secret_ref)
478                        ),
479                    );
480            }
481            self.indent -= 1;
482            result.push_str(&format!("{}}}\n", self.write_indent()));
483        }
484        if let Some(variables) = &context.variables {
485            result.push_str(&format!("{}variables {{\n", self.write_indent()));
486            self.indent += 1;
487            let mut keys: Vec<_> = variables.keys().collect();
488            keys.sort();
489            for key in keys {
490                let value = &variables[key];
491                result
492                    .push_str(
493                        &format!(
494                            "{}{} = {}\n", self.write_indent(), key, self
495                            .print_expression(value)
496                        ),
497                    );
498            }
499            self.indent -= 1;
500            result.push_str(&format!("{}}}\n", self.write_indent()));
501        }
502        let mut keys: Vec<_> = context.properties.keys().collect();
503        keys.sort();
504        for key in keys {
505            let value = &context.properties[key];
506            result
507                .push_str(
508                    &format!(
509                        "{}{} = {}\n", self.write_indent(), key, self
510                        .print_expression(value)
511                    ),
512                );
513        }
514        self.indent -= 1;
515        result.push_str(&format!("{}}}\n", self.write_indent()));
516        result
517    }
518    fn print_crew(&mut self, crew: &CrewDecl) -> String {
519        let mut result = format!("{}crew \"{}\" {{\n", self.write_indent(), crew.name);
520        self.indent += 1;
521        result.push_str(&format!("{}agents [\n", self.write_indent()));
522        self.indent += 1;
523        for agent in &crew.agents {
524            result.push_str(&format!("{}\"{}\"\n", self.write_indent(), agent));
525        }
526        self.indent -= 1;
527        result.push_str(&format!("{}]\n", self.write_indent()));
528        if let Some(process_type) = &crew.process_type {
529            result
530                .push_str(
531                    &format!("{}process = \"{}\"\n", self.write_indent(), process_type),
532                );
533        }
534        for (key, value) in &crew.properties {
535            result
536                .push_str(
537                    &format!(
538                        "{}{} = {}\n", self.write_indent(), key, self
539                        .print_expression(value)
540                    ),
541                );
542        }
543        self.indent -= 1;
544        result.push_str(&format!("{}}}\n", self.write_indent()));
545        result
546    }
547    fn print_plugin(&mut self, plugin: &PluginDecl) -> String {
548        let mut result = format!(
549            "{}plugin \"{}\" {{\n", self.write_indent(), plugin.name
550        );
551        self.indent += 1;
552        result
553            .push_str(
554                &format!("{}source = \"{}\"\n", self.write_indent(), plugin.source),
555            );
556        if let Some(version) = &plugin.version {
557            result
558                .push_str(
559                    &format!("{}version = \"{}\"\n", self.write_indent(), version),
560                );
561        }
562        for (key, value) in &plugin.config {
563            result
564                .push_str(
565                    &format!(
566                        "{}{} = {}\n", self.write_indent(), key, self
567                        .print_expression(value)
568                    ),
569                );
570        }
571        self.indent -= 1;
572        result.push_str(&format!("{}}}\n", self.write_indent()));
573        result
574    }
575    fn print_database(&mut self, database: &DatabaseDecl) -> String {
576        let mut result = format!(
577            "{}database \"{}\" {{\n", self.write_indent(), database.name
578        );
579        self.indent += 1;
580        if let Some(path) = &database.path {
581            result.push_str(&format!("{}path = \"{}\"\n", self.write_indent(), path));
582        }
583        if let Some(shards) = database.shards {
584            result.push_str(&format!("{}shards = {}\n", self.write_indent(), shards));
585        }
586        if let Some(compression) = database.compression {
587            result
588                .push_str(
589                    &format!("{}compression = {}\n", self.write_indent(), compression),
590                );
591        }
592        if let Some(cache_size) = database.cache_size {
593            result
594                .push_str(
595                    &format!("{}cache_size = {}\n", self.write_indent(), cache_size),
596                );
597        }
598        if let Some(vector_index) = &database.vector_index {
599            result.push_str(&format!("{}vector_index {{\n", self.write_indent()));
600            self.indent += 1;
601            result
602                .push_str(
603                    &format!(
604                        "{}index_type = \"{}\"\n", self.write_indent(), vector_index
605                        .index_type
606                    ),
607                );
608            result
609                .push_str(
610                    &format!(
611                        "{}dimensions = {}\n", self.write_indent(), vector_index
612                        .dimensions
613                    ),
614                );
615            if let Some(m) = vector_index.m {
616                result.push_str(&format!("{}m = {}\n", self.write_indent(), m));
617            }
618            if let Some(ef_construction) = vector_index.ef_construction {
619                result
620                    .push_str(
621                        &format!(
622                            "{}ef_construction = {}\n", self.write_indent(),
623                            ef_construction
624                        ),
625                    );
626            }
627            if let Some(distance_metric) = &vector_index.distance_metric {
628                result
629                    .push_str(
630                        &format!(
631                            "{}distance_metric = \"{}\"\n", self.write_indent(),
632                            distance_metric
633                        ),
634                    );
635            }
636            self.indent -= 1;
637            result.push_str(&format!("{}}}\n", self.write_indent()));
638        }
639        for (key, value) in &database.properties {
640            result
641                .push_str(
642                    &format!(
643                        "{}{} = {}\n", self.write_indent(), key, self
644                        .print_expression(value)
645                    ),
646                );
647        }
648        self.indent -= 1;
649        result.push_str(&format!("{}}}\n", self.write_indent()));
650        result
651    }
652    fn print_task(&mut self, task: &TaskDecl) -> String {
653        let mut result = format!(
654            "{}task \"{}\" {{\n", self.write_indent(), task.name
655        );
656        self.indent += 1;
657        let mut keys: Vec<_> = task.properties.keys().collect();
658        keys.sort();
659        for key in keys {
660            let value = &task.properties[key];
661            result
662                .push_str(
663                    &format!(
664                        "{}{} = {}\n", self.write_indent(), key, self
665                        .print_expression(value)
666                    ),
667                );
668        }
669        self.indent -= 1;
670        result.push_str(&format!("{}}}\n", self.write_indent()));
671        result
672    }
673    fn print_load(&mut self, load: &LoadDecl) -> String {
674        let mut result = format!(
675            "{}load \"{}\" {{\n", self.write_indent(), load.file_name
676        );
677        self.indent += 1;
678        for (key, value) in &load.properties {
679            result
680                .push_str(
681                    &format!(
682                        "{}{} = {}\n", self.write_indent(), key, self
683                        .print_expression(value)
684                    ),
685                );
686        }
687        self.indent -= 1;
688        result.push_str(&format!("{}}}\n", self.write_indent()));
689        result
690    }
691    fn print_section(&mut self, section: &SectionDecl) -> String {
692        let mut result = format!("{}section {} {{\n", self.write_indent(), section.name);
693        self.indent += 1;
694        let mut keys: Vec<_> = section.properties.keys().collect();
695        keys.sort();
696        for key in keys {
697            let value = &section.properties[key];
698            result
699                .push_str(
700                    &format!(
701                        "{}{} = {}\n", self.write_indent(), key, self
702                        .print_expression(value)
703                    ),
704                );
705        }
706        self.indent -= 1;
707        result.push_str(&format!("{}}}\n", self.write_indent()));
708        result
709    }
710    fn print_pipeline(&mut self, pipeline: &PipelineDecl) -> String {
711        let mut result = format!("{}pipeline {{\n", self.write_indent());
712        self.indent += 1;
713        let flow_str = pipeline
714            .flow
715            .iter()
716            .map(|node| match node {
717                PipelineNode::Step(s) => s.clone(),
718                _ => "...".to_string(),
719            })
720            .collect::<Vec<_>>()
721            .join(" -> ");
722        result.push_str(&format!("{}{}\n", self.write_indent(), flow_str));
723        self.indent -= 1;
724        result.push_str(&format!("{}}}\n", self.write_indent()));
725        result
726    }
727    fn print_secret_ref(&mut self, secret_ref: &SecretRef) -> String {
728        match secret_ref {
729            SecretRef::Environment(var) => format!("${}", var),
730            SecretRef::Vault(path) => format!("vault:\"{}\"", path),
731            SecretRef::File(path) => format!("file:\"{}\"", path),
732        }
733    }
734    fn print_expression(&mut self, expr: &Expression) -> String {
735        match expr {
736            Expression::String(s) => format!("\"{}\"", s),
737            Expression::Number(n) => format!("{}", n),
738            Expression::Bool(b) => format!("{}", b),
739            Expression::Duration(d) => {
740                format!(
741                    "{}{}", d.value, match d.unit { TimeUnit::Seconds => "s",
742                    TimeUnit::Minutes => "m", TimeUnit::Hours => "h", TimeUnit::Days =>
743                    "d", }
744                )
745            }
746            Expression::Variable(v) => format!("${}", v),
747            Expression::Reference(r) => format!("@{}", r),
748            Expression::IndexedReference(file, key) => format!("@{}[{}]", file, key),
749            Expression::Identifier(i) => i.clone(),
750            Expression::Pipeline(stages) => stages.join(" -> "),
751            Expression::Array(items) => {
752                format!(
753                    "[{}]", items.iter().map(| i | self.print_expression(i)).collect::<
754                    Vec < _ >> ().join(", ")
755                )
756            }
757            Expression::Object(map) => {
758                let mut keys: Vec<_> = map.keys().collect();
759                keys.sort();
760                let items = keys
761                    .into_iter()
762                    .map(|k| format!("{} = {}", k, self.print_expression(& map[k])))
763                    .collect::<Vec<_>>()
764                    .join(", ");
765                format!("{{ {} }}", items)
766            }
767            Expression::Null => "null".to_string(),
768            Expression::BinaryOp(left, op, right) => {
769                let op_str = match op {
770                    BinaryOperator::Eq => "==",
771                    BinaryOperator::Ne => "!=",
772                    BinaryOperator::Lt => "<",
773                    BinaryOperator::Le => "<=",
774                    BinaryOperator::Gt => ">",
775                    BinaryOperator::Ge => ">=",
776                    BinaryOperator::And => "&&",
777                    BinaryOperator::Or => "||",
778                    BinaryOperator::Add => "+",
779                    BinaryOperator::Sub => "-",
780                    BinaryOperator::Mul => "*",
781                    BinaryOperator::Div => "/",
782                };
783                format!(
784                    "{} {} {}", self.print_expression(left), op_str, self
785                    .print_expression(right)
786                )
787            }
788            _ => "...".to_string(),
789        }
790    }
791}
792impl Expression {
793    pub fn binary(left: Expression, op: BinaryOperator, right: Expression) -> Self {
794        Expression::BinaryOp(Box::new(left), op, Box::new(right))
795    }
796    pub fn as_string(&self) -> Option<String> {
797        match self {
798            Expression::String(s) => Some(s.clone()),
799            Expression::Identifier(s) => Some(s.clone()),
800            _ => None,
801        }
802    }
803    pub fn as_number(&self) -> Option<f64> {
804        match self {
805            Expression::Number(n) => Some(*n),
806            _ => None,
807        }
808    }
809    pub fn as_bool(&self) -> Option<bool> {
810        match self {
811            Expression::Bool(b) => Some(*b),
812            _ => None,
813        }
814    }
815    pub fn as_array(&self) -> Option<Vec<Expression>> {
816        match self {
817            Expression::Array(arr) => Some(arr.clone()),
818            _ => None,
819        }
820    }
821    pub fn as_object(&self) -> Option<&HashMap<String, Expression>> {
822        match self {
823            Expression::Object(map) => Some(map),
824            _ => None,
825        }
826    }
827    pub fn to_value(&self) -> Value {
828        match self {
829            Expression::String(s) => Value::String(s.clone()),
830            Expression::Number(n) => Value::Number(*n),
831            Expression::Bool(b) => Value::Bool(*b),
832            Expression::Null => Value::Null,
833            Expression::Duration(d) => Value::Duration(d.clone()),
834            Expression::Array(arr) => {
835                Value::Array(arr.iter().map(|e| e.to_value()).collect())
836            }
837            Expression::Object(map) => {
838                Value::Object(
839                    map.iter().map(|(k, v)| (k.clone(), v.to_value())).collect(),
840                )
841            }
842            Expression::Variable(v) => Value::Reference(format!("${}", v)),
843            Expression::Reference(r) => Value::Reference(format!("@{}", r)),
844            Expression::IndexedReference(file, key) => {
845                Value::Reference(format!("@{}[{}]", file, key))
846            }
847            Expression::Identifier(i) => Value::Identifier(i.clone()),
848            Expression::BinaryOp(left, op, right) => {
849                let op_str = match op {
850                    BinaryOperator::Eq => "==",
851                    BinaryOperator::Ne => "!=",
852                    BinaryOperator::Lt => "<",
853                    BinaryOperator::Le => "<=",
854                    BinaryOperator::Gt => ">",
855                    BinaryOperator::Ge => ">=",
856                    BinaryOperator::And => "&&",
857                    BinaryOperator::Or => "||",
858                    BinaryOperator::Add => "+",
859                    BinaryOperator::Sub => "-",
860                    BinaryOperator::Mul => "*",
861                    BinaryOperator::Div => "/",
862                };
863                Value::String(
864                    format!(
865                        "{} {} {}", format!("{:?}", left.to_value()), op_str,
866                        format!("{:?}", right.to_value())
867                    ),
868                )
869            }
870            _ => Value::String("".to_string()),
871        }
872    }
873}
874#[allow(dead_code)]
875pub struct AstBuilder {
876    ast: HelixAst,
877}
878#[allow(dead_code)]
879impl AstBuilder {
880    pub fn new() -> Self {
881        AstBuilder { ast: HelixAst::new() }
882    }
883    pub fn add_project(
884        mut self,
885        name: String,
886        properties: HashMap<String, Expression>,
887    ) -> Self {
888        self.ast.add_declaration(Declaration::Project(ProjectDecl { name, properties }));
889        self
890    }
891    pub fn add_agent(mut self, agent: AgentDecl) -> Self {
892        self.ast.add_declaration(Declaration::Agent(agent));
893        self
894    }
895    pub fn add_workflow(mut self, workflow: WorkflowDecl) -> Self {
896        self.ast.add_declaration(Declaration::Workflow(workflow));
897        self
898    }
899    pub fn add_context(mut self, context: ContextDecl) -> Self {
900        self.ast.add_declaration(Declaration::Context(context));
901        self
902    }
903    pub fn add_memory(mut self, memory: MemoryDecl) -> Self {
904        self.ast.add_declaration(Declaration::Memory(memory));
905        self
906    }
907    pub fn add_crew(mut self, crew: CrewDecl) -> Self {
908        self.ast.add_declaration(Declaration::Crew(crew));
909        self
910    }
911    pub fn add_pipeline(mut self, pipeline: PipelineDecl) -> Self {
912        self.ast.add_declaration(Declaration::Pipeline(pipeline));
913        self
914    }
915    pub fn add_plugin(mut self, plugin: PluginDecl) -> Self {
916        self.ast.add_declaration(Declaration::Plugin(plugin));
917        self
918    }
919    pub fn add_database(mut self, database: DatabaseDecl) -> Self {
920        self.ast.add_declaration(Declaration::Database(database));
921        self
922    }
923    pub fn add_load(mut self, load: LoadDecl) -> Self {
924        self.ast.add_declaration(Declaration::Load(load));
925        self
926    }
927    pub fn add_section(mut self, section: SectionDecl) -> Self {
928        self.ast.add_declaration(Declaration::Section(section));
929        self
930    }
931    pub fn build(self) -> HelixAst {
932        self.ast
933    }
934}