1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-02 23:14:57 +03:00

Document Inform's set of inter primitives

This commit is contained in:
Graham Nelson 2019-03-22 00:12:00 +00:00
parent 24709da69e
commit eabf3cf3d3
6 changed files with 624 additions and 10 deletions

View file

@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>P/cpiti</title>
<title>P/ip</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
@ -266,7 +266,7 @@ ice while a better and more systematic solution was found.
</p>
<hr class="tocbar">
<ul class="toc"><li><a href="P-cpiti.html">Back to 'Code Packages in Textual Inter'</a></li><li><i>(This section ends Preliminaries.)</i></li></ul><hr class="tocbar">
<ul class="toc"><li><a href="P-ip.html">Back to 'Inform Primitives'</a></li><li><i>(This section ends Preliminaries.)</i></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>

View file

@ -321,10 +321,14 @@ signature, so <code class="display"><span class="extract">ref</span></code>, <co
For example, suppose the following signatures:
</p>
<p class="inwebparagraph"> !primitive !jump lab -&gt; void<code class="display"><span class="extract">
</span></code> !primitive !pull ref -&gt; val<code class="display"><span class="extract">
</span></code> !primitive !if val code -&gt; void<code class="display"><span class="extract">
</span></code></p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">primitive !jump lab -&gt; void</span>
<span class="plain">primitive !pull ref -&gt; val</span>
<span class="plain">primitive !if val code -&gt; void</span>
</pre>
<p class="inwebparagraph">These might be invoked as follows:
</p>
@ -406,7 +410,7 @@ a reference, not a value.
</p>
<hr class="tocbar">
<ul class="toc"><li><a href="P-dpiti.html">Back to 'Data Packages in Textual Inter'</a></li><li><a href="P-cas.html">Continue with 'Chains and Stages'</a></li></ul><hr class="tocbar">
<ul class="toc"><li><a href="P-dpiti.html">Back to 'Data Packages in Textual Inter'</a></li><li><a href="P-ip.html">Continue with 'Inform Primitives'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>

348
docs/inter/P-ip.html Normal file
View file

