Module prefix

Source
Expand description

The \global, \long and \outer prefix commands

The \long and \outer commands are designed to place restrictions on macros to avoid performance problems. These restrictions are described in the TeXBook. Texlang does not currently impose these restrictions because hardware is much better than in the 70s, and minimizing the complexity of Texlang’s code is more important than stopping TeX users from writing slow TeX code. However, Texlang does enforce the rule that these prefix commands can only come before \def, \gdef, \edef and \xdef.

§Developer notes on \global

The \global command here is pretty much a nightmare to implement. One of the core principles of the Texlang implementation is to remove global state, but \global makes this really hard. The reason is that it changes the behavior, at run time, of a bunch of other commands like \def and \advance, and it also changes the semantics of variable assignment. It is impossible to scope \global tightly because of its wide effects.

The approach here has two parts.

First, for variable assignment, we just reimplement what happens in the VM except we pass a flag that makes the assignment global. This is not too bad as it’s only a few lines of code.

For commands, it’s a little messier. We maintain a component which has a flag global that is set to true by the \global command. Commands that can be prefixed with \global read the flag and act accordingly. The problem is that we need the global flag to be reset to false at some point; otherwise, \global would make all subsequent assignments global. To do this we introduce a convention: any command which can be prefixed by \global reads the flag a single time using the Component::read_and_reset_global method. This method returns the flag value and resets the flag to false.

In order for the convention to work correctly it is essential that all code paths within the command call read_and_reset_global - even if they don’t use the result! For example \gdef always creates a macro in the global scope, but it still needs to call read_and_reset_global. This behavior should be verified with unit tests, and this module provides an assert_global_is_false execution command to make this easy.

Finally, commands which can be prefixed with \global are manually added to the hash set inside the Component. This set is used to validate that the command that follows \global is allowed to be prefixed by it.

Structs§

Component
Component for the prefix commands.

Functions§

get_assert_global_is_false
Get an execution command that checks that the global flag is off.
get_global
Get the \global command.
get_globaldefs
Get the \globaldefs command.
get_long
get_outer
Get the \outer command.
variable_assignment_scope_hook