1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 08:34:22 +03:00
inform7/docs/imperative-module/5-ci.html
2022-09-21 23:39:34 +01:00

779 lines
123 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Compile Invocations</title>
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
function togglePopup(material_id) {
var popup = document.getElementById(material_id);
popup.classList.toggle("show");
}
</script>
<link href="../docs-assets/Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body class="commentary-font">
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-assets/Inform.png" height=72">
</a></h1>
<ul><li><a href="../index.html">home</a></li>
</ul><h2>Compiler</h2><ul>
<li><a href="../structure.html">structure</a></li>
<li><a href="../inbuildn.html">inbuild</a></li>
<li><a href="../inform7n.html">inform7</a></li>
<li><a href="../intern.html">inter</a></li>
<li><a href="../services.html">services</a></li>
<li><a href="../secrets.html">secrets</a></li>
</ul><h2>Other Tools</h2><ul>
<li><a href="../inblorbn.html">inblorb</a></li>
<li><a href="../indocn.html">indoc</a></li>
<li><a href="../inform6.html">inform6</a></li>
<li><a href="../inpolicyn.html">inpolicy</a></li>
<li><a href="../inrtpsn.html">inrtps</a></li>
</ul><h2>Resources</h2><ul>
<li><a href="../extensions.html">extensions</a></li>
<li><a href="../kits.html">kits</a></li>
</ul><h2>Repository</h2><ul>
<li><a href="https://github.com/ganelson/inform"><img src="../docs-assets/github.png" height=18> github</a></li>
</ul><h2>Related Projects</h2><ul>
<li><a href="../../../inweb/index.html">inweb</a></li>
<li><a href="../../../intest/index.html">intest</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'Compile Invocations' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../inform7n.html">Inform7</a></li><li><a href="index.html">imperative</a></li><li><a href="index.html#5">Chapter 5: Invocations</a></li><li><b>Compile Invocations</b></li></ul></div>
<p class="purpose">Generating code to perform an invocation.</p>
<ul class="toc"><li><a href="5-ci.html#SP1">&#167;1. Upper level: compiling from whole lists</a></li><li><a href="5-ci.html#SP2">&#167;2. Lower level: compiling single invocations</a></li><li><a href="5-ci.html#SP3">&#167;3. Tokens packets</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1" class="paragraph-anchor"></a><b>&#167;1. Upper level: compiling from whole lists. </b>Here, we are given an invocation list <span class="extract"><span class="extract-syntax">invl</span></span>, and we must generate Inter code
to carry it out. The code in this section does some complicated things; the
test group <span class="extract"><span class="extract-syntax">:invocations</span></span> may be helpful when maintaining it.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">CompileInvocations::list</span><button class="popup" onclick="togglePopup('usagePopup1')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup1">Usage of <span class="code-font"><span class="function-syntax">CompileInvocations::list</span></span>:<br/>Compile Rvalues - <a href="2-cr.html#SP1">&#167;1</a><br/>Compile Blocks and Lines - <a href="5-cbal.html#SP6">&#167;6</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">value_holster</span><span class="plain-syntax"> *</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">invl</span><span class="plain-syntax">, </span><span class="identifier-syntax">wording</span><span class="plain-syntax"> </span><span class="identifier-syntax">W</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_1" class="named-paragraph-link"><span class="named-paragraph">Check that the list is in canonical form</span><span class="named-paragraph-number">1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_2" class="named-paragraph-link"><span class="named-paragraph">Tell the holster we intend to generate Inter code</span><span class="named-paragraph-number">1.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">InvocationLists::length</span><span class="plain-syntax">(</span><span class="identifier-syntax">invl</span><span class="plain-syntax">) &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOGIF</span><span class="plain-syntax">(</span><span class="identifier-syntax">MATCHING</span><span class="plain-syntax">, </span><span class="string-syntax">"Compiling from %d invocation(s)\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">InvocationLists::length</span><span class="plain-syntax">(</span><span class="identifier-syntax">invl</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">source_location</span><span class="plain-syntax"> </span><span class="identifier-syntax">sl</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Lexer::word_location</span><span class="plain-syntax">(</span><span class="identifier-syntax">Wordings::first_wn</span><span class="plain-syntax">(</span><span class="identifier-syntax">W</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax"> = </span><span class="identifier-syntax">InvocationLists::first_reading</span><span class="plain-syntax">(</span><span class="identifier-syntax">invl</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3" class="named-paragraph-link"><span class="named-paragraph">Use runtime resolution only if necessary</span><span class="named-paragraph-number">1.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP1_1" class="paragraph-anchor"></a><b>&#167;1.1. </b>The invocation list has already been typechecked by <a href="../values-module/5-dsh.html" class="internal">Dash (in values)</a>. This
means that any invocation which could be disproved has been removed, and what's
left is either "proven" &mdash; i.e., certain to be applicable &mdash; or "unproven" &mdash;
i.e., only applicable if certain runtime checks are performed.
</p>
<p class="commentary">Here we check that the list does indeed contain 0 or more unproven invocations
followed by 0 or 1 proven ones, and that all invocations have the same number
of tokens.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Check that the list is in canonical form</span><span class="named-paragraph-number">1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">no_proven</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">no_unproven</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">common_token_count</span><span class="plain-syntax"> = -1, </span><span class="identifier-syntax">noncanonical</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">inv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">invl</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_no_tokens</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">common_token_count</span><span class="plain-syntax"> == -1) </span><span class="identifier-syntax">common_token_count</span><span class="plain-syntax"> = </span><span class="identifier-syntax">N</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">common_token_count</span><span class="plain-syntax"> != </span><span class="identifier-syntax">N</span><span class="plain-syntax">) </span><span class="identifier-syntax">noncanonical</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">no_unproven</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_proven</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">noncanonical</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">no_proven</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">no_proven</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">1</span><span class="plain-syntax">) </span><span class="identifier-syntax">noncanonical</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">noncanonical</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">invl</span><span class="plain-syntax">) </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"$e\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"invocation list not in canonical form"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1">&#167;1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_2" class="paragraph-anchor"></a><b>&#167;1.2. </b>In fact it is impossible for this to be called with <span class="extract"><span class="extract-syntax">VH-&gt;vhmode_wanted</span></span> set to
anything other than <span class="extract"><span class="extract-syntax">INTER_VAL_VHMODE</span></span> or <span class="extract"><span class="extract-syntax">INTER_VOID_VHMODE</span></span>.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Tell the holster we intend to generate Inter code</span><span class="named-paragraph-number">1.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">VH</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">vhmode_wanted</span><span class="plain-syntax"> == </span><span class="identifier-syntax">INTER_VAL_VHMODE</span><span class="plain-syntax">) </span><span class="identifier-syntax">VH</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">vhmode_provided</span><span class="plain-syntax"> = </span><span class="identifier-syntax">INTER_VAL_VHMODE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">VH</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">vhmode_provided</span><span class="plain-syntax"> = </span><span class="identifier-syntax">INTER_VOID_VHMODE</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1">&#167;1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3" class="paragraph-anchor"></a><b>&#167;1.3. </b>Our task is to compile code which executes the first applicable invocation. If
there is any possibility that none are, we must generate code to produce a
runtime problem message in that case.
</p>
<p class="commentary">Since the list is in canonical form, if the first invocation is proven then it
is the only one, and therefore no runtime resolution will be needed.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Use runtime resolution only if necessary</span><span class="named-paragraph-number">1.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1" class="named-paragraph-link"><span class="named-paragraph">Compile using runtime resolution to choose between invocations</span><span class="named-paragraph-number">1.3.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax"> = </span><a href="5-ci.html#SP4" class="function-link"><span class="function-syntax">CompileInvocations::new_tokens_packet</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="5-ci.html#SP2" class="function-link"><span class="function-syntax">CompileInvocations::single</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sl</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">, </span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1">&#167;1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1" class="paragraph-anchor"></a><b>&#167;1.3.1. </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 runtime.
</p>
<p class="commentary">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="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile using runtime resolution to choose between invocations</span><span class="named-paragraph-number">1.3.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">id_body</span><span class="plain-syntax"> *</span><span class="identifier-syntax">idb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Node::get_phrase_invoked</span><span class="plain-syntax">(</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">void_mode</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> == </span><span class="identifier-syntax">DECIDES_NOTHING_MOR</span><span class="plain-syntax">) </span><span class="identifier-syntax">void_mode</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2" class="named-paragraph-link"><span class="named-paragraph">Compile the resolution</span><span class="named-paragraph-number">1.3.1.2</span></a></span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3">&#167;1.3</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_1" class="paragraph-anchor"></a><b>&#167;1.3.1.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>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> if (condition for I1 to be valid) invoke I1(T1, ..., Tm);</span>
<span class="plain-syntax"> else if (condition for I2 to be valid) invoke I2(T1, ..., Tm);</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> else runtime-error-message();</span>
</pre>
<p class="commentary">where the chain of execution runs into the error message code only if none
of I1, ..., In can be applied. In the case where the final invocation is
proven, we can more simply do this:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> if (condition for I1 to be valid) invoke I1(T1, ..., Tm);</span>
<span class="plain-syntax"> else if (condition for I2 to be valid) invoke I2(T1, ..., Tm);</span>
<span class="plain-syntax"> else invoke In(T1, ..., Tm);</span>
</pre>
<p class="commentary firstcommentary"><a id="SP1_3_1_2" class="paragraph-anchor"></a><b>&#167;1.3.1.2. </b>That's almost what we do, but not quite. The problem lies in the fact that
the tokens <span class="extract"><span class="extract-syntax">T1</span></span>, ..., <span class="extract"><span class="extract-syntax">Tm</span></span> 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, and would also waste time if the tokens were slow to evaluate.
So in fact we modify our scheme like so:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> F1 = T1;</span>
<span class="plain-syntax"> F2 = T2;</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> if (condition for I1 to be valid) invoke I1(F1, ..., Fm);</span>
<span class="plain-syntax"> else if (condition for I2 to be valid) invoke I2(F1, ..., Fm);</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> else runtime-error-message();</span>
</pre>
<p class="commentary">Here <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> are called the "formal parameters". But now we have a tricky
issue to contend with: where can they be stored?
</p>
<p class="commentary">Here are the answers I thought of in turn:
</p>
<ul class="items"><li>&#9679; Make <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> local variables for the current function. Often works
but not always, since some of our eventual target VMs have low upper limits
on the number of locals in any one function.
</li><li>&#9679; Put <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> on the call stack for the current function. Impossible
because the Inter VM has no memory access to its call stack, a restriction
forced on Inter by the nature of the Z-machine and Glulx VMs it is a bridge to.
</li><li>&#9679; Have <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> be global variables. Impossible because they have to be
local in scope since evaluation of <span class="extract"><span class="extract-syntax">T2</span></span>, say, might itself involve a call to
another phrase which needs to make a resolution itself.
</li><li>&#9679; Have <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> be global variables, but push copies to the call stack
before the resolution, and pull them back afterwards, thus using only saved
copies. This sometimes works in void context (if we are careful to avoid cases
where the phrase invoked might perform a jump or return), but is impossible
in value context, where the Inter <span class="extract"><span class="extract-syntax">PUSH_BIP</span></span> and <span class="extract"><span class="extract-syntax">PULL_BIP</span></span> opcodes are illegal.
</li><li>&#9679; Force the current function to be a kernel function inside an outer shell
function, and then allocate <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> as memory in the <span class="extract"><span class="extract-syntax">I7SFRAME</span></span> space
provided by the shell function. This works, but is slower to access, and forces
us to have a memory stack, which can be a problem if we are compiling for a
very tight Z-machine memory.
</li><li>&#9679; Force the current function to be a kernel function inside an outer shell
function, but have <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> be global variables anyway. In the shell
function, push copies of <span class="extract"><span class="extract-syntax">F1, ..., Fn</span></span> to the call stack before calling the
kernel, and then pull these saved values back afterwards. This one, finally,
works in all cases, and is what we do.
</li></ul>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile the resolution</span><span class="named-paragraph-number">1.3.1.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">N</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_no_tokens</span><span class="plain-syntax">(</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">); </span><span class="comment-syntax"> must be &gt; 0, or we would be proven</span>
<span class="plain-syntax"> </span><a href="3-sf.html#SP12" class="function-link"><span class="function-syntax">Frames::need_at_least_this_many_formals</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">N</span><span class="plain-syntax">); </span><span class="comment-syntax"> forces the existence of a shell function</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">void_mode</span><span class="plain-syntax">) </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1" class="named-paragraph-link"><span class="named-paragraph">Compile the resolution in void mode</span><span class="named-paragraph-number">1.3.1.2.1</span></a></span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2" class="named-paragraph-link"><span class="named-paragraph">Compile the resolution in value mode</span><span class="named-paragraph-number">1.3.1.2.2</span></a></span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1">&#167;1.3.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile the resolution in void mode</span><span class="named-paragraph-number">1.3.1.2.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">N</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_2" class="named-paragraph-link"><span class="named-paragraph">Set the ith formal parameter to the ith token value</span><span class="named-paragraph-number">1.3.1.2.1.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">pos</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">if_depth</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, *</span><span class="identifier-syntax">last_inv</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">invl</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOGIF</span><span class="plain-syntax">(</span><span class="identifier-syntax">MATCHING</span><span class="plain-syntax">, </span><span class="string-syntax">"RC%d: $e\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">pos</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">); </span><span class="identifier-syntax">pos</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">last_inv</span><span class="plain-syntax"> = </span><span class="identifier-syntax">inv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">if_depth</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::code</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax"> = </span><a href="5-ci.html#SP4" class="function-link"><span class="function-syntax">CompileInvocations::new_tokens_packet</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_3" class="named-paragraph-link"><span class="named-paragraph">Substitute the formal parameters into the tokens packet</span><span class="named-paragraph-number">1.3.1.2.1.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">IFELSE_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_1" class="named-paragraph-link"><span class="named-paragraph">Put the condition check here</span><span class="named-paragraph-number">1.3.1.2.1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::code</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">if_depth</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><a href="5-ci.html#SP2" class="function-link"><span class="function-syntax">CompileInvocations::single</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sl</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">, </span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">last_inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::code</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_4" class="named-paragraph-link"><span class="named-paragraph">Compile call to function throwing an RTP</span><span class="named-paragraph-number">1.3.1.2.1.4</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">if_depth</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">(); </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">if_depth</span><span class="plain-syntax">--;</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2">&#167;1.3.1.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1.1. </b>There may be checks needed on several tokens, so we accumulate these into
a list divided by logical-and <span class="extract"><span class="extract-syntax">&amp;&amp;</span></span> operators.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Put the condition check here</span><span class="named-paragraph-number">1.3.1.2.1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">check_needed</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">Invocations::get_no_tokens</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">); </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">check_against</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_token_check_to_do</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">check_against</span><span class="plain-syntax">) </span><span class="identifier-syntax">check_needed</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">check_count</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">Invocations::get_no_tokens</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">); </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">check_against</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_token_check_to_do</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">check_against</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">check_count</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">check_count</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">check_needed</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">AND_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_1_1" class="named-paragraph-link"><span class="named-paragraph">Compile a check that this formal variable matches the token</span><span class="named-paragraph-number">1.3.1.2.1.1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">check_count</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"this should not be marked unproven"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax"> &lt;= </span><span class="identifier-syntax">check_count</span><span class="plain-syntax"> - </span><span class="constant-syntax">1</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1_1_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1.1.1. </b>The check is either against a general description, such as "even number", or
a specific value, such as "10".
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile a check that this formal variable matches the token</span><span class="named-paragraph-number">1.3.1.2.1.1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">nonlocal_variable</span><span class="plain-syntax"> *</span><span class="identifier-syntax">nlv</span><span class="plain-syntax"> = </span><a href="3-tv.html#SP2" class="function-link"><span class="function-syntax">TemporaryVariables::formal_parameter</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">spec</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Lvalues::new_actual_NONLOCAL_VARIABLE</span><span class="plain-syntax">(</span><span class="identifier-syntax">nlv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Specifications::is_description</span><span class="plain-syntax">(</span><span class="identifier-syntax">check_against</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><a href="4-cp.html#SP3" class="function-link"><span class="function-syntax">CompilePropositions::to_test_if_variable_matches</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">spec</span><span class="plain-syntax">, </span><span class="identifier-syntax">check_against</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Specifications::is_value</span><span class="plain-syntax">(</span><span class="identifier-syntax">check_against</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">pcalc_prop</span><span class="plain-syntax"> *</span><span class="identifier-syntax">prop</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Propositions::Abstract::to_set_relation</span><span class="plain-syntax">(</span><span class="identifier-syntax">R_equality</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">, </span><span class="identifier-syntax">spec</span><span class="plain-syntax">, </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">, </span><span class="identifier-syntax">check_against</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="4-cp.html#SP1" class="function-link"><span class="function-syntax">CompilePropositions::to_test_as_condition</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">NULL</span><span class="plain-syntax">, </span><span class="identifier-syntax">prop</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOG</span><span class="plain-syntax">(</span><span class="string-syntax">"Error on: $T"</span><span class="plain-syntax">, </span><span class="identifier-syntax">check_against</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"bad check-against in runtime type check"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_1_1">&#167;1.3.1.2.1.1</a>, <a href="5-ci.html#SP1_3_1_2_2_2_1_1_1">&#167;1.3.1.2.2.2.1.1.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1_2" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1.2. </b>A parameter corresponding to the name of a kind has no meaningful value
at runtime; we assign 0 to it for the sake of tidiness.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Set the ith formal parameter to the ith token value</span><span class="named-paragraph-number">1.3.1.2.1.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><a href="3-tv.html#SP2" class="function-link"><span class="function-syntax">TemporaryVariables::formal_parameter</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">STORE_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::ref_iname</span><span class="plain-syntax">(</span><span class="identifier-syntax">K_value</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><a href="3-tv.html#SP2" class="function-link"><span class="function-syntax">TemporaryVariables::iname_of_formal_parameter</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">token_sequence</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="identifier-syntax">construct</span><span class="plain-syntax"> == </span><span class="identifier-syntax">KIND_NAME_IDTC</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_number</span><span class="plain-syntax">(0);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">value</span><span class="plain-syntax"> =</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Invocations::get_token_as_parsed</span><span class="plain-syntax">(</span><span class="identifier-syntax">first_inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">to_be_used_as</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Specifications::to_kind</span><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">token_sequence</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="identifier-syntax">to_match</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><a href="2-cv.html#SP5" class="function-link"><span class="function-syntax">CompileValues::to_fresh_code_val_of_kind</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">value</span><span class="plain-syntax">, </span><span class="identifier-syntax">to_be_used_as</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>, <a href="5-ci.html#SP1_3_1_2_2_1">&#167;1.3.1.2.2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1_3" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1.3. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Substitute the formal parameters into the tokens packet</span><span class="named-paragraph-number">1.3.1.2.1.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">tokens_count</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">nonlocal_variable</span><span class="plain-syntax"> *</span><span class="identifier-syntax">nlv</span><span class="plain-syntax"> = </span><a href="3-tv.html#SP2" class="function-link"><span class="function-syntax">TemporaryVariables::formal_parameter</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">NonlocalVariables::set_kind</span><span class="plain-syntax">(</span><span class="identifier-syntax">nlv</span><span class="plain-syntax">, </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_kinds</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">]);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_vals</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">Lvalues::new_actual_NONLOCAL_VARIABLE</span><span class="plain-syntax">(</span><span class="identifier-syntax">nlv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>, <a href="5-ci.html#SP1_3_1_2_2_2_1">&#167;1.3.1.2.2.2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_1_4" class="paragraph-anchor"></a><b>&#167;1.3.1.2.1.4. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile call to function throwing an RTP</span><span class="named-paragraph-number">1.3.1.2.1.4</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::call</span><span class="plain-syntax">(</span><span class="identifier-syntax">Hierarchy::find</span><span class="plain-syntax">(</span><span class="identifier-syntax">ARGUMENTTYPEFAILED_HL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_number</span><span class="plain-syntax">((</span><span class="identifier-syntax">inter_ti</span><span class="plain-syntax">) </span><span class="identifier-syntax">sl</span><span class="plain-syntax">.</span><span class="identifier-syntax">line_number</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">inform_extension</span><span class="plain-syntax"> *</span><span class="identifier-syntax">E</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Extensions::corresponding_to</span><span class="plain-syntax">(</span><span class="identifier-syntax">sl</span><span class="plain-syntax">.</span><span class="identifier-syntax">file_of_origin</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">E</span><span class="plain-syntax">) </span><span class="identifier-syntax">EmitCode::val_number</span><span class="plain-syntax">((</span><span class="identifier-syntax">inter_ti</span><span class="plain-syntax">) </span><span class="identifier-syntax">E</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">allocation_id</span><span class="plain-syntax"> + </span><span class="constant-syntax">1</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>, <a href="5-ci.html#SP1_3_1_2_2_2">&#167;1.3.1.2.2.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2. </b>In value mode we want the same strategy and code paths, but all in the context
of a value. This means we can only use Inter opcodes which are legal in a value
context, making everything harder.
</p>
<p class="commentary">The <span class="extract"><span class="extract-syntax">TERNARYSEQUENTIAL_BIP</span></span> opcode is similar to evaluating <span class="extract"><span class="extract-syntax">x, y, z</span></span> in C: it
evaluates <span class="extract"><span class="extract-syntax">x</span></span>, throws that away, evaluates <span class="extract"><span class="extract-syntax">y</span></span>, ditto, then evaluates <span class="extract"><span class="extract-syntax">z</span></span> as
its answer. <span class="extract"><span class="extract-syntax">x</span></span> and <span class="extract"><span class="extract-syntax">y</span></span> are thus evaluated only for and side-effects that has.
Here <span class="extract"><span class="extract-syntax">x</span></span> is going to be code to set the formal parameters; <span class="extract"><span class="extract-syntax">y</span></span> will be code
to test the conditions for invocation and invoke one of them into a dummy
variable called <span class="extract"><span class="extract-syntax">formal_rv</span></span>; and <span class="extract"><span class="extract-syntax">z</span></span> will simply evaluate <span class="extract"><span class="extract-syntax">formal_rv</span></span>, thus
producing the answer.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile the resolution in value mode</span><span class="named-paragraph-number">1.3.1.2.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">TERNARYSEQUENTIAL_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="comment-syntax"> Here is x:</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2_1" class="named-paragraph-link"><span class="named-paragraph">Set the formal parameters in value mode</span><span class="named-paragraph-number">1.3.1.2.2.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax"> Here is y:</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2_2" class="named-paragraph-link"><span class="named-paragraph">Perform the tests and invocations in value mode</span><span class="named-paragraph-number">1.3.1.2.2.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment-syntax"> Here is z:</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_iname</span><span class="plain-syntax">(</span><span class="identifier-syntax">K_value</span><span class="plain-syntax">, </span><span class="identifier-syntax">Hierarchy::find</span><span class="plain-syntax">(</span><span class="identifier-syntax">FORMAL_RV_HL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2">&#167;1.3.1.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2.1. </b>In Inter, as in C, assignments return a value and are therefore legal here.
But because Inter does not provide a binary sequential opcode, we will fold
our run of assignments into a single value by adding them up &mdash; the result
doesn't matter, since it will be thrown away anyway. So if there are, say,
four formal parameters then our <span class="extract"><span class="extract-syntax">x</span></span> will be:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> (F4 = T4) + ((F3 = T3) + ((F2 = T2) + (F1 = T1)))</span>
</pre>
<p class="commentary">It isn't really important that we count downwards from 4 to 1 here, but we do
it because the Inform 6 compiler happens to evaluate operands of <span class="extract"><span class="extract-syntax">+</span></span> in the
order right then left. So this actually causes <span class="extract"><span class="extract-syntax">T1</span></span> to evaluate first, then <span class="extract"><span class="extract-syntax">T2</span></span>
and so on, provided Inform 6 is the eventual code generator.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Set the formal parameters in value mode</span><span class="named-paragraph-number">1.3.1.2.2.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">L</span><span class="plain-syntax"> = </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">N</span><span class="plain-syntax">-1; </span><span class="identifier-syntax">i</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">--) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) { </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">PLUS_BIP</span><span class="plain-syntax">); </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">(); }</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_2" class="named-paragraph-link"><span class="named-paragraph">Set the ith formal parameter to the ith token value</span><span class="named-paragraph-number">1.3.1.2.1.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="identifier-syntax">N</span><span class="plain-syntax">-1; </span><span class="identifier-syntax">i</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">--) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">i</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">L</span><span class="plain-syntax"> != </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">()) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"misimplemented"</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_2">&#167;1.3.1.2.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2_2" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2.2. </b>Now the fun really begins. We compile <span class="extract"><span class="extract-syntax">y</span></span> to an expression like so:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> ((condition for I1 to be valid) &amp;&amp; ((formal_rv = I1) bitwise-or 1)) ||</span>
<span class="plain-syntax"> ((condition for I2 to be valid) &amp;&amp; ((formal_rv = I2) bitwise-or 1)) ||</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> ((condition for In to be valid) &amp;&amp; ((formal_rv = In) bitwise-or 1)) ||</span>
<span class="plain-syntax"> (issue run-time-problem)</span>
</pre>
<p class="commentary">The key here is that Inter, like C, evaluates operands of <span class="extract"><span class="extract-syntax">&amp;&amp;</span></span> 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 <span class="extract"><span class="extract-syntax">formal_rv</span></span>) never
happens; and similarly for logical-or.
</p>
<p class="commentary">Bitwise-or does not short-circuit, so the faintly ridiculous trick of
bitwise-or-ing with 1 ensures that any value is made non-zero, so that the
assignment is always regarded by Inter as "true". This all means that if
any condition is valid, no subsequent conditions will even be tested.
</p>
<p class="commentary">Note that all functions return values in Inter, so the function call to issue
the run-time problem is indeed legal in a value context.
</p>
<p class="commentary">Matters are a little simpler if the final invocation is proven:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> ((condition for I1 to be valid) &amp;&amp; ((formal_rv = I1) bitwise-or 1)) ||</span>
<span class="plain-syntax"> ((condition for I2 to be valid) &amp;&amp; ((formal_rv = I2) bitwise-or 1)) ||</span>
<span class="plain-syntax"> ...</span>
<span class="plain-syntax"> ((formal_rv = In) bitwise-or 1)</span>
</pre>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Perform the tests and invocations in value mode</span><span class="named-paragraph-number">1.3.1.2.2.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">L</span><span class="plain-syntax"> = </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">number_unproven</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">, </span><span class="identifier-syntax">last_is_unproven</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">inv</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">invl</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) </span><span class="identifier-syntax">number_unproven</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">last_is_unproven</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">last_is_unproven</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">OR_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2_2_1" class="named-paragraph-link"><span class="named-paragraph">Perform the tests and invocations without RTP in value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">last_is_unproven</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_4" class="named-paragraph-link"><span class="named-paragraph">Compile call to function throwing an RTP</span><span class="named-paragraph-number">1.3.1.2.1.4</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">L</span><span class="plain-syntax"> != </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">()) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"misimplemented"</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_2">&#167;1.3.1.2.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2_2_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2.2.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Perform the tests and invocations without RTP in value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">L</span><span class="plain-syntax"> = </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">pos</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOOP_THROUGH_INVOCATION_LIST</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">invl</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOGIF</span><span class="plain-syntax">(</span><span class="identifier-syntax">MATCHING</span><span class="plain-syntax">, </span><span class="string-syntax">"RC%d: $e\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">pos</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">); </span><span class="identifier-syntax">pos</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">pos</span><span class="plain-syntax"> &lt; </span><span class="identifier-syntax">InvocationLists::length</span><span class="plain-syntax">(</span><span class="identifier-syntax">invl</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">OR_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax"> = </span><a href="5-ci.html#SP4" class="function-link"><span class="function-syntax">CompileInvocations::new_tokens_packet</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_3" class="named-paragraph-link"><span class="named-paragraph">Substitute the formal parameters into the tokens packet</span><span class="named-paragraph-number">1.3.1.2.1.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2_2_1_1" class="named-paragraph-link"><span class="named-paragraph">Compile code to apply this invocation if it's applicable, value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax"> = </span><span class="constant-syntax">1</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax"> &lt;= </span><span class="identifier-syntax">InvocationLists::length</span><span class="plain-syntax">(</span><span class="identifier-syntax">invl</span><span class="plain-syntax">) - </span><span class="constant-syntax">1</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">L</span><span class="plain-syntax"> != </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">()) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"misimplemented"</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_2_2">&#167;1.3.1.2.2.2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2_2_1_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2.2.1.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile code to apply this invocation if it's applicable, value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">L</span><span class="plain-syntax"> = </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">ands_made</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_2_2_1_1_1" class="named-paragraph-link"><span class="named-paragraph">Compile the check on invocation applicability, value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1.1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">BITWISEOR_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">STORE_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::ref_iname</span><span class="plain-syntax">(</span><span class="identifier-syntax">K_value</span><span class="plain-syntax">, </span><span class="identifier-syntax">Hierarchy::find</span><span class="plain-syntax">(</span><span class="identifier-syntax">FORMAL_RV_HL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><a href="5-ci.html#SP2" class="function-link"><span class="function-syntax">CompileInvocations::single</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sl</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">, </span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_number</span><span class="plain-syntax">(1);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">ands_made</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">L</span><span class="plain-syntax"> != </span><span class="identifier-syntax">EmitCode::level</span><span class="plain-syntax">()) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"misimplemented"</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_2_2_1">&#167;1.3.1.2.2.2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP1_3_1_2_2_2_1_1_1" class="paragraph-anchor"></a><b>&#167;1.3.1.2.2.2.1.1.1. </b><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile the check on invocation applicability, value mode</span><span class="named-paragraph-number">1.3.1.2.2.2.1.1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_unproven</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">checks_made</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">Invocations::get_no_tokens</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">); </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">check_against</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_token_check_to_do</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">check_against</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">AND_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">(); </span><span class="identifier-syntax">ands_made</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP1_3_1_2_1_1_1" class="named-paragraph-link"><span class="named-paragraph">Compile a check that this formal variable matches the token</span><span class="named-paragraph-number">1.3.1.2.1.1.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">checks_made</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">checks_made</span><span class="plain-syntax"> == </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"this should not be marked unproven"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP1_3_1_2_2_2_1_1">&#167;1.3.1.2.2.2.1.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP2" class="paragraph-anchor"></a><b>&#167;2. Lower level: compiling single invocations. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">CompileInvocations::single</span><button class="popup" onclick="togglePopup('usagePopup2')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup2">Usage of <span class="code-font"><span class="function-syntax">CompileInvocations::single</span></span>:<br/><a href="5-ci.html#SP1_3">&#167;1.3</a>, <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>, <a href="5-ci.html#SP1_3_1_2_2_2_1_1">&#167;1.3.1.2.2.2.1.1</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">value_holster</span><span class="plain-syntax"> *</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">inv</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">source_location</span><span class="plain-syntax"> *</span><span class="identifier-syntax">where_from</span><span class="plain-syntax">, </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> *</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOGIF</span><span class="plain-syntax">(</span><span class="identifier-syntax">MATCHING</span><span class="plain-syntax">, </span><span class="string-syntax">"Compiling single invocation: $e\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Node::get_say_verb</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">RTVerbs::ConjugateVerb_invoke_emit</span><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Node::get_say_verb</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">),</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Node::get_modal_verb</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">),</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Annotations::read_int</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">say_verb_negated_ANNOT</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Node::get_say_adjective</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">RTAdjectives::invoke</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_say_adjective</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP2_1" class="named-paragraph-link"><span class="named-paragraph">Invoke a phrasal invocation</span><span class="named-paragraph-number">2.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP2_1" class="paragraph-anchor"></a><b>&#167;2.1. </b>Note that the phrases which compile to Inter jump or return instructions can
never be marked to save <span class="extract"><span class="extract-syntax">self</span></span>, or the code here would lead to slow stack overflow
errors, since <span class="extract"><span class="extract-syntax">self</span></span> would be pushed but not pulled.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Invoke a phrasal invocation</span><span class="named-paragraph-number">2.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> = </span><span class="identifier-syntax">DONT_KNOW_MOR</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">save_self</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Invocations::is_marked_to_save_self</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)) </span><span class="identifier-syntax">save_self</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">save_self</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">PUSH_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_iname</span><span class="plain-syntax">(</span><span class="identifier-syntax">K_value</span><span class="plain-syntax">, </span><span class="identifier-syntax">Hierarchy::find</span><span class="plain-syntax">(</span><span class="identifier-syntax">SELF_HL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP2_1_2" class="named-paragraph-link"><span class="named-paragraph">The art of invocation is delegation</span><span class="named-paragraph-number">2.1.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP2_1_3" class="named-paragraph-link"><span class="named-paragraph">Compile a newline if the phrase implicitly requires one</span><span class="named-paragraph-number">2.1.3</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">save_self</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">PULL_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::ref_iname</span><span class="plain-syntax">(</span><span class="identifier-syntax">K_value</span><span class="plain-syntax">, </span><span class="identifier-syntax">Hierarchy::find</span><span class="plain-syntax">(</span><span class="identifier-syntax">SELF_HL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> != </span><span class="identifier-syntax">DONT_KNOW_MOR</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">LOGIF</span><span class="plain-syntax">(</span><span class="identifier-syntax">MATCHING</span><span class="plain-syntax">, </span><span class="string-syntax">"Single invocation return manner: %d\n"</span><span class="plain-syntax">, </span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><a href="3-fnc.html#SP4" class="function-link"><span class="function-syntax">Functions::defn_being_compiled</span></a><span class="plain-syntax">()) &amp;&amp; (</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> != </span><span class="identifier-syntax">DONT_KNOW_MOR</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="5-ci.html#SP2_1_1" class="named-paragraph-link"><span class="named-paragraph">If the invocation compiled to a return from a function, check this is allowed</span><span class="named-paragraph-number">2.1.1</span></a></span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP2">&#167;2</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP2_1_1" class="paragraph-anchor"></a><b>&#167;2.1.1. </b>For example, the definition of the phrase "To begin" isn't allowed to contain the
invocation "decide on 178", since it isn't a phrase to decide anything. This is
where that's checked:
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">If the invocation compiled to a return from a function, check this is allowed</span><span class="named-paragraph-number">2.1.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">id_body</span><span class="plain-syntax"> *</span><span class="identifier-syntax">current_idb</span><span class="plain-syntax"> = </span><a href="3-fnc.html#SP4" class="function-link"><span class="function-syntax">Functions::defn_being_compiled</span></a><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">manner_expected</span><span class="plain-syntax"> = </span><span class="identifier-syntax">current_idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> != </span><span class="identifier-syntax">manner_expected</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">manner_expected</span><span class="plain-syntax"> != </span><span class="identifier-syntax">DECIDES_NOTHING_AND_RETURNS_MOR</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::quote_source</span><span class="plain-syntax">(1, </span><span class="identifier-syntax">current_sentence</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::quote_text</span><span class="plain-syntax">(2,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">IDTypeData::describe_manner_of_return</span><span class="plain-syntax">(</span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax">, </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">, </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">K</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::quote_text</span><span class="plain-syntax">(3,</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">IDTypeData::describe_manner_of_return</span><span class="plain-syntax">(</span><span class="identifier-syntax">manner_expected</span><span class="plain-syntax">,</span>
<span class="plain-syntax"> &amp;(</span><span class="identifier-syntax">current_idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">), &amp;</span><span class="identifier-syntax">K</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">K</span><span class="plain-syntax">) </span><span class="identifier-syntax">Problems::quote_kind</span><span class="plain-syntax">(4, </span><span class="identifier-syntax">K</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">StandardProblems::handmade_problem</span><span class="plain-syntax">(</span><span class="identifier-syntax">Task::syntax_tree</span><span class="plain-syntax">(), </span><span class="identifier-syntax">_p_</span><span class="plain-syntax">(</span><span class="identifier-syntax">PM_WrongEndToPhrase</span><span class="plain-syntax">));</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">K</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::issue_problem_segment</span><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="string-syntax">"The line %1 seems to be a way that the phrase you're defining can come "</span>
<span class="plain-syntax"> </span><span class="string-syntax">"to an end, with %2, but it should always end up with a phrase to "</span>
<span class="plain-syntax"> </span><span class="string-syntax">"decide %4."</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::issue_problem_segment</span><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="string-syntax">"The line %1 seems to be a way that the phrase you're defining can come "</span>
<span class="plain-syntax"> </span><span class="string-syntax">"to an end, with %2, but it should always end up with %3."</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Problems::issue_problem_end</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP2_1">&#167;2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP2_1_2" class="paragraph-anchor"></a><b>&#167;2.1.2. </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="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">The art of invocation is delegation</span><span class="named-paragraph-number">2.1.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">id_body</span><span class="plain-syntax"> *</span><span class="identifier-syntax">idb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Node::get_phrase_invoked</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">IDTypeData::invoked_inline</span><span class="plain-syntax">(</span><span class="identifier-syntax">idb</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">manner_of_return</span><span class="plain-syntax"> =</span>
<span class="plain-syntax"> </span><a href="5-cii.html#SP3" class="function-link"><span class="function-syntax">CSIInline::csi_inline</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">where_from</span><span class="plain-syntax">, </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><a href="5-ciac.html#SP1" class="function-link"><span class="function-syntax">CallingFunctions::csi_by_call</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">VH</span><span class="plain-syntax">, </span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">where_from</span><span class="plain-syntax">, </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">);</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP2_1">&#167;2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP2_1_3" class="paragraph-anchor"></a><b>&#167;2.1.3. </b>If <span class="extract"><span class="extract-syntax">allow_implied_newlines</span></span> is set, we understand the final part of a
text literal to be allowed to print an implied newline. For example, here it's on:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">say</span><span class="plain-syntax"> </span><span class="string-syntax">"At [time of day], I like to serve afternoon tea. Indian or Chinese?"</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary">Here the question mark has an implied newline after it. But there are other
contexts in which newlines are not implied:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="identifier-syntax">let</span><span class="plain-syntax"> </span><span class="identifier-syntax">the</span><span class="plain-syntax"> </span><span class="identifier-syntax">warning</span><span class="plain-syntax"> </span><span class="identifier-syntax">rubric</span><span class="plain-syntax"> </span><span class="identifier-syntax">be</span><span class="plain-syntax"> </span><span class="string-syntax">"Snakes!"</span><span class="plain-syntax">;</span>
</pre>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Compile a newline if the phrase implicitly requires one</span><span class="named-paragraph-number">2.1.3</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">IDTypeData::is_a_say_phrase</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_phrase_invoked</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">))) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">Node::get_phrase_invoked</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">)-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">as_say</span><span class="plain-syntax">.</span><span class="identifier-syntax">say_phrase_running_on</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">allow_implied_newlines</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">tokens_count</span><span class="plain-syntax"> &gt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">Rvalues::is_CONSTANT_of_kind</span><span class="plain-syntax">(</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">token_vals</span><span class="plain-syntax">[0], </span><span class="identifier-syntax">K_text</span><span class="plain-syntax">)) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">Word::text_ending_sentence</span><span class="plain-syntax">(</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Wordings::first_wn</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">token_vals</span><span class="plain-syntax">[0]))))) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::inv</span><span class="plain-syntax">(</span><span class="identifier-syntax">PRINT_BIP</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::down</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::val_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">I</span><span class="string-syntax">"\n"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">EmitCode::up</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="5-ci.html#SP2_1">&#167;2.1</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP3" class="paragraph-anchor"></a><b>&#167;3. Tokens packets. </b>This structure is a convenient holder for the token values being used when
invoking a phrase, and for what we think their kinds are.
</p>
<p class="commentary">In many cases that will not be much of an issue, but suppose the phrase to be
invoked is polymorphic, like so &mdash;
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">To</span><span class="plain-syntax"> </span><span class="identifier-syntax">discuss</span><span class="plain-syntax"> (</span><span class="identifier-syntax">V</span><span class="plain-syntax"> - </span><span class="identifier-syntax">sayable</span><span class="plain-syntax"> </span><span class="identifier-syntax">value</span><span class="plain-syntax">):</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">say</span><span class="plain-syntax"> </span><span class="string-syntax">"You discourse about [V]."</span>
</pre>
<p class="commentary">If the invocation is "discuss 16", then the token has kind <span class="extract"><span class="extract-syntax">K_number</span></span> not
<span class="extract"><span class="extract-syntax">K_sayable_value</span></span>, because we derive the kind from what the phrase was actually
invoked on rather than the full range of what it might have been. Similarly,
the <span class="extract"><span class="extract-syntax">fn_kind</span></span> is <span class="extract"><span class="extract-syntax">function number -&gt; nothing</span></span>, not <span class="extract"><span class="extract-syntax">function sayable value -&gt; nothing</span></span>.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens_count</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">token_vals</span><span class="plain-syntax">[</span><span class="identifier-syntax">MAX_TOKENS_PER_PHRASE</span><span class="plain-syntax">];</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">token_kinds</span><span class="plain-syntax">[</span><span class="identifier-syntax">MAX_TOKENS_PER_PHRASE</span><span class="plain-syntax">];</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">fn_kind</span><span class="plain-syntax">;</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>The structure tokens_packet is accessed in 3/cb, 5/ciac, 5/cii and here.</li></ul>
<p class="commentary firstcommentary"><a id="SP4" class="paragraph-anchor"></a><b>&#167;4. </b>This is all easy to unpack from the invocation subtree.
</p>
<p class="commentary">If a token holds the name of a kind rather than a value as such, we use the
<span class="extract"><span class="extract-syntax">nothing</span></span> constant as the "token value", just as a placeholder. It won't be compiled.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> </span><span class="function-syntax">CompileInvocations::new_tokens_packet</span><button class="popup" onclick="togglePopup('usagePopup3')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup3">Usage of <span class="code-font"><span class="function-syntax">CompileInvocations::new_tokens_packet</span></span>:<br/><a href="5-ci.html#SP1_3">&#167;1.3</a>, <a href="5-ci.html#SP1_3_1_2_1">&#167;1.3.1.2.1</a>, <a href="5-ci.html#SP1_3_1_2_2_2_1">&#167;1.3.1.2.2.2.1</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">inv</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">id_body</span><span class="plain-syntax"> *</span><span class="identifier-syntax">idb</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Node::get_phrase_invoked</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">tokens_packet</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="identifier-syntax">tokens_count</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_no_tokens_needed</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">tokens_count</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">val</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Invocations::get_token_as_parsed</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">, </span><span class="identifier-syntax">i</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">K</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Specifications::to_kind</span><span class="plain-syntax">(</span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">token_sequence</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="identifier-syntax">to_match</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">IDTypeData::invoked_inline</span><span class="plain-syntax">(</span><span class="identifier-syntax">idb</span><span class="plain-syntax">) == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">) &amp;&amp;</span>
<span class="plain-syntax"> (</span><span class="identifier-syntax">Kinds::Behaviour::definite</span><span class="plain-syntax">(</span><span class="identifier-syntax">K</span><span class="plain-syntax">) == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_kinds</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">Specifications::to_kind</span><span class="plain-syntax">(</span><span class="identifier-syntax">val</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_kinds</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">K</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">token_sequence</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="identifier-syntax">construct</span><span class="plain-syntax"> == </span><span class="identifier-syntax">KIND_NAME_IDTC</span><span class="plain-syntax">)</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_vals</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">Rvalues::new_nothing_object_constant</span><span class="plain-syntax">();</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">else</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_vals</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">] = </span><span class="identifier-syntax">val</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">kind</span><span class="plain-syntax"> *</span><span class="identifier-syntax">return_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">Node::get_kind_resulting</span><span class="plain-syntax">(</span><span class="identifier-syntax">inv</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">return_kind</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">idb</span><span class="plain-syntax">)) </span><span class="identifier-syntax">return_kind</span><span class="plain-syntax"> = </span><span class="identifier-syntax">idb</span><span class="plain-syntax">-&gt;</span><span class="identifier-syntax">type_data</span><span class="plain-syntax">.</span><span class="identifier-syntax">return_kind</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="identifier-syntax">fn_kind</span><span class="plain-syntax"> =</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">Kinds::function_kind</span><span class="plain-syntax">(</span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">tokens_count</span><span class="plain-syntax">, </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">.</span><span class="element-syntax">token_kinds</span><span class="plain-syntax">, </span><span class="identifier-syntax">return_kind</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">tokens</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="5-cbal.html">&#10094;</a></li><li class="progresschapter"><a href="P-wtmd.html">P</a></li><li class="progresschapter"><a href="1-im.html">1</a></li><li class="progresschapter"><a href="2-cv.html">2</a></li><li class="progresschapter"><a href="3-sf.html">3</a></li><li class="progresschapter"><a href="4-cs.html">4</a></li><li class="progresscurrentchapter">5</li><li class="progresssection"><a href="5-cbal.html">cbal</a></li><li class="progresscurrent">ci</li><li class="progresssection"><a href="5-ciac.html">ciac</a></li><li class="progresssection"><a href="5-cii.html">cii</a></li><li class="progresssection"><a href="5-cste.html">cste</a></li><li class="progresssection"><a href="5-ca.html">ca</a></li><li class="progressnext"><a href="5-ciac.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>