1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 16:44:21 +03:00
inform7/docs/core-module/25-ci.html
2019-08-31 13:56:36 +01:00

981 lines
102 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>25/pi</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '25/ci' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">core</a></li><li><a href="index.html#25">Chapter 25: Compilation</a></li><li><b>Compile Invocations</b></li></ul><p class="purpose">Here we generate Inform 6 code to execute the phrase(s) called for by an invocation list.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP3">&#167;3. Top level: compiling lists</a></li><li><a href="#SP4">&#167;4. Lower level: compiling single invocations</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>This represents the tokens being used when invoking a phrase:
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">tokens_packet</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">tokens_count</span><span class="plain">; </span> <span class="comment">number of arguments to phrase</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">args</span><span class="plain">[32]; </span> <span class="comment">what they are</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">kind_required</span><span class="plain">[32]; </span> <span class="comment">what pointer kinds of value, if they are</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">as_requested</span><span class="plain">; </span> <span class="comment">kind for the function call</span>
<span class="plain">} </span><span class="reserved">tokens_packet</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure tokens_packet is accessed in 25/ciac, 25/cii and here.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. Top level: compiling lists. </b>The invocation list will consist of at least one invocation, and all of these
except possibly the last one will be "unproven" by the type-checking
apparatus &mdash; that is, will not be safe to execute without run-time checking.
We must execute exactly one invocation in the list &mdash; the first one which
is found to be type-safe &mdash; or else produce a run-time error message.
</p>
<p class="inwebparagraph">It follows that there is only one case where no checking is needed: when
the list consists of a single proven invocation. This we compile directly
to the I6 stream. In all other cases, we compile a function call to a
"resolver routine" to the I6 stream, delegating the choice to an
external routine: and we will probably have to compile this routine, too,
unless the decision on this block is one that we recognise from an
earlier invocation list (in what may be another setting entirely).
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Invocations::Compiler::compile_invocation_list</span><span class="plain">(</span><span class="identifier">value_holster</span><span class="plain"> *</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">invl</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_wanted</span><span class="plain"> == </span><span class="identifier">INTER_VAL_VHMODE</span><span class="plain">) </span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_provided</span><span class="plain"> = </span><span class="identifier">INTER_VAL_VHMODE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_provided</span><span class="plain"> = </span><span class="identifier">INTER_VOID_VHMODE</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">wn</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::length_of_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">) &gt; 0) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"Compiling from %d invocations\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="functiontext">Invocations::length_of_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">));</span>
<span class="identifier">source_location</span><span class="plain"> </span><span class="identifier">sl</span><span class="plain"> = </span><span class="identifier">Lexer::word_location</span><span class="plain">(</span><span class="identifier">wn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_to_save_self</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">))) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">PUSH_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">SELF_HL</span><span class="plain">));</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_unproven</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">))) {</span>
&lt;<span class="cwebmacro">Compile using run-time resolution to choose between invocations</span> <span class="cwebmacronumber">3.2</span>&gt;<span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
&lt;<span class="cwebmacro">Compile as a series of invocations all of which run</span> <span class="cwebmacronumber">3.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_to_save_self</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">))) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">PULL_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::ref_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">SELF_HL</span><span class="plain">));</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Invocations::Compiler::compile_invocation_list is used in 14/rv (<a href="14-rv.html#SP24">&#167;24</a>), 25/cp (<a href="25-cp.html#SP6">&#167;6</a>).</p>
<p class="inwebparagraph"><a id="SP3_1"></a><b>&#167;3.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile as a series of invocations all of which run</span> <span class="cwebmacronumber">3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> = 0;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">inv</span><span class="plain">;</span>
<span class="identifier">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">invl</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"C%d: $e\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">pos</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">)) {</span>
<span class="functiontext">NewVerbs::ConjugateVerb_invoke_emit</span><span class="plain">(</span>
<span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::get_modal_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="constant">say_verb_negated_ANNOT</span><span class="plain">));</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">)) {</span>
<span class="functiontext">Adjectives::Meanings::emit</span><span class="plain">(</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">));</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
&lt;<span class="cwebmacro">Otherwise, use the standard way to compile an invoked phrase</span> <span class="cwebmacronumber">3.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3">&#167;3</a>.</p>
<p class="inwebparagraph"><a id="SP3_1_1"></a><b>&#167;3.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Otherwise, use the standard way to compile an invoked phrase</span> <span class="cwebmacronumber">3.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">ParseTree::get_phrase_invoked</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">);</span>
<span class="reserved">tokens_packet</span><span class="plain"> </span><span class="identifier">tokens</span><span class="plain">;</span>
&lt;<span class="cwebmacro">First construct an arguments packet</span> <span class="cwebmacronumber">3.1.1.1</span>&gt;<span class="plain">;</span>
<span class="identifier">value_holster</span><span class="plain"> </span><span class="identifier">VH2</span><span class="plain"> = </span><span class="identifier">Holsters::new</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_wanted</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">returned_in_manner</span><span class="plain"> =</span>
<span class="functiontext">Invocations::Compiler::compile_single_invocation</span><span class="plain">(&amp;</span><span class="identifier">VH2</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">, &amp;</span><span class="identifier">sl</span><span class="plain">, &amp;</span><span class="identifier">tokens</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">phrase_being_compiled</span><span class="plain">) &amp;&amp; (</span><span class="identifier">returned_in_manner</span><span class="plain"> != </span><span class="constant">DONT_KNOW_MOR</span><span class="plain">))</span>
&lt;<span class="cwebmacro">If the invocation compiled to a return from a function, check this is allowed</span> <span class="cwebmacronumber">3.1.1.2</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_1">&#167;3.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_1_1_1"></a><b>&#167;3.1.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">First construct an arguments packet</span> <span class="cwebmacronumber">3.1.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">tokens</span><span class="element">.tokens_count</span><span class="plain"> = </span><span class="functiontext">Invocations::get_no_tokens_needed</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">tokens</span><span class="element">.tokens_count</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">val</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_as_parsed</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="functiontext">Specifications::to_kind</span><span class="plain">(</span>
<span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.token_sequence</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.to_match</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Phrases::TypeData::invoked_inline</span><span class="plain">(</span><span class="identifier">ph</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Kinds::Behaviour::definite</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">))</span>
<span class="identifier">tokens</span><span class="element">.kind_required</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="functiontext">Specifications::to_kind</span><span class="plain">(</span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">tokens</span><span class="element">.kind_required</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">K</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.token_sequence</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.construct</span><span class="plain"> == </span><span class="constant">KIND_NAME_PT_CONSTRUCT</span><span class="plain">)</span>
<span class="identifier">tokens</span><span class="element">.args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="functiontext">Rvalues::new_nothing_object_constant</span><span class="plain">();</span>
<span class="reserved">else</span>
<span class="identifier">tokens</span><span class="element">.args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">val</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">return_kind</span><span class="plain"> = </span><span class="identifier">ParseTree::get_kind_resulting</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">return_kind</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">ph</span><span class="plain">)) </span><span class="identifier">return_kind</span><span class="plain"> = </span><span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.return_kind</span><span class="plain">;</span>
<span class="identifier">tokens</span><span class="element">.as_requested</span><span class="plain"> =</span>
<span class="identifier">Kinds::function_kind</span><span class="plain">(</span><span class="identifier">tokens</span><span class="element">.tokens_count</span><span class="plain">, </span><span class="identifier">tokens</span><span class="element">.kind_required</span><span class="plain">, </span><span class="identifier">return_kind</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_1_1">&#167;3.1.1</a>, <a href="#SP3_2_3_3_1">&#167;3.2.3.3.1</a>, <a href="#SP3_2_3_4_1">&#167;3.2.3.4.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_1_1_2"></a><b>&#167;3.1.1.2. </b>For example, a standard "To..." phrase isn't allowed to contain the invocation
</p>
<blockquote>
<p>decide on 178;</p>
</blockquote>
<p class="inwebparagraph">since it isn't a phrase to decide anything. This is where that's checked:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">If the invocation compiled to a return from a function, check this is allowed</span> <span class="cwebmacronumber">3.1.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">manner_expected</span><span class="plain"> = </span><span class="identifier">phrase_being_compiled</span><span class="plain">-</span><span class="element">&gt;type_data.manner_of_return</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">returned_in_manner</span><span class="plain"> != </span><span class="identifier">manner_expected</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">manner_expected</span><span class="plain"> != </span><span class="constant">DECIDES_NOTHING_AND_RETURNS_MOR</span><span class="plain">)) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"C%d: $e: returned in manner %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">returned_in_manner</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"vs Phrase being compiled: %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">manner_expected</span><span class="plain">);</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="identifier">Problems::quote_text</span><span class="plain">(2,</span>
<span class="functiontext">Phrases::TypeData::describe_manner_of_return</span><span class="plain">(</span><span class="identifier">returned_in_manner</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">));</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">Problems::quote_text</span><span class="plain">(3,</span>
<span class="functiontext">Phrases::TypeData::describe_manner_of_return</span><span class="plain">(</span><span class="identifier">manner_expected</span><span class="plain">,</span>
<span class="plain">&amp;(</span><span class="identifier">phrase_being_compiled</span><span class="plain">-</span><span class="element">&gt;type_data</span><span class="plain">), &amp;</span><span class="identifier">K</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K</span><span class="plain">) </span><span class="functiontext">Problems::quote_kind</span><span class="plain">(4, </span><span class="identifier">K</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_WrongEndToPhrase</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">K</span><span class="plain">)</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"The line %1 seems to be a way that the phrase you're defining can come "</span>
<span class="string">"to an end, with %2, but it should always end up with a phrase to "</span>
<span class="string">"decide %4."</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"The line %1 seems to be a way that the phrase you're defining can come "</span>
<span class="string">"to an end, with %2, but it should always end up with %3."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_1_1">&#167;3.1.1</a>, <a href="#SP3_2_3_3_1_3">&#167;3.2.3.3.1.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2"></a><b>&#167;3.2. </b>We get to here if the first invocation is unproven, meaning that at compile
time it was impossible to determine whether it was type-safe to execute. We must
therefore compile code to determine this at run-time.
</p>
<p class="inwebparagraph">There are two basic forms of this: "void mode", where the phrases are going to
be Inform 6 statements in a void context, and "value mode", where the phrases
will be expressions being evaluated.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile using run-time resolution to choose between invocations</span> <span class="cwebmacronumber">3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">ParseTree::get_phrase_invoked</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">));</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain"> = </span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">));</span>
<span class="functiontext">Frames::need_at_least_this_many_formals</span><span class="plain">(</span><span class="identifier">N</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">void_mode</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.manner_of_return</span><span class="plain"> == </span><span class="constant">DECIDES_NOTHING_MOR</span><span class="plain">) </span><span class="identifier">void_mode</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Compile the resolution</span> <span class="cwebmacronumber">3.2.3</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3">&#167;3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_1"></a><b>&#167;3.2.1. </b>Our basic idea is best explained in void mode, where it's much simpler to
carry out. Suppose we have invocations I1, ..., In, and tokens T1, ..., Tm.
(In a group like this, every invocation will have the same number of tokens.)
We want each invocation in turn to try to handle the situation, and to stop
as soon as one of them does. The first thought is this:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">if (condition for I1 to be valid) invoke I1(T1, ..., Tm);</span>
<span class="plain">else if (condition for I2 to be valid) invoke I2(T1, ..., Tm);</span>
<span class="plain">...</span>
<span class="plain">else run-time-error-message();</span>
</pre>
<p class="inwebparagraph">where the chain of execution runs into the error message code only if none
of I1, ..., In can be applied. In fact, it will sometimes happen that the
final invocation can be proved applicable at compile time, and then we'll
compile this instead:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">if (condition for I1 to be valid) invoke I1(T1, ..., Tm);</span>
<span class="plain">else if (condition for I2 to be valid) invoke I2(T1, ..., Tm);</span>
<span class="plain">else invoke In(T1, ..., Tm);</span>
</pre>
<p class="inwebparagraph">Note that it's not possible for an intermediate invocation in the group to
be provably correct, because if it is then we wouldn't have collected any
further possibilities.
</p>
<p class="inwebparagraph"><a id="SP3_2_2"></a><b>&#167;3.2.2. </b>That's almost what we do, but not quite. The problem lies in the fact that
the tokens T1, ..., Tm are evaluated multiple times - not in the invocations
(since only one is reached in execution) but in the condition tests. This
multiple evaluation would be incorrect if token evaluation had side-effects,
as it easily might (for example if T1 were a call to some phrase to decide
something, and that phrase had side-effects). So in fact we modify our
scheme like so:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">formal_par1 = T1;</span>
<span class="plain">formal_par2 = T2;</span>
<span class="plain">...</span>
<span class="plain">if (condition for I1 to be valid) invoke I1(formal_par1, ..., formal_parm);</span>
<span class="plain">else if (condition for I2 to be valid) invoke I2(formal_par1, ..., formal_parm);</span>
<span class="plain">...</span>
<span class="plain">else run-time-error-message();</span>
</pre>
<p class="inwebparagraph">This fixes the side-effect problem, provided we compile the conditions so
that they measure the "formal parameters" instead of the original T1, T2, ...
But another possible trap is that the <code class="display"><span class="extract">formal_par1</span></code>, ..., variables need
to be local to the current I6 stack frame, since evaluation of T2, say,
might itself involve a call to another phrase which recursively needs to
make a resolution itself.
</p>
<p class="inwebparagraph">Finding local storage here is more problematic than it looks. I6 has an
absolute limit on the number of local variables, imposed by the virtual
machines it runs on. We can't create any local stack space, because the
stack isn't memory-accessible on either of the VMs Inform compiles to. It's
not reliable to create an auxiliary stack in main memory, because this
couldn't resize on the Z-machine, and we want to avoid use of the heap,
because we want Inform to carry on working even in cramped Z-machine cases
where there's no memory for any heap at all. What we do, then, is to store
<code class="display"><span class="extract">formal_par1</span></code> et seq as global I6 variables, and to use an outer shell
routine to push and pull their values, thus in effect making them additional
locals, albeit at a small performance hit.
</p>
<p class="inwebparagraph"><a id="SP3_2_3"></a><b>&#167;3.2.3. </b>In value mode we want the same strategy and code paths, but all in
the context of a value.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile the resolution</span> <span class="cwebmacronumber">3.2.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">void_mode</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Compile code to set the formal parameters in void mode</span> <span class="cwebmacronumber">3.2.3.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile code to apply the first invocation which is applicable</span> <span class="cwebmacronumber">3.2.3.3</span>&gt;<span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">TERNARYSEQUENTIAL_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_conditions_tested</span><span class="plain"> = 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">Produce::level</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
&lt;<span class="cwebmacro">Emit code to set the formal parameters in expression mode</span> <span class="cwebmacronumber">3.2.3.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain"> != </span><span class="identifier">Produce::level</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">())) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"formal parameter expression error"</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">NC</span><span class="plain"> = 0, </span><span class="identifier">unprov</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">prov</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Count the applicability conditions</span> <span class="cwebmacronumber">3.2.3.5</span>&gt;<span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">); </span><span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="string">"Think %d unprov %d prov %d"</span><span class="plain">, </span><span class="identifier">NC</span><span class="plain">, </span><span class="identifier">unprov</span><span class="plain">, </span><span class="identifier">prov</span><span class="plain">); </span><span class="functiontext">Emit::code_comment</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">); </span><span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">unprov</span><span class="plain">) { </span><span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">OR_BIP</span><span class="plain">); </span><span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); }</span>
&lt;<span class="cwebmacro">Compile code to apply the first invocation which is applicable, as expression</span> <span class="cwebmacronumber">3.2.3.4</span>&gt;<span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = 0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">NC</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">prov</span><span class="plain">) </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">unprov</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Compile code for the execution path where no invocations were applicable</span> <span class="cwebmacronumber">3.2.3.6</span>&gt;<span class="plain">;</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain"> != </span><span class="identifier">Produce::level</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">())) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"applicability expression error"</span><span class="plain">);</span>
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">FORMAL_RV_HL</span><span class="plain">));</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2">&#167;3.2</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_1"></a><b>&#167;3.2.3.1. </b>In void mode, this code is simple: it just produces a list of assignments:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">formal_par1 = T1;</span>
<span class="plain">formal_par2 = T2;</span>
<span class="plain">...</span>
&lt;<span class="cwebmacrodefn">Compile code to set the formal parameters in void mode</span> <span class="cwebmacronumber">3.2.3.1</span>&gt; =
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">N</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
&lt;<span class="cwebmacro">Compile the actual assignment</span> <span class="cwebmacronumber">3.2.3.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_2"></a><b>&#167;3.2.3.2. </b>In value mode, we exploit the fact that, as in C, assignments return a value
and are therefore legal in an expression context; but, again avoiding the
serial comma at the cost of a fruitless addition,
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">(formal_parn = Tn) + ... + (formal_par1 = T1)</span>
</pre>
<p class="inwebparagraph">Again, this is written in reverse order because I6 will evaluate this from
right to left: we want T1 to evaluate first, then T2, and so on.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Emit code to set the formal parameters in expression mode</span> <span class="cwebmacronumber">3.2.3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=</span><span class="identifier">N</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain">&gt;=0; </span><span class="identifier">i</span><span class="plain">--) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> &gt; 0) { </span><span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">PLUS_BIP</span><span class="plain">); </span><span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); }</span>
&lt;<span class="cwebmacro">Compile the actual assignment</span> <span class="cwebmacronumber">3.2.3.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=</span><span class="identifier">N</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain">&gt;0; </span><span class="identifier">i</span><span class="plain">--) </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_1_1"></a><b>&#167;3.2.3.1.1. </b>A parameter corresponding to the name of a kind has no meaningful value
at run-time; we assign 0 to it for the sake of tidiness.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile the actual assignment</span> <span class="cwebmacronumber">3.2.3.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">STORE_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::ref_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">NonlocalVariables::formal_par</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.token_sequence</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.construct</span><span class="plain"> == </span><span class="constant">KIND_NAME_PT_CONSTRUCT</span><span class="plain">)</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, 0);</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="constant">BEGIN_COMPILATION_MODE</span><span class="plain">;</span>
<span class="identifier">COMPILATION_MODE_ENTER</span><span class="plain">(</span><span class="constant">DEREFERENCE_POINTERS_CMODE</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">value</span><span class="plain"> =</span>
<span class="functiontext">Invocations::get_token_as_parsed</span><span class="plain">(</span><span class="functiontext">Invocations::first_in_list</span><span class="plain">(</span><span class="identifier">invl</span><span class="plain">), </span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">to_be_used_as</span><span class="plain"> = </span><span class="functiontext">Specifications::to_kind</span><span class="plain">(</span>
<span class="identifier">ph</span><span class="plain">-</span><span class="element">&gt;type_data.token_sequence</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.to_match</span><span class="plain">);</span>
<span class="functiontext">Specifications::Compiler::emit_to_kind</span><span class="plain">(</span><span class="identifier">value</span><span class="plain">, </span><span class="identifier">to_be_used_as</span><span class="plain">);</span>
<span class="constant">END_COMPILATION_MODE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_1">&#167;3.2.3.1</a>, <a href="#SP3_2_3_2">&#167;3.2.3.2</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3"></a><b>&#167;3.2.3.3. </b>So now we come to the part which switches the execution stream. In void mode,
it will look like so:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">if (condition for I1 to be valid) invoke I1;</span>
<span class="plain">else if (condition for I2 to be valid) invoke I2;</span>
<span class="plain">...</span>
<span class="plain">else run-time-error-message();</span>
</pre>
<p class="inwebparagraph">but in value mode, where invocations return values,
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">((condition for I1 to be valid) &amp;&amp; ((formal_rv = I1) bitwise-or 1))</span>
<span class="plain">logical-or ((condition for I2 to be valid) &amp;&amp; ((formal_rv = I2) bitwise-or 1))</span>
<span class="plain">...</span>
</pre>
<p class="inwebparagraph">The key here is that I6, like C, evaluates operands of <code class="display"><span class="extract">&amp;&amp;</span></code> left to right
and short-circuits: if the left operand is false, the right is never evaluated,
and its side-effect (of invoking a phrase and setting <code class="display"><span class="extract">formal_rv</span></code>) never
happens; and similarly for logical-or. Bitwise or doesn't have that property,
and the ridiculous trick of bitwise-or-ing with 1 ensures that any value is
made non-zero, so that the assignment is always regarded by I6 as "true".
This in turn means that if any invocation is reached in this expression,
no subsequent lines are looked at.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile code to apply the first invocation which is applicable</span> <span class="cwebmacronumber">3.2.3.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_conditions_tested</span><span class="plain"> = 0, </span><span class="identifier">if_depth</span><span class="plain"> = 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> = 0;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">inv</span><span class="plain">;</span>
<span class="identifier">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">invl</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"RC%d: $e\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">pos</span><span class="plain">++;</span>
<span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">inv</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">no_conditions_tested</span><span class="plain"> &gt; 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">void_mode</span><span class="plain">) {</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::code</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="plain">}</span>
&lt;<span class="cwebmacro">Compile code to apply this invocation if it's applicable</span> <span class="cwebmacronumber">3.2.3.3.1</span>&gt;<span class="character">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_unproven</span><span class="plain">(</span><span class="identifier">last_inv</span><span class="plain">)) {</span>
&lt;<span class="cwebmacro">Compile code for the execution path where no invocations were applicable</span> <span class="cwebmacronumber">3.2.3.6</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">if_depth</span><span class="plain"> &gt; 0) { </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); </span><span class="identifier">if_depth</span><span class="plain">--; }</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_4"></a><b>&#167;3.2.3.4. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile code to apply the first invocation which is applicable, as expression</span> <span class="cwebmacronumber">3.2.3.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> = 0;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">inv</span><span class="plain">;</span>
<span class="identifier">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">invl</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"RC%d: $e\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">pos</span><span class="plain">++;</span>
<span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">inv</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Compile code to apply this invocation if it's applicable, expression version</span> <span class="cwebmacronumber">3.2.3.4.1</span>&gt;<span class="character">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_5"></a><b>&#167;3.2.3.5. </b><code class="display">
&lt;<span class="cwebmacrodefn">Count the applicability conditions</span> <span class="cwebmacronumber">3.2.3.5</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">inv</span><span class="plain">;</span>
<span class="identifier">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">invl</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">checks_needed</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">last_inv</span><span class="plain"> = </span><span class="identifier">inv</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">check_against</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_check_to_do</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_against</span><span class="plain">) </span><span class="identifier">checks_needed</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">checks_needed</span><span class="plain">) </span><span class="identifier">NC</span><span class="plain">++; </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">prov</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_unproven</span><span class="plain">(</span><span class="identifier">last_inv</span><span class="plain">)) </span><span class="identifier">unprov</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_6"></a><b>&#167;3.2.3.6. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile code for the execution path where no invocations were applicable</span> <span class="cwebmacronumber">3.2.3.6</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">no_conditions_tested</span><span class="plain"> == 0) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"condition proof error"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">void_mode</span><span class="plain">) {</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::code</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="identifier">Produce::inv_call_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">ARGUMENTTYPEFAILED_HL</span><span class="plain">));</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, (</span><span class="identifier">inter_t</span><span class="plain">) </span><span class="identifier">sl</span><span class="plain">.</span><span class="identifier">line_number</span><span class="plain">);</span>
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">ef</span><span class="plain"> = </span><span class="functiontext">SourceFiles::get_extension_corresponding</span><span class="plain">(</span><span class="identifier">sl</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ef</span><span class="plain">) </span><span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, (</span><span class="identifier">inter_t</span><span class="plain">) </span><span class="identifier">ef</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain"> + 1);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3">&#167;3.2.3</a>, <a href="#SP3_2_3_3">&#167;3.2.3.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3_1"></a><b>&#167;3.2.3.3.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile code to apply this invocation if it's applicable</span> <span class="cwebmacronumber">3.2.3.3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">))</span>
<span class="functiontext">NewVerbs::ConjugateVerb_invoke_emit</span><span class="plain">(</span>
<span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::get_modal_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="constant">say_verb_negated_ANNOT</span><span class="plain">));</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">))</span>
<span class="functiontext">Adjectives::Meanings::emit</span><span class="plain">(</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">));</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">ParseTree::get_phrase_invoked</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">);</span>
<span class="reserved">tokens_packet</span><span class="plain"> </span><span class="identifier">tokens</span><span class="plain">;</span>
&lt;<span class="cwebmacro">First construct an arguments packet</span> <span class="cwebmacronumber">3.1.1.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Substitute the formal parameter variables into the tokens</span> <span class="cwebmacronumber">3.2.3.3.1.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile the check on invocation applicability, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile the invocation part, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.3</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_3">&#167;3.2.3.3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_4_1"></a><b>&#167;3.2.3.4.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile code to apply this invocation if it's applicable, expression version</span> <span class="cwebmacronumber">3.2.3.4.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">))</span>
<span class="functiontext">NewVerbs::ConjugateVerb_invoke_emit</span><span class="plain">(</span>
<span class="identifier">ParseTree::get_say_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::get_modal_verb</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">),</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="constant">say_verb_negated_ANNOT</span><span class="plain">));</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">))</span>
<span class="functiontext">Adjectives::Meanings::emit</span><span class="plain">(</span><span class="identifier">ParseTree::get_say_adjective</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">));</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">ParseTree::get_phrase_invoked</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">);</span>
<span class="reserved">tokens_packet</span><span class="plain"> </span><span class="identifier">tokens</span><span class="plain">;</span>
&lt;<span class="cwebmacro">First construct an arguments packet</span> <span class="cwebmacronumber">3.1.1.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Substitute the formal parameter variables into the tokens</span> <span class="cwebmacronumber">3.2.3.3.1.1</span>&gt;<span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">Produce::level</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()), </span><span class="identifier">or_made</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">ands_made</span><span class="plain"> = 0;</span>
&lt;<span class="cwebmacro">Compile the check on invocation applicability, expression version</span> <span class="cwebmacronumber">3.2.3.4.1.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile the invocation part, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.3</span>&gt;<span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">ands_made</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">target</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">or_made</span><span class="plain">) </span><span class="identifier">target</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target</span><span class="plain"> != </span><span class="identifier">Produce::level</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">())) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"levels wrong"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_4">&#167;3.2.3.4</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3_1_1"></a><b>&#167;3.2.3.3.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Substitute the formal parameter variables into the tokens</span> <span class="cwebmacronumber">3.2.3.3.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">tokens</span><span class="element">.tokens_count</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="functiontext">NonlocalVariables::set_kind</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">, </span><span class="identifier">tokens</span><span class="element">.kind_required</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="identifier">tokens</span><span class="element">.args</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="functiontext">Lvalues::new_actual_NONLOCAL_VARIABLE</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_3_1">&#167;3.2.3.3.1</a>, <a href="#SP3_2_3_4_1">&#167;3.2.3.4.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3_1_2"></a><b>&#167;3.2.3.3.1.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile the check on invocation applicability, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">check_needed</span><span class="plain"> = 0;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">check_against</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_check_to_do</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_against</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">check_needed</span><span class="plain">++;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_needed</span><span class="plain"> &gt; 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">void_mode</span><span class="plain">) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">IFELSE_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
&lt;<span class="cwebmacro">Put the condition check here, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.2.1</span>&gt;<span class="plain">;</span>
<span class="identifier">Produce::code</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">if_depth</span><span class="plain">++;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">AND_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
&lt;<span class="cwebmacro">Put the condition check here, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.2.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">no_conditions_tested</span><span class="plain">++;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Invocations::is_marked_unproven</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">))</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unable to compile a run-time kind check"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_3_1">&#167;3.2.3.3.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_4_1_1"></a><b>&#167;3.2.3.4.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile the check on invocation applicability, expression version</span> <span class="cwebmacronumber">3.2.3.4.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">check_needed</span><span class="plain"> = 0;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">check_against</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_check_to_do</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_against</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">check_needed</span><span class="plain">++;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_needed</span><span class="plain"> &gt; 0) {</span>
<span class="identifier">no_conditions_tested</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">no_conditions_tested</span><span class="plain"> &lt; </span><span class="identifier">NC</span><span class="plain">) || (</span><span class="identifier">prov</span><span class="plain">)) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">OR_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); </span><span class="identifier">or_made</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">check_against</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_check_to_do</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_against</span><span class="plain">) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">AND_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); </span><span class="identifier">ands_made</span><span class="plain">++;</span>
<span class="constant">BEGIN_COMPILATION_MODE</span><span class="plain">;</span>
<span class="identifier">COMPILATION_MODE_EXIT</span><span class="plain">(</span><span class="constant">DEREFERENCE_POINTERS_CMODE</span><span class="plain">);</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="functiontext">Lvalues::new_actual_NONLOCAL_VARIABLE</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Compile a check that this formal variable matches the token, emission version</span> <span class="cwebmacronumber">3.2.3.4.1.1.1</span>&gt;<span class="plain">;</span>
<span class="constant">END_COMPILATION_MODE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_4_1">&#167;3.2.3.4.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3_1_2_1"></a><b>&#167;3.2.3.3.1.2.1. </b>There may be checks needed on several tokens, so we accumulate these into
a list divided by logical-and <code class="display"><span class="extract">&amp;&amp;</span></code> operators.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Put the condition check here, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">and_depth</span><span class="plain"> = 0;</span>
<span class="constant">BEGIN_COMPILATION_MODE</span><span class="plain">;</span>
<span class="identifier">COMPILATION_MODE_EXIT</span><span class="plain">(</span><span class="constant">DEREFERENCE_POINTERS_CMODE</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0, </span><span class="identifier">check_count</span><span class="plain"> = 0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="functiontext">Invocations::get_no_tokens</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">check_against</span><span class="plain"> = </span><span class="functiontext">Invocations::get_token_check_to_do</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_against</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">check_count</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">check_count</span><span class="plain"> &lt; </span><span class="identifier">check_needed</span><span class="plain">) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">AND_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">and_depth</span><span class="plain">++;</span>
<span class="plain">}</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="functiontext">Lvalues::new_actual_NONLOCAL_VARIABLE</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Compile a check that this formal variable matches the token, emission version</span> <span class="cwebmacronumber">3.2.3.4.1.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">and_depth</span><span class="plain"> &gt; 0) { </span><span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()); </span><span class="identifier">and_depth</span><span class="plain">--; }</span>
<span class="constant">END_COMPILATION_MODE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_3_1_2">&#167;3.2.3.3.1.2</a> (twice).</p>
<p class="inwebparagraph"><a id="SP3_2_3_4_1_1_1"></a><b>&#167;3.2.3.4.1.1.1. </b>There are two things we might want to check, exemplified by what happens
in this situation:
</p>
<blockquote>
<p>To collate (N - an even number): ...</p>
</blockquote>
<blockquote>
<p>To collate (N - 10): ...</p>
</blockquote>
<blockquote>
<p>collate X;</p>
</blockquote>
<p class="inwebparagraph">To compile "collate X", we need to test at run-time which invocation applies.
(We actually check the second of these first, because it's more specific.)
In case we test if X is 10, in the other that X matches the description
"even number".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile a check that this formal variable matches the token, emission version</span> <span class="cwebmacronumber">3.2.3.4.1.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Specifications::is_description</span><span class="plain">(</span><span class="identifier">check_against</span><span class="plain">)) {</span>
<span class="functiontext">Calculus::Deferrals::emit_test_if_var_matches_description</span><span class="plain">(</span>
<span class="identifier">spec</span><span class="plain">, </span><span class="identifier">check_against</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">ParseTreeUsage::is_value</span><span class="plain">(</span><span class="identifier">check_against</span><span class="plain">)) {</span>
<span class="reserved">pcalc_prop</span><span class="plain"> *</span><span class="identifier">prop</span><span class="plain"> = </span><span class="functiontext">Calculus::Propositions::Abstract::to_set_relation</span><span class="plain">(</span><span class="identifier">R_equality</span><span class="plain">,</span>
<span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">check_against</span><span class="plain">);</span>
<span class="functiontext">Calculus::Deferrals::emit_test_of_proposition</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">prop</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Error on: $T"</span><span class="plain">, </span><span class="identifier">check_against</span><span class="plain">);</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"bad check-against in run-time type check"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_4_1_1">&#167;3.2.3.4.1.1</a>, <a href="#SP3_2_3_3_1_2_1">&#167;3.2.3.3.1.2.1</a>.</p>
<p class="inwebparagraph"><a id="SP3_2_3_3_1_3"></a><b>&#167;3.2.3.3.1.3. </b>...and the actual invocation is now simple. In void mode, simply:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">invoke(formal-vars)</span>
</pre>
<p class="inwebparagraph">whereas in value mode,
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">((formal_rv = invoke(formal-vars)) bitwise-or 1)</span>
</pre>
<p class="inwebparagraph">As noted above, the bitwise-or is a clumsy way to force the condition to
evaluate to "true" with a minimum of branches in the compiled code.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile the invocation part, emission version</span> <span class="cwebmacronumber">3.2.3.3.1.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (!</span><span class="identifier">void_mode</span><span class="plain">) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">BITWISEOR_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">STORE_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::ref_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">FORMAL_RV_HL</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="identifier">value_holster</span><span class="plain"> </span><span class="identifier">VH2</span><span class="plain"> = </span><span class="identifier">Holsters::new</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_wanted</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">returned_in_manner</span><span class="plain"> =</span>
<span class="functiontext">Invocations::Compiler::compile_single_invocation</span><span class="plain">(&amp;</span><span class="identifier">VH2</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">, &amp;</span><span class="identifier">sl</span><span class="plain">, &amp;</span><span class="identifier">tokens</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (!</span><span class="identifier">void_mode</span><span class="plain">) {</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, 1);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">returned_in_manner</span><span class="plain"> != </span><span class="constant">DONT_KNOW_MOR</span><span class="plain">)</span>
&lt;<span class="cwebmacro">If the invocation compiled to a return from a function, check this is allowed</span> <span class="cwebmacronumber">3.1.1.2</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3_2_3_3_1">&#167;3.2.3.3.1</a>, <a href="#SP3_2_3_4_1">&#167;3.2.3.4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Lower level: compiling single invocations. </b></p>
<p class="inwebparagraph">Phrases to decide a condition must compile to valid I6 conditions, which
we need to ensure there are round brackets around.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Invocations::Compiler::compile_single_invocation</span><span class="plain">(</span><span class="identifier">value_holster</span><span class="plain"> *</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">inv</span><span class="plain">,</span>
<span class="identifier">source_location</span><span class="plain"> *</span><span class="identifier">where_from</span><span class="plain">, </span><span class="reserved">tokens_packet</span><span class="plain"> *</span><span class="identifier">tokens</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"Compiling single invocation: $e\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">);</span>
<span class="constant">BEGIN_COMPILATION_MODE</span><span class="plain">;</span>
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">ParseTree::get_phrase_invoked</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">manner_of_return</span><span class="plain"> = </span><span class="constant">DONT_KNOW_MOR</span><span class="plain">;</span>
&lt;<span class="cwebmacro">The art of invocation is delegation</span> <span class="cwebmacronumber">4.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile a newline if the phrase implicitly requires one</span> <span class="cwebmacronumber">4.2</span>&gt;<span class="plain">;</span>
<span class="constant">END_COMPILATION_MODE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">manner_of_return</span><span class="plain"> != </span><span class="constant">DONT_KNOW_MOR</span><span class="plain">)</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">MATCHING</span><span class="plain">, </span><span class="string">"Single invocation return manner: %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">manner_of_return</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">manner_of_return</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Invocations::Compiler::compile_single_invocation is used in <a href="#SP3_1_1">&#167;3.1.1</a>, <a href="#SP3_2_3_3_1_3">&#167;3.2.3.3.1.3</a>.</p>
<p class="inwebparagraph"><a id="SP4_1"></a><b>&#167;4.1. </b>The real work is done by one of the two sections following this one. Note that
only inline invocations are allowed to produce an exotic manner of return &mdash; it's
not possible to define a high-level I7 phrase which effects, say, an immediate
end to the rule it's used in. Similarly, only inline invocations are allowed
to be followed by blocks of other phrases &mdash; that is, are allowed to define
control structures.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">The art of invocation is delegation</span> <span class="cwebmacronumber">4.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Phrases::TypeData::invoked_inline</span><span class="plain">(</span><span class="identifier">ph</span><span class="plain">))</span>
<span class="identifier">manner_of_return</span><span class="plain"> =</span>
<span class="functiontext">Invocations::Inline::csi_inline_outer</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">where_from</span><span class="plain">, </span><span class="identifier">tokens</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="functiontext">Invocations::AsCalls::csi_by_call</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">inv</span><span class="plain">, </span><span class="identifier">where_from</span><span class="plain">, </span><span class="identifier">tokens</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP4_2"></a><b>&#167;4.2. </b>This is where we implement the convention that saying text ending with a full
stop automatically generates a newline:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile a newline if the phrase implicitly requires one</span> <span class="cwebmacronumber">4.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Invocations::implies_newline</span><span class="plain">(</span><span class="identifier">inv</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">tokens</span><span class="plain">-</span><span class="element">&gt;tokens_count</span><span class="plain"> &gt; 0) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Rvalues::is_CONSTANT_of_kind</span><span class="plain">(</span><span class="identifier">tokens</span><span class="plain">-</span><span class="element">&gt;args</span><span class="plain">[0], </span><span class="identifier">K_text</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Word::text_ending_sentence</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">tokens</span><span class="plain">-</span><span class="element">&gt;args</span><span class="plain">[0]))))) {</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">PRINT_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::val_text</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">I</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4">&#167;4</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="25-pi.html">Back to 'Parse Invocations'</a></li><li><a href="25-ciac.html">Continue with 'Compile Invocations As Calls'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>