I’ve been looking at Inform’s parser loop. (See thread https://intfiction.org/t/working-on-a-unified-glulx-input-extension/8676/1 .)
It’s got a lot of grotty bits. One of the obvious, which many people have stumbled over, is that the blank-input error (“I beg your pardon?”) is wrapped up inside the Keyboard() routine. It doesn’t make it out to the “reading a command” activity.
Why is this? One motivation must have been to short-circuit blank inputs before the @saveundo. That is, if the player whacks the enter key a bunch of times and then types “UNDO”, we want to jump back to an undo point before the last valid command. Making them “UNDO” each blank input in turn is silly.
Notice that this doesn’t extend as far as erroneous inputs. If the player types “DFGHS” and gets an “I don’t recognize that verb” error, and then does “UNDO”, the game undoes the error input. (By the time the parser figures out that it’s an error, the undo point is already saved.) This is silly but we put up with it.
One way to fix this would be to delay saving an undo point until the parser has parsed out a valid command. That’s okay in theory but it’s risky. The parser does a lot of work, potentially extended by the game author. We don’t want to run that work before the undo point, because it could affect future commands. Then UNDO becomes unreliable and players become sad. It’s cleanest to save the undo point as soon as possible after the input event.
A nicer solution, I think, is to add a VM opcode @discardundo. This simply throws away the last undo point.
Now we have this layout:
Keyboard: KeyboardPrimitive() if UNDO command: @restoreundo @saveundo Parser: (before reading a command...) Keyboard() (after reading a command...) if input is blank: "I beg your pardon?" @discardundo continue parse parse parse if any parser error: show error @discardundo continue perform action
Now blank-input errors are handled exactly like all other parser errors. The Keyboard() routine is simpler. (In fact we can make it even simpler by moving the @saveundo above the KeyboardPrimitive() line, which is where intuition wants it.)
The down side, of course, is that it’s an interpreter change. Many interpreters are unmaintained these days so the @discardundo opcode will not be available.
(Consequence: I don’t want to tie my Unified Glulx Input work to this. But maybe as an optional enhancement, and suck up the regression in blank-line handling on old interpreters…)