extend namespace Command { /* * These are used by the parser when building * programs to run from the top level of the * interpreter */ public void display (poly v) /* * Used by the top-level read/eval/print loop. * For non-void 'v', * Prints out 'v' in the current default format. * Inserts 'v' into the history. */ { if (is_void (v)) return; History::insert (v); printf (format, v); putchar ('\n'); } public void display_base (poly v, int base) /* * Used by the top-level read/eval/print loop * when '# base' is appended to an expression. * For non-void 'v', * Prints out 'v' in 'base'. * Inserts 'v' into the history. */ { if (is_void (v)) return; History::insert (v); File::print (stdout, v, "g", base, 0, -1, " "); putchar ('\n'); } /* * Now add a collection of useful commands */ /* * quit * * quit - exit with code 0 * quit N - exit with code N */ void do_quit (int args...) { int code = 0; if (dim(args) > 0) code = args[0]; exit (code); } new ("quit", do_quit); /* * history * * history - show some recent history * history N - show N recent history * history N,M - show history from N to M */ void do_history (int args...) { switch (dim (args)) { case 0: History::show (format); break; case 1: History::show (format, args[0]); break; default: History::show (format, args[0], args[1]); break; } } new ("history", do_history); /* * print * * print name - pretty print name */ void do_pretty_print (string[*] names...) { pretty_print (stdout, names ...); } new_names ("print", do_pretty_print); new_names ("edit", edit); new_names ("undefine", undefine); /* * load * * load "filename" - read commands from "filename" */ void do_load (string f) { try { lex_file (f); } catch File::open_error (string msg, File::error_type err, string name) { File::fprintf (stderr, "Cannot load \"%s\": %s\n", name, msg); } } new ("load", do_load); /* * core behavior for autoload and autoimport */ void do_auto (string[*][*] args, bool do_import) { string autotype = "autoload"; if (do_import) autotype = "autoimport"; string make_filename(string m) { string r = ""; bool last_lower = false; for (int i = 0; i < String::length(m); i++) { int c = m[i]; bool cur_lower = Ctype::islower(c); if (Ctype::isupper(c)) { c = Ctype::tolower(c); if (last_lower) r = r + "-"; } r = r + String::new(c); last_lower = cur_lower; } return r + ".5c"; } void import_if_needed(string name) { if (do_import) { string imp = File::sprintf("import %s;\n", name); lex_string(imp); } } for (int i = 0; i < dim(args); i++) { string[*] name = args[i]; if (valid_name (name)) { for (int i = 0; i < dim(name); i++) import_if_needed(name[i]); continue; } for (int j = dim(name) - 1; j >= 0; j--) { import_if_needed(name[j]); string[*] subname = (string[j+1]) { [k] = name[k] }; if (!valid_name (subname)) { string f = make_filename(name[j]); if (!lex_library (f)) { File::fprintf (stderr, "Cannot load \"%s\" " + "file \"%s\", giving up.\n", autotype, f); return; } } } } } /* * autoimport * * autoimport ModuleName ... - * load a library named "module-name.5c" and * import ModuleName; do for each argument */ void do_autoimport (string[*] args...) { do_auto(args, true); } new_names ("autoimport", do_autoimport); /* * autoload * * autoload ModuleName ... - * load a library named "module-name.5c". */ void do_autoload (string[*] args...) { do_auto(args, false); } new_names ("autoload", do_autoload); /* * char * * char c1 c2 c3 - Print characters for given integers */ void do_char (int c ...) { for (int i = 0; i < dim (c); i++) printf ("%3d 0x%02x: %v\n", c[i], c[i], String::new (c[i])); } new ("char", do_char); void process_args(&string[*] argv) { bool lex_stdin = true; string script_name = ""; /* XXX Much of this architecture is driven by the fact that the lexer stacks the files to be processed rather than queueing them. */ typedef union { string library; string sfile; string script; string expr; } lexable; lexable[...] lexables = {}; void process_lexables() { } void save_lexable(lexable l) { lexables[dim(lexables)] = l; } void save_library(string arg) { save_lexable((lexable.library)arg); } void save_script(string arg) { save_lexable((lexable.script)arg); /* Add directory containing the script to the library path */ nickle_path = String::dirname (arg) + ":" + nickle_path; script_name = arg; lex_stdin = false; } void save_file(string arg) { save_lexable((lexable.sfile)arg); } void save_expr(string arg) { save_lexable((lexable.expr)arg); lex_stdin = false; } ParseArgs::argdesc argd = { args = { {var = {arg_lambda = save_library}, abbr = 'l', name = "library", expr_name = "lib", desc = "Library to load."}, {var = {arg_lambda = save_file}, abbr = 'f', name = "file", expr_name = "source", desc = "Source file to load."}, {var = {arg_lambda = save_expr}, abbr = 'e', name = "expr", expr_name = "expression", desc = "Expression to evaluate."} }, posn_args = { {var = {arg_lambda = save_script}, name = "script", optional = <>} }, unknown = &(int user_argind), prog_name = "nickle" }; /* actually parse the arguments */ ParseArgs::parseargs(&argd, &argv); /* Reset argv to hold remaining arguments */ if (lex_stdin && is_uninit(&user_argind)) { string[0] rest = {}; argv = rest; } else { if (is_uninit(&user_argind)) user_argind = dim(argv); string[dim(argv) - user_argind + 1] rest; rest[0] = script_name; for (int i = 1; i < dim(rest); i++) rest[i] = argv[i + user_argind - 1]; argv = rest; } /* Recall the comment above. Since the lexer stacks, we must stack stdin, which is to run last, *before* the other stuff. Bleah. */ if (lex_stdin) { /* Add the current directory to the library path */ nickle_path += ":."; /* we want stdin to be processed after all other lexables */ lex_input (stdin, "", false, File::isatty (stdin)); /* if there's a .nicklerc, we apparently want that next-to-last? */ try { lex_file (Environ::get ("HOME") + "/.nicklerc"); } catch invalid_argument (msg, int i, poly value) { /* do nothing */; } catch File::open_error (string msg, File::error_type err, string name) { /* do nothing */; } } /* now stack the other arguments, in reverse order */ for (int i = dim(lexables) - 1; i >=0; --i) { static void load_fail(string name, string msg) { File::fprintf (stderr, "Cannot load \"%s\": %s\n", name, msg); exit (1); } static void lex_script(string arg) { try { lex_file (arg); } catch File::open_error (string msg, File::error_type err, string name) { load_fail (name, msg); } } union switch(lexables[i]) { case library arg: if (!lex_library (arg)) load_fail (arg, "cannot load library"); break; case script arg: lex_script(arg); break; case sfile arg: lex_script(arg); break; case expr arg: lex_string(arg + "\n"); break; } } } }