call_stack.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // The definition of the Call_stack and Conditional_state classes. The former
  2. // encapsulates the variables that had been static within Executable classes,
  3. // and the latter encapsulates the state used by if_core
  4. //
  5. // Copyright (C) 2019 Samuel Newbold
  6. #include <algorithm>
  7. #include <list>
  8. #include <map>
  9. #include <set>
  10. #include <string>
  11. #include <vector>
  12. #include "arg_spec.h"
  13. #include "rwsh_stream.h"
  14. #include "variable_map.h"
  15. #include "argm.h"
  16. #include "arg_script.h"
  17. #include "builtin.h"
  18. #include "call_stack.h"
  19. #include "executable.h"
  20. #include "executable_map.h"
  21. #include "prototype.h"
  22. #include "function.h"
  23. void Call_stack::add_error(void) {
  24. unwind_stack_v = true;
  25. ++current_exception_count;}
  26. // code to call exception handlers when requested within a function
  27. void Call_stack::catch_blocks(const Argm& argm, Error_list& exceptions) {
  28. unsigned dropped_catches = 0;
  29. for (auto focus = exceptions.begin(); focus != exceptions.end();)
  30. if (find(argm.begin() + 1, argm.end(), (*focus)[0]) != argm.end()) {
  31. if (dropped_catches >= max_extra) {
  32. if (!execution_handler_excess_thrown)
  33. exceptions.add_error(Exception(Argm::Excessive_exceptions_in_catch,
  34. max_extra));
  35. execution_handler_excess_thrown = true;
  36. return;}
  37. unsigned previous_count = current_exception_count;
  38. in_exception_handler_v = true;
  39. unwind_stack_v = false;
  40. executable_map.run(*focus, exceptions);
  41. in_exception_handler_v = false;
  42. dropped_catches += current_exception_count - previous_count;
  43. if (!unwind_stack()) {
  44. focus = exceptions.erase(focus);
  45. --current_exception_count;}
  46. else focus++;}
  47. else focus++;
  48. if (current_exception_count || exit_requested) unwind_stack_v = true;
  49. else unwind_stack_v = false;
  50. in_exception_handler_v = false;}
  51. // run one exception handler restoring unwind_stack afterwards
  52. void Call_stack::catch_one(Argm& argm, Error_list& exceptions) {
  53. in_exception_handler_v = true;
  54. unwind_stack_v = false;
  55. executable_map.run(argm, exceptions);
  56. in_exception_handler_v = false;
  57. unwind_stack_v = true;}
  58. void Call_stack::collect_errors_core(const Argm& argm, bool logic,
  59. Error_list& parent) {
  60. Argm blank(argm.parent_map(), argm.input, argm.output.child_stream(),
  61. argm.error);
  62. blank.push_back(".mapped_argfunction");
  63. std::vector<std::string> other(argm.begin()+1, argm.end());
  64. for (auto j: *argm.argfunction()) {
  65. if (current_exception_count > max_collect) {
  66. if (!collect_excess_thrown)
  67. parent.add_error(Exception(Argm::Excessive_exceptions_collected,
  68. max_collect));
  69. unwind_stack_v = collect_excess_thrown = true;
  70. return;}
  71. Error_list children;
  72. Argm statement_argm = j.interpret(blank, children);
  73. if (!global_stack.unwind_stack())
  74. executable_map.run(statement_argm, children);
  75. if (children.size()) {
  76. unwind_stack_v = false;
  77. for (auto k: children) {
  78. parent.push_back(k);
  79. if (logic == (find(other.begin(), other.end(), k[0]) != other.end()))
  80. unwind_stack_v = true;}}} // will cause subsequent j to not run
  81. if (parent.size()) unwind_stack_v = true;}
  82. /* code to call exception handlers, separated out of operator() for clarity.
  83. The requirements for stack unwinding to work properly are as
  84. follows: any code that runs more than one other executable must test
  85. unwind_stack() in between each executable, which must be of an Executable
  86. rather than a direct call to the function that implements a builtin (the
  87. code below to run the fallback_handler is the only exception to this rule).
  88. main does not need to do this handling, because anything that it calls
  89. directly will have an initial nesting of 0.*/
  90. void Call_stack::exception_handler(Error_list& exceptions) {
  91. in_exception_handler_v = true;
  92. unwind_stack_v = false;
  93. std::set<std::string> failed_handlers;
  94. for(;exceptions.size(); exceptions.pop_front(), --current_exception_count){
  95. Argm& focus(exceptions.front());
  96. if (failed_handlers.find(focus[0]) == failed_handlers.end()) {
  97. unsigned previous_count = current_exception_count;
  98. executable_map.run(focus, exceptions);
  99. if (unwind_stack() || current_exception_count > previous_count) {
  100. failed_handlers.insert(focus[0]);
  101. exceptions.insert(++exceptions.begin(), exceptions.back());
  102. exceptions.pop_back();
  103. unwind_stack_v = false;}}
  104. if (failed_handlers.find(focus[0]) != failed_handlers.end())
  105. b_fallback_handler(Argm(".fallback_handler", focus.argv(),
  106. focus.argfunction(), Variable_map::global_map,
  107. focus.input, focus.output, focus.error),
  108. exceptions);}
  109. collect_excess_thrown = execution_handler_excess_thrown = false;
  110. in_exception_handler_v = false;}
  111. bool Call_stack::remove_exceptions(const std::string &name,
  112. Error_list& exceptions) {
  113. bool ret = false;
  114. bool unwind_stack_before = unwind_stack_v;
  115. for (auto focus = exceptions.begin(); focus != exceptions.end();)
  116. if ((*focus)[0] == name) {
  117. ret = true;
  118. focus = exceptions.erase(focus);
  119. --current_exception_count;}
  120. else focus++;
  121. if (unwind_stack_before && !exceptions.size()) unwind_stack_v = false;
  122. return ret;}
  123. void Call_stack::replace_error(void) {++current_exception_count;}
  124. void Call_stack::request_exit(int exit_val) {
  125. exit_requested = true;
  126. if (!in_exception_handler()) unwind_stack_v = true;
  127. exit_v += exit_val;}
  128. void Call_stack::reset(void) {
  129. unwind_stack_v = false;
  130. current_exception_count = 0;}
  131. Conditional_state::Conditional_state(void) : in_if_block(false),
  132. successful_condition(false), exception_thrown(false) {}