@ -0,0 +1,348 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>P/cpiti</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of 'P/ip' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">inter 1</a></li><li><a href="index.html#P">Preliminaries</a></li><li><b>Inform Primitives</b></li></ul><p class="purpose">The standard set of primitive invocations used within Inform.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Status</a></li><li><a href="#SP2">&#167;2. Arithmetic</a></li><li><a href="#SP3">&#167;3. Logical operators</a></li><li><a href="#SP4">&#167;4. Bitwise operators</a></li><li><a href="#SP5">&#167;5. Numerical comparison</a></li><li><a href="#SP6">&#167;6. Sequential evaluation</a></li><li><a href="#SP7">&#167;7. Random numbers</a></li><li><a href="#SP8">&#167;8. Printing</a></li><li><a href="#SP9">&#167;9. Stack access</a></li><li><a href="#SP10">&#167;10. Accessing storage</a></li><li><a href="#SP11">&#167;11. Indirect function calls</a></li><li><a href="#SP12">&#167;12. Control flow</a></li><li><a href="#SP13">&#167;13. Interactive fiction-only primitives</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Status. </b>The Inter specification allows for any number of primitive invocations to
be declared and used; none are built-in or required.
</p>
<p class="inwebparagraph">The Inform compiler, however, has a set of around 90 different primitives.
The back end of the compiler can compile those into valid Inform 6 code;
the front end of the compiler is guaranteed to declare and use only (a
subset of) those 90. That gives the following set of primitives a
kind of halfway status: though they are not part of the inter specification,
for the time being they're the only game in town.
</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. Arithmetic. </b>The following are standard integer arithmetic operations:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !plus val val -&gt; val</span></code>. 16 or 32-bit integer addition.
</li><li>(b) <code class="display"><span class="extract">primitive !minus val val -&gt; val</span></code>. 16 or 32-bit integer subtraction.
</li><li>(c) <code class="display"><span class="extract">primitive !unaryminus val -&gt; val</span></code>. Equivalent to performing <code class="display"><span class="extract">0 - x</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !times val val -&gt; val</span></code>. 16 or 32-bit integer multiplication.
</li><li>(e) <code class="display"><span class="extract">primitive !divide val val -&gt; val</span></code>. 16 or 32-bit integer division.
</li><li>(f) <code class="display"><span class="extract">primitive !modulo val val -&gt; val</span></code>. Remainder after such a division.
</li></ul>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. Logical operators. </b>In general, the value 0 is false, and all other values are true.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !not val -&gt; val</span></code>. True if the value is false, and vice versa.
</li><li>(b) <code class="display"><span class="extract">primitive !and val val -&gt; val</span></code>. True if both are true: doesn't evaluate the second if the first is false.
</li><li>(c) <code class="display"><span class="extract">primitive !or val val -&gt; val</span></code>. True if either is true: doesn't evaluate the second if the first is true.
</li></ul>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Bitwise operators. </b>These differ in that they do not "short circuit", and do not squash values
down to just 0 or 1.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !bitwiseand val val -&gt; val</span></code>.
</li><li>(a) <code class="display"><span class="extract">primitive !bitwiseor val val -&gt; val</span></code>.
</li><li>(a) <code class="display"><span class="extract">primitive !bitwisenot val -&gt; val</span></code>.
</li></ul>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Numerical comparison. </b>These are comparisons of signed integers. (If Inform needs to compare unsigned
integers, it calls a routine in the I6 template.)
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !eq val val -&gt; val</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !ne val val -&gt; val</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !gt val val -&gt; val</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !ge val val -&gt; val</span></code>.
</li><li>(e) <code class="display"><span class="extract">primitive !lt val val -&gt; val</span></code>.
</li><li>(f) <code class="display"><span class="extract">primitive !le val val -&gt; val</span></code>.
</li></ul>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. Sequential evaluation. </b>The reason for the existence of <code class="display"><span class="extract">!ternarysequential</span></code> is that it's a convenient
shorthand, and also that it helps the code generator with I6 generation,
because I6 has problems with the syntax of complicated sequential evals.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !sequential val val -&gt; val</span></code>. Evaluates the first, then the second
value, producing that second value.
</li><li>(a) <code class="display"><span class="extract">primitive !ternarysequential val val val -&gt; val</span></code>. Evaluates the first,
then the second, then the third value, producing that third value.
</li></ul>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Random numbers. </b>There is just one primitive for this:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !random val -&gt; val</span></code>. Produce a uniformly random integer in the range 0 up to <code class="display"><span class="extract">val</span></code> minus 1.
</li></ul>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Printing. </b>These print data of various kinds:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !print val -&gt; void</span></code>. Print text.
</li><li>(b) <code class="display"><span class="extract">primitive !printnumber val -&gt; void</span></code>. Print a (signed) number in decimal.
</li><li>(c) <code class="display"><span class="extract">primitive !printchar val -&gt; void</span></code>. Print a character value, from the ZSCII character set.
</li><li>(d) <code class="display"><span class="extract">primitive !printaddress val -&gt; void</span></code>. Print a dictionary word.
</li><li>(e) <code class="display"><span class="extract">primitive !printstring val -&gt; void</span></code>. Print a packed string.
</li></ul>
<p class="inwebparagraph">While these correspond to standard I6 library functions, they should probably
be removed from the set of primitives, but there are issues here to do with
the Inform 6 "veneer":
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !printnlnumber val -&gt; void</span></code>. Print number but in natural language.
</li><li>(b) <code class="display"><span class="extract">primitive !printname val -&gt; void</span></code>. Print name of an object.
</li><li>(c) <code class="display"><span class="extract">primitive !printdef val -&gt; void</span></code>. Print name of an object, preceded by definite article.
</li><li>(d) <code class="display"><span class="extract">primitive !printcdef val -&gt; void</span></code>. Print name of an object, preceded by capitalised definite article.
</li><li>(e) <code class="display"><span class="extract">primitive !printindef val -&gt; void</span></code>. Print name of an object, preceded by indefinite article.
</li><li>(f) <code class="display"><span class="extract">primitive !printcindef val -&gt; void</span></code>. Print name of an object, preceded by capitalised indefinite article.
</li></ul>
<p class="inwebparagraph">There are also primitive ways to change the visual style of text:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !font val -&gt; void</span></code>. Change to fixed-width font if value is 1, or regular if 0.
</li><li>(b) <code class="display"><span class="extract">primitive !stylebold void -&gt; void</span></code>. Change to bold type.
</li><li>(c) <code class="display"><span class="extract">primitive !styleunderline void -&gt; void</span></code>. Change to underlined type.
</li><li>(d) <code class="display"><span class="extract">primitive !styleroman void -&gt; void</span></code>. Change to roman (i.e., not bold, not underlined) type.
</li></ul>
<p class="inwebparagraph">Lastly, a primitive for a rum feature of Inform 6 allowing for the display of
"box quotations" on screen:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !box val -&gt; void</span></code>.
</li></ul>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Stack access. </b>The stack is not directly accessible anywhere in memory, so the only access
is via the following.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !push val -&gt; void</span></code>. Push value onto the stack.
</li><li>(b) <code class="display"><span class="extract">primitive !pull ref -&gt; void</span></code>. Pull value from the stack and write it into
the storage referred to. Values on the stack have unchecked kinds: it's up to
the author not to pull an inappropriate value.
</li></ul>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. Accessing storage. </b>Here the <code class="display"><span class="extract">ref</span></code> term is a refernce to a piece of storage: a property of an
instance, or a global variable, or an entry in memory, for example.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !store ref val -&gt; val</span></code>. Put the value in <code class="display"><span class="extract">ref</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !setbit ref val -&gt; void</span></code>. Set bits in the mask <code class="display"><span class="extract">val</span></code> in <code class="display"><span class="extract">ref</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !clearbit ref val -&gt; void</span></code>. Clear bits in the mask <code class="display"><span class="extract">val</span></code> in <code class="display"><span class="extract">ref</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !postincrement ref -&gt; val</span></code>. Performs the equivalent of <code class="display"><span class="extract">ref++</span></code>.
</li><li>(e) <code class="display"><span class="extract">primitive !preincrement ref -&gt; val</span></code>. Performs the equivalent of <code class="display"><span class="extract">++ref</span></code>.
</li><li>(f) <code class="display"><span class="extract">primitive !postdecrement ref -&gt; val</span></code>. Performs the equivalent of <code class="display"><span class="extract">ref--</span></code>.
</li><li>(g) <code class="display"><span class="extract">primitive !predecrement ref -&gt; val</span></code>. Performs the equivalent of <code class="display"><span class="extract">--ref</span></code>.
</li></ul>
<p class="inwebparagraph">Memory can be read with the following. The first value is the address of
the array; the second is an offset, that is, with 0 being the first entry,
1 the second, and so on. "Word" in this context means either an <code class="display"><span class="extract">int16</span></code> or
an <code class="display"><span class="extract">int32</span></code>, depending on what virtual machine are compiling to.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !lookup val val -&gt; val</span></code>. Find word at this word offset.
</li><li>(b) <code class="display"><span class="extract">primitive !lookupbyte val val -&gt; val</span></code>. Find byte at this byte offset.
</li></ul>
<p class="inwebparagraph">Those however only read from array entries. To write to array entries, we
need to use <code class="display"><span class="extract">!store</span></code> or similar (see above); but to do that, we need a
reference for the memory cell. We do that with:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !lookupref val val -&gt; ref</span></code>.
</li></ul>
<p class="inwebparagraph">(There is at present no equivalent for byte arrays.)
</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Indirect function calls. </b>Invocations of functions can only be made with <code class="display"><span class="extract">inv</span></code> when the function is
specified as a constant, and when its signature is therefore known. If
we need to call "whatever function this variable refers to", we have to
use one of the following. They differ only in their signatures. The
first value is the function address, and subsequent ones are arguments.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !indirect0v val -&gt; void</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !indirect1v val val -&gt; void</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !indirect2v val val val -&gt; void</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !indirect3v val val val val -&gt; void</span></code>.
</li><li>(e) <code class="display"><span class="extract">primitive !indirect4v val val val val val -&gt; void</span></code>.
</li><li>(f) <code class="display"><span class="extract">primitive !indirect5v val val val val val val -&gt; void</span></code>.
</li><li>(g) <code class="display"><span class="extract">primitive !indirect0 val -&gt; val</span></code>.
</li><li>(h) <code class="display"><span class="extract">primitive !indirect1 val val -&gt; val</span></code>.
</li><li>(i) <code class="display"><span class="extract">primitive !indirect2 val val val -&gt; val</span></code>.
</li><li>(j) <code class="display"><span class="extract">primitive !indirect3 val val val val -&gt; val</span></code>.
</li><li>(k) <code class="display"><span class="extract">primitive !indirect4 val val val val val -&gt; val</span></code>.
</li><li>(l) <code class="display"><span class="extract">primitive !indirect5 val val val val val val -&gt; val</span></code>.
</li></ul>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. Control flow. </b>The simplest control statement is an "if". Note that a different primitive
is used if there is an "else" attached: it would be impossible to use the
same primitive for both because they couldn't have the same signature.
</p>
<p class="inwebparagraph"><code class="display"><span class="extract">!ifdebug</span></code> is an oddity: it executes the code only if the program is
being compiled in "debugging mode". (In Inform, that would mean that the
story file is being made inside the application, or else released in a
special testing configuration.) While the same effect could be achieved
using conditional compliation splats, this is much more efficient.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !if val code -&gt; void</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !ifelse val code code -&gt; void</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !ifdebug code -&gt; void</span></code>.
</li></ul>
<p class="inwebparagraph">There are then several loops.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !while val code -&gt; void</span></code>. Similar to <code class="display"><span class="extract">while</span></code> in C.
</li><li>(b) <code class="display"><span class="extract">primitive !for val val val code -&gt; void</span></code>. Similar to <code class="display"><span class="extract">for</span></code> in C.
</li><li>(c) <code class="display"><span class="extract">primitive !objectloopx ref val code -&gt; void</span></code>. A loop over instances,
stored in the variable <code class="display"><span class="extract">ref</span></code>, of the kind of object <code class="display"><span class="extract">val</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !objectloop ref val val code -&gt; void</span></code>. A more general form,
where the secomd <code class="display"><span class="extract">val</span></code> is a condition to be evaluated which decides whether
to execute the code for given <code class="display"><span class="extract">ref</span></code> value.
</li></ul>
<p class="inwebparagraph">A switch statement takes a value, and then executes at most one of an
arbitrary number of possible code segments. This can't be implemented with
a single primitive, because its signature would have to be of varying
lengths with different uses (since some switches have many cases, some few).
Instead: a <code class="display"><span class="extract">switch</span></code> takes a single <code class="display"><span class="extract">code</span></code>, but that <code class="display"><span class="extract">code</span></code> can in turn
contain only invocations of <code class="display"><span class="extract">!case</span></code>, followed optionally by one of <code class="display"><span class="extract">!default</span></code>.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !switch val code -&gt; void</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !case val code -&gt; void</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !default code -&gt; void</span></code>.
</li></ul>
<p class="inwebparagraph">This looks a little baroque, but it works in practice:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">inv !switch</span>
<span class="plain"> val K_number X</span>
<span class="plain"> code _ _</span>
<span class="plain"> inv !case</span>
<span class="plain"> val K_number 1</span>
<span class="plain"> code _ _</span>
<span class="plain"> inv !print</span>
<span class="plain"> val K_text "One!"</span>
<span class="plain"> inv !case</span>
<span class="plain"> val K_number 2</span>
<span class="plain"> code _ _</span>
<span class="plain"> inv !print</span>
<span class="plain"> val K_text "Two!"</span>
<span class="plain"> inv !default</span>
<span class="plain"> code _ _</span>
<span class="plain"> inv !print</span>
<span class="plain"> val K_text "Something else!"</span>
</pre>
<p class="inwebparagraph">As in most C-like languages, there are primitives for:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !break void -&gt; void</span></code>. Exit the innermost switch case or loop.
</li><li>(b) <code class="display"><span class="extract">primitive !continue void -&gt; void</span></code>. Complete the current iteration of
the innermost loop.
</li></ul>
<p class="inwebparagraph">Two ways to terminate what's happening:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !return val -&gt; void</span></code>. Finish the current function, giving the
supplied value as the result if the function is being executed in a value
context, and throwing it away if not.
</li><li>(b) <code class="display"><span class="extract">primitive !quit void -&gt; void</span></code>. Halt the whole program immediately.
</li></ul>
<p class="inwebparagraph">And, lastly, the lowest-level way to travel:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !jump lab -&gt; void</span></code>. Jumo to this label in the current function.
</li></ul>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. Interactive fiction-only primitives. </b>The following would make no sense in a general-purpose program. Most mirror
very low-level I6 features, and Inform uses them mainly when converting
I6 code into inter: in almost all cases it's better to call routines in the
template rather than to use these. First, the spatial containment object tree:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !move val val -&gt; void</span></code>. Moves first to second (both are objects).
</li><li>(b) <code class="display"><span class="extract">primitive !in val val -&gt; val</span></code>. Tests if first is in second (both are objects).
</li><li>(c) <code class="display"><span class="extract">primitive !notin val val -&gt; val</span></code>. Negation of same.
</li></ul>
<p class="inwebparagraph">Object class membership:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !ofclass val val -&gt; val</span></code>. Does the first belong to the enumerated
subkind whose weak type ID is the second value?
</li></ul>
<p class="inwebparagraph">Attributes can be handled as follows. The values used to refer to these attributes
can be inter symbols for their properties, but only if those properties are
indeed stored as Z-machine or Glulx attributes at run-time.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !give val val -&gt; void</span></code>. Set the second (an attribute) for the first (an object).
</li><li>(b) <code class="display"><span class="extract">primitive !take val val -&gt; void</span></code>. Unset the second (an attribute) for the first (an object).
</li><li>(c) <code class="display"><span class="extract">primitive !has val val -&gt; val</span></code>. Test if the first (an object) has the second (an attibute).
</li><li>(d) <code class="display"><span class="extract">primitive !hasnt val val -&gt; val</span></code>. Negation of same.
</li></ul>
<p class="inwebparagraph">Direct access to virtual machine object properties:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) <code class="display"><span class="extract">primitive !propertyvalue val val -&gt; val</span></code>.
</li><li>(b) <code class="display"><span class="extract">primitive !propertyaddress val val -&gt; val</span></code>.
</li><li>(c) <code class="display"><span class="extract">primitive !propertylength val val -&gt; val</span></code>.
</li><li>(d) <code class="display"><span class="extract">primitive !provides val val -&gt; val</span></code>.
</li></ul>
<hr class="tocbar">
<ul class="toc"><li><a href="P-cpiti.html">Back to 'Code Packages in Textual Inter'</a></li><li><a href="P-cas.html">Continue with 'Chains and Stages'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>

