RTP To issue run-time problem messages, and to perform some run-time type checking which may issue such messages.
§1. Reporting. All RTPs are produced by calling IssueRTP. This does not necessarily issue
the problem right away, since reporting of these can be temporarily suspended,
and we also want to avoid long cascades of repeated RTPs.
The only compulsory argument is name, which is used by the Inform GUI apps
to notice that RTPs have been issued and to display an appropriate page of
explanatory documentation. The apps notice RTPs by looking for a particular
pattern of text, so do not reformat RTPs without coordinating with the apps.
It is usual also to give desc and set. desc is a description, which
can either be a string or a function which takes the three parameters and
prints out a line of description instead. set should be a constant identifying
which kit of code issued the RTP: for example, BasicInformKitRTPs. If an RTP
does not belong to the right set, the GUI apps won't be able to display
helpful pages about it.
The arguments par1, par2 and par3 are optional parameters which are
passed to the desc function, if there is one.
Array LatestRTPData --> (-1) ! -->0 = Name of current RTP, or -1 for none, or -2 for issued already 0 ! -->1 = par1 value 0 ! -->2 = par2 value 0 ! -->3 = par3 value 0 ! -->4 = description string or function 0 ! -->5 = set value false; ! -->6 = suspension flag (true if suspended, false if not) [ IssueRTP name desc set par1 par2 par3; if ((name ofclass String) && ((desc ofclass String) || (desc ofclass Routine) || (desc == -1)) && (set ofclass String)) { if (LatestRTPData-->0 == -1) { LatestRTPData-->0 = name; LatestRTPData-->1 = par1; LatestRTPData-->2 = par2; LatestRTPData-->3 = par3; LatestRTPData-->4 = desc; LatestRTPData-->5 = set; } ShowRTP(); } else { "*** Improper call to IssueRTP ***"; } ]; [ ClearRTP; LatestRTPData-->0 = -1; LatestRTPData-->6 = false; ]; [ SuspendRTP; LatestRTPData-->6 = true; ]; [ ResumeRTP; LatestRTPData-->6 = false; ]; [ ShowRTP name par1 par2 par3 desc suspended; if (LatestRTPData-->0 == -1 or -2) return; if (LatestRTPData-->6) return; name = LatestRTPData-->0; par1 = LatestRTPData-->1; par2 = LatestRTPData-->2; par3 = LatestRTPData-->3; LatestRTPData-->0 = -2; #Ifdef TARGET_GLULX; suspended = SuspendTextInput(Main_Window); #Endif; print "^*** Run-time problem ", (string) name; #ifdef DEBUG; if (LatestRTPData-->5) { print ": ", (string) LatestRTPData-->5; } #endif; print "^"; desc = LatestRTPData-->4; if (desc ~= -1) { print "*** "; if (desc ofclass String) print (string) desc, "^"; else if (desc ofclass Routine) desc(par1, par2, par3); } #Ifdef TARGET_GLULX; if (suspended) { ResumeTextInput(Main_Window); } #Endif; ];
§2. The VeneerError RTP. The following function, confusingly called RunTimeError and not to be
confused with IssueRTP above, is a residue from the old I6 library. Most of
its possible messages can't be seen in I7 use -- for instance I7 has no timers
or daemons, so error 4 is out of the question. We retain it only because the
veneer code added by I6 requires it to be present.
Constant MAX_TIMERS = 0; [ RunTimeError n p1 p2; IssueRTP("VeneerError", "Low level error.", BasicInformKitRTPs); print "*** Veneer error ", n, " (", p1, ",", p2, ")^"; #Ifdef DEBUG; print "*** "; switch (n) { 1: print "preposition not found (this should not occur)"; 2: print "Property value not routine or string: ~", (property) p2, "~ of ~", (name) p1, "~ (", p1, ")"; 3: print "Entry in property list not routine or string: ~", (property) p2, "~ list of ~", (name) p1, "~ (", p1, ")"; 4: print "Too many timers/daemons are active simultaneously. The limit is the library constant MAX_TIMERS (currently ", MAX_TIMERS, ") and should be increased"; 5: print "Object ~", (name) p1, "~ has no ~time_left~ property"; 7: print "The object ~", (name) p1, "~ can only be used as a player object if it has the ~number~ property"; 8: print "Attempt to take random entry from an empty table array"; 9: print p1, " is not a valid direction property number"; 10: print "The player-object is outside the object tree"; 11: print "The room ~", (name) p1, "~ has no ~description~ property"; 12: print "Tried to set a non-existent pronoun using SetPronoun"; 13: print "A 'topic' token can only be followed by a preposition"; default: print "(unexplained)"; } print "^"; #Endif; ! DEBUG ];
§3. RTPs issued by the compiler. Or properly speaking, by code generated by the Inform 7 compiler, usually in
response to runtime type-checking having failed. Rather than calling IssueRTP
directly, it calls one of the following.
[ IssueTypecheckingRTP line file; IssueRTP("PhraseAppliedToIncompatibleValue", "Phrase applied to an incompatible kind of value.", BasicInformKitRTPs); rtrue; ]; [ IssueIterationRTP what; IssueRTP("RepeatedThroughUnenumerableKind", "Could not iterate through values of this kind.", BasicInformKitRTPs); print "*** This arose from a description which started out here - ~", (string) what, "~.^"; rtrue; ]; [ IssueSetVariableRTP val setting kind; IssueRTP("SetVariableToWrongKindOfObject", "Tried to set a variable to the wrong kind of object.", BasicInformKitRTPs); print "*** You wrote '", (string) setting, "', which sets the value to ", (the) val, " - but that doesn't have the kind '", (string) kind, "'.^"; rtrue; ]; [ IssueChangedRelationRTP X Y rel; IssueRTP("ChangedRelationOutsideDomain", "Tried to change a relation for objects with the wrong kinds.", BasicInformKitRTPs); print "*** The relation was set up as ~", (string) RlnGetF(rel, RR_DESCRIPTION), "~, but you tried to ", "relate (or unrelate) ", (the) X, " to ", (the) Y, ".^"; rtrue; ]; [ IssueAbstractRelationRTP task rel; IssueRTP("UsedAbstractRelation", "Tried to make use of an abstract relation.", BasicInformKitRTPs); rtrue; ];
§4. Return Type Checking Failed. Similarly, though in a more restricted set of circumstances. Inform can usually
prove that the value returned by a phrase matches its supposed kind, but
because of the deliberately weak type-checking within the kind of value
"object" it will allow a broader kind of object to be returned when the
requirement is for a narrower one. In such cases, it checks the result with
the following routine. The value V is a valid "object", but that means
it can be nothing, and we must check that it matches a given I7 kind K
(where nothing is not valid).
[ CheckKindReturned V K; if (V ofclass K) return V; if (V == nothing) IssueRTP("DecidedOnNothing", "Attempt to 'decide on nothing'.", BasicInformKitRTPs); else IssueRTP("DecidedOnWrongKindOfObject", "Attempt to 'decide on V' where V is the wrong kind of object.", BasicInformKitRTPs); return V; ];