I6 Template Layer

Inform 7 6M62ContentsIntroductionFunction IndexRules Index

Tests.i6t

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; ! TARGET_GLULX 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; ! allow multiple objects 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;