Commit eebd9138 authored by Samuel Newbold's avatar Samuel Newbold

Builtins have prototypes-> s/.bad_argc/.bad_args/g

* Improved error handling while deleting 17% of builtin.cc and removing
  three quarters of the C++ throw statements.

* (A +- B) != A iff B != 0 and (A */ B) != A iff A != 0 and B != 1
  otherwise an .epsilon exception is thrown

* Also, added .var_multiply and * function

* A first version of a validating ln function
parent 7308a143
THIS IS PRE-ALPHA SOFTWARE. This means that major functionality is missing,
such as pipes, job control, and command completion. This also means that
scripts written for this version are unlikely to work on version 1.0 when it is
released. (As an example, control flow will change in one of the next few
versions so that the first command to return non-zero will cause functions and
scripts to terminate, unless used in some control flow contexts, such as .if).
.version_compatible will eventually permit you to protect scripts from
released. .version_compatible will eventually permit you to protect scripts from
incompatibilities, but the shell has not matured to a point where the current
semantics for .version_compatible may be depended upon.
......@@ -14,8 +11,6 @@ executable_not_found errors. You could make an argument that this is what
should be done, after all, both errors occurred. But then this should be the
behavior when a function calls an executable, which causes rwsh.autofunction to exceed MAX_NESTING, but in this case, only the excessive_nesting error occurs.
.return must set errno to 0, because other function calls are causing errors
If the shell receives a signal while waiting for input, it does not handle it
until after the line is input
......
This diff is collapsed.
......@@ -248,7 +248,7 @@ void Error_list::replace_error(const Argm& error){
push_back(error);
global_stack.replace_error();}
Old_argv::Old_argv(const Argm::Argv& src) : argc_v(src.size()) {
Old_argv::Old_argv(const Argv& src) : argc_v(src.size()) {
focus = new char*[src.size()+1];
copy_to_cstr(src.begin(), src.end(), focus);}
......
......@@ -2,10 +2,10 @@
class Command_block;
struct Error_list;
typedef std::vector<std::string> Argv;
class Argm {
public:
typedef std::vector<std::string> Argv;
Argm(Variable_map* parent_map_i,
Rwsh_istream_p input_i, Rwsh_ostream_p output_i, Rwsh_ostream_p error_i);
Argm(const Argv& args,
......@@ -32,7 +32,6 @@ class Argm {
Ambiguous_prototype_dash_dash,
Arguments_for_argfunction,
Autofunction,
Bad_argc,
Bad_argfunction_style,
Bad_args,
Bad_if_nest,
......@@ -49,6 +48,7 @@ class Argm {
Elipsis_first_arg,
Elipsis_out_of_option_group,
Else_without_if,
Epsilon,
Excess_argfunction,
Excessive_exceptions_collected,
Excessive_exceptions_in_catch,
......@@ -199,7 +199,7 @@ class Old_argv {
int argc_v;
public:
Old_argv(const Argm::Argv& src);
Old_argv(const Argv& src);
~Old_argv(void);
char** const argv(void) const {return focus;};
int argc(void) {return argc_v;}; };
......
This diff is collapsed.
......@@ -76,6 +76,7 @@ void b_usleep_overhead(const Argm& argm, Error_list& exceptions);
void b_var_add(const Argm& argm, Error_list& exceptions);
void b_var_divide(const Argm& argm, Error_list& exceptions);
void b_var_exists(const Argm& argm, Error_list& exceptions);
void b_var_multiply(const Argm& argm, Error_list& exceptions);
void b_var_subtract(const Argm& argm, Error_list& exceptions);
void b_version_compatible(const Argm& argm, Error_list& exceptions);
void b_version(const Argm& argm, Error_list& exceptions);
......
// The definition of the Binary and Builtin classes. The former executes
// external programs, the latter executes commands that are implemented by
// functions in builtin.cc.
// The definition of the Base_executable and Binary classes. The former
// provides functionality common to all derived types, the latter executes
// external programs.
//
// Copyright (C) 2005-2019 Samuel Newbold
......@@ -78,11 +78,3 @@ void Binary::execute(const Argm& argm_i, Error_list& exceptions) const {
else plumber.wait(&ret);
if (WIFEXITED(ret) && WEXITSTATUS(ret))
exceptions.add_error(Exception(Argm::Return_code, WEXITSTATUS(ret)));}
Builtin::Builtin(const std::string& name_i,
void (*impl)(const Argm& argm, Error_list& exceptions)) :
implementation(impl), name_v(name_i) {}
// run the given builtin
void Builtin::execute(const Argm& argm, Error_list& exceptions) const {
(*implementation)(argm, exceptions);}
......@@ -43,14 +43,3 @@ class Binary : public Named_executable {
virtual void execute(const Argm& argm, Error_list& exceptions) const;
virtual const std::string& name(void) const {return implementation;};
virtual std::string str() const {return implementation;}; };
class Builtin : public Named_executable {
void (*implementation)(const Argm& argm, Error_list& exceptions);
std::string name_v;
public:
Builtin(const std::string& name_i,
void (*impl)(const Argm& argm, Error_list& exceptions));
virtual void execute(const Argm& argm, Error_list& exceptions) const;
virtual const std::string& name(void) const {return name_v;};
virtual std::string str() const {return name_v;}; };
......@@ -116,7 +116,7 @@ void Executable_map::not_found(Argm& argm_i, Error_list& exceptions) {
argm_i.error);
tokenize_words("cmd [args ...]", std::back_inserter(prototype_argm));
set(new Function(Argm::exception_names[Argm::Function_not_found],
prototype_argm.begin(), prototype_argm.end(), false,
prototype_argm.argv(),
"{.echo $cmd (: command not found) \\( $cmd $args$ \\);"
" .echo (\n)}", exceptions));}
throw Exception(Argm::Function_not_found, argm_i);}
......
// The definition of the Function class which can be used to change the
// arguments passed to an executable and/or tie several other executables into
// a single executable.
// The definition of the Builtin, Command_block, and Function classes. The
// first of which executes commands that are implemented by functions in
// builtin.cc, the latter of which map arguments passed to an executable
// and/or tie several other executables into a single executable.
//
// Copyright (C) 2006-2019 Samuel Newbold
......@@ -27,6 +28,26 @@
#include "function.h"
Builtin::Builtin(const std::string& name_i,
void (*impl)(const Argm& argm, Error_list& exceptions),
const Argv& prototype_i) :
implementation(impl), name_v(name_i), prototype(prototype_i) {}
// run the given builtin
void Builtin::execute(const Argm& argm, Error_list& exceptions) const {
Variable_map locals(argm.parent_map());
prototype.arg_to_param(argm, locals, exceptions);
locals.bless_unused_vars();
if (prototype.non_prototype) std::abort();
else if (argm.argfunction() && prototype.exclude_argfunction)
exceptions.add_error(Exception(Argm::Excess_argfunction));
else if (!argm.argfunction() && prototype.required_argfunction)
exceptions.add_error(Exception(Argm::Missing_argfunction));
if (!global_stack.unwind_stack())
(*implementation)(argm, exceptions);}
std::string Builtin::str() const {return name_v + " " + prototype.str();};
// generate a new Command_block by unescaping argument functions and replacing
// unescaped_argfunction with the argument function in argm
Command_block* Command_block::apply(const Argm& argm, unsigned nesting,
......@@ -95,13 +116,9 @@ Command_block::Command_block(const std::string& src,
point = tpoint + 1;}
Function::Function(const std::string& name_i,
Argm::const_iterator first_parameter,
Argm::const_iterator parameter_end,
bool non_prototype_i,
const Argv& parameters,
const std::string& src, Error_list& errors) :
name_v(name_i),
prototype(first_parameter, parameter_end, non_prototype_i) {
if (prototype.non_prototype) default_error <<"deprecated string non-prototype: " <<name_i <<"\n";
name_v(name_i), prototype(parameters) {
std::string::size_type point = 0;
try {
body = Command_block(src, point, 0, errors);
......@@ -117,15 +134,13 @@ Function::Function(const std::string& name_i,
throw "unclosed parenthesis on construction of function " + name_i + "\n" +
error[1] + "\n";}}
Function::Function(const std::string& name_i,
Argm::const_iterator first_parameter,
Argm::const_iterator parameter_end,
bool non_prototype_i,
Function::Function(const std::string& name_i, const Argv& parameters,
const Command_block& src) :
name_v(name_i), prototype(parameters), body(src) {}
Function::Function(const std::string& name_i, bool non_prototype_i,
const Command_block& src) :
prototype(first_parameter, parameter_end, non_prototype_i),
name_v(name_i), body(src) {
//if (non_prototype_i) default_error <<"re-deprecated .function non-prototype: " <<name_i <<"\n";
}
name_v(name_i), prototype(non_prototype_i), body(src) {}
// run the given function
void Function::execute(const Argm& argm, Error_list& exceptions) const {
......
// Copyright (C) 2005-2019 Samuel Newbold
class Builtin : public Named_executable {
void (*implementation)(const Argm& argm, Error_list& exceptions);
std::string name_v;
Prototype prototype;
public:
Builtin(const std::string& name_i,
void (*impl)(const Argm& argm, Error_list& exceptions),
const Argv& prototype_i);
virtual void execute(const Argm& argm, Error_list& exceptions) const;
virtual const std::string& name(void) const {return name_v;};
virtual std::string str() const; };
class Command_block : public Base_executable, public std::vector<Arg_script> {
typedef std::vector<Arg_script> Base;
public:
......@@ -41,11 +53,11 @@ class Function : public Named_executable {
public:
Command_block body;
Function(const std::string& name, Argm::const_iterator first_parameter,
Argm::const_iterator parameter_end, bool non_prototype_i,
Function(const std::string& name, const Argv& parameters,
const std::string& src, Error_list& errors);
Function(const std::string& name_i, Argm::const_iterator first_parameter,
Argm::const_iterator parameter_end, bool non_prototype_i,
Function(const std::string& name_i, bool non_prototype_i,
const Command_block& src);
Function(const std::string& name_i, const Argv& parameters,
const Command_block& src);
Function(const Function& src) :
name_v(src.name_v), prototype(src.prototype), body(src.body) {}
......
......@@ -17,8 +17,8 @@ rwsh: $(objects) $(local_objects)
$(CXX) $^ $(CXXFLAGS) $(LDLIBS) -o $@
librwsh.a: $(objects)
ar -rv $@ $(objects)
deps.mk: $(objects:o=cc) $(local_objects:o=cc)
gcc >$@ -MM $^
# deps.mk: $(objects:o=cc) $(local_objects:o=cc)
# gcc >$@ -MM $^
include deps.mk
......
......@@ -120,15 +120,14 @@ Prototype::Prototype(bool non_prototype_i) :
positional(), required_argc(), non_prototype(non_prototype_i),
exclude_argfunction(true), required_argfunction(false) {}
Prototype::Prototype(Argm::const_iterator fp, Argm::const_iterator end,
bool non_prototype_i) :
Prototype::Prototype(const Argv& parameters) :
bare_dash_dash(false), dash_dash_position(-1), elipsis_var(""),
flag_options(), flags(ALL), parameter_names(),
positional(), required_argc(), non_prototype(non_prototype_i),
positional(), required_argc(), non_prototype(false),
exclude_argfunction(true), required_argfunction(false) {
bool has_elipsis = false;
for (; fp != end; ++fp) {
Parameter_group group(fp, end, parameter_names);
for (auto fp = parameters.begin(); fp != parameters.end(); ++fp) {
Parameter_group group(fp, parameters.end(), parameter_names);
if (has_elipsis && !group.required && !group.has_argfunction)
throw Exception(Argm::Post_elipsis_option, group.str());
else if (group.elipsis == -1) {
......
......@@ -42,8 +42,7 @@ class Prototype {
bool exclude_argfunction;
bool required_argfunction;
Prototype(bool non_prototype);
Prototype(Argm::const_iterator first_parameter,
Argm::const_iterator parameter_end, bool non_prototype_i);
Prototype(const Argv& parameters);
void arg_to_param(const Argm& invoking_argm, Variable_map& locals,
Error_list& exceptions) const;
void bad_args(std::string& missing, const Variable_map& locals,
......
......@@ -38,7 +38,6 @@ std::string Argm::exception_names[Argm::Exception_count] = {
".ambiguous_prototype_dash_dash",
".arguments_for_argfunction",
".autofunction",
".bad_argc",
".bad_argfunction_style",
".bad_args",
".bad_if_nest",
......@@ -55,6 +54,7 @@ std::string Argm::exception_names[Argm::Exception_count] = {
".elipsis_first_arg",
".elipsis_out_of_option_group",
".else_without_if",
".epsilon",
".excess_argfunction",
".excessive_exceptions_collected",
".excessive_exceptions_in_catch",
......@@ -139,7 +139,7 @@ int main(int argc, char *argv[]) {
catch (Exception& exception) {
executable_map.base_run(exception, exceptions);}
Command_stream command_stream(default_input, true);
Argm::Argv std_argv(&argv[0], &argv[argc]);
Argv std_argv(&argv[0], &argv[argc]);
Argm init_command(".init", std_argv,
nullptr, Variable_map::global_map,
default_input, default_output, default_error);
......
This diff is collapsed.
......@@ -20,18 +20,6 @@ double my_strtod(const std::string& src) {
else if (errno) {errno = 0; throw E_generic();}
else return ret;}
float my_strtof(const std::string& src) {
const char* focus = src.c_str();
char* endptr;
errno = 0;
float ret = strtof(focus, &endptr);
if (!*focus || *endptr) throw E_nan();
if (errno == ERANGE) {errno = 0; throw E_range();}
else if (ret == std::numeric_limits<float>::infinity() ||
ret == -std::numeric_limits<float>::infinity()) throw E_range();
else if (errno) {errno = 0; throw E_generic();}
else return ret;}
int my_strtoi(const std::string& src) {
const char* focus = src.c_str();
char* endptr;
......@@ -55,16 +43,3 @@ int my_strtoi(const std::string& src, int min, int max) {
else if (ret > max) throw E_range();
else if (errno) throw E_generic();
else return ret;}
char my_strtoc(const std::string& src) {
const char* focus = src.c_str();
char* endptr;
errno = 0;
long ret = strtol(focus, &endptr, 10);
if (!*focus || *endptr) throw E_nan();
if (errno == ERANGE) throw E_range();
else if (ret < CHAR_MIN) throw E_range();
else if (ret > CHAR_MAX) throw E_range();
else if (errno) throw E_generic();
else return ret;}
......@@ -5,7 +5,5 @@ class E_nan {};
class E_range {};
double my_strtod(const std::string& src);
float my_strtof(const std::string& src);
int my_strtoi(const std::string& src);
int my_strtoi(const std::string& src, int min, int max);
char my_strtoc(const std::string& src);
......@@ -16,9 +16,6 @@
.combine ( (it requests reading the user's mind) ) \( stack: $stack \) $nl}
.function_all_flags .arguments_for_argfunction name {
echo cannot specify arguments for $name directly}
.function_all_flags .bad_argc required needed optional [stack ...] {
.echo unacceptable argument count: received $required non-optional
echo , but needed $needed \(with $optional optional\) for $stack$}
.function_all_flags .bad_argfunction_style style {
echo $style is neither an argfunction nor a substitution nor a brace literal}
.function_all_flags .bad_args -- proto assigned needed excess call_stack ... {
......@@ -70,6 +67,9 @@
echo call stack: $stack$}
.function_all_flags .else_without_if stack ... {
echo else without if with call stack: $stack$}
.function_all_flags .epsilon var_val change stack ... {
echo $change is too small relative to $var_val to modify its value
echo call stack: $stack$}
.function_all_flags .excess_argfunction cmd [stack ...] {
echo $cmd does not accept an argfunction with call stack: $cmd $stack$}
.function_all_flags .excessive_exceptions_collected max stack ... {
......@@ -247,55 +247,49 @@
echo call stack: $stack$}
# ability of functions to act as builtin wrappers
.function_all_flags ! args ... {
fn ! args ... {
.if $args$ {.throw .false ${.echo ! $args}}
.else {.nop}}
.function_all_flags af -- [argv ...] .{argfunction} {.argfunction}
.function_all_flags c -- text ... {.combine $text$}
.function_all_flags e -- text ... {.echo $text}
.function_all_flags do_while argv ... .{argfunction} {
fn af -- [argv ...] .{argfunction} {.argfunction}
fn c -- text ... {.combine $text$}
fn e -- text ... {.echo $text}
fn do_while argv ... .{argfunction} {
.try_catch_recursive .break {
.nop $argv
.try_catch_recursive .continue {.argfunction}
.while $argv$ {.argfunction}}}
.function_all_flags echo -- text ... {.echo $text; .combine $nl}
.function_all_flags echo-comments cmd ... {
fn echo -- text ... {.echo $text; .combine $nl}
fn echo-comments cmd ... {
.stepwise $cmd$ {if_only .test_in $1 .nop # #! ## {echo &&&*}}}
.function_all_flags exec -- argv ... {.exec $argv$}
.function_all_flags elif command ... .{argfunction} {
fn exec -- argv ... {.exec $argv$}
fn elif command ... .{argfunction} {
.else_if $command$ {.argfunction}}
.function_all_flags else .{argfunction} {.else {.argfunction}}
fn false {.try_catch_recursive .return_code {${whichp false}}}
.function_all_flags fns -- name args ... .{argfunction} {
.function_all_flags $name [-*] $args$ {.argfunction}}
.function_all_flags if_only -- args ... .{argfunction} {
fn else .{argfunction} {.else {.argfunction}}
fn fns -- name args ... .{argfunction} {fn $name [-?] $args$ {.argfunction}}
fn if_only -- args ... .{argfunction} {
.if $args$ {.argfunction}; .else {.nop}}
.function_all_flags if_only_not -- args ... .{argfunction} {
fn if_only_not -- args ... .{argfunction} {
.if $args$ {.nop}; .else {.argfunction}}
fn ntimes n .{argfunction} {
.while test_var_greater n 0 {
.mapped_argfunction {.argfunction}
.var_subtract n 1}}
.function_all_flags outer_break stack ... {
.replace_exception .break $stack$}
.function_all_flags outer_continue stack ... {
.replace_exception .continue $stack$}
.function_all_flags scope_for var vals ... .{argfunction} {
fn outer_break stack ... {.replace_exception .break $stack$}
fn outer_continue stack ... {.replace_exception .continue $stack$}
fn scope_for var vals ... .{argfunction} {
.for $vals$ {
.scope $1 $var {.argfunction}}}
.function_all_flags outer_for var vals ... .{argfunction} {
fn outer_for var vals ... .{argfunction} {
.for $vals$ {
.scope $1 $var {
.try_catch_recursive outer_break outer_continue {.argfunction}}}}
.function_all_flags outer_while argv ... .{argfunction} {
fn outer_while argv ... .{argfunction} {
.while $argv$ {
.try_catch_recursive outer_break outer_continue {.argfunction}}}
.function_all_flags setf var value {
fn setf var value {
.if .var_exists $var {.set $var $value}
.else {.global $var $value}}
fn single -- args ... {.scope ${$args$}$ result {echo $result}}
fn test -- args ... {
.try_catch_recursive .return_code {${whichp test} $args$}}
fn test_var_not_equal var value {.test_string_unequal $$var $value}
fn test_var_greater -- var value {.test_greater $$var $value}
fn type [-t] args ... [.{argfunction}] {
......@@ -307,33 +301,42 @@ fn whence command [.{argfunction}] {
.try_catch_recursive .function_not_found {
.whence_function $command {.argfunction}}}
fn whichp binary {.which_path $binary $PATH}
.function_all_flags while_and_one_more argv ... .{argfunction} {
fn while_and_one_more argv ... .{argfunction} {
.try_catch_recursive .break {
.while $argv$ {.argfunction}
.try_catch_recursive .continue {.argfunction}}}
.function_all_flags var_exists -- var {.var_exists $var}
.function_all_flags var_in var set ... {.test_in $$var $set$}
.function_all_flags var_less var N {.test_less $$var $N}
.function_all_flags var_val -- [var ...] {
fn var_exists -- var {.var_exists $var}
fn var_in var set ... {.test_in $$var $set$}
fn var_less var N {.test_less $$var $N}
fn var_val -- [var ...] {
.if .var_exists var {.for $var$ {.combine $1 \( $$1 \) \ }}
.else {.nop}}
.function_all_flags paren_if_words -- value {
fn paren_if_words -- value {
.if .test_number_equal ${.argc $value$} 1 {.combine $value}
.else {.combine \( $value \)}}
fn polish -- operator builtin {
fn &&operator -- lhs rhs ... {
if_only .test_in $lhs + - / {
if_only .test_in $lhs + - / * {
.scope ${$lhs $rhs$}$ (-- l r ...) {
.set lhs $l
.set rhs $r}}
.scope $rhs$ (rhs [extra ...]) {
.if .test_in $rhs + - / {
.if .test_in $rhs + - / * {
.scope ${$rhs $extra$}$ (rhs [extra ...]) {
&&builtin lhs $rhs
echo $lhs $extra$}}
.else {
&&builtin lhs $rhs
echo $lhs $extra$}}}}
polish - .var_subtract
polish + .var_add
polish / .var_divide
polish * .var_multiply
polish - .var_subtract
# external commands tested in the test suite
fn false {.try_catch_recursive .return_code {${whichp false}}}
fn ln [-?] target {
.nop $-* # in case the following assertion fails
.test_file_exists $target
&{.which_path ln /bin:/usr/bin} $-* $target}
fn test -- args ... {.try_catch_recursive .return_code {${whichp test} $args$}}
......@@ -14,7 +14,7 @@
.try_catch_recursive .unused_variable {.collect_errors_except .nop {
# set up environment
.function_all_flags set_if_undefined -- var [value] {
fn set_if_undefined -- var [value] {
.if .var_exists $var {.nop $value$}
.else_if .var_exists value {.global $var $value}
.else {.global $var ()}}
......@@ -33,8 +33,7 @@ fn sfn command {
&&{.which_path $command $PATH} $-*$ @$s}}
fn fn-subcommand system command {
.function_all_flags &&{c $system - $command} -- [args ...] {
.if .var_exists args {&&{whichp $system} &&command $args$}
.else {&&{whichp $system} &&command}}}
&&{whichp $system} &&command $args$}}
fn sfn-subcommand system command {
.function_all_flags &&{c $system - $command} [-*] [file ...] {
if_only .var_exists file {.selection_set s $file}
......@@ -80,7 +79,7 @@ fns gdb [binary] {
if_only .var_exists binary {.set BUILT_EXECUTABLE $binary}
echo debugging $BUILT_EXECUTABLE
&{whichp gdb} $-*$ $BUILT_EXECUTABLE}
.function_all_flags git-git -- args ... {&{whichp git} $args$}
fn git-git -- args ... {&{whichp git} $args$}
fns git command [file ...] {
if_only .var_exists file {.selection_set s $file$}
.if .test_not_empty $s {&{whichp git} $-*$ $command @$s}
......@@ -118,7 +117,7 @@ fn home {cd $HOME}
fns head [-n lines] [-c bytes] [file ...] {
if_only .var_exists file {.selection_set s $file}
&&{whichp head} $-*$ @$s}
.function_all_flags ignore args ... {.set FIGNORE $args$}
fn ignore args ... {.set FIGNORE $args$}
fns ll [file ...] {
if_only .var_exists file {.selection_set s $file}
&&{whichp ls} -ld $-*$ @$s}
......@@ -156,34 +155,34 @@ sfn wc
fn unselect {.set s ()}
# internal functions
.function_all_flags .run_logic -- cmd [args ...] {
fn .run_logic -- cmd [args ...] {
.try_catch_recursive &{.internal_functions}$ {$cmd $args$ {.argfunction}}
# $* {.argfunction}}
.function_all_flags .prompt {.echo $s; .echo \$}
.function_all_flags .vars {
fn .prompt {.echo $s; .echo \$}
fn .vars {
.internal_vars
echo $nl HOME $HOME
echo REGEX $REGEX
echo s $s}
# misc
.function_all_flags . -- command ... {.source $command$}
.function_all_flags ex_count -- cmd {.execution_count $cmd; c $nl}
.function_all_flags exec -- command ... {.exec $command$ }
.function_all_flags exit value {.exit $value}
.function_all_flags last_time cmd {.last_execution_time $cmd; c $nl}
fn . -- command ... {.source $command$}
fn ex_count -- cmd {.execution_count $cmd; c $nl}
fn exec -- command ... {.exec $command$ }
fn exit value {.exit $value}
fn last_time cmd {.last_execution_time $cmd; c $nl}
fn local {. &{c $HOME /.rwshrc}}
fn mark {ntimes 4 {.echo ####################}; c $nl}
.function_all_flags timings cmd {
fn timings cmd {
.echo last time (); .last_execution_time $cmd; c $nl
.echo total time (); .total_execution_time $cmd; c $nl
.echo execution count (); .execution_count $cmd; c $nl}
.function_all_flags total_time cmd {.total_execution_time $cmd; c $nl}
.function_all_flags user_shell_ratio {
fn total_time cmd {.total_execution_time $cmd; c $nl}
fn user_shell_ratio {
.local time &&{.waiting_for_user}
.var_divide time &&{.waiting_for_shell}
.combine $time $nl}
.function_all_flags waiting {
fn waiting {
echo for user ${.waiting_for_user}
echo for binary ${.waiting_for_binary}
echo for shell ${.waiting_for_shell}}
......@@ -194,7 +193,7 @@ fn st-core [-?] [-nc] binary filter {
.if .test_not_empty $-? {
&{whichp diff} $-?$ test.result last.test.result >last.test.result.diff}
.else {
&{whichp diff} -c test.result last.test.result >last.test.result.diff}
&{whichp diff} -u test.result last.test.result >last.test.result.diff}
$filter$ last.test.result.diff}}
fn mst [-?] {make; st $-*$}
fn to {./rwsh -to}
......@@ -216,14 +215,14 @@ fn qt [-?] [-nc] {
to <test_quick.sh >last.test_quick.result
.if .test_not_empty $-? {
&{whichp diff} $-?$ test_quick.result last.test_quick.result}
.else {&{whichp diff} -c test_quick.result last.test_quick.result}}}
.else {&{whichp diff} -u test_quick.result last.test_quick.result}}}
fn bless-qt {&{whichp cp} last.test_quick.result test_quick.result}
fn arg-out {./rwsh -to <argfunction.sh}
fn arg-diff [-?] {
arg-out >argfunction.result.last
.if .test_not_empty $-? {
&{whichp diff} $-?$ argfunction.basic-result argfunction.result.last}
.else {&{whichp diff} -c argfunction.basic-result argfunction.result.last}}
.else {&{whichp diff} -u argfunction.basic-result argfunction.result.last}}
fn bless-arg {&{whichp cp} argfunction.result.last argfunction.basic-result}
# final setup and individual configuration
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -29,9 +29,6 @@ call stack .source .try_catch_recursive(body)
.combine ( (it requests reading the user's mind) ) \( stack: $stack \) $nl}
.function_all_flags .arguments_for_argfunction name {
echo cannot specify arguments for $name directly}
.function_all_flags .bad_argc required needed optional [stack ...] {
.echo unacceptable argument count: received $required non-optional
echo , but needed $needed \(with $optional optional\) for $stack$}
.function_all_flags .bad_argfunction_style style {
echo $style is neither an argfunction nor a substitution nor a brace literal}
.function_all_flags .bad_args -- proto assigned needed excess call_stack ... {
......@@ -83,6 +80,9 @@ call stack .source .try_catch_recursive(body)
echo call stack: $stack$}
.function_all_flags .else_without_if stack ... {
echo else without if with call stack: $stack$}
.function_all_flags .epsilon var_val change stack ... {
echo $change is too small relative to $var_val to modify its value
echo call stack: $stack$}
.function_all_flags .excess_argfunction cmd [stack ...] {
echo $cmd does not accept an argfunction with call stack: $cmd $stack$}
.function_all_flags .excessive_exceptions_collected max stack ... {
......@@ -260,55 +260,49 @@ call stack .source .try_catch_recursive(body)
echo call stack: $stack$}
# ability of functions to act as builtin wrappers
.function_all_flags ! args ... {
fn ! args ... {
.if $args$ {.throw .false ${.echo ! $args}}
.else {.nop}}
.function_all_flags af -- [argv ...] .{argfunction} {.argfunction}
.function_all_flags c -- text ... {.combine $text$}
.function_all_flags e -- text ... {.echo $text}
.function_all_flags do_while argv ... .{argfunction} {
fn af -- [argv ...] .{argfunction} {.argfunction}
fn c -- text ... {.combine $text$}
fn e -- text ... {.echo $text}
fn do_while argv ... .{argfunction} {
.try_catch_recursive .break {
.nop $argv
.try_catch_recursive .continue {.argfunction}
.while $argv$ {.argfunction}}}
.function_all_flags echo -- text ... {.echo $text; .combine $nl}
.function_all_flags echo-comments cmd ... {
fn echo -- text ... {.echo $text; .combine $nl}
fn echo-comments cmd ... {
.stepwise $cmd$ {if_only .test_in $1 .nop # #! ## {echo &&&*}}}
.function_all_flags exec -- argv ... {.exec $argv$}
.function_all_flags elif command ... .{argfunction} {
fn exec -- argv ... {.exec $argv$}
fn elif command ... .{argfunction} {
.else_if $command$ {.argfunction}}
.function_all_flags else .{argfunction} {.else {.argfunction}}
fn false {.try_catch_recursive .return_code {${whichp false}}}
.function_all_flags fns -- name args ... .{argfunction} {
.function_all_flags $name [-*] $args$ {.argfunction}}
.function_all_flags if_only -- args ... .{argfunction} {
fn else .{argfunction} {.else {.argfunction}}
fn fns -- name args ... .{argfunction} {fn $name [-?] $args$ {.argfunction}}
fn if_only -- args ... .{argfunction} {
.if $args$ {.argfunction}; .else {.nop}}
.function_all_flags if_only_not -- args ... .{argfunction} {
fn if_only_not -- args ... .{argfunction} {
.if $args$ {.nop}; .else {.argfunction}}
fn ntimes n .{argfunction} {
.while test_var_greater n 0 {
.mapped_argfunction {.argfunction}
.var_subtract n 1}}
.function_all_flags outer_break stack ... {
.replace_exception .break $stack$}
.function_all_flags outer_continue stack ... {
.replace_exception .continue $stack$}
.function_all_flags scope_for var vals ... .{argfunction} {
fn outer_break stack ... {.replace_exception .break $stack$}
fn outer_continue stack ... {.replace_exception .continue $stack$}
fn scope_for var vals ... .{argfunction} {
.for $vals$ {
.scope $1 $var {.argfunction}}}
.function_all_flags outer_for var vals ... .{argfunction} {
fn outer_for var vals ... .{argfunction} {
.for $vals$ {
.scope $1 $var {
.try_catch_recursive outer_break outer_continue {.argfunction}}}}
.function_all_flags outer_while argv ... .{argfunction} {
fn outer_while argv ... .{argfunction} {
.while $argv$ {
.try_catch_recursive outer_break outer_continue {.argfunction}}}
.function_all_flags setf var value {
fn setf var value {
.if .var_exists $var {.set $var $value}
.else {.global $var $value}}
fn single -- args ... {.scope ${$args$}$ result {echo $result}}
fn test -- args ... {
.try_catch_recursive .return_code {${whichp test} $args$}}
fn test_var_not_equal var value {.test_string_unequal $$var $value}
fn test_var_greater -- var value {.test_greater $$var $value}
fn type [-t] args ... [.{argfunction}] {
......@@ -320,36 +314,45 @@ fn whence command [.{argfunction}] {
.try_catch_recursive .function_not_found {
.whence_function $command {.argfunction}}}
fn whichp binary {.which_path $binary $PATH}
.function_all_flags while_and_one_more argv ... .{argfunction} {
fn while_and_one_more argv ... .{argfunction} {
.try_catch_recursive .break {
.while $argv$ {.argfunction}
.try_catch_recursive .continue {.argfunction}}}
.function_all_flags var_exists -- var {.var_exists $var}
.function_all_flags var_in var set ... {.test_in $$var $set$}
.function_all_flags var_less var N {.test_less $$var $N}
.function_all_flags var_val -- [var ...] {
fn var_exists -- var {.var_exists $var}
fn var_in var set ... {.test_in $$var $set$}
fn var_less var N {.test_less $$var $N}
fn var_val -- [var ...] {
.if .var_exists var {.for $var$ {.combine $1 \( $$1 \) \ }}
.else {.nop}}
.function_all_flags paren_if_words -- value {
fn paren_if_words -- value {
.if .test_number_equal ${.argc $value$} 1 {.combine $value}
.else {.combine \( $value \)}}
fn polish -- operator builtin {
fn &&operator -- lhs rhs ... {
if_only .test_in $lhs + - / {
if_only .test_in $lhs + - / * {
.scope ${$lhs $rhs$}$ (-- l r ...) {
.set lhs $l
.set rhs $r}}
.scope $rhs$ (rhs [extra ...]) {
.if .test_in $rhs + - / {
.if .test_in $rhs + - / * {
.scope ${$rhs $extra$}$ (rhs [extra ...]) {
&&builtin lhs $rhs
echo $lhs $extra$}}
.else {
&&builtin lhs $rhs
echo $lhs $extra$}}}}
polish - .var_subtract
polish + .var_add
polish / .var_divide
polish * .var_multiply
polish - .var_subtract
# external commands tested in the test suite
fn false {.try_catch_recursive .return_code {${whichp false}}}
fn ln [-?] target {
.nop $-* # in case the following assertion fails
.test_file_exists $target
&{.which_path ln /bin:/usr/bin} $-* $target}