devalang_wasm/language/syntax/parser/driver/statements/
core.rs1use super::super::duration::parse_duration_token;
2use super::super::helpers::{parse_array_value, parse_synth_definition};
3use crate::language::syntax::ast::{Statement, StatementKind, Value};
4use anyhow::{Result, anyhow};
6use std::iter::Iterator;
7
8pub fn parse_tempo(
10 mut parts: impl Iterator<Item = impl AsRef<str>>,
11 line_number: usize,
12) -> Result<Statement> {
13 let value = parts
14 .next()
15 .ok_or_else(|| anyhow!("tempo declaration requires a value"))?;
16 let bpm: f32 = value
17 .as_ref()
18 .parse()
19 .map_err(|_| anyhow!("invalid tempo value: '{}'", value.as_ref()))?;
20 Ok(Statement::tempo(bpm, line_number, 1))
21}
22
23pub fn parse_print(line: &str, line_number: usize) -> Result<Statement> {
25 let message = line
26 .strip_prefix("print")
27 .ok_or_else(|| {
28 anyhow!(
29 "Invalid print statement: expected 'print' keyword at line {}",
30 line_number
31 )
32 })?
33 .trim();
34
35 if message.starts_with('"') && message.ends_with('"') && message.len() >= 2 {
38 let cleaned = message[1..message.len() - 1].to_string();
39 Ok(Statement::new(
40 StatementKind::Print,
41 Value::String(cleaned),
42 0,
43 line_number,
44 1,
45 ))
46 } else if let Ok(num) = message.parse::<f32>() {
47 Ok(Statement::new(
48 StatementKind::Print,
49 Value::Number(num),
50 0,
51 line_number,
52 1,
53 ))
54 } else {
55 Ok(Statement::new(
57 StatementKind::Print,
58 Value::Identifier(message.to_string()),
59 0,
60 line_number,
61 1,
62 ))
63 }
64}
65
66pub fn parse_sleep(
68 mut parts: impl Iterator<Item = impl AsRef<str>>,
69 line_number: usize,
70) -> Result<Statement> {
71 let value = parts
72 .next()
73 .ok_or_else(|| anyhow!("sleep instruction requires a duration"))?;
74 let duration = parse_duration_token(value.as_ref())?;
75 Ok(Statement::new(
76 StatementKind::Sleep,
77 Value::Duration(duration),
78 0,
79 line_number,
80 1,
81 ))
82}
83
84pub fn parse_bank(
86 mut parts: impl Iterator<Item = impl AsRef<str>>,
87 line_number: usize,
88) -> Result<Statement> {
89 let name = parts
90 .next()
91 .ok_or_else(|| anyhow!("bank declaration requires a name"))?
92 .as_ref()
93 .to_string();
94
95 let alias = if let Some(word) = parts.next() {
96 if word.as_ref() == "as" {
97 parts.next().map(|v| v.as_ref().to_string())
98 } else {
99 None
100 }
101 } else {
102 None
103 };
104
105 Ok(Statement::new(
106 StatementKind::Bank { name, alias },
107 Value::Null,
108 0,
109 line_number,
110 1,
111 ))
112}
113
114pub fn parse_let(
116 line: &str,
117 mut parts: impl Iterator<Item = impl AsRef<str>>,
118 line_number: usize,
119) -> Result<Statement> {
120 let name = parts
121 .next()
122 .ok_or_else(|| anyhow!("let statement requires a name"))?
123 .as_ref()
124 .to_string();
125
126 let remainder = line
127 .splitn(2, '=')
128 .nth(1)
129 .map(|r| r.trim().to_string())
130 .unwrap_or_default();
131
132 let value = if remainder.is_empty() {
133 None
134 } else if remainder.starts_with("synth ") {
135 Some(parse_synth_definition(&remainder)?)
137 } else if remainder.starts_with('[') && remainder.ends_with(']') {
138 Some(parse_array_value(&remainder)?)
140 } else {
141 if let Ok(num) = remainder.parse::<f32>() {
143 Some(Value::Number(num))
144 } else {
145 Some(Value::Identifier(remainder))
147 }
148 };
149
150 Ok(Statement::new(
151 StatementKind::Let { name, value },
152 Value::Null,
153 0,
154 line_number,
155 1,
156 ))
157}
158
159pub fn parse_var(
161 line: &str,
162 mut parts: impl Iterator<Item = impl AsRef<str>>,
163 line_number: usize,
164) -> Result<Statement> {
165 let name = parts
166 .next()
167 .ok_or_else(|| anyhow!("var statement requires a name"))?
168 .as_ref()
169 .to_string();
170
171 let remainder = line
172 .splitn(2, '=')
173 .nth(1)
174 .map(|r| r.trim().to_string())
175 .unwrap_or_default();
176
177 let value = if remainder.is_empty() {
178 None
179 } else {
180 if let Ok(num) = remainder.parse::<f32>() {
182 Some(Value::Number(num))
183 } else {
184 Some(Value::Identifier(remainder))
186 }
187 };
188
189 Ok(Statement::new(
190 StatementKind::Var { name, value },
191 Value::Null,
192 0,
193 line_number,
194 1,
195 ))
196}
197
198pub fn parse_const(
200 line: &str,
201 mut parts: impl Iterator<Item = impl AsRef<str>>,
202 line_number: usize,
203) -> Result<Statement> {
204 let name = parts
205 .next()
206 .ok_or_else(|| anyhow!("const statement requires a name"))?
207 .as_ref()
208 .to_string();
209
210 let remainder = line
211 .splitn(2, '=')
212 .nth(1)
213 .map(|r| r.trim().to_string())
214 .unwrap_or_default();
215
216 if remainder.is_empty() {
217 return Err(anyhow!("const declaration requires initialization"));
218 }
219
220 let value = if let Ok(num) = remainder.parse::<f32>() {
222 Some(Value::Number(num))
223 } else {
224 Some(Value::Identifier(remainder))
226 };
227
228 Ok(Statement::new(
229 StatementKind::Const { name, value },
230 Value::Null,
231 0,
232 line_number,
233 1,
234 ))
235}