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