View file

@ -31,6 +31,10 @@
<p><a href="P-cpiti.html"><spon class="sectiontitle">Code Packages in Textual Inter</span></a> -
<span class="purpose">How executable functions are expressed in textual inter programs.</span></p>
</li>
<li>
<p><a href="P-ip.html"><spon class="sectiontitle">Inform Primitives</span></a> -
<span class="purpose">The standard set of primitive invocations used within Inform.</span></p>
</li>
<li>
<p><a href="P-cas.html"><spon class="sectiontitle">Chains and Stages</span></a> -
<span class="purpose">Sequences of named code-generation stages are called chains.</span></p>

View file

@ -203,9 +203,9 @@ Just as |val| supplies a value as needed by a |val| term in an invocation
signature, so |ref|, |lab| and |code| meet the other possible requirements.
For example, suppose the following signatures:
!primitive !jump lab -> void|
!primitive !pull ref -> val|
!primitive !if val code -> void|
|primitive !jump lab -> void|
|primitive !pull ref -> val|
|primitive !if val code -> void|
These might be invoked as follows:

View file

@ -0,0 +1,258 @@
Inform Primitives.
The standard set of primitive invocations used within Inform.
@h Status.
The Inter specification allows for any number of primitive invocations to
be declared and used; none are built-in or required.
The Inform compiler, however, has a set of around 90 different primitives.
The back end of the compiler can compile those into valid Inform 6 code;
the front end of the compiler is guaranteed to declare and use only (a
subset of) those 90. That gives the following set of primitives a
kind of halfway status: though they are not part of the inter specification,
for the time being they're the only game in town.
@h Arithmetic.
The following are standard integer arithmetic operations:
(a) |primitive !plus val val -> val|. 16 or 32-bit integer addition.
(b) |primitive !minus val val -> val|. 16 or 32-bit integer subtraction.
(c) |primitive !unaryminus val -> val|. Equivalent to performing |0 - x|.
(d) |primitive !times val val -> val|. 16 or 32-bit integer multiplication.
(e) |primitive !divide val val -> val|. 16 or 32-bit integer division.
(f) |primitive !modulo val val -> val|. Remainder after such a division.
@h Logical operators.
In general, the value 0 is false, and all other values are true.
(a) |primitive !not val -> val|. True if the value is false, and vice versa.
(b) |primitive !and val val -> val|. True if both are true: doesn't evaluate the second if the first is false.
(c) |primitive !or val val -> val|. True if either is true: doesn't evaluate the second if the first is true.
@h Bitwise operators.
These differ in that they do not "short circuit", and do not squash values
down to just 0 or 1.
(a) |primitive !bitwiseand val val -> val|.
(a) |primitive !bitwiseor val val -> val|.
(a) |primitive !bitwisenot val -> val|.
@h Numerical comparison.
These are comparisons of signed integers. (If Inform needs to compare unsigned
integers, it calls a routine in the I6 template.)
(a) |primitive !eq val val -> val|.
(b) |primitive !ne val val -> val|.
(c) |primitive !gt val val -> val|.
(d) |primitive !ge val val -> val|.
(e) |primitive !lt val val -> val|.
(f) |primitive !le val val -> val|.
@h Sequential evaluation.
The reason for the existence of |!ternarysequential| is that it's a convenient
shorthand, and also that it helps the code generator with I6 generation,
because I6 has problems with the syntax of complicated sequential evals.
(a) |primitive !sequential val val -> val|. Evaluates the first, then the second
value, producing that second value.
(a) |primitive !ternarysequential val val val -> val|. Evaluates the first,
then the second, then the third value, producing that third value.
@h Random numbers.
There is just one primitive for this:
(a) |primitive !random val -> val|. Produce a uniformly random integer in the range 0 up to |val| minus 1.
@h Printing.
These print data of various kinds:
(a) |primitive !print val -> void|. Print text.
(b) |primitive !printnumber val -> void|. Print a (signed) number in decimal.
(c) |primitive !printchar val -> void|. Print a character value, from the ZSCII character set.
(d) |primitive !printaddress val -> void|. Print a dictionary word.
(e) |primitive !printstring val -> void|. Print a packed string.
While these correspond to standard I6 library functions, they should probably
be removed from the set of primitives, but there are issues here to do with
the Inform 6 "veneer":
(a) |primitive !printnlnumber val -> void|. Print number but in natural language.
(b) |primitive !printname val -> void|. Print name of an object.
(c) |primitive !printdef val -> void|. Print name of an object, preceded by definite article.
(d) |primitive !printcdef val -> void|. Print name of an object, preceded by capitalised definite article.
(e) |primitive !printindef val -> void|. Print name of an object, preceded by indefinite article.
(f) |primitive !printcindef val -> void|. Print name of an object, preceded by capitalised indefinite article.
There are also primitive ways to change the visual style of text:
(a) |primitive !font val -> void|. Change to fixed-width font if value is 1, or regular if 0.
(b) |primitive !stylebold void -> void|. Change to bold type.
(c) |primitive !styleunderline void -> void|. Change to underlined type.
(d) |primitive !styleroman void -> void|. Change to roman (i.e., not bold, not underlined) type.
Lastly, a primitive for a rum feature of Inform 6 allowing for the display of
"box quotations" on screen:
(a) |primitive !box val -> void|.
@h Stack access.
The stack is not directly accessible anywhere in memory, so the only access
is via the following.
(a) |primitive !push val -> void|. Push value onto the stack.
(b) |primitive !pull ref -> void|. Pull value from the stack and write it into
the storage referred to. Values on the stack have unchecked kinds: it's up to
the author not to pull an inappropriate value.
@h Accessing storage.
Here the |ref| term is a refernce to a piece of storage: a property of an
instance, or a global variable, or an entry in memory, for example.
(a) |primitive !store ref val -> val|. Put the value in |ref|.
(b) |primitive !setbit ref val -> void|. Set bits in the mask |val| in |ref|.
(c) |primitive !clearbit ref val -> void|. Clear bits in the mask |val| in |ref|.
(d) |primitive !postincrement ref -> val|. Performs the equivalent of |ref++|.
(e) |primitive !preincrement ref -> val|. Performs the equivalent of |++ref|.
(f) |primitive !postdecrement ref -> val|. Performs the equivalent of |ref--|.
(g) |primitive !predecrement ref -> val|. Performs the equivalent of |--ref|.
Memory can be read with the following. The first value is the address of
the array; the second is an offset, that is, with 0 being the first entry,
1 the second, and so on. "Word" in this context means either an |int16| or
an |int32|, depending on what virtual machine are compiling to.
(a) |primitive !lookup val val -> val|. Find word at this word offset.
(b) |primitive !lookupbyte val val -> val|. Find byte at this byte offset.
Those however only read from array entries. To write to array entries, we
need to use |!store| or similar (see above); but to do that, we need a
reference for the memory cell. We do that with:
(a) |primitive !lookupref val val -> ref|.
(There is at present no equivalent for byte arrays.)
@h Indirect function calls.
Invocations of functions can only be made with |inv| when the function is
specified as a constant, and when its signature is therefore known. If
we need to call "whatever function this variable refers to", we have to
use one of the following. They differ only in their signatures. The
first value is the function address, and subsequent ones are arguments.
(a) |primitive !indirect0v val -> void|.
(b) |primitive !indirect1v val val -> void|.
(c) |primitive !indirect2v val val val -> void|.
(d) |primitive !indirect3v val val val val -> void|.
(e) |primitive !indirect4v val val val val val -> void|.
(f) |primitive !indirect5v val val val val val val -> void|.
(g) |primitive !indirect0 val -> val|.
(h) |primitive !indirect1 val val -> val|.
(i) |primitive !indirect2 val val val -> val|.
(j) |primitive !indirect3 val val val val -> val|.
(k) |primitive !indirect4 val val val val val -> val|.
(l) |primitive !indirect5 val val val val val val -> val|.
@h Control flow.
The simplest control statement is an "if". Note that a different primitive
is used if there is an "else" attached: it would be impossible to use the
same primitive for both because they couldn't have the same signature.
|!ifdebug| is an oddity: it executes the code only if the program is
being compiled in "debugging mode". (In Inform, that would mean that the
story file is being made inside the application, or else released in a
special testing configuration.) While the same effect could be achieved
using conditional compliation splats, this is much more efficient.
(a) |primitive !if val code -> void|.
(b) |primitive !ifelse val code code -> void|.
(c) |primitive !ifdebug code -> void|.
There are then several loops.
(a) |primitive !while val code -> void|. Similar to |while| in C.
(b) |primitive !for val val val code -> void|. Similar to |for| in C.
(c) |primitive !objectloopx ref val code -> void|. A loop over instances,
stored in the variable |ref|, of the kind of object |val|.
(d) |primitive !objectloop ref val val code -> void|. A more general form,
where the secomd |val| is a condition to be evaluated which decides whether
to execute the code for given |ref| value.
A switch statement takes a value, and then executes at most one of an
arbitrary number of possible code segments. This can't be implemented with
a single primitive, because its signature would have to be of varying
lengths with different uses (since some switches have many cases, some few).
Instead: a |switch| takes a single |code|, but that |code| can in turn
contain only invocations of |!case|, followed optionally by one of |!default|.
(a) |primitive !switch val code -> void|.
(b) |primitive !case val code -> void|.
(c) |primitive !default code -> void|.
This looks a little baroque, but it works in practice:
|inv !switch|
| val K_number X|
| code _ _|
| inv !case|
| val K_number 1|
| code _ _|
| inv !print|
| val K_text "One!"|
| inv !case|
| val K_number 2|
| code _ _|
| inv !print|
| val K_text "Two!"|
| inv !default|
| code _ _|
| inv !print|
| val K_text "Something else!"|
As in most C-like languages, there are primitives for:
(a) |primitive !break void -> void|. Exit the innermost switch case or loop.
(b) |primitive !continue void -> void|. Complete the current iteration of
the innermost loop.
Two ways to terminate what's happening:
(a) |primitive !return val -> void|. Finish the current function, giving the
supplied value as the result if the function is being executed in a value
context, and throwing it away if not.
(b) |primitive !quit void -> void|. Halt the whole program immediately.
And, lastly, the lowest-level way to travel:
(a) |primitive !jump lab -> void|. Jumo to this label in the current function.
@h Interactive fiction-only primitives.
The following would make no sense in a general-purpose program. Most mirror
very low-level I6 features, and Inform uses them mainly when converting
I6 code into inter: in almost all cases it's better to call routines in the
template rather than to use these. First, the spatial containment object tree:
(a) |primitive !move val val -> void|. Moves first to second (both are objects).
(b) |primitive !in val val -> val|. Tests if first is in second (both are objects).
(c) |primitive !notin val val -> val|. Negation of same.
Object class membership:
(a) |primitive !ofclass val val -> val|. Does the first belong to the enumerated
subkind whose weak type ID is the second value?
Attributes can be handled as follows. The values used to refer to these attributes
can be inter symbols for their properties, but only if those properties are
indeed stored as Z-machine or Glulx attributes at run-time.
(a) |primitive !give val val -> void|. Set the second (an attribute) for the first (an object).
(b) |primitive !take val val -> void|. Unset the second (an attribute) for the first (an object).
(c) |primitive !has val val -> val|. Test if the first (an object) has the second (an attibute).
(d) |primitive !hasnt val val -> val|. Negation of same.
Direct access to virtual machine object properties:
(a) |primitive !propertyvalue val val -> val|.
(b) |primitive !propertyaddress val val -> val|.
(c) |primitive !propertylength val val -> val|.
(d) |primitive !provides val val -> val|.