Excellent! I think Forsaken Denizen is currently the largest Dialog project out there, so if it’s so far below the limits, that’s a great sign for the language in general.
As a side note, I would like to figure out the difference between what’s stored in “object data 1” and “object data 2” before making an official release, but most of it remains a mystery to me at this point. “Object data 1” includes the raw Z-machine object table and property tables, while “object data 2” is…something else, to do with per-object flags and variables? Maybe?
I’ve started tinkering with the Å-machine repository too. My first pull request adds two features to the JavaScript interpreter:
It now uses the style class names from the Dialog source instead of the index numbers, if they’re available; (div @green) will now be sent to the browser as <div class="aa-green"> instead of <div class="aalook14">. The aa- prefix ensures it won’t collide with any CSS classes used by the interpreter itself, which all start with aa and no hyphen.
Any lines in a Dialog style class that start with aria- will be applied as HTML attributes, allowing authors to set ARIA properties for screen readers. If you have a style definition like this:
(style class @italic)
font-style: italic;
aria-role: emphasis;
That will now create <span class="aa-italic" role="emphasis"> on the browser side. The aria-role property is renamed to role; all other properties starting with aria- will be passed through unchanged.
EDIT: I’ve also integrated the accessibility improvements from Miss Gosling:
An option to double the font size
Links are <a> elements instead of <span>s
Previous inputs are <h2> elements instead of <span>s
Speaking of that repository, though—should we set up similar protections on the main branch, with people reviewing pull requests? I don’t know if people have as much interest in tinkering with the web interpreter as with the compiler itself, but I have various changes I’d like to make (accessibility and enhanced styling things), and I’d like to do it in the proper way.
I’ve finally got around to implementing the gender-neutral language stuff on my end. A couple questions before making a pull request:
How exactly does the versioning work? Would 1.0 be correct for the newest version of the standard library (1 because it’s not Linus’ work, 1.0 because it’s the first minor version of the standard library since forking)? I see that some previous changes to the compiler got versions like 1a02, but I don’t understand what the “a” is for. Or do I not touch the version at all, until there’s an official release? What about the “release notes” in the readme?
This will require documentation changes eventually, but I assume it’s fine if I leave it for now, since the situation with the documentation isn’t totally figured out yet?
Also, I took the liberty of making it so that “notice” updates the “them” pronoun even when noticing people of specified binary gender, since it’s quite possible that the narration won’t specify their gender at first. In other words, I changed it so the following is now supported:
You see a mechanic working on a car in the corner.
> TALK TO THEM
She ignores you.
But I could change it back if people think there’s an issue with that.
We’re still talking about this. For whatever reason, the library uses version numbers like “0.43” (major.minor), the compiler uses version numbers like “0m03” (major, minor-as-a-letter, patch), and the documentation uses version numbers like “12” (a single number), and we’re still trying to figure out how, or when, we should update those.
So for now, I’d say don’t worry about it. We’ll handle that separate from the pull request.
Likewise. Right now, hlship is doing a bunch of work to put the documentation in an easily-editable form, and we’re holding off on any updates to it until he’s done with that.
Seems reasonable to me!
I say go ahead and make a pull request, and we’ll check it out!
The ability to trace queries is incredibly useful. The only other thing I might want in the trace output is the option to see query level numbers instead of the indented output with the pipes. It’s comprehensible as is, but with a screen reader, I do have to count them each time. Not sure how complex that would be to set up, being a built-in predicate, or if anyone else would even want it. I guess it would count as a minor change to the language, and wouldn’t be backwards compatible.
Thoughts? I’ll be messing around and trying to implement this for my own benefit, but if anyone else wants it…
All, I suppose. I’m mainly using it in the debugger, and the manual seems to say that this is the best place to be using it, so I guess the debugger would be a sensible priority. But if it can do it there and people want it, it might be a good idea to add it to the others also.
So it would be very easy to just print the level number instead of printing | for each level. It looks like the Z-machine backend doesn’t handle levels like this, it just prints queries entered and exited, though I should test this to be sure. And on the Å-machine, it’s all left up to the interpreter.
Honestly, the hardest part will be adding the extra option to the command line, because it means I have to look up how getopt works again!
Currently, tracing in the debugger gives output like this.
| QUERY (test) unifyfail.dg:14
| | ENTER (test) unifyfail.dg:1
| | QUERY ([$ $] = $) unifyfail.dg:2
| | FOUND ([$ $] = [$ $]) unifyfail.dg:2
Value of Y: [$ $].
| | QUERY ($ = 24) unifyfail.dg:4
| | FOUND (24 = 24) unifyfail.dg:4
Value of Y: [24 24].
| | QUERY (test again) unifyfail.dg:6
| | | ENTER (test again) unifyfail.dg:8
| | | QUERY ($ = 24) unifyfail.dg:9
| | | FOUND (24 = 24) unifyfail.dg:9
Value of Y: $.
| | FOUND (test again) unifyfail.dg:6
| FOUND (test) unifyfail.dg:14
But with a screen reader, it would be better if it output like this:
1 QUERY (test) unifyfail.dg:14
2 ENTER (test) unifyfail.dg:1
2 QUERY ([$ $] = $) unifyfail.dg:2
2 FOUND ([$ $] = [$ $]) unifyfail.dg:2
Value of Y: [$ $].
2 QUERY ($ = 24) unifyfail.dg:4
2 FOUND (24 = 24) unifyfail.dg:4
Value of Y: [24 24].
2 QUERY (test again) unifyfail.dg:6
3 ENTER (test again) unifyfail.dg:8
3 QUERY ($ = 24) unifyfail.dg:9
3 FOUND (24 = 24) unifyfail.dg:9
Value of Y: $.
2 FOUND (test again) unifyfail.dg:6
1 FOUND (test) unifyfail.dg:14
Or would you also like a | or something at the beginning of tracing lines to distinguish them from normal output?
On Z-machine, the output is this:
QUERY (test) at unifyfail.dg:14
ENTER (test) at unifyfail.dg:1
QUERY ([$ $] = $) at unifyfail.dg:2
Value of Y: [$ $].
QUERY ($ = 24) at unifyfail.dg:4
Value of Y: [24 24].
QUERY (test again) at unifyfail.dg:6
ENTER (test again) at unifyfail.dg:8
QUERY ($ = 24) at unifyfail.dg:9
Value of Y: $.
Which has no level marking at all, so I’m not going to make any changes there at the moment.
Although if I think about it, perhaps a | at the beginning of the line wouldn’t go amiss, to distinguish it from potential game output that begins with a number?
Well, here’s another mystery solved: the current Dialog compiler never uses any of the Z-machine’s standard object properties! Per-object variables are always stored in its own data structures instead.
This is what “object data 2” is: for each per-object variable, an array of (number of objects) words. Since Miss Gosling only uses a single per-object variable (the standard library ($ has relation $)), and has 174 objects, this takes up 2×174=348 bytes of space.
“Object data 1”, meanwhile, holds the property tables, which only contain the data required by the Z-machine (six bytes for attributes/per-object flags, two bytes each for parent, sibling, and child pointers, two bytes for property table pointer, for a total of 14), the internal name of the object (#diningroom and whatnot), and a one-byte property table terminator. In Miss Gosling’s case, that averages out to about 22 bytes per object.
I find it curious that using a separate array ended up being more efficient than the Z-machine’s built-in property system. They would take up the same amount of space, so it must be a matter of time. The Z-machine property table is optimized for a situation where not every object provides every property (and in fact most objects don’t provide every property), so I imagine Linus discovered it’s less efficient than a simple array if that assumption doesn’t hold.
This also suggests that, if you’re running low on addressable memory, passing the -s flag (strip internal object names) will recover about seven bytes per object, which in a big game might be a lot!