1use std::i64;
2
3use pest::iterators::{Pair, Pairs};
4
5use crate::errors::HakuError;
6use crate::parse::Rule;
7
8#[derive(Debug, Clone)]
10pub enum Seq {
11 Int(i64, i64, i64),
13 Str(String),
15 Idents(Vec<String>),
17 Exec(String),
19 Var(String),
21}
22
23pub const FLAG_QUIET: u32 = 1;
27pub const FLAG_PASS: u32 = 2;
29
30pub fn is_flag_on(flags: u32, flag: u32) -> bool {
32 flags & flag == flag
33}
34
35#[derive(Debug, Clone)]
37pub enum Op {
38 Comment(String),
40 DocComment(String),
43 Include(u32, String),
48 Error(String),
50 Feature(bool, String),
56 Func(String, Vec<Op>),
61 StmtClose,
63 Assign(String, Vec<Op>),
68 DefAssign(String, Vec<Op>),
75 EitherAssign(bool, String, Vec<Op>),
84 Compare(String, Vec<Op>),
89 If(Vec<Op>),
91 ElseIf(Vec<Op>),
93 AndExpr(Vec<Op>),
96 Else,
98 Break,
100 Continue,
102 Return,
104 While(Vec<Op>),
106 For(String, Seq),
108 Recipe(String, u32, Vec<String>, Vec<String>),
117 Shell(u32, String),
122
123 Int(i64),
126 Str(String),
128 Var(String),
130 Exec(String),
132 Not(Vec<Op>),
134 Cd(u32, String),
136 Pause,
138}
139
140fn str_to_flags(s: &str) -> u32 {
142 let mut flags: u32 = 0;
143 if s.find('@').is_some() {
144 flags |= FLAG_QUIET;
145 }
146 if s.find('-').is_some() {
147 flags |= FLAG_PASS;
148 }
149 flags
150}
151
152pub fn build_recipe(p: Pairs<Rule>) -> Result<Op, HakuError> {
154 let mut flags: u32 = 0;
155 let mut name = String::new();
156 let mut vars = Vec::new();
157 let mut deps = Vec::new();
158
159 let pstr = p.as_str().to_string();
160 for s in p {
161 match s.as_rule() {
162 Rule::cmd_flags => flags = str_to_flags(s.as_str()),
163 Rule::sec_name => name = s.as_str().to_string(),
164 Rule::sec_args => {
165 let inner = s.into_inner();
166 for s_in in inner {
167 vars.push(s_in.as_str().to_string());
168 }
169 if !vars.is_empty() {
170 for v in &vars[..vars.len() - 1] {
171 if v.starts_with('+') {
172 return Err(HakuError::RecipeListArgError(pstr));
173 }
174 }
175 }
176 }
177 Rule::sec_deps => {
178 let inner = s.into_inner();
179 for s_in in inner {
180 deps.push(s_in.as_str().to_string());
181 }
182 }
183 _ => { }
184 }
185 }
186
187 Ok(Op::Recipe(name, flags, vars, deps))
188}
189
190pub fn build_cd(p: Pairs<Rule>) -> Result<Op, HakuError> {
192 let mut flags: u32 = 0;
193 let mut cmd = String::new();
194 for s in p {
195 match s.as_rule() {
196 Rule::cmd_flags => flags = str_to_flags(s.as_str()),
197 Rule::cd_body => cmd = strip_quotes(s.as_str()).to_string(),
198 _ => {}
199 }
200 }
201
202 Ok(Op::Cd(flags, cmd))
203}
204
205pub fn build_include(p: Pairs<Rule>) -> Result<Op, HakuError> {
207 let mut flags: u32 = 0;
208 let mut cmd = String::new();
209 for s in p {
210 match s.as_rule() {
211 Rule::cmd_flags => flags = str_to_flags(s.as_str()),
212 Rule::include_body => cmd = strip_quotes(s.as_str()).to_string(),
213 _ => {}
214 }
215 }
216
217 Ok(Op::Include(flags, cmd))
218}
219
220pub fn build_error(p: Pairs<Rule>) -> Result<Op, HakuError> {
222 let mut cmd = String::new();
223 for s in p {
224 if let Rule::error_body = s.as_rule() {
225 cmd = strip_quotes(s.as_str()).to_string();
226 }
227 }
228
229 Ok(Op::Error(cmd))
230}
231
232pub fn build_shell_cmd(p: Pairs<Rule>) -> Result<Op, HakuError> {
234 let mut flags: u32 = 0;
235 let mut cmd = String::new();
236 for s in p {
237 match s.as_rule() {
238 Rule::cmd_flags => flags = str_to_flags(s.as_str()),
239 Rule::shell_cmd => cmd = s.as_str().to_string(),
240 _ => {}
241 }
242 }
243
244 Ok(Op::Shell(flags, cmd))
245}
246
247pub fn strip_quotes(s: &str) -> &str {
250 if s.starts_with('"') {
251 s.trim_matches('"')
252 } else if s.starts_with('\'') {
253 s.trim_matches('\'')
254 } else if s.starts_with('`') {
255 s.trim_matches('`')
256 } else {
257 s
258 }
259}
260
261pub fn strip_var_deco(s: &str) -> &str {
266 let s = s.trim_matches('$');
267 let s = s.trim_start_matches('{');
268 s.trim_end_matches('}')
269}
270
271fn build_seq(p: Pairs<Rule>) -> Result<Seq, HakuError> {
281 let text = p.as_str().to_owned();
282 for pair in p {
283 match pair.as_rule() {
284 Rule::squoted | Rule::dquoted => return Ok(Seq::Str(strip_quotes(pair.as_str()).to_string())),
285 Rule::exec => return Ok(Seq::Exec(strip_quotes(pair.as_str()).to_string())),
286 Rule::raw_seq => {
287 let mut list = Vec::new();
288 for ids in pair.into_inner() {
289 match ids.as_rule() {
290 Rule::ident => list.push(ids.as_str().to_owned()),
291 _ => unimplemented!(),
292 }
293 }
294 return Ok(Seq::Idents(list));
295 }
296 Rule::int_seq => {
297 let mut start = String::new();
298 let mut end = String::new();
299 let mut step = "1".to_string();
300 for int in pair.into_inner() {
301 match int.as_rule() {
302 Rule::int | Rule::hex_int => {
303 if start.is_empty() {
304 start = int.as_str().to_owned();
305 } else if end.is_empty() {
306 end = int.as_str().to_owned();
307 } else {
308 step = int.as_str().to_owned();
309 }
310 }
311 _ => unimplemented!(),
312 }
313 }
314 let istart = if let Ok(i) = s_to_i64(&start) {
315 i
316 } else {
317 return Err(HakuError::SeqIntError("start", start));
318 };
319 let iend = if let Ok(i) = s_to_i64(&end) {
320 i
321 } else {
322 return Err(HakuError::SeqIntError("end", end));
323 };
324 let istep = if let Ok(i) = s_to_i64(&step) {
325 i
326 } else {
327 return Err(HakuError::SeqIntError("step", end));
328 };
329 if istep == 0 || (istep > 0 && istart > iend) || (istep < 0 && istart < iend) {
330 return Err(HakuError::SeqError(istart, iend, istep));
331 }
332 return Ok(Seq::Int(istart, iend, istep));
333 }
334 Rule::str_seq => {
335 let mut list = Vec::new();
336 for ids in pair.into_inner() {
337 match ids.as_rule() {
338 Rule::string => list.push(strip_quotes(ids.as_str()).to_owned()),
339 _ => unimplemented!(),
340 }
341 }
342 return Ok(Seq::Idents(list));
343 }
344 Rule::var_seq => {
345 let mut var_name = String::new();
346 for ids in pair.into_inner() {
347 match ids.as_rule() {
348 Rule::ident => var_name = ids.as_str().to_owned(),
349 _ => unimplemented!(),
350 }
351 }
352 if var_name.is_empty() {
353 return Err(HakuError::SeqVarNameError(text));
354 }
355 return Ok(Seq::Var(var_name));
356 }
357 _ => unimplemented!(),
358 }
359 }
360 unimplemented!()
361}
362
363pub fn build_for(p: Pairs<Rule>) -> Result<Op, HakuError> {
365 let mut seq = Seq::Str(String::new());
366 let mut var = String::new();
367 for s in p {
368 match s.as_rule() {
369 Rule::ident => var = s.as_str().to_string(),
370 Rule::seq => seq = build_seq(s.into_inner())?,
371 _ => {}
372 }
373 }
374 Ok(Op::For(var, seq))
375}
376
377fn build_arg_value(p: Pair<Rule>) -> Result<Op, HakuError> {
379 match p.as_rule() {
380 Rule::int | Rule::hex_int => {
381 if let Ok(i) = s_to_i64(p.as_str()) {
382 return Ok(Op::Int(i));
383 }
384 }
385 Rule::exec => return Ok(Op::Exec(strip_quotes(p.as_str()).to_string())),
386 Rule::string => {
387 for in_p in p.into_inner() {
388 match in_p.as_rule() {
389 Rule::squoted | Rule::dquoted => return Ok(Op::Str(strip_quotes(in_p.as_str()).to_string())),
390 _ => unimplemented!(),
391 }
392 }
393 }
394 Rule::var => return Ok(Op::Var(strip_var_deco(p.as_str()).to_string())),
395 Rule::func => return build_func(p.into_inner()),
396 Rule::dquoted | Rule::squoted => return Ok(Op::Str(strip_quotes(p.as_str()).to_string())),
397 _ => {
398 println!("{:?}", p);
399 unimplemented!();
400 }
401 }
402 unimplemented!()
403}
404
405fn build_arg(p: Pairs<Rule>) -> Result<Op, HakuError> {
407 let mut neg = false;
408 for pair in p {
409 match pair.as_rule() {
410 Rule::not_op => neg = !neg,
411 Rule::arg => {
412 let val = pair.as_str().to_string();
413 if let Some(pp) = pair.into_inner().next() {
414 let op = build_arg_value(pp);
415 if neg {
416 let op = op?;
417 return Ok(Op::Not(vec![op]));
418 } else {
419 return op;
420 }
421 } else {
422 return Err(HakuError::ParseError(val, String::new()));
423 }
424 }
425 _ => {
426 let op = build_arg_value(pair);
427 if neg {
428 let op = op?;
429 return Ok(Op::Not(vec![op]));
430 } else {
431 return op;
432 }
433 }
434 }
435 }
436 unimplemented!()
437}
438
439fn build_arglist(p: Pairs<Rule>) -> Result<Vec<Op>, HakuError> {
441 let mut vec: Vec<Op> = Vec::new();
442 for pair in p {
443 match pair.as_rule() {
444 Rule::arg => vec.push(build_arg(pair.into_inner())?),
445 _ => unimplemented!(),
446 }
447 }
448 Ok(vec)
449}
450
451pub fn build_func(p: Pairs<Rule>) -> Result<Op, HakuError> {
453 let mut name = String::new();
454 for pair in p {
455 match pair.as_rule() {
456 Rule::ident => name = pair.as_str().to_string(),
457 Rule::arglist => {
458 return Ok(Op::Func(name, build_arglist(pair.into_inner())?));
459 }
460 _ => {
461 println!("{:?}", pair);
462 unimplemented!();
463 }
464 }
465 }
466 Ok(Op::Func(name, Vec::new()))
467}
468
469fn build_s_expr(p: Pairs<Rule>) -> Result<Op, HakuError> {
471 let mut v = Vec::new();
472 let mut cmp = String::new();
473 for pair in p {
474 match pair.as_rule() {
475 Rule::arg => v.push(build_arg(pair.into_inner())?),
476 Rule::cmp_op => cmp = pair.as_str().to_string(),
477 _ => {
478 println!("{:?}", pair);
479 unimplemented!();
480 }
481 }
482 }
483 if cmp.is_empty() {
484 Ok(v.pop().unwrap_or_else(|| unreachable!()))
485 } else {
486 Ok(Op::Compare(cmp, v))
487 }
488}
489
490fn build_and_expr(p: Pairs<Rule>) -> Result<Op, HakuError> {
492 let mut v = Vec::new();
493 for pair in p {
494 match pair.as_rule() {
495 Rule::sexpr => {
496 let op = build_s_expr(pair.into_inner())?;
497 v.push(op);
498 }
499 Rule::and_op => {} _ => {
501 println!("{:?}", pair);
502 unimplemented!();
503 }
504 }
505 }
506 Ok(Op::AndExpr(v))
507}
508
509fn build_condition(p: Pairs<Rule>) -> Result<Vec<Op>, HakuError> {
511 let mut v = Vec::new();
512 for pair in p {
513 match pair.as_rule() {
514 Rule::andexpr => v.push(build_and_expr(pair.into_inner())?),
515 Rule::or_op => {} _ => {
517 println!("{:?}", pair);
518 unimplemented!();
519 }
520 }
521 }
522 Ok(v)
523}
524
525fn build_expr(p: Pairs<Rule>) -> Result<Vec<Op>, HakuError> {
527 let mut v: Vec<Op> = Vec::new();
528 for pair in p {
529 match pair.as_rule() {
530 Rule::andexpr => v.push(build_and_expr(pair.into_inner())?),
531 Rule::cond => {
532 let mut cexpr = build_condition(pair.into_inner())?;
533 v.append(&mut cexpr);
534 }
535 _ => {
536 println!("{:?}", pair);
537 unimplemented!();
538 }
539 }
540 }
541 Ok(v)
542}
543
544pub fn build_assign(p: Pairs<Rule>) -> Result<Op, HakuError> {
546 let mut name = String::new();
547 for pair in p {
548 match pair.as_rule() {
549 Rule::ident => name = pair.as_str().to_string(),
550 Rule::assign_expr => {
551 return Ok(Op::Assign(name, build_expr(pair.into_inner())?));
552 }
553 _ => {} }
555 }
556 unreachable!();
557}
558
559pub fn build_def_assign(p: Pairs<Rule>) -> Result<Op, HakuError> {
561 let mut name = String::new();
562 for pair in p {
563 match pair.as_rule() {
564 Rule::ident => name = pair.as_str().to_string(),
565 Rule::assign_expr => {
566 return Ok(Op::DefAssign(name, build_expr(pair.into_inner())?));
567 }
568 _ => {} }
570 }
571 unreachable!();
572}
573
574pub fn build_either_assign(p: Pairs<Rule>) -> Result<Op, HakuError> {
576 let mut name = String::new();
577 let mut exprs = Vec::new();
578 for pair in p {
579 match pair.as_rule() {
580 Rule::ident => name = pair.as_str().to_string(),
581 Rule::either_arg => {
582 let a = build_arg(pair.into_inner())?;
583 exprs.push(a);
584 }
585 _ => {} }
587 }
588 Ok(Op::EitherAssign(false, name, exprs))
589}
590
591pub fn build_either_def_assign(p: Pairs<Rule>) -> Result<Op, HakuError> {
593 let mut name = String::new();
594 let mut exprs = Vec::new();
595 for pair in p {
596 match pair.as_rule() {
597 Rule::ident => name = pair.as_str().to_string(),
598 Rule::either_arg => {
599 let a = build_arg(pair.into_inner())?;
600 exprs.push(a);
601 }
602 _ => {} }
604 }
605 Ok(Op::EitherAssign(true, name, exprs))
606}
607
608pub fn build_if(p: Pairs<Rule>) -> Result<Op, HakuError> {
610 for pair in p {
611 if let Rule::cond = pair.as_rule() {
612 return Ok(Op::If(build_condition(pair.into_inner())?));
613 }
614 }
615 unreachable!()
616}
617
618pub fn build_elseif(p: Pairs<Rule>) -> Result<Op, HakuError> {
620 for pair in p {
621 if let Rule::cond = pair.as_rule() {
622 return Ok(Op::ElseIf(build_condition(pair.into_inner())?));
623 }
624 }
625 unreachable!()
626}
627
628pub fn build_while(p: Pairs<Rule>) -> Result<Op, HakuError> {
630 for pair in p {
631 if let Rule::cond = pair.as_rule() {
632 return Ok(Op::While(build_condition(pair.into_inner())?));
633 }
634 }
635 unreachable!()
636}
637
638pub(crate) fn s_to_i64(s: &str) -> Result<i64, ()> {
639 if !s.starts_with("0x") && !s.starts_with("0X") {
640 if let Ok(i) = s.parse::<i64>() {
641 return Ok(i);
642 }
643 return Err(());
644 }
645 let trimmed = if s.starts_with("0x") { s.trim_start_matches("0x") } else { s.trim_start_matches("0X") };
646 if let Ok(i) = i64::from_str_radix(trimmed, 16) {
647 return Ok(i);
648 }
649 Err(())
650}