function.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // The definition of the Builtin, Command_block, and Function classes. The
  2. // first of which executes commands that are implemented by functions in
  3. // builtin.cc, the latter of which map arguments passed to an executable
  4. // and/or tie several other executables into a single executable.
  5. //
  6. // Copyright (C) 2006-2019 Samuel Newbold
  7. #include <algorithm>
  8. #include <iterator>
  9. #include <list>
  10. #include <map>
  11. #include <set>
  12. #include <string>
  13. #include <sys/time.h>
  14. #include <vector>
  15. #include "arg_spec.h"
  16. #include "rwsh_stream.h"
  17. #include "variable_map.h"
  18. #include "argm.h"
  19. #include "arg_script.h"
  20. #include "call_stack.h"
  21. #include "clock.h"
  22. #include "executable.h"
  23. #include "executable_map.h"
  24. #include "prototype.h"
  25. #include "function.h"
  26. Builtin::Builtin(const std::string& name_i,
  27. void (*impl)(const Argm& argm, Error_list& exceptions),
  28. const Argv& prototype_i) :
  29. implementation(impl), name_v(name_i), prototype(prototype_i) {}
  30. // run the given builtin
  31. void Builtin::execute(const Argm& argm, Error_list& exceptions) {
  32. Variable_map locals(argm.parent_map());
  33. prototype.arg_to_param(argm.argv(), locals, exceptions);
  34. locals.bless_unused_vars();
  35. if (argm.argfunction() && prototype.exclude_argfunction)
  36. exceptions.add_error(Exception(Argm::Excess_argfunction));
  37. else if (!argm.argfunction() && prototype.required_argfunction)
  38. exceptions.add_error(Exception(Argm::Missing_argfunction));
  39. if (!global_stack.unwind_stack())
  40. (*implementation)(argm, exceptions);}
  41. std::string Builtin::str() const {return name_v + " " + prototype.str();};
  42. // generate a new Command_block by unescaping argument functions and replacing
  43. // unescaped_argfunction with the argument function in argm
  44. Command_block* Command_block::apply(const Argm& argm, unsigned nesting,
  45. Error_list& exceptions) const {
  46. if ((*this)[0].is_argfunction())
  47. if (argm.argfunction()) {
  48. Command_block* result = new Command_block(*argm.argfunction());
  49. result->promote_soons(nesting);
  50. return result;}
  51. else return 0;
  52. else {
  53. Command_block* result = new Command_block();
  54. std::back_insert_iterator<std::vector<Arg_script> > ins(*result);
  55. for (auto i: *this) i.apply(argm, nesting, ins, exceptions);
  56. result->trailing = trailing;
  57. return result;}}
  58. void Command_block::execute(const Argm& argm, Error_list& exceptions) {
  59. Prototype prototype(Argv{});
  60. Variable_map locals(argm.parent_map());
  61. try {
  62. Argm params(argm.argv(), argm.argfunction(), &locals,
  63. argm.input, argm.output, argm.error);
  64. statements_execute(params, exceptions);
  65. prototype.unused_var_check(&locals, exceptions);}
  66. catch (Exception error) {
  67. prototype.unused_var_check(&locals, exceptions);
  68. throw error;}}
  69. void Command_block::statements_execute(const Argm& src_argm,
  70. Error_list& exceptions) {
  71. for (auto j: *this) {
  72. Argm statement_argm = j.interpret(src_argm, exceptions);
  73. if (global_stack.unwind_stack()) break;
  74. executable_map.run(statement_argm, exceptions);
  75. if (global_stack.unwind_stack()) break;}}
  76. void Command_block::prototype_execute(const Argm& argm,
  77. const Prototype& prototype,
  78. Error_list& exceptions) {
  79. Variable_map locals(argm.parent_map());
  80. prototype.arg_to_param(argm.argv(), locals, exceptions);
  81. if (argm.argfunction() && prototype.exclude_argfunction)
  82. exceptions.add_error(Exception(Argm::Excess_argfunction));
  83. else if (!argm.argfunction() && prototype.required_argfunction)
  84. exceptions.add_error(Exception(Argm::Missing_argfunction));
  85. try {
  86. if (!global_stack.unwind_stack()) {
  87. Argm params(argm.argv(), argm.argfunction(), &locals,
  88. argm.input, argm.output, argm.error);
  89. statements_execute(params, exceptions);}
  90. prototype.unused_var_check(&locals, exceptions);}
  91. catch (Exception error) {
  92. prototype.unused_var_check(&locals, exceptions);
  93. throw error;}}
  94. void Command_block::promote_soons(unsigned nesting) {
  95. if (this) for (auto j = begin(); j != end(); ++j) j->promote_soons(nesting);}
  96. std::string Command_block::str() const {
  97. std::string body;
  98. for (auto i = begin(); i != end()-1; ++i) body += i->str() + "";
  99. return "{" + body + back().str() + "}";} //+ trailing + ",";}
  100. // if src[point] == '{' , then the block ends at the matching '}', otherwise
  101. // it continues to the end of the string.
  102. Command_block::Command_block(const std::string& src,
  103. std::string::size_type& point,
  104. unsigned max_soon, Error_list& errors) {
  105. std::string::size_type tpoint = point;
  106. while (tpoint != std::string::npos) {
  107. if (src[tpoint] == '}')
  108. if (src[point] == '{') break;
  109. else errors.add_error(Exception(Argm::Mismatched_brace,
  110. src.substr(0, tpoint+1)));
  111. else;
  112. if (src[tpoint] == '{' || src[tpoint] == '}' ||
  113. src[tpoint] == ';' || src[tpoint] =='\n') ++tpoint;
  114. push_back(Arg_script(src, tpoint, max_soon, errors));
  115. if (size() != 1 && back().is_argfunction())
  116. default_output <<".argfunction cannot occur as one of several "
  117. "commands\n";}
  118. if (tpoint == std::string::npos) {
  119. if (src[point] == '{') errors.add_error(Exception(Argm::Unclosed_brace,
  120. src.substr(0, point-1)));
  121. point = std::string::npos;}
  122. else point = tpoint + 1;}
  123. Function::Function(const std::string& name_i, const Argv& parameters,
  124. const Command_block& src) :
  125. name_v(name_i), prototype(parameters), body(src) {}
  126. // run the given function
  127. void Function::execute(const Argm& argm, Error_list& exceptions) {
  128. body.prototype_execute(argm, prototype, exceptions);}
  129. void Function::promote_soons(unsigned nesting) {
  130. if (this) body.promote_soons(nesting);}
  131. // convert the function to a string. except for the handling of the name this
  132. // is the inverse of the string constructor.
  133. std::string Function::str() const {
  134. return ".function " + escape(name()) + " " + prototype.str() + " " +
  135. body.str();}