1 //: Continuations are a powerful primitive for constructing advanced kinds of
  2 //: control *policies* like back-tracking.
  3 //:
  4 //: In Mu, continuations are first-class and delimited, and are constructed
  5 //: out of two primitives:
  6 //:
  7 //:  * 'call-with-continuation-mark' marks the top of the call stack and then
  8 //:    calls the provided function.
  9 //:  * 'return-continuation-until-mark' copies the top of the stack
 10 //:    until the mark, and returns it as the result of
 11 //:    call-with-continuation-mark (which might be a distant ancestor on the call
 12 //:    stack; intervening calls don't return)
 13 //:
 14 //: The resulting slice of the stack can now be called just like a regular
 15 //: function.
 16 
 17 :(before "End Mu Types Initialization")
 18 pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
void contact_in_group(void **state);
void contact_not_in_group(void **state);
void contact_name_when_name_exists(void **state);
void contact_jid_when_name_not_exists(void **state);
void contact_string_when_name_exists(void **state);
void contact_string_when_name_not_exists(void **state);
void contact_string_when_default_resource(void **state);
void contact_presence_offline(void **state);
void contact_presence_uses_highest_priority(void **state);
void contact_presence_chat_when_same_prioroty(void **state);
void contact_presence_online_when_same_prioroty(void **state);
void contact_presence_away_when_same_prioroty(void **state);
void contact_presence_xa_when_same_prioroty(void **state);
void contact_presence_dnd(void **state);
void contact_subscribed_when_to(void **state);
void contact_subscribed_when_both(void **state);
void contact_not_subscribed_when_from(void **state);
void contact_not_subscribed_when_no_subscription_value(void **state);
void contact_not_available(void **state);
void contact_not_available_when_highest_priority_away(void **state);
void contact_not_available_when_highest_priority_xa(void **state);
void contact_not_available_when_highest_priority_dnd(void **state);
void contact_available_when_highest_priority_online(void **state);
void contact_available_when_highest_priority_chat(void **state);
/span>calls.front().is_base_of_continuation = true; 105 Current_routine->calls.push_front(call(Recipe_ordinal[current_instruction().ingredients.at(0).name])); 106 ingredients.erase(ingredients.begin()); // drop the callee 107 finish_call_housekeeping(caller_instruction, ingredients); 108 continue; 109 } 110 111 //: save the slice of current call stack until the 'call-with-continuation-mark' 112 //: call, and return it as the result. 113 //: todo: implement delimited continuations in Mu's memory 114 :(before "End Globals") 115 map<long long int, call_stack> Delimited_continuation; 116 long long int Next_delimited_continuation_id = 0; 117 :(before "End Reset") 118 Delimited_continuation.clear(); 119 Next_delimited_continuation_id = 0; 120 121 :(before "End Primitive Recipe Declarations") 122 RETURN_CONTINUATION_UNTIL_MARK, 123 :(before "End Primitive Recipe Numbers") 124 Recipe_ordinal["return-continuation-until-mark"] = RETURN_CONTINUATION_UNTIL_MARK; 125 :(before "End Primitive Recipe Checks") 126 case RETURN_CONTINUATION_UNTIL_MARK: { 127 break; 128 } 129 :(before "End Primitive Recipe Implementations") 130 case RETURN_CONTINUATION_UNTIL_MARK: { 131 // first clear any existing ingredients, to isolate the creation of the 132 // continuation from its calls 133 Current_routine->calls.front().ingredient_atoms.clear(); 134 Current_routine->calls.front().next_ingredient_to_process = 0; 135 // copy the current call stack until the most recent marked call 136 call_stack::iterator find_base_of_continuation(call_stack& c); // manual prototype containing '::' 137 call_stack::iterator base = find_base_of_continuation(Current_routine->calls); 138 if (base == Current_routine->calls.end()) { 139 ¦ raise << maybe(current_recipe_name()) << "couldn't find a 'call-with-continuation-mark' to return to\n" << end(); 140 ¦ raise << maybe(current_recipe_name()) << "call stack:\n" << end(); 141 ¦ for (call_stack::iterator p = Current_routine->calls.begin(); p != Current_routine->calls.end(); ++p) 142 ¦ ¦ raise << maybe(current_recipe_name()) << " " << get(Recipe, p->running_recipe).name << '\n' << end(); 143 ¦ break; 144 } 145 Delimited_continuation[Next_delimited_continuation_id] = call_stack(Current_routine->calls.begin(), base); 146 while (Current_routine->calls.begin() != base) { 147 ¦ if (Trace_stream) { 148 ¦ ¦ --Trace_stream->callstack_depth; 149 ¦ ¦ assert(Trace_stream->callstack_depth >= 0); 150 ¦ } 151 ¦ Current_routine->calls.pop_front(); 152 } 153 // return it as the result of the marked call 154 products.resize(1); 155 products.at(0).push_back(Next_delimited_continuation_id); 156 ++Next_delimited_continuation_id; 157 break; // continue to process rest of marked call 158 } 159 160 :(code) 161 call_stack::iterator find_base_of_continuation(call_stack& c) { 162 for (call_stack::iterator p = c.begin(); p != c.end(); ++p) 163 ¦ if (p->is_base_of_continuation) return p; 164 return c.end(); 165 } 166 167 //: overload 'call' for continuations 168 :(after "Begin Call") 169 if (current_instruction().ingredients.at(0).type->atom 170 ¦ && current_instruction().ingredients.at(0).type->name == "continuation") { 171 // copy multiple calls on to current call stack 172 assert(scalar(ingredients.at(0))); 173 if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) 174 ¦ raise << maybe(current_recipe_name()) << "no such delimited continuation " << current_instruction().ingredients.at(0).original_string << '\n' << end(); 175 const call_stack& new_calls = Delimited_continuation[ingredients.at(0).at(0)]; 176 const call& caller = (SIZE(new_calls) > 1) ? *++new_calls.begin() : Current_routine->calls.front(); 177 for (call_stack::const_reverse_iterator p = new_calls.rbegin(); p != new_calls.rend(); ++p) 178 ¦ Current_routine->calls.push_front(*p); 179 if (Trace_stream) { 180 ¦ Trace_stream->callstack_depth += SIZE(new_calls); 181 ¦ trace("trace") << "calling delimited continuation; growing callstack depth to " << Trace_stream->callstack_depth << end(); 182 ¦ assert(Trace_stream->callstack_depth < 9000); // 9998-101 plus cushion 183 } 184 ++current_step_index(); // skip past the return-continuation-until-mark 185 ingredients.erase(ingredients.begin()); // drop the callee 186 finish_call_housekeeping(to_instruction(caller), ingredients); 187 continue; 188 }