Version 1/220331 of Data Structures (for Glulx only) by Dannii Willis begins here. "Provides support for some additional data structures" [Supported releases: 6M62] Chapter - Template changes [ Clean up the function stubs ] Include (- -) instead of "Data Structures Stubs" in "Figures.i6t". [ For unknown reasons, most of the new kinds don't get added to KOVComparisonFunction, so augment it ] Include (- Replace KOVComparisonFunction KOVComparisonFunction_Orig; -) after "Definitions.i6t". Include (- [ KOVComparisonFunction k ak; ak = KindAtomic(k); switch(ak) { ANY_TY, CLOSURE_TY, COUPLE_TY, MAP_TY, OPTION_TY, PROMISE_TY, RESULT_TY: return BlkValueCompare; default: return KOVComparisonFunction_Orig(k); } ]; -) after "Printing Routines" in "Output.i6t". Chapter - General utilities To decide what V is a/-- new (name of kind of value V): (- {-new:V} -). To ignore the result of (V - value): (- {V}; -). [ The immutable kinds are compared based on their values. The mutable kinds are compared based on their long blocks, and so can share a comparison function. ] Include (- [ Data_Structures_Compare_Common v1 v2 v1_LB v2_LB; v1_LB = BlkValueGetLongBlock(v1); v2_LB = BlkValueGetLongBlock(v2); ! Equal long blocks means these are the same return v1_LB - v2_LB; ]; [ Data_Structures_Distinguish v1 v2; if (Data_Structures_Compare_Common(v1, v2) == 0) rfalse; rtrue; ]; -). Chapter - Anys [ Anys have a two word long block (ignoring the header). Word 0: the kind of the value Word 1: the value ] Include (- ! Static block values have three parts: the short block (0 means the long block follows immediately), the long block header, and the long block data. ! $050C0000 means a block of length 2^5=32 bytes, that is resident (static) and uses word values. Array ANY_TY_Default --> 0 $050C0000 ANY_TY MAX_POSITIVE_NUMBER NULL_TY 0; Constant ANY_TY_KOV = 0; Constant ANY_TY_VALUE = 1; [ ANY_TY_Support task arg1 arg2; switch(task) { COMPARE_KOVS: return ANY_TY_Compare(arg1, arg2); COPYQUICK_KOVS: rtrue; COPYSB_KOVS: BlkValueCopySB1(arg1, arg2); CREATE_KOVS: return ANY_TY_Create(arg2); DESTROY_KOVS: ANY_TY_Destroy(arg1); } ! We don't respond to the other tasks rfalse; ]; [ ANY_TY_Compare any1 any2 cf delta any1kov; ! Equal long blocks means these are the same if (BlkValueGetLongBlock(any1) == BlkValueGetLongBlock(any2)) { return 0; } any1kov = BlkValueRead(any1, ANY_TY_KOV); ! Compare the kinds delta = any1kov - BlkValueRead(any2, ANY_TY_KOV); if (delta) { return delta; } ! Then compare the contents cf = KOVComparisonFunction(any1kov); if (cf == 0 or UnsignedCompare) { return BlkValueRead(any1, ANY_TY_VALUE) - BlkValueRead(any2, ANY_TY_VALUE); } else { return cf(BlkValueRead(any1, ANY_TY_VALUE), BlkValueRead(any2, ANY_TY_VALUE)); } ]; [ ANY_TY_Create short_block long_block; long_block = FlexAllocate(2 * WORDSIZE, ANY_TY, BLK_FLAG_WORD); BlkValueWrite(long_block, ANY_TY_KOV, NULL_TY, 1); short_block = BlkValueCreateSB1(short_block, long_block); return short_block; ]; [ ANY_TY_Destroy any; if (KOVIsBlockValue(BlkValueRead(any, ANY_TY_KOV))) { BlkValueFree(BlkValueRead(any, ANY_TY_VALUE)); } ]; [ ANY_TY_Distinguish any1 any2; if (ANY_TY_Compare(any1, any2) == 0) rfalse; rtrue; ]; [ ANY_TY_Get any kov checked_bv backup or anykov txt; anykov = BlkValueRead(any, ANY_TY_KOV); if (anykov == kov) { if (checked_bv) { return RESULT_TY_Set(checked_bv, kov, BlkValueRead(any, ANY_TY_VALUE)); } else { return BlkValueRead(any, ANY_TY_VALUE); } } LocalParking-->0 = kov; LocalParking-->1 = any; if (checked_bv) { txt = BlkValueCreate(TEXT_TY); BlkValueCopy(txt, ANY_TY_Print_Kind_Mismatch); return RESULT_TY_Set(checked_bv, 0, txt); } else { if (~~or) { ANY_TY_Print_Kind_Mismatch_Inner(); print "^"; } return backup; } ]; Array ANY_TY_Print_Illegal_Pattern --> CONSTANT_PACKED_TEXT_STORAGE "@@94@{5C}$"; [ ANY_TY_Print_Kind_Name skov val plural show_object_subkinds basekov subkind str; basekov = KindAtomic(skov); switch (basekov) { ACTION_NAME_TY: print "action name"; ACTIVITY_TY: print "activity"; ANY_TY: print "any"; CLOSURE_TY: print "closure"; COUPLE_TY: if (plural) { print "couples of "; } else { print "couple of "; } ANY_TY_Print_Subkind_Name(skov, 0, 0, show_object_subkinds); print " and "; ANY_TY_Print_Subkind_Name(skov, 1, 0, show_object_subkinds); DESCRIPTION_OF_TY: print "description"; EQUATION_TY: print "equation"; EXTERNAL_FILE_TY: print "external file"; FIGURE_NAME_TY: print "figure name"; LIST_OF_TY: if (plural) { print "lists of "; } else { print "list of "; } ANY_TY_Print_Subkind_Name(skov, 0, 1, show_object_subkinds); MAP_TY: if (plural) { print "maps of "; } else { print "map of "; } ANY_TY_Print_Subkind_Name(skov, 0, 1, show_object_subkinds); print " to "; ANY_TY_Print_Subkind_Name(skov, 1, 1, show_object_subkinds); NULL_TY: print "null"; NUMBER_TY: print "number"; OBJECT_TY: print "object"; OPTION_TY: ANY_TY_Print_Subkind_Name(skov, 0, 0, show_object_subkinds); print " option"; PROMISE_TY: ANY_TY_Print_Subkind_Name(skov, 0, 0, show_object_subkinds); print " promise"; PHRASE_TY: print "phrase"; PROPERTY_TY: print "property"; REAL_NUMBER_TY: print "real number"; RELATION_TY: print "relation"; RESPONSE_TY: print "response"; RESULT_TY: ANY_TY_Print_Subkind_Name(skov, 0, 0, show_object_subkinds); print " result"; RULE_TY: print "rule"; RULEBOOK_OUTCOME_TY: print "rulebook outcome"; RULEBOOK_TY: print "rulebook"; SCENE_TY: print "scene"; SNIPPET_TY: print "snippet"; SOUND_NAME_TY: print "sound name"; STORED_ACTION_TY: print "stored action"; TABLE_TY: print "table"; TABLE_COLUMN_TY: print "table column"; TEXT_TY: print "text"; TIME_TY: print "time"; TRUTH_STATE_TY: print "truth state"; UNDERSTANDING_TY: print "topic"; UNICODE_CHARACTER_TY: print "unicode character"; USE_OPTION_TY: print "use option"; VERB_TY: print "verb"; default: str = BlkValueCreate(TEXT_TY); LocalParking-->0 = basekov; LocalParking-->1 = val; TEXT_TY_ExpandIfPerishable(str, ANY_TY_Print_Kind_Text); if (TEXT_TY_Replace_RE(REGEXP_BLOB, str, ANY_TY_Print_Illegal_Pattern, 0, 0)) { print (TEXT_TY_Say) TEXT_TY_RE_GetMatchVar(1); } else { print (TEXT_TY_Say) str; } BlkValueFree(str); } if (plural) { if (basekov == COUPLE_TY or LIST_OF_TY or MAP_TY) { return; } print "s"; } ]; Array ANY_TY_Print_Kind_Mismatch --> CONSTANT_PERISHABLE_TEXT_STORAGE ANY_TY_Print_Kind_Mismatch_Inner; [ ANY_TY_Print_Kind_Mismatch_Inner; print "Any kind mismatch: expected "; ANY_TY_Print_Kind_Name(LocalParking-->0, 0, 0, 1); print ", got "; ANY_TY_Print_Kind_Name(BlkValueRead(LocalParking-->1, ANY_TY_KOV), BlkValueRead(LocalParking-->1, ANY_TY_VALUE), 0, 1); ]; Array ANY_TY_Print_Kind_Text --> CONSTANT_PERISHABLE_TEXT_STORAGE ANY_TY_Print_Kind_Text_Inner; [ ANY_TY_Print_Kind_Text_Inner; PrintKindValuePair(LocalParking-->0, LocalParking-->1); ]; [ ANY_TY_Print_Subkind_Name skov subkind_num plural show_object_subkinds subkind; subkind = KindBaseTerm(skov, subkind_num); ANY_TY_Print_Kind_Name(subkind, 0, plural, show_object_subkinds); if (show_object_subkinds && subkind == OBJECT_TY) { print " (subkind ", skov, ")"; } ]; [ ANY_TY_Say any kov; kov = BlkValueRead(any, ANY_TY_KOV); print "Any<"; ANY_TY_Print_Kind_Name(kov); print ": "; PrintKindValuePair(kov, BlkValueRead(any, ANY_TY_VALUE)); print ">"; ]; [ ANY_TY_Set any kov value long_block valcopy; ! Check this Any hasn't been set before if (BlkValueRead(any, ANY_TY_KOV) ~= NULL_TY) { print "Error! Cannot set an Any twice!^"; return any; } ! Write to the long block directly, without copy-on-write semantics long_block = BlkValueGetLongBlock(any); BlkValueWrite(long_block, ANY_TY_KOV, kov, 1); ! Make our own copy of the value if (KOVIsBlockValue(kov)) { valcopy = BlkValueCreate(kov); BlkValueCopy(valcopy, value); value = valcopy; } BlkValueWrite(long_block, ANY_TY_VALUE, value, 1); return any; ]; -). To decide which any is (V - value of kind K) as an any: (- ANY_TY_Set({-new:any}, {-strong-kind:K}, {-by-reference:V}) -). To say kind/type of (A - any): (- ANY_TY_Print_Kind_Name(BlkValueRead({-by-reference:A}, ANY_TY_KOV)); -). To decide if kind/type of (A - any) is (name of kind of value K): (- (BlkValueRead({-by-reference:A}, ANY_TY_KOV) == {-strong-kind:K}) -). [ We declare this as a loop, even though it isn't, because nonexisting variables don't seem to be unassigned at the end of conditionals. ] To if kind/type/-- of/-- (A - any) is (name of kind of value K) let (V - nonexisting K variable) be the value begin -- end loop: (- if (BlkValueRead({-by-reference:A}, ANY_TY_KOV) == {-strong-kind:K} && ( (KOVIsBlockValue({-strong-kind:K}) && BlkValueCopy({-lvalue-by-reference:V}, BlkValueRead({-by-reference:A}, ANY_TY_VALUE)) || ({-lvalue-by-reference:V} = BlkValueRead({-by-reference:A}, ANY_TY_VALUE)) ) , 1)) -). To decide what K result is (A - any) as a/an (name of kind of value K): (- ANY_TY_Get({-by-reference:A}, {-strong-kind:K}, {-new:K result}) -). To decide what K is (A - any) as a/an (name of kind of value K) or (backup - K): (- ANY_TY_Get({-by-reference:A}, {-strong-kind:K}, 0, {-by-reference:backup}, 1) -). Section - Unit tests (for use with Unit Tests by Zed Lopez) (not for release) (unindexed) Data Structures Anys is a unit test. "Data Structures: Anys functionality" Data Structures Anys is heap tracking. Test global any is an any that varies. Persons have an any called test property any. To decide what any is test returning a text any from a phrase: decide on "Hello world!" as an any; For testing data structures anys: [ Test untyped (null) anys ] let NullAny1 be an any; for "Untyped any is kind null" assert the kind of NullAny1 is null; for "Name of kind of untyped any" assert "[kind of NullAny1]" is "null"; for "Saying untyped any" assert "[NullAny1]" is "Any"; for "Default value of global any" assert test global any is null as an any; for "Default value of property any" assert test property any of yourself is null as an any; if NullAny1 is a number let NullAnyValue be the value: for "Any let V be the value" fail; otherwise: for "Any let V be the value" pass; [ Test basic functionality with a number any ] let NumAny1 be 1234 as an any; for "Any kind" assert the kind of NumAny1 is number; for "Any result" assert NumAny1 as a number is 1234 as a result; for "Any equality" assert NumAny1 is 1234 as an any; let NumAny1Error be a text error result with message "Any kind mismatch: expected text, got number"; for "Any cast to text error message" assert NumAny1 as a text is NumAny1Error; let NumAny1Text2 be NumAny1 as a text or "Oops, not a text"; for "Any cast with backup value" assert NumAny1Text2 is "Oops, not a text"; for "Any unchecked" assert NumAny1 as a number unchecked is 1234; if NumAny1 is a number let NumAnyValue be the value: for "Any let V be the value" assert NumAnyValue is 1234; otherwise: for "Any let V be the value" fail; [ Test anys with with block values with a text any ] let TextAny1 be "Hello world!" as an any; for "Any kind" assert the kind of TextAny1 is text; for "Any result" assert TextAny1 as a text is "Hello world!" as a result; for "Any equality" assert TextAny1 is "Hello world!" as an any; for "Any returned from phrase" assert test returning a text any from a phrase is "Hello world!" as an any; for "Any unchecked" assert TextAny1 as a text unchecked is "Hello world!"; if TextAny1 is a text let TextAnyValue be the value: for "Any let V be the value" assert TextAnyValue is "Hello world!"; otherwise: for "Any let V be the value" fail; [ Test comparison operators ] for "Any > comparison" assert 1234 as an any > 1233 as an any; for "Any < comparison" assert 1234 as an any < 1235 as an any; for "Any > comparison" assert "Hello" as an any > "Apple" as an any; for "Any < comparison" assert "Hello" as an any < "Zoo" as an any; [ Check that object subkinds are shown in error messages ] let ListAny1 be {yourself} as an any; for "Any subkinds shown in error messages" assert "[ListAny1 as a number]" rmatches "Error\(Any kind mismatch: expected number, got list of objects \(subkind \d+\)\)"; Data Structures Anys All Kinds is a unit test. "Data Structures: Anys of all kinds" Data Structures Anys All Kinds is heap tracking. Equation - Data Structures Test Equation F=ma where F is a number, m is a number, a is an number. The file of Data Structures Test File is called "DSTF". To data structures test phrase (this is data structures test phrase): do nothing; Sound of Data Structures Test Sound is the file "DSTS". For testing data structures anys all kinds: [ Test that printing anys of all the kinds works ] for "Any" assert "[waiting action as an any]" is "Any"; for "Any" assert "[printing the name as an any]" is "Any"; for "Any" assert "[1234 as an any as an any]" is "Any>"; for "Any" assert "[1234 and yourself as a couple as an any]" is "Any"; [ descriptions? ] for "Any" assert "[Data Structures Test Equation as an any]" rmatches "Any\"; for "Any" assert "[file of Data Structures Test File as an any]" is "Any"; for "Any
" assert "[figure of cover as an any]" is "Any
"; for "Any" assert "[{yourself} as an any]" is "Any"; for "Any" assert "[(new map of numbers to things) as an any]" is "Any"; for "Any" assert "[null as an any]" is "Any"; for "Any" assert "[1234 as an any]" is "Any"; for "Any" assert "[yourself as an any]" is "Any"; for "Any