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 = §ion.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}