1use crate::dict::dict_new;
6use crate::dict::dict_path_insert;
7use crate::dict::dict_path_remove;
8use crate::dict::list_to_dict;
9use crate::interp::Interp;
10use crate::types::*;
11use crate::util;
12use crate::*;
13use std::fs;
14use std::time::Instant;
15
16pub fn cmd_append(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
21 check_args(1, argv, 2, 0, "varName ?value value ...?")?;
22
23 let mut new_string: String = interp
26 .var(&argv[1])
27 .and_then(|val| Ok(val.to_string()))
28 .unwrap_or_else(|_| String::new());
29
30 for item in &argv[2..] {
32 new_string.push_str(item.as_str());
33 }
34
35 interp.set_var_return(&argv[1], new_string.into())
37}
38
39pub fn cmd_array(interp: &mut Interp, context_id: ContextID, argv: &[Value]) -> MoltResult {
41 interp.call_subcommand(context_id, argv, 1, &ARRAY_SUBCOMMANDS)
42}
43
44const ARRAY_SUBCOMMANDS: [Subcommand; 6] = [
45 Subcommand("exists", cmd_array_exists),
46 Subcommand("get", cmd_array_get),
47 Subcommand("names", cmd_array_names),
48 Subcommand("set", cmd_array_set),
49 Subcommand("size", cmd_array_size),
50 Subcommand("unset", cmd_array_unset),
51];
52
53pub fn cmd_array_exists(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
55 check_args(2, argv, 3, 3, "arrayName")?;
56 molt_ok!(Value::from(interp.array_exists(argv[2].as_str())))
57}
58
59pub fn cmd_array_names(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
62 check_args(2, argv, 3, 3, "arrayName")?;
63 molt_ok!(Value::from(interp.array_names(argv[2].as_str())))
64}
65
66pub fn cmd_array_get(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
69 check_args(2, argv, 3, 3, "arrayName")?;
70 molt_ok!(Value::from(interp.array_get(argv[2].as_str())))
71}
72
73pub fn cmd_array_set(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
75 check_args(2, argv, 4, 4, "arrayName list")?;
76
77 let var_name = argv[2].as_var_name();
81
82 if var_name.index().is_none() {
83 interp.array_set(var_name.name(), &*argv[3].as_list()?)
84 } else {
85 interp.array_set(var_name.name(), &*Value::empty().as_list()?)?;
89
90 molt_err!("can't set \"{}\": variable isn't array", &argv[2])
93 }
94}
95
96pub fn cmd_array_size(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
98 check_args(2, argv, 3, 3, "arrayName")?;
99 molt_ok!(Value::from(interp.array_size(argv[2].as_str()) as MoltInt))
100}
101
102pub fn cmd_array_unset(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
104 check_args(2, argv, 3, 4, "arrayName ?index?")?;
105
106 if argv.len() == 3 {
107 interp.array_unset(argv[2].as_str());
108 } else {
109 interp.unset_element(argv[2].as_str(), argv[3].as_str());
110 }
111 molt_ok!()
112}
113
114pub fn cmd_assert_eq(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
119 check_args(1, argv, 3, 3, "received expected")?;
120
121 if argv[1] == argv[2] {
122 molt_ok!()
123 } else {
124 molt_err!(
125 "assertion failed: received \"{}\", expected \"{}\".",
126 argv[1],
127 argv[2]
128 )
129 }
130}
131
132pub fn cmd_break(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
137 check_args(1, argv, 1, 1, "")?;
138
139 Err(Exception::molt_break())
140}
141
142pub fn cmd_catch(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
148 check_args(1, argv, 2, 4, "script ?resultVarName? ?optionsVarName?")?;
149
150 let result = interp.eval_value(&argv[1]);
152
153 let (code, value) = match &result {
154 Ok(val) => (0, val.clone()),
155 Err(exception) => match exception.code() {
156 ResultCode::Okay => unreachable!(), ResultCode::Error => (1, exception.value()),
158 ResultCode::Return => (2, exception.value()),
159 ResultCode::Break => (3, exception.value()),
160 ResultCode::Continue => (4, exception.value()),
161 ResultCode::Other(_) => unimplemented!(), },
163 };
164
165 if argv.len() >= 3 {
166 interp.set_var(&argv[2], value)?;
167 }
168
169 if argv.len() == 4 {
170 interp.set_var(&argv[3], interp.return_options(&result))?;
171 }
172
173 Ok(Value::from(code))
174}
175
176pub fn cmd_continue(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
180 check_args(1, argv, 1, 1, "")?;
181
182 Err(Exception::molt_continue())
183}
184
185pub fn cmd_dict(interp: &mut Interp, context_id: ContextID, argv: &[Value]) -> MoltResult {
187 interp.call_subcommand(context_id, argv, 1, &DICT_SUBCOMMANDS)
188}
189
190const DICT_SUBCOMMANDS: [Subcommand; 9] = [
191 Subcommand("create", cmd_dict_new),
192 Subcommand("exists", cmd_dict_exists),
193 Subcommand("get", cmd_dict_get),
194 Subcommand("keys", cmd_dict_keys),
195 Subcommand("remove", cmd_dict_remove),
196 Subcommand("set", cmd_dict_set),
197 Subcommand("size", cmd_dict_size),
198 Subcommand("unset", cmd_dict_unset),
199 Subcommand("values", cmd_dict_values),
200];
201
202fn cmd_dict_new(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
204 if argv.len() % 2 != 0 {
206 return molt_err!(
207 "wrong # args: should be \"{} {}\"",
208 Value::from(&argv[0..2]).to_string(),
209 "?key value?"
210 );
211 }
212
213 if argv.len() > 2 {
215 molt_ok!(Value::from(list_to_dict(&argv[2..])))
216 } else {
217 molt_ok!(Value::from(dict_new()))
218 }
219}
220
221fn cmd_dict_exists(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
223 check_args(2, argv, 4, 0, "dictionary key ?key ...?")?;
224
225 let mut value: Value = argv[2].clone();
226 let indices = &argv[3..];
227
228 for index in indices {
229 if let Ok(dict) = value.as_dict() {
230 if let Some(val) = dict.get(index) {
231 value = val.clone();
232 } else {
233 return molt_ok!(false);
234 }
235 } else {
236 return molt_ok!(false);
237 }
238 }
239
240 molt_ok!(true)
241}
242
243fn cmd_dict_get(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
245 check_args(2, argv, 3, 0, "dictionary ?key ...?")?;
246
247 let mut value: Value = argv[2].clone();
248 let indices = &argv[3..];
249
250 for index in indices {
251 let dict = value.as_dict()?;
252
253 if let Some(val) = dict.get(index) {
254 value = val.clone();
255 } else {
256 return molt_err!("key \"{}\" not known in dictionary", index);
257 }
258 }
259
260 molt_ok!(value)
261}
262
263fn cmd_dict_keys(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
266 check_args(2, argv, 3, 3, "dictionary")?;
267
268 let dict = argv[2].as_dict()?;
269 let keys: MoltList = dict.keys().cloned().collect();
270 molt_ok!(keys)
271}
272
273fn cmd_dict_remove(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
275 check_args(2, argv, 3, 0, "dictionary ?key ...?")?;
276
277 let mut dict = (&*argv[2].as_dict()?).clone();
279
280 for key in &argv[3..] {
282 dict.shift_remove(key);
284 }
285
286 molt_ok!(dict)
288}
289
290fn cmd_dict_set(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
292 check_args(2, argv, 5, 0, "dictVarName key ?key ...? value")?;
293
294 let value = &argv[argv.len() - 1];
295 let keys = &argv[3..(argv.len() - 1)];
296
297 if let Ok(old_dict_val) = interp.var(&argv[2]) {
298 interp.set_var_return(&argv[2], dict_path_insert(&old_dict_val, keys, value)?)
299 } else {
300 let new_val = Value::from(dict_new());
301 interp.set_var_return(&argv[2], dict_path_insert(&new_val, keys, value)?)
302 }
303}
304
305fn cmd_dict_size(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
307 check_args(2, argv, 3, 3, "dictionary")?;
308
309 let dict = argv[2].as_dict()?;
310 molt_ok!(dict.len() as MoltInt)
311}
312
313fn cmd_dict_unset(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
315 check_args(2, argv, 4, 0, "dictVarName key ?key ...?")?;
316
317 let keys = &argv[3..];
318
319 if let Ok(old_dict_val) = interp.var(&argv[2]) {
320 interp.set_var_return(&argv[2], dict_path_remove(&old_dict_val, keys)?)
321 } else {
322 let new_val = Value::from(dict_new());
323 interp.set_var_return(&argv[2], dict_path_remove(&new_val, keys)?)
324 }
325}
326
327fn cmd_dict_values(_: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
330 check_args(2, argv, 3, 3, "dictionary")?;
331
332 let dict = argv[2].as_dict()?;
333 let values: MoltList = dict.values().cloned().collect();
334 molt_ok!(values)
335}
336
337pub fn cmd_error(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
345 check_args(1, argv, 2, 2, "message")?;
346
347 molt_err!(argv[1].clone())
348}
349
350pub fn cmd_exit(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
356 check_args(1, argv, 1, 2, "?returnCode?")?;
357
358 let return_code: MoltInt = if argv.len() == 1 {
359 0
360 } else {
361 argv[1].as_int()?
362 };
363
364 std::process::exit(return_code as i32)
365}
366
367pub fn cmd_expr(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
376 check_args(1, argv, 2, 2, "expr")?;
377
378 interp.expr(&argv[1])
379}
380
381pub fn cmd_for(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
386 check_args(1, argv, 5, 5, "start test next command")?;
387
388 let start = &argv[1];
389 let test = &argv[2];
390 let next = &argv[3];
391 let command = &argv[4];
392
393 interp.eval_value(start)?;
395
396 while interp.expr_bool(test)? {
397 let result = interp.eval_value(command);
398
399 if let Err(exception) = result {
400 match exception.code() {
401 ResultCode::Break => break,
402 ResultCode::Continue => (),
403 _ => return Err(exception),
404 }
405 }
406
407 let result = interp.eval_value(next);
409
410 if let Err(exception) = result {
411 match exception.code() {
412 ResultCode::Break => break,
413 ResultCode::Continue => {
414 return molt_err!("invoked \"continue\" outside of a loop");
415 }
416 _ => return Err(exception),
417 }
418 }
419 }
420
421 molt_ok!()
422}
423
424pub fn cmd_foreach(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
435 check_args(1, argv, 4, 4, "varList list body")?;
436
437 let var_list = &*argv[1].as_list()?;
438 let list = &*argv[2].as_list()?;
439 let body = &argv[3];
440
441 let mut i = 0;
442
443 while i < list.len() {
444 for var in var_list {
445 if i < list.len() {
446 interp.set_var(&var, list[i].clone())?;
447 i += 1;
448 } else {
449 interp.set_var(&var, Value::empty())?;
450 }
451 }
452
453 let result = interp.eval_value(body);
454
455 if let Err(exception) = result {
456 match exception.code() {
457 ResultCode::Break => break,
458 ResultCode::Continue => (),
459 _ => return Err(exception),
460 }
461 }
462 }
463
464 molt_ok!()
465}
466
467pub fn cmd_global(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
472 if interp.scope_level() > 0 {
476 for name in &argv[1..] {
477 interp.upvar(0, name.as_str());
479 }
480 }
481 molt_ok!()
482}
483
484#[derive(Eq, PartialEq, Debug)]
485enum IfWants {
486 Expr,
487 ThenBody,
488 SkipThenClause,
489 ElseClause,
490 ElseBody,
491}
492
493pub fn cmd_if(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
503 let mut argi = 1;
504 let mut wants = IfWants::Expr;
505
506 while argi < argv.len() {
507 match wants {
508 IfWants::Expr => {
509 wants = if interp.expr_bool(&argv[argi])? {
510 IfWants::ThenBody
511 } else {
512 IfWants::SkipThenClause
513 };
514 }
515 IfWants::ThenBody => {
516 if argv[argi].as_str() == "then" {
517 argi += 1;
518 }
519
520 if argi < argv.len() {
521 return interp.eval_value(&argv[argi]);
522 } else {
523 break;
524 }
525 }
526 IfWants::SkipThenClause => {
527 if argv[argi].as_str() == "then" {
528 argi += 1;
529 }
530
531 if argi < argv.len() {
532 argi += 1;
533 wants = IfWants::ElseClause;
534 }
535 continue;
536 }
537 IfWants::ElseClause => {
538 if argv[argi].as_str() == "elseif" {
539 wants = IfWants::Expr;
540 } else {
541 wants = IfWants::ElseBody;
542 continue;
543 }
544 }
545 IfWants::ElseBody => {
546 if argv[argi].as_str() == "else" {
547 argi += 1;
548
549 if argi == argv.len() {
551 return molt_err!(
552 "wrong # args: no script following after \"{}\" argument",
553 argv[argi - 1]
554 );
555 }
556 }
557
558 if argi < argv.len() {
559 return interp.eval_value(&argv[argi]);
560 } else {
561 break;
562 }
563 }
564 }
565
566 argi += 1;
567 }
568
569 if argi < argv.len() {
570 return molt_err!("wrong # args: extra words after \"else\" clause in \"if\" command");
571 } else if wants == IfWants::Expr {
572 return molt_err!(
573 "wrong # args: no expression after \"{}\" argument",
574 argv[argi - 1]
575 );
576 } else if wants == IfWants::ThenBody || wants == IfWants::SkipThenClause {
577 return molt_err!(
578 "wrong # args: no script following after \"{}\" argument",
579 argv[argi - 1]
580 );
581 } else {
582 molt_ok!() }
585}
586
587pub fn cmd_incr(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
591 check_args(1, argv, 2, 3, "varName ?increment?")?;
592
593 let increment: MoltInt = if argv.len() == 3 {
594 argv[2].as_int()?
595 } else {
596 1
597 };
598
599 let new_value = increment
600 + interp
601 .var(&argv[1])
602 .and_then(|val| Ok(val.as_int()?))
603 .unwrap_or_else(|_| 0);
604
605 interp.set_var_return(&argv[1], new_value.into())
606}
607
608pub fn cmd_info(interp: &mut Interp, context_id: ContextID, argv: &[Value]) -> MoltResult {
610 interp.call_subcommand(context_id, argv, 1, &INFO_SUBCOMMANDS)
611}
612
613const INFO_SUBCOMMANDS: [Subcommand; 11] = [
614 Subcommand("args", cmd_info_args),
615 Subcommand("body", cmd_info_body),
616 Subcommand("cmdtype", cmd_info_cmdtype),
617 Subcommand("commands", cmd_info_commands),
618 Subcommand("complete", cmd_info_complete),
619 Subcommand("default", cmd_info_default),
620 Subcommand("exists", cmd_info_exists),
621 Subcommand("globals", cmd_info_globals),
622 Subcommand("locals", cmd_info_locals),
623 Subcommand("procs", cmd_info_procs),
624 Subcommand("vars", cmd_info_vars),
625];
626
627pub fn cmd_info_args(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
629 check_args(2, argv, 3, 3, "procname")?;
630 interp.proc_args(&argv[2].as_str())
631}
632
633pub fn cmd_info_body(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
635 check_args(2, argv, 3, 3, "procname")?;
636 interp.proc_body(&argv[2].as_str())
637}
638
639pub fn cmd_info_cmdtype(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
641 check_args(2, argv, 3, 3, "command")?;
642 interp.command_type(&argv[2].as_str())
643}
644
645pub fn cmd_info_commands(interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
647 molt_ok!(Value::from(interp.command_names()))
648}
649
650pub fn cmd_info_default(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
652 check_args(2, argv, 5, 5, "procname arg varname")?;
653
654 if let Some(val) = interp.proc_default(&argv[2].as_str(), &argv[3].as_str())? {
655 interp.set_var(&argv[4], val)?;
656 molt_ok!(1)
657 } else {
658 interp.set_var(&argv[4], Value::empty())?;
659 molt_ok!(0)
660 }
661}
662
663pub fn cmd_info_exists(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
665 check_args(2, argv, 3, 3, "varname")?;
666 Ok(interp.var_exists(&argv[2]).into())
667}
668
669pub fn cmd_info_complete(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
671 check_args(2, argv, 3, 3, "command")?;
672
673 if interp.complete(argv[2].as_str()) {
674 molt_ok!(true)
675 } else {
676 molt_ok!(false)
677 }
678}
679
680pub fn cmd_info_globals(interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
683 molt_ok!(Value::from(interp.vars_in_global_scope()))
684}
685
686pub fn cmd_info_locals(interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
689 molt_ok!(Value::from(interp.vars_in_local_scope()))
690}
691
692pub fn cmd_info_procs(interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
694 molt_ok!(Value::from(interp.proc_names()))
695}
696
697pub fn cmd_info_vars(interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
700 molt_ok!(Value::from(interp.vars_in_scope()))
701}
702
703pub fn cmd_join(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
707 check_args(1, argv, 2, 3, "list ?joinString?")?;
708
709 let list = &argv[1].as_list()?;
710
711 let join_string = if argv.len() == 3 {
712 argv[2].to_string()
713 } else {
714 " ".to_string()
715 };
716
717 let list: Vec<String> = list.iter().map(|v| v.to_string()).collect();
719
720 molt_ok!(list.join(&join_string))
721}
722
723pub fn cmd_lappend(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
728 check_args(1, argv, 2, 0, "varName ?value ...?")?;
729
730 let var_result = interp.var(&argv[1]);
731
732 let mut list: MoltList = if var_result.is_ok() {
733 var_result.expect("got value").to_list()?
734 } else {
735 Vec::new()
736 };
737
738 let mut values = argv[2..].to_owned();
739 list.append(&mut values);
740 interp.set_var_return(&argv[1], Value::from(list))
741}
742
743pub fn cmd_lindex(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
747 check_args(1, argv, 2, 0, "list ?index ...?")?;
748
749 if argv.len() != 3 {
750 lindex_into(&argv[1], &argv[2..])
751 } else {
752 lindex_into(&argv[1], &*argv[2].as_list()?)
753 }
754}
755
756pub fn lindex_into(list: &Value, indices: &[Value]) -> MoltResult {
757 let mut value: Value = list.clone();
758
759 for index_val in indices {
760 let list = value.as_list()?;
761 let index = index_val.as_int()?;
762
763 value = if index < 0 || index as usize >= list.len() {
764 Value::empty()
765 } else {
766 list[index as usize].clone()
767 };
768 }
769
770 molt_ok!(value)
771}
772
773pub fn cmd_list(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
777 molt_ok!(&argv[1..])
779}
780
781pub fn cmd_llength(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
785 check_args(1, argv, 2, 2, "list")?;
786
787 molt_ok!(argv[1].as_list()?.len() as MoltInt)
788}
789
790pub fn cmd_pdump(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
794 check_args(1, argv, 1, 1, "")?;
795
796 interp.profile_dump();
797
798 molt_ok!()
799}
800
801pub fn cmd_pclear(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
805 check_args(1, argv, 1, 1, "")?;
806
807 interp.profile_clear();
808
809 molt_ok!()
810}
811
812pub fn cmd_proc(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
816 check_args(1, argv, 4, 4, "name args body")?;
817
818 let name = argv[1].as_str();
820 let args = &*argv[2].as_list()?;
821
822 for arg in args {
824 let vec = arg.as_list()?;
825
826 if vec.is_empty() {
827 return molt_err!("argument with no name");
828 } else if vec.len() > 2 {
829 return molt_err!("too many fields in argument specifier \"{}\"", arg);
830 }
831 }
832
833 interp.add_proc(name, args, &argv[3]);
835
836 molt_ok!()
837}
838
839pub fn cmd_puts(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
848 check_args(1, argv, 2, 2, "string")?;
849
850 println!("{}", argv[1]);
851 molt_ok!()
852}
853
854pub fn cmd_rename(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
859 check_args(1, argv, 3, 3, "oldName newName")?;
860
861 let old_name = argv[1].as_str();
863 let new_name = argv[2].as_str();
864
865 if !interp.has_command(old_name) {
866 return molt_err!("can't rename \"{}\": command doesn't exist", old_name);
867 }
868
869 if new_name.is_empty() {
871 interp.remove_command(old_name);
872 } else {
873 interp.rename_command(old_name, new_name);
874 }
875
876 molt_ok!()
877}
878
879pub fn cmd_return(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
888 check_args(1, argv, 1, 0, "?options...? ?value?")?;
889
890 let mut code = ResultCode::Okay;
892 let mut level: MoltInt = 1;
893 let mut error_code: Option<Value> = None;
894 let mut error_info: Option<Value> = None;
895
896 if argv.len() == 1 {
898 return Err(Exception::molt_return_ext(
899 Value::empty(),
900 level as usize,
901 code,
902 ));
903 }
904
905 let return_value: Value;
908
909 let opt_args: &[Value] = if argv.len() % 2 == 0 {
910 return_value = argv[argv.len() - 1].clone();
912 &argv[1..argv.len() - 1]
913 } else {
914 return_value = Value::empty();
916 &argv[1..argv.len()]
917 };
918
919 let mut queue = opt_args.iter();
921
922 while let Some(opt) = queue.next() {
923 let val = queue
926 .next()
927 .expect("missing option value: coding error in cmd_return");
928
929 match opt.as_str() {
930 "-code" => {
931 code = ResultCode::from_value(val)?;
932 }
933 "-errorcode" => {
934 error_code = Some(val.clone());
935 }
936 "-errorinfo" => {
937 error_info = Some(val.clone());
938 }
939 "-level" => {
940 level = val.as_int()?;
943 }
944 _ => return molt_err!("invalid return option: \"{}\"", opt),
946 }
947 }
948
949 if code == ResultCode::Error {
951 Err(Exception::molt_return_err(
952 return_value,
953 level as usize,
954 error_code,
955 error_info,
956 ))
957 } else if level == 0 && code == ResultCode::Okay {
958 Ok(return_value)
960 } else {
961 Err(Exception::molt_return_ext(
962 return_value,
963 level as usize,
964 code,
965 ))
966 }
967}
968
969pub fn cmd_set(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
975 check_args(1, argv, 2, 3, "varName ?newValue?")?;
976
977 if argv.len() == 3 {
978 interp.set_var_return(&argv[1], argv[2].clone())
979 } else {
980 molt_ok!(interp.var(&argv[1])?)
981 }
982}
983
984pub fn cmd_source(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
988 check_args(1, argv, 2, 2, "filename")?;
989
990 let filename = argv[1].as_str();
991
992 match fs::read_to_string(filename) {
993 Ok(script) => interp.eval(&script),
994 Err(e) => molt_err!("couldn't read file \"{}\": {}", filename, e),
995 }
996}
997
998pub fn cmd_string(interp: &mut Interp, context_id: ContextID, argv: &[Value]) -> MoltResult {
1000 interp.call_subcommand(context_id, argv, 1, &STRING_SUBCOMMANDS)
1001}
1002
1003const STRING_SUBCOMMANDS: [Subcommand; 4] = [
1004 Subcommand("cat", cmd_string_cat),
1005 Subcommand("compare", cmd_string_compare),
1006 Subcommand("equal", cmd_string_equal),
1007 Subcommand("length", cmd_string_length),
1011 ];
1022
1023#[allow(unused)]
1025pub fn cmd_string_todo(_interp: &mut Interp, _: ContextID, _argv: &[Value]) -> MoltResult {
1026 molt_err!("TODO")
1027}
1028
1029pub fn cmd_string_cat(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1031 let mut buff = String::new();
1032
1033 for arg in &argv[2..] {
1034 buff.push_str(arg.as_str());
1035 }
1036
1037 molt_ok!(buff)
1038}
1039
1040pub fn cmd_string_compare(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1042 check_args(2, argv, 4, 7, "?-nocase? ?-length length? string1 string2")?;
1043
1044 let arglen = argv.len();
1046 let mut nocase = false;
1047 let mut length: Option<MoltInt> = None;
1048
1049 let opt_args = &argv[2..arglen - 2];
1051 let mut queue = opt_args.iter();
1052
1053 while let Some(opt) = queue.next() {
1054 match opt.as_str() {
1055 "-nocase" => nocase = true,
1056 "-length" => {
1057 if let Some(val) = queue.next() {
1058 length = Some(val.as_int()?);
1059 } else {
1060 return molt_err!("wrong # args: should be \"string compare ?-nocase? ?-length length? string1 string2\"");
1061 }
1062 }
1063 _ => return molt_err!("bad option \"{}\": must be -nocase or -length", opt),
1064 }
1065 }
1066
1067 if nocase {
1068 let val1 = &argv[arglen - 2];
1069 let val2 = &argv[arglen - 1];
1070
1071 let val1 = Value::from(val1.as_str().to_lowercase());
1073 let val2 = Value::from(val2.as_str().to_lowercase());
1074
1075 molt_ok!(util::compare_len(val1.as_str(), val2.as_str(), length)?)
1076 } else {
1077 molt_ok!(util::compare_len(argv[arglen - 2].as_str(), argv[arglen - 1].as_str(), length)?)
1078 }
1079}
1080
1081pub fn cmd_string_equal(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1083 check_args(2, argv, 4, 7, "?-nocase? ?-length length? string1 string2")?;
1084
1085 let arglen = argv.len();
1087 let mut nocase = false;
1088 let mut length: Option<MoltInt> = None;
1089
1090 let opt_args = &argv[2..arglen - 2];
1092 let mut queue = opt_args.iter();
1093
1094 while let Some(opt) = queue.next() {
1095 match opt.as_str() {
1096 "-nocase" => nocase = true,
1097 "-length" => {
1098 if let Some(val) = queue.next() {
1099 length = Some(val.as_int()?);
1100 } else {
1101 return molt_err!("wrong # args: should be \"string equal ?-nocase? ?-length length? string1 string2\"");
1102 }
1103 }
1104 _ => return molt_err!("bad option \"{}\": must be -nocase or -length", opt),
1105 }
1106 }
1107
1108 if nocase {
1109 let val1 = &argv[arglen - 2];
1110 let val2 = &argv[arglen - 1];
1111
1112 let val1 = Value::from(val1.as_str().to_lowercase());
1114 let val2 = Value::from(val2.as_str().to_lowercase());
1115
1116 let flag = util::compare_len(val1.as_str(), val2.as_str(), length)? == 0;
1117 molt_ok!(flag)
1118 } else {
1119 let flag = util::compare_len(argv[arglen - 2].as_str(), argv[arglen - 1].as_str(), length)? == 0;
1120 molt_ok!(flag)
1121 }
1122}
1123
1124pub fn cmd_string_length(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1126 check_args(2, argv, 3, 3, "string")?;
1127
1128 let len: MoltInt = argv[2].as_str().chars().count() as MoltInt;
1129 molt_ok!(len)
1130}
1131
1132pub fn cmd_throw(_interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1136 check_args(1, argv, 3, 3, "type message")?;
1137
1138 Err(Exception::molt_err2(argv[1].clone(), argv[2].clone()))
1139}
1140
1141pub fn cmd_time(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1146 check_args(1, argv, 2, 3, "command ?count?")?;
1147
1148 let command = &argv[1];
1149
1150 let count = if argv.len() == 3 {
1151 argv[2].as_int()?
1152 } else {
1153 1
1154 };
1155
1156 let start = Instant::now();
1157
1158 for _i in 0..count {
1159 let result = interp.eval_value(command);
1160 if result.is_err() {
1161 return result;
1162 }
1163 }
1164
1165 let span = start.elapsed();
1166
1167 let avg = if count > 0 {
1168 span.as_nanos() / (count as u128)
1169 } else {
1170 0
1171 } as MoltInt;
1172
1173 molt_ok!("{} nanoseconds per iteration", avg)
1174}
1175
1176pub fn cmd_unset(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1182 check_args(1, argv, 1, 0, "?-nocomplain? ?--? ?name name name...?")?;
1183
1184 let mut options_ok = true;
1185
1186 for arg in argv {
1187 let var = arg.as_str();
1188
1189 if options_ok {
1190 if var == "--" {
1191 options_ok = false;
1192 continue;
1193 } else if var == "-nocomplain" {
1194 continue;
1195 }
1196 }
1197
1198 interp.unset_var(arg);
1199 }
1200
1201 molt_ok!()
1202}
1203
1204pub fn cmd_while(interp: &mut Interp, _: ContextID, argv: &[Value]) -> MoltResult {
1209 check_args(1, argv, 3, 3, "test command")?;
1210
1211 while interp.expr_bool(&argv[1])? {
1212 let result = interp.eval_value(&argv[2]);
1213
1214 if let Err(exception) = result {
1215 match exception.code() {
1216 ResultCode::Break => break,
1217 ResultCode::Continue => (),
1218 _ => return Err(exception),
1219 }
1220 }
1221 }
1222
1223 molt_ok!()
1224}