1#[macro_export]
43macro_rules! molt_ok {
44 () => (
45 Ok($crate::Value::empty())
46 );
47 ($arg:expr) => (
48 Ok($crate::Value::from($arg))
49 );
50 ($($arg:tt)*) => (
51 Ok($crate::Value::from(format!($($arg)*)))
52 )
53}
54
55#[macro_export]
97macro_rules! molt_err {
98 ($arg:expr) => (
99 Err($crate::Exception::molt_err($crate::Value::from($arg)))
100 );
101 ($($arg:tt)*) => (
102 Err($crate::Exception::molt_err($crate::Value::from(format!($($arg)*))))
103 )
104}
105
106#[macro_export]
107macro_rules! molt_err_help {
108 ($arg:expr) => {{
109 let mut e = $crate::Exception::molt_err($crate::Value::from($arg));
110 e.to_help();
111 Err(e)
112 }};
113 ($($arg:tt)*) => {{
114 let mut e = $crate::Exception::molt_err($crate::Value::from(format!($($arg)*)));
115 e.to_help();
116 Err(e)
117 }}
118}
119
120#[macro_export]
121macro_rules! molt_err_uncompleted {
122 ($arg:expr) => {{
123 let mut e = $crate::Exception::molt_err($crate::Value::from($arg));
124 e.to_uncomplete();
125 Err(e)
126 }};
127 ($($arg:tt)*) => {{
128 let mut e = $crate::Exception::molt_err($crate::Value::from(format!($($arg)*)));
129 e.to_uncomplete();
130 Err(e)
131 }}
132}
133
134#[macro_export]
180macro_rules! molt_throw {
181 ($code:expr, $msg:expr) => (
182 Err($crate::Exception::molt_err2($crate::Value::from($code), $crate::Value::from($msg)))
183 );
184 ($code:expr, $($arg:tt)*) => (
185 Err($crate::Exception::molt_err2($crate::Value::from($code), $crate::Value::from(format!($($arg)*))))
186 )
187}
188
189#[macro_export]
190macro_rules! join_strings {
191 () => {
192 ""
193 };
194 ($a:expr $(,)?) => {
195 $a
196 };
197 ($a:expr, $b:expr $(,)?) => {
198 concat!($a, " or ", $b)
199 };
200 ($a:expr, $($rest:expr),+ $(,)?) => {
201 concat!($a, ", ", join_strings!($($rest),+))
202 };
203}
204
205#[macro_export]
232macro_rules! _gen_subcommand_generic {
233 ($subc:expr, [ $( ($cmd_name:tt, $cmd_func:expr$(,)?) ),* $(,)?] $(,)?) => {
234 {
235 #[inline]
236 fn f<Ctx:'static>(interp: &mut $crate::prelude::Interp<Ctx>, argv: &[$crate::prelude::Value]) -> $crate::prelude::MoltResult {
237 check_args($subc, argv, $subc + 1, 0, "subcommand ?arg ...?")?;
238 let sub_name = argv[$subc].as_str();
239 match sub_name {
240 $(
241 $cmd_name => $cmd_func(interp, argv),
242 )*
243 _ => molt_err!("unknown or ambiguous subcommand \"{}\", must be:\n{}.", sub_name, join_strings!( $($cmd_name,)* )),
244 }
245 }
246 f
247 }
248 }
249}
250
251#[macro_export]
278macro_rules! gen_subcommand {
279 ($ctx_type:ty, $subc:expr, [ $( ($cmd_name:tt, $cmd_space:tt, $cmd_func:expr, $cmd_help:expr$(,)?) ),* $(,)?] $(,)?) => {
280 {
281 #[inline]
282 fn f(interp: &mut $crate::prelude::Interp<$ctx_type>, argv: &[$crate::prelude::Value]) -> $crate::prelude::MoltResult {
283 check_args($subc, argv, $subc + 1, 0, "subcommand ?arg ...?")?;
284 let sub_name = argv[$subc].as_str();
285 const HELP_MSG: &str = join_helps_subcmd!( $( [$cmd_name,$cmd_space,$cmd_help], )* );
286 match sub_name {
287 $(
288 $cmd_name => $cmd_func(interp, argv),
289 )*
290 "-help" => molt_ok!("usage of{}:\n{}",argv[0..$subc].iter().map(|v|v.as_str()).collect::<Vec<&str>>().join(" "),HELP_MSG),
291 _ => molt_err_help!("unknown subcommand in \"{} {}\", usage:\n{}", argv[0..$subc].iter().map(|v|v.as_str()).collect::<Vec<&str>>().join(" "),sub_name,HELP_MSG ),
292 }
293 }
294 f
295 }
296 }
297}
298
299#[macro_export]
300macro_rules! join_helps_subcmd {
301 ( ) => {
302 ""
303 };
304 ( [$first:expr, $second:expr, $third:expr]$(,)? ) => {
306 concat!(" ", $first, " ", $second, $third, "\n -help")
307 };
308 ( [$first:expr, $second:expr, $third:expr], $( [$rest_first:expr, $rest_second:expr, $rest_third:expr] ),+$(,)? ) => {
310 concat!(
311 " ", $first, " ", $second, $third, "\n",
312 join_helps_subcmd!($( [$rest_first, $rest_second, $rest_third] ),+)
313 )
314 };
315}
316
317#[macro_export]
318macro_rules! join_helps {
319 ( ) => {
320 ""
321 };
322 ( [$first:expr, $second:expr, $third:expr]$(,)? ) => {
324 concat!(" ", $first, " ", $second, $third, "\n help [-all]")
325 };
326 ( [$first:expr, $second:expr, $third:expr], $( [$rest_first:expr, $rest_second:expr, $rest_third:expr] ),+$(,)? ) => {
328 concat!(
329 " ", $first, " ", $second, $third, "\n",
330 join_helps!($( [$rest_first, $rest_second, $rest_third] ),+)
331 )
332 };
333}
334
335#[macro_export]
336macro_rules! gen_command {
337 ($ctx_type:ty, [ $( ($native_name:tt, $native_func:expr $(,)?) ),* $(,)?], [ $( ($embedded_name:tt, $embedded_space:tt, $embedded_func:expr, $embedded_help:tt $(,)?) ),* $(,)?] $(,)?) => {
338 $crate::prelude::Command::new(
339 {fn f(name: &str, interp: &mut $crate::prelude::Interp<$ctx_type>, argv: &[$crate::prelude::Value]) -> $crate::prelude::MoltResult {
340 const HELP_MSG: &str = join_helps!( $( [$embedded_name,$embedded_space,$embedded_help], )* );
341 match name {
342 $crate::prelude::_APPEND => $crate::prelude::cmd_append(interp, argv),
344 $crate::prelude::_ARRAY => $crate::prelude::cmd_array(interp, argv),
345 $crate::prelude::_ASSERT_EQ => $crate::prelude::cmd_assert_eq(interp, argv),
346 $crate::prelude::_BREAK => $crate::prelude::cmd_break(interp, argv),
347 $crate::prelude::_CATCH => $crate::prelude::cmd_catch(interp, argv),
348 $crate::prelude::_CONTINUE => $crate::prelude::cmd_continue(interp, argv),
349 $crate::prelude::_DICT => $crate::prelude::cmd_dict(interp, argv),
350 $crate::prelude::_ERROR => $crate::prelude::cmd_error(interp, argv),
351 $crate::prelude::_EXPR => $crate::prelude::cmd_expr(interp, argv),
352 $crate::prelude::_FOR => $crate::prelude::cmd_for(interp, argv),
353 $crate::prelude::_FOREACH => $crate::prelude::cmd_foreach(interp, argv),
354 $crate::prelude::_GLOBAL => $crate::prelude::cmd_global(interp, argv),
355 $crate::prelude::_IF => $crate::prelude::cmd_if(interp, argv),
356 $crate::prelude::_INCR => $crate::prelude::cmd_incr(interp, argv),
357 $crate::prelude::_INFO => $crate::prelude::cmd_info(interp, argv),
358 $crate::prelude::_JOIN => $crate::prelude::cmd_join(interp, argv),
359 $crate::prelude::_LAPPEND => $crate::prelude::cmd_lappend(interp, argv),
360 $crate::prelude::_LINDEX => $crate::prelude::cmd_lindex(interp, argv),
361 $crate::prelude::_LIST => $crate::prelude::cmd_list(interp, argv),
362 $crate::prelude::_LLENGTH => $crate::prelude::cmd_llength(interp, argv),
363 $crate::prelude::_PROC => $crate::prelude::cmd_proc(interp, argv),
364 $crate::prelude::_PUTS => $crate::prelude::cmd_puts(interp, argv),
365 $crate::prelude::_RENAME => $crate::prelude::cmd_rename(interp, argv),
366 $crate::prelude::_RETURN => $crate::prelude::cmd_return(interp, argv),
367 $crate::prelude::_SET => $crate::prelude::cmd_set(interp, argv),
368 $crate::prelude::_STRING => $crate::prelude::cmd_string(interp, argv),
369 $crate::prelude::_THROW => $crate::prelude::cmd_throw(interp, argv),
370 $crate::prelude::_TIME => $crate::prelude::cmd_time(interp, argv),
371 $crate::prelude::_UNSET => $crate::prelude::cmd_unset(interp, argv),
372 $crate::prelude::_WHILE => $crate::prelude::cmd_while(interp, argv),
373 "help" => {
374 if let Some(v)= argv.get(1){
375 if v.as_str()=="-all"{
376 let proc_command_names = interp.proc_command_names();
377 if proc_command_names.is_empty(){
378 return molt_ok!("usage of {}:\ntcl:\n {}\n{}:\n{}", interp.name,interp.native_command_names(),interp.name,HELP_MSG);
379 }else{
380 return molt_ok!("usage of {}:\ntcl:\n {}\n{}:\n{}\nprocedure:\n {}", interp.name,interp.native_command_names(),interp.name,HELP_MSG,proc_command_names);
381 }
382 }
383 }
384 molt_ok!("usage of {}:\n{}",interp.name,HELP_MSG)},
385 $(
387 $native_name => $native_func(interp, argv),
388 )*
389 $(
391 $embedded_name => $embedded_func(interp, argv),
392 )*
393 other => {
395 if let Some(proc) = interp.get_proc(other) {
396 proc.clone().execute(interp, argv)
397 } else {
398 let proc_command_names = interp.proc_command_names();
399 if proc_command_names.is_empty(){
400 molt_err_help!("unknown command \"{}\", valid commands:\ntcl:\n {}\n{}:\n{}", name,interp.native_command_names(),interp.name,HELP_MSG)
401 }else{
402 molt_err_help!("unknown command \"{}\", valid commands:\ntcl:\n {}\n{}:\n{}\nprocedure:\n {}", name,interp.native_command_names(),interp.name,HELP_MSG,proc_command_names)
403 }
404 }
405 }
406 }
407 }
408 f as fn(&str, &mut $crate::prelude::Interp<$ctx_type>, &[$crate::prelude::Value]) -> $crate::prelude::MoltResult
409 },
410 {fn f(name: &str, interp: &$crate::prelude::Interp<$ctx_type>) -> Option<$crate::prelude::CommandType> {
411 match name {
412 $crate::prelude::_APPEND => Some($crate::prelude::CommandType::Native),
413 $crate::prelude::_ARRAY => Some($crate::prelude::CommandType::Native),
414 $crate::prelude::_ASSERT_EQ => Some($crate::prelude::CommandType::Native),
415 $crate::prelude::_BREAK => Some($crate::prelude::CommandType::Native),
416 $crate::prelude::_CATCH => Some($crate::prelude::CommandType::Native),
417 $crate::prelude::_CONTINUE => Some($crate::prelude::CommandType::Native),
418 $crate::prelude::_DICT => Some($crate::prelude::CommandType::Native),
419 $crate::prelude::_ERROR => Some($crate::prelude::CommandType::Native),
420 $crate::prelude::_EXPR => Some($crate::prelude::CommandType::Native),
421 $crate::prelude::_FOR => Some($crate::prelude::CommandType::Native),
422 $crate::prelude::_FOREACH => Some($crate::prelude::CommandType::Native),
423 $crate::prelude::_GLOBAL => Some($crate::prelude::CommandType::Native),
424 $crate::prelude::_IF => Some($crate::prelude::CommandType::Native),
425 $crate::prelude::_INCR => Some($crate::prelude::CommandType::Native),
426 $crate::prelude::_INFO => Some($crate::prelude::CommandType::Native),
427 $crate::prelude::_JOIN => Some($crate::prelude::CommandType::Native),
428 $crate::prelude::_LAPPEND => Some($crate::prelude::CommandType::Native),
429 $crate::prelude::_LINDEX => Some($crate::prelude::CommandType::Native),
430 $crate::prelude::_LIST => Some($crate::prelude::CommandType::Native),
431 $crate::prelude::_LLENGTH => Some($crate::prelude::CommandType::Native),
432 $crate::prelude::_PROC => Some($crate::prelude::CommandType::Native),
433 $crate::prelude::_PUTS => Some($crate::prelude::CommandType::Native),
434 $crate::prelude::_RENAME => Some($crate::prelude::CommandType::Native),
435 $crate::prelude::_RETURN => Some($crate::prelude::CommandType::Native),
436 $crate::prelude::_SET => Some($crate::prelude::CommandType::Native),
437 $crate::prelude::_STRING => Some($crate::prelude::CommandType::Native),
438 $crate::prelude::_THROW => Some($crate::prelude::CommandType::Native),
439 $crate::prelude::_TIME => Some($crate::prelude::CommandType::Native),
440 $crate::prelude::_UNSET => Some($crate::prelude::CommandType::Native),
441 $crate::prelude::_WHILE => Some($crate::prelude::CommandType::Native),
442 $(
443 $native_name => Some($crate::prelude::CommandType::Native),
444 )*
445 $(
446 $embedded_name => Some($crate::prelude::CommandType::Embedded),
447 )*
448 other => {
449 if interp.contains_proc(other) {
450 Some($crate::prelude::CommandType::Proc)
451 } else {
452 None
453 }
454 }
455 }
456 }
457 f as fn(&str, &$crate::prelude::Interp<$ctx_type>) -> Option<$crate::prelude::CommandType>
458 },
459 &[
460 $crate::prelude::_APPEND,
461 $crate::prelude::_ARRAY,
462 $crate::prelude::_ASSERT_EQ,
463 $crate::prelude::_BREAK,
464 $crate::prelude::_CATCH,
465 $crate::prelude::_CONTINUE,
466 $crate::prelude::_DICT,
467 $crate::prelude::_ERROR,
468 $crate::prelude::_EXPR,
469 $crate::prelude::_FOR,
470 $crate::prelude::_FOREACH,
471 $crate::prelude::_GLOBAL,
472 $crate::prelude::_IF,
473 $crate::prelude::_INCR,
474 $crate::prelude::_INFO,
475 $crate::prelude::_JOIN,
476 $crate::prelude::_LAPPEND,
477 $crate::prelude::_LINDEX,
478 $crate::prelude::_LIST,
479 $crate::prelude::_LLENGTH,
480 $crate::prelude::_PROC,
481 $crate::prelude::_PUTS,
482 $crate::prelude::_RENAME,
483 $crate::prelude::_RETURN,
484 $crate::prelude::_SET,
485 $crate::prelude::_STRING,
486 $crate::prelude::_THROW,
487 $crate::prelude::_TIME,
488 $crate::prelude::_UNSET,
489 $crate::prelude::_WHILE,
490 $(
491 $native_name,
492 )*
493 ],
494 &[
495 $(
496 $embedded_name,
497 )*
498 ]
499 )
500 };
501}
502
503#[cfg(test)]
504mod tests {
505 use crate::*;
506
507 #[test]
508 fn test_molt_ok() {
509 let result: MoltResult = molt_ok!();
510 assert_eq!(Ok(Value::empty()), result);
511
512 let result: MoltResult = molt_ok!(5);
513 assert_eq!(Ok(Value::from(5)), result);
514
515 let result: MoltResult = molt_ok!("Five");
516 assert_eq!(Ok(Value::from("Five")), result);
517
518 let result: MoltResult = molt_ok!("The answer is {}.", 5);
519 assert_eq!(Ok(Value::from("The answer is 5.")), result);
520 }
521
522 #[test]
523 fn test_molt_err() {
524 check_err(molt_err!("error message"), "error message");
525 check_err(molt_err!("error {}", 5), "error 5");
526 }
527
528 #[test]
529 fn test_molt_throw() {
530 check_throw(molt_throw!("MYERR", "error message"), "MYERR", "error message");
531 check_throw(molt_throw!("MYERR", "error {}", 5), "MYERR", "error 5");
532 }
533
534 fn check_err(result: MoltResult, msg: &str) -> bool {
535 match result {
536 Err(exception) => exception.is_error() && exception.value() == msg.into(),
537 _ => false,
538 }
539 }
540
541 fn check_throw(result: MoltResult, code: &str, msg: &str) -> bool {
542 match result {
543 Err(exception) => {
544 exception.is_error()
545 && exception.value() == msg.into()
546 && exception.error_code() == code.into()
547 }
548 _ => false,
549 }
550 }
551}