devalang_wasm/language/syntax/parser/driver/
routing.rs1use crate::language::syntax::ast::{Statement, StatementKind, Value};
2use crate::language::syntax::parser::driver::effects::parse_chained_effects;
3use anyhow::{Result, anyhow};
4
5pub fn parse_routing_command(line_number: usize) -> Result<Statement> {
6 Ok(Statement::new(
9 StatementKind::Routing { body: Vec::new() },
10 Value::Null,
11 0,
12 line_number,
13 1,
14 ))
15}
16
17pub fn parse_routing_statement<'a>(line: &str, line_number: usize) -> Result<Statement> {
19 let trimmed = line.trim();
20
21 if trimmed.starts_with("node ") {
23 let rest = trimmed[5..].trim();
24 if let Some((name, alias)) = rest.split_once('=') {
25 let name = name.trim().trim_end_matches(':').to_string();
26 let alias = alias.trim().trim_end_matches(':').to_string();
27 return Ok(Statement::new(
28 StatementKind::RoutingNode {
29 name,
30 alias: Some(alias),
31 },
32 Value::Null,
33 0,
34 line_number,
35 1,
36 ));
37 } else {
38 let name = rest.trim_end_matches(':').to_string();
39 return Ok(Statement::new(
40 StatementKind::RoutingNode { name, alias: None },
41 Value::Null,
42 0,
43 line_number,
44 1,
45 ));
46 }
47 }
48
49 if trimmed.starts_with("fx ") {
51 let rest = trimmed[3..].trim();
52 if let Some((target, effects_str)) = rest.split_once("->") {
53 let target = target.trim().to_string();
54 let effects_chain = format!("->{}", effects_str);
55 let effects = parse_chained_effects(&effects_chain)?;
56 return Ok(Statement::new(
57 StatementKind::RoutingFx { target, effects },
58 Value::Null,
59 0,
60 line_number,
61 1,
62 ));
63 } else {
64 return Err(anyhow!(
65 "fx statement requires effects after '->': {}",
66 trimmed
67 ));
68 }
69 }
70
71 if trimmed.starts_with("route ") {
73 let rest = trimmed[6..].trim();
74 if let Some((source_part, rest)) = rest.split_once(" to ") {
75 let source = source_part.trim().to_string();
76 if let Some((dest_part, effect_part)) = rest.split_once(" with ") {
77 let destination = dest_part.trim().to_string();
78 let effect_str = effect_part.trim().trim_end_matches(':');
79 let effects = parse_single_routing_effect(effect_str)?;
80 return Ok(Statement::new(
81 StatementKind::RoutingRoute {
82 source,
83 destination,
84 effects: Some(effects),
85 },
86 Value::Null,
87 0,
88 line_number,
89 1,
90 ));
91 } else {
92 let destination = rest.trim().trim_end_matches(':').to_string();
93 return Ok(Statement::new(
94 StatementKind::RoutingRoute {
95 source,
96 destination,
97 effects: None,
98 },
99 Value::Null,
100 0,
101 line_number,
102 1,
103 ));
104 }
105 } else {
106 return Err(anyhow!(
107 "route statement requires format: route <source> to <dest> [with effect(...)]: {}",
108 trimmed
109 ));
110 }
111 }
112
113 if trimmed.starts_with("duck ") {
115 let rest = trimmed[5..].trim();
116 if let Some((source_part, rest)) = rest.split_once(" to ") {
117 let source = source_part.trim().to_string();
118 if let Some((dest_part, effect_part)) = rest.split_once(" with ") {
119 let destination = dest_part.trim().to_string();
120 let effect_str = effect_part.trim().trim_end_matches(':');
121 let effect = parse_single_routing_effect(effect_str)?;
122 return Ok(Statement::new(
123 StatementKind::RoutingDuck {
124 source,
125 destination,
126 effect,
127 },
128 Value::Null,
129 0,
130 line_number,
131 1,
132 ));
133 } else {
134 return Err(anyhow!(
135 "duck statement requires 'with' clause: {}",
136 trimmed
137 ));
138 }
139 } else {
140 return Err(anyhow!(
141 "duck statement requires format: duck <source> to <dest> with effect(...): {}",
142 trimmed
143 ));
144 }
145 }
146
147 if trimmed.starts_with("sidechain ") {
149 let rest = trimmed[10..].trim();
150 if let Some((source_part, rest)) = rest.split_once(" to ") {
151 let source = source_part.trim().to_string();
152 if let Some((dest_part, effect_part)) = rest.split_once(" with ") {
153 let destination = dest_part.trim().to_string();
154 let effect_str = effect_part.trim().trim_end_matches(':');
155 let effect = parse_single_routing_effect(effect_str)?;
156 return Ok(Statement::new(
157 StatementKind::RoutingSidechain {
158 source,
159 destination,
160 effect,
161 },
162 Value::Null,
163 0,
164 line_number,
165 1,
166 ));
167 } else {
168 return Err(anyhow!(
169 "sidechain statement requires 'with' clause: {}",
170 trimmed
171 ));
172 }
173 } else {
174 return Err(anyhow!(
175 "sidechain statement requires format: sidechain <source> to <dest> with effect(...): {}",
176 trimmed
177 ));
178 }
179 }
180
181 Err(anyhow!("Unknown routing statement: {}", trimmed))
182}
183
184fn parse_single_routing_effect(effect_str: &str) -> Result<Value> {
186 let effect_str = effect_str.trim();
187 if effect_str.is_empty() {
188 return Err(anyhow!("Empty effect definition"));
189 }
190
191 if let Some((name, params_str)) = effect_str.split_once('(') {
193 let name = name.trim().to_string();
194 let params_str = params_str.trim_end_matches(')');
195
196 if params_str.contains('{') && params_str.contains('}') {
198 let map_str = params_str.trim_matches(|c| c == '{' || c == '}');
199 let mut params_map = std::collections::HashMap::new();
200
201 for pair in map_str.split(',') {
202 if let Some((key, value)) = pair.split_once(':') {
203 let key = key.trim().to_string();
204 let value = value.trim();
205
206 let value = if value == "true" {
207 Value::Boolean(true)
208 } else if value == "false" {
209 Value::Boolean(false)
210 } else if let Ok(num) = value.parse::<f32>() {
211 Value::Number(num)
212 } else {
213 Value::String(value.trim_matches('"').to_string())
214 };
215
216 params_map.insert(key, value);
217 }
218 }
219
220 let mut result = std::collections::HashMap::new();
221 result.insert(name, Value::Map(params_map));
222 return Ok(Value::Map(result));
223 } else if let Ok(num) = params_str.parse::<f32>() {
224 let mut result = std::collections::HashMap::new();
225 result.insert(name, Value::Number(num));
226 return Ok(Value::Map(result));
227 } else {
228 let mut result = std::collections::HashMap::new();
229 result.insert(
230 name,
231 Value::String(params_str.trim_matches('"').to_string()),
232 );
233 return Ok(Value::Map(result));
234 }
235 } else {
236 let mut result = std::collections::HashMap::new();
237 result.insert(effect_str.to_string(), Value::Null);
238 return Ok(Value::Map(result));
239 }
240}