Tests contents
Abstract Command.
The code below is compiled only if the symbol DEBUG is defined, which it always is for normal runs in the Inform user interface, but not for Release runs.
Not all of these commands are documented; this is intentional. They may be changed in name or function. This is all of the testing commands except for the GLKLIST command, which is in Glulx.i6t (and does not exist when the target VM is the Z-machine).
We take the commands in alphabetical order, beginning with ABSTRACT, which moves an object to a new position in the object tree.
22[ XAbstractSub;
23 if (XTestMove(noun, second)) return;
24 move noun to second;
25 "[Abstracted.]";
26];
27
28[ XTestMove obj dest;
29 if (obj <= InformLibrary) "[Cant move ", (name) obj, ": its a system object.]";
30 if (obj.component_parent) "[Cant move ", (name) obj, ": its part of ",
31 (the) obj.component_parent, ".]";
32 while (dest) {
33 if (dest == obj) "[Cant move ", (name) obj, ": it would contain itself.]";
34 dest = CoreOfParentOfCoreOf(dest);
35 }
36 rfalse;
37];
Actions Command.
ACTIONS turns tracing of actions on.
43[ ActionsOnSub; trace_actions = 1; say__p = 1; "Actions listing on."; ];
44[ ActionsOffSub; trace_actions = 0; say__p = 1; "Actions listing off."; ];
Gonear Command.
GONEAR teleports the player to the vicinity of some named item.
50[ GonearSub;
51 PlayerTo(LocationOf(noun));
52];
Purloin Command.
To PURLOIN is to acquire something without reference to any rules on accessibility.
58[ XPurloinSub;
59 if (XTestMove(noun, player)) return;
60 move noun to player; give noun moved ~concealed;
61 say__p = 1;
62 "[Purloined.]";
63];
Random Command.
RANDOM forces the random-number generator to a predictable seed value.
69[ PredictableSub;
70 VM_Seed_RNG(-100);
71 say__p = 1;
72 "[Random number generator now predictable.]";
73];
Relations Command.
RELATIONS lists the current state of the mutable relations.
79[ ShowRelationsSub;
80 IterateRelations(ShowOneRelation);
81];
82
83[ ShowOneRelation rel;
84 if ((RlnGetF(rel, RR_PERMISSIONS)) & (RELS_SHOW)) {
85 (RlnGetF(rel, RR_HANDLER))(rel, RELS_SHOW);
86 }
87];
Responses Command.
RESPONSES lists the known responses.
93Global suppress_text_substitution = false;
94[ ShowResponsesSub a i j reg wd set_mode;
95 if (NO_RESPONSES == 0) "There are no lettered responses.";
96 wn = 2;
97 if (NextWordStopped() == 'now') set_mode = 1; else wn--;
98 if (NextWordStopped() == 'set') set_mode = 2; else wn--;
99 wd = NextWordStopped(); wn--;
100 if (wd == 'all') reg = 0;
101 else {
102 reg = -1;
103 if (wd ~= -1) reg = TryNumber(wn);
104 if (reg < 0) {
105 say__p = 1;
106 print ">--> The following sets of responses are available:^";
107 print " RESPONSES ALL^";
108 }
109 }
110 for (a=0, i=1, j=0: ResponseDivisions-->a: a=a+3, i++) {
111 if (ResponseDivisions-->a ~= EMPTY_TEXT_PACKED) j++;
112 if ((reg == 0) || (reg == j)) {
113 if (ResponseDivisions-->a ~= EMPTY_TEXT_PACKED) {
114 if (set_mode) {
115 print "[", (string) ResponseDivisions-->a, "]^";
116 } else {
117 print (string) ResponseDivisions-->a, ":^";
118 }
119 }
120 ShowResponsesRange(ResponseDivisions-->(a+1), ResponseDivisions-->(a+2), set_mode);
121 }
122 if (reg < 0) {
123 if (ResponseDivisions-->a ~= EMPTY_TEXT_PACKED) {
124 print " RESPONSES ", j, ": ", (string) ResponseDivisions-->a, "^";
125 }
126 }
127 }
128];
129
130[ ShowResponsesRange from to set_mode i;
131 say__p = 1;
132 for (i=from: i<=to: i++) {
133 switch (set_mode) {
134 1: print "now ";
135 2: ;
136 0: print " ";
137 }
138 print (PrintResponse) i;
139 switch (set_mode) {
140 1: print " is ";
141 2: print " is ";
142 0: print ": ";
143 }
144 suppress_text_substitution = true;
145 CarryOutActivity(PRINTING_RESPONSE_ACT, i);
146 suppress_text_substitution = false;
147 switch (set_mode) {
148 1: print ";";
149 2: print ".";
150 }
151 print "^";
152 }
153];
Rules Command.
RULES changes the level of rule tracing.
159[ RulesOnSub;
160 debug_rules = 1; say__p = 1;
161 "Rules tracing now switched on. Type ~rules off~ to switch it off again,
162 or ~rules all~ to include even rules which do not apply.";
163];
164[ RulesAllSub;
165 debug_rules = 2; say__p = 1;
166 "Rules tracing now switched to ~all~. Type ~rules off~ to switch it off again.";
167];
168[ RulesOffSub;
169 debug_rules = 0; say__p = 1;
170 "Rules tracing now switched off. Type ~rules~ to switch it on again.";
171];
Scenes Command.
SCENES switches scene-change tracing on or off, and also shows the current position.
177[ ScenesOnSub;
178 debug_scenes = 1;
179 ShowSceneStatus(); say__p = 1;
180 "(Scene monitoring now switched on. Type ~scenes off~ to switch it off again.)";
181];
182[ ScenesOffSub;
183 debug_scenes = 0; say__p = 1;
184 "(Scene monitoring now switched off. Type ~scenes~ to switch it on again.)";
185];
Scope Command.
SCOPE prints a numbered list of all objects in scope to the player.
191Global x_scope_count;
192[ ScopeSub;
193 x_scope_count = 0;
194 LoopOverScope(Print_ScL, noun);
195 if (x_scope_count == 0) "Nothing is in scope.";
196];
197[ Print_ScL obj; print_ret ++x_scope_count, ": ", (a) obj, " (", obj, ")"; ];
Showheap Command.
SHOWHEAP is for debugging the memory heap, and is intended for Inform maintainers rather than users.
204[ ShowHeapSub;
205 HeapDebug();
206];
ShowMe Command.
SHOWME is probably the most useful testing command: it shows the state of the current room, or a named item.
213[ ShowMeSub t_0 na;
214 t_0 = noun;
215 if (noun == nothing) noun = real_location;
216 if (ShowMeRecursively(noun, 0, (noun == real_location))) {
217 if (noun == real_location)
218 print "* denotes things which are not in scope^";
219 }
220 if (t_0 ofclass K2_thing) {
221 print "location:"; ShowRLocation(noun, true); print "^";
222 }
223 {-call:PL::Showme::compile_SHOWME_details}
224];
225
226[ ShowRLocation obj top;
227 if (obj ofclass K1_room) return;
228 print " ";
229 if (parent(obj)) {
230 if (obj has worn) print "worn by ";
231 else {
232 if (parent(obj) has animate) print "carried by ";
233 if (parent(obj) has container) print "in ";
234 if (parent(obj) ofclass K1_room) print "in ";
235 if (parent(obj) has supporter) print "on ";
236 }
237 print (the) parent(obj);
238 ShowRLocation(parent(obj));
239 } else {
240 if (obj.component_parent) {
241 if (top == false) print ", which is ";
242 print "part of ", (the) obj.component_parent;
243 ShowRLocation(obj.component_parent);
244 }
245 else print "out of play";
246 }
247];
248
249[ ShowMeRecursively obj depth f c i k;
250 spaces(2*depth);
251 if (f && (depth > 0) && (TestScope(obj, player) == false)) { print "*"; c = true; }
252 print (name) obj;
253 if (depth > 0) {
254 if (obj.component_parent) print " (part of ", (name) obj.component_parent, ")";
255 if (obj has worn) print " (worn)";
256 }
257 if (obj provides KD_Count) {
258 k = KindHierarchy-->((obj.KD_Count)*2);
259 if ((k ~= K2_thing) || (depth==0)) {
260 print " - ";
261 if (k == K4_door or K5_container) {
262 if (obj has transparent) print "transparent ";
263 if (obj has locked) print "locked ";
264 else if (obj has open) print "open ";
265 else print "closed ";
266 }
267 print (I7_Kind_Name) k;
268 }
269 }
270 print "^";
271 if (obj.component_child) c = c | ShowMeRecursively(obj.component_child, depth+2, f);
272 if ((depth>0) && (obj.component_sibling))
273 c = c | ShowMeRecursively(obj.component_sibling, depth, f);
274 if (child(obj)) c = c | ShowMeRecursively(child(obj), depth+2, f);
275 if ((depth>0) && (sibling(obj))) c = c | ShowMeRecursively(sibling(obj), depth, f);
276 return c;
277];
278
279[ AllowInShowme pr;
280 if (pr == workflag or concealed or mentioned) rfalse;
281 rtrue;
282];
Showverb Command.
SHOWVERB is a holdover from old I6 days, but still quite useful. It writes out the I6 command verb grammar for the supplied command.
289[ ShowVerbSub address lines meta i x;
290 wn = 2; x = NextWordStopped();
291 if (x == 0 || ((x->#dict_par1) & 1) == 0)
292 "Try typing ~showverb~ and then the name of a verb.";
293 meta = ((x->#dict_par1) & 2)/2;
294 i = DictionaryWordToVerbNum(x);
295 address = VM_CommandTableAddress(i);
296 lines = address->0;
297 address++;
298 print "Verb ";
299 if (meta) print "meta ";
300 VM_PrintCommandWords(i);
301 new_line;
302 if (lines == 0) print "has no grammar lines.^";
303 for (: lines>0 : lines--) {
304 address = UnpackGrammarLine(address);
305 print " "; DebugGrammarLine(); new_line;
306 }
307 ParaContent();
308];
309
310[ DebugGrammarLine pcount;
311 print " * ";
312 for (: line_token-->pcount ~= ENDIT_TOKEN : pcount++) {
313 if ((line_token-->pcount)->0 & $10) print "/ ";
314 print (DebugToken) line_token-->pcount, " ";
315 }
316 print "-> ", (DebugAction) action_to_be;
317 if (action_reversed) print " reverse";
318];
319
320[ DebugToken token;
321 AnalyseToken(token);
322 switch (found_ttype) {
323 ILLEGAL_TT:
324 print "<illegal token number ", token, ">";
325 ELEMENTARY_TT:
326 switch (found_tdata) {
327 NOUN_TOKEN: print "noun";
328 HELD_TOKEN: print "held";
329 MULTI_TOKEN: print "multi";
330 MULTIHELD_TOKEN: print "multiheld";
331 MULTIEXCEPT_TOKEN: print "multiexcept";
332 MULTIINSIDE_TOKEN: print "multiinside";
333 CREATURE_TOKEN: print "creature";
334 SPECIAL_TOKEN: print "special";
335 NUMBER_TOKEN: print "number";
336 TOPIC_TOKEN: print "topic";
337 ENDIT_TOKEN: print "END";
338 }
339 PREPOSITION_TT:
340 print "", (address) found_tdata, "";
341 ROUTINE_FILTER_TT:
342 print "noun=Routine(", found_tdata, ")";
343 ATTR_FILTER_TT:
344 print (DebugAttribute) found_tdata;
345 SCOPE_TT:
346 print "scope=Routine(", found_tdata, ")";
347 GPR_TT:
348 print "Routine(", found_tdata, ")";
349 }
350];
Test Command.
TEST runs a short script of commands from the source text.
356#Iftrue ({-value:NUMBER_CREATED(test_scenario)} > 0);
357
358[ TestScriptSub;
359 switch(special_word) {
360{-call:PL::Parsing::TestScripts::compile_switch}
361 default:
362 print ">--> The following tests are available:^";
363{-call:PL::Parsing::TestScripts::compile_printout}
364 }
365];
366
367#ifdef TARGET_GLULX;
368Constant TEST_STACK_SIZE = 128;
369#ifnot;
370Constant TEST_STACK_SIZE = 48;
371#endif;
372
373Array test_stack --> TEST_STACK_SIZE;
374Global test_sp = 0;
375[ TestStart T R l k;
376 if (test_sp >= TEST_STACK_SIZE) ">--> Testing too many levels deep";
377 test_stack-->test_sp = T;
378 test_stack-->(test_sp+1) = 0;
379 test_stack-->(test_sp+3) = l;
380 test_sp = test_sp + 4;
381 if ((R-->0) && (R-->0 ~= real_location)) {
382 print "(first moving to ", (name) R-->0, ")^";
383 PlayerTo(R-->0, 1);
384 }
385 k=1;
386 while (R-->k) {
387 if (R-->k notin player) {
388 print "(first acquiring ", (the) R-->k, ")^";
389 move R-->k to player;
390 }
391 k++;
392 }
393 print "(Testing.)^"; say__p = 1;
394];
395[ TestKeyboardPrimitive a_buffer a_table p i j l spaced ch;
396 if (test_sp == 0) {
397 test_stack-->2 = 1;
398 return VM_ReadKeyboard(a_buffer, a_table);
399 }
400 else {
401 p = test_stack-->(test_sp-4);
402 i = test_stack-->(test_sp-3);
403 l = test_stack-->(test_sp-1);
404 print "[";
405 print test_stack-->2;
406 print "] ";
407 test_stack-->2 = test_stack-->2 + 1;
408 style bold;
409 while ((i < l) && (p->i ~= '/')) {
410 ch = p->i;
411 if (spaced || (ch ~= ' ')) {
412 if ((p->i == '[') && (p->(i+1) == '/') && (p->(i+2) == ']')) {
413 ch = '/'; i = i+2;
414 }
415 a_buffer->(j+WORDSIZE) = ch;
416 print (char) ch;
417 i++; j++;
418 spaced = true;
419 } else i++;
420 }
421 style roman;
422 print "^";
423 #ifdef TARGET_ZCODE;
424 a_buffer->1 = j;
425 #ifnot;
426 a_buffer-->0 = j;
427 #endif;
428 VM_Tokenise(a_buffer, a_table);
429 if (p->i == '/') i++;
430 if (i >= l) {
431 test_sp = test_sp - 4;
432 } else test_stack-->(test_sp-3) = i;
433 }
434];
435
436#IFNOT;
437
438[ TestScriptSub;
439 ">--> No test scripts exist for this game.";
440];
441
442#ENDIF;
Trace Command.
Another holdover from I6: TRACE sets the level of parser tracing, on a scale of 0 (off, the default) to 5.
449[ TraceOnSub; parser_trace=1; say__p = 1; "[Trace on.]"; ];
450
451[ TraceLevelSub;
452 parser_trace = parsed_number; say__p = 1;
453 print "[Parser tracing set to level ", parser_trace, ".]^";
454];
455
456[ TraceOffSub; parser_trace=0; say__p = 1; "Trace off."; ];
Tree Command.
TREE prints out the I6 object tree, though this is not always very helpful in I7 terms. It should arguably be withdrawn, but doesn't seem to do any harm.
463[ XTreeSub i;
464 if (noun == 0) {
465 objectloop (i)
466 if (i ofclass Object && parent(i) == 0) XObj(i);
467 }
468 else XObj(noun,1);
469];
470
471[ XObj obj f;
472 if (parent(obj) == 0) print (name) obj; else print (a) obj;
473 print " (", obj, ") ";
474 if (f == 1 && parent(obj) ~= 0)
475 print "(in ", (name) parent(obj), " ", parent(obj), ")";
476 new_line;
477 if (child(obj) == 0) rtrue;
478 if (obj == Class)
479 WriteListFrom(child(obj), NEWLINE_BIT+INDENT_BIT+ALWAYS_BIT+NOARTICLE_BIT, 1);
480 else
481 WriteListFrom(child(obj), NEWLINE_BIT+INDENT_BIT+ALWAYS_BIT+FULLINV_BIT, 1);
482];
Grammar.
In the old I6 parser, testing commands had their own scope hardwired in to the code: this worked by comparing the verb command word directly against 'scope' and the like. That would go wrong if the testing commands were translated into other languages, and was a crude design at best. The following scope token is better: using this token instead of multi provides a noun with universal scope (but restricted to I7 objects, so I6 pseudo-objects like compass are not picked up) and able to accept multiple objects.
494[ testcommandnoun obj o2;
495 switch (scope_stage) {
496 1: rtrue;
497 2: objectloop (obj)
498 if ((obj ofclass Object) && (obj provides KD_Count))
499 PlaceInScope(obj, true);
500 3: print "There seems to be no such object anywhere in the model world.^";
501 }
502];
503
504{-testing-command:abstract}
505 * scope=testcommandnoun 'to' scope=testcommandnoun -> XAbstract;
506{-testing-command:actions}
507 * -> ActionsOn
508 * 'on' -> ActionsOn
509 * 'off' -> ActionsOff;
510{-testing-command:gonear}
511 * scope=testcommandnoun -> Gonear;
512{-testing-command:purloin}
513 * scope=testcommandnoun -> XPurloin;
514{-testing-command:random}
515 * -> Predictable;
516{-testing-command:relations}
517 * -> ShowRelations;
518{-testing-command:responses}
519 * -> ShowResponses
520 * special -> ShowResponses
521 * 'now' special -> ShowResponses
522 * 'set' special -> ShowResponses;
523{-testing-command:rules}
524 * -> RulesOn
525 * 'all' -> RulesAll
526 * 'on' -> RulesOn
527 * 'off' -> RulesOff;
528{-testing-command:scenes}
529 * -> ScenesOn
530 * 'on' -> ScenesOn
531 * 'off' -> ScenesOff;
532{-testing-command:scope}
533 * -> Scope
534 * scope=testcommandnoun -> Scope;
535{-testing-command:showheap}
536 * -> ShowHeap;
537{-testing-command:showme}
538 * -> ShowMe
539 * scope=testcommandnoun -> ShowMe;
540{-testing-command:showverb}
541 * special -> Showverb;
542{-testing-command:test}
543 * -> TestScript
544 * special -> TestScript;
545{-testing-command:trace}
546 * -> TraceOn
547 * number -> TraceLevel
548 * 'on' -> TraceOn
549 * 'off' -> TraceOff;
550{-testing-command:tree}
551 * -> XTree
552 * scope=testcommandnoun -> XTree;