For information on changes to the library (adv3), refer to the Recent Library Changes list.
A compiler bug introduced in 3.0.17 caused Workbench (and the stand-alone interpreter) to crash when loading certain games when compiled for debugging. The compiler was mis-calculating some internal data structure sizes, which effectively corrupted the .t3 file; this happened when the byte code for a function plus its debug symbols was over a certain threshold size. This has been corrected.
The compiler has a new feature called "multi-methods." This implements a relatively new object-oriented programming technique known as multiple dispatch, in which the types of multiple arguments can be used to determine which of several possible functions to call. The traditional TADS method call uses a single-dispatch system: when you write "x.foo(3)", you're invoking the method foo as defined on the object x, or as inherited from the nearest superclass of x that defines that method. This is known as single dispatch because a single value (x) controls the selection of which definition of foo will be invoked. With multiple dispatch, this notion is extended so that multiple values can be considered when selecting which method to invoke. For example, you could write one version of a function "putIn()" that operates on a Thing and a Container, and another version of the same function that operates on a Liquid and a Vessel, and the system will automatically choose the correct version at run-time based on the types of both arguments. This new system is described more fully in the System Manual.
The compiler can now generate information in each object about the source file where the object was defined. This new information is stored in a new property, sourceTextGroup; this supplements the existing sourceTextOrder property. Since the new information takes up extra space in the compiled file, it's not generated by default. To generate it, include the new compiler option "-Gstg" in your makefile or command line, or place the directive #pragma sourceTextGroup(on) directive in each source module where you wish to generate the information. The #pragma lets you selectively generate the information in specific source files, or even in specific portions of specific source files: the corresponding directive #pragma sourceTextGroup(off) lets you turn off the information in a section where you don't need it.
When you turn on sourceTextGroup generation, the compiler automatically adds a sourceTextGroup property to each object, just as it automatically adds a sourceTextOrder value. The sourceTextGroup value is a reference to an anonymous object that the compiler automatically creates. One such object is generated per source module for which sourceTextGroup generation is activated. This object contains two properties: sourceTextGroupName is a string giving the name of the module, as it appeared in the compiler command line, makefile (.t3m), or library (.tl) file; sourceTextGroupOrder is an integer giving the relative order of the module among the list of modules comprising the overall program.
sourceTextGroup is useful in cases where you want to establish the order of appearance in source files among objects in multiple modules. For a given object x, x.sourceTextGroup.sourceTextGroupOrder gives you the relative order within the overall build of the module where x was defined, and x.sourceTextOrder gives you the relative order of x among the objects defined within that module. Between the two values, you can establish a linear ordering for all of the statically defined objects in the entire program.
The compiler now stores "links" to resource files in the .t3 file when compiling in Debug mode. This makes it easier to test a game that uses multimedia resources, by making the Build environment match the Release environment more precisely.
In the past, when building in Debug mode, the compiler completely ignored multimedia resource files listed in the "-res" section of the command line or makefile. This was by design; the reasoning was that when you're compiling in Debug mode, you'll only be running that copy on your development machine, within your build environment, where all of the resource files are available as local files; and since the files are all available as separate local files anyway, we can make the compilation go faster by skipping the step where we copy those files into the .t3 file.
This worked fine most of the time, but it didn't work in the occasional case where the resource name is different from the corresponding local file's name in the file system. One example is the Cover Art file, which is always stored in the game under the resource name ".system/CoverArt.jpg", which is usually not the same name the file has locally. This meant that if you tried to refer to such a resource via HTML (such as with an <IMG> tag), the resource was reported as missing when running the debug build.
The new arrangement fixes this problem without giving up the time savings. With the new scheme, the compiler stores a link for each resource in the .t3 file: this simply records the mapping from resource name to local file name. The HTML renderer can then look up the appropriate local file for each resource, including any resources that have special names. As before, the actual contents of the resources are not copied.
Note that none of this affects Release builds. The compiler has always copied the full contents of all resources into the .t3 file when doing a Release build, and continues to do so. Release builds continue to be fully self-contained, so that you only have to distribute the .t3 file to players, not the individual graphics and sound files it refers to.
The compiler's status output didn't add a line break after each resource files being added to the project, resulting in poorly formatted displays. This has been corrected.
This is the TADS 3.0 General Release version.
x: object m(p) { } n = (p) // bad code generated here p = nil ;
The bad code resulted from the compiler mistakenly using the local symbol table from the method m(p) while generating the code for n; so the compiler incorrectly treated p as a parameter variable in n, even though n has no parameters. This has been corrected.
The local-to-Unicode character set mapper now converts any unmappable character found in a source string to Unicode U+FFFD, the standard Unicode "replacement character." In the past, the mapper converted unmappable characters to question marks, "?". Converting to question marks was undesirable because of the ambiguity it created. When compiling source code, for example, it led the compiler to think that the source file literally contained a question mark where the unmappable character was found; the diagnostics the compiler reported in these cases were thus confusing and misleading. Unicode defines the character U+FFFD specifically for the purpose of replacing source characters that cannot be mapped to Unicode; this gives the compiler and other consumers of mapped characters an unambiguous indication that the original input character was unmappable. The compiler uses this new information to report a specific diagnostic message when it finds a U+FFFD in the input stream.
There are no changes to the compiler or interpreter core in this release. The only changes in the adv3 library and the Windows HTML TADS interpreter.
There are no changes to the compiler or interpreter core in this release. The only changes are in the adv3 library and the Windows HTML TADS interpreter.
testObj: object prop1 = [ {: say(prop2) } ] prop2 = 'hello!' ;
Note: 3.0.6l was a library-only release, so there was no system release called 3.0.6l.
export propNotDefined; class A: object propNotDefined(prop, [args]) { "This is A.propNotDefined\n"; } ; class B: A propNotDefined(prop, [args]) { "This is B.propNotDefined\n"; } p1() { inherited(); } ; main(args) { local x = new B(); x.p1(); }
When this program is run, the result displayed will be "This is A.propNotDefined". B.p1() attempts to inherit the base class definition of p1(); when it doesn't find an inherited definition, it searches for propNotDefined() using the same search pattern it used to find the inherited p1(). That is, the search starts with B's superclass, because that's where the search for the inherited p1() started from.
Old Name | New Name |
---|---|
BIGNUM_SIGN | BignumSign |
BIGNUM_EXP | BignumExp |
BIGNUM_EXP_SIGN | BignumExpSign |
BIGNUM_LEADING_ZERO | BignumLeadingZero |
BIGNUM_POINT | BignumPoint |
BIGNUM_COMMAS | BignumCommas |
BIGNUM_POS_SPACE | BignumPosSpace |
BIGNUM_EUROSTYLE | BignumEuroStyle |
TYPE_NIL | TypeNil |
TYPE_TRUE | TypeTrue |
TYPE_OBJECT | TypeObject |
TYPE_PROP | TypeProp |
TYPE_INT | TypeInt |
TYPE_SSTRING | TypeSString |
TYPE_DSTRING | TypeDString |
TYPE_LIST | TypeList |
TYPE_CODE | TypeCode |
TYPE_FUNCPTR | TypeFuncPtr |
TYPE_NATIVE_CODE | TypeNativeCode |
TYPE_ENUM | TypeEnum |
PROPDEF_ANY | PropDefAny |
PROPDEF_DIRECTLY | PropDefDirectly |
PROPDEF_INHERITS | PropDefInherits |
PROPDEF_GET_CLASS | PropDefGetClass |
STR_HTML_KEEP_SPACES | HtmlifyKeepSpaces |
STR_HTML_KEEP_NEWLINES | HtmlifyKeepNewlines |
STR_HTML_KEEP_TABS | HtmlifyKeepTabs |
STR_HTML_KEEP_WHITESPACE | HtmlifyKeepWhitespace |
T3DBG_CHECK | T3DebugCheck |
T3DBG_BREAK | T3DebugBreak |
OBJ_INSTANCES | ObjInstances |
OBJ_CLASSES | ObjClasses |
OBJ_ALL | ObjAll |
REPLACE_ONCE | ReplaceOnce |
REPLACE_ALL | ReplaceAll |
GETTIME_DATE_AND_TIME | GetTimeDateAndTime |
GETTIME_TICKS | GetTimeTicks |
INEVT_KEY | InEvtKey |
INEVT_TIMEOUT | InEvtTimeout |
INEVT_HREF | InEvtHref |
INEVT_NOTIMEOUT | InEvtNotimeout |
INEVT_EOF | InEvtEof |
INEVT_LINE | InEvtLine |
INEVT_END_QUIET_SCRIPT | InEvtEndQuietScript |
INDLG_OK | InDlgOk |
INDLG_OKCANCEL | InDlgOkcancel |
INDLG_YESNO | InDlgYesNo |
INDLG_YESNOCANCEL | InDlgYesNoCancel |
INDLG_ICON_NONE | InDlgIconNone |
INDLG_ICON_WARNING | InDlgIconWarning |
INDLG_ICON_INFO | InDlgIconInfo |
INDLG_ICON_QUESTION | InDlgIconQuestion |
INDLG_ICON_ERROR | InDlgIconError |
INDLG_LBL_OK | InDlgLblOk |
INDLG_LBL_CANCEL | InDlgLblCancel |
INDLG_LBL_YES | InDlgLblYes |
INDLG_LBL_NO | InDlgLblNo |
INFILE_OPEN | InFileOpen |
INFILE_SAVE | InFileSave |
INFILE_SUCCESS | InFileSuccess |
INFILE_FAILURE | InFileFailure |
INFILE_CANCEL | InFileCancel |
FILETYPE_LOG | FileTypeLog |
FILETYPE_DATA | FileTypeData |
FILETYPE_CMD | FileTypeCmd |
FILETYPE_TEXT | FileTypeText |
FILETYPE_BIN | FileTypeBin |
FILETYPE_UNKNOWN | FileTypeUnknown |
FILETYPE_T3IMAGE | FileTypeT3Image |
FILETYPE_T3SAVE | FileTypeT3Save |
SYSINFO_VERSION | SysInfoVersion |
SYSINFO_OS_NAME | SysInfoOsName |
SYSINFO_HTML | SysInfoHtml |
SYSINFO_JPEG | SysInfoJpeg |
SYSINFO_PNG | SysInfoPng |
SYSINFO_WAV | SysInfoWav |
SYSINFO_MIDI | SysInfoMidi |
SYSINFO_WAV_MIDI_OVL | SysInfoWavMidiOvl |
SYSINFO_WAV_OVL | SysInfoWavOvl |
SYSINFO_PREF_IMAGES | SysInfoPrefImages |
SYSINFO_PREF_SOUNDS | SysInfoPrefSounds |
SYSINFO_PREF_MUSIC | SysInfoPrefMusic |
SYSINFO_PREF_LINKS | SysInfoPrefLinks |
SYSINFO_MPEG | SysInfoMpeg |
SYSINFO_MPEG1 | SysInfoMpeg1 |
SYSINFO_MPEG2 | SysInfoMpeg2 |
SYSINFO_MPEG3 | SysInfoMpeg3 |
SYSINFO_HTML_MODE | SysInfoHtmlMode |
SYSINFO_LINKS_HTTP | SysInfoLinksHttp |
SYSINFO_LINKS_FTP | SysInfoLinksFtp |
SYSINFO_LINKS_NEWS | SysInfoLinksNews |
SYSINFO_LINKS_MAILTO | SysInfoLinksMailto |
SYSINFO_LINKS_TELNET | SysInfoLinksTelnet |
SYSINFO_PNG_TRANS | SysInfoPngTrans |
SYSINFO_PNG_ALPHA | SysInfoPngAlpha |
STATMODE_NORMAL | StatModeNormal |
STATMODE_STATUS | StatModeStatus |
SCRFILE_QUIET | ScriptFileQuiet |
SCRFILE_NONSTOP | ScriptFileNonstop |
CHARSET_DISPLAY | CharsetDisplay |
CHARSET_FILE | CharsetFile |
firstPerson | FirstPerson |
secondPerson | SecondPerson |
thirdPerson | ThirdPerson |
spellIntTeenHundreds | SpellIntTeenHundreds |
spellIntAndTens | SpellIntAndTens |
spellIntCommas | SpellIntCommas |
Logical | logical |
LogicalRank | logicalRank |
LogicalRankOrd | logicalRankOrd |
Dangerous | dangerous |
NonObvious | nonObvious |
IllogicalNow | illogicalNow |
Illogical | illogical |
Inaccessible | inaccessible |
DefaultReport | defaultReport |
MainReport | mainReport |
ReportBefore | reportBefore |
ReportAfter | reportAfter |
ReportFailure | reportFailure |
IsNonDefaultReport | gIsNonDefaultReport |
SingleDobj | singleDobj |
SingleIobj | singleIobj |
DobjList | dobjList |
IobjList | iobjList |
NumberPhrase | singleNumber |
TopicPhrase | singleTopic |
LiteralPhrase | singleLiteral |
DirPhrase | singleDir |
self.(processorProp)(txt, typ, toks)
txt is the text that matched the rule (this is the same as the lone argument to the old interface). typ is the token type from the rule (i.e., element [2] of the sublist defining the rule). toks is a Vector containing the token list under construction. The method must append the appropriate set of tokens to the Vector in toks. The method is not required to append any tokens; the rule in the default tokenizer rule set that matches whitespace, for example, doesn't generate any tokens, since whitespace characters have no significance other than separating tokens in the default rule set. The rule is also allowed to generate more than one token; this is useful for rules that generate certain tokens types only if they immediately follow particular text patterns. Note that the processor method is not required to use the typ value given, since each new token the method adds to the result Vector can be of whatever type is appropriate; the type information is included so that a single processor method can be re-used for similar types of processing that produce different token types.
grammar nounPhrase(1): adjective->adj_ : object ;
The tag's only purpose is to provide an identifying name for the new "grammarInfo" method, described below.
myObject: object obj = nil setObj(obj) { self.obj = obj; } ;
In the past, the code above would have had to use a different name for the formal parameter variable obj, because it would not have been able to refer to the property of the same name. With the new interpretation, the code can distinguish between the local and the property by referring to the property explicitly using self.obj.
Note that it is still simple to obtain the old behavior of evaluating the local variable and calling a method via the resulting property pointer. To do this, simply enclose the local in parentheses: x.(y).