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:
parent
24709da69e
commit
eabf3cf3d3
|
@ -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>
|
||||
|
|
|
@ -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 -> void<code class="display"><span class="extract">
|
||||
</span></code> !primitive !pull ref -> val<code class="display"><span class="extract">
|
||||
</span></code> !primitive !if val code -> void<code class="display"><span class="extract">
|
||||
</span></code></p>
|
||||
<p class="inwebparagraph"></p>
|
||||
|
||||
|
||||
<pre class="display">
|
||||
<span class="plain">primitive !jump lab -> void</span>
|
||||
<span class="plain">primitive !pull ref -> val</span>
|
||||
<span class="plain">primitive !if val code -> 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
348
docs/inter/P-ip.html
Normal 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">★</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">§1. Status</a></li><li><a href="#SP2">§2. Arithmetic</a></li><li><a href="#SP3">§3. Logical operators</a></li><li><a href="#SP4">§4. Bitwise operators</a></li><li><a href="#SP5">§5. Numerical comparison</a></li><li><a href="#SP6">§6. Sequential evaluation</a></li><li><a href="#SP7">§7. Random numbers</a></li><li><a href="#SP8">§8. Printing</a></li><li><a href="#SP9">§9. Stack access</a></li><li><a href="#SP10">§10. Accessing storage</a></li><li><a href="#SP11">§11. Indirect function calls</a></li><li><a href="#SP12">§12. Control flow</a></li><li><a href="#SP13">§13. Interactive fiction-only primitives</a></li></ul><hr class="tocbar">
|
||||
|
||||
<p class="inwebparagraph"><a id="SP1"></a><b>§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>§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 -> val</span></code>. 16 or 32-bit integer addition.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !minus val val -> val</span></code>. 16 or 32-bit integer subtraction.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !unaryminus val -> 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 -> val</span></code>. 16 or 32-bit integer multiplication.
|
||||
</li><li>(e) <code class="display"><span class="extract">primitive !divide val val -> val</span></code>. 16 or 32-bit integer division.
|
||||
</li><li>(f) <code class="display"><span class="extract">primitive !modulo val val -> val</span></code>. Remainder after such a division.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP3"></a><b>§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 -> 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 -> 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 -> 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>§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 -> val</span></code>.
|
||||
</li><li>(a) <code class="display"><span class="extract">primitive !bitwiseor val val -> val</span></code>.
|
||||
</li><li>(a) <code class="display"><span class="extract">primitive !bitwisenot val -> val</span></code>.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP5"></a><b>§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 -> val</span></code>.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !ne val val -> val</span></code>.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !gt val val -> val</span></code>.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !ge val val -> val</span></code>.
|
||||
</li><li>(e) <code class="display"><span class="extract">primitive !lt val val -> val</span></code>.
|
||||
</li><li>(f) <code class="display"><span class="extract">primitive !le val val -> val</span></code>.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP6"></a><b>§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 -> 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 -> 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>§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 -> 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>§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 -> void</span></code>. Print text.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !printnumber val -> void</span></code>. Print a (signed) number in decimal.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !printchar val -> void</span></code>. Print a character value, from the ZSCII character set.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !printaddress val -> void</span></code>. Print a dictionary word.
|
||||
</li><li>(e) <code class="display"><span class="extract">primitive !printstring val -> 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 -> void</span></code>. Print number but in natural language.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !printname val -> void</span></code>. Print name of an object.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !printdef val -> void</span></code>. Print name of an object, preceded by definite article.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !printcdef val -> 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 -> void</span></code>. Print name of an object, preceded by indefinite article.
|
||||
</li><li>(f) <code class="display"><span class="extract">primitive !printcindef val -> 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 -> 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 -> void</span></code>. Change to bold type.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !styleunderline void -> void</span></code>. Change to underlined type.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !styleroman void -> 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 -> void</span></code>.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP9"></a><b>§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 -> void</span></code>. Push value onto the stack.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !pull ref -> 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>§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 -> 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 -> 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 -> 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 -> 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 -> 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 -> 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 -> 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 -> val</span></code>. Find word at this word offset.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !lookupbyte val val -> 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 -> 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>§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 -> void</span></code>.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !indirect1v val val -> void</span></code>.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !indirect2v val val val -> void</span></code>.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !indirect3v val val val val -> void</span></code>.
|
||||
</li><li>(e) <code class="display"><span class="extract">primitive !indirect4v val val val val val -> void</span></code>.
|
||||
</li><li>(f) <code class="display"><span class="extract">primitive !indirect5v val val val val val val -> void</span></code>.
|
||||
</li><li>(g) <code class="display"><span class="extract">primitive !indirect0 val -> val</span></code>.
|
||||
</li><li>(h) <code class="display"><span class="extract">primitive !indirect1 val val -> val</span></code>.
|
||||
</li><li>(i) <code class="display"><span class="extract">primitive !indirect2 val val val -> val</span></code>.
|
||||
</li><li>(j) <code class="display"><span class="extract">primitive !indirect3 val val val val -> val</span></code>.
|
||||
</li><li>(k) <code class="display"><span class="extract">primitive !indirect4 val val val val val -> val</span></code>.
|
||||
</li><li>(l) <code class="display"><span class="extract">primitive !indirect5 val val val val val val -> val</span></code>.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP12"></a><b>§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 -> void</span></code>.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !ifelse val code code -> void</span></code>.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !ifdebug code -> 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 -> 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 -> 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 -> 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 -> 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 -> void</span></code>.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !case val code -> void</span></code>.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !default code -> 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 -> void</span></code>. Exit the innermost switch case or loop.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !continue void -> 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 -> 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 -> 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 -> void</span></code>. Jumo to this label in the current function.
|
||||
</li></ul>
|
||||
<p class="inwebparagraph"><a id="SP13"></a><b>§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 -> void</span></code>. Moves first to second (both are objects).
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !in val val -> 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 -> 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 -> 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 -> 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 -> 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 -> 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 -> 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 -> val</span></code>.
|
||||
</li><li>(b) <code class="display"><span class="extract">primitive !propertyaddress val val -> val</span></code>.
|
||||
</li><li>(c) <code class="display"><span class="extract">primitive !propertylength val val -> val</span></code>.
|
||||
</li><li>(d) <code class="display"><span class="extract">primitive !provides val val -> 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
258
inter/Preliminaries/Inform Primitives.w
Normal file
258
inter/Preliminaries/Inform Primitives.w
Normal 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|.
|
Loading…
Reference in a new issue