# Mu - 029tools.cc

      1 //: Allow Mu programs to log facts just like we've been doing in C++ so far.
      2
      3 :(scenario trace)
      4 def main [
      5   trace 1, [foo], [this is a trace in Mu]
      6 ]
      7 +foo: this is a trace in Mu
      8
      9 :(before "End Primitive Recipe Declarations")
     10 TRACE,
     11 :(before "End Primitive Recipe Numbers")
     12 put(Recipe_ordinal, "trace", TRACE);
     13 :(before "End Primitive Recipe Checks")
     14 case TRACE: {
     15   if (SIZE(inst.ingredients) < 3) {
     16     raise << maybe(get(Recipe, r).name) << "'trace' takes three or more ingredients rather than '" << to_original_string(inst) << "'\n" << end();
     17     break;
     18   }
     19   if (!is_mu_number(inst.ingredients.at(0))) {
     20     raise << maybe(get(Recipe, r).name) << "first ingredient of 'trace' should be a number (depth), but got '" << inst.ingredients.at(0).original_string << "'\n" << end();
     21     break;
     22   }
     23   if (!is_literal_text(inst.ingredients.at(1))) {
     24     raise << maybe(get(Recipe, r).name) << "second ingredient of 'trace' should be a literal string (label), but got '" << inst.ingredients.at(1).original_string << "'\n" << end();
     25     break;
     26   }
     27   break;
     28 }
     29 :(before "End Primitive Recipe Implementations")
     30 case TRACE: {
     31   int depth = ingredients.at(0).at(0);
     32   string label = current_instruction().ingredients.at(1).name;
     33   ostringstream out;
     34   for (int i = 2;  i < SIZE(current_instruction().ingredients);  ++i) {
     35     if (i > 2) out << ' ';
     36     out << inspect(current_instruction().ingredients.at(i), ingredients.at(i));
     37   }
     38   trace(depth, label) << out.str() << end();
     39   break;
     40 }
     41
     42 //: simpler limited version of 'trace'
     43
     44 :(before "End Primitive Recipe Declarations")
     45 STASH,
     46 :(before "End Primitive Recipe Numbers")
     47 put(Recipe_ordinal, "stash", STASH);
     48 :(before "End Primitive Recipe Checks")
     49 case STASH: {
     50   break;
     51 }
     52 :(before "End Primitive Recipe Implementations")
     53 case STASH: {
     54   ostringstream out;
     55   for (int i = 0;  i < SIZE(current_instruction().ingredients);  ++i) {
     56     if (i) out << ' ';
     57     out << inspect(current_instruction().ingredients.at(i), ingredients.at(i));
     58   }
     59   trace(2, "app") << out.str() << end();
     60   break;
     61 }
     62
     63 :(scenario stash_literal_string)
     64 def main [
     65   stash [foo]
     66 ]
     67 +app: foo
     68
     69 :(scenario stash_literal_number)
     70 def main [
     71   stash [foo:], 4
     72 ]
     73 +app: foo: 4
     74
     75 :(scenario stash_number)
     76 def main [
     77   1:num <- copy 34
     78   stash [foo:], 1:num
     79 ]
     80 +app: foo: 34
     81
     82 :(code)
     83 string inspect(const reagent& r, const vector<double>& data) {
     84   if (is_literal(r))
     85     return r.name;
     86   // End inspect Special-cases(r, data)
     87   ostringstream out;
     88   for (long long i = 0;  i < SIZE(data);  ++i) {
     89     if (i) out << ' ';
     90     out << no_scientific(data.at(i));
     91   }
     92   return out.str();
     93 }
     94
     95 :(before "End Primitive Recipe Declarations")
     96 HIDE_ERRORS,
     97 :(before "End Primitive Recipe Numbers")
     98 put(Recipe_ordinal, "hide-errors", HIDE_ERRORS);
     99 :(before "End Primitive Recipe Checks")
    100 case HIDE_ERRORS: {
    101   break;
    102 }
    103 :(before "End Primitive Recipe Implementations")
    104 case HIDE_ERRORS: {
    105   Hide_errors = true;
    106   break;
    107 }
    108
    109 :(before "End Primitive Recipe Declarations")
    110 SHOW_ERRORS,
    111 :(before "End Primitive Recipe Numbers")
    112 put(Recipe_ordinal, "show-errors", SHOW_ERRORS);
    113 :(before "End Primitive Recipe Checks")
    114 case SHOW_ERRORS: {
    115   break;
    116 }
    117 :(before "End Primitive Recipe Implementations")
    118 case SHOW_ERRORS: {
    119   Hide_errors = false;
    120   break;
    121 }
    122
    123 :(before "End Primitive Recipe Declarations")
    124 TRACE_UNTIL,
    125 :(before "End Primitive Recipe Numbers")
    126 put(Recipe_ordinal, "trace-until", TRACE_UNTIL);
    127 :(before "End Primitive Recipe Checks")
    128 case TRACE_UNTIL: {
    129   break;
    130 }
    131 :(before "End Primitive Recipe Implementations")
    132 case TRACE_UNTIL: {
    133   if (Trace_stream) {
    134     Trace_stream->collect_depth = ingredients.at(0).at(0);
    135   }
    136   break;
    137 }
    138
    139 :(before "End Primitive Recipe Declarations")
    140 _DUMP_TRACE,
    141 :(before "End Primitive Recipe Numbers")
    142 put(Recipe_ordinal, "$dump-trace", _DUMP_TRACE);
    143 :(before "End Primitive Recipe Checks")
    144 case _DUMP_TRACE: {
    145   break;
    146 }
    147 :(before "End Primitive Recipe Implementations")
    148 case _DUMP_TRACE: {
    149   if (ingredients.empty()) {
    150     DUMP("");
    151   }
    152   else {
    153     DUMP(current_instruction().ingredients.at(0).name);
    154   }
    155   break;
    156 }
    157
    158 :(before "End Primitive Recipe Declarations")
    159 _CLEAR_TRACE,
    160 :(before "End Primitive Recipe Numbers")
    161 put(Recipe_ordinal, "$clear-trace", _CLEAR_TRACE);
    162 :(before "End Primitive Recipe Checks")
    163 case _CLEAR_TRACE: {
    164   break;
    165 }
    166 :(before "End Primitive Recipe Implementations")
    167 case _CLEAR_TRACE: {
    168   if (Trace_stream) Trace_stream->past_lines.clear();
    169   break;
    170 }
    171
    172 :(before "End Primitive Recipe Declarations")
    173 _SAVE_TRACE,
    174 :(before "End Primitive Recipe Numbers")
    175 put(Recipe_ordinal, "$save-trace", _SAVE_TRACE);
    176 :(before "End Primitive Recipe Checks")
    177 case _SAVE_TRACE: {
    178   break;
    179 }
    180 :(before "End Primitive Recipe Implementations")
    181 case _SAVE_TRACE: {
    182   if (Save_trace) Trace_stream->save();
    183   break;
    184 }
    185
    186 //:: 'cheating' by using the host system
    187
    188 :(before "End Primitive Recipe Declarations")
    189 _PRINT,
    190 :(before "End Primitive Recipe Numbers")
    191 put(Recipe_ordinal, "$print", _PRINT);
    192 :(before "End Primitive Recipe Checks")
    193 case _PRINT: {
    194   break;
    195 }
    196 :(before "End Primitive Recipe Implementations")
    197 case _PRINT: {
    198   for (int i = 0;  i < SIZE(ingredients);  ++i) {
    199     if (is_literal(current_instruction().ingredients.at(i))) {
    200       trace(9998, "run") << "$print: " << current_instruction().ingredients.at(i).name << end();
    201       if (!has_property(current_instruction().ingredients.at(i), "newline")) {
    202         cout << current_instruction().ingredients.at(i).name;
    203       }
    204       // hack: '$print 10' prints '10', but '$print 10/newline' prints '\n'
    205       // End $print 10/newline Special-cases
    206       else {
    207         cout << '\n';
    208       }
    209     }
    210     // End $print Special-cases
    211     else {
    212       for (int j = 0;  j < SIZE(ingredients.at(i));  ++j) {
    213         trace(9998, "run") << "$print: " << ingredients.at(i).at(j) << end();
    214         if (j > 0) cout << " ";
    215         cout << no_scientific(ingredients.at(i).at(j));
    216       }
    217     }
    218   }
    219   cout.flush();
    220   break;
    221 }
    222
    223 :(before "End Primitive Recipe Declarations")
    224 _EXIT,
    225 :(before "End Primitive Recipe Numbers")
    226 put(Recipe_ordinal, "$exit", _EXIT);
    227 :(before "End Primitive Recipe Checks")
    228 case _EXIT: {
    229   break;
    230 }
    231 :(before "End Primitive Recipe Implementations")
    232 case _EXIT: {
    233   exit(0);
    234   break;
    235 }
    236
    237 :(before "End Primitive Recipe Declarations")
    238 _SYSTEM,
    239 :(before "End Primitive Recipe Numbers")
    240 put(Recipe_ordinal, "$system", _SYSTEM);
    241 :(before "End Primitive Recipe Checks")
    242 case _SYSTEM: {
    243   if (SIZE(inst.ingredients) != 1) {
    244     raise << maybe(get(Recipe, r).name) << "'$system' requires exactly one ingredient, but got '" << to_string(inst) << "'\n" << end();
    245     break;
    246   }
    247   if (!is_literal_text(inst.ingredients.at(0))) {
    248     raise << maybe(get(Recipe, r).name) << "ingredient to '$system' must be a literal text, but got '" << to_string(inst) << "'\n" << end();
    249   }
    250   break;
    251 }
    252 :(before "End Primitive Recipe Implementations")
    253 case _SYSTEM: {
    254   int status = system(current_instruction().ingredients.at(0).name.c_str());
    255   products.resize(1);
    256   products.at(0).push_back(status);
    257   break;
    258 }
    259
    260 :(before "End Primitive Recipe Declarations")
    261 _DUMP_MEMORY,
    262 :(before "End Primitive Recipe Numbers")
    263 put(Recipe_ordinal, "$dump-memory", _DUMP_MEMORY);
    264 :(before "End Primitive Recipe Checks")
    265 case _DUMP_MEMORY: {
    266   break;
    267 }
    268 :(before "End Primitive Recipe Implementations")
    269 case _DUMP_MEMORY: {
    270   dump_memory();
    271   break;
    272 }
    273
    274 //: In times of real extremis we need to create a whole new modality for debug
    275 //: logs, independent of other changes to the screen or Trace_stream.
    276
    277 :(before "End Globals")
    278 ofstream LOG;
    279 :(before "End One-time Setup")
    280 //? LOG.open("log");
    281
    282 :(before "End Primitive Recipe Declarations")
    283 _LOG,
    284 :(before "End Primitive Recipe Numbers")
    285 put(Recipe_ordinal, "$log", _LOG);
    286 :(before "End Primitive Recipe Checks")
    287 case _LOG: {
    288   break;
    289 }
    290 :(before "End Primitive Recipe Implementations")
    291 case _LOG: {
    292   ostringstream out;
    293   for (int i = 0;  i < SIZE(current_instruction().ingredients);  ++i) {
    294     out << inspect(current_instruction().ingredients.at(i), ingredients.at(i));
    295   }
    296   LOG << out.str() << '\n';
    297   break;
    298 }
    299
    300 //: set a variable from within Mu code
    301 //: useful for selectively tracing or printing after some point
    302 :(before "End Globals")
    303 bool Foo = false;
    304 :(before "End Primitive Recipe Declarations")
    305 _FOO,
    306 :(before "End Primitive Recipe Numbers")
    307 put(Recipe_ordinal, "$foo", _FOO);
    308 :(before "End Primitive Recipe Checks")
    309 case _FOO: {
    310   break;
    311 }
    312 :(before "End Primitive Recipe Implementations")
    313 case _FOO: {
    314   Foo = true;
    315   break;
    316 }