The LATEX3 SourcesThe LATEX3 Project∗ March 14, 2013 Abstract This is the reference documentation for the expl3 programming environment. The expl3 modules set up an experimental naming scheme for LATEX commands, which allow the LATEX programmer to systematically name functions and variables, and specify the argument types of functions. The TEX and ε-TEX primitives are all given a new name according to these conventions. However, in the main direct use of the primitives is not required or encouraged: the expl3 modules define an independent low-level LATEX3 programming language. At present, the expl3 modules are designed to be loaded on top of LATEX 2ε . In time, a LATEX3 format will be produced based on this code. This allows the code to be used in LATEX 2ε packages now while a stand-alone LATEX3 is developed. While expl3 is still experimental, the bundle is now regarded as broadly stable. The syntax conventions and functions provided are now ready for wider use. There may still be changes to some functions, but these will be minor when compared to the scope of expl3. New modules will be added to the distributed version of expl3 as they reach maturity. ∗ E-mail:
[email protected] i Contents I Introduction to expl3 and this document 1 1 Naming functions and variables 1.1 Terminological inexactitude . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 2 Documentation conventions 3 3 Formal language conventions which apply generally 5 4 TEX concepts not supported by LATEX3 5 II The l3bootstrap package: Bootstrap code 6 1 Using the LATEX3 modules 1.1 Internal functions and variables . . . . . . . . . . . . . . . . . . . . . . . 6 7 III 1 IV The l3names package: Namespace for primitives 8 Setting up the LATEX3 programming language 8 The l3basics package: Basic definitions 9 1 No operation functions 9 2 Grouping material 9 3 Control sequences and functions 3.1 Defining functions . . . . . . . . . . . . . . . 3.2 Defining new functions using parameter text 3.3 Defining new functions using the signature . 3.4 Copying control sequences . . . . . . . . . . . 3.5 Deleting control sequences . . . . . . . . . . 3.6 Showing control sequences . . . . . . . . . . 3.7 Converting to and from control sequences . . 4 . . . . . . . 10 10 11 13 15 16 16 17 Using or removing tokens and arguments 4.1 Selecting tokens from delimited arguments . . . . . . . . . . . . . . . . 18 20 ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Predicates and conditionals 5.1 Tests on control sequences 5.2 Testing string equality . . . 5.3 Engine-specific conditionals 5.4 Primitive conditionals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 21 22 23 23 6 Internal kernel functions 24 V The l3expan package: Argument expansion 27 1 Defining new variants 27 2 Methods for defining variants 28 3 Introducing the variants 28 4 Manipulating the first argument 29 5 Manipulating two arguments 30 6 Manipulating three arguments 31 7 Unbraced expansion 32 8 Preventing expansion 32 9 Internal functions and variables 34 VI The l3prg package: Control structures 35 1 Defining a set of conditional functions 35 2 The boolean data type 37 3 Boolean expressions 39 4 Logical loops 40 5 Producing n copies 41 6 Detecting TEX’s mode 41 7 Primitive conditionals 42 8 Internal programming functions 42 iii The l3quark package: Quarks VII 44 1 Introduction to quarks and scan marks 1.1 Quarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 44 2 Defining quarks 45 3 Quark tests 45 4 Recursion 46 5 Clearing quarks away 47 6 An example of recursion with quarks 47 7 Internal quark functions 48 8 Scan marks 48 VIII The l3token package: Token manipulation 49 1 All possible tokens 49 2 Character tokens 50 3 Generic tokens 53 4 Converting tokens 54 5 Token conditionals 54 6 Peeking ahead at the next token 58 7 Decomposing a macro definition 61 The l3int package: Integers 62 IX 1 Integer expressions 62 2 Creating and initialising integers 63 3 Setting and incrementing integers 64 4 Using integers 65 5 Integer expression conditionals 65 iv 6 Integer expression loops 67 7 Integer step functions 69 8 Formatting integers 69 9 Converting from other formats to integers 71 10 Viewing integers 72 11 Constant integers 73 12 Scratch integers 73 13 Primitive conditionals 74 14 Internal functions 74 X The l3skip package: Dimensions and skips 76 1 Creating and initialising dim variables 76 2 Setting dim variables 77 3 Utilities for dimension calculations 77 4 Dimension expression conditionals 78 5 Dimension expression loops 80 6 Using dim expressions and variables 81 7 Viewing dim variables 82 8 Constant dimensions 82 9 Scratch dimensions 82 10 Creating and initialising skip variables 83 11 Setting skip variables 83 12 Skip expression conditionals 84 13 Using skip expressions and variables 84 14 Viewing skip variables 85 v 15 Constant skips 85 16 Scratch skips 85 17 Inserting skips into the output 86 18 Creating and initialising muskip variables 86 19 Setting muskip variables 87 20 Using muskip expressions and variables 87 21 Viewing muskip variables 88 22 Constant muskips 88 23 Scratch muskips 88 24 Primitive conditional 88 25 Internal functions 89 XI The l3tl package: Token lists 90 1 Creating and initialising token list variables 91 2 Adding data to token list variables 92 3 Modifying token list variables 92 4 Reassigning token list category codes 93 5 Reassigning token list character codes 93 6 Token list conditionals 94 7 Mapping to token lists 95 8 Using token lists 97 9 Working with the content of token lists 98 10 The first token from a token list 99 11 Viewing token lists 102 12 Constant token lists 102 vi 13 Scratch token lists 102 14 Internal functions 103 The l3seq package: Sequences and stacks XII 104 1 Creating and initialising sequences 104 2 Appending data to sequences 105 3 Recovering items from sequences 105 4 Recovering values from sequences with branching 106 5 Modifying sequences 107 6 Sequence conditionals 108 7 Mapping to sequences 108 8 Sequences as stacks 110 9 Constant and scratch sequences 111 10 Viewing sequences 111 11 Internal sequence functions 111 XIII The l3clist package: Comma separated lists 113 1 Creating and initialising comma lists 113 2 Adding data to comma lists 114 3 Modifying comma lists 115 4 Comma list conditionals 115 5 Mapping to comma lists 116 6 Comma lists as stacks 118 7 Viewing comma lists 119 8 Constant and scratch comma lists 120 vii XIV The l3prop package: Property lists 121 1 Creating and initialising property lists 121 2 Adding entries to property lists 122 3 Recovering values from property lists 122 4 Modifying property lists 123 5 Property list conditionals 123 6 Recovering values from property lists with branching 123 7 Mapping to property lists 124 8 Viewing property lists 125 9 Scratch property lists 126 10 Constants 126 11 Internal property list functions 126 XV The l3box package: Boxes 127 1 Creating and initialising boxes 127 2 Using boxes 128 3 Measuring and setting box dimensions 128 4 Box conditionals 129 5 The last box inserted 130 6 Constant boxes 130 7 Scratch boxes 130 8 Viewing box contents 130 9 Horizontal mode boxes 131 10 Vertical mode boxes 132 11 Primitive box conditionals 134 viii XVI The l3coffins package: Coffin code layer 135 1 Creating and initialising coffins 135 2 Setting coffin content and poles 135 3 Joining and using coffins 137 4 Measuring coffins 137 5 Coffin diagnostics 138 5.1 Constants and variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 XVII 1 The l3color package: Colour support Colour in boxes XVIII 139 139 The l3msg package: Messages 140 1 Creating new messages 140 2 Contextual information for messages 141 3 Issuing messages 142 4 Redirecting messages 144 5 Low-level message functions 145 6 Kernel-specific functions 146 7 Expandable errors 147 8 Internal l3msg functions 148 XIX The l3keys package: Key–value interfaces 149 1 Creating keys 150 2 Sub-dividing keys 154 3 Choice and multiple choice keys 154 4 Setting keys 156 5 Setting known keys only 157 ix 6 Utility functions for keys 157 7 Low-level interface for parsing key–val lists 157 The l3file package: File and I/O operations XX 160 1 File operation functions 160 1.1 Input–output stream management . . . . . . . . . . . . . . . . . . . . . 161 1.2 Reading from files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 2 Writing to files 2.1 Wrapping lines in output . . . . . . 2.2 Constant input–output streams . . . 2.3 Primitive conditionals . . . . . . . . 2.4 Internal file functions and variables 2.5 Internal input–output functions . . XXI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The l3fp package: floating points . . . . . . . . . . . . . . . . . . . . . . . . . 163 164 165 165 165 166 167 1 Creating and initialising floating point variables 168 2 Setting floating point variables 168 3 Using floating point numbers 169 4 Floating point conditionals 170 5 Floating point expression loops 171 6 Some useful constants, and scratch variables 172 7 Floating point exceptions 173 8 Viewing floating points 174 9 Floating point expressions 175 9.1 Input of floating point numbers . . . . . . . . . . . . . . . . . . . . . . . 175 9.2 Precedence of operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 9.3 Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 10 Disclaimer and roadmap XXII 1 181 The l3luatex package: LuaTeX-specific functions Breaking out to Lua 184 184 x 2 Category code tables 185 XXIII The l3candidates package: Experimental additions to l3kernel 187 1 Additions to l3basics 2 Additions to l3box 187 2.1 Affine transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 2.2 Viewing part of a box . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 2.3 Internal variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 3 Additions to l3clist 190 4 Additions to l3coffins 191 5 Additions to l3file 192 6 Additions to l3fp 193 7 Additions to l3prop 193 8 Additions to l3seq 194 9 Additions to l3skip 196 10 Additions to l3tl 196 11 Additions to l3tokens 197 XXIV 1 2 187 Implementation 198 l3bootstrap implementation 1.1 Format-specific code . . . . . . . . . . 1.2 Package-specific code part one . . . . 1.3 The \pdfstrcmp primitive in XETEX . 1.4 Engine requirements . . . . . . . . . . 1.5 Package-specific code part two . . . . 1.6 Dealing with package-mode meta-data 1.7 The LATEX3 code environment . . . . 1.8 Deprecated functions . . . . . . . . . l3names implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 198 199 200 200 201 202 204 206 206 xi 3 4 5 l3basics implementation 3.1 Renaming some TEX primitives (again) . . . . . . . . 3.2 Defining some constants . . . . . . . . . . . . . . . . . 3.3 Defining functions . . . . . . . . . . . . . . . . . . . . 3.4 Selecting tokens . . . . . . . . . . . . . . . . . . . . . 3.5 Gobbling tokens from input . . . . . . . . . . . . . . . 3.6 Conditional processing and definitions . . . . . . . . . 3.7 Dissecting a control sequence . . . . . . . . . . . . . . 3.8 Exist or free . . . . . . . . . . . . . . . . . . . . . . . 3.9 Defining and checking (new) functions . . . . . . . . . 3.10 More new definitions . . . . . . . . . . . . . . . . . . . 3.11 Copying definitions . . . . . . . . . . . . . . . . . . . 3.12 Undefining functions . . . . . . . . . . . . . . . . . . . 3.13 Generating parameter text from argument count . . . 3.14 Defining functions from a given number of arguments 3.15 Using the signature to define functions . . . . . . . . . 3.16 Checking control sequence equality . . . . . . . . . . . 3.17 Diagnostic functions . . . . . . . . . . . . . . . . . . . 3.18 Engine specific definitions . . . . . . . . . . . . . . . . 3.19 Doing nothing functions . . . . . . . . . . . . . . . . . 3.20 String comparisons . . . . . . . . . . . . . . . . . . . . 3.21 Breaking out of mapping functions . . . . . . . . . . . 3.22 Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 217 219 219 220 222 222 228 229 232 233 235 235 236 237 238 240 240 241 242 242 243 244 l3expan implementation 4.1 General expansion . . . . . . . . . . . . . 4.2 Hand-tuned definitions . . . . . . . . . . 4.3 Definitions with the automated technique 4.4 Last-unbraced versions . . . . . . . . . . 4.5 Preventing expansion . . . . . . . . . . . 4.6 Defining function variants . . . . . . . . . 4.7 Variants which cannot be created earlier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 246 249 252 253 254 255 261 l3prg implementation 5.1 Primitive conditionals . . . . . . . . . 5.2 Defining a set of conditional functions 5.3 The boolean data type . . . . . . . . . 5.4 Boolean expressions . . . . . . . . . . 5.5 Logical loops . . . . . . . . . . . . . . 5.6 Producing n copies . . . . . . . . . . . 5.7 Detecting TEX’s mode . . . . . . . . . 5.8 Internal programming functions . . . 5.9 Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 262 262 262 264 270 271 272 273 275 xii . . . . . . . . . . . . . . . . . . 6 l3quark implementation 278 6.1 Quarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 6.2 Scan marks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 6.3 Deprecated quark functions . . . . . . . . . . . . . . . . . . . . . . . . . 282 7 l3token implementation 7.1 Character tokens . . . . . . . . . 7.2 Generic tokens . . . . . . . . . . 7.3 Token conditionals . . . . . . . . 7.4 Peeking ahead at the next token 7.5 Decomposing a macro definition 7.6 Deprecated functions . . . . . . 8 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 283 285 286 296 302 302 l3int implementation 8.1 Integer expressions . . . . . . . . . . . . . 8.2 Creating and initialising integers . . . . . 8.3 Setting and incrementing integers . . . . 8.4 Using integers . . . . . . . . . . . . . . . 8.5 Integer expression conditionals . . . . . . 8.6 Integer expression loops . . . . . . . . . . 8.7 Integer step functions . . . . . . . . . . . 8.8 Formatting integers . . . . . . . . . . . . 8.9 Converting from other formats to integers 8.10 Viewing integer . . . . . . . . . . . . . . . 8.11 Constant integers . . . . . . . . . . . . . 8.12 Scratch integers . . . . . . . . . . . . . . 8.13 Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 305 307 309 310 310 314 315 316 321 325 325 326 326 l3skip implementation 9.1 Length primitives renamed . . . . . . . 9.2 Creating and initialising dim variables . 9.3 Setting dim variables . . . . . . . . . . . 9.4 Utilities for dimension calculations . . . 9.5 Dimension expression conditionals . . . 9.6 Dimension expression loops . . . . . . . 9.7 Using dim expressions and variables . . 9.8 Viewing dim variables . . . . . . . . . . 9.9 Constant dimensions . . . . . . . . . . . 9.10 Scratch dimensions . . . . . . . . . . . . 9.11 Creating and initialising skip variables 9.12 Setting skip variables . . . . . . . . . . 9.13 Skip expression conditionals . . . . . . . 9.14 Using skip expressions and variables . 9.15 Inserting skips into the output . . . . . 9.16 Viewing skip variables . . . . . . . . . 9.17 Constant skips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 328 328 329 330 331 332 334 335 335 335 335 336 337 338 338 338 338 . . . . . . xiii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.18 9.19 9.20 9.21 9.22 9.23 9.24 9.25 10 11 Scratch skips . . . . . . . . . . . . . . . . Creating and initialising muskip variables Setting muskip variables . . . . . . . . . . Using muskip expressions and variables . Viewing muskip variables . . . . . . . . . Constant muskips . . . . . . . . . . . . . Scratch muskips . . . . . . . . . . . . . . Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 339 340 340 341 341 341 341 l3tl implementation 10.1 Functions . . . . . . . . . . . . . . . . . 10.2 Constant token lists . . . . . . . . . . . 10.3 Adding to token list variables . . . . . . 10.4 Reassigning token list category codes . 10.5 Reassigning token list character codes . 10.6 Modifying token list variables . . . . . . 10.7 Token list conditionals . . . . . . . . . . 10.8 Mapping to token lists . . . . . . . . . . 10.9 Using token lists . . . . . . . . . . . . . 10.10Working with the contents of token lists 10.11Token by token changes . . . . . . . . . 10.12The first token from a token list . . . . 10.13Viewing token lists . . . . . . . . . . . . 10.14Scratch token lists . . . . . . . . . . . . 10.15Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 342 344 345 346 348 348 350 353 355 355 357 360 365 365 366 l3seq implementation 11.1 Allocation and initialisation . . . 11.2 Appending data to either end . . 11.3 Modifying sequences . . . . . . . 11.4 Sequence conditionals . . . . . . 11.5 Recovering data from sequences 11.6 Mapping to sequences . . . . . . 11.7 Sequence stacks . . . . . . . . . 11.8 Viewing sequences . . . . . . . . 11.9 Scratch sequences . . . . . . . . 11.10Deprecated interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 369 371 371 373 374 377 379 380 380 381 . . . . . . . . . . xiv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 13 14 15 16 l3clist implementation 12.1 Allocation and initialisation . . 12.2 Removing spaces around items 12.3 Adding data to comma lists . . 12.4 Comma lists as stacks . . . . . 12.5 Modifying comma lists . . . . . 12.6 Comma list conditionals . . . . 12.7 Mapping to comma lists . . . . 12.8 Viewing comma lists . . . . . . 12.9 Scratch comma lists . . . . . . 12.10Deprecated interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 382 383 384 385 387 389 389 392 393 393 l3prop implementation 13.1 Allocation and initialisation . . . . . . . . . . . . . . . 13.2 Accessing data in property lists . . . . . . . . . . . . . 13.3 Property list conditionals . . . . . . . . . . . . . . . . 13.4 Recovering values from property lists with branching . 13.5 Mapping to property lists . . . . . . . . . . . . . . . . 13.6 Viewing property lists . . . . . . . . . . . . . . . . . . 13.7 Deprecated interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 395 396 400 401 402 403 403 l3box implementation 14.1 Creating and initialising boxes . . . . 14.2 Measuring and setting box dimensions 14.3 Using boxes . . . . . . . . . . . . . . . 14.4 Box conditionals . . . . . . . . . . . . 14.5 The last box inserted . . . . . . . . . 14.6 Constant boxes . . . . . . . . . . . . . 14.7 Scratch boxes . . . . . . . . . . . . . . 14.8 Viewing box contents . . . . . . . . . 14.9 Horizontal mode boxes . . . . . . . . 14.10Vertical mode boxes . . . . . . . . . . 14.11Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 404 406 406 406 407 407 407 408 409 410 412 l3coffins Implementation 15.1 Coffins: data structures and general variables 15.2 Basic coffin functions . . . . . . . . . . . . . 15.3 Measuring coffins . . . . . . . . . . . . . . . . 15.4 Coffins: handle and pole management . . . . 15.5 Coffins: calculation of pole intersections . . . 15.6 Aligning and typesetting of coffins . . . . . . 15.7 Coffin diagnostics . . . . . . . . . . . . . . . 15.8 Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412 412 414 418 418 421 424 429 434 l3color Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 xv . 17. . . 19. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6 Deprecated functions . . . . . . . . . . . . . . . . 19. . . . . . . .4 Hard-wrapping lines to a character 19. 18. . . . . . . . . . 19. . . . . . . . . . . . . . . count . . . . . . . . . . . . . . . . . . . . . 18. . . . . . . . . . . 17. . . . . . . . .1 File operations . . . . .2 Immediate writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19. . 17. . . . . . 19. . . . . . . . . .6 Setting keys . .3 The key defining mechanism . . . . . . . . . . .2 Messages: support functions and text . . . . . . . .3 Showing messages: low level mechanism 17. . . 17. . . . . . . . . . 436 436 438 439 441 448 453 455 456 l3keys Implementation 18. . . . .2 Input operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17. . . . . . . . . . .8 Messages . . . . . . . . . . . . . . .2. . .7 Utilities . . . . . . . . . . . . . . . . . . . . . . . .9 Deprecated functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17. . . . . . 459 459 462 464 465 470 473 476 477 478 . . . . . . . . . . . . . 18. . . . . . . . . . . 19. . . . . . . . . . . . . . .4 Stream management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19. . . . .2 Constants and variables . . . . 18. . . . . . . . . . . . . . . . . . . . . . . . . . . 478 479 483 484 484 486 487 487 488 489 490 490 490 496 496 . .7 Showing variables .3 Reading input . . . 19. . . . . . . . . . . . . . . . . 19. . .2 Stream management .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 Messages . . . . . . . . .1 Creating messages . . . . . .4 Turning properties into actions 18. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2. .8 Deprecated functions . . . . . .4 Displaying messages . . l3file implementation 19. . . . . .2. . . . . . . . . . . . . . . . . . . . . . 20 l3fp implementation 498 21 l3fp-aux implementation 498 xvi . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Deferred writing . . . . . . .5 Creating key properties . . . . . . . . . . . . . . . . . . .3 Special characters for writing . . . . . . . . . . . 18. . . .4. 19. . . . . 18. . .4. . . . . . . . . . 19. . .1 Low-level interface . . . . . .3 Output operations . . . . . . . . . . . 19. . . . . . .4. . . . . . . . . . . . . . . . . . . . .1 Variables and constants . . . . . . 18. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 Kernel-specific functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Variables and constants . . . . . . . . . . . .6 Expandable errors . . . . . . . . .17 18 19 l3msg implementation 17. . . . . . . . . . . . . . . 22. . . . . . . . . . . .2 Traps . . . . . . .1 Flags . . . . . . . . .3 Infix operators . .3 Overflow. . . . . . . . . . . . . . . . . . 23. . . . . . . . . . . .1 Storing results . . . . . . 23. . . . . . . . . . and exact zero . . . . . . 22. . . . . . .5 Packing digits . . . . . . . . . . . . . . . . . . . . . . . . . .1 Using arguments and semicolons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22. . . . . . . . . . underflow. . . . . . .9 Length of a floating point array . . . . . . . . . . . . . . . . . . . . . . . . parentheses. 24 l3fp-round implementation 516 24. . . .1 Rounding tools . 28. . . . . . .22 23 Internal storage of floating points numbers 22. .2 The round function . . . . . . . . . . . 28. . . . . . . . . . . 519 25 l3fp-parse implementation 521 26 Precedences 521 27 Evaluating an expression 522 28 Work plan 28. . . . . . . . . . 29 . . . . . . 510 511 511 515 515 . .7 Functions for use within primitive conditional branches 22. . . . . . . . . . . . . . . . . .4 Expanding after a floating point number . . . . . . . . . . . . . . . . . 28. .11Messages . . . . . . and functions . . . . . . . . . . . .4 Prefix operators. . . . . . . . . . . . . . . . . . . . . . . . 23. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . and structure of floating points . . . 22.4 Messages .3 Errors . . Internal representation . . . . .2 Precedence . . 28. . . . . . . . . . . . . . 498 498 499 501 501 503 505 507 508 509 509 510 l3fp-traps Implementation 23. . . . . . . . . .8 Small integer floating points . . . . . . . . . . . . . . . . . .5 Type detection . . . . . . . .6 Decimate (dividing by a power of 10) . . . . . . . . . . . 516 24. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22. . . . 22. . . . . . . . . . 22. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Constants. . . . . . . . . . . . . . . . . . . 22. . . . . . . 522 522 524 525 527 530 530 xvii . .10x-like expansion expandably . . . . . . . 22. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Unary minus. . . . 33. . 30.2. .5 Main functions . . . .3 Reading digits . . . . . . . . . . . . .2. . . . . .4 Floating point expression loops 32. .30 Internal parsing functions 30. . . . . . . . . . . . . . . . . . . 30. . xviii . . . . 31 Messages 32 l3fp-logic Implementation 32. . 32. . . . . . . .6 Beyond 16 digits: rounding 30. . . . . . . . . . . . . . . . . . .4. . exponent. . . . . . . .1 Trimming leading zeros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . and special numbers . . . . .3 Absolute subtraction . . . . . . . . .3 Implementing the significand division 33. . . . . . . . . . . . . . . . .2 Exact zero . . . . . . . . . . . . . . . . . . . . .1 Expansion control . . . . . . . . . . . . 33. . . . . . . . . . . . . 32.1 Syntax of internal functions . . . . .3 Comparison . . . . 30. . . . . . . . . . . . . 33. . . . . . . . . . . . . . . . . . . 30. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4.4. . . .7. . . . . . . . . . . . .7 Ternary operator . . . . . . 30. . .4. . . . . . . .3. . .2 Absolute addition . . . . . . . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . .8 Infix operators . . . . . . . 33 . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Existence test . . . . . . . . .4 Parsing one operand . . . . . . . . . . . . . . . . . .7 Prefix operators . .1 Signs. . . . .1 Sign. . . . . . . . . . . . not . . . . . .2 Work plan . . . . . . . . . . . . . . . . . .4. . . . . 30. . and special numbers . . . . . . . . . . . . . . . 30. 563 563 564 564 566 567 569 570 l3fp-basics Implementation 33. . . plus. . . . . . . . . . . . . . . .1 Common to several operations . . . 33. . . . . . . . . . . . . . . . . . . . . . . . . 30. . . . . . . . . . . 531 532 533 533 534 539 541 541 543 545 548 551 552 554 554 556 556 557 563 . . . . . . . . . .6 Main functions . . . . . . . . . . . . . . . . . . . .1 Identifiers . . . . . . . . . . .4 Large significand . . . .6 Boolean operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . and special numbers . . . 571 571 572 573 575 577 582 582 583 586 586 587 590 595 . . . . . . . . . . . . . . . . . . . . . . 30. . . . . .4. . . . . 30. . . . . . . . . . . . .2 Absolute multiplication . . . . 33. . . . . . . . . . . . . . . . . . . 30. .3 Other prefixes . . . .1 Signs. . . . . . . . . . . . . . . .2 Addition and subtraction . . . . 30. . . . . . . . . . . . . . .7. . 32. . . . . 32. . 30. . . . . . . . . . . . . . .5 Finding the exponent . . . . . . . . . . . .4 Division . . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33. . .2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33. . . . . . . . . . . . 33. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Fp object type .3 Multiplication . . . . . . . 32. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33. . . . . . . . . .5 Extrema . .5 Unary operations . . . . . . .7. . . . . . . . . . . . . . . . . 30. . . . 30. . . . . . . . . . . . . . . 33. . . . . . . . . . . . 33.3 Small significand . . . . . . . . . . . . . . . . . . . . . . . 37. . . . 34. . . . . . .2. 37. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 Description of extended fixed points . . . . . . . . . . . . list . . . . . . . . . . . . . . . . . . . . . . . . .1. 37. .2 Computing the power series . . . . . . . and special numbers 35. . . . . . . . .3 Sign. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Dividing a fixed point number by a small integer 34. . . . . . 37. . 37. . . . . . . . . .5 Formatting . . 34. . . . . . . . 627 627 628 631 632 634 l3fp-convert implementation 37. . . . . . .2 Scientific notation . . . . . . . . . . . . . . . . . . .5 Multiplying fixed points . . . . . . . . . . . . . . . . . . . . . . . .1. . . . . . . . . . . 34. . . . . .2 Updating values . . . . . . . . . . .6 Combining product and sum of fixed points . . .2 Some constants . . . . . . . . . . . . . . . . . . . exponent. . . . . . . . . . .4 Adding and subtracting fixed points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Decimal representation . . . 36. . . . . . . . . . . . . . . . . .3 Power . . l3fp-assign implementation 38.1. . . . . exponent. . . . . . . . . . . 34. .9 Convert an array of floating points . . . . . .1 Trimming trailing zeros . . . . . . . 38. . . . . .7 Convert from a dimension . . . . . . . . . . . . . . . . . . 38. . . . . . . . . and special numbers 35. . l3fp-old implementation 647 39. . . . . . 37. . . 607 607 607 608 608 608 616 616 620 Implementation 36. 637 637 637 639 640 641 641 642 643 644 . . . . . .1 Sign and special numbers . . . . . . . . . .2 Small and tiny arguments . . . . . .4 Absolute ln . . .1. . . . . . . to a comma . . . . .1. . . 35. . . . . . . . . . . . . . . . . .34 35 36 37 38 39 l3fp-extended implementation 34. . . . . . . . . . . . . . . . . . . . . . . . . . 37. . . . . . . . . 35. . . . . . . . .4 Token list representation .3 Showing values . . . . 35. . . .1 Compatibility . . . . . . . . . . . . .1 Assigning values . . . . . . . . . . . . . . . 595 595 596 597 598 599 600 602 l3fp-expo implementation 35. . . . . . . . . . . . . . .2 Helpers for extended fixed points . . 644 644 645 646 646 . . . . . . . . . 35. . . . . .1 Logarithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Reduction of large arguments 36. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Exponential . . . . . . 647 xix . . . . . . . . . . . . . . . . . . . . . . . . 36.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . .8 Use and eval . . 36.1 Sign. . . . . . . .4 Some useful constants and scratch variables . . . . . . . .1 Direct trigonometric functions . . . . . . . . . . . . . . . . . . . . . . .1. 38. . 37. . . . .7 Converting from fixed point to floating point . . . . . 34. . . . . . . . . . . . . . . . .1 Work plan . . .6 Convert to dimension or integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35. . . . . . . . 654 41 l3candidates Implementation 41. . . . . . . . . . . . . . .2 Affine transformations . . . . . . . . . . . . . . . . . . . . . . . 41. . . . . . . .2 Messages . . . . . . . . . . . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . . .14Additions to l3tokens . . . .5 Additions to l3coffins . . . . . . . . . 41. . . . . . . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13Additions to l3tl . . . . . . . . . . . . . . . . . . 41. . . . . . . . . 41. . .3 Deprecated functions . . . 41. . . . . . . . . . . . . . . .3 Viewing part of a box . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 651 40. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654 40. . . . . . . . . . . . . . . . . . . 41. . . .11Additions to l3seq . . . . . . .1 Category code tables . . . . . . . .4 Additions to l3clist . . . . . . . . . . .12Additions to l3skip . . . . . . . . . . . . . . . . . . . . . . . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . 41. . . . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6 Rotating coffins . . . . . . . . . . Index . . . . . . . . . . . . . 41. . . . . . . . . . . . . . . . . . . . . . . . . . 655 655 655 663 665 669 669 673 676 677 677 678 682 683 686 689 xx . . . . . . . . . . . .8 Additions to l3file . . .40 l3luatex implementation 650 40. . . . . . . . .7 Resizing coffins . . . . . . . . . . . . . .10Additions to l3prop . . . . . .1 Additions to l3box . . . .9 Additions to l3fp . . The complete list of arg-spec letters for a function is referred to as the signature of the function. for example \foo:v {MyVariable}. Most functions take one or more arguments. In general. 1 . all functions concerned with comma lists are in module clist and begin \clist_. However. each argument is represented by a single letter. and then the value is recovered. The name of each function is divided into logical units using _. on the other hand. Thus apart from a small number of very basic functions. this will be blank and the function name will end :. all expl3 function names contain at least one underscore to divide the module name from the descriptive name of the function. V and v These mean value of variable. o This means expansion once. Every function must include an argument specifier. Instead. and use the following argument specifiers: D The D specifier means do not use. c This means csname. using v a csname is constructed first. Only the kernel team should use anything with a D specifier! N and n These mean no manipulation. o is useful for correctly processing information with delimited arguments. Both pass the argument through exactly as given. For functions which take no arguments. and indicates that the argument will be turned into a csname before being used. all will be well. and some are then given a second name. the symbols _ and : are used in internal macro names to provide structure. This describes the arguments expected by the function. while : separates the name of the function from the argument specifier (“arg-spec”).pdf. The V and v specifiers are used to get the content of a variable without needing to worry about the underlying TEX structure containing the data. A V argument will be a single token (similar to N). the V and v specifiers are favoured over o for recovering stored information. A general guide to the LATEX3 programming language is found in expl3. of a single token for N and of a set of tokens given in braces for n. if you use a single token for an n argument. In most cases.Part I Introduction to expl3 and this document This document is intended to act as a comprehensive reference manual for the expl3 language. Each function name starts with the module to which it belongs. Usually. 1 Naming functions and variables LATEX3 does not use @ as a “letter” for defining internal macros. for example \foo:V \MyVariable. For example. All of the TEX primitives are initially \let to a D name. So So \foo:c {ArgumentOne} will act in the same way as \foo:N \ArgumentOne. the int module contains some scratch variables called \l_tmpa_int. In such a case adding the module name up front to denote the module and in the back to indicate the type. g Parameters whose value should only be set globally. For example. f The f specifier stands for full expansion. there is the w specifier for weird arguments. Notice that the argument specifier describes how the argument is processed prior to being passed to the underlying function. Functions which feature an x-type argument are in general not expandable. there are the branch specifiers T (true) and F (false). box Box register. p The letter p indicates TEX parameters. Each variable name is then build up in a similar way to that of a function. T and F For logic tests. For example. and in contrast to x stops at the first nonexpandable item (reading the argument from left to right) without trying to expand it. w Finally. unless specifically noted. but mainly applies to delimited values (where the argument must be terminated by some arbitrary string).g. when setting a token list variable (a macro used for storage). Variables end with a short identifier to show the variable type: bool Either true or false. l Parameters whose value should only be set locally.. e. \foo:c will take its argument. but make the logic much easier to see. Normally this will be used for delimited functions as expl3 provides better methods for creating simple sequential arguments.x The x specifier stands for exhaustive expansion: every token in the argument is fully expanded until only unexpandable ones remain. convert it to a control sequence and pass it to \foo:N. This covers everything else. but begin with a single letter to define the type of variable: c Constant: global parameters whose value should not be changed. \l_tmpb_int. typically starting with the module1 name and then a descriptive part. the sequence \tl_set:Nn \l_mya_tl { A } \tl_set:Nn \l_myb_tl { B } \tl_set:Nf \l_mya_tl { \l_mya_tl \l_myb_tl } will leave \l_mya_tl with the content A\l_myb_tl. The TEX \edef primitive carries out this type of expansion. as A cannot be expanded and so terminates expansion before \l_myb_tl is considered. Both specifiers treat the input in the same way as n (no change). 2 . 1 The module names are not used in case of generic scratch registers defined in the data type modules. as in \l_int_tmpa_int would be very unreadable. and so on. Variables are named in a similar manner to functions. when actually we just mean “the macro expands to something”.1 Terminological inexactitude A word of warning. In this document. fp floating-point values. and functions are simply macros that may or may not take arguments and expand to their replacement text. please ask. and others referring to the expl3 programming modules. This means that sometimes we will use phrases like “the function returns a value”. and a consistent wrapper is applied to all forms of “data” whether they be macros or actually registers. and if placed into the input stream will simply expand to their definition as well — a “function” with no arguments and a “token list variable” are in truth one and the same. several conventions are used to help describe the features of the code. respectively). the term “execute” might be used in place of “expand” or it might refer to the more specific case of “processing in TEX’s stomach” (if you are familiar with the TEXbook parlance). stream An input or output stream (for reading from or writing to. If in doubt. 2 Documentation conventions This document is typeset with the experimental l3doc class.clist Comma separated list. chances are we’ve been hasty in writing certain definitions and need to be told to tighten up our terminology. 1. tl Token list variables: placeholder for a token list. skip “Rubber” lengths. dim “Rigid” lengths. In truth. int Integer-valued count register. we often refer to “variables” and “functions” as if they were actual constructs from a real programming language. prop Property list. seq “Sequence”: a data-type used to implement lists (with access at both ends) and stacks. The conventions of the expl3 code are designed to clearly separate the ideas of “macros that contain data” and “macros that contain code”. some “variables” are actually registers that must be initialised and their values set and retrieved with specific functions. A number of conventions are used here to make the documentation clearer. 3 . TEX is a macro processor. On the other hand. Many of the common variables are also macros. Similarly. coffin a “box with handles” — a higher-level data type for carrying out box alignment operations. For a function with a “user” name. Here. To indicate this without repetition. which allows it to be used within an x-type argument (in plain TEX terms. inside an \edef). \ExplSyntaxOff The textual description of how the function works would appear here. Restricted expandable functions A few functions are fully expandable but cannot be fully expanded within an f-type argument. In this case. only the star will indicate that the function is expandable. but as a name rather than as a control sequence. this information is given in a shortened form: 4 . Fully expandable functions Some functions are fully expandable. For programming functions. these are termed variants of each other. From the argument specifier. This allows them to be used for different “true”/“false” branches. F and TF argument specifiers. the function takes no arguments and so the name of the function is simply reprinted... the function expects a hcsi. These fully expandable functions are indicated in the documentation by a star: \cs_to_str:N ? \cs_to_str:N hcs i As with other functions. this might read: \ExplSyntaxOn \ExplSyntaxOff \seq_new:N \seq_new:c \ExplSyntaxOn . which use _ and : in their name there are a few additional conventions: If two related functions are given with identical names but different argument specifiers. They will carry out the same function but will take different types of argument: \seq_new:N hsequence i When a number of variants are described. the arguments are usually illustrated only for the base function. The syntax of the function is shown in mono-spaced text to the right of the box. as well as within an f-type argument.Each group of related functions is given in a box. some text should follow which explains how the function works. \seq_new:c also expects a sequence name. depending on which outcome the conditional is being used to test. Usually. with T. In this case a hollow star is used to indicate this: \seq_map_function:NN I \seq_map_function:NN hseq i hfunction i Conditional functions Conditional (if) functions are normally defined in three variants. and the latter functions are printed in grey to show this more clearly. shorthand for a hcontrol sequencei. Each argument given in the illustration should be described in the following text. hsequencei indicates that \seq_new:N expects the name of a sequence. In this example. the function is similar to one in LATEX 2ε or plain TEX. Formal ideas which apply to general classes of function are therefore summarised here. it would point out that this function is the TEX primitive \string. Usually. the test if evaluated to give a logically TRUE or FALSE result. In this case. In some cases. the functions provided here may break when used on top of LATEX 2ε if \outer tokens are used in the arguments. and so both htrue codei and hfalse codei will be shown. Here. the text will include an extra “TEXhackers note” section: \token_to_str:N htoken i The normal description text. TEXhackers note: Detail for the experienced TEX or LATEX 2ε programmer. For tests which have a TF argument specification. Variables. As such. either the htrue codei or the hfalse codei will be left in the input stream. the logical value determined by the test is left in the input stream: this will typically be part of a larger logical construct. 4 TEX concepts not supported by LATEX3 The TEX concept of an “\outer” macro is not supported at all by LATEX3. In the case where the test is expandable. constants and so on are described in a similar manner: \l_tmpa_tl \token_to_str:N ? A short piece of text will describe the variable: there is no syntax illustration in this case. The two variant forms T and F take only htrue codei and hfalse codei. all conditional functions in the expl3 modules should be defined in this way. 5 . respectively. and a predicate (_p) variant is available. Depending on this result. the illustration will use the TF variant. there is also a need to avoid repetition. 3 Formal language conventions which apply generally As this is a formal reference guide for LATEX3 programming. the star also shows that this function is expandable.\xetex_if_engine:TF ? \xetex_if_engine:TF {htrue code i} {hfalse code i} The underlining and italic of TF indicates that \xetex_if_engine:T. the descriptions of functions are intended to be reasonably “complete”. With some minor exceptions. \xetex_if_engine:F and \xetex_if_engine:TF are all available. In these cases. However. \ExplFileVersion for version and \ExplFileDescription for the description. The information pieces are stored in separate control sequences with \ExplFileName for the part of the file name leading up to the period. See implementation for details. These modules will also form the basis of the LATEX3 format. Within this environment. but work in this area is incomplete and not included in this documentation at present. \ExplSyntaxOff will be called to reverse this. At the end of the file. \ProvidesClass and \ProvidesFile. The \ExplSyntaxOff reverts to the document category code régime.Part II The l3bootstrap package Bootstrap code 1 Using the LATEX3 modules The modules documented in source3 are designed to be used on top of LATEX 2ε and are loaded all as one with the usual \usepackage{expl3} or \RequirePackage{expl3} instructions. thus allowing access to the names of code functions and variables. To summarize: Every single package using this syntax should identify itself using one of the above methods. \ExplFileDate for date. \ExplSyntaxOn \ExplSyntaxOff Updated: 2011-08-13 \ProvidesExplPackage \ProvidesExplClass \ProvidesExplFile \GetIdInfo \ExplSyntaxOn hcode i \ExplSyntaxOff The \ExplSyntaxOn function switches to a category code régime in which spaces are ignored and in which the colon (:) and underscore (_) are treated as “letters”. As the modules use a coding syntax different from standard LATEX 2ε it provides a few functions for setting it up. Special care is taken so that every package or class file loaded with \RequirePackage or alike are loaded with usual LATEX 2ε category codes and the LATEX3 category code scheme is reloaded when needed afterwards.) \RequirePackage{l3bootstrap} \GetIdInfo $Id: hSVN info field i $ {hdescription i} Updated: 2012-06-04 Extracts all information from a SVN field. However. If you use the \GetIdInfo command you can use the information when loading a package with \ProvidesExplPackage{\ExplFileName} {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} 6 . they also implicitly switch \ExplSyntaxOn for the remainder of the code with the file. ~ is used to input a space. \RequirePackage{expl3} \ProvidesExplPackage {hpackage i} {hdate i} {hversion i} {hdescription i} These functions act broadly in the same way as the LATEX 2ε kernel functions \ProvidesPackage. (This is the same concept as LATEX 2ε provides in turning on \makeatletter within package and class code. Spaces are not ignored in these fields. 1.1 \__expl_package_check: Internal functions and variables \__expl_package_check: Used to ensure that all parts of expl3 are loaded together (i. This variable should only be set by \ExplSyntaxOn/\ExplSyntaxOff. Issues an error if a kernel package is loaded independently of the bundle. \l__kernel_expl_bool A boolean which records the current code syntax status: true if currently inside a code environment.e. as part of expl3). 7 . Introduced by TEX itself. \pdftex_. TEX by Topic and the manuals for pdfTEX.. It performs the following tasks: • defines new names for all TEX primitives. This module is entirely dedicated to primitives.. As such. \xetex_.. 8 . Introduced by XETEX. the primitives are not documented here: The TEXbook. XETEX and LuaTEX should be consulted for details of the primitives... \etex_. Introduced by LuaTEX. • switches to the category code régime for programming... Introduced by pdfTEX. Introduced by the ε-TEX extensions.. • provides support settings for building the code as a TEX format.. These are named based on the engine which first introduced them: \tex_.. which should not be used directly within LATEX3 code (outside of “kernel-level” code).Part III The l3names package Namespace for primitives 1 Setting up the LATEX3 programming language This module is at the core of the LATEX3 programming language. \luatex_. Here we describe those functions that are used all over the place. With that we mean functions dealing with the construction and testing of control sequences. Indeed. Assignments are local to groups unless carried out in a global manner. \scan_stop: \scan_stop: A non-expandable function which does nothing.Part IV The l3basics package Basic definitions As the name suggest this package holds some basic definitions which are needed by most or all other packages in this set. 2 \group_begin: \group_end: Grouping material \group_begin: \group_end: These functions begin and end a group for definition purposes. Furthermore the basic parts of conditional processing are covered. \group_insert_after:N \group_insert_after:N htoken i Adds htokeni to the list of htokensi to be inserted when the current group level ends. it is often necessary to start a group within one function and finish it within another. for example when seeking to use non-standard category codes. conditional processing dealing with specific data types is described in the modules specific for the respective data types.) Each \group_begin: must be matched by a \group_end:. 9 . The current group level may be closed by a \group_end: function or by a token with category code 2 (close-group). Does not vanish on expansion but produces no typeset output. 1 \prg_do_nothing: ? No operation functions \prg_do_nothing: An expandable function which does nothing at all: leaves nothing in the input stream after a single expansion. (A small number of exceptions to this rule will be noted as necessary elsewhere in this document. The list of htokensi to be inserted will be empty at the beginning of a group: multiple applications of \group_insert_after:N may be used to build the inserted list one htokeni at a time. although this does not have to occur within the same function. The later will be a } if standard category codes apply. new Create a new function with the new scope. #2. etc.2 and 3. There are three ways to define new functions. Base functions can only have the following argument specifiers: N and n No manipulation. Within each set of scope there are different ways to define a function. #2.3 are primarily meant to define base functions only. protected Create a new function with the protected restriction. set Create a new function with the set scope. hcodei is therefore used as a shorthand for “replacement text”. 10 . ). In contrast. The parameter may contain \par tokens but the function will not expand within an x-type expansion. Finally. The parameter may not contain \par tokens. Declaring a function before setting up the code means that the name chosen will be checked and an error raised if it is already in use. nopar Create a new function with the nopar restriction. such as \cs_new:Npn. . Within the substitution text the actual parameters are substituted for the formal parameters (#1. T and F Functionally equivalent to n (you are actually encouraged to use the family of \prg_new_conditional: functions described in Section ??). The definition is restricted to the current TEX group and will not result in an error if the function is already defined. The name of a function can be checked at the point of definition using the \cs_new. which must always be declared).. the functions in Subsections 3. such as \cs_set_nopar:Npn. such as \cs_set_protected:Npn. All classes define a function to expand to the substitution text.) is replaced the appropriate arguments absorbed by the function.1 Defining functions Functions can be created with no requirement that they are declared first (in contrast to variables. a function is replaced by the replacement text (“code”) in which each parameter in the code (#1. The definition is global and will result in an error if it is already defined. At point of use. “protected” functions are not expanded within x expansions. such as \cs_gset:Npn. creating new functions means creating macros. such as \cs_set:Npn. The definition is global and will not result in an error if the function is already defined. 3..3 Control sequences and functions As TEX is a macro language. Functions which are not “protected” will be fully expanded inside an x expansion. . functions: this is recommended for all functions which are defined for the first time. . gset Create a new function with the gset scope. The differences depend on restrictions on the actual parameters and the expandability of the resulting function. In the following. but they do not handle expansion for you. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. Within the hcodei. The definition is global and an error will result if the hfunctioni is already defined.) will be replaced by those absorbed by the function. the hparametersi (#1. #2. etc. #2. etc. The definition is global and an error will result if the hfunctioni is already defined. #2.p and w These are special cases.) will be replaced by those absorbed by the function. \cs_new_protected_nopar:Npn \cs_new_protected_nopar:(cpn|Npx|cpx) \cs_new_protected_nopar:Npn hfunction i hparameters i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. the hparametersi (#1. etc. #2.) will be replaced by those absorbed by the function. Within the hcodei. the hparametersi (#1. \cs_new_nopar:Npn hfunction i hparameters i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. You should define the base function and then use \cs_generate_variant:Nn to generate custom variants as described in Section 1. The hfunctioni will not expand within an x-type argument. \cs_set:Npn \cs_set:(cpn|Npx|cpx) \cs_set:Npn hfunction i hparameters i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. #2. etc. \cs_new_protected:Npn \cs_new_protected:(cpn|Npx|cpx) \cs_new_protected:Npn hfunction i hparameters i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. Within the hcodei.2 \cs_new:Npn \cs_new:(cpn|Npx|cpx) \cs_new_nopar:Npn \cs_new_nopar:(cpn|Npx|cpx) Defining new functions using parameter text \cs_new:Npn hfunction i hparameters i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. The \cs_new: functions below (and friends) do not stop you from using other argument specifiers in your function names. The definition is global and an error will result if the hfunctioni is already defined. Within the hcodei.) will be replaced by those absorbed by the function. Within the hcodei. the hparametersi (#1. 3. etc. The hfunctioni will not expand within an x-type argument. 11 . the hparametersi (#1.) will be replaced by those absorbed by the function. The definition is global and an error will result if the hfunctioni is already defined. the hparametersi (#1. #2. \cs_gset_protected:Npn \cs_gset_protected:(cpn|Npx|cpx) \cs_gset_protected:Npn hfunction i hparameters i {hcode i} Globally sets hfunctioni to expand to hcodei as replacement text. The assignment of a meaning to the hfunctioni is not restricted to the current TEX group level: the assignment is global. The hfunctioni will not expand within an x-type argument.) will be replaced by those absorbed by the function. \cs_set_protected:Npn \cs_set_protected:(cpn|Npx|cpx) \cs_set_protected:Npn hfunction i hparameters i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. Within the hcodei. Within the hcodei. The assignment of a meaning to the hfunctioni is not restricted to the current TEX group level: the assignment is global. #2.) will be replaced by those absorbed by the function. the hparametersi (#1. the hparametersi (#1. etc.) will be replaced by those absorbed by the function. \cs_gset:Npn \cs_gset:(cpn|Npx|cpx) \cs_gset_nopar:Npn \cs_gset_nopar:(cpn|Npx|cpx) \cs_gset:Npn hfunction i hparameters i {hcode i} Globally sets hfunctioni to expand to hcodei as replacement text. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. The assignment of a meaning to the hfunctioni is not restricted to the current TEX group level: the assignment is global. etc. the hparametersi (#1. etc. Within the hcodei.) will be replaced by those absorbed by the function. etc. The hfunctioni will not expand within an x-type argument. Within the hcodei. Within the hcodei. Within the hcodei. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. \cs_gset_nopar:Npn hfunction i hparameters i {hcode i} Globally sets hfunctioni to expand to hcodei as replacement text. etc. \cs_set_protected_nopar:Npn \cs_set_protected_nopar:(cpn|Npx|cpx) \cs_set_protected_nopar:Npn hfunction i hparameters i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. #2. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. the hparametersi (#1. #2.\cs_set_nopar:Npn \cs_set_nopar:(cpn|Npx|cpx) \cs_set_nopar:Npn hfunction i hparameters i {hcode i} Sets hfunctioni to expand to hcodei as replacement text.) will be replaced by those absorbed by the function. #2. 12 . When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. the hparametersi (#1. The hfunctioni will not expand within an x-type argument. etc.) will be replaced by those absorbed by the function. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. #2. #2. These hparametersi (#1.) will be replaced by those absorbed by the function. #2. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. etc. the number of hparametersi is detected automatically from the function signature.) will be replaced by those absorbed by the function.) will be replaced by those absorbed by the function. \cs_new_protected:Nn hfunction i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. the hparametersi (#1. The assignment of a meaning to the hfunctioni is not restricted to the current TEX group level: the assignment is global. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. The hfunctioni will not expand within an x-type argument. The definition is global and an error will result if the hfunctioni is already defined. Within the hcodei. \cs_new_protected_nopar:Nn \cs_new_protected_nopar:(cn|Nx|cx) \cs_new_protected_nopar:Nn hfunction i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. Within the hcodei. These hparametersi (#1. #2. These hparametersi (#1. 3. etc. The definition is global and an error will result if the hfunctioni is already defined. Within the hcodei. the number of hparametersi is detected automatically from the function signature. \cs_new_nopar:Nn hfunction i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. The hfunctioni will not expand within an x-type argument. #2. #2.\cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:(cpn|Npx|cpx) \cs_gset_protected_nopar:Npn hfunction i hparameters i {hcode i} Globally sets hfunctioni to expand to hcodei as replacement text.) will be replaced by those absorbed by the function. the number of hparametersi is detected automatically from the function signature. etc. The hfunctioni will not expand within an x-type argument. The definition is global and an error will result if the hfunctioni is already defined.) will be replaced by those absorbed by the function. 13 . Within the hcodei. These hparametersi (#1. Within the hcodei. the number of hparametersi is detected automatically from the function signature.3 \cs_new:Nn \cs_new:(cn|Nx|cx) \cs_new_nopar:Nn \cs_new_nopar:(cn|Nx|cx) \cs_new_protected:Nn \cs_new_protected:(cn|Nx|cx) Defining new functions using the signature \cs_new:Nn hfunction i {hcode i} Creates hfunctioni to expand to hcodei as replacement text. etc. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. The definition is global and an error will result if the hfunctioni is already defined. etc. 14 . etc. etc. Within the hcodei. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. #2. #2. the number of hparametersi is detected automatically from the function signature. These hparametersi (#1. Within the hcodei. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens.) will be replaced by those absorbed by the function. \cs_set_protected:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. etc. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. The assignment of a meaning to the hfunctioni is global.) will be replaced by those absorbed by the function. #2. etc. the number of hparametersi is detected automatically from the function signature. \cs_gset:Nn \cs_gset:(cn|Nx|cx) \cs_gset_nopar:Nn \cs_gset_nopar:(cn|Nx|cx) \cs_gset:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. #2. Within the hcodei. Within the hcodei. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. These hparametersi (#1. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. The hfunctioni will not expand within an x-type argument. the number of hparametersi is detected automatically from the function signature. etc. Within the hcodei.) will be replaced by those absorbed by the function.) will be replaced by those absorbed by the function. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. #2. The assignment of a meaning to the hfunctioni is restricted to the current TEX group level. the number of hparametersi is detected automatically from the function signature.) will be replaced by those absorbed by the function. Within the hcodei. These hparametersi (#1. the number of hparametersi is detected automatically from the function signature. \cs_set_protected_nopar:Nn \cs_set_protected_nopar:(cn|Nx|cx) \cs_set_protected_nopar:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text.) will be replaced by those absorbed by the function. These hparametersi (#1. \cs_gset_nopar:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. the number of hparametersi is detected automatically from the function signature. These hparametersi (#1. #2.\cs_set:Nn \cs_set:(cn|Nx|cx) \cs_set_nopar:Nn \cs_set_nopar:(cn|Nx|cx) \cs_set_protected:Nn \cs_set_protected:(cn|Nx|cx) \cs_set:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. These hparametersi (#1. \cs_set_nopar:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. The hfunctioni will not expand within an x-type argument. The assignment of a meaning to the hfunctioni is global. etc. the number of hparametersi is detected automatically from the function signature.) will be replaced by those absorbed by the function. etc. #2. 3. The second control sequence may subsequently be altered without affecting the copy. the number of hparametersi is detected automatically from the function signature. Within the hcodei. \cs_new_eq:NN \cs_new_eq:(Nc|cN|cc) \cs_new_eq:NN hcs1 i hcs2 i \cs_new_eq:NN hcs1 i htoken i Globally creates hcontrol sequence1 i and sets it to have the same meaning as hcontrol sequence2 i or htokeni. 15 . The assignment of a meaning to the hfunctioni is global. \cs_generate_from_arg_count:NNnn \cs_generate_from_arg_count:(cNnn|Ncnn) \cs_generate_from_arg_count:NNnn hfunction i hcreator i hnumber i hcode i Updated: 2012-01-14 Uses the hcreatori function (which should have signature Npn. Within the hcodei. The hnumberi of arguments is an integer expression. These hparametersi (#1. for example \cs_new:Npn) to define a hfunctioni which takes hnumberi arguments and has hcodei as replacement text. The assignment of a meaning to the hfunctioni is global. \cs_gset_protected_nopar:Nn \cs_gset_protected_nopar:(cn|Nx|cx) \cs_gset_protected_nopar:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text. etc.4 Copying control sequences Control sequences (not just functions as defined above) can be set to have the same meaning using the functions described here. The hfunctioni will not expand within an x-type argument. These hparametersi (#1. When the hfunctioni is used the hparametersi absorbed cannot contain \par tokens. In the following text “cs” is used as an abbreviation for “control sequence”. evaluated as detailed for \int_eval:n. The hfunctioni will not expand within an x-type argument. #2.\cs_gset_protected:Nn \cs_gset_protected:(cn|Nx|cx) \cs_gset_protected:Nn hfunction i {hcode i} Sets hfunctioni to expand to hcodei as replacement text.) will be replaced by those absorbed by the function. Making two control sequences equivalent means that the second control sequence is a copy of the first (rather than a pointer to it). Thus the old and new control sequence are not tied together: changes to one are not reflected in the other. The assignment of a meaning to the hcontrol sequence1 i is restricted to the current TEX group level. The second control sequence may subsequently be altered without affecting the copy. wrapped to a fixed number of characters per line. \cs_undefine:N \cs_undefine:c \cs_undefine:N hcontrol sequence i Sets hcontrol sequencei to be globally undefined. 3.\cs_set_eq:NN \cs_set_eq:(Nc|cN|cc) \cs_set_eq:NN hcs1 i hcs2 i \cs_set_eq:NN hcs1 i htoken i Sets hcontrol sequence1 i to have the same meaning as hcontrol sequence2 i (or htokeni).5 Deleting control sequences There are occasions where control sequences need to be deleted. The assignment of a meaning to the hcontrol sequence1 i is not restricted to the current TEX group level: the assignment is global. 16 . Updated: 2012-09-09 TEXhackers note: This is similar to the TEX primitive \show. This is handled in a very simple manner. TEXhackers note: This is TEX’s \meaning primitive. This will show the hreplacement texti for a macro. The second control sequence may subsequently be altered without affecting the copy. \cs_show:N \cs_show:c \cs_show:N hcontrol sequence i Displays the definition of the hcontrol sequencei on the terminal.6 \cs_meaning:N ? \cs_meaning:c ? Updated: 2011-12-22 Showing control sequences \cs_meaning:N hcontrol sequence i This function expands to the meaning of the hcontrol sequencei control sequence. \cs_gset_eq:NN \cs_gset_eq:(Nc|cN|cc) \cs_gset_eq:NN hcs1 i hcs2 i \cs_gset_eq:NN hcs1 i htoken i Globally sets hcontrol sequence1 i to have the same meaning as hcontrol sequence2 i (or htokeni). The c variant correctly reports undefined arguments. Updated: 2011-09-15 3. when fully expanded. or a mixture of these. The hcontrol sequence namei must. they will be of category code 10 (space). they will be of category code 10 (space). \cs_if_exist_use:NTF \cs_if_exist_use:cTF New: 2012-11-10 \cs_if_exist_use:NTF ? \cs_if_exist_use:cTF ? New: 2012-11-10 \cs:w ? \cs_end: ? \cs_if_exist_use:N hcontrol sequence i Tests whether the hcontrol sequencei is currently defined (whether as a function or another control sequence type).3. The content for hcontrol sequence namei may be literal material or from other expandable functions. TEXhackers note: These are the TEX primitives \csname and \endcsname. or a mixture of these. The content for hcontrol sequence namei may be literal material or from other expandable functions. consist of character tokens which are not active: typically. and if it does inserts the hcontrol sequencei into the input stream followed by the htrue codei. 11 (letter) or 12 (other). This process requires one expansion. \cs_if_exist_use:NTF hcontrol sequence i {htrue code i} {hfalse code i} Tests whether the hcontrol sequencei is currently defined (whether as a function or another control sequence type). The hcontrol sequence namei must. both \cs:w a b c \cs_end: and 17 . As an example of the \cs:w and \cs_end: functions. consist of character tokens which are not active: typically. As an example of the \use:c function.7 \use:c ? Converting to and from control sequences \use:c {hcontrol sequence name i} Converts the given hcontrol sequence namei into a single control sequence token. both \use:c { a b c } and \tl_new:N \l_my_tl \tl_set:Nn \l_my_tl { a b c } \use:c { \tl_use:N \l_my_tl } would be equivalent to \abc after two expansions of \use:c. 11 (letter) or 12 (other). when fully expanded. and if it does inserts the hcontrol sequencei into the input stream. \cs:w hcontrol sequence name i \cs_end: Converts the given hcontrol sequence namei into a single control sequence token. This process requires two expansions. an f-expansion will be correct as well. the category code is determined by the the situation in force when first function absorbs the token). The sequence will not include the current escape token. only the outer braces will be removed. the category code of each token is set when the token is read by a function (if it is read more than once. 18 . these functions will absorb between one and four arguments. so that one expansion of \use:nn { abc } { { def } } will result in the input stream containing abc { def } i. but this loses a space at the start of the result. as indicated by the argument specifier. \cs_to_str:N ? \cs_to_str:N hcontrol sequence i Converts the given hcontrol sequencei into a series of characters with category code 12 (other). The braces surrounding each argument will be removed leaving the remaining tokens in the input stream. If one or more tokens are wrapped in braces then in absorbing them the outer set will be removed. In most cases. All of these functions require only a single expansion to operate. 4 Using or removing tokens and arguments Tokens in the input can be read and used or read and discarded. At the same time. \use:n ? \use:(nn|nnn|nnnn) ? \use:n \use:nn \use:nnn \use:nnnn {hgroup1 i} {hgroup1 i} {hgroup2 i} {hgroup1 i} {hgroup2 i} {hgroup3 i} {hgroup1 i} {hgroup2 i} {hgroup3 i} {hgroup4 i} As illustrated. \token_to_str:N. or two o-type expansions will be required to convert the hcontrol sequencei to a sequence of characters in the input stream. cf. and so an x-type expansion. Full expansion of this function requires exactly 2 expansion steps.\tl_new:N \l_my_tl \tl_set:Nn \l_my_tl { a b c } \cs:w \tl_use:N \l_my_tl \cs_end: would be equivalent to \abc after one expansion of \cs:w. The category code of these tokens will also be fixed by this process (if it has not already been by some other absorption). of category code 10. except spaces.e. third or fourth arguments in the input stream. \use_i:nnn {harg1 i} {harg2 i} {harg3 i} These functions absorb three arguments from the input stream. \use_iii:nnnn and \use_iv:nnnn work similarly. The function \use_i:nn discards the second argument. \use_i:nnnn {harg1 i} {harg2 i} {harg3 i} {harg4 i} These functions absorb four arguments from the input stream. an N argument). \use_none:n ? \use_none:(nn|nnn|nnnn|nnnnn|nnnnnn|nnnnnnn|nnnnnnnn|nnnnnnnnn) ? \use_none:n {hgroup1 i} These functions absorb between one and nine groups from the input stream. The function \use_i:nnn discards the second and third arguments. the outer braces will be removed and the third group will be removed. The function \use_i:nnnn discards the second. \use_ii:nnnn. An example: \use_i_ii:nnn { abc } { { def } } { ghi } will result in the input stream containing abc { def } i. leaving nothing on the resulting input stream. and leaves the content of the first argument in the input stream. and leaves the content of the first argument in the input stream. 19 . One or more of the n arguments may be an unbraced single token (i.e. The category code of these tokens will also be fixed (if it has not already been by some other absorption). \use_ii:nnn and \use_iii:nnn work similarly.\use_i:nn ? \use_ii:nn ? \use_i:nnn ? \use_ii:nnn ? \use_iii:nnn ? \use_i:nnnn \use_ii:nnnn \use_iii:nnnn \use_iv:nnnn ? ? ? ? \use_i_ii:nnn ? \use_i:nn {harg1 i} {harg2 i} These functions absorb two arguments from the input stream. respectively. A single expansion is needed for the functions to take effect. respectively. The category code of these tokens will also be fixed (if it has not already been by some other absorption). and leaves the content of the first argument in the input stream. \use_i_ii:nnn {harg1 i} {harg2 i} {harg3 i} This functions will absorb three arguments and leave the content of the first and second in the input stream. leaving the content of second or third arguments in the input stream. leaving the content of second. third and fourth arguments. The category code of these tokens will also be fixed (if it has not already been by some other absorption).e. These functions work after a single expansion. A single expansion is needed for the functions to take effect. The category code of these tokens will also be fixed (if it has not already been by some other absorption). A single expansion is needed for the functions to take effect. A single expansion is needed for the functions to take effect. \use_ii:nn discards the first argument and leaves the content of the second argument in the input stream. These arguments are denoted with T and F. An example would be \cs_if_free:cTF {abc} {htrue codei} {hfalse codei} a function that will turn the first argument into a control sequence (since it’s marked as c) then checks whether this control sequence is still free and then depending on the result carry out the code in the second argument (true case) or in the third argument (false case). respectively.\use:x \use:x {hexpandable tokens i} Updated: 2011-12-31 Fully expands the hexpandable tokensi and inserts the result into the input stream at the current location. leaving nothing in the input stream. Package writers are free to choose which types to define but the kernel definitions will always provide all three versions. either the code supplied as the htrue codei or the hfalse codei. \use_none_delimit_by_q_nil:w ? \use_none_delimit_by_q_stop:w ? \use_none_delimit_by_q_recursion_stop:w ? \use_none_delimit_by_q_nil:w hbalanced text i \q_nil \use_none_delimit_by_q_stop:w hbalanced text i \q_stop \use_none_delimit_by_q_recursion_stop:w hbalanced text i \q_recursion_stop Absorb the hbalanced texti form the input stream delimited by the marker given in the function name. leaving hinserted tokensi in the input stream for further processing. whenever a TF function is defined it will usually be accompanied by T and F functions as well.1 Selecting tokens from delimited arguments A different kind of function for selecting tokens from the token stream are those that use delimited arguments. These are provided for convenience when the branch only needs to go a single way. 5 Predicates and conditionals LATEX3 has three concepts for conditional flow processing: Branching conditionals Functions that carry out a test and then execute. 20 . These type of functions are known as “conditionals”. depending on its result. Any hash characters (#) in the argument must be doubled. 4. \use_i_delimit_by_q_nil:nw ? \use_i_delimit_by_q_stop:nw ? \use_i_delimit_by_q_recursion_stop:nw ? \use_i_delimit_by_q_nil:nw {hinserted tokens i} hbalanced text i \q_nil \use_i_delimit_by_q_stop:nw {hinserted tokens i} hbalanced text i \q_stop \use_i_delimit_by_q_recursion_stop:nw {hinserted tokens i} hbalanced text i \q_recursion_stop Absorb the hbalanced texti form the input stream delimited by the marker given in the function name. Any valid definition of hcontrol sequencei will evaluate as true. For example. Their use is discouraged in expl3 (although still used in low-level definitions) because they are more fragile and in many cases require more expansion control (hence more code) than the two types of conditionals described above. but if they are expandable they will be accompanied by a “predicate” for the same test as described below. i. \c_true_bool \c_false_bool Constants that represent true and false. a “branching conditional” will also exist that behaves like a conditional described above.1 \cs_if_eq_p:NN ? \cs_if_eq:NNTF ? Tests on control sequences \cs_if_eq_p:NN {hcs1 i} {hcs2 i} \cs_if_eq:NNTF {hcs1 i} {hcs2 i} {htrue code i} {hfalse code i} Compares the definition of two hcontrol sequencesi and is logically true the same. \cs_if_exist_p:N \cs_if_exist_p:c \cs_if_exist:NTF \cs_if_exist:cTF ? ? ? ? \cs_if_exist_p:N hcontrol sequence i \cs_if_exist:NTF hcontrol sequence i {htrue code i} {hfalse code i} Tests whether the hcontrol sequencei is currently defined (whether as a function or another control sequence type). It would be used in constructions like \bool_if:nTF { \cs_if_free_p:N \l_tmpz_tl || \cs_if_free_p:N \g_tmpz_tl } {htrue codei} {hfalse codei} For each predicate defined. 5. \cs_if_free_p:N would be a predicate function for the same type of test as the conditional described above. respectively. Used to implement predicates. Primitive conditionals There is a third variety of conditional. if they have exactly the same definition when examined with \cs_show:N. These conditional functions may or may not be fully expandable.Important to note is that these branching conditionals with htrue codei and/or hfalse codei are always defined in a way that the code of the chosen alternative can operate on following tokens in the input stream. It would return “true” if its argument (a single token denoted by N) is still free for definition. 21 . Predicates “Predicates” are functions that return a special type of boolean value which can be tested by the boolean expression parser.e. All functions of this type are expandable and have names that end with _p in the description part. which is the original concept used in plain TEX and LATEX 2ε . . and is true if the two lists contain the same characters in the same order. and is true if the two lists contain the same characters in the same order.2 \str_if_eq_p:nn \str_if_eq_p:(Vn|on|no|nV|VV) \str_if_eq:nnTF \str_if_eq:(Vn|on|no|nV|VV)TF Testing string equality ? ? ? ? \str_if_eq_p:nn {htl1 i} {htl2 i} \str_if_eq:nnTF {htl1 i} {htl2 i} {htrue code i} {hfalse code i} Compares the two htoken listsi on a character by character basis. If none of the tests are true then the else code will be left in the input stream. \str_if_eq_x_p:nn ? \str_if_eq_x:nnTF ? New: 2012-06-05 \str_if_eq_x_p:nn {htl1 i} {htl2 i} \str_if_eq_x:nnTF {htl1 i} {htl2 i} {htrue code i} {hfalse code i} Compares the full expansion of two htoken listsi on a character by character basis. 5. {hstring casen i} } {helse code i} string i} {hcode case1 i} {hcode case2 i} {hcode casen i} This function compares the htest stringi in turn with each of the hstring casesi. Thus for example \str_if_eq_p:no { abc } { \tl_to_str:n { abc } } is logically true..\cs_if_free_p:N \cs_if_free_p:c \cs_if_free:NTF \cs_if_free:cTF ? ? ? ? \cs_if_free_p:N hcontrol sequence i \cs_if_free:NTF hcontrol sequence i {htrue code i} {hfalse code i} Tests whether the hcontrol sequencei is currently free to be defined. This test will be false if the hcontrol sequencei currently exists (as defined by \cs_if_exist:N). \str_case:nnn ? \str_case:onn ? New: 2012-06-03 \str_case:nnn {htest { {hstring case1 i} {hstring case2 i} . Thus for example \str_if_eq_x_p:nn { abc } { \tl_to_str:n { abc } } is logically true. If the two are equal (as described for \str_if_eq:nnTF then the associated hcodei is left in the input stream. 22 . Hence the names for these underlying functions will often contain a :w part but higher level functions are often available.4 Primitive conditionals The ε-TEX engine itself provides many different conditionals. Updated: 2011-09-06 5. We will prefix primitive conditionals with \if_. Updated: 2011-09-06 \xetex_if_engine_p: ? \xetex_if_engine:TF ? \xetex_if_engine:TF {htrue code i} {hfalse code i} Detects is the document is being compiled using XETEX.\str_case_x:nnn ? New: 2012-06-05 \str_case_x:nnn {htest string i} { {hstring case1 i} {hcode case1 i} {hstring case2 i} {hcode case2 i} . 23 . If none of the tests are true then the else code will be left in the input stream.. Updated: 2011-09-06 \pdftex_if_engine_p: ? \pdftex_if_engine:TF ? \pdftex_if_engine:TF {htrue code i} {hfalse code i} Detects is the document is being compiled using pdfTEX. Certain conditionals deal with specific data types like boxes and fonts and are described there. and must always yield the same result: for example. Some expand whatever comes after them and others don’t. The htest stringi is expanded in each comparison. The ones described below are either the universal conditionals or deal with control sequences. {hstring casen i} {hcode casen i} } {helse code i} This function compares the full expansion of the htest stringi in turn with the full expansion of the hstring casesi.. See for instance \int_compare_p:nNn which is a wrapper for \if_int_compare:w.3 \luatex_if_engine_p: ? \luatex_if_engine:TF ? Engine-specific conditionals \luatex_if_engine:TF {htrue code i} {hfalse code i} Detects is the document is being compiled using LuaTEX. If the two full expansions are equal (as described for \str_if_eq:nnTF then the associated hcodei is left in the input stream. random numbers should not be used within this string. 5. TEXhackers note: These are equivalent to their corresponding TEX primitive conditionals. tokens. \if_catcode:w tests if the category codes of the two tokens are the same whereas \if:w tests if the character codes are identical. otherwise execute hfalse codei. \if_meaning:w ? \if_meaning:w harg1 i harg2 i htrue code i \else: hfalse code i \fi: \if_meaning:w executes htrue codei when harg1 i and harg2 i are the same. in all cases the unexpanded definitions are compared. \if:w ? \if_charcode:w ? \if_catcode:w ? \if:w htoken1 i htoken2 i htrue code i \else: hfalse code i \fi: \if_catcode:w htoken1 i htoken2 i htrue code i \else: hfalse code i \fi: \if_cs_exist:N ? \if_cs_exist:w ? \if_cs_exist:N hcs i htrue code i \else: hfalse code i \fi: \if_cs_exist:w htokens i \cs_end: htrue code i \else: hfalse code i \fi: These conditionals will expand any following tokens until two unexpandable tokens are left. prefix the token in question with \exp_not:N. \if_charcode:w is an alternative name for \if:w. otherwise it executes hfalse codei. while \if_false: always executes hfalse codei. harg1 i and harg2 i could be functions. \if_mode_horizontal: \if_mode_vertical: \if_mode_math: \if_mode_inner: ? ? ? ? \if_mode_horizontal: htrue code i \else: hfalse code i \fi: Execute htrue codei if currently in horizontal mode. If you wish to prevent this expansion. see l3int for more. 6 \__chk_if_exist_cs:N \__chk_if_exist_cs:c Internal kernel functions \__chk_if_exist_cs:N hcs i This function checks that hcsi exists according to the criteria for \cs_if_exist_p:N. TEXhackers note: This is TEX’s \ifx. 24 . The latter function does not turn the control sequence in question into \scan_stop:! This can be useful when dealing with control sequences which cannot be entered as a single token. \reverse_if:N reverses any two-way primitive conditional.\if_true: \if_false: \or: \else: \fi: \reverse_if:N ? ? ? ? ? ? \if_true: htrue code i \else: hfalse code i \fi: \if_false: htrue code i \else: hfalse code i \fi: \reverse_if:N hprimitive conditional i \if_true: always executes htrue codei. \reverse_if:N is ε-TEX’s \unless. Check if hcsi appears in the hash table or if the control sequence that can be formed from htokensi appears in the hash table. Similar for the other functions. variables. and if not raises a kernel-level error. \or: is used in case switches. \else: and \fi: delimit the branches of the conditional. e. etc.e. \__kernel_register_show:N hregister i Used to show the contents of a TEX register at the terminal. If there was no hsignaturei then the result is the marker value −1. This information is then placed in the input stream after the hprocessori function in three parts: the hnamei. after the colon). The hnamei will not include the escape character.e.) by removing trailing htokensi and the end marker \q_recursion_stop. The hnumberi of tokens in the hsignaturei is then left in the input stream. the part before the colon) and the hsignaturei (i. Splits the hfunctioni into the hnamei (i. and inserting the hcodei for the successful case. the part before the colon) and the hsignaturei (i. \__cs_get_function_name:N ? \__cs_get_function_name:N hfunction i Splits the hfunctioni into the hnamei (i. charactes with category other). \__cs_get_function_signature:N ? \__cs_get_function_signature:N hfunction i Splits the hfunctioni into the hnamei (i. for instance defining functions whose definition involves tokens which are hard to insert normally (spaces. \__cs_count_signature:N ? \__cs_count_signature:c ? \__cs_count_signature:N hfunction i \__cs_split_function:NN ? \__cs_split_function:NN hfunction i hprocessor i Splits the hfunctioni into the hnamei (i.e. and both the hnamei and hsignaturei are made up of tokens with category code 12 (other). \__cs_tmp:w \__kernel_register_show:N \__kernel_register_show:c \__prg_case_end:nw Function used for various short-term usages. The hsignaturei is then left in the input stream made up of tokens with category code 12 (other). The hnamei is then left in the input stream without the escape character present made up of tokens with category code 12 (other).\__chk_if_free_cs:N \__chk_if_free_cs:c \__chk_if_free_cs:N hcs i This function checks that hcsi is free according to the criteria for \cs_if_free_p:N. and if not raises a kernel-level error.e. the part before the colon) and the hsignaturei (i. after the colon). 25 .e. the part before the colon) and the hsignaturei (i.e. the hsignaturei and a logic token indicating if a colon was found (to differentiate variables from function names). after the colon). after the colon). formatted such that internal parts of the mechanism are not visible.e. \__prg_case_end:nw {hcode i} htokens i \q_recursion_stop Used to terminate case statements (\int_case:nnn. The hprocessori should be a function with argument specification :nnN (plus any trailing arguments needed). and is true if the two lists contain the same characters in the same order.\__str_if_eq_x_return:nn \__str_if_eq_x_return:nn {htl1 i} {htl2 i} Compares the full expansion of two htoken listsi on a character by character basis. This is a version of \str_if_eq_x:nn(TF) coded for speed. Either \prg_return_true: or \prg_return_false: is then left in the input stream. 26 . The next section explains how to define missing variants. They all look alike. the first and the second are a single tokens. The functions in this module all have prefix exp.g. an example would be \exp_args:NNo. Not all possible variations are implemented for every base function. The steps above may be automated by using the function \cs_generate_variant:Nn. They just expand into the appropriate \exp_ function followed by the desired base function. Instead only those that are used within the LATEX3 kernel or otherwise seem to be of general interest are implemented. e. From this example we can also see how the variants are defined. while the third argument should be given in braces. the first argument to \exp_args:NNo is the base function and the other arguments are preprocessed and then passed to this base function. Consult the module description to find out which functions are actually defined. Internally preprocessing of arguments is done with functions from the \exp_ module. 1 Defining new variants The definition of variant forms for base functions may be necessary when writing new functions or when applying a kernel function in a situation that we haven’t thought of before. described next. This function has three arguments. Therefore adding such definition to later releases of the kernel will not make such style files obsolete. \cs_new_nopar:Npn \seq_gpush:No { \exp_args:NNo \seq_gpush:Nn } Providing variants in this way in style files is uncritical as the \cs_new_nopar:Npn function will silently accept definitions whenever the new definition is identical to an already given one. 27 .Part V The l3expan package Argument expansion This module provides generic methods for expanding TEX arguments in a systematic manner. If \seq_gpush:No was not defined it could be coded in the following way: \exp_args:NNo \seq_gpush:Nn \g_file_name_stack \l_tmpa_tl In other words. Applying \exp_args:NNo will expand the content of third argument once before any expansion of the first and second arguments. In the example the first argument to the base function should be a single token which is left unchanged while the second argument is expanded once. The V type returns the value of a register. and v. which can be one of tl. The v type is the same except it first creates a 28 . f. V. skip. So for example \cs_set:Npn \foo:Nn #1#2 { code here } \cs_generate_variant:Nn \foo:Nn { c } will create a new function \foo:cn which will expand its first argument into a control sequence name and pass the result to \foo:Nn. 3 Introducing the variants The available internal functions for argument expansion come in two flavours. and. • Arguments that need full expansion (i. Similarly \cs_generate_variant:Nn \foo:Nn { NV . functions of this type will not work correctly in arguments that are themselves subject to x expansion. as is any \exp_args:Nhvariant i function needed to carry out the expansion. For each hvarianti given. • Arguments that should consist of single tokens should come first. The comma-separated list of hvariant argument specifiersi is then used to define variants of the horiginal argument specifieri where these are not already defined. unless in the last position. num. some of them are faster then others. c. or built-in TEX registers. Therefore it is usually best to follow the following guidelines when defining new functions that are supposed to come with variant forms: • Arguments that might need expansion should come first in the list of arguments to make processing faster. with possible trailing N or n. and o will need special processing which is not fast. dim.. f. o. i. • In general. namely those that contain only N..e. which are not expanded. are denoted with x) should be avoided if possible as they can not be processed expandably. in the last position. The \cs_generate_variant:Nn function can only be applied if the hparent control sequencei is already defined. toks.2 \cs_generate_variant:Nn Updated: 2012-08-28 Methods for defining variants \cs_generate_variant:Nn hparent control sequence i {hvariant argument specifiers i} This function is used to define argument-specifier variants of the hparent control sequencei for LATEX3 code-level macros. The hparent control sequencei is first separated into the hbase namei and horiginal argument specifieri. cV } would generate the functions \foo:NV and \foo:cV in the same way. int. a function is created which will expand its arguments as detailed and pass them to the hparent control sequencei. multi-token arguments n. Therefore it is best to use the optimized functions. The hvarianti is created globally. If the hparent control sequencei is protected then the new sequence will also be protected.e. Using \tl_set:Nx is not an option as that will die horribly. \exp_args:Nc ? \exp_args:cc ? \exp_args:Nc hfunction i {htokens i} This function absorbs two arguments (the hfunctioni name and the htokensi)... should the lower-level functions with o specifiers be employed.control sequence out of its argument before returning the value. It requires \tl_set:Nf to be defined as \cs_set_nopar:Npn \tl_set:Nf { \exp_args:NNf \tl_set:Nn } If you use this type of expansion in conditional processing then you should stick to using TF type functions only as it does not try to finish any \if. The :cc variant constructs the hfunctioni name in the same manner as described for the htokensi. The documentation you are currently reading will therefore require a fair bit of re-writing.. This function absorbs two arguments (the hfunctioni name and the htokensi). and the result is inserted in braces into the input stream after reinsertion of the hfunctioni. Thus the hfunctioni may take more than one argument: all others will be left unchanged. \exp_args:No ? \exp_args:No hfunction i {htokens i} . and are then turned into a control sequence. Furthermore we want to store the execution of it in a htl vari. (An internal error will occur if such a conversion is not possible). Only when specific expansion steps are needed. Thus the hfunctioni may take more than one argument: all others will be left unchanged. The f type is so special that it deserves an example. Instead we can do a \tl_set:Nf \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } } which puts the desired result in \l_tmpb_tl. This recent addition to the argument specifiers may shake things up a bit as most places where o is used will be replaced by V. the programmer should not need to be concerned with expansion control. In this example we assume \l_tmpa_tl contains the text string lur. Let’s pretend we want to set the control sequence whose name is given by b \l_tmpa_tl b equal to the list of tokens \aaa a. \fi: itself! 4 Manipulating the first argument These functions are described in detail: expansion of multiple tokens follows the same rules but is described in a shorter fashion. functions with a V specifier should be used. When simply using the content of a variable. 29 . such as when using delimited arguments. the v specifier is available for the same purpose. The htokensi are expanded once. The result is inserted into the input stream after reinsertion of the hfunctioni. For those referred to by (cs)name. The straightforward approach is \tl_set:No \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } } Unfortunately this only puts \exp_args:Nc \tl_set:Nn {b \l_tmpa_tl b} { \aaa a } into \l_tmpb_tl and not \tl_set:Nn \blurb { \aaa a } as we probably wanted.. The htokensi are expanded until only characters remain. In general. The result is inserted in braces into the input stream after reinsertion of the hfunctioni. Thus the hfunctioni may take more than one argument: all others will be left unchanged. \exp_args:Nno ? \exp_args:(NnV|Nnf|Noo|Nof|Noc|Nff|Nfo|Nnc) ? \exp_args:Noo htoken i {htokens1 i} {htokens2 i} Updated: 2012-01-14 These functions absorb three arguments and expand the second and third as detailed by their argument specifier. This control sequence should be the name of a hvariablei. followed by the expansion of the second and third arguments. Thus the hfunctioni may take more than one argument: all others will be left unchanged. The content of the hvariablei are recovered and placed inside braces into the input stream after reinsertion of the hfunctioni.\exp_args:NV ? \exp_args:NV hfunction i hvariable i This function absorbs two arguments (the names of the hfunctioni and the the hvariablei). \exp_args:Nx \exp_args:Nx hfunction i {htokens i} This function absorbs two arguments (the hfunctioni name and the htokensi) and exhaustively expands the htokensi second. The content of the hvariablei are recovered and placed inside braces into the input stream after reinsertion of the hfunctioni. The htokensi are expanded until only characters remain. These functions need special (slower) processing. 5 Manipulating two arguments \exp_args:NNo ? \exp_args:(NNc|NNv|NNV|NNf|Nco|Ncf|Ncc|NVV) ? \exp_args:NNc htoken1 i htoken2 i {htokens i} These optimized functions absorb three arguments and expand the second and third as detailed by their argument specifier. The first argument of the function is then the next item on the input stream. Thus the hfunctioni may take more than one argument: all others will be left unchanged. 30 . \exp_args:Nv ? \exp_args:Nv hfunction i {htokens i} This function absorbs two arguments (the hfunctioni name and the htokensi). and the result is inserted in braces into the input stream after reinsertion of the hfunctioni. followed by the expansion of the second and third arguments. The htokensi are fully expanded until the first non-expandable token or space is found. \exp_args:Nf ? \exp_args:Nf hfunction i {htokens i} This function absorbs two arguments (the hfunctioni name and the htokensi). The first argument of the function is then the next item on the input stream. Thus the hfunctioni may take more than one argument: all others will be left unchanged. and are then turned into a control sequence. (An internal error will occur if such a conversion is not possible). followed by the expansion of the second argument. These functions need special (slower) processing. etc. \exp_args:NNoo ? \exp_args:(NNno|Nnno|Nnnc|Nooo) ? \exp_args:NNNo htoken1 i htoken2 i htoken3 i {htokens i} These functions absorb four arguments and expand the second. The first argument of the function is then the next item on the input stream. These functions are not expandable. \exp_args:NNnx \exp_args:(NNox|Nnnx|Nnox|Noox|Ncnx|Nccx) \exp_args:NNnx htoken1 i htoken2 i {htokens1 i} {htokens2 i} These functions absorb four arguments and expand the second. followed by the expansion of the second argument. 6 Manipulating three arguments \exp_args:NNNo ? \exp_args:(NNNV|Nccc|NcNc|NcNo|Ncco) ? \exp_args:NNNo htoken1 i htoken2 i htoken3 i {htokens i} These optimized functions absorb four arguments and expand the second. The first argument of the function is then the next item on the input stream. 31 . etc. The first argument of the function is then the next item on the input stream.\exp_args:NNx \exp_args:(Nnx|Ncx|Nox|Nxo|Nxx) \exp_args:NNx htoken1 i htoken2 i {htokens i} These functions absorb three arguments and expand the second and third as detailed by their argument specifier. etc. followed by the expansion of the second and third arguments. third and fourth as detailed by their argument specifier. third and fourth as detailed by their argument specifier. followed by the expansion of the second argument. third and fourth as detailed by their argument specifier. The first argument of the function is then the next item on the input stream. \exp_last_unbraced:Nf \mypkg_foo:w { } \q_stop leads to an infinite loop. :Noo. which are not wrapped in braces.7 Unbraced expansion \exp_last_unbraced:Nf ? \exp_last_unbraced:(NV|No|Nv|Nco|NcV|NNV|NNo|Nno|Noo|Nfo|NNNV|NNNo|NnNo) ? \exp_last_unbraced:Nno htoken i htokens1 i htokens2 i Updated: 2012-02-12 These functions absorb the number of arguments given by their specification. while if htoken2 i has not expansion (for example. This can cause problems if the argument is empty: for instance. This function is not expandable. with the last argument not surrounded by the usual braces. The first argument of the function is then the next item on the input stream. including group-opening and -closing tokens ({ or } assuming normal TEX category codes). \exp_after:wN ? \exp_after:wN htoken1 i htoken2 i Carries out a single expansion of htoken2 i (which may consume arguments) prior to the expansion of htoken1 i. \exp_last_two_unbraced:Noo ? \exp_last_two_unbraced:Noo htoken i htokens1 i {htokens2 i} This function absorbs three arguments and expand the second and third once. It is important to notice that htoken1 i may be any single token. expansion should be carried out using an appropriate argument specifier variant or the appropriate \exp_arg:N function. as the quark is f-expanded. if it is a character) then it will be left unchanged. 8 Preventing expansion Despite the fact that the following functions are all about preventing expansion. Of these. the last argument is unbraced by some of those functions before expansion. the :Nno. If htoken2 i is a TEX primitive. 32 . they’re designed to be used in an expandable context and hence are all marked as being ‘expandable’ since they themselves will not appear after the expansion has completed. Unless specifically required. TEXhackers note: This is the TEX primitive \expandafter renamed. \exp_last_unbraced:Nx \exp_last_unbraced:Nx hfunction i {htokens i} This functions fully expands the htokensi and leaves the result in the input stream after reinsertion of hfunctioni. and :Nfo variants need special (slower) processing. it will be executed rather than expanded. TEXhackers note: As an optimization. carry out the expansion indicated and leave the the results in the input stream. This function needs special (slower) processing. followed by the expansion of the second and third arguments. Hence its argument must be surrounded by braces. for example an x-type argument. for example an x-type argument. TEXhackers note: This is the TEX \noexpand primitive. Expansion then stops. \exp_not:n ? \exp_not:n {htokens i} Prevents expansion of the htokensi in a context where they would otherwise be expanded. but when typeset it produces the underlying space (␣). for example an x-type argument. for example an x-type argument. \exp_not:v ? \exp_not:v {htokens i} Expands the htokensi until only unexpandable content remains. it will retain its form. The function itself is an implicit space token. and the result of the expansion (including any tokens which were not expanded) is protected from further expansion. Thus if a function \function:f starts an f-type expansion and all of htokensi are expandable \exp_stop:f will terminate the expansion of tokens even if hmore tokensi are also expandable. \exp_not:V ? \exp_not:V hvariable i Recovers the content of the hvariablei. and further expansion is prevented in a context where it would otherwise be expanded. then prevents expansion of this material in a context where it would otherwise be expanded. TEXhackers note: This is the ε-TEX \unexpanded primitive. and then converts this into a control sequence. \exp_not:c ? \exp_not:c {htokens i} Expands the htokensi until only unexpandable content remains. then prevents any further expansion in a context where they would otherwise be expanded. 33 . Further expansion of this control sequence is then inhibited. \exp_not:f ? \exp_not:f {htokens i} Expands htokensi fully until the first unexpandable token is found. Inside an x-type expansion. The content of the hvariablei is recovered. \exp_not:o ? \exp_not:o {htokens i} Expands the htokensi once.\exp_not:N ? \exp_not:N htoken i Prevents expansion of the htokeni in a context where it would otherwise be expanded. for example an x-type argument. and then converts this into a control sequence (which should be a hvariablei name). \exp_stop_f: ? \function:f htokens i \exp_stop_f: hmore tokens i Updated: 2011-06-03 This function terminates an f-type expansion. 9 \l__exp_internal_tl \::n \::N \::p \::c \::o \::f \::x \::v \::V \::: Internal functions and variables The \exp_ module has its private variables to temporarily store results of the argument expansion. This is done to avoid interference with other functions using temporary variables. 34 . \cs_set_nopar:Npn \exp_args:Ncof { \::c \::o \::f \::: } Internal forms for the base expansion types. These names do not conform to the general LATEX3 approach as this makes them more readily visible in the log and so forth. . \cs_set:Npn). F and TF. Those conditionals are expandable if hcodei is. After processing the input. The new versions will check for existing definitions and perform assignments globally (cf. The conditionals created are dependent on the comma-separated list of hconditionsi. \prg_new_protected_conditional:Npnn \prg_new_protected_conditional:Nnn \prg_set_protected_conditional:Npnn \prg_set_protected_conditional:Nnn \prg_new_protected_conditional:Npnn \hname i:harg spec i hparameters i {hconditions i} {hcode i} \prg_new_protected_conditional:Nnn \hname i:harg spec i {hconditions i} {hcode i} Updated: 2012-02-06 These functions create a family of protected conditionals using the same {hcodei} to perform the test created. T.. The firs form is predicate functions that turn the returned state into a boolean htruei or hfalsei. The hcodei does not need to be expandable. possibly involving assignments and calling other functions that do not read further ahead in the input stream. \cs_set:Npn). which should be one or more of T.\fi: structure.g. a state is returned. 1 \prg_new_conditional:Npnn \prg_new_conditional:Nnn \prg_set_conditional:Npnn \prg_set_conditional:Nnn Updated: 2012-02-06 Defining a set of conditional functions \prg_new_conditional:Npnn \hname i:harg spec i hparameters i {hconditions i} {hcode i} \prg_new_conditional:Nnn \hname i:harg spec i {hconditions i} {hcode i} These functions create a family of conditionals using the same {hcodei} to perform the test created. The new version will check for existing definitions and perform assignments globally (cf. LATEX3 has two forms of conditional flow processing based on these states. \cs_new:Npn) whereas the set version will not (cf. say an herrori state for erroneous input. The second form is the kind of functions choosing a particular argument from the input stream based on the result of the testing as in \cs_if_free:NTF which also takes one argument (the N) and then executes either true or false depending on the result.Part VI The l3prg package Control structures Conditional processing in LATEX3 is defined as something that performs a series of tests. \cs_new:Npn) whereas the set versions do no check and perform assignments locally (cf.. The conditionals created are depended on the comma-separated list of hconditionsi. e. The typical states returned are htruei and hfalsei but other states are possible. the function \cs_if_free_p:N checks whether the control sequence given as its argument is free and then returns the boolean htruei or hfalsei values to be used in testing with \if_predicate:w or in functions to be described below. which should be one or more of p. For example. text as input in a function comparing integers. 35 . F and TF (not p). Important to note here is that the arguments are executed after exiting the underlying \if. The return statements take care of resolving the remaining \else: and \fi: before returning the state.The conditionals are defined by \prg_new_conditional:Npnn and friends as: • \hname i_p:harg spec i — a predicate function which will supply either a logical true or logical false. the functions \prg_return_true: and \prg_return_false: are used to indicate the logical outcomes of the test. • \hname i:harg spec iTF — a function with two more argument than the original harg speci demands. failing to do so will result in erroneous output if that branch is executed. 36 . TF } { \if_meaning:w \l_tmpa_tl #1 \prg_return_true: \else: \if_meaning:w \l_tmpa_tl #2 \prg_return_true: \else: \prg_return_false: \fi: \fi: } This defines the function \foo_if_bar_p:NN. This function will not work properly for protected conditionals. Within the hcodei. • \hname i:harg spec iT — a function with one more argument than the original harg speci demands. The htrue branchi code in the first additional argument will be left on the input stream if the test is true. The hcodei of the test may use hparametersi as specified by the second argument to \prg_set_conditional:Npnn: this should match the hargument specificationi but this is not enforced. This function is intended for use in cases where one or more logical tests are combined to lead to a final outcome. \cs_new:Nn. T . • \hname i:harg spec iF — a function with one more argument than the original harg speci demands. etc. while the hfalse branchi code in the second argument will be left on the input stream if the test is false. The htrue branchi code in this additional argument will be left on the input stream only if the test is true. An example can easily clarify matters here: \prg_set_conditional:Npnn \foo_if_bar:NN #1#2 { p . The Nnn versions infer the number of arguments from the argument specification given (cf. The hfalse branchi code in this additional argument will be left on the input stream only if the test is false. \foo_if_bar:NNTF and \foo_if_bar:NNT but not \foo_if_bar:NNF (because F is missing from the hconditionsi list).). There must be a return statement for each branch. The problem of the primitive \if_false: and \if_true: tokens is that it is not always safe to pass them around as they may interfere with scanning for termination of primitive conditional processing. The new version will check for existing definitions (cf. The return functions trigger what is internally an f-expansion process to complete the evaluation of the conditional.. \prg_return_true: ? \prg_return_false: ? \prg_return_true: \prg_return_false: These ‘return’ functions define the logical state of a conditional statement. which should be one or more of p. Or. Besides preventing problems as described above. Therefore. \bool_new:N \bool_new:c \bool_set_false:N \bool_set_false:c \bool_gset_false:N \bool_gset_false:c \bool_new:N hboolean i Creates a new hbooleani or raises an error if the name is already taken. etc. Therefore. The conditionals copied are depended on the comma-separated list of hconditionsi.g. F and TF. 2 The boolean data type This section describes a boolean data type which is closely connected to conditional processing as sometimes you want to execute some code depending on the value of a switch (e. The declaration is global. Not. All conditional \bool_ functions except assignments are expandable and expect the input to also be fully expandable (which will generally mean being constructed from predicate functions. etc. 37 . While they may appear multiple times each within the code of such conditionals. \bool_set_false:N hboolean i Sets hbooleani logically false. which can then be used on both the boolean type and predicate functions. They appear within the code for a conditional function generated by \prg_set_conditional:Npnn. draft/final) and other times you perhaps want to use it as a predicate function in an \if_predicate:w test.\prg_new_eq_conditional:NNn \prg_set_eq_conditional:NNn \prg_new_eq_conditional:NNn \hname1 i:harg spec1 i \hname2 i:harg spec2 i {hconditions i} These functions copies a family of conditionals. to indicate when a true or false branch has been taken. The hbooleani will initially be false. \cs_new:Npn) whereas the set version will not (cf. it also allows us to implement a simple boolean parser supporting the logical operations And. we employ two canonical booleans: \c_true_bool or \c_false_bool. the execution of the conditional must result in the expansion of one of these two functions exactly once. \cs_set:Npn). after \prg_return_true: or \prg_return_false: there must be no non-expandable material in the input stream for the remainder of the expansion of the conditional code. possibly nested). T. This includes other instances of either of these functions. Updated: 2012-07-08 \bool_if_p:N \bool_if_p:c \bool_if:NTF \bool_if:cTF ? ? ? ? \bool_show:N \bool_show:c \bool_if_p:N hboolean i \bool_if:NTF hboolean i {htrue code i} {hfalse code i} Tests the current truth of hbooleani.\bool_set_true:N \bool_set_true:c \bool_gset_true:N \bool_gset_true:c \bool_set_eq:NN \bool_set_eq:(cN|Nc|cc) \bool_gset_eq:NN \bool_gset_eq:(cN|Nc|cc) \bool_set_true:N hboolean i Sets hbooleani logically true. and continues expansion based on this result. It is never used by the kernel code. 38 . It is never used by the kernel code. New: 2012-03-03 \l_tmpa_bool \l_tmpb_bool A scratch boolean for local assignment. Updated: 2012-07-08 \bool_if_exist_p:N \bool_if_exist_p:c \bool_if_exist:NTF \bool_if_exist:cTF ? ? ? ? \bool_if_exist_p:N hboolean i \bool_if_exist:NTF hboolean i {htrue code i} {hfalse code i} Tests whether the hbooleani is currently defined. \g_tmpa_bool \g_tmpb_bool A scratch boolean for global assignment. it may be overwritten by other non-kernel code and so should only be used for short-term storage. and so is safe for use with any LATEX3-defined function. \bool_set:Nn hboolean i {hboolexpr i} \bool_set:Nn \bool_set:cn \bool_gset:Nn \bool_gset:cn Evaluates the hboolean expressioni as described for \bool_if:n(TF). However. and so is safe for use with any LATEX3-defined function. This does not check that the hbooleani really is a boolean variable. and sets the hbooleani variable to the logical truth of this evaluation. \bool_show:N hboolean i Displays the logical truth of the hbooleani on the terminal. it may be overwritten by other non-kernel code and so should only be used for short-term storage. New: 2012-02-09 \bool_show:n {hboolean expression i} \bool_show:n New: 2012-02-09 Displays the logical truth of the hboolean expressioni on the terminal. However. \bool_set_eq:NN hboolean1 i hboolean2 i Sets the content of hboolean1 i equal to that of hboolean2 i. 3 Boolean expressions As we have a boolean datatype and predicate functions returning boolean htruei or hfalsei values. || (“Or”). it seems only fitting that we also provide a parser for hboolean expressionsi. For example \bool_if_p:n { \int_compare_p:nNn { && ( \int_compare_p:nNn \int_compare_p:nNn \int_compare_p:nNn ) && ! \int_compare_p:nNn } 1 } = { 1 } { 2 } = { 3 } || { 4 } = { 4 } || { 1 } = { \error } % is skipped { 2 } = { 4 } will be true and will not evaluate \int_compare_p:nNn { 1 } = { \error }. return boolean htruei or hfalsei. || and ! with their usual precedences. Or and Not as the well-known infix operators &&. ! (“Not”) and parentheses. It supports the logical operations And. The logical Not applies to the next predicate or group. the remaining tests within the current group are skipped. \int_compare_p:n { 1 ( \int_compare_p:n \int_compare_p:n \int_compare_p:n ) && ! ( \int_compare_p:n = 1 } && { 2 = 3 } || { 4 = 4 } || { 1 = \error } % is skipped { 2 = 4 } ) is a valid boolean expression. Note that minimal evaluation is carried out whenever possible so that whenever a truth value cannot be changed any more. Minimal evaluation is used in the processing. 39 . so that once a result is defined there is not further expansion of the tests. and continues expansion based on this result. \bool_if_p:n ? \bool_if:nTF ? Updated: 2012-07-08 \bool_if_p:n {hboolean expression i} \bool_if:nTF {hboolean expression i} {htrue code i} {hfalse code i} Tests the current truth of hboolean expressioni. For example. In addition to this. parentheses can be used to isolate sub-expressions. A boolean expression is an expression which given input in the form of predicate functions and boolean variables. The hboolean expressioni should consist of a series of predicates or boolean variables with the logical relationship between these defined using && (“And”). \bool_until_do:Nn hboolean i {hcode i} This function firsts checks the logical value of the hbooleani. \bool_do_while:Nn hboolean i {hcode i} Places the hcodei in the input stream for TEX to process. The process will then loop until the hbooleani is false.\bool_not_p:n ? Updated: 2012-07-08 \bool_xor_p:nn ? Updated: 2012-07-08 \bool_not_p:n {hboolean expression i} Function version of !(hboolean expressioni) within a boolean expression. 4 Logical loops Loops using either boolean expressions or stored boolean values. \bool_do_until:nn {hboolean expression i} {hcode i} Places the hcodei in the input stream for TEX to process. and then checks the logical value of the hbooleani. If it is true then the hcodei will be inserted into the input stream again and the process will loop until the hbooleani is false. There is no infix operation for this logical operator. \bool_do_until:Nn I \bool_do_until:cn I \bool_do_while:Nn I \bool_do_while:cn I \bool_until_do:Nn I \bool_until_do:cn I \bool_while_do:Nn I \bool_while_do:cn I \bool_do_until:nn I Updated: 2012-07-08 \bool_do_while:nn I Updated: 2012-07-08 \bool_do_until:Nn hboolean i {hcode i} Places the hcodei in the input stream for TEX to process. \bool_xor_p:nn {hboolexpr1 i} {hboolexpr2 i} Implements an “exclusive or” operation between two boolean expressions. and then checks the logical value of the hboolean expressioni as described for \bool_if:nTF. and then checks the logical value of the hboolean expressioni as described for \bool_if:nTF. If it is false the hcodei is placed in the input stream and expanded. After the completion of the hcodei the truth of the hbooleani is re-evaluated. 40 . If it is false then the hcodei will be inserted into the input stream again and the process will loop until the hbooleani is true. The process will then loop until the hbooleani is true. \bool_do_while:nn {hboolean expression i} {hcode i} Places the hcodei in the input stream for TEX to process. and then checks the logical value of the hbooleani. \bool_while_do:Nn hboolean i {hcode i} This function firsts checks the logical value of the hbooleani. If it is false then the hcodei will be inserted into the input stream again and the process will loop until the hboolean expressioni evaluates to true. After the completion of the hcodei the truth of the hbooleani is re-evaluated. If it is true the hcodei is placed in the input stream and expanded. If it is true then the hcodei will be inserted into the input stream again and the process will loop until the hboolean expressioni evaluates to false. After the completion of the hcodei the truth of the hboolean expressioni is re-evaluated. The process will then loop until the hboolean expressioni is false. \mode_if_math_p: ? \mode_if_math:TF ? \mode_if_math:TF {htrue code i} {hfalse code i} Detects if TEX is currently in maths mode. 6 \mode_if_horizontal_p: ? \mode_if_horizontal:TF ? Producing n copies Detecting TEX’s mode \mode_if_horizontal_p: \mode_if_horizontal:TF {htrue code i} {hfalse code i} Detects if TEX is currently in horizontal mode.\bool_until_do:nn I Updated: 2012-07-08 \bool_while_do:nn I Updated: 2012-07-08 \bool_until_do:nn {hboolean expression i} {hcode i} This function firsts checks the logical value of the hboolean expressioni (as described for \bool_if:nTF). 41 . After the completion of the hcodei the truth of the hboolean expressioni is re-evaluated. Updated: 2011-09-05 \mode_if_vertical_p: ? \mode_if_vertical:TF ? \mode_if_vertical_p: \mode_if_vertical:TF {htrue code i} {hfalse code i} Detects if TEX is currently in vertical mode. \mode_if_inner_p: ? \mode_if_inner:TF ? \mode_if_inner_p: \mode_if_inner:TF {htrue code i} {hfalse code i} Detects if TEX is currently in inner mode. If it is true the hcodei is placed in the input stream and expanded. 5 \prg_replicate:nn ? Updated: 2011-07-04 \prg_replicate:nn {hinteger expression i} {htokens i} Evaluates the hinteger expressioni (which should be zero or positive) and creates the resulting number of copies of the htokensi. It yields its result after two expansion steps. If it is false the hcodei is placed in the input stream and expanded. The function is both expandable and safe for nesting. The process will then loop until the hboolean expressioni is true. \bool_while_do:nn {hboolean expression i} {hcode i} This function firsts checks the logical value of the hboolean expressioni (as described for \bool_if:nTF). Without the special grouping. to obtain the expected output when testing \mode_if_math:TF at the start of a math array cell: placing \scan_align_safe_stop: before \mode_if_math:TF will give the correct result. This function does not destroy any kerning if used in other locations.7 \if_predicate:w ? Primitive conditionals \if_predicate:w hpredicate i htrue code i \else: hfalse code i \fi: This function takes a predicate function and branches according to the result. int. This function is required. \__prg_variable_get_scope:N ? \__prg_variable_get_scope:N hvariable i Returns the scope (g for global. 8 \group_align_safe_begin: ? \group_align_safe_end: ? Updated: 2011-08-11 \scan_align_safe_stop: Updated: 2011-09-06 Internal programming functions \group_align_safe_begin: . as TEX uses group level to determine the effect of alignment tokens. This group is designed in such a way that it does not add brace groups to the output but does act as a group for the & token inside \halign. blank otherwise) for the hvariablei. This is necessary to allow grabbing of tokens for testing purposes. \group_align_safe_end: These functions are used to enclose material in a TEX alignment environment within a specially-constructed group. although this does not have to occur within the same function.) \if_bool:N ? \if_bool:N hboolean i htrue code i \else: hfalse code i \fi: This function takes a boolean variable and branches according to the result. etc. \__prg_variable_get_type:N ? \__prg_variable_get_type:N hvariable i Returns the type of hvariablei (tl. (In practice this function would also accept a single boolean variable in place of the hpredicatei but to make the coding clearer this should be done through \if_bool:N. TEXhackers note: This is a protected version of \prg_do_nothing:. for example. but does render functions nonexpandable. the use of a function such as \peek_after:Nw will result in a forbidden comparison of the internal \endtemplate token.) 42 . yielding a fatal error.. \scan_align_safe_stop: Stops TEX’s scanner looking for expandable control sequences at the beginning of an alignment cell.. Each \group_align_safe_begin: must be matched by a \group_align_safe_end:. which therefore stops TEX’s scanner in the circumstances described without producing any affect on the output. \__prg_map_2:w. After the loop ends. \__prg_break: ? \__prg_break:n ? \__prg_break:n {htokens i} . inserting in the input stream the huser codei after the hending codei for the loop. This occurs even if the the break functions are not applied: \__prg_break_point:Nn is functionally-equivalent in these cases to \use_ii:nn.. The function breaks loops. \__prg_break_point: ? This copy of \prg_do_nothing: is used to mark the end of a fast short-term recursions: the function \__prg_break:n uses this to break out of the loop. \__prg_break_point:Nn \htype i_map_break: {hending code i} Breaks a recursion in mapping contexts. and inserts htokensi in the input stream. the htokensi are inserted into the input stream.. until reaching a loop with the same htypei as its first argument.. \g__prg_map_int This integer is used by non-expandable mapping functions to track the level of nesting in force. etc. labelled by \g__prg_map_int hold functions to be mapped over various list datatypes in inline and variable mappings.\__prg_break_point:Nn ? \__prg_break_point:Nn \htype i_map_break: htokens i Used to mark the end of a recursion or mapping: the functions \htype i_map_break: and \htype i_map_break:n use this to break out of the loop. 43 . \__prg_map_break:Nn ? \__prg_map_break:Nn \htype i_map_break: {huser code i} . The functions \__prg_map_1:w. This \htype i_map_break: argument is simply used as a recognizable marker for the htypei... inserting their hending codei. \__prg_break_point: Breaks a recursion which has no hending codei and which is not a user-breakable mapping (see for instance \prop_get:Nn). Quarks also permit the following ingenious trick when parsing tokens: when you pick up a token in a temporary variable and you want to know whether you have picked up a particular quark. \q_stop). For example. For example. with the most command use case as the ‘stop token’ (i. when writing a macro to parse a user-defined date \date_parse:n {19/June/1981} one might write a command such as \cs_new:Npn \date_parse:n #1 { \date_parse_aux:w #1 \q_stop } \cs_new:Npn \date_parse_aux:w #1 / #2 / #3 \q_stop { <do something with the date> } Quarks are sometimes also used as error return values for functions that receive erroneous input.e. A set of special quark testing functions is set up below. As mentioned above. By convention all constants of type quark start out with \q_. 44 . This would result in an endless loop! They are meant to be used as delimiter in weird functions. An example of the quark testing functions and their use in recursion can be seen in the implementation of \clist_map_function:NN. if the key does not exist then the return value is the quark \q_no_value.1 Quarks Quarks are control sequences that expand to themselves and should therefore never be executed directly in the code. such quarks are extremely fragile and it is imperative when using such functions that code is carefully written to check for pathological cases to avoid leakage of a quark into an uncontrolled environment. Scan marks are for internal use by the kernel: they are not intended for more general use. and scan marks start with \s_. in the function \prop_get:NnN to retrieve a value stored in some key of a property list. All the quark testing functions are expandable although the ones testing only single tokens are much faster. 1.Part VII The l3quark package Quarks 1 Introduction to quarks and scan marks Two special types of constants in LATEX3 are “quarks” and “scan marks”. all you have to do is compare the temporary variable to the quark using \tl_if_eq:NNTF. Quark to mark a null value in structured variables or functions. This is therefore used as a “return” value by functions such as \prop_get:NnN if there is no data to return. when one is requested from a data structure. and an error message will be raised if the name was already taken. which is only ever used as a delimiter).2 \quark_new:N Defining quarks \quark_new:N hquark i Creates a new hquarki which expands only to hquarki. such as \cs_set:Npn \tmp:w #1#2 \q_stop {#1} \q_mark Used as a marker for delimited arguments when \q_stop is already in use. \quark_if_nil_p:N ? \quark_if_nil:NTF ? \quark_if_nil_p:N htoken i \quark_if_nil:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is equal to \q_nil. \q_stop Used as a marker for delimited arguments. Tests if the htokeni is equal to \q_no_value. Used as an end delimiter when this may itself may need to be tested (in contrast to \q_stop. \quark_if_no_value_p:n {htoken list i} \quark_if_no_value:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the htoken listi contains only \q_no_value (distinct from htoken listi being empty or containing \q_no_value plus one or more other tokens). 3 Quark tests The method used to define quarks means that the single token (N) tests are faster than the multi-token (n) tests. 45 . The later should therefore only be used when the argument can definitely take more than a single token. The hquarki will be defined globally. \q_no_value A canonical value for a missing value. \quark_if_nil_p:n \quark_if_nil_p:(o|V) \quark_if_nil:nTF \quark_if_nil:(o|V)TF ? ? ? ? \quark_if_nil_p:n {htoken list i} \quark_if_nil:nTF {htoken list i} {htrue code i} {hfalse code i} \quark_if_no_value_p:N \quark_if_no_value_p:c \quark_if_no_value:NTF \quark_if_no_value:cTF ? ? ? ? \quark_if_no_value_p:N htoken i \quark_if_no_value:NTF htoken i {htrue code i} {hfalse code i} \quark_if_no_value_p:n ? \quark_if_no_value:nTF ? Tests if the htoken listi contains only \q_nil (distinct from htoken listi being empty or containing \q_nil plus one or more other tokens). 4 Recursion This module provides a uniform interface to intercepting and terminating loops as when one is doing tail recursion. Its purpose is to make it possible to terminate the recursion at any point easily. and if so terminates the recursion this is part of using \use_none_delimit_by_q_recursion_stop:w. \q_recursion_tail This quark is appended to the data structure in question and appears as a real element there. This means it gets any list separators around it. 46 . The building blocks follow below and an example is shown in Section 6. and if so terminates the recursion this is part of using \use_none_delimit_by_q_recursion_stop:w. The hinsertioni code is then added to the input stream after the recursion has ended. and if so terminates the recursion this is part of using \use_none_delimit_by_q_recursion_stop:w. The recursion input must include the marker tokens \q_recursion_tail and \q_recursion_stop as the last two items. \quark_if_recursion_tail_stop_do:Nn \quark_if_recursion_tail_stop_do:Nn htoken i {hinsertion i} Tests if htokeni contains only the marker \q_recursion_tail. \quark_if_recursion_tail_stop:n \quark_if_recursion_tail_stop:o \quark_if_recursion_tail_stop:n {htoken list i} Updated: 2011-09-06 Tests if the htoken listi contains only \q_recursion_tail. The recursion input must include the marker tokens \q_recursion_tail and \q_recursion_stop as the last two items. and if so terminates the recursion this is part of using \use_none_delimit_by_q_recursion_stop:w. The hinsertioni code is then added to the input stream after the recursion has ended. The recursion input must include the marker tokens \q_recursion_tail and \q_recursion_stop as the last two items. The recursion input must include the marker tokens \q_recursion_tail and \q_recursion_stop as the last two items. \quark_if_recursion_tail_stop_do:nn \quark_if_recursion_tail_stop_do:on \quark_if_recursion_tail_stop_do:nn {htoken list i} {hinsertion i} Updated: 2011-09-06 Tests if the htoken listi contains only \q_recursion_tail. \q_recursion_stop This quark is added after the data structure. \quark_if_recursion_tail_stop:N \quark_if_recursion_tail_stop:N htoken i Tests if htokeni contains only the marker \q_recursion_tail. These quarks are used to mark the end of the token list being operated upon. The token list #1 is terminated using \q_recursion_tail. Using quarks to define such functions simplifies their logic and ensures robustness in many cases.5 Clearing quarks away \use_none_delimit_by_q_recursion_stop:w \use_none_delimit_by_q_recursion_stop:w htokens i \q_recursion_stop Used to prematurely terminate a recursion using \q_recursion_stop as the end marker. Here is a small example to demonstrate how to use quarks in this fashion. 1 2 3 4 5 \cs_new:Npn \my_map_dbl:nn #1#2 { \cs_set:Npn \__my_map_dbl_fn:nn ##1 ##2 {#2} \__my_map_dbl:nn #1 \q_recursion_tail \q_recursion_tail \q_recursion_stop } The definition of the internal recursion function follows. 6 An example of recursion with quarks Quarks are mainly used internally in the expl3 code to define recursion functions such as \tl_map_inline:nn and so on. First of all. First check if either of the input tokens are the termination quarks. We shall define a command called \my_map_dbl:nn which takes a token list and applies an operation to every pair of tokens. apply the inline function to the two arguments. 6 7 8 9 10 \cs_new:Nn \__my_map_dbl:nn { \quark_if_recursion_tail_stop:n {#1} \quark_if_recursion_tail_stop:n {#2} \__my_map_dbl_fn:nn {#1} {#2} Finally. Then. removing any remaining htokensi from the input stream. Here’s the definition of \my_map_dbl:nn. recurse: \__my_map_dbl:nn 11 12 } 47 . concluding with \q_recursion_stop. Then initiate the recursion using an internal function. with delimiters according to the type of recursion (here a pair of \q_recursion_tail). \use_i_delimit_by_q_recursion_stop:nw \use_i_delimit_by_q_recursion_stop:nw {hinsertion i} htokens i \q_recursion_stop Used to prematurely terminate a recursion using \q_recursion_stop as the end marker. \my_map_dbl:nn {abcd} {[--#1--#2--]~} would produce “[–a–b–] [–c–d–] ”. The hinsertioni is then made into the input stream after the end of the recursion. if not. removing any remaining htokensi from the input stream. For example. define the function that will do the processing based on the inline function argument #2. \__use_none_delimit_by_s__stop:w \__use_none_delimit_by_s__stop:w htokens i \s__stop Removes the htokensi and \s__stop from the input stream. and if so terminates the recursion using \htype i_map_break:. 7 Internal quark functions \__quark_if_recursion_tail_break:NN \__quark_if_recursion_tail_break:nN \__quark_if_recursion_tail_break:nN {htoken list i} \htype i_map_break: Tests if htoken listi contains only \q_recursion_tail. they can be used as delimiters in weird functions and are often safer to use for this purpose. This leads to a low-level TEX error if \s__stop is absent. This allows to skip to that point if the end of the instructions should not be performed (see l3regex). Like quarks. 48 . The scan marks system is only for internal use by the kernel team in a small number of very specific places. they can be used to mark the end of a set of instructions. Since they are harmless when executed by TEX in non-expandable contexts. this mapping function cannot be nested. \s__stop Used at the end of a set of instructions. hence will never expand in an expansion context and will be (largely) invisible if they are encountered in a typesetting context. 8 Scan marks Scan marks are control sequences set equal to \scan_stop:. since the second map will overwrite the definition of \__my_map_dbl_fn:nn. The hscan marki will be defined globally. and an error message will be raised if the name was already taken by another scan mark. The recursion end should be marked by \prg_break_point:Nn \htype i_map_break:. \__scan_new:N \__scan_new:N hscan mark i Creates a new hscan marki which is set equal to \scan_stop:.Note that contrarily to LATEX3 built-in mapping functions. as a marker that can be jumped to using \__use_none_delimit_by_s__stop:w. These functions should not be used more generally. It is very important to distinguish two aspects of a token: its meaning. how many arguments it takes etc. Most of the time we will be using the term “token” but most of the time the function we’re describing can equally well by used on a control sequence as such one is one token as well. Functions for these two types are found in the l3tl module. namely the primitive testing the next two characters for equality of their character code. and what it looks like.Part VIII The l3token package Token manipulation This module deals with tokens. a macro or a primitive. \if:w. For instance. and \tex_if:D are three for the same internal operation of TEX. \cs_new:Npn \show_until_if:w #1 \if:w { \tl_show:n {#1} } \show_until_if:w \tex_if:D \if_charcode:w \if:w 49 . 1 All possible tokens Let us start by reviewing every case that a given token can fall into. Namely. We shall refer to list of tokens as tlists and such lists represented by a single control sequence is a “token list variable” tl var. it is often desirable to know just what a certain token is: is it a control sequence or something else. This module provides functions for both and as such will have two primary function categories: \token_ for anything that deals with tokens and \peek_ for looking ahead in the token stream. the example function \show_until_if:w defined below will take everything until \if:w as an argument. They behave identically in many situations. Another thing of great importance (especially when it comes to document commands) is looking ahead in the token stream to see if a certain character is present and maybe even remove it or disregard other tokens while scanning. despite the presence of other copies of \if:w under different names. TEX distinguishes them when searching for a delimited argument. \if_charcode:w. Similarly one often needs to know if a control sequence is expandable or not. However. Now this is perhaps not the most precise description so let’s try with a better description: When programming in TEX. 50 .2 Character tokens \char_set_catcode_escape:N \char_set_catcode_group_begin:N \char_set_catcode_group_end:N \char_set_catcode_math_toggle:N \char_set_catcode_alignment:N \char_set_catcode_end_line:N \char_set_catcode_parameter:N \char_set_catcode_math_superscript:N \char_set_catcode_math_subscript:N \char_set_catcode_ignore:N \char_set_catcode_space:N \char_set_catcode_letter:N \char_set_catcode_other:N \char_set_catcode_active:N \char_set_catcode_comment:N \char_set_catcode_invalid:N \char_set_catcode_letter:N hcharacter i Sets the category code of the hcharacteri to that indicated in the function name. This version can be used to set up characters which cannot otherwise be given (cf. The assignment is local. Depending on the current category code of the htokeni the escape token may also be needed: \char_set_catcode_other:N \% The assignment is local. \char_set_catcode_escape:n \char_set_catcode_group_begin:n \char_set_catcode_group_end:n \char_set_catcode_math_toggle:n \char_set_catcode_alignment:n \char_set_catcode_end_line:n \char_set_catcode_parameter:n \char_set_catcode_math_superscript:n \char_set_catcode_math_subscript:n \char_set_catcode_ignore:n \char_set_catcode_space:n \char_set_catcode_letter:n \char_set_catcode_other:n \char_set_catcode_active:n \char_set_catcode_comment:n \char_set_catcode_invalid:n \char_set_catcode_letter:n {hinteger expression i} Sets the category code of the hcharacteri which has character code as given by the hinteger expressioni. the N-type variants). the symbolic functions \char_set_catcode_htype i should be preferred. The two hcharactersi may be specified using an hinteger expressioni for the character code concerned. but there are cases where these lower-level functions may be useful.\char_set_catcode:nn \char_set_catcode:nn {hintexpr1 i} {hintexpr2 i} These functions set the category code of the hcharacteri which has character code as given by the hinteger expressioni. The setting applies within the current TEX group. The first hinteger expressioni is the character code and the second is the category code to apply. \char_set_lccode:nn \char_set_lcode:nn {hintexpr1 i} {hintexpr2 i} This function set up the behaviour of hcharacteri when found inside \tl_to_lowercase:n. This may include the TEX ‘hcharacteri method for converting a single character into its character code: \char_set_lccode:nn { ‘\A } { ‘\a } % Standard behaviour \char_set_lccode:nn { ‘\A } { ‘\A + 32 } \char_set_lccode:nn { 50 } { 60 } The setting applies within the current TEX group. In general. \char_show_value_catcode:n \char_show_value_catcode:n {hinteger expression i} Displays the current category code of the hcharacteri with character code given by the hinteger expressioni on the terminal. \char_value_lccode:n ? \char_value_lccode:n {hinteger expression i} Expands to the current lower case code of the hcharacteri with character code given by the hinteger expressioni. \char_value_catcode:n ? \char_value_catcode:n {hinteger expression i} Expands to the current category code of the hcharacteri with character code given by the hinteger expressioni. such that hcharacter1 i will be converted into hcharacter2 i. \char_show_value_lccode:n \char_show_value_lccode:n {hinteger expression i} Displays the current lower case code of the hcharacteri with character code given by the hinteger expressioni on the terminal. 51 . \char_set_sfcode:nn \char_set_sfcode:nn {hintexpr1 i} {hintexpr2 i} This function sets up the space factor for the hcharacteri. \char_set_mathcode:nn \char_set_mathcode:nn {hintexpr1 i} {hintexpr2 i} This function sets up the math code of hcharacteri. The setting applies within the current TEX group. The setting applies within the current TEX group. \char_value_mathcode:n ? \char_value_mathcode:n {hinteger expression i} Expands to the current math code of the hcharacteri with character code given by the hinteger expressioni. The hcharacteri is specified as an hinteger expressioni which will be used as the character code of the relevant character. \char_value_uccode:n ? \char_value_uccode:n {hinteger expression i} Expands to the current upper case code of the hcharacteri with character code given by the hinteger expressioni. 52 . \char_value_sfcode:n ? \char_value_sfcode:n {hinteger expression i} Expands to the current space factor for the hcharacteri with character code given by the hinteger expressioni.32 } \char_set_uccode:nn { 60 } { 50 } The setting applies within the current TEX group. This may include the TEX ‘hcharacteri method for converting a single character into its character code: \char_set_uccode:nn { ‘\a } { ‘\A } % Standard behaviour \char_set_uccode:nn { ‘\A } { ‘\A . \char_show_value_mathcode:n \char_show_value_mathcode:n {hinteger expression i} Displays the current math code of the hcharacteri with character code given by the hinteger expressioni on the terminal. such that hcharacter1 i will be converted into hcharacter2 i. The two hcharactersi may be specified using an hinteger expressioni for the character code concerned. \char_show_value_uccode:n \char_show_value_uccode:n {hinteger expression i} Displays the current upper case code of the hcharacteri with character code given by the hinteger expressioni on the terminal. The hcharacteri is specified as an hinteger expressioni which will be used as the character code of the relevant character.\char_set_uccode:nn \char_set_uccode:nn {hintexpr1 i} {hintexpr2 i} This function set up the behaviour of hcharacteri when found inside \tl_to_uppercase:n. Escaped tokens should be added to the sequence when they are defined for general document use. This will be an implicit representation of htoken2 i. \c_catcode_letter_token \c_catcode_other_token These are implicit tokens which have the category code described by their name.\char_show_value_sfcode:n \char_show_value_sfcode:n {hinteger expression i} Displays the current space factor for the hcharacteri with character code given by the hinteger expressioni on the terminal. \l_char_active_seq New: 2012-01-23 \l_char_special_seq New: 2012-01-23 Used to track which tokens will require special handling at the document level as they are of category hactivei (catcode 13). for example \\ for the backslash or \{ for an opening brace. \c_catcode_active_tl A token list containing an active token. Used to track which tokens will require special handling when working with verbatimlike material at the document level as they are not of categories hletteri (catcode 11) or hotheri (catcode 12). 3 \token_new:Nn Generic tokens \token_new:Nn htoken1 i {htoken2 i} Defines htoken1 i to globally be a snapshot of htoken2 i. \c_group_begin_token \c_group_end_token \c_math_toggle_token \c_alignment_token \c_parameter_token \c_math_superscript_token \c_math_subscript_token \c_space_token These are implicit tokens which have the category code described by their name. Each entry in the sequence consists of a single escaped token. Active tokens should be added to the sequence when they are defined for general document use. They are used internally for test purposes but are also available to the programmer for other uses. Each entry in the sequence consists of a single active character. 53 . They are used internally for test purposes and should not be used other than for category code tests. This is used internally for test purposes and should not be used other than in appropriately-constructed category code tests. 54 . as it is not a valid N-type argument. 5 \token_if_group_begin_p:N ? \token_if_group_begin:NTF ? Token conditionals \token_if_group_begin_p:N htoken i \token_if_group_begin:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a begin group token ({ when normal TEX category codes are in force). although this will also have category code 12 (the escape character is part of the htokeni). This function requires only a single expansion. This will be the primitive TEX description of the htokeni. \token_if_alignment_p:N ? \token_if_alignment:NTF ? \token_if_alignment_p:N htoken i \token_if_alignment:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of an alignment token (& when normal TEX category codes are in force). TEXhackers note: This is the TEX primitive \meaning. as it is not a valid N-type argument. Note that an explicit end group token cannot be tested in this way. The current escape character will be the first character in the sequence. Note that an explicit begin group token cannot be tested in this way. TEXhackers note: \token_to_str:N is the TEX primitive \string renamed. thus for example both functions defined by \cs_set_nopar:Npn and token list variables defined using \tl_new:N will be described as macros. \token_to_str:N ? \token_to_str:c ? \token_to_str:N htoken i Converts the given htokeni into a series of characters with category code 12 (other). \token_if_group_end_p:N ? \token_if_group_end:NTF ? \token_if_group_end_p:N htoken i \token_if_group_end:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of an end group token (} when normal TEX category codes are in force).4 \token_to_meaning:N ? \token_to_meaning:c ? Converting tokens \token_to_meaning:N htoken i Inserts the current meaning of the htokeni into the input stream as a series of characters of category code 12 (other). \token_if_math_toggle_p:N ? \token_if_math_toggle:NTF ? \token_if_math_toggle_p:N htoken i \token_if_math_toggle:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a math shift token ($ when normal TEX category codes are in force). \token_if_eq_charcode_p:NN ? \token_if_eq_charcode:NNTF ? \token_if_eq_charcode_p:NN htoken1 i htoken2 i \token_if_eq_charcode:NNTF htoken1 i htoken2 i {htrue code i} {hfalse code i} Tests if the two htokensi have the same character code. Note that an explicit space token with character code 32 cannot be tested in this way. \token_if_space_p:N ? \token_if_space:NTF ? \token_if_space_p:N htoken i \token_if_space:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a space token. 55 . \token_if_math_superscript_p:N ? \token_if_math_superscript:NTF ? \token_if_math_superscript_p:N htoken i \token_if_math_superscript:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a superscript token (^ when normal TEX category codes are in force). \token_if_other_p:N ? \token_if_other:NTF ? \token_if_other_p:N htoken i \token_if_other:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of an “other” token.\token_if_parameter_p:N ? \token_if_parameter:NTF ? \token_if_parameter_p:N htoken i \token_if_alignment:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a macro parameter token (# when normal TEX category codes are in force). \token_if_eq_catcode_p:NN ? \token_if_eq_catcode:NNTF ? \token_if_eq_catcode_p:NN htoken1 i htoken2 i \token_if_eq_catcode:NNTF htoken1 i htoken2 i {htrue code i} {hfalse code i} Tests if the two htokensi have the same category code. as it is not a valid N-type argument. \token_if_math_subscript_p:N ? \token_if_math_subscript:NTF ? \token_if_math_subscript_p:N htoken i \token_if_math_subscript:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a subscript token (_ when normal TEX category codes are in force). \token_if_active_p:N ? \token_if_active:NTF ? \token_if_active_p:N htoken i \token_if_active:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of an active character. \token_if_letter_p:N ? \token_if_letter:NTF ? \token_if_letter_p:N htoken i \token_if_letter:NTF htoken i {htrue code i} {hfalse code i} Tests if htokeni has the category code of a letter token. \token_if_cs_p:N htoken i \token_if_cs:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is a control sequence. \token_if_protected_macro_p:N ? \token_if_protected_macro:NTF ? \token_if_protected_macro_p:N htoken i \token_if_protected_macro:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is a protected macro: a macro which is both protected and long will return logical false. \token_if_macro_p:N ? \token_if_macro:NTF ? Updated: 2011-05-23 \token_if_cs_p:N ? \token_if_cs:NTF ? \token_if_macro_p:N htoken i \token_if_macro:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is a TEX macro. \token_if_chardef_p:N ? \token_if_chardef:NTF ? Updated: 2012-01-20 \token_if_chardef_p:N htoken i \token_if_chardef:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is defined to be a chardef.\token_if_eq_meaning_p:NN ? \token_if_eq_meaning:NNTF ? \token_if_eq_meaning_p:NN htoken1 i htoken2 i \token_if_eq_meaning:NNTF htoken1 i htoken2 i {htrue code i} {hfalse code i} Tests if the two htokensi have the same meaning when expanded. \token_if_long_macro_p:N ? \token_if_long_macro:NTF ? Updated: 2012-01-20 \token_if_long_macro_p:N htoken i \token_if_long_macro:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is a long macro. This test returns hfalsei for an undefined token. boxes and small integer constants are implemented as chardefs. \token_if_expandable_p:N ? \token_if_expandable:NTF ? \token_if_expandable_p:N htoken i \token_if_expandable:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is expandable. TEXhackers note: Booleans. \token_if_protected_long_macro_p:N ? \token_if_protected_long_macro:NTF ? Updated: 2012-01-20 \token_if_protected_long_macro_p:N htoken i \token_if_protected_long_macro:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is a protected long macro. 56 . \token_if_primitive_p:N ? \token_if_primitive:NTF ? Updated: 2011-05-23 \token_if_primitive_p:N htoken i \token_if_primitive:NTF htoken i {htrue code i} {hfalse code i} Tests if the htokeni is an engine primitive.\token_if_mathchardef_p:N ? \token_if_mathchardef:NTF ? \token_if_mathchardef_p:N htoken i \token_if_mathchardef:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is defined to be a mathchardef. chardefs. \token_if_muskip_register_p:N ? \token_if_muskip_register:NTF ? \token_if_muskip_register_p:N htoken i \token_if_muskip_register:NTF htoken i {htrue code i} {hfalse code i} New: 2012-02-15 Tests if the htokeni is defined to be a muskip register. \token_if_toks_register_p:N ? \token_if_toks_register:NTF ? \token_if_toks_register_p:N htoken i \token_if_toks_register:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is defined to be a toks register (not used byLATEX3). TEXhackers note: Constant integers may be implemented as integer registers. 57 . or mathchardefs depending on their value. \token_if_dim_register_p:N ? \token_if_dim_register:NTF ? \token_if_dim_register_p:N htoken i \token_if_dim_register:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is defined to be a dimension register. \token_if_skip_register_p:N ? \token_if_skip_register:NTF ? \token_if_skip_register_p:N htoken i \token_if_skip_register:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is defined to be a skip register. \token_if_int_register_p:N ? \token_if_int_register:NTF ? \token_if_int_register_p:N htoken i \token_if_int_register:NTF htoken i {htrue code i} {hfalse code i} Updated: 2012-01-20 Tests if the htokeni is defined to be a integer register. \peek_catcode:NTF Updated: 2012-12-20 \peek_catcode:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same category code as the htest tokeni (as defined by the test \token_if_eq_catcode:NNTF). \peek_gafter:Nw \peek_gafter:Nw hfunction i htoken i Globally sets the test variable \g_peek_token equal to htokeni (as an implicit token. The generic \peek_after:Nw is provided along with a family of predefined tests for common cases. { or } (assuming normal TEX category codes). \g_peek_token Token set by \peek_gafter:Nw and available for testing as described above. not as a token list). This is handled using the “peek” functions. As peeking ahead does not skip spaces the predefined tests include both a space-respecting and space-skipping version.e. i. it is not necessarily the next argument which would be grabbed by a normal function. and then expands the hfunctioni. \l_peek_token Token set by \peek_after:Nw and available for testing as described above.e. 58 . Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test). i. and then expands the hfunctioni. The htokeni here may be ␣. { or } (assuming normal TEX category codes). The htokeni will remain in the input stream as the next item after the hfunctioni. \peek_catcode_ignore_spaces:NTF Updated: 2012-12-20 \peek_catcode_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same category code as the htest tokeni (as defined by the test \token_if_eq_catcode:NNTF). it is not necessarily the next argument which would be grabbed by a normal function. The htokeni will remain in the input stream as the next item after the hfunctioni. Spaces are respected by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test).6 Peeking ahead at the next token There is often a need to look ahead at the next token in the input stream while leaving it in place. \peek_after:Nw \peek_after:Nw hfunction i htoken i Locally sets the test variable \l_peek_token equal to htokeni (as an implicit token. not as a token list). The htokeni here may be ␣. The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). \peek_charcode:NTF Updated: 2012-12-20 \peek_charcode:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same character code as the htest tokeni (as defined by the test \token_if_eq_charcode:NNTF). 59 . Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test).\peek_catcode_remove:NTF Updated: 2012-12-20 \peek_catcode_remove:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same category code as the htest tokeni (as defined by the test \token_if_eq_catcode:NNTF). Spaces are respected by the test and the htokeni will be removed from the input stream if the test is true. \peek_charcode_ignore_spaces:NTF Updated: 2012-12-20 \peek_charcode_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same character code as the htest tokeni (as defined by the test \token_if_eq_charcode:NNTF). Spaces are respected by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test). Spaces are respected by the test and the htokeni will be removed from the input stream if the test is true. \peek_catcode_remove_ignore_spaces:NTF Updated: 2012-12-20 \peek_catcode_remove_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same category code as the htest tokeni (as defined by the test \token_if_eq_catcode:NNTF). \peek_charcode_remove:NTF Updated: 2012-12-20 \peek_charcode_remove:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same character code as the htest tokeni (as defined by the test \token_if_eq_charcode:NNTF). Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be removed from the input stream if the test is true. \peek_charcode_remove_ignore_spaces:NTF Updated: 2012-12-20 \peek_charcode_remove_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same character code as the htest tokeni (as defined by the test \token_if_eq_charcode:NNTF). The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). Spaces are respected by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test). \peek_meaning_ignore_spaces:NTF Updated: 2012-12-05 \peek_meaning_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same meaning as the htest tokeni (as defined by the test \token_if_eq_meaning:NNTF). \peek_meaning:NTF Updated: 2011-07-02 \peek_meaning:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same meaning as the htest tokeni (as defined by the test \token_if_eq_meaning:NNTF). Spaces are respected by the test and the htokeni will be removed from the input stream if the test is true. The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). The function will then place either the htrue codei or hfalse codei in the input stream (as appropriate to the result of the test). \peek_meaning_remove:NTF Updated: 2011-07-02 \peek_meaning_remove:NTF htest token i {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream has the same meaning as the htest tokeni (as defined by the test \token_if_eq_meaning:NNTF). Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be removed from the input stream if the test is true. Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test). Explicit and implicit space tokens (with character code 32 and category code 10) are ignored and removed by the test and the htokeni will be removed from the input stream if the test is true. 60 . \peek_meaning_remove_ignore_spaces:NTF Updated: 2012-12-05 \peek_meaning_remove_ignore_spaces:NTF htest token i {htrue code i} {hfalse code i} Tests if the next non-space htokeni in the input stream has the same meaning as the htest tokeni (as defined by the test \token_if_eq_meaning:NNTF). If the htokeni is not a macro then \scan_stop: will be left in the input stream 61 . If the htokeni is not a macro then \scan_stop: will be left in the input stream \token_get_prefix_spec:N ? \token_get_prefix_spec:N htoken i If the htokeni is a macro. this function will leave the TEX prefixes applicable in input stream as a string of tokens of category code 12 (with spaces having category code 10). this function will leave the primitive TEX argument specification in input stream as a string of tokens of category code 12 (with spaces having category code 10). \token_get_replacement_spec:N ? \token_get_replacement_spec:N htoken i If the htokeni is a macro. all three functions leave \scan_stop: in the input stream. then the spec function will produce incorrect results. If the htokeni is not a macro then \scan_stop: will be left in the input stream TEXhackers note: If the arg spec. Thus for example for a token \next defined by \cs_set:Npn \next #1#2 { x #1 y #2 } will leave #1#2 in the input stream. this function will leave the replacement text in input stream as a string of tokens of category code 12 (with spaces having category code 10). Thus for example for a token \next defined by \cs_set:Npn \next #1#2 { x #1~y #2 } will leave \long in the input stream. contains the string ->.7 Decomposing a macro definition These functions decompose TEX macros into their constituent parts: if the htokeni passed is not a macro then no decomposition can occur. \token_get_arg_spec:N ? \token_get_arg_spec:N htoken i If the htokeni is a macro. Thus for example for a token \next defined by \cs_set:Npn \next #1#2 { x #1~y #2 } will leave x#1 y#2 in the input stream. In the later case. After two expansions. -. then calculates the result of dividing the first value by the second. The result is left in the input stream as an hinteger denotationi after two expansions. This is not an hinternal integeri. and therefore requires suitable termination if used in a TEX-style integer assignment. \int_div_round:nn {hintexpr1 i} {hintexpr2 i} Evaluates the two hinteger expressionsi as described earlier. Ties are rounded away from zero. \int_abs:n ? Updated: 2012-09-26 \int_div_round:nn ? Updated: 2012-09-26 \int_abs:n {hinteger expression i} Evaluates the hinteger expressioni as described for \int_eval:n and leaves the absolute value of the result in the input stream as an hinteger denotationi after two expansions. Note that this is identical to using / directly in an hinteger expressioni.( 3 + 4 * 5 ) } both evaluate to −6. rounding any remainder. The {hinteger expressioni} may contain the operators +. along with parenthesis ( and ).Part IX The l3int package Integers Calculation and comparison of integer values can be carried out using literal numbers. For example both \int_eval:n { 5 + 4 * 3 . constants and integers stored in token list variables. int registers. * and /. This module carries out these functions on integer expressions (“intexpr”).( 3 + 4 * 5 ) } and \tl_new:N \l_my_tl \tl_set:Nn \l_my_tl { 5 } \int_new:N \l_my_int \int_set:Nn \l_my_int { 4 } \int_eval:n { \l_my_tl + \l_my_int * 3 . expanding any integer and token list variables within the hexpressioni to their content (without requiring \int_use:N/\tl_use:N) and applying the standard mathematical rules. \int_eval:n yields an hinteger denotationi which is left in the input stream. 62 . The standard operators +. 1 \int_eval:n ? Integer expressions \int_eval:n {hinteger expression i} Evaluates the hinteger expressioni. / and * and parentheses can be used within such expressions to carry arithmetic operations. -. The hintegeri will initially be equal to 0. This is left in the input stream as an hinteger denotationi after two expansions. \int_const:Nn hinteger i {hinteger expression i} Creates a new constant hintegeri or raises an error if the name is already taken. 2 \int_new:N \int_new:c \int_const:Nn \int_const:cn Updated: 2011-10-22 \int_zero:N \int_zero:c \int_gzero:N \int_gzero:c \int_zero_new:N \int_zero_new:c \int_gzero_new:N \int_gzero_new:c Creating and initialising integers \int_new:N hinteger i Creates a new hintegeri or raises an error if the name is already taken. \int_zero:N hinteger i Sets hintegeri to 0. Note that division using / rounds the result. The declaration is global. then applies \int_(g)zero:N to leave the hintegeri set to zero. then calculates the result of dividing the first value by the second. \int_max:nn {hintexpr1 i} {hintexpr2 i} \int_min:nn {hintexpr1 i} {hintexpr2 i} Evaluates the hinteger expressionsi as described for \int_eval:n and leaves either the larger or smaller value in the input stream as an hinteger denotationi after two expansions.\int_div_truncate:nn ? Updated: 2012-02-09 \int_max:nn \int_min:nn ? ? Updated: 2012-09-26 \int_mod:nn ? Updated: 2012-09-26 \int_div_truncate:nn {hintexpr1 i} {hintexpr2 i} Evaluates the two hinteger expressionsi as described earlier. 63 . \int_mod:nn {hintexpr1 i} {hintexpr2 i} Evaluates the two hinteger expressionsi as described earlier. The value of the hintegeri will be set globally to the hinteger expressioni. \int_zero_new:N hinteger i Ensures that the hintegeri exists globally by applying \int_new:N if necessary. New: 2011-12-13 \int_set_eq:NN \int_set_eq:(cN|Nc|cc) \int_gset_eq:NN \int_gset_eq:(cN|Nc|cc) \int_set_eq:NN hinteger1 i hinteger2 i Sets the content of hinteger1 i equal to that of hinteger2 i. then calculates the integer remainder of dividing the first expression by the second. truncating any remainder. The result is left in the input stream as an hinteger denotationi after two expansions. Updated: 2011-10-22 64 .\int_if_exist_p:N \int_if_exist_p:c \int_if_exist:NTF \int_if_exist:cTF ? ? ? ? \int_if_exist_p:N hint i \int_if_exist:NTF hint i {htrue code i} {hfalse code i} Tests whether the hinti is currently defined. Updated: 2011-10-22 \int_decr:N \int_decr:c \int_gdecr:N \int_gdecr:c \int_decr:N hinteger i \int_incr:N \int_incr:c \int_gincr:N \int_gincr:c \int_incr:N hinteger i \int_set:Nn \int_set:cn \int_gset:Nn \int_gset:cn Decreases the value stored in hintegeri by 1. which must evaluate to an integer (as described for \int_eval:n). Increases the value stored in hintegeri by 1. \int_set:Nn hinteger i {hinteger expression i} Sets hintegeri to the value of hinteger expressioni. This does not check that the hinti really is an integer variable. Updated: 2011-10-22 \int_sub:Nn \int_sub:cn \int_gsub:Nn \int_gsub:cn \int_sub:Nn hinteger i {hinteger expression i} Subtracts the result of the hinteger expressioni from the current content of the hintegeri. New: 2012-03-03 3 \int_add:Nn \int_add:cn \int_gadd:Nn \int_gadd:cn Setting and incrementing integers \int_add:Nn hinteger i {hinteger expression i} Adds the result of the hinteger expressioni to the current content of the hintegeri. The two results are then compared using the hrelationi: Equal Greater than Less than 65 = > < . Can be omitted in places where an hintegeri is required (such as in the first and third arguments of \int_compare:nNnTF). An error will be raised if the variable does not exist or if it is invalid. 5 \int_compare_p:nNn ? \int_compare:nNnTF ? Integer expression conditionals \int_compare_p:nNn {hintexpr1 i} hrelation i {hintexpr2 i} \int_compare:nNnTF {hintexpr1 i} hrelation i {hintexpr2 i} {htrue code i} {hfalse code i} This function first evaluates each of the hinteger expressionsi as described for \int_eval:n. TEXhackers note: \int_use:N is the TEX primitive \the: this is one of several LATEX3 names for this primitive.4 \int_use:N \int_use:c ? ? Updated: 2011-10-22 Using integers \int_use:N hinteger i Recovers the content of an hintegeri and places it directly in the input stream. hintexprN i hrelationN i hintexprN +1 i } \int_compare:nTF { hintexpr1 i hrelation1 i .. until finally comparing hintexprN i and hintexprN +1 i using the hrelationN i. and the evaluation is lazy. The hrelationsi can be any of the following: Equal Greater than or equal to Greater than Less than or equal to Less than Not equal 66 = or == >= > <= < != ..\int_compare_p:n ? \int_compare:nTF ? Updated: 2013-01-13 \int_compare_p:n { hintexpr1 i hrelation1 i .. namely it compares hintexpr1 i and hintexpr2 i using the hrelation1 i. hintexprN i hrelationN i hintexprN +1 i } {htrue code i} {hfalse code i} This function evaluates the hinteger expressionsi as described for \int_eval:n and compares consecutive result using the corresponding hrelationi. in the sense that if one comparison is false.. then no other hinteger expressioni is evaluated and no other comparison is performed. The test yields true if all comparisons are true. then hintexpr2 i and hintexpr3 i using the hrelation2 i. Each hinteger expressioni is evaluated only once. 67 .\int_case:nnn ? New: 2012-06-03 \int_case:nnn {htest integer expression i} { {hintexpr case1 i} {hcode case1 i} {hintexpr case2 i} {hcode case2 i} . 6 \int_do_until:nNnn I Integer expression loops \int_do_until:nNnn {hintexpr1 i} hrelation i {hintexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process. as appropriate. {hintexpr casen i} {hcode casen i} } {helse code i} This function evaluates the htest integer expressioni and compares this in turn to each of the hinteger expression casesi. \int_if_even_p:n \int_if_even:nTF \int_if_odd_p:n \int_if_odd:nTF ? ? ? ? \int_if_odd_p:n {hinteger expression i} \int_if_odd:nTF {hinteger expression i} {htrue code i} {hfalse code i} This function first evaluates the hinteger expressioni as described for \int_eval:n. For example \int_case:nnn { 2 * 5 } { { 5 } { Small } { 4 + 6 } { Medium } { -2 * 10 } { Negative } } { No idea! } will leave “Medium” in the input stream. and then evaluates the relationship between the two hinteger expressionsi as described for \int_compare:nNnTF. and then evaluates the relationship between the two hinteger expressionsi as described for \int_compare:nNnTF.. \int_do_while:nNnn I \int_do_while:nNnn {hintexpr1 i} hrelation i {hintexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process.. It then evaluates if this is odd or even. If the two are equal then the associated hcodei is left in the input stream. If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. If none of the tests are true then the else code will be left in the input stream. After the hcodei has been processed by TEX the test will be repeated. After the hcodei has been processed by TEX the test will be repeated. After the hcodei has been processed by TEX the test will be repeated. and a loop will occur until the test is true. \int_do_while:nn {hinteger relation i} {hcode i} Places the hcodei in the input stream for TEX to process. After the hcodei has been processed by TEX the test will be repeated. and then places the hcodei in the input stream if the hrelationi is true. and a loop will occur until the test is false. \int_until_do:nn {hintegerr elation i} {hcode i} Evaluates the hinteger relationi as described for \int_compare:nTF. If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. and a loop will occur until the test is false. \int_while_do:nn {hinteger relation i} {hcode i} Evaluates the hinteger relationi as described for \int_compare:nTF. and a loop will occur until the test is true. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. \int_while_do:nNnn I \int_while_do:nNnn {hintexpr1 i} hrelation i {hintexpr2 i} {hcode i} Evaluates the relationship between the two hinteger expressionsi as described for \int_compare:nNnTF. and then places the hcodei in the input stream if the hrelationi is false. 68 . and then evaluates the hinteger relationi as described for \int_compare:nTF. and then places the hcodei in the input stream if the hrelationi is true.\int_until_do:nNnn I \int_until_do:nNnn {hintexpr1 i} hrelation i {hintexpr2 i} {hcode i} Evaluates the relationship between the two hinteger expressionsi as described for \int_compare:nNnTF. and then evaluates the hinteger relationi as described for \int_compare:nTF. \int_do_until:nn I Updated: 2013-01-13 \int_do_while:nn I Updated: 2013-01-13 \int_until_do:nn I Updated: 2013-01-13 \int_while_do:nn I Updated: 2013-01-13 \int_do_until:nn {hinteger relation i} {hcode i} Places the hcodei in the input stream for TEX to process. and then places the hcodei in the input stream if the hrelationi is false. all of which should be integer expressions. hstepi and hfinal valuei. all of which should be integer expressions. The hfunctioni is then placed in front of each hvaluei from the hinitial valuei to the hfinal valuei in turn (using hstepi between each hvaluei). The hcodei is then placed in front of each hvaluei from the hinitial valuei to the hfinal valuei in turn (using hstepi between each hvaluei).7 \int_step_function:nnnN I New: 2012-06-04 Updated: 2012-06-29 Integer step functions \int_step_function:nnnN {hinitial value i} {hstep i} {hfinal value i} hfunction i This function first evaluates the hinitial valuei. \int_step_variable:nnnNn {hinitial value i} {hstep i} {hfinal value i} htl var i {hcode i} New: 2012-06-04 Updated: 2012-06-29 This function first evaluates the hinitial valuei. Thus hfunctioni should absorb one numerical argument. hstepi and hfinal valuei. For example \cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad } \int_step_function:nnnN { 1 } { 1 } { 5 } \my_func:n would print [I saw 1] \int_step_inline:nnnn New: 2012-06-04 Updated: 2012-06-29 \int_step_variable:nnnNn [I saw 2] [I saw 3] [I saw 4] [I saw 5] \int_step_inline:nnnn {hinitial value i} {hstep i} {hfinal value i} {hcode i} This function first evaluates the hinitial valuei. 69 . with category code 12 (other). The hcodei is inserted into the input stream. 8 Formatting integers Integers can be placed into the output stream with formatting. hstepi and hfinal valuei. These conversions apply to any integer expressions. \int_to_arabic:n ? Updated: 2011-10-22 \int_to_arabic:n {hinteger expression i} Places the value of the hinteger expressioni in the input stream as digits. Thus the hcodei should make use of the htl vari. with the htl vari defined as the current hvaluei. all of which should be integer expressions. Thus the hcodei should define a function of one argument (#1). \int_to_alph:n ? \int_to_Alph:n ? Updated: 2011-09-17 \int_to_alph:n {hinteger expression i} Evaluates the hinteger expressioni and converts the result into a series of letters.. This should be given as htotal symbolsi pairs of entries. 70 . use \int_convert_to_symbols:nnn to define an alphabet-specific function. adding letters when necessary to increase the total possible range of representable numbers. For conversions using other alphabets. { 26 } { z } } } \int_to_binary:n ? Updated: 2011-09-17 \int_to_binary:n {hinteger expression i} Calculates the value of the hinteger expressioni and places the binary representation of the result in the input stream. The basic \int_to_alph:n and \int_to_Alph:n functions should not be modified. a number and the appropriate symbol. \int_to_symbols:nnn ? Updated: 2011-09-17 \int_to_symbols:nnn {hinteger expression i} {htotal symbols i} hvalue to symbol mapping i This is the low-level function for conversion of an hinteger expressioni into a symbolic form (which will often be letters). \int_to_alph:n { 26 } is represented as z and \int_to_alph:n { 27 } is converted to aa. The conversion rule uses the 26 letters of the English alphabet.. Values are actually converted to symbols according to the hvalue to symbol mappingi. which are then left in the input stream. Thus the \int_to_alph:n function is defined as \cs_new:Npn \int_to_alph:n #1 { \int_convert_to_symbols:nnn {#1} { 26 } { { 1 } { a } { 2 } { b } . in order. The htotal symbolsi available should be given as an integer expression. Thus \int_to_alph:n { 1 } places a in the input stream. For bases greater than 10 the higher “digits” are represented by the upper case letters from the English alphabet. Upper case letters are used for digits beyond 9. The maximum hbasei value is 36. \int_to_roman:n I \int_to_Roman:n I Updated: 2011-10-22 \int_to_roman:n {hinteger expression i} Places the value of the hinteger expressioni in the input stream as Roman numerals. Either lower or upper case letters may be used.\int_to_hexadecimal:n ? Updated: 2011-09-17 \int_to_octal:n ? Updated: 2011-09-17 \int_to_base:nn ? Updated: 2011-09-17 \int_to_hexadecimal:n {hinteger expression i} Calculates the value of the hinteger expressioni and places the hexadecimal (base 16) representation of the result in the input stream. This is the inverse function of \int_to_alph:n. etc. the later may be given as an integer expression. \int_to_base:nn {hinteger expression i} {hbase i} Calculates the value of the hinteger expressioni and converts it into the appropriate representation in the hbasei. 9 \int_from_alph:n ? Converting from other formats to integers \int_from_alpa:n {hletters i} Converts the hlettersi into the integer (base 10) representation and leaves this in the input stream. \int_from_binary:n ? \int_from_binary:n {hbinary number i} Converts the hbinary numberi into the integer (base 10) representation and leaves this in the input stream. The hlettersi are treated using the English alphabet only. The Roman numerals are letters with category code 11 (letter). with “a” equal to 1 through to “z” equal to 26. \int_to_octal:n {hinteger expression i} Calculates the value of the hinteger expressioni and places the octal (base 8) representation of the result in the input stream. TEXhackers note: This is a generic version of \int_to_binary:n. either lower case (\int_to_roman:n) or upper case (\int_to_Roman:n). \int_from_hexadecimal:n ? \int_from_binary:n {hhexadecimal number i} Converts the hhexadecimal numberi into the integer (base 10) representation and leaves this in the input stream. Digits greater than 9 may be represented in the hhexadecimal numberi by upper or lower case letters. 71 . 10 \int_show:N \int_show:c \int_show:n New: 2011-11-22 Viewing integers \int_show:N hinteger i Displays the value of the hintegeri on the terminal. \int_from_base:nn ? \int_from_base:nn {hnumber i} {hbase i} Converts the hnumberi in hbasei into the appropriate value in base 10. plus optionally a leading sign. The hroman numerali may be in upper or lower case. \int_show:n hinteger expression i Displays the result of evaluating the hinteger expressioni on the terminal. if the numeral is not valid then the resulting value will be −1. Updated: 2012-05-27 72 . The hnumberi should consist of digits and letters (either lower or upper case). \int_from_roman:n ? \int_from_roman:n {hroman numeral i} Converts the hroman numerali into the integer (base 10) representation and leaves this in the input stream. The maximum hbasei value is 36.\int_from_octal:n ? \int_from_octal:n {hoctal number i} Converts the hoctal numberi into the integer (base 10) representation and leaves this in the input stream. These are never used by the kernel code. 12 Scratch integers \l_tmpa_int \l_tmpb_int Scratch integer for local assignment. and so are safe for use with any LATEX3-defined function. These are never used by the kernel code. and so are safe for use with any LATEX3-defined function. they may be overwritten by other non-kernel code and so should only be used for short-term storage. However. The maximum value that can be stored as an integer. However. Maximum number of registers. 73 . \g_tmpa_int \g_tmpb_int Scratch integer for global assignment.11 \c_minus_one \c_zero \c_one \c_two \c_three \c_four \c_five \c_six \c_seven \c_eight \c_nine \c_ten \c_eleven \c_twelve \c_thirteen \c_fourteen \c_fifteen \c_sixteen \c_thirty_two \c_one_hundred \c_two_hundred_fifty_five \c_two_hundred_fifty_six \c_one_thousand \c_ten_thousand \c_max_int \c_max_register_int Constant integers Integer values used with primitive tests and assignments: self-terminating nature makes these more convenient and faster than literal numbers. they may be overwritten by other non-kernel code and so should only be used for short-term storage. < or > with category code 12.. TEXhackers note: These are both names for the TEX primitive \ifnum. 74 .g. TEXhackers note: This is the TEX primitive \romannumeral renamed. 14 \__int_to_roman:w ? Internal functions \__int_to_roman:w hinteger i hspace i or hnon-expandable token i Converts hintegeri to it lower case Roman representation. The \else: branch is optional. etc. The first case (hcase0 i) is executed if hintegeri is 0. the second (hcase1 i) if the hintegeri is 1. TEXhackers note: These are the TEX primitives \ifcase and \or. and tests whether the resulting hintegeri is odd. \else: hdefault i \fi: Selects a case to execute based on the value of the hintegeri. \if_int_odd:w ? \if_int_odd:w htokens i htrue code i \else: htrue code i \fi: hoptional space i Expands htokensi until a non-numeric token or a space is found. using \int_eval:n). a constant or an integer expression (e.13 \if_int_compare:w ? Primitive conditionals \if_int_compare:w hinteger1 i hrelation i hinteger2 i htrue code i \else: hfalse code i \fi: Compare two integers using hrelationi.. which must be one of =. Note that this function produces a string of letters with category code 12 and that protected functions are expanded by this process. Expansion ends when a space or non-expandable token is found. Negative hintegeri values result in no output. The hintegeri may be a literal. TEXhackers note: This is the TEX primitive \ifodd. If so. \if_case:w ? \or: ? \if_case:w hinteger i hcase0 i \or: hcase1 i \or: . The \else: branch is optional. although the function does not terminate expansion until a suitable endpoint is found in the same way as for positive numbers. htrue codei is executed. \__prg_compare_error: \__prg_compare_error:Nw \__prg_compare_error: \__prg_compare_error:Nw htoken i These are used within \int_compare:n(TF). \__int_eval:w ? \__int_eval_end: ? \__int_eval:w hintexpr i \__int_eval_end: Evaluates hinteger expressioni as described for \int_eval:n. The latter is gobbled by the scanner mechanism: \__int_eval_end: itself is unexpandable but used correctly the entire construct is expandable. The evaluation stops when an unexpandable token which is not a valid part of an integer is read or when \__int_eval_end: is reached. \dim_compare:n(TF) and so on to recover correctly if the n-type argument does not contain a properly-formed relation.\__int_value:w ? \__int_value:w hinteger i \__int_value:w htokens i hoptional space i Expands htokensi until an hintegeri is formed. One space may be gobbled in the process. 75 . TEXhackers note: This is the TEX primitive \number. TEXhackers note: This is the ε-TEX primitive \numexpr. \dim_zero_new:N hdimension i Ensures that the hdimensioni exists globally by applying \dim_new:N if necessary. \dim_zero:N hdimension i Sets hdimensioni to 0 pt. hdimensioni really is a dimension variable. The hdimensioni will initially be equal to 0 pt. the muskip type is available for use in math mode: this is a special form of skip where the lengths involved are determined by the current math font (in mu).Part X The l3skip package Dimensions and skips LATEX3 provides two general length variables: dim and skip. New: 2012-03-03 76 This does not check that the . New: 2012-01-07 \dim_if_exist_p:N \dim_if_exist_p:c \dim_if_exist:NTF \dim_if_exist:cTF ? ? ? ? \dim_if_exist_p:N hdimension i \dim_if_exist:NTF hdimension i {htrue code i} {hfalse code i} Tests whether the hdimensioni is currently defined. Lengths stored as dim variables have a fixed length. The declaration is global. but for clarity the functions are grouped by variable type. then applies \dim_(g)zero:N to leave the hdimensioni set to zero. The value of the hdimensioni will be set globally to the hdimension expressioni. 1 \dim_new:N \dim_new:c \dim_const:Nn \dim_const:cn New: 2012-03-05 \dim_zero:N \dim_zero:c \dim_gzero:N \dim_gzero:c \dim_zero_new:N \dim_zero_new:c \dim_gzero_new:N \dim_gzero_new:c Creating and initialising dim variables \dim_new:N hdimension i Creates a new hdimensioni or raises an error if the name is already taken. In addition. whereas skip lengths have a rubber (stretch/shrink) component. \dim_const:Nn hdimension i {hdimension expression i} Creates a new constant hdimensioni or raises an error if the name is already taken. There are common features in the creation and setting of length variables. Updated: 2011-10-22 \dim_set_eq:NN \dim_set_eq:(cN|Nc|cc) \dim_gset_eq:NN \dim_gset_eq:(cN|Nc|cc) \dim_set_eq:NN hdimension1 i hdimension2 i Sets the content of hdimension1 i equal to that of hdimension2 i. Updated: 2011-10-22 \dim_set:Nn hdimension i {hdimension expression i} \dim_set:Nn \dim_set:cn \dim_gset:Nn \dim_gset:cn Sets hdimensioni to the value of hdimension expressioni. 77 . as a hdimension denotationi. which must evaluate to a length with units. \dim_sub:Nn hdimension i {hdimension expression i} \dim_sub:Nn \dim_sub:cn \dim_gsub:Nn \dim_gsub:cn Subtracts the result of the hdimension expressioni from the current content of the hdimensioni. leaving the result in the input stream as a hdimension denotationi. Updated: 2011-10-22 3 \dim_abs:n ? Updated: 2012-09-26 \dim_max:nn \dim_min:nn ? ? New: 2012-09-09 Updated: 2012-09-26 Utilities for dimension calculations \dim_abs:n {hdimexpr i} Converts the hdimexpri to its absolute value.2 Setting dim variables \dim_add:Nn hdimension i {hdimension expression i} \dim_add:Nn \dim_add:cn \dim_gadd:Nn \dim_gadd:cn Adds the result of the hdimension expressioni to the current content of the hdimensioni. \dim_max:nn {hdimexpr1 i} {hdimexpr2 i} \dim_min:nn {hdimexpr1 i} {hdimexpr2 i} Evaluates the two hdimension expressionsi and leaves either the maximum or minimum value in the input stream as appropriate. allowing syntax such as \dim_set:Nn \l_my_dim { 10 pt * \dim_ratio:nn { 5 pt } { 10 pt } } The output of \dim_ratio:nn on full expansion is a ration expression between two integers. with all distances converted to scaled points. 4 \dim_compare_p:nNn ? \dim_compare:nNnTF ? Dimension expression conditionals \dim_compare_p:nNn {hdimexpr1 i} hrelation i {hdimexpr2 i} \dim_compare:nNnTF {hdimexpr1 i} hrelation i {hdimexpr2 i} {htrue code i} {hfalse code i} This function first evaluates each of the hdimension expressionsi as described for \dim_eval:n. The two results are then compared using the hrelationi: Equal Greater than Less than 78 = > < . This ratio is then left in the input stream.\dim_ratio:nn I Updated: 2011-10-22 \dim_ratio:nn {hdimexpr1 i} {hdimexpr2 i} Parses the two hdimension expressionsi and converts the ratio of the two to a form suitable for use inside a hdimension expressioni. Thus \tl_set:Nx \l_my_tl { \dim_ratio:nn { 5 pt } { 10 pt } } \tl_show:N \l_my_tl will display 327680/655360 on the terminal. until finally comparing hdimexprN i and hdimexprN +1 i using the hrelationN i. hdimexprN i hrelationN i hdimexprN +1 i } {htrue code i} {hfalse code i} This function evaluates the hdimension expressionsi as described for \dim_eval:n and compares consecutive result using the corresponding hrelationi... Each hdimension expressioni is evaluated only once. then hdimexpr2 i and hdimexpr3 i using the hrelation2 i. hdimexprN i hrelationN i hdimexprN +1 i } \dim_compare:nTF { hdimexpr1 i hrelation1 i .. namely it compares hdimexpr1 i and hdimexpr2 i using the hrelation1 i. then no other hdimension expressioni is evaluated and no other comparison is performed. The hrelationsi can be any of the following: Equal Greater than or equal to Greater than Less than or equal to Less than Not equal 79 = or == >= > <= < != . and the evaluation is lazy.\dim_compare_p:n ? \dim_compare:nTF ? Updated: 2013-01-13 \dim_compare_p:n { hdimexpr1 i hrelation1 i . in the sense that if one comparison is false. The test yields true if all comparisons are true.. 10 pt } { Negative } } { No idea! } will leave “Medium” in the input stream. and then evaluates the relationship between the two hdimension expressionsi as described for \dim_compare:nNnTF. For example \dim_set:Nn \l_tmpa_dim { 5 pt } \dim_case:nnn { 2 \l_tmpa_dim } { { 5 pt } { Small } { 4 pt + 6 pt } { Medium } { . {hdimexpr casen i} {hcode casen i} } {helse code i} This function evaluates the htest dimension expressioni and compares this in turn to each of the hdimension expression casesi. After the hcodei has been processed by TEX the test will be repeated. \dim_do_while:nNnn I \dim_do_while:nNnn {hdimexpr1 i} hrelation i {hdimexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process.. If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. \dim_until_do:nNnn I \dim_until_do:nNnn {hdimexpr1 i} hrelation i {hdimexpr2 i} {hcode i} Evaluates the relationship between the two hdimension expressionsi as described for \dim_compare:nNnTF.. 5 \dim_do_until:nNnn I Dimension expression loops \dim_do_until:nNnn {hdimexpr1 i} hrelation i {hdimexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process. and then evaluates the relationship between the two hdimension expressionsi as described for \dim_compare:nNnTF. and then places the hcodei in the input stream if the hrelationi is false. If none of the tests are true then the else code will be left in the input stream. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. and a loop will occur until the test is true. If the two are equal then the associated hcodei is left in the input stream.\dim_case:nnn ? New: 2012-06-03 \dim_case:nnn {htest dimension expression i} { {hdimexpr case1 i} {hcode case1 i} {hdimexpr case2 i} {hcode case2 i} . 80 . and then places the hcodei in the input stream if the hrelationi is true. and will require suitable termination if used in a TEX-style assignment as it is not an hinternal dimensioni. expanding any dimensions and token list variables within the hexpressioni to their content (without requiring \dim_use:N/\tl_use:N) and applying the standard mathematical rules. and then evaluates the hdimension relationi as described for \dim_compare:nTF. \dim_while_do:nn {hdimension relation i} {hcode i} Evaluates the hdimension relationi as described for \dim_compare:nTF. and a loop will occur until the test is false. After the hcodei has been processed by TEX the test will be repeated. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. and then places the hcodei in the input stream if the hrelationi is false. and then places the hcodei in the input stream if the hrelationi is true. \dim_until_do:nn {hdimension relation i} {hcode i} Evaluates the hdimension relationi as described for \dim_compare:nTF. and then evaluates the hdimension relationi as described for \dim_compare:nTF.\dim_while_do:nNnn I \dim_while_do:nNnn {hdimexpr1 i} hrelation i {hdimexpr2 i} {hcode i} Evaluates the relationship between the two hdimension expressionsi as described for \dim_compare:nNnTF. 81 . If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. This will be expressed in points (pt). The result of the calculation is left in the input stream as a hdimension denotationi after two expansions. and a loop will occur until the test is true. After the hcodei has been processed by TEX the test will be repeated. \dim_do_until:nn I Updated: 2013-01-13 \dim_do_while:nn I Updated: 2013-01-13 \dim_until_do:nn I Updated: 2013-01-13 \dim_while_do:nn I Updated: 2013-01-13 \dim_do_until:nn {hdimension relation i} {hcode i} Places the hcodei in the input stream for TEX to process. After the hcodei has been processed by TEX the test will be repeated. and a loop will occur until the test is false. \dim_do_while:nn {hdimension relation i} {hcode i} Places the hcodei in the input stream for TEX to process. 6 \dim_eval:n ? Updated: 2011-10-22 Using dim expressions and variables \dim_eval:n {hdimension expression i} Evaluates the hdimension expressioni. \dim_use:N ? \dim_use:c ? \dim_use:N hdimension i Recovers the content of a hdimensioni and places it directly in the input stream. An error will be raised if the variable does not exist or if it is invalid. Can be omitted in places where a hdimensioni is required (such as in the argument of \dim_eval:n). TEXhackers note: \dim_use:N is the TEX primitive \the: this is one of several LATEX3 names for this primitive. 7 \dim_show:N \dim_show:c \dim_show:n New: 2011-11-22 Viewing dim variables \dim_show:N hdimension i Displays the value of the hdimensioni on the terminal. \dim_show:n hdimension expression i Displays the result of evaluating the hdimension expressioni on the terminal. Updated: 2012-05-27 8 \c_max_dim \c_zero_dim Constant dimensions The maximum value that can be stored as a dimension. This can also be used as a component of a skip. A zero length as a dimension. This can also be used as a component of a skip. 9 Scratch dimensions \l_tmpa_dim \l_tmpb_dim Scratch dimension for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. \g_tmpa_dim \g_tmpb_dim Scratch dimension for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 82 10 \skip_new:N \skip_new:c \skip_const:Nn \skip_const:cn New: 2012-03-05 \skip_zero:N \skip_zero:c \skip_gzero:N \skip_gzero:c \skip_zero_new:N \skip_zero_new:c \skip_gzero_new:N \skip_gzero_new:c Creating and initialising skip variables \skip_new:N hskip i Creates a new hskipi or raises an error if the name is already taken. The declaration is global. The hskipi will initially be equal to 0 pt. \skip_const:Nn hskip i {hskip expression i} Creates a new constant hskipi or raises an error if the name is already taken. The value of the hskipi will be set globally to the hskip expressioni. \skip_zero:N hskip i Sets hskipi to 0 pt. \skip_zero_new:N hskip i Ensures that the hskipi exists globally by applying \skip_new:N if necessary, then applies \skip_(g)zero:N to leave the hskipi set to zero. New: 2012-01-07 \skip_if_exist_p:N \skip_if_exist_p:c \skip_if_exist:NTF \skip_if_exist:cTF ? ? ? ? \skip_if_exist_p:N hskip i \skip_if_exist:NTF hskip i {htrue code i} {hfalse code i} Tests whether the hskipi is currently defined. This does not check that the hskipi really is a skip variable. New: 2012-03-03 11 \skip_add:Nn \skip_add:cn \skip_gadd:Nn \skip_gadd:cn Setting skip variables \skip_add:Nn hskip i {hskip expression i} Adds the result of the hskip expressioni to the current content of the hskipi. Updated: 2011-10-22 \skip_set:Nn \skip_set:cn \skip_gset:Nn \skip_gset:cn \skip_set:Nn hskip i {hskip expression i} Sets hskipi to the value of hskip expressioni, which must evaluate to a length with units and may include a rubber component (for example 1 cm plus 0.5 cm. Updated: 2011-10-22 83 \skip_set_eq:NN \skip_set_eq:(cN|Nc|cc) \skip_gset_eq:NN \skip_gset_eq:(cN|Nc|cc) \skip_sub:Nn \skip_sub:cn \skip_gsub:Nn \skip_gsub:cn \skip_set_eq:NN hskip1 i hskip2 i Sets the content of hskip1 i equal to that of hskip2 i. \skip_sub:Nn hskip i {hskip expression i} Subtracts the result of the hskip expressioni from the current content of the hskipi. Updated: 2011-10-22 12 \skip_if_eq_p:nn ? \skip_if_eq:nnTF ? Skip expression conditionals \skip_if_eq_p:nn {hskipexpr1 i} {hskipexpr2 i} \dim_compare:nTF {hskipexpr1 i} {hskipexpr2 i} {htrue code i} {hfalse code i} This function first evaluates each of the hskip expressionsi as described for \skip_eval:n. The two results are then compared for exact equality, i.e. both the fixed and rubber components must be the same for the test to be true. \skip_if_finite_p:n ? \skip_if_finite:nTF ? New: 2012-03-05 \skip_if_finite_p:n {hskipexpr i} \skip_if_finite:nTF {hskipexpr i} {htrue code i} {hfalse code i} Evaluates the hskip expressioni as described for \skip_eval:n, and then tests if all of its components are finite. 13 Using skip expressions and variables \skip_eval:n ? \skip_eval:n {hskip expression i} Updated: 2011-10-22 Evaluates the hskip expressioni, expanding any skips and token list variables within the hexpressioni to their content (without requiring \skip_use:N/\tl_use:N) and applying the standard mathematical rules. The result of the calculation is left in the input stream as a hglue denotationi after two expansions. This will be expressed in points (pt), and will require suitable termination if used in a TEX-style assignment as it is not an hinternal gluei. 84 \skip_use:N ? \skip_use:c ? \skip_use:N hskip i Recovers the content of a hskipi and places it directly in the input stream. An error will be raised if the variable does not exist or if it is invalid. Can be omitted in places where a hdimensioni is required (such as in the argument of \skip_eval:n). TEXhackers note: \skip_use:N is the TEX primitive \the: this is one of several LATEX3 names for this primitive. 14 \skip_show:N \skip_show:c \skip_show:n New: 2011-11-22 Viewing skip variables \skip_show:N hskip i Displays the value of the hskipi on the terminal. \skip_show:n hskip expression i Displays the result of evaluating the hskip expressioni on the terminal. Updated: 2012-05-27 15 \c_max_skip Constant skips Updated: 2012-11-02 The maximum value that can be stored as a skip (equal to \c_max_dim in length), with no stretch nor shrink component. \c_zero_skip A zero length as a skip, with no stretch nor shrink component. Updated: 2012-11-01 16 Scratch skips \l_tmpa_skip \l_tmpb_skip Scratch skip for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. \g_tmpa_skip \g_tmpb_skip Scratch skip for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 85 17 \skip_horizontal:N \skip_horizontal:(c|n) Updated: 2011-10-22 Inserting skips into the output \skip_horizontal:N hskip i \skip_horizontal:n {hskipexpr i} Inserts a horizontal hskipi into the current list. TEXhackers note: \skip_horizontal:N is the TEX primitive \hskip renamed. \skip_vertical:N \skip_vertical:(c|n) Updated: 2011-10-22 \skip_vertical:N hskip i \skip_vertical:n {hskipexpr i} Inserts a vertical hskipi into the current list. TEXhackers note: \skip_vertical:N is the TEX primitive \vskip renamed. 18 \muskip_new:N \muskip_new:c \muskip_const:Nn \muskip_const:cn New: 2012-03-05 \muskip_zero:N \muskip_zero:c \muskip_gzero:N \muskip_gzero:c \muskip_zero_new:N \muskip_zero_new:c \muskip_gzero_new:N \muskip_gzero_new:c Creating and initialising muskip variables \muskip_new:N hmuskip i Creates a new hmuskipi or raises an error if the name is already taken. The declaration is global. The hmuskipi will initially be equal to 0 mu. \muskip_const:Nn hmuskip i {hmuskip expression i} Creates a new constant hmuskipi or raises an error if the name is already taken. The value of the hmuskipi will be set globally to the hmuskip expressioni. \skip_zero:N hmuskip i Sets hmuskipi to 0 mu. \muskip_zero_new:N hmuskip i Ensures that the hmuskipi exists globally by applying \muskip_new:N if necessary, then applies \muskip_(g)zero:N to leave the hmuskipi set to zero. New: 2012-01-07 \muskip_if_exist_p:N \muskip_if_exist_p:c \muskip_if_exist:NTF \muskip_if_exist:cTF ? ? ? ? \muskip_if_exist_p:N hmuskip i \muskip_if_exist:NTF hmuskip i {htrue code i} {hfalse code i} Tests whether the hmuskipi is currently defined. This does not check that the hmuskipi really is a muskip variable. New: 2012-03-03 86 19 \muskip_add:Nn \muskip_add:cn \muskip_gadd:Nn \muskip_gadd:cn Setting muskip variables \muskip_add:Nn hmuskip i {hmuskip expression i} Adds the result of the hmuskip expressioni to the current content of the hmuskipi. Updated: 2011-10-22 \muskip_set:Nn \muskip_set:cn \muskip_gset:Nn \muskip_gset:cn \muskip_set:Nn hmuskip i {hmuskip expression i} Sets hmuskipi to the value of hmuskip expressioni, which must evaluate to a math length with units and may include a rubber component (for example 1 mu plus 0.5 mu. Updated: 2011-10-22 \muskip_set_eq:NN \muskip_set_eq:(cN|Nc|cc) \muskip_gset_eq:NN \muskip_gset_eq:(cN|Nc|cc) \muskip_sub:Nn \muskip_sub:cn \muskip_gsub:Nn \muskip_gsub:cn \muskip_set_eq:NN hmuskip1 i hmuskip2 i Sets the content of hmuskip1 i equal to that of hmuskip2 i. \muskip_sub:Nn hmuskip i {hmuskip expression i} Subtracts the result of the hmuskip expressioni from the current content of the hskipi. Updated: 2011-10-22 20 \muskip_eval:n ? Updated: 2011-10-22 \muskip_use:N ? \muskip_use:c ? Using muskip expressions and variables \muskip_eval:n {hmuskip expression i} Evaluates the hmuskip expressioni, expanding any skips and token list variables within the hexpressioni to their content (without requiring \muskip_use:N/\tl_use:N) and applying the standard mathematical rules. The result of the calculation is left in the input stream as a hmuglue denotationi after two expansions. This will be expressed in mu, and will require suitable termination if used in a TEX-style assignment as it is not an hinternal mugluei. \muskip_use:N hmuskip i Recovers the content of a hskipi and places it directly in the input stream. An error will be raised if the variable does not exist or if it is invalid. Can be omitted in places where a hdimensioni is required (such as in the argument of \muskip_eval:n). TEXhackers note: \muskip_use:N is the TEX primitive \the: this is one of several LATEX3 names for this primitive. 87 21 Viewing muskip variables \muskip_show:N \muskip_show:c \muskip_show:N hmuskip i \muskip_show:n \muskip_show:n hmuskip expression i New: 2011-11-22 Displays the value of the hmuskipi on the terminal. Displays the result of evaluating the hmuskip expressioni on the terminal. Updated: 2012-05-27 22 \c_max_muskip \c_zero_muskip Constant muskips The maximum value that can be stored as a muskip, with no stretch nor shrink component. A zero length as a muskip, with no stretch nor shrink component. 23 Scratch muskips \l_tmpa_muskip \l_tmpb_muskip Scratch muskip for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. \g_tmpa_muskip \g_tmpb_muskip Scratch muskip for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 24 \if_dim:w Primitive conditional \if_dim:w hdimen1 i hrelation i hdimen2 i htrue code i \else: hfalse i \fi: Compare two dimensions. The hrelationi is one of <, = or > with category code 12. TEXhackers note: This is the TEX primitive \ifdim. 88 25 \__dim_eval:w ? \__dim_eval_end: ? Internal functions \__dim_eval:w hdimexpr i \__dim_eval_end: Evaluates hdimension expressioni as described for \dim_eval:n. The evaluation stops when an unexpandable token which is not a valid part of a dimension is read or when \__dim_eval_end: is reached. The latter is gobbled by the scanner mechanism: \__dim_eval_end: itself is unexpandable but used correctly the entire construct is expandable. TEXhackers note: This is the ε-TEX primitive \dimexpr. \__dim_strip_bp:n ? \__dim_strip_pt:n ? New: 2011-11-11 \__dim_strip_bp:n {hdimension expression i} \__dim_strip_pt:n {hdimension expression i} Evaluates the hdimension expressioni, expanding any dimensions and token list variables within the hexpressioni to their content (without requiring \dim_use:N/\tl_use:N) and applying the standard mathematical rules. The magnitude of the result, expressed in big points (bp) or points (pt), will be left in the input stream with no units. If the decimal part of the magnitude is zero, this will be omitted. If the {hdimension expressioni} contains additional units, these will be ignored, so for example \__dim_strip_pt:n { 1 bp pt } will leave 1.00374 in the input stream (i.e. the magnitude of one “big point” when converted to points). 89 Part XI The l3tl package Token lists TEX works with tokens, and LATEX3 therefore provides a number of functions to deal with lists of tokens. Token lists may be present directly in the argument to a function: \foo:n { a collection of \tokens } or may be stored in a so-called “token list variable”, which have the suffix tl: a token list variable can also be used as the argument to a function, for example \foo:N \l_some_tl In both cases, functions are available to test an manipulate the lists of tokens, and these have the module prefix tl. In many cases, function which can be applied to token list variables are paired with similar functions for application to explicit lists of tokens: the two “views” of a token list are therefore collected together here. A token list (explicit, or stored in a variable) can be seen either as a list of “items”, or a list of “tokens”. An item is whatever \use:n would grab as its argument: a single non-space token or a brace group, with optional leading explicit space characters (each item is thus itself a token list). A token is either a normal N argument, or ␣, {, or } (assuming normal TEX category codes). Thus for example { Hello } ~ world contains six items (Hello, w, o, r, l and d), but thirteen tokens ({, H, e, l, l, o, }, ␣, w, o, r, l and d). Functions which act on items are often faster than their analogue acting directly on tokens. TEXhackers note: When TEX fetches an undelimited argument from the input stream, explicit character tokens with character code 32 (space) and category code 10 (space), which we here call “explicit space characters”, are ignored. If the following token is an explicit character token with category code 1 (begin-group) and an arbitrary character code, then TEX scans ahead to obtain an equal number of explicit character tokens with category code 1 (begin-group) and 2 (end-group), and the resulting list of tokens (with outer braces removed) becomes the argument. Otherwise, a single token is taken as the argument for the macro: we call such single tokens “N-type”, as they are suitable to be used as an argument for a function with the signature :N. When TEX reads a character of category code 10 for the first time, it is converted to an explicit space character, with character code 32, regardless of the initial character code. “Funny” spaces with a different category code, can be produced using \tl_to_lowercase:n or \tl_to_uppercase:n. Explicit space characters are also produced as a result of \token_to_str:N, \tl_to_str:n, etc. 90 1 \tl_new:N \tl_new:c \tl_const:Nn \tl_const:(Nx|cn|cx) \tl_clear:N \tl_clear:c \tl_gclear:N \tl_gclear:c \tl_clear_new:N \tl_clear_new:c \tl_gclear_new:N \tl_gclear_new:c \tl_set_eq:NN \tl_set_eq:(cN|Nc|cc) \tl_gset_eq:NN \tl_gset_eq:(cN|Nc|cc) \tl_concat:NNN \tl_concat:ccc \tl_gconcat:NNN \tl_gconcat:ccc Creating and initialising token list variables \tl_new:N htl var i Creates a new htl vari or raises an error if the name is already taken. The declaration is global. The htl vari will initially be empty. \tl_const:Nn htl var i {htoken list i} Creates a new constant htl vari or raises an error if the name is already taken. The value of the htl vari will be set globally to the htoken listi. \tl_clear:N htl var i Clears all entries from the htl vari within the scope of the current TEX group. \tl_clear_new:N htl var i Ensures that the htl vari exists globally by applying \tl_new:N if necessary, then applies \tl_(g)clear:N to leave the htl vari empty. \tl_set_eq:NN htl var1 i htl var2 i Sets the content of htl var1 i equal to that of htl var2 i. \tl_concat:NNN htl var1 i htl var2 i htl var3 i Concatenates the content of htl var2 i and htl var3 i together and saves the result in htl var1 i. The htl var2 i will be placed at the left side of the new token list. New: 2012-05-18 \tl_if_exist_p:N \tl_if_exist_p:c \tl_if_exist:NTF \tl_if_exist:cTF ? ? ? ? \tl_if_exist_p:N htl var i \tl_if_exist:NTF htl var i {htrue code i} {hfalse code i} Tests whether the htl vari is currently defined. This does not check that the htl vari really is a token list variable. New: 2012-03-03 91 2 Adding data to token list variables \tl_set:Nn \tl_set:(NV|Nv|No|Nf|Nx|cn|cV|cv|co|cf|cx) \tl_gset:Nn \tl_gset:(NV|Nv|No|Nf|Nx|cn|cV|cv|co|cf|cx) \tl_set:Nn htl var i {htokens i} Sets htl vari to contain htokensi, removing any previous content from the variable. \tl_put_left:Nn \tl_put_left:(NV|No|Nx|cn|cV|co|cx) \tl_gput_left:Nn \tl_gput_left:(NV|No|Nx|cn|cV|co|cx) \tl_put_left:Nn htl var i {htokens i} Appends htokensi to the left side of the current content of htl vari. \tl_put_right:Nn \tl_put_right:(NV|No|Nx|cn|cV|co|cx) \tl_gput_right:Nn \tl_gput_right:(NV|No|Nx|cn|cV|co|cx) \tl_put_right:Nn htl var i {htokens i} Appends htokensi to the right side of the current content of htl vari. 3 \tl_replace_once:Nnn \tl_replace_once:cnn \tl_greplace_once:Nnn \tl_greplace_once:cnn Modifying token list variables \tl_replace_once:Nnn htl var i {hold tokens i} {hnew tokens i} Replaces the first (leftmost) occurrence of hold tokensi in the htl vari with hnew tokensi. hOld tokensi cannot contain {, } or # (more precisely, explicit character tokens with category code 1 (begin-group) or 2 (end-group), and tokens with category code 6). Updated: 2011-08-11 \tl_replace_all:Nnn \tl_replace_all:cnn \tl_greplace_all:Nnn \tl_greplace_all:cnn Updated: 2011-08-11 \tl_remove_once:Nn \tl_remove_once:cn \tl_gremove_once:Nn \tl_gremove_once:cn \tl_replace_all:Nnn htl var i {hold tokens i} {hnew tokens i} Replaces all occurrences of hold tokensi in the htl vari with hnew tokensi. hOld tokensi cannot contain {, } or # (more precisely, explicit character tokens with category code 1 (begin-group) or 2 (end-group), and tokens with category code 6). As this function operates from left to right, the pattern hold tokensi may remain after the replacement (see \tl_remove_all:Nn for an example). \tl_remove_once:Nn htl var i {htokens i} Removes the first (leftmost) occurrence of htokensi from the htl vari. hTokensi cannot contain {, } or # (more precisely, explicit character tokens with category code 1 (begingroup) or 2 (end-group), and tokens with category code 6). Updated: 2011-08-11 92 \tl_remove_all:Nn \tl_remove_all:cn \tl_gremove_all:Nn \tl_gremove_all:cn Updated: 2011-08-11 \tl_remove_all:Nn htl var i {htokens i} Removes all occurrences of htokensi from the htl vari. hTokensi cannot contain {, } or # (more precisely, explicit character tokens with category code 1 (begin-group) or 2 (endgroup), and tokens with category code 6). As this function operates from left to right, the pattern htokensi may remain after the removal, for instance, \tl_set:Nn \l_tmpa_tl {abbccd} \tl_remove_all:Nn \l_tmpa_tl {bc} will result in \l_tmpa_tl containing abcd. 4 Reassigning token list category codes \tl_set_rescan:Nnn \tl_set_rescan:(Nno|Nnx|cnn|cno|cnx) \tl_gset_rescan:Nnn \tl_gset_rescan:(Nno|Nnx|cnn|cno|cnx) \tl_set_rescan:Nnn htl var i {hsetup i} {htokens i} Updated: 2011-12-18 Sets htl vari to contain htokensi, applying the category code régime specified in the hsetupi before carrying out the assignment. This allows the htl vari to contain material with category codes other than those that apply when htokensi are absorbed. See also \tl_rescan:nn. \tl_rescan:nn \tl_rescan:nn {hsetup i} {htokens i} Updated: 2011-12-18 Rescans htokensi applying the category code régime specified in the hsetupi, and leaves the resulting tokens in the input stream. See also \tl_set_rescan:Nnn. 5 \tl_to_lowercase:n Updated: 2012-09-08 Reassigning token list character codes \tl_to_lowercase:n {htokens i} Works through all of the htokensi, replacing each character token with the lower case equivalent as defined by \char_set_lccode:nn. Characters with no defined lower case character code are left unchanged. This process does not alter the category code assigned to the htokensi. TEXhackers note: This is a wrapper around the TEX primitive \lowercase. 93 \tl_to_uppercase:n Updated: 2012-09-08 \tl_to_uppercase:n {htokens i} Works through all of the htokensi, replacing each character token with the upper case equivalent as defined by \char_set_uccode:nn. Characters with no defined upper case character code are left unchanged. This process does not alter the category code assigned to the htokensi. TEXhackers note: This is a wrapper around the TEX primitive \uppercase. 6 Token list conditionals \tl_if_blank_p:n \tl_if_blank_p:(V|o) \tl_if_blank:nTF \tl_if_blank:(V|o)TF ? ? ? ? \tl_if_blank_p:n {htoken list i} \tl_if_blank:nTF {htoken list i} {htrue code i} {hfalse code i} \tl_if_empty_p:N \tl_if_empty_p:c \tl_if_empty:NTF \tl_if_empty:cTF ? ? ? ? \tl_if_empty_p:N htl var i \tl_if_empty:NTF htl var i {htrue code i} {hfalse code i} \tl_if_empty_p:n \tl_if_empty_p:(V|o) \tl_if_empty:nTF \tl_if_empty:(V|o)TF ? ? ? ? \tl_if_empty_p:n {htoken list i} \tl_if_empty:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the htoken listi consists only of blank spaces (i.e. contains no item). The test is true if htoken listi is zero or more explicit space characters (explicit tokens with character code 32 and category code 10), and is false otherwise. Tests if the htoken list variablei is entirely empty (i.e. contains no tokens at all). Tests if the htoken listi is entirely empty (i.e. contains no tokens at all). New: 2012-05-24 Updated: 2012-06-05 \tl_if_eq_p:NN \tl_if_eq_p:(Nc|cN|cc) \tl_if_eq:NNTF \tl_if_eq:(Nc|cN|cc)TF ? ? ? ? \tl_if_eq_p:NN {htl var1 i} {htl var2 i} \tl_if_eq:NNTF {htl var1 i} {htl var2 i} {htrue code i} {hfalse code i} Compares the content of two htoken list variablesi and is logically true if the two contain the same list of tokens (i.e. identical in both the list of characters they contain and the category codes of those characters). Thus for example \tl_set:Nn \l_tmpa_tl { abc } \tl_set:Nx \l_tmpb_tl { \tl_to_str:n { abc } } \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl { true } { false } yields false. \tl_if_eq:nnTF \tl_if_eq:nnTF htoken list1 i {htoken list2 i} {htrue code i} {hfalse code i} Tests if htoken list1 i and htoken list2 i contain the same list of tokens, both in respect of character codes and category codes. 94 \tl_if_in:NnTF \tl_if_in:cnTF \tl_if_in:nnTF \tl_if_in:(Vn|on|no)TF \tl_if_single_p:N \tl_if_single_p:c \tl_if_single:NTF \tl_if_single:cTF ? ? ? ? Updated: 2011-08-13 \tl_if_single_p:n ? \tl_if_single:nTF ? Updated: 2011-08-13 \tl_case:Nnn ? \tl_case:cnn ? New: 2012-06-03 \tl_if_in:NnTF htl var i {htoken list i} {htrue code i} {hfalse code i} Tests if the htoken listi is found in the content of the htl vari. The htoken listi cannot contain the tokens {, } or # (more precisely, explicit character tokens with category code 1 (begin-group) or 2 (end-group), and tokens with category code 6). \tl_if_in:nnTF {htoken list1 i} {htoken list2 i} {htrue code i} {hfalse code i} Tests if htoken list2 i is found inside htoken list1 i. The htoken list2 i cannot contain the tokens {, } or # (more precisely, explicit character tokens with category code 1 (begingroup) or 2 (end-group), and tokens with category code 6). \tl_if_single_p:N htl var i \tl_if_single:NTF htl var i {htrue code i} {hfalse code i} Tests if the content of the htl vari consists of a single item, i.e. is a single normal token (neither an explicit space character nor a begin-group character) or a single brace group, surrounded by optional spaces on both sides. In other words, such a token list has token count 1 according to \tl_count:N. \tl_if_single_p:n {htoken list i} \tl_if_single:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the htoken listi has exactly one item, i.e. is a single normal token (neither an explicit space character nor a begin-group character) or a single brace group, surrounded by optional spaces on both sides. In other words, such a token list has token count 1 according to \tl_count:n. \tl_case:Nnn htest token { htoken list variable htoken list variable ... htoken list variable } {helse code i} list variable i case1 i {hcode case1 i} case2 i {hcode case2 i} casen i {hcode casen i} This function compares the htest token list variablei in turn with each of the htoken list variable casesi. If the two are equal (as described for \tl_if_eq:NNTF) then the associated hcodei is left in the input stream. If none of the tests are true then the else code will be left in the input stream. 7 \tl_map_function:NN I \tl_map_function:cN I Updated: 2012-06-29 Mapping to token lists \tl_map_function:NN htl var i hfunction i Applies hfunctioni to every hitemi in the htl vari. The hfunctioni will receive one argument for each iteration. This may be a number of tokens if the hitemi was stored within braces. Hence the hfunctioni should anticipate receiving n-type arguments. See also \tl_map_function:nN. 95 \tl_map_function:nN I Updated: 2012-06-29 \tl_map_inline:Nn \tl_map_inline:cn Updated: 2012-06-29 \tl_map_inline:nn Updated: 2012-06-29 \tl_map_variable:NNn \tl_map_variable:cNn Updated: 2012-06-29 \tl_map_variable:nNn Updated: 2012-06-29 \tl_map_break: I Updated: 2012-06-29 \tl_map_function:nN htoken list i hfunction i Applies hfunctioni to every hitemi in the htoken listi, The hfunctioni will receive one argument for each iteration. This may be a number of tokens if the hitemi was stored within braces. Hence the hfunctioni should anticipate receiving n-type arguments. See also \tl_map_function:NN. \tl_map_inline:Nn htl var i {hinline function i} Applies the hinline functioni to every hitemi stored within the htl vari. The hinline functioni should consist of code which will receive the hitemi as #1. One in line mapping can be nested inside another. See also \tl_map_function:NN. \tl_map_inline:nn htoken list i {hinline function i} Applies the hinline functioni to every hitemi stored within the htoken listi. The hinline functioni should consist of code which will receive the hitemi as #1. One in line mapping can be nested inside another. See also \tl_map_function:nN. \tl_map_variable:NNn htl var i hvariable i {hfunction i} Applies the hfunctioni to every hitemi stored within the htl vari. The hfunctioni should consist of code which will receive the hitemi stored in the hvariablei. One variable mapping can be nested inside another. See also \tl_map_inline:Nn. \tl_map_variable:nNn htoken list i hvariable i {hfunction i} Applies the hfunctioni to every hitemi stored within the htoken listi. The hfunctioni should consist of code which will receive the hitemi stored in the hvariablei. One variable mapping can be nested inside another. See also \tl_map_inline:nn. \tl_map_break: Used to terminate a \tl_map_... function before all entries in the htoken list variablei have been processed. This will normally take place within a conditional statement, for example \tl_map_inline:Nn \l_my_tl { \str_if_eq:nnT { #1 } { bingo } { \tl_map_break: } % Do something useful } See also \tl_map_break:n. Use outside of a \tl_map_... scenario will lead to low level TEX errors. TEXhackers note: When the mapping is broken, additional tokens may be inserted by the internal macro \__prg_break_point:Nn before the htokensi are inserted into the input stream. This will depend on the design of the mapping function. 96 97 . \tl_to_str:n {htokens i} Converts the given htokensi into a series of characters with category code 12 (other) with the exception of spaces.. An error will be raised if the variable does not exist or if it is invalid.. which retain category code 10 (space).\tl_map_break:n I Updated: 2012-06-29 \tl_map_break:n {htokens i} Used to terminate a \tl_map_. \tl_use:N ? \tl_use:c ? \tl_use:N htl var i Recovers the content of a htl vari and places it directly in the input stream. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before the htokensi are inserted into the input stream.. Note that this function requires only a single expansion. which retain category code 10 (space). scenario will lead to low level TEX errors. inserting the htokensi after the mapping has ended. TEXhackers note: When the mapping is broken. TEXhackers note: This is the ε-TEX primitive \detokenize. for example \tl_map_inline:Nn \l_my_tl { \str_if_eq:nnT { #1 } { bingo } { \tl_map_break:n { <tokens> } } % Do something useful } Use outside of a \tl_map_. Hence its argument must be given within braces. function before all entries in the htoken list variablei have been processed. This hstringi is then left in the input stream. Note that it is possible to use a htl vari directly without an accessor function. 8 \tl_to_str:N ? \tl_to_str:c ? \tl_to_str:n ? Using token lists \tl_to_str:N htl var i Converts the content of the htl vari into a series of characters with category code 12 (other) with the exception of spaces. This will normally take place within a conditional statement. This hstringi is then left in the input stream. This will depend on the design of the mapping function.. Items which are initially not braced are copied with braces in the result. . .9 \tl_count:n ? \tl_count:(V|o) ? New: 2012-05-13 \tl_count:N ? \tl_count:c ? New: 2012-05-13 \tl_reverse:n ? \tl_reverse:(V|o) ? Updated: 2012-01-08 Working with the content of token lists \tl_count:n {htokens i} Counts the number of hitemsi in htokensi and leaves this information in the input stream. consider the slower function \tl_reverse:n. See also \tl_reverse:n. TEXhackers note: The result is returned within \exp_not:n. Unbraced tokens count as one element as do each token group ({. }). . . . so that hitem1 ihitem2 ihitem3 i . This process will ignore any unprotected spaces within htokensi. hitemn i becomes hitemn i. hitemn i becomes hitemn i. but keep the outer set of braces. \tl_reverse_items:n {htoken list i} Reverses the order of the hitemsi stored in htl vari. . }). for improved performance. which keep their outer set of braces. and keep the outer set of braces. . 98 . . Unbraced tokens count as one element as do each token group ({. which means that the token list will not expand further when appearing in an x-type argument expansion. . consider \tl_reverse_items:n. . See also \tl_reverse:N. . . . Tokens are not reversed within braced token groups. \tl_reverse_items:n. giving an hinteger denotationi. In situations where performance is important. hitem3 ihitem2 ihitem1 i. hitem3 ihitem2 ihitem1 i. and. This process will preserve unprotected space within the htoken listi. \tl_reverse:n {htoken list i} Reverses the order of the hitemsi in the htoken listi. which means that the token list will not expand further when appearing in an x-type argument expansion. \tl_reverse:N \tl_reverse:c \tl_greverse:N \tl_greverse:c Updated: 2012-01-08 \tl_reverse_items:n ? New: 2012-01-08 \tl_reverse:N htl var i Reverses the order of the hitemsi stored in htl vari. Braced token groups are copied without reversing the order of tokens. {hitemn i} becomes {hitemn i} . so that {hitem1 i}{hitem2 i}{hitem3 i} . TEXhackers note: The result is returned within \exp_not:n. This process will ignore any unprotected spaces within the htl vari. so that hitem1 ihitem2 ihitem3 i . giving an hinteger denotationi. {hitem3 i}{hitem2 i}{hitem1 i}. \tl_count:N htl var i Counts the number of token groups in the htl vari and leaves this information in the input stream. In cases where preserving spaces is important. This process will preserve unprotected spaces within the htoken list variablei. This function requires three expansions. . Braced token groups are copied without reversing the order of tokens. See also \tl_count:n. This process will remove any unprotected space within the htoken listi. . See also \tl_count:N. This function requires three expansions. . 99 . discarding the rest of the htoken listi. which means that the token list will not expand further when appearing in an x-type argument expansion.\tl_trim_spaces:n ? New: 2011-07-09 Updated: 2012-06-25 \tl_trim_spaces:n {htoken list i} Removes any leading and trailing explicit space characters (explicit tokens with character code 32 and category code 10) from the htoken listi and leaves the result in the input stream. or the remaining tokens. which means that the token list will not expand further when appearing in an x-type argument expansion. the braces will be removed. \tl_head:N ? \tl_head:(n|V|v|f) ? Updated: 2012-09-09 \tl_head:n {htoken list i} Leaves in the input stream the first hitemi in the htoken listi. New: 2011-07-09 10 The first token from a token list Functions which deal with either only the very first item (balanced text or single normal token) in a token list. for example \tl_head:n { abc } and \tl_head:n { ~ abc } will both leave a in the input stream. All leading explicit space characters (explicit tokens with character code 32 and category code 10) are discarded. TEXhackers note: The result is returned within \exp_not:n. and so \tl_head:n { ~ { ~ ab } c } yields ␣ab. rather than a single token. If the “head” is a brace group. \tl_trim_spaces:N \tl_trim_spaces:c \tl_gtrim_spaces:N \tl_gtrim_spaces:c \tl_trim_spaces:N htl var i Removes any leading and trailing explicit space characters (explicit tokens with character code 32 and category code 10) from the content of the htl vari. TEXhackers note: The result is returned within \exp_not:n. A blank htoken listi (see \tl_if_blank:nTF) will result in \tl_head:n leaving nothing in the input stream. as described for \tl_to_str:n. and thus is suitable for use within an o-type expansion. which may be avoided by the inclusion of an empty group in the input (as shown). nothing is left in the input stream. The first character may be a space. Alternatively. All leading explicit space characters (explicit tokens with character code 32 and category code 10) are discarded. The \str_tail:n function leaves all characters except the first in the input stream. \tl_if_blank:nF may be used to avoid using the function with a “blank” argument. and leaves the remaining tokens in the input stream. \tl_tail:N ? \tl_tail:(n|V|v|f) ? Updated: 2012-09-01 \tl_tail:n {htoken list i} Discards all leading explicit space characters (explicit tokens with character code 32 and category code 10) and the first hitemi in the htoken listi. A blank htoken listi (which consists only of space characters) will result in a low-level TEX error. This function requires only a single expansion. 100 . \tl_head:n should be preferred if the number of expansions is not critical. which means that the token list will not expand further when appearing in an x-type argument expansion. \tl_if_head_eq_catcode_p:nN ? \tl_if_head_eq_catcode:nNTF ? Updated: 2012-07-09 \tl_if_head_eq_catcode_p:nN {htoken list i} htest token i \tl_if_head_eq_catcode:nNTF {htoken list i} htest token i {htrue code i} {hfalse code i} Tests if the first htokeni in the htoken listi has the same category code as the htest tokeni. In general. the test will always be false. TEXhackers note: The result is returned within \exp_not:n. Thus for example \tl_tail:n { a ~ {bc} d } and \tl_tail:n { ~ a ~ {bc} d } will both leave ␣{bc}d in the input stream. A blank htoken listi (see \tl_if_blank:nTF) will result in \tl_tail:n leaving nothing in the input stream. \str_head:n ? \str_tail:n ? New: 2011-08-10 \str_head:n {htoken list i} \str_tail:n {htoken list i} Converts the htoken listi into a string.\tl_head:w ? \tl_head:w htoken list i { } \q_stop Leaves in the input stream the first hitemi in the htoken listi. without the need for an explicit test. The \str_head:n function then leaves the first character of this string in the input stream. If the htoken listi argument is entirely empty. In the case where the htoken listi is empty. discarding the rest of the htoken listi. the test is false if the htoken listi starts with an implicit token such as \c_group_begin_token. or if it is empty. the test will always be false. \tl_if_head_is_group_p:n ? \tl_if_head_is_group:nTF ? New: 2012-07-08 \tl_if_head_is_group_p:n {htoken list i} \tl_if_head_is_group:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the first htokeni in the htoken listi is an explicit begin-group character (with category code 1 and any character code). 101 . In the case where the htoken listi is empty. In particular. or if it is empty. In particular. \tl_if_head_is_N_type_p:n ? \tl_if_head_is_N_type:nTF ? \tl_if_head_is_N_type_p:n {htoken list i} \tl_if_head_is_N_type:nTF {htoken list i} {htrue code i} {hfalse code i} New: 2012-07-08 Tests if the first htokeni in the htoken listi is a normal N-type argument. \tl_if_head_is_space_p:n ? \tl_if_head_is_space:nTF ? Updated: 2012-07-08 \tl_if_head_is_space_p:n {htoken list i} \tl_if_head_is_space:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the first htokeni in the htoken listi is an explicit space character (explicit token with character code 12 and category code 10). An empty argument yields false.\tl_if_head_eq_charcode_p:nN \tl_if_head_eq_charcode_p:fN \tl_if_head_eq_charcode:nNTF \tl_if_head_eq_charcode:fNTF ? ? ? ? \tl_if_head_eq_charcode_p:nN {htoken list i} htest token i \tl_if_head_eq_charcode:nNTF {htoken list i} htest token i {htrue code i} {hfalse code i} Updated: 2012-07-09 Tests if the first htokeni in the htoken listi has the same character code as the htest tokeni. if the htoken listi starts with a brace group. it is neither an explicit space character (explicit token with character code 32 and category code 10) nor an explicit begin-group character (with category code 1 and any character code). as it does not have a “normal” first token. In the case where htoken listi is empty. the test will always be false. the test is false if the htoken listi starts with an implicit token such as \c_space_token. This function is useful to implement actions on token lists on a token by token basis. \tl_if_head_eq_meaning_p:nN ? \tl_if_head_eq_meaning:nNTF ? Updated: 2012-07-09 \tl_if_head_eq_meaning_p:nN {htoken list i} htest token i \tl_if_head_eq_meaning:nNTF {htoken list i} htest token i {htrue code i} {hfalse code i} Tests if the first htokeni in the htoken listi has the same meaning as the htest tokeni. This function is useful to implement actions on token lists on a token by token basis. This function is useful to implement actions on token lists on a token by token basis. in other words. In other words. they may be overwritten by other non-kernel code and so should only be used for short-term storage. However. It is a constant that is set by TEX and should not be overwritten by the package. For use where an explicit space is required. However. Constant that gets the “job name” assigned when TEX starts. These are never used by the kernel code. and so are safe for use with any LATEX3-defined function. TEXhackers note: This copies the contents of the primitive \jobname. Updated: 2012-09-09 TEXhackers note: This is similar to the TEX primitive \show. An explicit space character contained in a token list (compare this with \c_space_token). These are never used by the kernel code. 12 \c_empty_tl \c_job_name_tl Updated: 2011-08-18 \c_space_tl Constant token lists Constant that is always empty. TEXhackers note: This is similar to the ε-TEX primitive \showtokens. \tl_show:n \tl_show:n htoken list i Updated: 2012-09-09 Displays the htoken listi on the terminal. 102 . wrapped to a fixed number of characters per line. 13 Scratch token lists \l_tmpa_tl \l_tmpb_tl Scratch token lists for local assignment. \g_tmpa_tl \g_tmpb_tl Scratch token lists for global assignment. wrapped to a fixed number of characters per line. and so are safe for use with any LATEX3-defined function.11 \tl_show:N \tl_show:c Viewing token lists \tl_show:N htl var i Displays the content of the htl vari on the terminal. they may be overwritten by other non-kernel code and so should only be used for short-term storage. For instance. 103 . followed by a brace group containing \use_none:n \q_mark htrimmed token listi. and the o-type expansion removes the \q_mark. \tl_trim_spaces:n is implemented by taking the hcontinuationi to be \exp_not:o. and expands to the hcontinuationi.14 \__tl_trim_spaces:nn Internal functions \__tl_trim_spaces:nn { \q_mark htoken list i } {hcontinuation i} This function removes all leading and trailing explicit space characters from the htoken listi. This function is also used in l3clist and l3candidates. \seq_clear:N hsequence i Clears all items from the hsequencei. the htoken listi is split into hitemsi as a htoken listi. Empty hitemsi are preserved by \seq_set_split:Nnn. If the hdelimiteri is empty. and can be removed afterwards using \seq_remove_all:Nn hsequencei {hi}. then one set of outer braces is removed (if any). The hsequencei will initially contain no items. \seq_clear_new:N hsequence i Ensures that the hsequencei exists globally by applying \seq_new:N if necessary. 1 \seq_new:N \seq_new:c \seq_clear:N \seq_clear:c \seq_gclear:N \seq_gclear:c \seq_clear_new:N \seq_clear_new:c \seq_gclear_new:N \seq_gclear_new:c \seq_set_eq:NN \seq_set_eq:(cN|Nc|cc) \seq_gset_eq:NN \seq_gset_eq:(cN|Nc|cc) \seq_set_split:Nnn \seq_set_split:NnV \seq_gset_split:Nnn \seq_gset_split:NnV New: 2011-08-15 Updated: 2012-07-02 Creating and initialising sequences \seq_new:N hsequence i Creates a new hsequencei or raises an error if the name is already taken. It is possible to map functions to sequences such that the function is applied to every item in the sequence. } or # (assuming TEX’s normal category code régime). Sequences are also used to implement stack functions in LATEX3. 104 . \seq_set_eq:NN hsequence1 i hsequence2 i Sets the content of hsequence1 i equal to that of hsequence2 i. \seq_set_split:Nnn hsequence i {hdelimiter i} {htoken list i} Splits the htoken listi into hitemsi separated by hdelimiteri. which contain an ordered list of entries which may contain any hbalanced texti. The hdelimiteri may not contain {. this space trimming behaviour is identical to that of l3clist functions.Part XII The l3seq package Sequences and stacks LATEX3 implements a “sequence” data type. then applies \seq_(g)clear:N to leave the hsequencei empty. The declaration is global. Spaces on both sides of each hitemi are ignored. This is achieved using a number of dedicated stack functions. and assigns the result to the hsequencei. setting the htoken list variablei used with \tl_set:Nn and never \tl_gset:Nn. \seq_if_exist_p:N hsequence i \seq_if_exist:NTF hsequence i {htrue code i} {hfalse code i} Tests whether the hsequencei is currently defined. 105 . The items in hsequence2 i will be placed at the left side of the new sequence. \seq_get_right:NN hsequence i htoken list variable i Stores the right-most item from a hsequencei in the htoken list variablei without removing it from the hsequencei. These functions all assign the recovered material locally.\seq_concat:NNN \seq_concat:ccc \seq_gconcat:NNN \seq_gconcat:ccc \seq_if_exist_p:N \seq_if_exist_p:c \seq_if_exist:NTF \seq_if_exist:cTF ? ? ? ? \seq_concat:NNN hsequence1 i hsequence2 i hsequence3 i Concatenates the content of hsequence2 i and hsequence3 i together and saves the result in hsequence1 i.e. \seq_put_right:Nn \seq_put_right:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_gput_right:Nn \seq_gput_right:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_put_right:Nn hsequence i {hitem i} Appends the hitemi to the right of the hsequencei. \seq_get_left:NN \seq_get_left:cN Updated: 2012-05-14 \seq_get_right:NN \seq_get_right:cN Updated: 2012-05-19 \seq_get_left:NN hsequence i htoken list variable i Stores the left-most item from a hsequencei in the htoken list variablei without removing it from the hsequencei. This does not check that the hsequencei really is a sequence variable. The htoken list variablei is assigned locally. the actions at the left of the sequence are faster than those acting on the right. The htoken list variablei is assigned locally. i. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. New: 2012-03-03 2 Appending data to sequences \seq_put_left:Nn \seq_put_left:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_gput_left:Nn \seq_gput_left:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_put_left:Nn hsequence i {hitem i} Appends the hitemi to the left of the hsequencei. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. 3 Recovering items from sequences Items can be recovered from either the left or the right of sequences. For implementation reasons. The hsequencei is modified globally. 106 . If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. Both of the variables are assigned locally. \seq_get_left:NNTF \seq_get_left:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_get_right:NNTF \seq_get_right:cNTF New: 2012-05-19 \seq_get_left:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. stores the right-most item from a hsequencei in the htoken list variablei without removing it from a hsequencei. The htoken list variablei is assigned locally. i. The value of the htoken list variablei is not defined in this case and should not be relied upon. The value of the htoken list variablei is not defined in this case and should not be relied upon. If the hsequencei is non-empty. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. while the assignment of the htoken list variablei is local. The hsequencei is modified globally. i. removes the item from the sequence and stores it in in the htoken list variablei. leaves the hfalse codei in the input stream. \seq_gpop_right:NN hsequence i htoken list variable i Pops the right-most item from a hsequencei into the htoken list variablei.\seq_pop_left:NN \seq_pop_left:cN Updated: 2012-05-14 \seq_gpop_left:NN \seq_gpop_left:cN Updated: 2012-05-14 \seq_pop_right:NN \seq_pop_right:cN Updated: 2012-05-19 \seq_gpop_right:NN \seq_gpop_right:cN Updated: 2012-05-19 \seq_pop_left:NN hsequence i htoken list variable i Pops the left-most item from a hsequencei into the htoken list variablei. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. removes the item from the sequence and stores it in the htoken list variablei.e.e.e. \seq_get_right:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. leaves the hfalse codei in the input stream. The htoken list variablei is assigned locally. 4 Recovering values from sequences with branching The functions in this section combine tests for non-empty sequences with recovery of an item from the sequence. removes the item from the sequence and stores it in the htoken list variablei. stores the left-most item from a hsequencei in the htoken list variablei without removing it from a hsequencei. i. \seq_gpop_left:NN hsequence i htoken list variable i Pops the left-most item from a hsequencei into the htoken list variablei. If the hsequencei is non-empty. They offer increased readability and performance over separate testing and recovery phases. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. i. \seq_pop_right:NN hsequence i htoken list variable i Pops the right-most item from a hsequencei into the htoken list variablei. Both of the variables are assigned locally.e. removes the item from the sequence and stores it in the htoken list variablei. while the assignment of the htoken list variablei is local. leaving the left most copy of each item in the hsequencei. pops the right-most item from a hsequencei in the htoken list variablei.e. i. removes the item from a hsequencei. leaves the hfalse codei in the input stream. The hsequencei is modified globally. The value of the htoken list variablei is not defined in this case and should not be relied upon.e. The functions here may be used to update sequences. \seq_remove_duplicates:N \seq_remove_duplicates:c \seq_gremove_duplicates:N \seq_gremove_duplicates:c \seq_remove_duplicates:N hsequence i Removes duplicate items from the hsequencei. The hitemi comparison takes place on a token basis. i. pops the right-most item from a hsequencei in the htoken list variablei. 5 Modifying sequences While sequences are normally used as ordered lists.e. removes the item from a hsequencei. i. TEXhackers note: This function iterates through every item in the hsequencei and does a comparison with the hitemsi already checked. it may be necessary to modify the content. 107 . leaves the hfalse codei in the input stream. Both the hsequencei and the htoken list variablei are assigned locally. i. pops the left-most item from a hsequencei in the htoken list variablei. If the hsequencei is non-empty. If the hsequencei is non-empty. leaves the hfalse codei in the input stream. pops the left-most item from a hsequencei in the htoken list variablei. The value of the htoken list variablei is not defined in this case and should not be relied upon. removes the item from a hsequencei. while retaining the order of the unaffected entries. leaves the hfalse codei in the input stream. It is therefore relatively slow with large sequences.\seq_pop_left:NNTF \seq_pop_left:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_gpop_left:NNTF \seq_gpop_left:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_pop_right:NNTF \seq_pop_right:cNTF New: 2012-05-19 \seq_gpop_right:NNTF \seq_gpop_right:cNTF New: 2012-05-19 \seq_pop_left:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. Both the hsequencei and the htoken list variablei are assigned locally. If the hsequencei is non-empty. while the htoken list variablei is assigned locally. as for \tl_if_eq:nn(TF).e. The hsequencei is modified globally. The value of the htoken list variablei is not defined in this case and should not be relied upon. If the hsequencei is non-empty. removes the item from a hsequencei. while the htoken list variablei is assigned locally. \seq_gpop_right:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. \seq_pop_right:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. \seq_gpop_left:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. The value of the htoken list variablei is not defined in this case and should not be relied upon. The function \seq_map_inline:Nn is faster than \seq_map_function:NN for sequences with more than about 10 items. One mapping may be nested inside another.i and applies the hfunction using tl var. 7 \seq_map_function:NN I \seq_map_function:cN I Updated: 2012-06-29 \seq_map_inline:Nn \seq_map_inline:cn Updated: 2012-06-29 Mapping to sequences \seq_map_function:NN hsequence i hfunction i Applies hfunctioni to every hitemi stored in the hsequencei. i {hfunction using tl var. 108 . \seq_map_inline:Nn hsequence i {hinline function i} Applies hinline functioni to every hitemi stored within the hsequencei.i.i The hfunctioni will usually consist of code making use of the htl var.\seq_remove_all:Nn \seq_remove_all:cn \seq_gremove_all:Nn \seq_gremove_all:cn \seq_remove_all:Nn hsequence i {hitem i} Removes every occurrence of hitemi from the hsequencei. One variable mapping can be nested inside another. The hitemi comparison takes place on a token basis. but this is not enforced. The hitemsi are returned from left to right. \seq_if_in:NnTF \seq_if_in:(NV|Nv|No|Nx|cn|cV|cv|co|cx)TF \seq_if_in:NnTF hsequence i {hitem i} {htrue code i} {hfalse code i} Tests if the hitemi is present in the hsequencei. \seq_map_variable:NNn \seq_map_variable:(Ncn|cNn|ccn) \seq_map_variable:NNn hsequence i htl var. as for \tl_if_eq:nn(TF). The hinline functioni should consist of code which will receive the hitemi as #1. 6 \seq_if_empty_p:N \seq_if_empty_p:c \seq_if_empty:NTF \seq_if_empty:cTF ? ? ? ? Sequence conditionals \seq_if_empty_p:N hsequence i \seq_if_empty:NTF hsequence i {htrue code i} {hfalse code i} Tests if the hsequencei is empty (containing no items). The hfunctioni will receive one argument for each iteration. One in line mapping can be nested inside another. The hitemsi are returned from left to right. The hitemsi are returned from left to right. i} Updated: 2012-06-29 Stores each entry in the hsequencei in turn in the htl var. 109 . inserting the htokensi after the mapping has ended.. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before further items are taken from the input stream. The total number of items in a hsequencei will include those which are empty and duplicates. for example \seq_map_inline:Nn \l_my_seq { \str_if_eq:nnTF { #1 } { bingo } { \seq_map_break:n { <tokens> } } { % Do something useful } } Use outside of a \seq_map_. This will normally take place within a conditional statement. \seq_map_break:n I Updated: 2012-06-29 \seq_map_break:n {htokens i} Used to terminate a \seq_map_. function before all entries in the hsequencei have been processed. function before all entries in the hsequencei have been processed... This will depend on the design of the mapping function. every item in a hsequencei is unique. scenario will lead to low level TEX errors. \seq_count:N ? \seq_count:c ? New: 2012-07-13 \seq_count:N hsequence i Leaves the number of items in the hsequencei in the input stream as an hinteger denotationi.e. TEXhackers note: When the mapping is broken. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before the htokensi are inserted into the input stream.\seq_map_break: I Updated: 2012-06-29 \seq_map_break: Used to terminate a \seq_map_... i. This will depend on the design of the mapping function. TEXhackers note: When the mapping is broken.. for example \seq_map_inline:Nn \l_my_seq { \str_if_eq:nnTF { #1 } { bingo } { \seq_map_break: } { % Do something useful } } Use outside of a \seq_map_. scenario will lead to low level TEX errors. This will normally take place within a conditional statement... removes the item from the hsequencei. If the hsequencei is non-empty. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. \seq_get:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. The htoken list variablei is assigned locally. removes the item from the hsequencei. The htoken list variablei is assigned locally. leaves the hfalse codei in the input stream. stores the top item from a hsequencei in the htoken list variablei without removing it from the hsequencei. \seq_gpop:NN hsequence i htoken list variable i Pops the top item from a hsequencei into the htoken list variablei. pops the top item from the hsequencei in the htoken list variablei.e. leaves the hfalse codei in the input stream.8 Sequences as stacks Sequences can be used as stacks. \seq_pop:NN hsequence i htoken list variable i Pops the top item from a hsequencei into the htoken list variablei. \seq_pop:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. leaves the hfalse codei in the input stream. \seq_get:NN \seq_get:cN Updated: 2012-05-14 \seq_pop:NN \seq_pop:cN Updated: 2012-05-14 \seq_gpop:NN \seq_gpop:cN Updated: 2012-05-14 \seq_get:NNTF \seq_get:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_pop:NNTF \seq_pop:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_gpop:NNTF \seq_gpop:cNTF New: 2012-05-14 Updated: 2012-05-19 \seq_get:NN hsequence i htoken list variable i Reads the top item from a hsequencei into the htoken list variablei without removing it from the hsequencei. \seq_gpop:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hsequencei is empty. while the htoken list variablei is assigned locally. The hsequencei is modified globally. If the hsequencei is non-empty. for performance reasons. The hsequencei is modified globally. but not in both ways. i. where data is pushed to and popped from the top of the sequence. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. 110 . i. Both of the variables are assigned locally. (The left of a sequence is the top. If hsequencei is empty the htoken list variablei will contain the special marker \q_no_value. Both the hsequencei and the htoken list variablei are assigned locally. while the htoken list variablei is assigned locally. If the hsequencei is non-empty. The value of the htoken list variablei is not defined in this case and should not be relied upon.e. pops the top item from the hsequencei in the htoken list variablei. The value of the htoken list variablei is not defined in this case and should not be relied upon.) The stack functions for sequences are not intended to be mixed with the general ordered data functions detailed in the previous section: a sequence should either be used as an ordered data type or as a stack. The value of the htoken list variablei is not defined in this case and should not be relied upon. 10 \seq_show:N \seq_show:c Viewing sequences \seq_show:N hsequence i Displays the entries in the hsequencei in the terminal. an error will be raised. These are never used by the kernel code. \__seq_push_item_def:n \__seq_push_item_def:x \__seq_push_item_def:n {hcode i} Saves the definition of \__seq_item:n and redefines it to accept one parameter and expand to hcodei. If expanded outside of a mapping or manipulation function. The definition should always be set globally. Scratch sequences for global assignment. This function should always be balanced by use of \__seq_pop_item_def:. they may be overwritten by other non-kernel code and so should only be used for short-term storage. Updated: 2012-09-09 11 \__seq_item:n ? Internal sequence functions \__seq_item:n hitem i The internal token used to begin each sequence entry. New: 2012-07-02 \l_tmpa_seq \l_tmpb_seq New: 2012-04-26 \g_tmpa_seq \g_tmpb_seq New: 2012-04-26 Scratch sequences for local assignment. However. 9 \c_empty_seq Constant and scratch sequences Constant that is always empty. These are never used by the kernel code. and so are safe for use with any LATEX3-defined function. they may be overwritten by other non-kernel code and so should only be used for short-term storage. 111 . However. and so are safe for use with any LATEX3-defined function.\seq_push:Nn \seq_push:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_gpush:Nn \seq_gpush:(NV|Nv|No|Nx|cn|cV|cv|co|cx) \seq_push:Nn hsequence i {hitem i} Adds the {hitemi} to the top of the hsequencei. \__seq_pop_item_def: \__seq_pop_item_def: Restores the definition of \__seq_item:n most recently saved by \__seq_push_item_def:n. This function should always be used in a balanced pair with \__seq_push_item_def:n. 112 . \clist_new:N \l_my_clist \clist_put_left:Nn \l_my_clist { ~ a ~ . \clist_clear_new:N hcomma list i Ensures that the hcomma listi exists globally by applying \clist_new:N if necessary. or starts or ends with a space. The resulting ordered list can then be mapped over using \clist_map_function:NN. To include an item which contains a comma.{b}. or # (assuming the usual TEX category codes apply). The declaration is global. and spaces are removed from both sides of each item on input. ~ {b} ~ } \clist_put_right:Nn \l_my_clist { ~ { c ~ } . 113 . }. thus \clist_clear_new:N \l_my_clist \clist_put_right:Nn \l_my_clist { .d. 1 \clist_new:N \clist_new:c \clist_clear:N \clist_clear:c \clist_gclear:N \clist_gclear:c \clist_clear_new:N \clist_clear_new:c \clist_gclear_new:N \clist_gclear_new:c Creating and initialising comma lists \clist_new:N hcomma list i Creates a new hcomma listi or raises an error if the name is already taken. Hence. The sequence data type should be preferred to comma lists if items are to contain {. ~ . Comma lists cannot contain empty items. d } results in \l_my_clist containing a. \clist_clear:N hcomma list i Clears all items from the hcomma listi.Part XIII The l3clist package Comma separated lists Comma lists contain ordered data where items can be added to the left or right end of the list. . Several items can be added at once. surround it with braces. } \clist_if_empty:NTF \l_my_clist { true } { false } will leave true in the input stream. then applies \clist_(g)clear:N to leave the list empty.{c~}. The hcomma listi will initially contain no items. This does not check that the hcomma listi really is a comma list...hitemn i} Updated: 2011-09-05 Appends the hitemsi to the left of the hcomma listi. removing any previous content from the variable. Spaces are removed from both sides of each item.. \clist_concat:NNN hcomma list1 i hcomma list2 i hcomma list3 i Concatenates the content of hcomma list2 i and hcomma list3 i together and saves the result in hcomma list1 i.\clist_set_eq:NN \clist_set_eq:(cN|Nc|cc) \clist_gset_eq:NN \clist_gset_eq:(cN|Nc|cc) \clist_concat:NNN \clist_concat:ccc \clist_gconcat:NNN \clist_gconcat:ccc \clist_if_exist_p:N \clist_if_exist_p:c \clist_if_exist:NTF \clist_if_exist:cTF ? ? ? ? \clist_set_eq:NN hcomma list1 i hcomma list2 i Sets the content of hcomma list1 i equal to that of hcomma list2 i. \clist_put_left:Nn \clist_put_left:(NV|No|Nx|cn|cV|co|cx) \clist_gput_left:Nn \clist_gput_left:(NV|No|Nx|cn|cV|co|cx) \clist_put_left:Nn hcomma list i {hitem1 i. Spaces are removed from both sides of each item.hitemn i} Updated: 2011-09-05 Appends the hitemsi to the right of the hcomma listi.... New: 2012-03-03 2 Adding data to comma lists \clist_set:Nn \clist_set:(NV|No|Nx|cn|cV|co|cx) \clist_gset:Nn \clist_gset:(NV|No|Nx|cn|cV|co|cx) \clist_set:Nn hcomma list i {hitem1 i. 114 ...hitemn i} New: 2011-09-06 Sets hcomma listi to contain the hitemsi.. Spaces are removed from both sides of each item... \clist_if_exist_p:N hcomma list i \clist_if_exist:NTF hcomma list i {htrue code i} {hfalse code i} Tests whether the hcomma listi is currently defined.. \clist_put_right:Nn \clist_put_right:(NV|No|Nx|cn|cV|co|cx) \clist_gput_right:Nn \clist_gput_right:(NV|No|Nx|cn|cV|co|cx) \clist_put_right:Nn hcomma list i {hitem1 i. The items in hcomma list2 i will be placed at the left side of the new comma list. TEXhackers note: This function iterates through every item in the hcomma listi and does a comparison with the hitemsi already checked. while retaining the order of the unaffected entries. as for \tl_if_eq:nn(TF). it will not work if any of the items in the hcomma listi contains {. or # (assuming the usual TEX category codes apply). The functions here may be used to update comma lists. \clist_remove_duplicates:N \clist_remove_duplicates:c \clist_gremove_duplicates:N \clist_gremove_duplicates:c \clist_remove_duplicates:N hcomma list i Removes duplicate items from the hcomma listi. }. it may be necessary to modify the content. The hitemi comparison takes place on a token basis. leaving the left most copy of each item in the hcomma listi. The hitemi comparison takes place on a token basis. }. It is therefore relatively slow with large comma lists.3 Modifying comma lists While comma lists are normally used as ordered lists. or # (assuming the usual TEX category codes apply). as for \tl_if_eq:nn(TF). 115 . Furthermore. \clist_remove_all:Nn \clist_remove_all:cn \clist_gremove_all:Nn \clist_gremove_all:cn Updated: 2011-09-06 \clist_remove_all:Nn hcomma list i {hitem i} Removes every occurrence of hitemi from the hcomma listi. 4 \clist_if_empty_p:N \clist_if_empty_p:c \clist_if_empty:NTF \clist_if_empty:cTF ? ? ? ? Comma list conditionals \clist_if_empty_p:N hcomma list i \clist_if_empty:NTF hcomma list i {htrue code i} {hfalse code i} Tests if the hcomma listi is empty (containing no items). TEXhackers note: The hitemi may not contain {. the item is ignored. as an n-type argument. if your comma list that is being mapped is {a␣.␣{c}.{}. {b}~ . This case is more efficient than using n-type comma lists. \clist_map_inline:Nn \clist_map_inline:(cn|nn) Updated: 2012-06-29 \clist_map_inline:Nn hcomma list i {hinline function i} Applies hinline functioni to every hitemi stored within the hcomma listi. }. spaces have already been trimmed on input.␣{{b}␣}.␣. The hinline functioni should consist of code which will receive the hitemi as #1. and ‘c’. one set is removed. Otherwise. The hitemsi are returned from left to right. \clist_if_in:nnTF { a .} then the arguments passed to the mapped function are ‘a’. but braces are not removed. and items are simply stripped of one set of braces if any. and should not contain . nor start or end with a space. Thus. The function \clist_map_inline:Nn is in general more efficient than \clist_map_function:NN. When the comma list is given explicitly. When the comma list is given as an N-type argument. The hfunctioni will receive one argument for each iteration. If the result of trimming spaces is empty. an empty argument. c } { b } {true} {false} yields false. ‘{b}␣’. One in line mapping can be nested inside another. Hence.\clist_if_in:NnTF \clist_if_in:(NV|No|cn|cV|co|nn|nV|no)TF \clist_if_in:NnTF hcomma list i {hitem i} {htrue code i} {hfalse code i} Updated: 2011-09-06 Tests if the hitemi is present in the hcomma listi. 5 Mapping to comma lists The functions described in this section apply a specified function to each item of a comma list. \clist_map_function:NN I \clist_map_function:(cN|nN) I \clist_map_function:NN hcomma list i hfunction i Updated: 2012-06-29 Applies hfunctioni to every hitemi stored in the hcomma listi. or # (assuming the usual TEX category codes apply). TEXhackers note: The hitemi may not contain {. In the case of an n-type hcomma listi. if the item is surrounded by braces. and the result is passed to the mapped function. spaces are stripped from each item. {b} . One mapping may be nested inside another. spaces are trimmed around each item. The hitemsi are returned from left to right. 116 . TEXhackers note: When the mapping is broken. i {hfunction using tl var. The hitemsi are returned from left to right.. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before further items are taken from the input stream.. for example \clist_map_inline:Nn \l_my_clist { \str_if_eq:nnTF { #1 } { bingo } { \clist_map_break: } { % Do something useful } } Use outside of a \clist_map_. i} Updated: 2012-06-29 Stores each entry in the hcomma listi in turn in the htl var. scenario will lead to low level TEX errors.i. This will normally take place within a conditional statement... One variable mapping can be nested inside another. 117 .\clist_map_variable:NNn \clist_map_variable:(cNn|nNn) \clist_map_variable:NNn hcomma list i htl var. function before all entries in the hcomma listi have been processed. but this is not enforced. \clist_map_break: I Updated: 2012-06-29 \clist_map_break: Used to terminate a \clist_map_.i and applies the hfunction using tl var. This will depend on the design of the mapping function.i The hfunctioni will usually consist of code making use of the htl var. (The left of a comma list is the top. \clist_get:NN \clist_get:cN Updated: 2012-05-14 \clist_get:NNTF \clist_get:cNTF New: 2012-05-14 \clist_get:NN hcomma list i htoken list variable i Stores the left-most item from a hcomma listi in the htoken list variablei without removing it from the hcomma listi. for example \clist_map_inline:Nn \l_my_clist { \str_if_eq:nnTF { #1 } { bingo } { \clist_map_break:n { <tokens> } } { % Do something useful } } Use outside of a \clist_map_.e. TEXhackers note: When the mapping is broken.. This will depend on the design of the mapping function.) The stack functions for comma lists are not intended to be mixed with the general ordered data functions detailed in the previous section: a comma list should either be used as an ordered data type or as a stack.. stores the top item from the hcomma listi in the htoken list variablei without removing it from the hcomma listi. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before the htokensi are inserted into the input stream. 118 . If the hcomma listi is empty the htoken list variablei will contain the marker value \q_no_value. but not in both ways. The htoken list variablei is assigned locally. \clist_count:N ? \clist_count:(c|n) ? New: 2012-07-13 \clist_count:N hcomma list i Leaves the number of items in the hcomma listi in the input stream as an hinteger denotationi. The total number of items in a hcomma listi will include those which are duplicates.. i.. function before all entries in the hcomma listi have been processed. for performance reasons. The value of the htoken list variablei is not defined in this case and should not be relied upon. 6 Comma lists as stacks Comma lists can be used as stacks. every item in a hcomma listi is unique. \clist_get:NNTF hcomma list i htoken list variable i {htrue code i} {hfalse code i} If the hcomma listi is empty. where data is pushed to and popped from the top of the comma list. scenario will lead to low level TEX errors. The htoken list variablei is assigned locally. If the hcomma listi is non-empty. leaves the hfalse codei in the input stream. inserting the htokensi after the mapping has ended. This will normally take place within a conditional statement.\clist_map_break:n I Updated: 2012-06-29 \clist_map_break:n {htokens i} Used to terminate a \clist_map_. The value of the htoken list variablei is not defined in this case and should not be relied upon. The hcomma listi is modified globally. leaves the hfalse codei in the input stream. leaves the hfalse codei in the input stream.e. If the hcomma listi is non-empty. The value of the htoken list variablei is not defined in this case and should not be relied upon. Both the hcomma listi and the htoken list variablei are assigned locally. Both of the variables are assigned locally. i.e. 7 \clist_show:N \clist_show:c Viewing comma lists \clist_show:N hcomma list i Displays the entries in the hcomma listi in the terminal. i. i. \clist_push:Nn \clist_push:(NV|No|Nx|cn|cV|co|cx) \clist_gpush:Nn \clist_gpush:(NV|No|Nx|cn|cV|co|cx) \clist_push:Nn hcomma list i {hitems i} Adds the {hitemsi} to the top of the hcomma listi. \clist_pop:NNTF hsequence i htoken list variable i {htrue code i} {hfalse code i} If the hcomma listi is empty. removes the item from the comma list and stores it in the htoken list variablei. Spaces are removed from both sides of each item. i.e. removes the item from the comma list and stores it in the htoken list variablei. removes the item from the hcomma listi. removes the item from the hcomma listi. If the hcomma listi is non-empty. \clist_gpop:NNTF hcomma list i htoken list variable i {htrue code i} {hfalse code i} If the hcomma listi is empty. while the htoken list variablei is assigned locally.e. The hcomma listi is modified globally. while the assignment of the htoken list variablei is local. pops the top item from the hcomma listi in the htoken list variablei. \clist_gpop:NN hcomma list i htoken list variable i Pops the left-most item from a hcomma listi into the htoken list variablei.\clist_pop:NN \clist_pop:cN Updated: 2011-09-06 \clist_gpop:NN \clist_gpop:cN \clist_pop:NNTF \clist_pop:cNTF New: 2012-05-14 \clist_gpop:NNTF \clist_gpop:cNTF New: 2012-05-14 \clist_pop:NN hcomma list i htoken list variable i Pops the left-most item from a hcomma listi into the htoken list variablei. 119 . Updated: 2012-09-09 \clist_show:n \clist_show:n {htokens i} Updated: 2012-09-09 Displays the entries in the comma list in the terminal. pops the top item from the hcomma listi in the htoken list variablei. 8 \c_empty_clist Constant and scratch comma lists Constant that is always empty. New: 2012-07-02 \l_tmpa_clist \l_tmpb_clist New: 2011-09-06 \g_tmpa_clist \g_tmpb_clist New: 2011-09-06 Scratch comma lists for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. Scratch comma lists for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 120 Part XIV The l3prop package Property lists LATEX3 implements a “property list” data type, which contain an unordered list of entries each of which consists of a hkeyi and an associated hvaluei. The hkeyi and hvaluei may both be any hbalanced texti. It is possible to map functions to property lists such that the function is applied to every key–value pair within the list. Each entry in a property list must have a unique hkeyi: if an entry is added to a property list which already contains the hkeyi then the new entry will overwrite the existing one. The hkeysi are compared on a string basis, using the same method as \str_if_eq:nn. Property lists are intended for storing key-based information for use within code. This is in contrast to key–value lists, which are a form of input parsed by the keys module. 1 \prop_new:N \prop_new:c \prop_clear:N \prop_clear:c \prop_gclear:N \prop_gclear:c \prop_clear_new:N \prop_clear_new:c \prop_gclear_new:N \prop_gclear_new:c \prop_set_eq:NN \prop_set_eq:(cN|Nc|cc) \prop_gset_eq:NN \prop_gset_eq:(cN|Nc|cc) Creating and initialising property lists \prop_new:N hproperty list i Creates a new hproperty listi or raises an error if the name is already taken. The declaration is global. The hproperty listi will initially contain no entries. \prop_clear:N hproperty list i Clears all entries from the hproperty listi. \prop_clear_new:N hproperty list i Ensures that the hproperty listi exists globally by applying \prop_new:N if necessary, then applies \prop_(g)clear:N to leave the list empty. \prop_set_eq:NN hproperty list1 i hproperty list2 i Sets the content of hproperty list1 i equal to that of hproperty list2 i. 121 2 Adding entries to property lists \prop_put:Nnn \prop_put:(NnV|Nno|Nnx|NVn|NVV|Non|Noo|cnn|cnV|cno|cnx|cVn|cVV|con|coo) \prop_gput:Nnn \prop_gput:(NnV|Nno|Nnx|NVn|NVV|Non|Noo|cnn|cnV|cno|cnx|cVn|cVV|con|coo) \prop_put:Nnn hproperty list i {hkey i} {hvalue i} Updated: 2012-07-09 Adds an entry to the hproperty listi which may be accessed using the hkeyi and which has hvaluei. Both the hkeyi and hvaluei may contain any hbalanced texti. The hkeyi is stored after processing with \tl_to_str:n, meaning that category codes are ignored. If the hkeyi is already present in the hproperty listi, the existing entry is overwritten by the new hvaluei. \prop_put_if_new:Nnn \prop_put_if_new:cnn \prop_gput_if_new:Nnn \prop_gput_if_new:cnn \prop_put_if_new:Nnn hproperty list i {hkey i} {hvalue i} If the hkeyi is present in the hproperty listi then no action is taken. If the hkeyi is not present in the hproperty listi then a new entry is added. Both the hkeyi and hvaluei may contain any hbalanced texti. The hkeyi is stored after processing with \tl_to_str:n, meaning that category codes are ignored. 3 Recovering values from property lists \prop_get:NnN \prop_get:(NVN|NoN|cnN|cVN|coN) \prop_get:NnN hproperty list i {hkey i} htl var i Updated: 2011-08-28 Recovers the hvaluei stored with hkeyi from the hproperty listi, and places this in the htoken list variablei. If the hkeyi is not found in the hproperty listi then the htoken list variablei will contain the special marker \q_no_value. The htoken list variablei is set within the current TEX group. See also \prop_get:NnNTF. \prop_pop:NnN \prop_pop:(NoN|cnN|coN) Updated: 2011-08-18 \prop_gpop:NnN \prop_gpop:(NoN|cnN|coN) Updated: 2011-08-18 \prop_pop:NnN hproperty list i {hkey i} htl var i Recovers the hvaluei stored with hkeyi from the hproperty listi, and places this in the htoken list variablei. If the hkeyi is not found in the hproperty listi then the htoken list variablei will contain the special marker \q_no_value. The hkeyi and hvaluei are then deleted from the property list. Both assignments are local. See also \prop_pop:NnNTF. \prop_gpop:NnN hproperty list i {hkey i} htl var i Recovers the hvaluei stored with hkeyi from the hproperty listi, and places this in the htoken list variablei. If the hkeyi is not found in the hproperty listi then the htoken list variablei will contain the special marker \q_no_value. The hkeyi and hvaluei are then deleted from the property list. The hproperty listi is modified globally, while the assignment of the htoken list variablei is local. See also \prop_gpop:NnNTF. 122 4 \prop_remove:Nn \prop_remove:(NV|cn|cV) \prop_gremove:Nn \prop_gremove:(NV|cn|cV) Modifying property lists \prop_remove:Nn hproperty list i {hkey i} Removes the entry listed under hkeyi from the hproperty listi. If the hkeyi is not found in the hproperty listi no change occurs, i.e there is no need to test for the existence of a key before deleting it. New: 2012-05-12 5 \prop_if_exist_p:N \prop_if_exist_p:c \prop_if_exist:NTF \prop_if_exist:cTF ? ? ? ? Property list conditionals \prop_if_exist_p:N hproperty list i \prop_if_exist:NTF hproperty list i {htrue code i} {hfalse code i} Tests whether the hproperty listi is currently defined. This does not check that the hproperty listi really is a property list variable. New: 2012-03-03 \prop_if_empty_p:N \prop_if_empty_p:c \prop_if_empty:NTF \prop_if_empty:cTF ? ? ? ? \prop_if_empty_p:N hproperty list i \prop_if_empty:NTF hproperty list i {htrue code i} {hfalse code i} Tests if the hproperty listi is empty (containing no entries). \prop_if_in_p:Nn \prop_if_in_p:(NV|No|cn|cV|co) \prop_if_in:NnTF \prop_if_in:(NV|No|cn|cV|co)TF ? ? ? ? \prop_if_in:NnTF hproperty list i {hkey i} {htrue code i} {hfalse code i} Updated: 2011-09-15 Tests if the hkeyi is present in the hproperty listi, making the comparison using the method described by \str_if_eq:nnTF. TEXhackers note: This function iterates through every key–value pair in the hproperty listi and is therefore slower than using the non-expandable \prop_get:NnNTF. 6 Recovering values from property lists with branching The functions in this section combine tests for the presence of a key in a property list with recovery of the associated valued. This makes them useful for cases where different cases follow dependent on the presence or absence of a key in a property list. They offer increased readability and performance over separate testing and recovery phases. 123 \prop_get:NnNTF \prop_get:(NVN|NoN|cnN|cVN|coN)TF \prop_get:NnNTF hproperty list i {hkey i} htoken list variable i {htrue code i} {hfalse code i} Updated: 2012-05-19 If the hkeyi is not present in the hproperty listi, leaves the hfalse codei in the input stream. The value of the htoken list variablei is not defined in this case and should not be relied upon. If the hkeyi is present in the hproperty listi, stores the corresponding hvaluei in the htoken list variablei without removing it from the hproperty listi, then leaves the htrue codei in the input stream. The htoken list variablei is assigned locally. \prop_pop:NnNTF \prop_pop:cnNTF New: 2011-08-18 Updated: 2012-05-19 \prop_gpop:NnNTF \prop_gpop:cnNTF New: 2011-08-18 Updated: 2012-05-19 \prop_pop:NnNTF hproperty list i {hkey i} htoken list variable i {htrue code i} {hfalse code i} If the hkeyi is not present in the hproperty listi, leaves the hfalse codei in the input stream. The value of the htoken list variablei is not defined in this case and should not be relied upon. If the hkeyi is present in the hproperty listi, pops the corresponding hvaluei in the htoken list variablei, i.e. removes the item from the hproperty listi. Both the hproperty listi and the htoken list variablei are assigned locally. \prop_gpop:NnNTF hproperty list i {hkey i} htoken list variable i {htrue code i} {hfalse code i} If the hkeyi is not present in the hproperty listi, leaves the hfalse codei in the input stream. The value of the htoken list variablei is not defined in this case and should not be relied upon. If the hkeyi is present in the hproperty listi, pops the corresponding hvaluei in the htoken list variablei, i.e. removes the item from the hproperty listi. The hproperty listi is modified globally, while the htoken list variablei is assigned locally. 7 \prop_map_function:NN I \prop_map_function:cN I Updated: 2013-01-08 \prop_map_inline:Nn \prop_map_inline:cn Updated: 2013-01-08 Mapping to property lists \prop_map_function:NN hproperty list i hfunction i Applies hfunctioni to every hentryi stored in the hproperty listi. The hfunctioni will receive two argument for each iteration: the hkeyi and associated hvaluei. The order in which hentriesi are returned is not defined and should not be relied upon. \prop_map_inline:Nn hproperty list i {hinline function i} Applies hinline functioni to every hentryi stored within the hproperty listi. The hinline functioni should consist of code which will receive the hkeyi as #1 and the hvaluei as #2. The order in which hentriesi are returned is not defined and should not be relied upon. 124 \prop_map_break: I Updated: 2012-06-29 \prop_map_break: Used to terminate a \prop_map_... function before all entries in the hproperty listi have been processed. This will normally take place within a conditional statement, for example \prop_map_inline:Nn \l_my_prop { \str_if_eq:nnTF { #1 } { bingo } { \prop_map_break: } { % Do something useful } } Use outside of a \prop_map_... scenario will lead to low level TEX errors. \prop_map_break:n I Updated: 2012-06-29 \prop_map_break:n {htokens i} Used to terminate a \prop_map_... function before all entries in the hproperty listi have been processed, inserting the htokensi after the mapping has ended. This will normally take place within a conditional statement, for example \prop_map_inline:Nn \l_my_prop { \str_if_eq:nnTF { #1 } { bingo } { \prop_map_break:n { <tokens> } } { % Do something useful } } Use outside of a \prop_map_... scenario will lead to low level TEX errors. 8 \prop_show:N \prop_show:c Viewing property lists \prop_show:N hproperty list i Displays the entries in the hproperty listi in the terminal. Updated: 2012-09-09 125 9 \l_tmpa_prop \l_tmpb_prop New: 2012-06-23 \g_tmpa_prop \g_tmpb_prop New: 2012-06-23 Scratch property lists for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. Scratch property lists for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 10 \c_empty_prop \l__prop_internal_tl \__prop_split:NnTF Updated: 2013-01-08 Constants A permanently-empty property list used for internal comparisons. 11 \s__prop Scratch property lists Internal property list functions The internal token used to separate out property list entries, surrounding each hkeyi. Token list used to store new key–value pairs to be inserted by functions of the \prop_put:Nnn family. \__prop_split:NnTF hproperty list i {hkey i} {htrue code i} {hfalse code i} Splits the hproperty listi at the hkeyi, giving three token lists: the hextracti of hproperty listi before the hkeyi, the hvaluei associated with the hkeyi and the hextracti of the hproperty listi after the hvaluei. Both hextractsi retain the internal structure of a property list, and the concatenation of the two hextractsi is a property list. If the hkeyi is present in the hproperty listi then the htrue codei is left in the input stream, with #1, #2, and #3 replaced by the first hextracti, the hvaluei, and the second extract. If the hkeyi is not present in the hproperty listi then the hfalse codei is left in the input stream, with no trailing material. Both htrue codei and hfalse codei are used in the replacement text of a macro defined internally, hence macro parameter characters should be doubled, except #1, #2, and #3 which stand in the htrue codei for the three extracts from the property list. The hkeyi comparison takes place as described for \str_if_eq:nn. 126 Part XV The l3box package Boxes There are three kinds of box operations: horizontal mode denoted with prefix \hbox_, vertical mode with prefix \vbox_, and the generic operations working in both modes with prefix \box_. 1 \box_new:N \box_new:c \box_clear:N \box_clear:c \box_gclear:N \box_gclear:c \box_clear_new:N \box_clear_new:c \box_gclear_new:N \box_gclear_new:c \box_set_eq:NN \box_set_eq:(cN|Nc|cc) \box_gset_eq:NN \box_gset_eq:(cN|Nc|cc) \box_set_eq_clear:NN \box_set_eq_clear:(cN|Nc|cc) Creating and initialising boxes \box_new:N hbox i Creates a new hboxi or raises an error if the name is already taken. The declaration is global. The hboxi will initially be void. \box_clear:N hbox i Clears the content of the hboxi by setting the box equal to \c_void_box. \box_clear_new:N hbox i Ensures that the hboxi exists globally by applying \box_new:N if necessary, then applies \box_(g)clear:N to leave the hboxi empty. \box_set_eq:NN hbox1 i hbox2 i Sets the content of hbox1 i equal to that of hbox2 i. \box_set_eq_clear:NN hbox1 i hbox2 i Sets the content of hbox1 i within the current TEX group equal to that of hbox2 i, then clears hbox2 i globally. \box_gset_eq_clear:NN \box_gset_eq_clear:(cN|Nc|cc) \box_gset_eq_clear:NN hbox1 i hbox2 i Sets the content of hbox1 i equal to that of hbox2 i, then clears hbox2 i. These assignments are global. 127 \box_if_exist_p:N \box_if_exist_p:c \box_if_exist:NTF \box_if_exist:cTF ? ? ? ? \box_if_exist_p:N hbox i \box_if_exist:NTF hbox i {htrue code i} {hfalse code i} Tests whether the hboxi is currently defined. This does not check that the hboxi really is a box. New: 2012-03-03 2 \box_use:N \box_use:c Using boxes \box_use:N hbox i Inserts the current content of the hboxi onto the current list for typesetting. TEXhackers note: This is the TEX primitive \copy. \box_use_clear:N \box_use_clear:c \box_use_clear:N hbox i Inserts the current content of the hboxi onto the current list for typesetting, then globally clears the content of the hboxi. TEXhackers note: This is the TEX primitive \box. \box_move_right:nn \box_move_left:nn \box_move_up:nn \box_move_down:nn \box_move_right:nn {hdimexpr i} {hbox function i} This function operates in vertical mode, and inserts the material specified by the hbox functioni such that its reference point is displaced horizontally by the given hdimexpri from the reference point for typesetting, to the right or left as appropriate. The hbox functioni should be a box operation such as \box_use:N \<box> or a “raw” box specification such as \vbox:n { xyz }. \box_move_up:nn {hdimexpr i} {hbox function i} This function operates in horizontal mode, and inserts the material specified by the hbox functioni such that its reference point is displaced vertical by the given hdimexpri from the reference point for typesetting, up or down as appropriate. The hbox functioni should be a box operation such as \box_use:N \<box> or a “raw” box specification such as \vbox:n { xyz }. 3 \box_dp:N \box_dp:c Measuring and setting box dimensions \box_dp:N hbox i Calculates the depth (below the baseline) of the hboxi in a form suitable for use in a hdimension expressioni. TEXhackers note: This is the TEX primitive \dp. 128 \box_ht:N \box_ht:c \box_ht:N hbox i Calculates the height (above the baseline) of the hboxi in a form suitable for use in a hdimension expressioni. TEXhackers note: This is the TEX primitive \ht. \box_wd:N \box_wd:c \box_wd:N hbox i Calculates the width of the hboxi in a form suitable for use in a hdimension expressioni. TEXhackers note: This is the TEX primitive \wd. \box_set_dp:Nn \box_set_dp:cn Updated: 2011-10-22 \box_set_ht:Nn \box_set_ht:cn Updated: 2011-10-22 \box_set_wd:Nn \box_set_wd:cn Updated: 2011-10-22 \box_set_dp:Nn hbox i {hdimension expression i} Set the depth (below the baseline) of the hboxi to the value of the {hdimension expressioni}. This is a global assignment. \box_set_ht:Nn hbox i {hdimension expression i} Set the height (above the baseline) of the hboxi to the value of the {hdimension expressioni}. This is a global assignment. \box_set_wd:Nn hbox i {hdimension expression i} Set the width of the hboxi to the value of the {hdimension expressioni}. This is a global assignment. 4 Box conditionals \box_if_empty_p:N \box_if_empty_p:c \box_if_empty:NTF \box_if_empty:cTF ? ? ? ? \box_if_empty_p:N hbox i \box_if_empty:NTF hbox i {htrue code i} {hfalse code i} \box_if_horizontal_p:N \box_if_horizontal_p:c \box_if_horizontal:NTF \box_if_horizontal:cTF ? ? ? ? \box_if_horizontal_p:N hbox i \box_if_horizontal:NTF hbox i {htrue code i} {hfalse code i} \box_if_vertical_p:N \box_if_vertical_p:c \box_if_vertical:NTF \box_if_vertical:cTF ? ? ? ? \box_if_vertical_p:N hbox i \box_if_vertical:NTF hbox i {htrue code i} {hfalse code i} Tests if hboxi is a empty (equal to \c_empty_box). Tests if hboxi is a horizontal box. Tests if hboxi is a vertical box. 129 5 \box_set_to_last:N \box_set_to_last:c \box_gset_to_last:N \box_gset_to_last:c \box_set_to_last:N hbox i Sets the hboxi equal to the last item (box) added to the current partial list, removing the item from the list at the same time. When applied to the main vertical list, the hboxi will always be void as it is not possible to recover the last added item. 6 \c_empty_box The last box inserted Constant boxes This is a permanently empty box, which is neither set as horizontal nor vertical. Updated: 2012-11-04 7 \l_tmpa_box \l_tmpb_box Updated: 2012-11-04 \g_tmpa_box \g_tmpb_box Scratch boxes for local assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. Scratch boxes for global assignment. These are never used by the kernel code, and so are safe for use with any LATEX3-defined function. However, they may be overwritten by other non-kernel code and so should only be used for short-term storage. 8 \box_show:N \box_show:c Scratch boxes Viewing box contents \box_show:N hbox i Shows full details of the content of the hboxi in the terminal. Updated: 2012-05-11 \box_show:Nnn \box_show:cnn New: 2012-05-11 \box_log:N \box_log:c \box_show:Nnn hbox i hintexpr1 i hintexpr2 i Display the contents of hboxi in the terminal, showing the first hintexpr1 i items of the box, and descending into hintexpr2 i group levels. \box_show:N hbox i Writes full details of the content of the hboxi to the log. New: 2012-05-11 130 \box_log:Nnn \box_log:cnn New: 2012-05-11 \box_show:Nnn hbox i hintexpr1 i hintexpr2 i Writes the contents of hboxi to the log, showing the first hintexpr1 i items of the box, and descending into hintexpr2 i group levels. 9 \hbox:n Horizontal mode boxes \hbox:n {hcontents i} Typesets the hcontentsi into a horizontal box of natural width and then includes this box in the current list for typesetting. TEXhackers note: This is the TEX primitive \hbox. \hbox_to_wd:nn \hbox_to_wd:nn {hdimexpr i} {hcontents i} Typesets the hcontentsi into a horizontal box of width hdimexpri and then includes this box in the current list for typesetting. \hbox_to_zero:n \hbox_to_zero:n {hcontents i} Typesets the hcontentsi into a horizontal box of zero width and then includes this box in the current list for typesetting. \hbox_set:Nn \hbox_set:cn \hbox_gset:Nn \hbox_gset:cn \hbox_set_to_wd:Nnn \hbox_set_to_wd:cnn \hbox_gset_to_wd:Nnn \hbox_gset_to_wd:cnn \hbox_overlap_right:n \hbox_set:Nn hbox i {hcontents i} Typesets the hcontentsi at natural width and then stores the result inside the hboxi. \hbox_set_to_wd:Nnn hbox i {hdimexpr i} {hcontents i} Typesets the hcontentsi to the width given by the hdimexpri and then stores the result inside the hboxi. \hbox_overlap_right:n {hcontents i} Typesets the hcontentsi into a horizontal box of zero width such that material will protrude to the right of the insertion point. \hbox_overlap_left:n \hbox_overlap_left:n {hcontents i} Typesets the hcontentsi into a horizontal box of zero width such that material will protrude to the left of the insertion point. 131 \hbox_set:Nw \hbox_set:cw \hbox_set_end: \hbox_gset:Nw \hbox_gset:cw \hbox_gset_end: \hbox_unpack:N \hbox_unpack:c \hbox_set:Nw hbox i hcontents i \hbox_set_end: Typesets the hcontentsi at natural width and then stores the result inside the hboxi. In contrast to \hbox_set:Nn this function does not absorb the argument when finding the hcontenti, and so can be used in circumstances where the hcontenti may not be a simple argument. \hbox_unpack:N hbox i Unpacks the content of the horizontal hboxi, retaining any stretching or shrinking applied when the hboxi was set. TEXhackers note: This is the TEX primitive \unhcopy. \hbox_unpack_clear:N \hbox_unpack_clear:c \hbox_unpack_clear:N hbox i Unpacks the content of the horizontal hboxi, retaining any stretching or shrinking applied when the hboxi was set. The hboxi is then cleared globally. TEXhackers note: This is the TEX primitive \unhbox. 10 Vertical mode boxes Vertical boxes inherit their baseline from their contents. The standard case is that the baseline of the box is at the same position as that of the last item added to the box. This means that the box will have no depth unless the last item added to it had depth. As a result most vertical boxes have a large height value and small or zero depth. The exception are _top boxes, where the reference point is that of the first item added. These tend to have a large depth and small height, although the latter will typically be non-zero. \vbox:n \vbox:n {hcontents i} Updated: 2011-12-18 Typesets the hcontentsi into a vertical box of natural height and includes this box in the current list for typesetting. TEXhackers note: This is the TEX primitive \vbox. \vbox_top:n \vbox_top:n {hcontents i} Updated: 2011-12-18 Typesets the hcontentsi into a vertical box of natural height and includes this box in the current list for typesetting. The baseline of the box will tbe equal to that of the first item added to the box. TEXhackers note: This is the TEX primitive \vtop. 132 \vbox_to_ht:nn \vbox_to_ht:nn {hdimexpr i} {hcontents i} Updated: 2011-12-18 Typesets the hcontentsi into a vertical box of height hdimexpri and then includes this box in the current list for typesetting. \vbox_to_zero:n \vbox_to_zero:n {hcontents i} Updated: 2011-12-18 Typesets the hcontentsi into a vertical box of zero height and then includes this box in the current list for typesetting. \vbox_set:Nn \vbox_set:cn \vbox_gset:Nn \vbox_gset:cn \vbox_set:Nn hbox i {hcontents i} Typesets the hcontentsi at natural height and then stores the result inside the hboxi. Updated: 2011-12-18 \vbox_set_top:Nn \vbox_set_top:cn \vbox_gset_top:Nn \vbox_gset_top:cn \vbox_set_top:Nn hbox i {hcontents i} Typesets the hcontentsi at natural height and then stores the result inside the hboxi. The baseline of the box will tbe equal to that of the first item added to the box. Updated: 2011-12-18 \vbox_set_to_ht:Nnn \vbox_set_to_ht:cnn \vbox_gset_to_ht:Nnn \vbox_gset_to_ht:cnn \vbox_set_to_ht:Nnn hbox i {hdimexpr i} {hcontents i} Typesets the hcontentsi to the height given by the hdimexpri and then stores the result inside the hboxi. Updated: 2011-12-18 \vbox_set:Nw \vbox_set:cw \vbox_set_end: \vbox_gset:Nw \vbox_gset:cw \vbox_gset_end: \vbox_set:Nw hbox i hcontents i \vbox_set_end: Typesets the hcontentsi at natural height and then stores the result inside the hboxi. In contrast to \vbox_set:Nn this function does not absorb the argument when finding the hcontenti, and so can be used in circumstances where the hcontenti may not be a simple argument. Updated: 2011-12-18 \vbox_set_split_to_ht:NNn Updated: 2011-10-22 \vbox_set_split_to_ht:NNn hbox1 i hbox2 i {hdimexpr i} Sets hbox1 i to contain material to the height given by the hdimexpri by removing content from the top of hbox2 i (which must be a vertical box). TEXhackers note: This is the TEX primitive \vsplit. 133 \vbox_unpack:N \vbox_unpack:c \vbox_unpack:N hbox i Unpacks the content of the vertical hboxi, retaining any stretching or shrinking applied when the hboxi was set. TEXhackers note: This is the TEX primitive \unvcopy. \vbox_unpack_clear:N \vbox_unpack_clear:c \vbox_unpack:N hbox i Unpacks the content of the vertical hboxi, retaining any stretching or shrinking applied when the hboxi was set. The hboxi is then cleared globally. TEXhackers note: This is the TEX primitive \unvbox. 11 \if_hbox:N ? Primitive box conditionals \if_hbox:N hbox i htrue code i \else: hfalse code i \fi: Tests is hboxi is a horizontal box. TEXhackers note: This is the TEX primitive \ifhbox. \if_vbox:N ? \if_vbox:N hbox i htrue code i \else: hfalse code i \fi: Tests is hboxi is a vertical box. TEXhackers note: This is the TEX primitive \ifvbox. \if_box_empty:N ? \if_box_empty:N hbox i htrue code i \else: hfalse code i \fi: Tests is hboxi is an empty (void) box. TEXhackers note: This is the TEX primitive \ifvoid. 134 storing the result in the hcoffini. For details about the design concept of a coffin.Part XVI The l3coffins package Coffin code layer The material in this module provides the low-level support system for coffins. \hcoffin_set:Nn \hcoffin_set:cn New: 2011-08-17 \hcoffin_set:Nn hcoffin i {hmaterial i} Typesets the hmateriali in horizontal mode. The declaration is global. \coffin_if_exist_p:N hbox i \coffin_if_exist:NTF hbox i {htrue code i} {hfalse code i} Tests whether the hcoffini is currently defined. The hcoffini will initially be empty. \coffin_clear:N hcoffin i Clears the content of the hcoffini within the current TEX group level. see the xcoffins module (in the l3experimental bundle). Updated: 2011-09-03 135 . New: 2011-08-17 \coffin_set_eq:NN \coffin_set_eq:(Nc|cN|cc) New: 2011-08-17 \coffin_if_exist_p:N \coffin_if_exist_p:c \coffin_if_exist:NTF \coffin_if_exist:cTF ? ? ? ? \coffin_set_eq:NN hcoffin1 i hcoffin2 i Sets both the content and poles of hcoffin1 i equal to those of hcoffin2 i within the current TEX group level. New: 2012-06-20 2 Setting coffin content and poles All coffin functions create and manipulate coffins locally within the current TEX group level. The standard poles for the hcoffini are then set up based on the size of the typeset material. 1 \coffin_new:N \coffin_new:c New: 2011-08-17 \coffin_clear:N \coffin_clear:c Creating and initialising coffins \coffin_new:N hcoffin i Creates a new hcoffini or raises an error if the name is already taken. \vcoffin_set:Nnw hcoffin i {hwidth i} hmaterial i \vcoffin_set_end: Typesets the hmateriali in vertical mode constrained to the given hwidthi and stores the result in the hcoffini.\hcoffin_set:Nw \hcoffin_set:cw \hcoffin_set_end: New: 2011-09-10 \vcoffin_set:Nnn \vcoffin_set:cnn New: 2011-08-17 Updated: 2012-05-22 \vcoffin_set:Nnw \vcoffin_set:cnw \vcoffin_set_end: New: 2011-09-10 Updated: 2012-05-22 \hcoffin_set:Nw hcoffin i hmaterial i \hcoffin_set_end: Typesets the hmateriali in horizontal mode. The standard poles for the hcoffini are then set up based on the size of the typeset material. The hpolei will be located at the hoffseti from the left-hand edge of the bounding box of the hcoffini. The hoffseti should be given as a dimension expression. These functions are useful for setting the entire contents of an environment in a coffin. \coffin_set_horizontal_pole:Nnn \coffin_set_horizontal_pole:cnn \coffin_set_horizontal_pole:Nnn hcoffin i {hpole i} {hoffset i} New: 2012-07-20 Sets the hpolei to run horizontally through the hcoffini. The hoffseti should be given as a dimension expression. 136 . The standard poles for the hcoffini are then set up based on the size of the typeset material. storing the result in the hcoffini. These functions are useful for setting the entire contents of an environment in a coffin. \coffin_set_vertical_pole:Nnn \coffin_set_vertical_pole:cnn \coffin_set_vertical_pole:Nnn hcoffin i {hpole i} {hoffset i} New: 2012-07-20 Sets the hpolei to run vertically through the hcoffini. The hpolei will be located at the hoffseti from the bottom edge of the bounding box of the hcoffini. The standard poles for the hcoffini are then set up based on the size of the typeset material. \vcoffin_set:Nnn hcoffin i {hwidth i} {hmaterial i} Typesets the hmateriali in vertical mode constrained to the given hwidthi and stores the result in the hcoffini. the point of intersection of hcoffin1 -pole1 i and hcoffin1 -pole2 i. the point of intersection of hcoffin2 -pole1 i and hcoffin2 -pole2 i. and hhandle2 i. \coffin_join:NnnNnnnn \coffin_join:(cnnNnnnn|Nnncnnnn|cnncnnnn) \coffin_join:NnnNnnnn hcoffin1 i {hcoffin1 -pole1 i} {hcoffin1 -pole2 i} hcoffin2 i {hcoffin2 -pole1 i} {hcoffin2 -pole2 i} {hx-offset i} {hy-offset i} This function joins hcoffin2 i to hcoffin1 i such that the bounding box of hcoffin1 i may expand. The alignment is carried out by first calculating hhandle1 i. The two offsets should be given as dimension expressions. The two offsets should be given as dimension expressions. The coffin is then typeset in horizontal mode such that the relationship between the current reference point in the document and the hhandlei is described by the hx-offseti and hy-offseti. The two offsets should be given as dimension expressions. the point of intersection of hcoffin2 -pole1 i and hcoffin2 -pole2 i.3 Joining and using coffins \coffin_attach:NnnNnnnn hcoffin1 i {hcoffin1 -pole1 i} {hcoffin1 -pole2 i} hcoffin2 i {hcoffin2 -pole1 i} {hcoffin2 -pole2 i} {hx-offset i} {hy-offset i} \coffin_attach:NnnNnnnn \coffin_attach:(cnnNnnnn|Nnncnnnn|cnncnnnn) This function attaches hcoffin2 i to hcoffin1 i such that the bounding box of hcoffin1 i is not altered. The alignment is carried out by first calculating hhandle1 i. i. 137 . Typesetting a coffin is therefore analogous to carrying out an alignment where the “parent” coffin is the current insertion point. 4 \coffin_dp:N \coffin_dp:c Measuring coffins \coffin_dp:N hcoffin i Calculates the depth (below the baseline) of the hcoffini in a form suitable for use in a hdimension expressioni. hcoffin2 i can protrude outside of the bounding box of the coffin. the point of intersection of hpole1 i and hpole2 i. \coffin_typeset:Nnnnn \coffin_typeset:cnnnn Updated: 2012-07-20 \coffin_typeset:Nnnnn hcoffin i {hpole1 i} {hpole2 i} {hx-offset i} {hy-offset i} Typesetting is carried out by first calculating hhandlei. hcoffin2 i is then attached to hcoffin1 i such that the relationship between hhandle1 i and hhandle2 i is described by the hx-offseti and hy-offseti. the point of intersection of hcoffin1 -pole1 i and hcoffin1 -pole2 i.e. The new bounding box will cover the area containing the bounding boxes of the two original coffins. hcoffin2 i is then attached to hcoffin1 i such that the relationship between hhandle1 i and hhandle2 i is described by the hx-offseti and hy-offseti. and hhandle2 i. \coffin_mark_handle:Nnnn hcoffin i {hpole1 i} {hpole2 i} {hcolour i} This function first calculates the hhandlei for the hcoffini as defined by the intersection of hpole1 i and hpole2 i. \coffin_wd:N hcoffin i Calculates the width of the hcoffini in a form suitable for use in a hdimension expressioni. and so are safe for use with any LATEX3-defined function. The hhandlesi will be labelled as part of this process: the locations of the hhandlesi and the labels are both printed in the hcolouri specified.\coffin_ht:N \coffin_ht:c \coffin_wd:N \coffin_wd:c \coffin_ht:N hcoffin i Calculates the height (above the baseline) of the hcoffini in a form suitable for use in a hdimension expressioni. It then prints the hcoffini at the current location in the source. height and depth of the typeset material are given.and y-components of a vector denoting the direction of the pole. It then marks the position of the hhandlei on the hcoffini. which determines the direction of the pole. 138 . The width. Scratch coffins for local assignment. with the position of the hhandlesi marked on the coffin.1 \c_empty_coffin \l_tmpa_coffin \l_tmpb_coffin New: 2012-06-19 Coffin diagnostics Constants and variables A permanently empty coffin. Notice that the poles of a coffin are defined by four values: the x and y co-ordinates of a point that the pole passes through and the x. These are never used by the kernel code. rather than the absolute values. The hhandlei will be labelled as part of this process: the location of the hhandlei and the label are both printed in the hcolouri specified. 5 \coffin_display_handles:Nn \coffin_display_handles:cn Updated: 2011-09-02 \coffin_mark_handle:Nnnn \coffin_mark_handle:cnnn Updated: 2011-09-02 \coffin_show_structure:N \coffin_show_structure:c Updated: 2012-09-09 \coffin_display_handles:Nn hcoffin i {hcolour i} This function first calculates the intersections between all of the hpolesi of the hcoffini to give a set of hhandlesi. they may be overwritten by other non-kernel code and so should only be used for short-term storage. along with the location of all of the poles of the coffin. \coffin_show_structure:N hcoffin i This function shows the structural information about the hcoffini in the terminal. 5. It is the ratio between the later. However. . so that the boxed material uses the color at the point where it is set.. \color_group_end: group. This function should usually be used within a \color_group_begin: . \color_ensure_current: Ensures that material inside a box will use the foreground color at the point where the box is set.Part XVII The l3color package Colour support This module provides support for color in LATEX3. \color_group_begin: \color_group_end: New: 2011-09-03 \color_ensure_current: New: 2011-09-03 \color_group_begin: . rather than that in force when the box is used. the material here is mainly intended to support a small number of low-level requirements in other l3kernel modules. 1 Colour in boxes Controlling the color of text in boxes requires a small number of control functions. .. \color_group_end: Creates a color group: one used to “trap” color settings. At present. 139 . rather than where it is used. message behaviour can be altered and messages can be entirely suppressed. Within htexti and hmore texti four parameters (#1 to #4) can be used: these will be supplied at the time the message is used. \% and \~ can be used to produce the corresponding character.. warning or info. \}. will allow only those messages from the submodule to be filtered out. If no hmore texti is available then a standard text is given instead. \\ may be used to force a new line and \␣ forces an explicit space. at this stage.. Messages may be subdivided by one level using the / character. 140 . Thus for example \msg_new:nnnn { mymodule } { submodule / message } . The text of messages will automatically by wrapped to the length available in the console. \#. As a result. By separating out the creation and use of messages. \{. the detail level and so on. Named messages are created in the first part of the process. 1 Creating new messages All messages have to be created before they can be used. The second part of the process is actually producing a message. At this stage a choice of message class has to be made. no decision is made about the type of output that the message will produce. either when errors occur or to indicate how the code is proceeding.Part XVIII The l3msg package Messages Messages need to be passed to the user by modules. Additionally. module or message name basis. The system used by l3msg to create messages divides the process into two distinct parts. \msg_new:nnnn \msg_new:nnn Updated: 2011-08-16 \msg_new:nnnn {hmodule i} {hmessage i} {htext i} {hmore text i} Creates a hmessagei for a given hmodulei. In this way. the messages can be altered later without needing details of where they are used in the code. several benefits are available. First. The l3msg module provides a consistent method for doing this (as opposed to writing directly to the terminal or log). This can be done on a message class. This makes it possible to alter the language used. the output which results from a given message can be altered. The message will be defined to first give htexti and then hmore texti if the user requests it. In particular. for example error. This is used within the message filtering system to allow for example the LATEX kernel messages to belong to the module LaTeX while still being filterable at a more granular level. Secondly. formatting is only needed where it will help to show meaning. An error will be raised if the hmessagei already exists. If no hmore texti is available then a standard text is given instead. \msg_error_text:n ? \msg_error_text:n {hmodule i} Produces the standard text hmodule i error This function can be redefined to alter the language in which the message is given.\msg_set:nnnn \msg_set:nnn \msg_gset:nnnn \msg_gset:nnn \msg_if_exist_p:nn ? \msg_if_exist:nnTF ? New: 2012-03-03 \msg_set:nnnn {hmodule i} {hmessage i} {htext i} {hmore text i} Sets up the text for a hmessagei for a given hmodulei. The message will be defined to first give htexti and then hmore texti if the user requests it. and thus suitable for giving context to messages. \msg_fatal_text:n ? \msg_fatal_text:n {hmodule i} Produces the standard text Fatal hmodule i error This function can be redefined to alter the language in which the message is given. \msg_if_exist_p:nn {hmodule i} {hmessage i} \msg_if_exist:nnTF {hmodule i} {hmessage i} {htrue code i} {hfalse code i} Tests whether the hmessagei for the hmodulei is currently defined. \msg_line_number: ? \msg_line_number: Prints the current line number when a message is given. 141 . 2 \msg_line_context: I Contextual information for messages \msg_line_context: Prints the current line number when a message is given. \msg_critical_text:n ? \msg_critical_text:n {hmodule i} Produces the standard text Critical hmodule i error This function can be redefined to alter the language in which the message is given. using #1 as the name of the hmodulei to be included. using #1 as the name of the hmodulei to be included. Within htexti and hmore texti four parameters (#1 to #4) can be used: these will be supplied at the time the message is used. using #1 as the name of the hmodulei to be included. The number itself is proceeded by the text on line. extra arguments will be ignored.\msg_warning_text:n ? \msg_warning_text:n {hmodule i} Produces the standard text hmodule i warning This function can be redefined to alter the language in which the message is given. 3 Issuing messages Messages behave differently depending on the message class. After issuing a fatal error the TEX run will halt. This function can be redefined to alter the language in which the message is given. In all cases. \msg_fatal:nnnnnn \msg_fatal:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_fatal:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Issues hmodulei error hmessagei. \msg_see_documentation_text:n ? \msg_see_documentation_text:n {hmodule i} Produces the standard text See the hmodule i documentation for further information. using #1 as the name of the hmodulei to be included. \msg_info_text:n ? \msg_info_text:n {hmodule i} Produces the standard text: hmodule i info This function can be redefined to alter the language in which the message is given. using #1 as the name of the hmodulei to be included. or empty arguments added (of course the sense of the message may be impaired). using #1 as the name of the hmodulei to be included. passing harg onei to harg fouri to the text-creating functions. 142 . The four arguments will be converted to strings before being added to the message text: the x-type variants should be used to expand material. If the number of arguments supplied here does not match the number in the definition of the message. the message may be issued supplying 0 to 4 arguments. \msg_critical:nnnnnn \msg_critical:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_critical:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Issues hmodulei error hmessagei. The information text will be added to the log file. passing harg onei to harg fouri to the text-creating functions. TEX will stop reading the current input file. This may halt the TEX run (if the current file is the main file) or may abort reading a sub-file. \msg_error:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} \msg_error:nnnnnn \msg_error:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) Updated: 2012-08-11 Issues hmodulei error hmessagei. passing harg onei to harg fouri to the text-creating functions. 143 . but the TEX run will not be interrupted. TEXhackers note: The TEX \endinput primitive is used to exit the file. passing harg onei to harg fouri to the text-creating functions. In particular. \msg_log:nnnnnn \msg_log:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_log:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Issues hmodulei information hmessagei. \msg_info:nnnnnn \msg_info:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_info:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Issues hmodulei information hmessagei. The information text will be added to the log file: the output is briefer than \msg_info:nnnnnn. passing harg onei to harg fouri to the text-creating functions. the rest of the current line remains in the input stream. passing harg onei to harg fouri to the text-creating functions. The warning text will be added to the log file and the terminal. the run will continue. After user input. After issuing a critical error. \msg_warning:nnnnnn \msg_warning:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_warning:nnxxxx {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Issues hmodulei warning hmessagei. The error will interrupt processing and issue the text at the terminal. or even \msg_redirect_name:nnn { module } { my-message } { warning } to target just one message. which can be used to alter the behaviour of the message when it is given. we could alter the behaviour with \msg_redirect_class:nn { error } { warning } to turn all errors into warnings. However. Thus we might have \msg_new:nnnn { module } { my-message } { Some~text } { Some~more~text } to define a message. Multiple redirections are possible. this will raise an error.\msg_none:nnnnnn \msg_none:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) \msg_none:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Updated: 2012-08-11 Does nothing: used as a message class to prevent any output at all (see the discussion of message redirection). if redirections are requested as A → B. Namely. or with \msg_redirect_module:nnn { module } { error } { warning } to alter only messages from that module. 144 . Redirection to a missing class will raise errors immediately. then to messages from one module and finally to messages of one class. B → C and C → A in this order. With no filtering. Infinite loops are prevented by eliminating the redirection starting from the target of the redirection that caused the loop to appear. 4 Redirecting messages Each message has a “name”. Redirections can be cancelled by providing an empty argument for the target class. \msg_redirect_class:nn Updated: 2012-04-27 \msg_redirect_class:nn {hclass one i} {hclass two i} Changes the behaviour of messages of hclass onei so that they are processed using the code for those of hclass twoi. with \msg_error:nn { module } { my-message } when it is used. Redirection applies first to individual messages. Thus it is possible to select out an individual message for special treatment even if the entire class is already redirected. then the A → B redirection is cancelled. .... This function can be used to make a selected message “silent” without changing global parameters: \msg_redirect_name:nnn { module } { annoying-message } { none } 5 Low-level message functions The lower-level message functions should usually be accessed from the higher-level system........... For example...... No further redirection is performed. the documentation for the latter should be consulted for full details....... where the hextra texti will be wrapped within the current line length. all of the warning messages of hmodulei could be turned off with: \msg_redirect_module:nnn { module } { warning } { none } \msg_redirect_name:nnn Updated: 2012-04-27 \msg_redirect_name:nnn {hmodule i} {hmessage i} {hclass i} Redirects a specific hmessagei from a specific hmodulei to act as a member of hclassi of messages............. Wrapping of both htexti and hmore texti takes place using \iow_wrap:nnnN.... Messages of hclass onei from sources other than hmodulei are not affected by this redirection..........\msg_redirect_module:nnn Updated: 2012-04-27 \msg_redirect_module:nnn {hmodule i} {hclass one i} {hclass two i} Redirects message of hclass onei for hmodulei to act as though they were from hclass twoi. issuing a formatted message comprising hfirst linei and htexti laid out in the format !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! <first line> ! ! <text> !............. there are occasions where direct access to these functions is desirable. \msg_interrupt:nnn New: 2012-06-28 \msg_interrupt:nnn {hfirst line i} {htext i} {hextra text i} Interrupts the TEX run...... 145 .......... However..... at which stage the hextra texti will be shown in the terminal in the format |’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ | <extra text> |. where the htexti will be wrapped to fit within the current line length.......... This function can be used to make some messages “silent” by default. The user may then request more information..... where the htexti will be wrapped to fit within the current line length........ The message will be defined to first give htexti and then hmore texti if the user requests it..........\msg_log:n \msg_log:n {htext i} New: 2012-06-28 Writes to the log file with the htexti laid out in the format ......... Wrapping takes place using \iow_wrap:nnnN.... \__msg_kernel_set:nnnn {hmodule i} {hmessage i} {htext i} {hmore text i} Sets up the text for a kernel hmessagei for a given hmodulei. 6 Kernel-specific functions Messages from LATEX3 itself are handled by the general message system.. An error will be raised if the hmessagei already exists....... the documentation for the latter should be consulted for full details.. \__msg_kernel_new:nnnn \__msg_kernel_new:nnn Updated: 2011-08-16 \__msg_kernel_set:nnnn \__msg_kernel_set:nnn \__msg_kernel_new:nnnn {hmodule i} {hmessage i} {htext i} {hmore text i} Creates a kernel hmessagei for a given hmodulei............. and also ensures that serious errors can be handled properly. 146 . \msg_term:n \msg_term:n {htext i} New: 2012-06-28 Writes to the terminal and log file with the htexti laid out in the format ************************************************* * <text> ************************************************* where the htexti will be wrapped to fit within the current line length... the documentation for the latter should be consulted for full details........... Wrapping takes place using \iow_wrap:nnnN. This allows some text to be pre-defined. ... Within htexti and hmore texti four parameters (#1 to #4) can be used: these will be supplied and expanded at the time the message is used...... If no hmore texti is available then a standard text is given instead.. The message will be defined to first give htexti and then hmore texti if the user requests it................ <text> ....... Within htexti and hmore texti four parameters (#1 to #4) can be used: these will be supplied and expanded at the time the message is used...... If no hmore texti is available then a standard text is given instead.. but have their own functions... passing harg onei to harg fouri to the text-creating functions. the interface is similar. 7 Expandable errors In a few places. Cannot be redirected. The error will stop processing and issue the text at the terminal. The information text will be added to the log file. \__msg_kernel_expandable_error:nnnnnn ? \__msg_kernel_expandable_error:(nnnnn|nnnn|nnn|nn) ? New: 2011-11-23 \__msg_kernel_expandable_error:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Issues an error. The warning text will be added to the log file. \__msg_kernel_error:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} \__msg_kernel_error:nnnnnn \__msg_kernel_error:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) Updated: 2012-08-11 Issues kernel hmodulei error hmessagei. with the important caveat that the message text and arguments are not expanded. the LATEX3 kernel needs to produce errors in an expansion only context. passing harg onei to harg fouri to the textcreating functions. However.\__msg_kernel_fatal:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} \__msg_kernel_fatal:nnnnnn \__msg_kernel_fatal:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) Updated: 2012-08-11 Issues kernel hmodulei error hmessagei. After user input. After issuing a fatal error the TEX run will halt. \__msg_kernel_warning:nnnnnn \__msg_kernel_warning:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) Updated: 2012-08-11 \__msg_kernel_warning:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Issues kernel hmodulei warning hmessagei. but the TEX run will not be interrupted. \__msg_kernel_info:nnnnnn \__msg_kernel_info:(nnnnn|nnnn|nnn|nn|nnxxxx|nnxxx|nnxx|nnx) Updated: 2012-08-11 \__msg_kernel_info:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Issues kernel hmodulei information hmessagei. passing harg onei to harg fouri to the text-creating functions. otherwise it will be cropped. as none of the tools to print to the terminal or the log file are expandable. passing harg onei to harg fouri to the text-creating functions. the run will continue. This must be handled internally very differently from normal error messages. The resulting string must be shorter than a line. passing harg onei to harg fouri to the text-creating functions. Cannot be redirected. 147 . and messages should be very short. \__msg_show_variable:n {hformatted text i} Shows the hformatted texti on the terminal. TEXhackers note: This function expands to an empty token list after two steps. the \__msg_show_item:nn and \__msg_show_item_unbraced:nn versions for key– value like data structures. \__msg_term:nnnnnn \__msg_term:(nnnnnV|nnnnn|nnn|nn) \__msg_term:nnnnnn {hmodule i} {hmessage i} {harg one i} {harg two i} {harg three i} {harg four i} Prints the hmessagei from hmodulei in the terminal without formatting. 148 . The hformatted contenti will be processed as the first argument in a call to \iow_wrap:nnnN. The herror messagei must be short: it is cropped at the end of one line. \__msg_show_item:n \__msg_show_item:nn \__msg_show_item_unbraced:nn \__msg_show_item:n hitem i \__msg_show_item:nn hitem-key i hitem-value i Updated: 2012-09-09 Auxiliary functions used within the argument of \__msg_show_variable:Nnn to format variable items correctly for display. \␣ and other formatting sequences can be used. and prints the herror messagei. and the part of hformatted texti before the first > is removed. the hformatted contenti must either be empty or contain >. \__msg_show_variable:Nnn Updated: 2012-09-09 \__msg_show_variable:n Updated: 2012-09-09 \__msg_show_variable:Nnn hvariable i {htype i} {hformatted content i} Displays the hformatted contenti of the hvariablei of htypei in the terminal. 8 Internal l3msg functions The following functions are used in several kernel modules. Tokens inserted in response to TEX’s prompt are read with the current category code setting. and inserted just after the place where the error message was issued.\__msg_expandable_error:n {herror message i} \__msg_expandable_error:n ? New: 2011-08-11 Updated: 2011-08-13 Issues an “Undefined error” message from TEX itself. Once expanded and processed. the hformatted texti must contain >. Used in messages which print complex variable contents completely. hence \\. The \__msg_show_item:n version is used for simple lists. unless it is empty. After expansion. everything until the first > will be removed. Failure to do so causes low-level TEX errors. \keys_set:nn will be used within a document function. for example \DeclareDocumentCommand \SomePackageSetup { m } { \keys_set:nn { module } { #1 } } \DeclareDocumentCommand \SomePackageMacro { o m } { \group_begin: 149 . key-two . minimising the number of functions and arguments required.tl_set:N = \l_module_store_tl } These values can then be set as with other key–value approaches: \keys_set:nn { module } { key-one = value one.Part XIX The l3keys package Key–value interfaces The key–value method is a popular system for creating large numbers of settings for controlling function or package behaviour. the system normally results in input of the form \PackageControlMacro{ key-one = value one. For the user. key-two = value two ]{argument}.code:n = code including parameter #1. key-two = value two } At a document level. Keys are themselves created using a key–value interface. key-two = value two } or \PackageMacro[ key-one = value one. Each key is created by setting one or more properties of the key: \keys_define:nn { module } { key-one . The high level functions here are intended as a method to create key–value controls. code:n = Some~code~using~#1. it will be created at the point that the key is set up. If the variable does not exist.\keys_set:nn { module } { #1 } % Main code for \SomePackageMacro \group_end: } Key names may contain any tokens.bool_set:N . as they are handled internally using \tl_to_str:n. The individual properties are described in the following text. each property is illustrated attached to an arbitrary hkeyi.value_required: } where the properties of the key begin from the . 1 \keys_define:nn Creating keys \keys_define:nn {hmodule i} {hkeyval list i} Parses the hkeyval listi and defines the keys listed there for hmodulei. and so \tl_set:Nn \l_module_tmp_tl { key } \keys_define:nn { module } { \l_module_tmp_tl . 150 . The various properties available take either no arguments at all. The hkeyval listi should consist of one or more key names along with an associated key property.code:n = code } will create a key called \l_module_tmp_tl. In practice the hmodulei should be chosen to be unique to the module in question (unless deliberately adding keys to an existing module). but there are no restrictions on the nature of the text. or require exactly one argument. In the following discussion. which when used may be supplied with a hvaluei. a typical use of \keys_define:nn might read \keys_define:nn { mymodule } { keyname . it is suggested that the character / is reserved for sub-division of keys into logical groups. The properties of a key determine how it acts. . keyname . after the key name. Functions and variables are not expanded when creating key names. The hmodulei name should be a text value.bool_gset:N hkey i .bool_set:N = hboolean i Defines hkeyi to set hbooleani to hvaluei (which must be either true or false). All key definitions are local. and not one called key. As will be discussed in section 2. This is indicated in the name of the property using an argument specification. Inside hcodei. . Choices are discussed in detail in section 3.choice_code:n = hcode i Stores hcodei for use when . Spaces around commas and empty items will be stripped.choices:nn hkey i .. \l_keys_choice_tl will be the name of the choice made. \l_keys_choice_tl will expand to the name of the choice made.clist_gset:N .clist_set:N .clist_set:N = hcomma list variable i Defines hkeyi to set hcomma list variablei to hvaluei.generate_choices:n creates one or more choice sub-keys of the current key.code:n . If the hbooleani does not exist. which will be the hvaluei given for the hkeyi. it will be created at the point that the key is set up.choice_code:n .bool_set_inverse:N . If the variable does not exist.bool_set_inverse:N = hboolean i Defines hkeyi to set hbooleani to the logical inverse of hvaluei (which must be either true or false).choice: Sets hkeyi to act as a choice key.code:n = hcode i Stores the hcodei for execution when hkeyi is used. Inside hcodei. as discussed in section 3.choice: hkey i .bool_gset_inverse:N New: 2011-08-28 .code:x hkey i .generate_choices:n. and \l_keys_choice_int will be the position of the choice in the list given to . The The hcodei can include one parameter (#1). and defines a series hchoicesi which are implemented using the hcodei. . it will be created at the point that the key is set up. hkey i .clist_set:c . The x-type variant will expand hcodei at the point where the hkeyi is created. 151 .clist_gset:c hkey i . Each valid choice for hkeyi must then be created.choice_code:x . and \l_keys_choice_int will be the position of the choice in the list of hchoicesi (indexed from 1). Choices are discussed in detail in section 3. hkey i . New: 2011/09/11 .choices:nn hchoices i hcode i New: 2011-08-21 Sets hkeyi to act as a choice key. Each choice will be set up to execute hcodei as set using . it will be created at the point that the key is set up.initial:n . equivalent to New: 2012-06-02 \keys_set:nn {hmodulei} { hkeyi = hvaluei } ..dim_gset:N . This will be used if only the key name is given.fp_gset:N . If the variable does not exist. The hlisti should consist of a comma-separated list of choice names. hkey i .int_gset:N . If the variable does not exist.default:V hkey i .int_set:c .int_set:N = hinteger i Defines hkeyi to set hintegeri to hvaluei (which must be an integer expression).fp_set:N = hfloating point i Defines hkeyi to set hfloating pointi to hvaluei (which must a floating point number).generate_choices:n = {hlist i} This property will mark hkeyi as a multiple choice key. % Prints ’Hello Fred’ key. but not if a blank hvaluei is given: \keys_define:nn { module } { key .dim_set:N = hdimension i Defines hkeyi to set hdimensioni to hvaluei (which must a dimension expression). 152 .initial:V hkey i . and will use the hlisti to define the choices.default:n . % Prints ’Hello World’ key = .int_gset:c hkey i . which is used if no value is given.fp_set:c .choice_code:x).dim_set:N .default:n = World } \keys_set:nn { module } { key = Fred. hkey i .generate_choices:n hkey i .default:n = hdefault i Creates a hdefaulti value for hkeyi. Choices are discussed in detail in section 3.code:n = Hello~#1.choice_code:n (or .int_set:N .dim_gset:c .initial:n = hvalue i Initialises the hkeyi with the hvaluei. it will be created at the point that the key is set up. If the variable does not exist. it will be created at the point that the key is set up. % Prints ’Hello ’ } . key .fp_gset:c .dim_set:c .fp_set:N . . multichoice: Sets hkeyi to act as a multiple choice key.tl_set:c .multichoices:nn New: 2011-08-21 . If a hvaluei is given then an error will be issued. 153 . it will be created at the point that the key is set up. as discussed in section 3.meta:x .tl_set:N = htoken list variable i Defines hkeyi to set htoken list variablei to hvaluei.meta:n . If the variable does not exist.tl_set:N .tl_gset_x:N . hkey i . using \tl_set:Nx).tl_set_x:c .multichoice: New: 2011-08-21 . This property is experimental. If the variable does not exist.value_required: Specifies that hkeyi must receive a hvaluei when used.skip_gset:c . which will set hkeyval listi in one go. . If the variable does not exist. This property is experimental. If a hvaluei is not given then an error will be issued.value_forbidden: Specifies that hkeyi cannot receive a hvaluei when used. hkey i .skip_set:c .tl_gset:c .e..value_forbidden: hkey i . hkey i . and \l_keys_choice_int will be the position of the choice in the list of hchoicesi (indexed from 1). which will be subjected to an x-type expansion (i.multichoices:nn hchoices i hcode i Sets hkeyi to act as a multiple choice key.skip_set:N . it will be created at the point that the key is set up. hkey i .meta:n = {hkeyval list i} Makes hkeyi a meta-key. hkey i . Choices are discussed in detail in section 3.value_required: hkey i . hkey i .tl_set_x:N = htoken list variable i Defines hkeyi to set htoken list variablei to hvaluei. Each valid choice for hkeyi must then be created. Inside hcodei. \l_keys_choice_tl will be the name of the choice made. then the value will be passed through to the subsidiary hkeysi for processing (as #1).tl_gset:N .skip_set:N = hskip i Defines hkeyi to set hskipi to hvaluei (which must be a skip expression). and defines a series hchoicesi which are implemented using the hcodei. it will be created at the point that the key is set up.skip_gset:N .tl_set_x:N . If hkeyi is given with a value at the time the key is used.tl_gset_x:c . generate_choices:n properties: \keys_define:nn { module } { key . 3 Choice and multiple choice keys The l3keys system supports two types of choice key.choice: property: \keys_define:nn { module } { key .~ which~is~in~position~ \int_use:N \l_keys_choice_int \c_space_tl in~the~list.choice_code:n = { You~gave~choice~’\int_use:N \l_keys_choice_tl’. and can be rapidly created using the . In many cases. }. the keys can share the same code. this subdivision is particularly relevant to making multiple choices.choice_code:n and . in which a series of pre-defined input values are linked to varying implementations. This can be carried out in two ways. Here. the best choice of token for sub-dividing keys in this way is /.code:n = code } As illustrated.choice: } For keys which are set up as choices.2 Sub-dividing keys When creating large numbers of keys. This is because of the method that is used to represent keys internally. Mutually-exclusive choices are created by setting the . the valid choices are generated by creating sub-keys of the choice key.code:n = code } or to the key name: \keys_define:nn { module } { subgroup / key . “Multiple” choice keys are also supported: these allow a selection of values to be chosen at the same time. 154 . This can be achieved either by adding a sub-division to the module name: \keys_define:nn { module / subgroup } { key . Both of the above code fragments set the same key. it may be desirable to divide them into several sub-groups for a given module. choices execute similar code which is dependant only on the name of the choice or the position of the choice in the list of choices. Choice keys are usually created so that the various values are mutually-exclusive: only one can apply at any one time. which has full name module/subgroup/key. As will be illustrated in the next section. the variables \l_keys_choice_tl and \l_keys_choice_int are available to indicate the name of the current choice.generate_choices:n.multichoice: and .choices:nn.choices:nn. \l_keys_choice_int \l_keys_choice_tl Inside the code block for a choice generated using . choice-c } } Following common computing practice. The position is indexed from 0. choice-b. choice-b.generate_choices:n = { choice-a.multichoices:nn.choice:.choice_code:n and . key / choice-b . This can be achieved by setting the .generate_choice: or . The same approach is also implemented by the experimental property . As with mutually exclusive choices. } It is possible to mix the two methods.choices:nn property should not be mixed with use of .generate_choices:n into one property: \keys_define:nn { module } { key .~ which~is~in~position~ \int_use:N \l_keys_choice_int \c_space_tl in~the~list. This combines the functionality of . These variables do not have defined behaviour when used outside of code created using . choice-c } { You~gave~choice~’\int_use:N \l_keys_choice_tl’. then manually defining sub-keys. anything might happen). On the other hand. } } Note that the .code:n = code-b.key . key / choice-c . and its position in the comma list. \l_keys_choice_int is indexed from 1.choice: property of a key.e. Thus both 155 . but manually-created choices should not use \l_keys_choice_tl or \l_keys_choice_int.choices:nn = { choice-a.code:n = code-a. key / choice-a . \keys_define:nn { module } { key . multiple choices are define as sub-keys. Multiple choices are created in a very similar manner to mutually-exclusive choices.code:n = code-c. it is sometimes useful to create choices which use entirely different code from one another.generate_choices:n (i. using the properties . and sets those keys which are defined for hmodulei. } 156 .\keys_define:nn { module } { key . \keys_define:nn { module } { unknown . The behaviour on finding an unknown key can be set by defining a special unknown key: this will be illustrated later. key / choice-c .code:n = You~tried~to~set~key~’\l_keys_key_tl’~to~’#1’. When multiple choice keys are set.~ which~is~in~position~ \int_use:N \l_keys_choice_int \c_space_tl in~the~list. choice-b. } are valid.code:n = code-b. c } % ’key’ defined as a multiple choice } Each choice will be applied in turn. choice-c } { You~gave~choice~’\int_use:N \l_keys_choice_tl’. This mechanism can be used to create new keys from user input. If a key is not known.choices:nn. \keys_set:nn will look for a special unknown key for the same module. the value is treated as a comma-separated list: \keys_set:nn { module } { key = { a . 4 \keys_set:nn \keys_set:(nV|nv|no) Setting keys \keys_set:nn {hmodule i} {hkeyval list i} Parses the hkeyval listi. with the usual handling of unknown values. b .multichoices:nn property causes \l_keys_choice_tl and \l_keys_choice_int to be set in exactly the same way as described for .multichoices:nn = { choice-a. The .code:n = code-c.code:n = code-a. key / choice-a .multichoice:. } } and \keys_define:nn { module } { key . key / choice-b . if any code has been defined for hkeyi/hchoicei. Note that this will have been processed using \tl_to_str:n. \keys_if_choice_exist_p:nnn ? \keys_if_choice_exist:nnnTF ? New: 2011-08-21 \keys_if_choice_exist_p:nnn hmodule i hkey i hchoice i \keys_if_choice_exist:nnnTF hmodule i hkey i hchoice i {htrue code i} {hfalse code i} Tests if the hchoicei is defined for the hkeyi within the hmodulei„ i. i. the path of the key used is available as \l_keys_path_tl. and sets those keys which are defined for hmodulei.e. the value of the key is available as \l_keys_value_tl. Any keys which are unknown are not processed further by the parser. The key–value pairs for each unknown key name will be stored in the hclisti. 5 Setting known keys only \keys_set_known:nnN \keys_set_known:(nVN|nvN|noN) \keys_set_known:nn {hmodule i} {hkeyval list i} hclist i New: 2011-08-23 Parses the hkeyval listi. 6 \keys_if_exist_p:nn ? \keys_if_exist:nnTF ? Utility functions for keys \keys_if_exist_p:nn hmodule i hkey i \keys_if_exist:nnTF hmodule i hkey i {htrue code i} {hfalse code i} Tests if the hkeyi exists for hmodulei.\l_keys_key_tl When processing an unknown key. \keys_show:nn \keys_show:nn {hmodule i} {hkey i} Shows the function which is used to actually implement a hkeyi for a hmodulei. the name of the key is available as \l_keys_key_tl. Note that this will be empty if no value was given for the key. Note that this will have been processed using \tl_to_str:n. The test is false if the hkeyi itself is not defined. \l_keys_value_tl When processing an unknown key.e. 7 Low-level interface for parsing key–val lists To re-cap from earlier. a key–value list is input of the form 157 . if any code has been defined for hkeyi. \l_keys_path_tl When processing an unknown key. e two arguments). One function is needed to process key–value pairs (i. are treated identically. thus key = {value here}. This processing is not carried out by the low-level parser itself. are corrected so that the parser does not “miss” any due to category code changes. and each key–value pair does not necessarily contain an equals sign or a value! Processing this type of input correctly requires a number of careful steps. and so the parser requires the names of two functions along with the key–value list.e.KeyOne = ValueOne . KeyThree where each key–value pair is separated by a comma from the rest of the list. After the parsing phase is completed. The parser does not double # tokens or expand any input. in especial circumstances you may wish to use a lower-level approach. to correctly account for braces. and key = value here. spaces and the category codes of separators. KeyTwo = ValueTwo . Spaces are removed from the ends of the keys and values. While the functions described earlier are used as a high-level interface for processing such input. and a second function if required for keys given without arguments (i. The tokens = and . 158 . Values which are given in braces will have exactly one set removed. a single argument). the resulting keys and values (or keys alone) are available for further processing. The low-level parsing system converts a hkey–value listi into hkeysi and associated hvaluesi. Thus \keyval_parse:NNn \function:n \function:nn { key1 = value1 . After \keyval_parse:NNn has parsed the hkey–value listi. and any outer set of braces are removed from the hvaluei as part of the processing. Spaces are trimmed from the ends of the hkeyi and hvaluei. key3 = . 159 . hfunction1 i will be used to process keys given with no value and hfunction2 i will be used to process keys given with a value. key4 } will be converted into an input stream \function:nn \function:nn \function:nn \function:n { { { { key1 key2 key3 key4 } { value1 } } { value2 } } { } } Note that there is a difference between an empty value (an equals sign followed by nothing) and a missing value (no equals sign at all).\keyval_parse:NNn Updated: 2011-09-08 \keyval_parse:NNn hfunction1 i hfunction2 i {hkey–value list i} Parses the hkey–value listi into a series of hkeysi and associated hvaluesi. or keys alone (if no hvaluei was given). hfunction1 i should take one argument. while hfunction2 i should absorb two arguments. key2 = value2. The order of the hkeysi in the hkey–value listi will be preserved. If the file is not found then the htl vari will contain the marker \q_no_value.Part XX The l3file package File and I/O operations This module provides functions for working with external files. It is important to remember that when reading external files TEX will attempt to locate them both the operating system path and entries in the TEX file database (most TEX systems use such a database). and if found sets the htl vari the fully-qualified name of the file. Some of these functions apply to an entire file. \file_if_exist:nTF {hfile name i} {htrue code i} {hfalse code i} Searches for hfile namei using the current TEX search path and the additional paths controlled by \file_path_include:n). 1 \g_file_current_name_tl \file_if_exist:nTF Updated: 2012-02-10 \file_add_path:nN File operation functions Contains the name of the current LATEX file.. \file_input:n \file_input:n {hfile name i} Updated: 2012-02-17 Searches for hfile namei in the path as detailed for \file_if_exist:nTF. (writing). and have prefix \file_. while others are used to work with files on a line by line basis and have prefix \ior_... It will be equal to \c_job_name_tl at the start of a LATEX run and will be modified each time a file is read using \file_input:n. An error will be raised if the file is not found. For functions which expect a hfile namei argument. Thus the “current path” for TEX is somewhat broader than that for other programs. Any active characters (as declared in \l_char_active_seq) will not be expanded. the path and file name.. Spaces are not allowed in file names... All files read are recorded for information and the file name stack is updated by this function. allowing the direct use of these in file names. (reading) or \iow_. this argument may contain both literal items and expandable content. \file_add_path:nN {hfile name i} htl var i Updated: 2012-02-10 Searches for hfile namei in the path as detailed for \file_if_exist:nTF. which should on full expansion be the desired file name. This variable should not be modified: it is intended for information only. and if found reads in the file as additional LATEX source.e.. i. 160 . The hstreami is available for access immediately and will remain allocated to hfile namei until a \ior_close:N instruction is given or the TEX run ends. to release them for other processes. Spaces are not allowed in the hpathi.\file_path_include:n Updated: 2012-07-04 \file_path_remove:n Updated: 2012-07-04 \file_list: \file_path_include:n {hpath i} Adds hpathi to the list of those used to search when reading files. The hpathi is processed in the same way as a hfile namei. direct use of the streams by the programmer is not supported in LATEX3. Spaces are not allowed in the hpathi. If the hstreami was already open it is closed before the new operation begins. and the hstreami will behave as the corresponding \c_term_. Note that I/O operations are global: streams should all be declared with global names and treated accordingly. \file_path_remove:n {hpath i} Removes hpathi from the list of those used to search when reading files. with x-type expansion except active characters. As a result. The assignment is local.. the programmer should close streams when they are no longer needed.1 Input–output stream management As TEX is limited to 16 input streams and 16 output streams. The htrue codei is then inserted into the input stream. i.e. The hpathi is processed in the same way as a hfile namei. The hstreami is not opened until the appropriate \. The assignment is local. no error is raised and the hfalse codei is inserted into the input stream.e. Instead. and these are allocated and deallocated as needed by other modules._open:Nn function is used. \ior_open:NnTF hstream i {hfile name i} {htrue code i} {hfalse code i} Opens hfile namei for reading using hstreami as the control sequence for file access. 1. either for reading or for writing as appropriate... with x-type expansion except active characters. an internal pool of streams is maintained. \file_list: This function will list all files loaded using \file_input:n in the log file.. If the file is not found. If the hstreami was already open it is closed before the new operation begins.. i. \ior_new:N \ior_new:c \iow_new:N \iow_new:c New: 2011-09-26 Updated: 2011-12-27 \ior_open:Nn \ior_open:cn Updated: 2012-02-10 \ior_open:NnTF \ior_open:cnTF New: 2013-01-12 \ior_new:N hstream i \iow_new:N hstream i Globally reserves the name of the hstreami. The hstreami is available for access immediately and will remain allocated to hfile namei until a \ior_close:N instruction is given or the TEX run ends.. \ior_open:Nn hstream i {hfile name i} Opens hfile namei for reading using hstreami as the control sequence for file access. Attempting to use a hstreami which has not been opened is an error.. 161 . 162 . However. 1. If the hstreami is not open. \ior_get_str:NN New: 2012-06-24 Updated: 2012-07-31 \ior_get_str:NN hstream i htoken list variable i Function that reads one line from the input hstreami and stores the result locally in the htoken listi variable. input is requested from the terminal. The material read from the hstreami will be tokenized by TEX according to the category codes in force when the function is used.e. If the hstreami is not open. TEXhackers note: This protected macro is a wrapper around the ε-TEX primitive \readline. \ior_close:N hstream i \iow_close:N hstream i Closes the hstreami.\iow_open:Nn \iow_open:cn Updated: 2012-02-09 \ior_close:N \ior_close:c \iow_close:N \iow_close:c \iow_open:Nn hstream i {hfile name i} Opens hfile namei for writing using hstreami as the control sequence for file access. Updated: 2012-07-31 \ior_list_streams: \iow_list_streams: Updated: 2012-09-09 \ior_list_streams: \iow_list_streams: Displays a list of the file names associated with each open stream: intended for tracking down problems. writing is not additive). TEXhackers note: This protected macro expands to the TEX primitive \read along with the to keyword. Opening a file for writing will clear any existing content in the file (i. with the exception of space characters which are given category code 10 (space).2 Reading from files \ior_get:NN \ior_get:NN hstream i htoken list variable i New: 2012-06-24 Function that reads one or more lines (until an equal number of left and right braces are found) from the input hstreami and stores the result locally in the htoken listi variable. Streams should always be closed when they are finished with as this ensures that they remain available to other programmers. The hstreami is available for access immediately and will remain allocated to hfile namei until a \iow_close:N instruction is given or the TEX run ends. If the hstreami was already open it is closed before the new operation begins. the end-line character normally added by this primitive is not included in the result of \ior_get_str:NN. input is requested from the terminal. The material is read from the hstreami as a series of tokens with category code 12 (other). at shipout).g. \iow_shipout:Nn hstream i {htokens i} This functions writes htokensi to the specified hstreami when the current page is finalised (i. The test will also return a true value if the hstreami is not open. Useful when trying to write difficult characters such as %. the write operation is called on expansion of \iow_now:Nn). The x-type variants expand the htokensi at the point where the function is used but not when the resulting tokens are written to the hstreami (cf. {. 2 \iow_now:Nn \iow_now:Nx Updated: 2012-06-05 \iow_log:n \iow_log:x \iow_term:n \iow_term:x \iow_shipout:Nn \iow_shipout:Nx \iow_shipout_x:Nn \iow_shipout_x:Nx Updated: 2012-09-08 Writing to files \iow_now:Nn hstream i {htokens i} This functions writes htokensi to the specified hstreami immediately (i.e. The htokensi are expanded at the time of writing in addition to any expansion when the function is used. }. etc. TEXhackers note: This is a wrapper around the TEX primitive \write.e. for example: \iow_now:Nx \g_my_iow { \iow_char:N \{ text \iow_char:N \} } The function has no effect if writing is taking place without expansion (e. in messages. This makes these functions suitable for including material finalised during the page building process (such as the page number integer). \iow_shipout_x:Nn hstream i {htokens i} This functions writes htokensi to the specified hstreami when the current page is finalised (i. \iow_char:N ? \iow_char:N \hchar i Inserts hchari into the output stream.\ior_if_eof_p:N ? \ior_if_eof:NTF ? Updated: 2012-02-10 \ior_if_eof_p:N hstream i \ior_if_eof:NTF hstream i {htrue code i} {hfalse code i} Tests if the end of a hstreami has been reached during a reading operation.e. \iow_shipout_x:Nn). \iow_log:n {htokens i} This function writes the given htokensi to the log (transcript) file immediately: it is a dedicated version of \iow_now:Nn. 163 . in the second argument of \iow_now:Nn). \iow_term:n {htokens i} This function writes the given htokensi to the terminal file immediately: it is a dedicated version of \iow_now:Nn. at shipout). At the start of each line which is wrapped. this is less conceptually clear than conversion to a string. \tl_to_str:N. with the following substitutions: • \\ may be used to force a new line. • \#. Additional functions may be added to the wrapping by using the hset upi.e. The htexti and hrun-on texti are exhaustively expanded by the function. \{. the argument passed to the hfunctioni) will consist of characters of category “other” (category code 12). use \\ to force line breaks.1 \iow_wrap:nnnN New: 2012-06-28 Wrapping lines in output \iow_wrap:nnnN {htext i} {hrun-on text i} {hset up i} hfunction i This function will wrap the htexti to a fixed number of characters per line. This function will not cause a line break. • \iow_indent:n may be used to indent a part of the message. The function has no effect if writing is taking place without expansion (e. which is executed before the wrapping takes place: this may include overriding the substitutions listed. \%. the hrun-on texti will be inserted. and only affects lines which start within the scope of the htexti. The result of the wrapping operation is passed as a braced argument to the hfunctioni. etc. \~ may be used to represent the corresponding character.\iow_newline: ? \iow_newline: Function to add a new line within the htokensi written to a file. This is done in such a way that \exp_not:N or \exp_not:n could be used to prevent expansion of material. indents htexti by four spaces. \iow_indent:n New: 2011-09-21 \iow_indent:n {htext i} In the context of \iow_wrap:nnnN (for instance in messages). \}. \iow_wrap:nnnN carries out an x-type expansion on the htexti to expand it. Any expandable material in the htexti which is not to be expanded on wrapping should be converted to a string using \token_to_str:N. The output of \iow_wrap:nnnN (i. which will typically be a wrapper around a write operation. However. \tl_to_str:n. 2. TEXhackers note: Internally. which is therefore the supported method for handling expandable material in the htexti. The line character count targeted will be the value of \l_iow_line_count_int minus the number of characters in the hrun-on texti. 164 . in the second argument of \iow_now:Nn). • \␣ may be used to represent a forced space (for example after a control sequence). with the exception of spaces which will have category “space” (category code 10). In case the indented htexti should appear on separate lines from the surrounding text.g. This means that the output will not expand further when written to a file. 4 \l__file_internal_name_ior \l__file_internal_name_tl Internal file functions and variables Used to test for the existence of files when opening. (“other”). Reading from this stream using \ior_get:NN or similar will result in a prompt from TEX of the form <tl>= \c_log_iow \c_term_iow Constant output streams for writing to the log and to the terminal (plus the log). 165 . Used to return the full name of a file for internal use. 2. and character code 32 (space). 2. This value depends on the TEX system in use: the standard value is 78.\l_iow_line_count_int New: 2012-06-24 \c_catcode_other_space_tl New: 2011-09-05 The maximum number of characters in a line to be written by the \iow_wrap:nnnN function.2 \c_term_ior Constant input–output streams Constant input stream for reading from the terminal. which is true for non-existent files.3 \if_eof:w ? Primitive conditionals \if_eof:w hstream i htrue code i \else: hfalse code i \fi: Tests if the hstreami returns “end of file”. respectively. The \else: branch is optional. Token list containing one character with category code 12. which is typically correct for unmodified TEXlive and MiKTEX systems. TEXhackers note: This is the TEX primitive \ifeof. 2. which are not expanded. The list of hactivei tokens is taken from \l_char_active_seq. If any spaces are found in the name after expansion. See for example the implementation of \file_add_path:nN. The hsanitized namei is then inserted (in braces) after the htokensi. 2. and it does not attempt to add a hpathi to the hfile namei: it is therefore intended to be used by higher-level functions which have already fully expanded the hfile namei and which need to perform multiple open or close operations.5 \__ior_open:Nn \__ior_open:No New: 2012-01-23 Internal input–output functions \__ior_open:Nn hstream i {hfile name i} This function has identical syntax to the public version. 166 . However. an error is raised. which should further process the file name. is does not take precautions against active characters in the hfile namei.\__file_name_sanitize:nn New: 2012-02-09 \__file_name_sanitize:nn {hname i} {htokens i} Exhaustively-expands the hnamei with the exception of any category hactivei (catcode 13) tokens. deg (one degree in radians).5)}{2} + 2\cdot 10^{-3} = \ExplSyntaxOn \fp_to_decimal:n {sin 3. .Part XXI The l3fp package: floating points A decimal floating point number is one which is stored as a significand and a separate exponent. n) round towards zero. acsc x. abs(x).3 to know what the various operations do.0001). which is automatically replaced by its current value. division x/y. multiplication x ∗ y. and skip variables to floating points. The module implements expandably a wide set of arithmetic. (not yet) Inverse trigonometric functions: asin x.2 for details about how an expression is parsed. xy . atan x. • Exponentials: exp x. or as a stored floating point variable.). and other operations on decimal floating point numbers. ternary operator x ? y : z. acosh x. round0(x. tanh x. described in section 7. cot x. And (not yet) modulo. expressing dimensions in points and ignoring the stretch and shrink components of skips. n) round to closest. .5 /2 + 2e-3} $. disjunction x || y. sec x. • Extrema: max(x. cosh x. x ! = y etc. x <= y. • Automatic conversion (no need for \htype i_use:N) of integer. y.g. ln x. • Basic arithmetic: addition x + y. y. asech x. x >? y. dimension. asec x. • Trigonometry: sin x. tan x. 167 . atanh x. trigonometric. See section 9. automatically expressed in points. min(x. (not yet) Hyperbolic functions and their inverse functions: sinh x. An example of use could be the following. • Boolean logic: negation ! x. round±(x. cos x. . • Rounding functions: round(x. or -. and parentheses. coth x. acoth x.234e-34. sech x. . to be used within floating point expressions.). acos x. acot x. n) round towards ±∞. Some operations may raise exceptions (error messages).1 for a description of what a floating point is. subtraction x − y. • Comparison operators: x < y. Floating point numbers can be given either explicitly (in a form such as 1. . Floating point expressions support the following operations with their usual precedence. csch. acsch x.. \LaTeX{} can now compute: $ \frac{\sin (3. pc is 12. and section 9. csc x. • Dimensions. • Constants: pi. e. . section 9. and asinh x. and “quantize”. conjunction x && y. this module is mostly meant as an underlying tool for higher-level commands. one could provide a function to typeset nicely the result of floating point computations. siunitx} \ExplSyntaxOn \NewDocumentCommand { \calcnum } { m } { \num { \fp_to_scientific:n {#1} } } \ExplSyntaxOff \calcnum { 2 pi * sin ( 2. Updated: 2012-05-08 168 . The hfp vari will be set globally equal to the result of evaluating the hfloating point expressioni.3 ^ 5 ) } 1 \fp_new:N \fp_new:c Updated: 2012-05-08 \fp_const:Nn \fp_const:cn Updated: 2012-05-08 \fp_zero:N \fp_zero:c \fp_gzero:N \fp_gzero:c Creating and initialising floating point variables \fp_new:N hfp var i Creates a new hfp vari or raises an error if the name is already taken. The declaration is global.But in all fairness. The hfp vari will initially be +0. Updated: 2012-05-08 2 \fp_set:Nn \fp_set:cn \fp_gset:Nn \fp_gset:cn Setting floating point variables \fp_set:Nn hfp var i {hfloating point expression i} Sets hfp vari equal to the result of computing the hfloating point expressioni. \fp_const:Nn hfp var i {hfloating point expression i} Creates a new constant hfp vari or raises an error if the name is already taken. For example. \fp_zero:N hfp var i Sets the hfp vari to +0. \usepackage{xparse. Updated: 2012-05-08 \fp_zero_new:N \fp_zero_new:c \fp_gzero_new:N \fp_gzero_new:c \fp_zero_new:N hfp var i Ensures that the hfp vari exists globally by applying \fp_new:N if necessary. then applies \fp_(g)zero:N to leave the hfp vari set to zero. Leading or trailing zeros may be inserted to compensate for the exponent. and integers are expressed without a decimal separator. Updated: 2012-05-08 \fp_sub:Nn hfp var i {hfloating point expression i} \fp_sub:Nn \fp_sub:cn \fp_gsub:Nn \fp_gsub:cn Subtracts the result of computing the hfloating point expressioni from the hfp vari. Non-significant trailing zeros are trimmed. Leading or trailing zeros may be inserted to compensate for the exponent. Updated: 2012-05-08 \fp_add:Nn hfp var i {hfloating point expression i} \fp_add:Nn \fp_add:cn \fp_gadd:Nn \fp_gadd:cn Adds the result of computing the hfloating point expressioni to the hfp vari. Non-significant trailing zeros are trimmed. and integers are expressed without a decimal separator. The output is identical to \fp_to_decimal:n. The values ±∞ and nan trigger an “invalid operation” exception. Updated: 2012-05-08 3 \fp_eval:n ? New: 2012-05-08 Updated: 2012-07-08 \fp_to_decimal:N ? \fp_to_decimal:(c|n) ? New: 2012-05-08 Updated: 2012-07-08 \fp_to_dim:N ? \fp_to_dim:(c|n) ? Updated: 2012-07-08 Using floating point numbers \fp_eval:n {hfloating point expression i} Evaluates the hfloating point expressioni and expresses the result as a decimal number with 16 significant figures and no exponent.\fp_set_eq:NN \fp_set_eq:(cN|Nc|cc) \fp_gset_eq:NN \fp_gset_eq:(cN|Nc|cc) \fp_set_eq:NN hfp var1 i hfp var2 i Sets the floating point variable hfp var1 i equal to the current value of hfp var2 i. The values ±∞ and nan trigger an “invalid operation” exception. the result may be outside the range [−214 + 2−17 . This function is identical to \fp_to_decimal:n. with an additional trailing pt. \fp_to_decimal:N hfp var i \fp_to_decimal:n {hfloating point expression i} Evaluates the hfloating point expressioni and expresses the result as a decimal number with 16 significant figures and no exponent. 214 −2−17 ] of valid TEX dimensions. 169 . \fp_to_dim:N hfp var i \fp_to_dim:n {hfloating point expression i} Evaluates the hfloating point expressioni and expresses the result as a dimension (in pt) suitable for use in dimension expressions. The values ±∞ and nan trigger an “invalid operation” exception. leading to overflow errors if used as a dimension. In particular. The values ±∞ and nan trigger an “invalid operation” exception. This does not check that the hfp vari really is a floating point variable. Leading or trailing zeros may be inserted to compensate for the exponent. -inf. Negative numbers start with -. ∞) are expressed in scientific notation with trailing zeros trimmed (see \fp_to_scientific:n). with ties rounded to an even integer. \fp_to_scientific:N hfp var i \fp_to_scientific:n {hfloating point expression i} Evaluates the hfloating point expressioni and expresses the result in scientific notation with 16 significant figures: hoptional .\fp_to_int:N ? \fp_to_int:(c|n) ? Updated: 2012-07-08 \fp_to_scientific:N ? \fp_to_scientific:(c|n) ? New: 2012-05-08 Updated: 2012-07-08 \fp_to_int:N hfp var i \fp_to_int:n {hfloating point expression i} Evaluates the hfloating point expressioni. with trailing zeros trimmed. This function is identical to \fp_to_decimal:N. 4 \fp_if_exist_p:N \fp_if_exist_p:c \fp_if_exist:NTF \fp_if_exist:cTF ? ? ? ? Floating point conditionals \fp_if_exist_p:N hfp var i \fp_if_exist:NTF hfp var i {htrue code i} {hfalse code i} Tests whether the hfp vari is currently defined. 10−3 ) and [1016 . \fp_use:N hfp var i Inserts the value of the hfp vari into the input stream as a decimal number with 16 significant figures and no exponent. The special values ±0. and rounds the result to the closest integer. The values ±∞ and nan trigger an “invalid operation” exception. and no decimal separator for integer values (see \fp_to_decimal:n.h15 digitsiehoptional signihexponenti The leading hdigiti is non-zero except in the case of ±0.ihdigiti. triggering TEX errors if used in an integer expression. Integers are expressed without a decimal separator. The result may be outside the range [−231 + 1. Numbers in the ranges (0. inf. ± inf and nan are rendered as 0. -0. The values ±∞ and nan trigger an “invalid operation” exception. and nan respectively. Non-significant trailing zeros are trimmed. Numbers in the range [10−3 . \fp_to_tl:N ? \fp_to_tl:(c|n) ? Updated: 2012-07-08 \fp_use:N \fp_use:c ? ? Updated: 2012-07-08 \fp_to_tl:N hfp var i \fp_to_tl:n {hfloating point expression i} Evaluates the hfloating point expressioni and expresses the result in (almost) the shortest possible form. 1016 ) are expressed in a decimal notation without exponent. Updated: 2012-05-08 170 . 231 − 1] of valid TEX integers. x=y. plus optional leading ! (which negate the hrelationi). one can use the following. with the restriction that the hrelationi may not start with ?. and returns true if the hrelationi is obeyed. The latter case occurs exactly when one of the operands is nan. \fp_compare:nNnTF { <value> } ? { 0 } { } % <value> is nan { } % <value> is not nan 5 \fp_do_until:nNnn I New: 2012-08-16 \fp_do_while:nNnn I New: 2012-08-16 \fp_until_do:nNnn I New: 2012-08-16 Floating point expression loops \fp_do_until:nNnn {hfpexpr1 i} hrelation i {hfpexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process. Two floating point numbers x and y may obey four mutually exclusive relations: xhy. \fp_do_while:nNnn {hfpexpr1 i} hrelation i {hfpexpr2 i} {hcode i} Places the hcodei in the input stream for TEX to process. Note that a nan is distinct from any value. or x and y are not ordered. even another nan. and this relations is denoted by the symbol ?. 171 . Since a nan is not comparable to any floating point. and a loop will occur until the test is true. to test if a value is nan. and then evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nNnTF. where 0 is an arbitrary floating point. and ?. >. hence x = x is not true for a nan. \fp_until_do:nNnn {hfpexpr1 i} hrelation i {hfpexpr2 i} {hcode i} Evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nNnTF. The n functions support as a hrelationi any non-empty string of those four symbols. and then evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nNnTF. !? (comparable). =. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. and then places the hcodei in the input stream if the hrelationi is false.\fp_compare_p:nNn \fp_compare_p:n \fp_compare:nNnTF \fp_compare:nTF ? ? ? ? Updated: 2012-05-08 \fp_compare_p:nNn \fp_compare:nNnTF \fp_compare_p:n { \fp_compare:nTF { {hfpexpr1 i} hrelation i {hfpexpr2 i} {hfpexpr1 i} hrelation i {hfpexpr2 i} {htrue code i} {hfalse code i} hfpexpr1 i hrelation i hfpexpr2 i } hfpexpr1 i hrelation i hfpexpr2 i } {htrue code i} {hfalse code i} Compares the hfpexpr1 i and the hfpexpr2 i. != (not equal). If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. The nNn functions support the hrelationsi <. Common choices of hrelationi include >= (greater or equal). After the hcodei has been processed by TEX the test will be repeated.xiy. and scratch variables Zero. If the test is true then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is false. with either sign. \fp_while_do:nn { hfpexpr1 i hrelation i hfpexpr2 i } {hcode i} Evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nTF. After the hcodei has been processed by TEX the test will be repeated. New: 2012-05-08 \c_one_fp One as an fp: useful for comparisons in some places. \fp_do_while:nn { hfpexpr1 i hrelation i hfpexpr2 i } {hcode i} Places the hcodei in the input stream for TEX to process. If the test is false then the hcodei will be inserted into the input stream again and a loop will occur until the hrelationi is true. \fp_until_do:nn { hfpexpr1 i hrelation i hfpexpr2 i } {hcode i} Evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nTF. 6 \c_zero_fp \c_minus_zero_fp Some useful constants. New: 2012-05-08 172 . and then places the hcodei in the input stream if the hrelationi is false. After the hcodei has been processed by TEX the test will be repeated. and a loop will occur until the test is false. and a loop will occur until the test is false. and a loop will occur until the test is true. and then evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nTF.\fp_while_do:nNnn I New: 2012-08-16 \fp_do_until:nn I New: 2012-08-16 \fp_do_while:nn I New: 2012-08-16 \fp_until_do:nn I New: 2012-08-16 \fp_while_do:nn I New: 2012-08-16 \fp_while_do:nNnn {hfpexpr1 i} hrelation i {hfpexpr2 i} {hcode i} Evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nNnTF. and then evaluates the relationship between the two hfloating point expressionsi as described for \fp_compare:nTF. After the hcodei has been processed by TEX the test will be repeated. and then places the hcodei in the input stream if the hrelationi is true. and then places the hcodei in the input stream if the hrelationi is true. \fp_do_until:nn { hfpexpr1 i hrelation i hfpexpr2 i } {hcode i} Places the hcodei in the input stream for TEX to process. New: 2012-05-08 \c_e_fp The value of the base of the natural logarithm. Within floating point expressions. The IEEE standard defines 5 types of exceptions. they may be overwritten by other non-kernel code and so should only be used for short-term storage. 7 Floating point exceptions The functions defined in this section are experimental. This normally results in a nan.\c_inf_fp \c_minus_inf_fp Infinity.g. suitable to be used for trigonometric functions. for instance 0/0. or when evaluating e. This results in ±0. or 10 ** 1e9999.. • Overflow occurs whenever the result of an operation is too large to be represented as a normal floating point number. • Invalid operation occurs for operations with no defined outcome. they may be overwritten by other non-kernel code and so should only be used for short-term storage. • Division by zero occurs when dividing a non-zero number by 0.g. \g_tmpa_fp \g_tmpb_fp Scratch floating points for global assignment. and so are safe for use with any LATEX3-defined function. and so are safe for use with any LATEX3-defined function.. with either sign. However. \l_tmpa_fp \l_tmpb_fp Scratch floating points for local assignment. “Exceptions” may occur when performing some floating point operations. These are never used by the kernel code. this can be accessed as deg. Multiply an angle given in degrees by this value to obtain a result in radians. 173 . ln(0) or cot(0). However. e = exp(1). These can be input directly in a floating point expression as inf and -inf. Note that 180 deg = pi exactly. except for conversion functions whose target type does not have a notion of nan (e. The value is rounded in a slightly odd way. • Underflow occurs whenever the result of an operation is too close to 0 to be represented as a normal floating point number. This results in ±∞. or sin(∞). such as 0 / 0. This can be input directly in a floating point expression as pi. and almost any operation involving a nan. This results in ±∞. These are never used by the kernel code. The value of 1◦ in radians. to ensure for instance that sin(pi) yields an exact 0. and their functionality may be altered or removed altogether. Updated: 2012-05-08 \c_pi_fp Updated: 2012-05-08 \c_one_degree_fp New: 2012-05-08 The value of π. \fp_to_dim:n). or do nothing at all. overflow. or only turn the flag on. \fp_flag_off:n {hexception i} Locally turns off the flag which indicates whether the hexceptioni has occurred. To each exception is associated a “flag”. which normally means the given hexceptioni has occurred. or underflow) within the current group are treated as htrap typei. The behaviour when an exception occurs can be modified (using \fp_trap:nn) to either produce an error and turn the flag on.• Inexact occurs whenever the result of a computation is not exact. Note that this function is expandable: it is used internally by l3fp to signal when exceptions do occur. \fp_flag_on:n {hexception i} Locally turns on the flag to indicate (or pretend) that the hexceptioni has occurred. the hexceptioni will halt the TEX run and display some information about the current operation in the terminal. and may be altered or removed. Updated: 2012-08-14 174 . and leave no trace. • error: additionally. At the moment. and may be altered or removed. The state of the flag can be tested and modified. this exception is entirely ignored in LATEX3. almost always. This function is experimental. in other words. and may be altered or removed. division_by_zero. and may be altered or removed. Other exceptions only raise the corresponding flag. the “invalid operation” exception triggers an (expandable) error. 8 \fp_show:N \fp_show:(c|n) New: 2012-05-08 Viewing floating points \fp_show:N hfp var i \fp_show:n {hfloating point expression i} Evaluates the hfloating point expressioni and displays the result in the terminal. By default. • flag: the hexceptioni will turn the corresponding flag on when it occurs. This function is experimental. which can be • none: the hexceptioni will be entirely ignored. This function is experimental. which can be either on or off . \fp_trap:nn {hexception i} {htrap type i} All occurrences of the hexceptioni (invalid_operation. and raises the corresponding flag. \fp_if_flag_on_p:n ? \fp_if_flag_on:nTF ? New: 2012-08-08 \fp_flag_off:n New: 2012-08-08 \fp_flag_on:n ? New: 2012-08-08 \fp_trap:nn New: 2012-07-19 Updated: 2012-08-08 \fp_if_flag_on_p:n {hexception i} \fp_if_flag_on:nTF {hexception i} {htrue code i} {hfalse code i} Tests if the flag for the hexceptioni is on. This function is experimental. 9 Floating point expressions 9.1 Input of floating point numbers We support four types of floating point numbers: • ±0.d1 d2 . . . d16 · 10n , a normal floating point number, with di ∈ [0, 9], d1 6= 0, and |n| ≤ 10000; • ±0, zero, with a given sign; • ±∞, infinity, with a given sign; • nan, is “not a number”, and can be either quiet or signalling (not yet: this distinction is currently unsupported); (not yet) subnormal numbers ±0.d1 d2 . . . d16 · 10−10000 with d1 = 0. Normal floating point numbers are stored in base 10, with 16 significant figures. On input, a normal floating point number consists of: • hsigni: a possibly empty string of + and - characters; • hsignificandi: a non-empty string of digits together with zero or one dot; • hexponenti optionally: the character e, followed by a possibly empty string of + and - tokens, and a non-empty string of digits. The sign of the resulting number is + if hsigni contains an even number of -, and otherwise, hence, an empty hsigni denotes a non-negative input. The stored significand is obtained from hsignificandi by omitting the decimal separator and leading zeros, and rounding to 16 significant digits, filling with trailing zeros if necessary. In particular, the value stored is exact if the input hsignificandi has at most 16 digits. The stored hexponenti is obtained by combining the input hexponenti (0 if absent) with a shift depending on the position of the significand and the number of leading zeros. A special case arises if the resulting hexponenti is either too large or too small for the floating point number to be represented. This results either in an overflow (the number is then replaced by ±∞), or an underflow (resulting in ±0). The result is thus ±0 if and only if hsignificandi contains no non-zero digit (i.e., consists only in 0 characters, and an optional . character), or if there is an underflow. Note that a single dot is currently a valid floating point number, equal to +0, but that is not guaranteed to remain true. Special numbers are input as follows: • inf represents +∞, and can be preceded by any hsigni, yielding ±∞ as appropriate. • nan represents a (quiet) non-number. It can be preceded by any sign, but that will be ignored. • Any unrecognizable string triggers an error, and produces a nan. 175 Note that e-1 is not a representation of 10−1 , because it could be mistaken with the difference of “e” and 1. This is consistent with several other programming languages. However, in order to avoid confusions, e-1 is not considered to be this difference either. To input the base of natural logarithms, use exp(1) or \c_e_fp. 9.2 Precedence of operators We list here all the operations supported in floating point expressions, in order of decreasing precedence: operations listed earlier bind more tightly than operations listed below them. • Implicit multiplication by juxtaposition (2pi, etc). • Function calls (sin, ln, etc). • Binary ** and ^ (right associative). • Unary +, -, !. • Binary *, / and %. • Binary + and -. • Comparisons >=, !=, <?, etc. • Logical and, denoted by &&. • Logical or, denoted by ||. • Ternary operator ?: (right associative). The precedence of operations can be overridden using parentheses. In particular, those precedences imply that sin2pi = sin(2π) = 0, 2ˆ2max(3, 4) = 22 max(3,4) = 256. Functions are called on the value of their argument, contrarily to TEX macros. 9.3 Operations We now present the various operations allowed in floating point expressions, from the lowest precedence to the highest. When used as a truth value, a floating point expression is false if it is ±0, and true otherwise, including when it is nan. 176 ?: \fp_eval:n { hoperand1 i ? hoperand2 i : hoperand3 i } The ternary operator ?: results in hoperand2 i if hoperand1 i is true, and hoperand3 i if it is false (equal to ±0). All three hoperandsi are evaluated in all cases. The operator is right associative, hence \fp_eval:n { 1 + 3 > 4 ? 1 : 2 + 4 > 5 ? 2 : 3 + 5 > 6 ? 3 : 4 } first tests whether 1 + 3 > 4; since this isn’t true, the branch following : is taken, and 2 + 4 > 5 is compared; since this is true, the branch before : is taken, and everything else is (evaluated then) ignored. That allows testing for various cases in a concise manner, with the drawback that all computations are made in all cases. TWOBARS \fp_eval:n { hoperand1 i || hoperand2 i } If hoperand1 i is true (non-zero), use that value, otherwise the value of hoperand2 i. Both hoperandsi are evaluated in all cases. && \fp_eval:n { hoperand1 i && hoperand2 i } If hoperand1 i is false (equal to ±0), use that value, otherwise the value of hoperand2 i. Both hoperandsi are evaluated in all cases. < = > ? \fp_eval:n { hoperand1 i hcomparison i hoperand2 i } + - \fp_eval:n { hoperand1 i + hoperand2 i } \fp_eval:n { hoperand1 i - hoperand2 i } The hcomparisoni consists of a non-empty string of <, =, >, and ?, optionally preceeded by !. It may not start with ?. This evaluates to +1 if the hcomparisoni between the hoperand1 i and hoperand2 i is true, and +0 otherwise. Computes the sum or the difference of its two hoperandsi. The “invalid operation” exception occurs for ∞ − ∞. “Underflow” and “overflow” occur when appropriate. * / \fp_eval:n { hoperand1 i * hoperand2 i } \fp_eval:n { hoperand1 i / hoperand2 i } Computes the product or the ratio of its two hoperandsi. The “invalid operation” exception occurs for ∞/∞, 0/0, or 0 ∗ ∞. “Division by zero” occurs when dividing a finite non-zero number by ±0. “Underflow” and “overflow” occur when appropriate. 177 + ! \fp_eval:n { + hoperand i } \fp_eval:n { - hoperand i } \fp_eval:n { ! hoperand i } The unary + does nothing, the unary - changes the sign of the hoperandi, and ! hoperandi evaluates to 1 if hoperandi is false and 0 otherwise (this is the not boolean function). Those operations never raise exceptions. ** ^ \fp_eval:n { hoperand1 i ** hoperand2 i } \fp_eval:n { hoperand1 i ^ hoperand2 i } Raises hoperand1 i to the power hoperand2 i. This operation is right associative, hence 2 ** 2 ** 3 equals 2ˆ2ˆ3 = 256. The “invalid operation” exception occurs if hoperand1 i is negative or −0, and hoperand2 i is not an integer, unless the result is zero (in that case, the sign is chosen arbitrarily to be +0). “Division by zero” occurs when raising ±0 to a strictly negative power. “Underflow” and “overflow” occur when appropriate. abs \fp_eval:n { abs( hfpexpr i ) } Computes the absolute value of the hfpexpri. This function does not raise any exception beyond those raised when computing its operand hfpexpri. See also \fp_abs:n. exp \fp_eval:n { exp( hfpexpr i ) } Computes the exponential of the hfpexpri. “Underflow” and “overflow” occur when appropriate. ln \fp_eval:n { ln( hfpexpr i ) } Computes the natural logarithm of the hfpexpri. Negative numbers have no (real) logarithm, hence the “invalid operation” is raised in that case, including for ln(−0). “Division by zero” occurs when evaluating ln(+0) = −∞. “Underflow” and “overflow” occur when appropriate. max min \fp_eval:n { max( hfpexpr1 i , hfpexpr2 i , ... \fp_eval:n { min( hfpexpr1 i , hfpexpr2 i , ... ) } ) } Evalutes each hfpexpri and computes the largest (smallest) of those. If any of the hfpexpri is a nan, the result is nan. Those operations do not raise exceptions. 178 round round0 round+ round- \fp_eval:n { round hoption i ( hfpexpr i ) } \fp_eval:n { round hoption i ( hfpexpr1 i , hfpexpr2 i ) } Rounds hfpexpr1 i to hfpexpr2 i places. When hfpexpr2 i is omitted, it is assumed to be 0, i.e., hfpexpr1 i is rounded to an integer. The hoptioni controls the rounding direction: • by default, the operation rounds to the closest allowed number (rounding ties to even); • with 0, the operation rounds towards 0, i.e., truncates; • with +, the operation rounds towards +∞; • with -, the operation rounds towards −∞. If hfpexpr2 i does not yield an integer less than 108 in absolute value, then an “invalid operation” exception is raised. “Overflow” may occur if the result is infinite (this cannot happen unless hfpexpr2 i < −9984). sin cos tan cot csc sec \fp_eval:n \fp_eval:n \fp_eval:n \fp_eval:n \fp_eval:n \fp_eval:n { { { { { { sin( cos( tan( cot( csc( sec( hfpexpr i hfpexpr i hfpexpr i hfpexpr i hfpexpr i hfpexpr i ) ) ) ) ) ) } } } } } } Computes the sine, cosine, tangent, cotangent, cosecant, or secant of the hfpexpri. The trigonometric functions are undefined for an argument of ±∞, leading to the “invalid operation” exception. Additionally, evaluating tangent, cotangent, cosecant, or secant at one of their poles leads to a “division by zero” exception. “Underflow” and “overflow” occur when appropriate. inf nan pi deg The special values +∞, −∞, and nan are represented as inf, -inf and nan (see \c_inf_fp, \c_minus_inf_fp and \c_nan_fp). The value of π (see \c_pi_fp). The value of 1◦ in radians (see \c_one_degree_fp). 179 em ex in pt pc cm mm dd cc nd nc bp sp Those units of measurement are equal to their values in pt, namely 1in = 72.27pt 1pt = 1pt 1pc = 12pt 1 1cm = in = 28.45275590551181pt 2.54 1 1mm = in = 2.845275590551181pt 25.4 1dd = 0.376065mm = 1.07000856496063pt 1cc = 12dd = 12.84010277952756pt 1nd = 0.375mm = 1.066978346456693pt 1nc = 12nd = 12.80374015748031pt 1 1bp = in = 1.00375pt 72 −16 1sp = 2 pt = 1.52587890625e − 5pt. The values of the (font-dependent) units em and ex are gathered from TEX when the surrounding floating point expression is evaluated. true false \dim_to_fp:n ? New: 2012-05-08 \fp_abs:n ? New: 2012-05-14 Updated: 2012-07-08 \fp_max:nn ? \fp_min:nn ? New: 2012-09-26 Other names for 1 and +0. \dim_to_fp:n {hdimexpr i} Expands to an internal floating point number equal to the value of the hdimexpri in pt. Since dimension expressions are evaluated much faster than their floating point equivalent, \dim_to_fp:n can be used to speed up parts of a computation where a low precision is acceptable. \fp_abs:n {hfloating point expression i} Evaluates the hfloating point expressioni as described for \fp_eval:n and leaves the absolute value of the result in the input stream. This function does not raise any exception beyond those raised when evaluating its argument. Within floating point expressions, abs() can be used. \fp_max:nn {hfp expression 1i} {hfp expression 2i} Evaluates the hfloating point expressionsi as described for \fp_eval:n and leaves the resulting larger (max) or smaller (min) value in the input stream. This function does not raise any exception beyond those raised when evaluating its argument. Within floating point expressions, max() and min() can be used. 180 10 Disclaimer and roadmap The package may break down if: • the escape character is either a digit, or an underscore, • the \uccodes are changed: the test for whether a character is a letter actually tests if the upper-case code of the character is between A and Z. The following need to be done. I’ll try to time-order the items. • Decide what exponent range to consider. • Change the internal representation of fp, by replacing braced groups of 4 digits by delimited arguments. Also consider changing the fp structure a bit to allow using \pdftex_strcmp:D to compare (not in LuaTEX: it is too slow)? • Modulo and remainder, and rounding functions quantize, quantize0, quantize+, quantize-, quantize=, round=. Should the modulo also be provided as (catcode 12) %? • \fp_format:nn {hfpexpri} {hformati}, but what should hformati be? More general pretty printing? • Add and, or, xor? Perhaps under the names all, any, and xor? • Add csc and sec. • Add log(x, b) for logarithm of x in base b. • hypot (Euclidean length) and atan(x, y) = atan(x/y), also called atan2 in other math packages. Cartesian-to-polar transform. Other inverse trigonometric functions acos, asin, atan (one and two arguments). Also asec, acsc? • Hyperbolic functions cosh, sinh, tanh. • Inverse hyperbolics. • Base conversion, input such as 0xAB.CDEF. • Random numbers (pgfmath provides rnd, rand, random), with seed reset at every \fp_set:Nn. • Factorial (not with !), gamma function. • Improve coefficients of the sin and tan series. • Treat upper and lower case letters identically in identifiers, and ignore underscores. • Parse −3 < −2 < −1 as it should, not (−3 < −2) < −1. • Add an array(1,2,3) and i=complex(0,1). 181 • Provide an experimental map function? Perhaps easier to implement if it is a single character, @sin(1,2)? • Provide \fp_if_nan:nTF, and an isnan function? Pgfmath also provides box-measurements (depth, height, width), but boxes are not possible expandably. Bugs. (Exclamation points mark important bugs.) ! Some functions are not monotonic when they should. For instance, sin(1 − 10−16 ) is wrongly greater than sin(1). • Add exceptions to ?:, !<=>?, &&, ||, and !. • round should accept any integer as its second argument. • Logarithms of numbers very close to 1 are inaccurate. • tan and cot give very slightly wrong results for arguments near 10−8 . • When rounding towards −∞, \dim_to_fp:n {0pt} should return −0, not +0. • The result of (±0) + (±0) should depend on the rounding mode. • 0e9999999999 gives a TEX “number too large” error. • Conversion to integers with \fp_to_int:n does not check for overflow. • Subnormals are not implemented. • max(-inf) will lose any information attached to this -inf. • The overflow trap receives the wrong argument in l3fp-expo (see exp(1e5678) in m3fp-traps001). Possible optimizations/improvements. • Optimize argument reduction for trigonometric functions: we don’t need 6×4 digits here, only 4 × 4. • In subsection 9.1, write a grammar. • Fix the TWO BARS business with the index. • It would be nice if the parse auxiliaries for each operation were set up in the corresponding module, rather than centralizing in l3fp-parse. • Some functions should get an _o ending to indicate that they expand after their result. • More care should be given to distinguish expandable/restricted expandable (auxiliary and internal) functions. • The code for the ternary set of functions is ugly. 182 • There are many ~ missing in the doc to avoid bad line-breaks. • The algorithm for computing the logarithm of the significand could be made to use a 5 terms Taylor series instead of 10 terms by taking c = 2000/(b200xc+1) ∈ [10, 95] instead of c ∈ [1, 10]. Also, it would then be possible to simplify the computation of t, using methods similar to \__fp_fixed_div_to_float:ww. However, we would then have to hard-code the logarithms of 44 small integers instead of 9. • Improve notations in the explanations of the division algorithm (l3fp-basics). • Understand and document \__fp_basics_pack_weird_low:NNNNw and \__fp_basics_pack_weird_high:NNNNNNNNw better. Move the other basics_pack auxiliaries to l3fp-aux under a better name. • Find out if underflow can really occur for trigonometric functions, and redoc as appropriate. • Add bibliography. Some of Kahan’s articles, some previous TEX fp packages, the international standards,. . . • Also take into account the “inexact” exception? 183 Part XXII The l3luatex package LuaTeX-specific functions 1 Breaking out to Lua The LuaTEX engine provides access to the Lua programming language, and with it access to the “internals” of TEX. In order to use this within the framework provided here, a family of functions is available. When used with pdfTEX or XETEX these will raise an error: use \luatex_if_engine:T to avoid this. Details of coding the LuaTEX engine are detailed in the LuaTEX manual. \lua_now:n \lua_now:x ? ? Updated: 2012-08-02 \lua_now_x:n ? \lua_now_x:x ? New: 2012-08-02 \lua_now:n {htoken list i} The htoken listi is first tokenized by TEX, which will include converting line ends to spaces in the usual TEX manner and which respects currently-applicable TEX category codes. The resulting hLua inputi is passed to the Lua interpreter for processing. Each \lua_now:n block is treated by Lua as a separate chunk. The Lua interpreter will execute the hLua inputi immediately, and in an expandable manner. \lua_now_x:n {htoken list i} The htoken listi is first tokenized and expanded by TEX, which will include converting line ends to spaces in the usual TEX manner and which respects currently-applicable TEX category codes. The resulting hLua inputi is passed to the Lua interpreter for processing. Each \lua_now_x:n block is treated by Lua as a separate chunk. The Lua interpreter will execute the hLua inputi immediately, and in an expandable manner. TEXhackers note: \lua_now_x:n is the LuaTEX primitive \directlua renamed. \lua_shipout:n \lua_shipout:x \lua_shipout:n {htoken list i} The htoken listi is first tokenized by TEX, which will include converting line ends to spaces in the usual TEX manner and which respects currently-applicable TEX category codes. The resulting hLua inputi is passed to the Lua interpreter when the current page is finalised (i.e. at shipout). Each \lua_shipout:n block is treated by Lua as a separate chunk. The Lua interpreter will execute the hLua inputi during the page-building routine: no TEX expansion of the hLua inputi will occur at this stage. TEXhackers note: At a TEX level, the hLua inputi is stored as a “whatsit”. 184 \lua_shipout_x:n \lua_shipout_x:x \lua_shipout:n {htoken list i} The htoken listi is first tokenized by TEX, which will include converting line ends to spaces in the usual TEX manner and which respects currently-applicable TEX category codes. The resulting hLua inputi is passed to the Lua interpreter when the current page is finalised (i.e. at shipout). Each \lua_shipout:n block is treated by Lua as a separate chunk. The Lua interpreter will execute the hLua inputi during the page-building routine: the hLua inputi is expanded during this process in addition to any expansion when the argument was read. This makes these functions suitable for including material finalised during the page building process (such as the page number). TEXhackers note: \lua_shipout_x:n is the LuaTEX primitive \latelua named using the LATEX3 scheme. At a TEX level, the hLua inputi is stored as a “whatsit”. 2 Category code tables As well as providing methods to break out into Lua, there are places where additional LATEX3 functions are provided by the LuaTEX engine. In particular, LuaTEX provides category code tables. These can be used to ensure that a set of category codes are in force in a more robust way than is possible with other engines. These are therefore used by \ExplSyntaxOn and ExplSyntaxOff when using the LuaTEX engine. \cctab_new:N \cctab_new:N hcategory code table i Creates a new category code table, initially with the codes as used by iniTEX. \cctab_gset:Nn \cctab_gset:Nn hcategory code table i {hcategory code set up i} Sets the hcategory code tablei to apply the category codes which apply when the prevailing régime is modified by the hcategory code set upi. Thus within a standard code block the starting point will be the code applied by \c_code_cctab. The assignment of the table is global: the underlying primitive does not respect grouping. \cctab_begin:N \cctab_begin:N hcategory code table i Switches the category codes in force to those stored in the hcategory code tablei. The prevailing codes before the function is called are added to a stack, for use with \cctab_end:. \cctab_end: \cctab_end: Ends the scope of a hcategory code tablei started using \cctab_begin:N, retuning the codes to those in force before the matching \cctab_begin:N was used. \c_code_cctab Category code table for the code environment. This does not include setting the behaviour of the line-end character, which is only altered by \ExplSyntaxOn. 185 \c_document_cctab \c_initex_cctab \c_other_cctab \c_str_cctab Category code table for a standard LATEX document. This does not include setting the behaviour of the line-end character, which is only altered by \ExplSyntaxOff. Category code table as set up by iniTEX. Category code table where all characters have category code 12 (other). Category code table where all characters have category code 12 (other) with the exception of spaces, which have category code 10 (space). 186 Part XXIII The l3candidates package Experimental additions to l3kernel This module provides a space in which functions can be added to l3kernel (expl3) while still being experimental. As such, the functions here may not remain in their current form, or indeed at all, in l3kernel in the future. In contrast to the material in l3experimental, the functions here are all small additions to the kernel. We encourage programmers to test them out and report back on the LaTeX-L mailing list. 1 \cs_if_exist_use:NTF ? \cs_if_exist_use:cTF ? Additions to l3basics \cs_if_exist_use:NTF hcontrol sequence i {htrue code i} {hfalse code i} If the hcontrol sequencei exists, leave it in the input stream, followed by the htrue codei (unbraced). Otherwise, leave the hfalsei code in the input stream. For example, \cs_set:Npn \mypkg_use_character:N #1 { \cs_if_exist_use:cF { mypkg_#1:n } { \mypkg_default:N #1 } } calls the function \mypkg_#1:n if it exists, and falls back to a default action otherwise. This could also be done (more slowly) using \str_case_x:nnn. TEXhackers note: The c variants do not introduce the hcontrol sequencei in the hash table if it is not there. 2 2.1 Additions to l3box Affine transformations Affine transformations are changes which (informally) preserve straight lines. Simple translations are affine transformations, but are better handled in TEX by doing the translation first, then inserting an unmodified box. On the other hand, rotation and resizing of boxed material can best be handled by modifying boxes. These transformations are described here. \box_resize:Nnn \box_resize:cnn \box_resize:Nnn hbox i {hx-size i} {hy-size i} Resize the hboxi to hx-sizei horizontally and hy-sizei vertically (both of the sizes are dimension expressions). The hy-sizei is the vertical size (height plus depth) of the box. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the resizing is applied. Negative sizes will cause the material in the hboxi to be reversed in direction, but the reference point of the hboxi will be unchanged. The resizing applies within the current TEX group level. 187 \box_resize_to_ht_plus_dp:Nn \box_resize_to_ht_plus_dp:cn \box_resize_to_ht_plus_dp:Nn hbox i {hy-size i} Resize the hboxi to hy-sizei vertically, scaling the horizontal size by the same amount (hy-sizei is a dimension expression). The hy-sizei is the vertical size (height plus depth) of the box. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the resizing is applied. A negative size will cause the material in the hboxi to be reversed in direction, but the reference point of the hboxi will be unchanged. The resizing applies within the current TEX group level. \box_resize_to_wd:Nn \box_resize_to_wd:cn \box_rotate:Nn \box_rotate:cn \box_scale:Nnn \box_scale:cnn \box_resize_to_wd:Nn hbox i {hx-size i} Resize the hboxi to hx-sizei horizontally, scaling the vertical size by the same amount (hx-sizei is a dimension expression). The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the resizing is applied. A negative size will cause the material in the hboxi to be reversed in direction, but the reference point of the hboxi will be unchanged. The resizing applies within the current TEX group level. \box_rotate:Nn hbox i {hangle i} Rotates the hboxi by hanglei (in degrees) anti-clockwise about its reference point. The reference point of the updated box will be moved horizontally such that it is at the left side of the smallest rectangle enclosing the rotated material. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the rotation is applied. The rotation applies within the current TEX group level. \box_scale:Nnn hbox i {hx-scale i} {hy-scale i} Scales the hboxi by factors hx-scalei and hy-scalei in the horizontal and vertical directions, respectively (both scales are integer expressions). The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the scaling is applied. Negative scalings will cause the material in the hboxi to be reversed in direction, but the reference point of the hboxi will be unchanged. The scaling applies within the current TEX group level. 2.2 \box_clip:N \box_clip:c Viewing part of a box \box_clip:N hbox i Clips the hboxi in the output so that only material inside the bounding box is displayed in the output. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the clipping is applied. The clipping applies within the current TEX group level. These functions require the LATEX3 native drivers: they will not work with the LATEX 2ε graphics drivers! TEXhackers note: Clipping is implemented by the driver, and as such the full content of the box is places in the output file. Thus clipping does not remove any information from the raw output, and hidden material can therefore be viewed by direct examination of the file. 188 \box_trim:Nnnnn \box_trim:cnnnn \box_viewport:Nnnnn \box_viewport:cnnnn \box_trim:Nnnnn hbox i {hleft i} {hbottom i} {hright i} {htop i} Adjusts the bounding box of the hboxi hlefti is removed from the left-hand edge of the bounding box, hrighti from the right-hand edge and so fourth. All adjustments are hdimension expressionsi. Material output of the bounding box will still be displayed in the output unless \box_clip:N is subsequently applied. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the trim operation is applied. The adjustment applies within the current TEX group level. The behavior of the operation where the trims requested is greater than the size of the box is undefined. \box_viewport:Nnnnn hbox i {hllx i} {hlly i} {hurx i} {hury i} Adjusts the bounding box of the hboxi such that it has lower-left co-ordinates (hllxi, hllyi) and upper-right co-ordinates (hurxi, huryi). All four co-ordinate positions are hdimension expressionsi. Material output of the bounding box will still be displayed in the output unless \box_clip:N is subsequently applied. The updated hboxi will be an hbox, irrespective of the nature of the hboxi before the viewport operation is applied. The adjustment applies within the current TEX group level. 2.3 Internal variables \l__box_angle_fp The angle through which a box is rotated by \box_rotate:Nn, given in degrees counterclockwise. This value is required by the underlying driver code in l3driver to carry out the driver-dependent part of box rotation. \l__box_cos_fp \l__box_sin_fp The sine and cosine of the angle through which a box is rotated by \box_rotate:Nn: the values refer to the angle counter-clockwise. These values are required by the underlying driver code in l3driver to carry out the driver-dependent part of box rotation. \l__box_scale_x_fp \l__box_scale_y_fp The scaling factors by which a box is scaled by \box_scale:Nnn or \box_resize:Nnn. These values are required by the underlying driver code in l3driver to carry out the driver-dependent part of box rotation. \l__box_internal_box Box used for affine transformations, which is used to contain rotated material when applying \box_rotate:Nn. This box must be correctly constructed for the driver-dependent code in l3driver to function correctly. 189 indexing occurs from the bottom (right) of the comma list. hence the comma list {~. If the hinteger expressioni is negative.} (without outer braces) contains one element.{}. while {~.~} (without outer braces) is empty. this function will evaluate the hinteger expressioni and leave the appropriate item from the comma list in the input stream. Items which contain either spaces or commas are surrounded by braces. The rules for space trimming are as for other n-type comma-list functions. Tests if the hcomma listi is empty (containing no items). When the hinteger expressioni is larger than the number of items in the hcomma listi (as calculated by \clist_count:N) then the function will expand to nothing. \clist_const:Nn \clist_const:(Nx|cn|cx) \clist_const:Nn hclist var i {hcomma list i} \clist_if_empty_p:n ? \clist_if_empty:nTF ? \clist_if_empty_p:n {hcomma list i} \clist_if_empty:nTF {hcomma list i} {htrue code i} {hfalse code i} Creates a new constant hclist vari or raises an error if the name is already taken.~. 190 .. TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). The value of the hclist vari will be set globally to the hcomma listi. which happens to be empty: the comma-list is not empty.3 \clist_item:Nn \clist_item:(cn|nn) Additions to l3clist \clist_item:Nn hcomma list i {hinteger expression i} Indexing items in the hcomma listi from 1 at the top (left). which means that the hitemi will not expand further when appearing in an x-type argument expansion. \clist_set_from_seq:NN \clist_set_from_seq:(cN|Nc|cc) \clist_gset_from_seq:NN \clist_gset_from_seq:(cN|Nc|cc) \clist_set_from_seq:NN hcomma list i hsequence i Sets the hcomma listi to be equal to the content of the hsequencei. For example. Multiple rotations will not result in the bounding box of the coffin growing unnecessarily. \coffin_rotate:Nn \coffin_rotate:cn \coffin_rotate:Nn hcoffin i {hangle i} \coffin_scale:Nnn \coffin_scale:cnn \coffin_scale:Nnn hcoffin i {hx-scale i} {hy-scale i} Rotates the hcoffini by the given hanglei (given in degrees counter-clockwise).~and~ } will insert “a.\clist_use:Nnnn ? New: 2012-06-26 \clist_use:Nnnn hclist var i {hseparator between two i} {hseparator between more than two i} {hseparator between final two i} Places the contents of the hclist vari in the input stream. The first separator argument is not used in this case because the comma list has more than 2 items. b. b . An error will be raised if the variable does not exist or if it is invalid. de. The two scale factors should be given as real numbers. it is placed in the input stream. If the comma list has 2 items. the hseparator between more than twoi is placed between each pair of items except the last. if the comma list has more than 2 items. Scales the hcoffini by a factors hx-scalei and hy-scalei in the horizontal and vertical directions. respectively. If the comma list has 1 item. c. 191 . TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). {de} . c . both of which should be given as dimension expressions. with the appropriate hseparatori between the items. 4 \coffin_resize:Nnn \coffin_resize:cnn Additions to l3coffins \coffin_resize:Nnn hcoffin i {hwidth i} {htotal-height i} Resized the hcoffini to hwidthi and htotal-heighti. f } \clist_use:Nnnn \l_tmpa_clist { ~and~ } { . \clist_set:Nn \l_tmpa_clist { a . then they are placed in the input stream separated by the hseparator between twoi. .~ } { . This process will rotate both the coffin content and poles. for which the hseparator between final twoi is used. and a comma list with no items produces no output. which means that the hitemsi will not expand further when appearing in an x-type argument expansion. Namely. and f” in the input stream. scenario will lead to low level TEX errors.. This will normally take place within a conditional statement. \ior_map_break: Used to terminate a \ior_map_.. Note that TEX removes trailing space and tab characters (character codes 32 and 9) from every line upon input. The hinline functioni should consist of code which will receive the hlinei as #1. Note that TEX removes trailing space and tab characters (character codes 32 and 9) from every line upon input. with the exception of space characters which are given category code 10 (space). The material is read from the hstreami as a series of tokens with category code 12 (other). TEXhackers note: When the mapping is broken.. This will depend on the design of the mapping function.. \ior_str_map_inline:Nn {hstream i} {hinline function i} Applies the hinline functioni to every hlinei in the hstreami. function before all lines from the hstreami have been processed. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before further items are taken from the input stream. 192 .5 \ior_map_inline:Nn New: 2012-02-11 \ior_str_map_inline:Nn New: 2012-02-11 \ior_map_break: New: 2012-06-29 Additions to l3file \ior_map_inline:Nn hstream i {hinline function i} Applies the hinline functioni to hlinesi obtained by reading one or more lines (until an equal number of left and right braces are found) from the hstreami. for example \ior_map_inline:Nn \l_my_ior { \str_if_eq:nnTF { #1 } { bingo } { \ior_map_break: } { % Do something useful } } Use outside of a \ior_map_. The hinline functioni should consist of code which will receive the hlinei as #1. TEX also ignores any trailing new-line marker from the file it reads. TEX also ignores any trailing new-line marker from the file it reads. TEXhackers note: When the mapping is broken.. scenario will lead to low level TEX errors... The hcodei receives each key–value pair in the hproperty listi as two trailing brace groups. the hkeyi and the hvaluei as its three arguments. This will normally take place within a conditional statement.. For that specific task. \prop_map_tokens:Nn \l_my_prop { \str_if_eq:nnT { mykey } } will expand to the value corresponding to mykey: for each pair in \l_my_prop the function \str_if_eq:nnT receives mykey. inserting the htokensi after the mapping has ended.\ior_map_break:n New: 2012-06-29 \ior_map_break:n {htokens i} Used to terminate a \ior_map_. 6 \fp_set_from_dim:Nn \fp_set_from_dim:cn \fp_gset_from_dim:Nn \fp_gset_from_dim:cn \fp_set_from_dim:Nn hfloating point variable i {hdimexpr i} Sets the hfloating point variablei to the distance represented by the hdimension expressioni in the units points. This means that distances given in other units are first converted to points before being assigned to the hfloating point variablei. 7 \prop_map_tokens:Nn I \prop_map_tokens:cn I Additions to l3fp Additions to l3prop \prop_map_tokens:Nn hproperty list i {hcode i} Analogue of \prop_map_function:NN which maps several tokens instead of a single function. \prop_get:Nn is faster. For instance. additional tokens may be inserted by the internal macro \__prg_break_point:Nn before the htokensi are inserted into the input stream. 193 . for example \ior_map_inline:Nn \l_my_ior { \str_if_eq:nnTF { #1 } { bingo } { \ior_map_break:n { <tokens> } } { % Do something useful } } Use outside of a \ior_map_. This will depend on the design of the mapping function. function before all lines in the hstreami have been processed. If the hkeyi is missing. which means that the hitemi will not expand further when appearing in an x-type argument expansion. The result is returned within the \unexpanded primitive (\exp_not:n). returning items from both sequences from left to right. whichever sequence has fewer items determines how many iterations occur). 8 \seq_item:Nn ? \seq_item:cn ? Additions to l3seq \seq_item:Nn hsequence i {hinteger expression i} Indexing items in the hsequencei from 1 at the top (left). \seq_reverse:N \seq_greverse:N \seq_reverse:N hsequence i Reverses the order of items in the hsequencei. When the hinteger expressioni is larger than the number of items in the hsequencei (as calculated by \seq_count:N) then the function will expand to nothing. \seq_set_from_clist:NN \seq_set_from_clist:(cN|Nc|cc|Nn|cn) \seq_gset_from_clist:NN \seq_gset_from_clist:(cN|Nc|cc|Nn|cn) \seq_set_from_clist:NN hsequence i hcomma-list i Sets the hsequencei within the current TEX group to be equal to the content of the hcomma-listi. and assigns the result to hsequencei.\prop_get:Nn ? \prop_get:cn ? \prop_get:Nn hproperty list i {hkey i} Expands to the hvaluei corresponding to the hkeyi in the hproperty listi. this function will evaluate the hinteger expressioni and leave the appropriate item from the sequence in the input stream. 194 .e. this has an empty expansion. TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). TEXhackers note: This function is slower than the non-expandable analogue \prop_get:NnN. \seq_mapthread_function:NNN I \seq_mapthread_function:(NcN|cNN|ccN) I \seq_mapthread_function:NNN hseq1 i hseq2 i hfunction i Applies hfunctioni to every pair of items hseq1 -itemi–hseq2 -itemi from the two sequences. If the hinteger expressioni is negative. locally or globally according to the variant chosen. The hfunctioni will receive two n-type arguments for each iteration. which means that the hvaluei will not expand further when appearing in an x-type argument expansion. The mapping will terminate when the end of either sequence is reached (i. indexing occurs from the bottom (right) of the sequence. and will lead to low-level TEX errors. For example. \seq_map_break: cannot be used in this function. The first separator argument is not used in this case because the sequence has more than 2 items. If the sequence has 1 item.\seq_set_filter:NNn \seq_gset_filter:NNn \seq_set_filter:NNn hsequence1 i hsequence2 i {hinline boolexpr i} Evaluates the hinline boolexpri for every hitemi stored within the hsequence2 i. it is placed in the input stream. TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). If the sequence has 2 items. which means that the hitemsi will not expand further when appearing in an x-type argument expansion. Namely. The hinline boolexpri will receive the hitemi as #1.~and~ } will insert “a. with the appropriate hseparatori between the items. \seq_set_map:NNn \seq_gset_map:NNn New: 2011-12-22 \seq_set_map:NNn hsequence1 i hsequence2 i {hinline function i} Applies hinline functioni to every hitemi stored within the hsequence2 i. the code in hinline functioni should be expandable. \seq_map_break: cannot be used in this function. if the sequence has more than 2 items. TEXhackers note: Contrarily to other mapping functions. and f” in the input stream. As such. and an empty sequence produces no output. \seq_set_split:Nnn \l_tmpa_seq { | } { a | b | c | {de} | f } \seq_use:Nnnn \l_tmpa_seq { ~and~ } { .~ } { . b. for which the hseparator between final twoi is used. \seq_use:Nnnn ? New: 2012-06-26 \seq_use:Nnnn hseq var i {hseparator between two i} {hseparator between more than two i} {hseparator between final two i} Places the contents of the hseq vari in the input stream. An error will be raised if the variable does not exist or if it is invalid. TEXhackers note: Contrarily to other mapping functions. de. The sequence of all hitemsi for which the hinline boolexpri evaluated to true is assigned to hsequence1 i. c. The sequence resulting from x-expanding hinline functioni applied to each hitemi is assigned to hsequence1 i. The hinline functioni should consist of code which will receive the hitemi as #1. then they are placed in the input stream separated by the hseparator between twoi. the hseparator between more than twoi is placed between each pair of items except the last. and will lead to low-level TEX errors. 195 . but the braces themselves are not exchanged. i. If it does then it assigns hdimen1 i the stretch component and hdimen2 i the shrink component. 196 . contributes one to the total.e. Token groups ({. which works directly on TEX tokens. is either a single space character or a single “normal” token. \tl_reverse_tokens:n {a~{b()}} leaves {)(b}~a in the input stream. }) are not single tokens. reverses the order of the htokensi: the first will be the last and the last will become first. Every token. giving an hinteger denotationi. For instance. as this would lead to an unbalanced token list. If it contains infinite glue set hdimen1 i and hdimen2 i to 0 pt and place #2 into the input stream: this is usually an error or warning message of some sort. the token count of a~{bc} is 6. including spaces and braces. \tl_count_tokens:n ? \tl_count_tokens:n {htokens i} Counts the number of TEX tokens in the htokensi and leaves this information in the input stream. thus for instance. 10 \tl_if_single_token_p:n ? \tl_if_single_token:nTF ? Additions to l3tl \tl_if_single_token_p:n {htoken list i} \tl_if_single_token:nTF {htoken list i} {htrue code i} {hfalse code i} Tests if the token list consists of exactly one token. The reversal also operates within brace groups. Spaces are preserved. This function requires three expansions. TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). . which means that the token list will not expand further when appearing in an x-type argument expansion. This function requires two steps of expansion. . \tl_reverse_tokens:n ? \tl_reverse_tokens:n {htokens i} This function.9 Additions to l3skip \skip_split_finite_else_action:nnNN \skip_split_finite_else_action:nnNN {hskipexpr i} {haction i} hdimen1 i hdimen2 i Checks if the hskipexpri contains finite glue. 197 .\tl_expandable_uppercase:n ? \tl_expandable_lowercase:n ? \tl_expandable_uppercase:n {htokens i} \tl_expandable_lowercase:n {htokens i} The \tl_expandable_uppercase:n function works through all of the htokensi. The hchari is made active within the current TEX group level.) will be replaced by those absorbed. but the definition is global. which means that the hitemi will not expand further when appearing in an x-type argument expansion. The hchari is made active within the current TEX group level. TEXhackers note: The result is returned within the \unexpanded primitive (\exp_not:n). The hchari is made active within the current TEX group level. Within the hcodei. #2. starting at −1 for the right-most item. \char_gset_active:Npn hchar i hparameters i {hcode i} Makes hchari an active character to expand to hcodei as replacement text. The result is returned within the \unexpanded primitive (\exp_not:n). This function requires two steps of expansion. etc. then thr function expands to nothing. and leaves other tokens unchanged. If the index is out of bounds. \tl_expandable_lowercase:n replaces characters in the range A–Z by letters in the range a–z. \char_set_active_eq:NN hchar i hfunction i Makes hchari an active character equivalent in meaning to the hfunctioni (which may itself be an active character).) will be replaced by those absorbed. indexing occurs from the right of the token list. and the definition is also local. \tl_item:nn ? \tl_item:(Nn|cn) ? \tl_item:nn {htoken list i} {hinteger expression i} Indexing items in the htoken listi from 1 on the left. This function is therefore suited to cases where an active character definition should be applied only in some context (where the hchari is again made active). TEXhackers note: Begin-group and end-group characters are normalized and become { and }. Within the hcodei. which means that the token list will not expand further when appearing in an x-type argument expansion. 11 \char_set_active:Npn \char_set_active:Npx \char_gset_active:Npn \char_gset_active:Npx \char_set_active_eq:NN Additions to l3tokens \char_set_active:Npn hchar i hparameters i {hcode i} Makes hchari an active character to expand to hcodei as replacement text. respectively. If the hinteger expressioni is negative. with category code 11 (letter). etc. replacing characters in the range a–z (with arbitrary category code) by the corresponding letter in the range A–Z. the hparametersi (#1. and the definition is also local. Similarly. #2. this function will evaluate the hinteger expressioni and leave the appropriate item from the htoken listi in the input stream. the hparametersi (#1. The htokeni will be left in the input stream after the htrue codei or hfalse codei (as appropriate to the result of the test). the test will take the hfalsei branch. or an outer token (never used in LATEX3) and htruei in all other cases. so do it the old-fashioned way. 9 10 11 h*initexi \catcode ‘\^^I = 10 \relax h/initexi For LuaTEX the extra primitives need to be enabled before they can be used. The test will be hfalsei if the next htokeni is either an explicit or implicit begin-group or end-group token (with any character code).1 h*initex | packagei h@@=expli Format-specific code The very first thing to do is to bootstrap the iniTEX system so that everything else will actually work. but the definition is global. even though the next htokeni is in fact a valid N-type argument. However. or an explicit or implicit space character (with character code 32 and category code 10). The primitive \strcmp is simulated using some Lua code. but to be on the safe side. This function is therefore suited to cases where an active character definition should be applied only in some context (where the hchari is again made active). The hchari is made active within the current TEX group level. if the next htokeni is for instance \c_space_token. Note that a htruei result ensures that the next htokeni is a valid N-type argument. 3 4 5 6 7 8 h*initexi \catcode \catcode \catcode \catcode h/initexi ‘\{ ‘\} ‘\# ‘\^ = = = = 1 2 6 7 \relax \relax \relax \relax Tab characters should not show up in the code.\char_gset_active_eq:NN \char_gset_active_eq:NN hchar i hfunction i Makes hchari an active character equivalent in meaning to the hfunctioni (which may itself be an active character). \peek_N_type:TF Updated: 2012-12-20 \peek_N_type:TF {htrue code i} {hfalse code i} Tests if the next htokeni in the input stream can be safely grabbed as an N-type argument. TEX does not start with some pretty basic character codes set up. which currently has to be applied to every job as the Lua code is not 198 . Part XXIV Implementation l3bootstrap implementation 1 1 2 1. No \ifdefined yet. Thanks to Taco Hoekwater for this code.2 h*initexi \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname directlua\endcsname\relax \else \directlua { tex. 47 48 49 50 51 52 53 h*packagei \ProvidesPackage{l3bootstrap} [% \ExplFileDate\space v\ExplFileVersion\space L3 Experimental bootstrap code% ] h/packagei 199 .extraprimitives ()) lua.% "\noexpand\luaescapestring{#2}"% )% }% } \fi h/initexi Package-specific code part one The package starts by identifying itself: the information itself is taken from the SVN Id string at the start of the source file.enableprimitives(’’.write("1") end end end lua.part of the format. B) if A == B then tex.write("-1") else tex.tex.bytecode[1] = function () function strcmp (A. The odd \csname business is needed so that the later deletion code will work.bytecode[1]()}} \long\edef\pdfstrcmp#1#2% {% \expandafter\noexpand\csname\detokenize{luatex_directlua:D}\endcsname {% strcmp% (% "\noexpand\luaescapestring{#1}". 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 1.write("0") elseif A < B then tex.bytecode[1]() } \everyjob\expandafter {\csname\detokenize{luatex_directlua:D}\endcsname{lua. XeTeX 0. load Heiko Oberdiek’s luatex package instead. 54 55 56 57 58 59 60 61 62 63 64 65 66 67 1. so there is some shuffling to do. there is also a need to deal with some low-level allocation stuff that could usefully be added to lualatex. 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname pdfstrcmp\endcsname\relax h*packagei \PackageError{expl3}{Required primitives not found} {% LaTeX3 requires the e-TeX primitives and \string\pdfstrcmp. The XETEX version is just \strcmp. 68 69 70 71 1.\MessageBreak \MessageBreak These are available in engine versions:\MessageBreak . At present. As it is currently not.\MessageBreak \MessageBreak Loading of expl3 will abort!% } \expandafter\endinput 200 .30\MessageBreak .LuaTeX 0.40\MessageBreak or later.4 \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname pdfstrcmp\endcsname\relax \let\pdfstrcmp\strcmp \fi Engine requirements The code currently requires functionality equivalent to \pdfstrcmp in addition to ε-TEX.pdfTeX 1. The former is therefore used as a test for a suitable engine.ini.For LuaTEX the functionality of the \pdfstrcmp primitive needs to be provided: the pdftexmcds package is used to do this if necessary.3 h*packagei \def\@tempa% {% \def\@tempa{}% \RequirePackage{luatex}% \RequirePackage{pdftexcmds}% \let\pdfstrcmp\pdf@strcmp } \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname directlua\endcsname\relax \else \expandafter\@tempa \fi h/packagei The \pdfstrcmp primitive in XETEX Only pdfTEX has a primitive called \pdfstrcmp.9994\MessageBreak . ^^J% ^^J% Format building will abort!% } \errmessage{Required primitives not found}% \expandafter\end h/initexi \fi Package-specific code part two Experimental syntax switching is set up here for the package-loading process.5 \ExplSyntaxOff \ExplSyntaxOn h/packagei h*initexi \newlinechar‘\^^J\relax \errhelp{% LaTeX3 requires the e-TeX primitives and \pdfstrcmp. These are redefined in expl3 for the package and in l3final for the format.88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 1.LuaTeX 0.40^^J% or later.^^J% ^^J% These are available in engine versions:^^J% .30^^J% .^^J% ^^J% For pdfTeX and XeTeX the ’-etex’ command-line switch is also needed.pdfTeX 1. 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 h*packagei \protected\edef\ExplSyntaxOff {% \catcode 9 = \the\catcode 9\relax \catcode 32 = \the\catcode 32\relax \catcode 34 = \the\catcode 34\relax \catcode 38 = \the\catcode 38\relax \catcode 58 = \the\catcode 58\relax \catcode 94 = \the\catcode 94\relax \catcode 95 = \the\catcode 95\relax \catcode 124 = \the\catcode 124\relax \catcode 126 = \the\catcode 126\relax \endlinechar = \the\endlinechar\relax \chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 0 \relax } \protected\edef\ExplSyntaxOn { \catcode 9 = 9 \relax \catcode 32 = 9 \relax \catcode 34 = 12 \relax \catcode 58 = 11 \relax \catcode 94 = 7 \relax \catcode 95 = 11 \relax 201 .9994^^J% .XeTeX 0. % }% }% \protected\def\ProvidesExplPackage##1##2##3##4% {% \ProvidesPackage{##1}[##2 v##3 ##4]% \ExplSyntaxOn }% \ProvidesExplPackage } \protected\def\ProvidesExplClass#1#2#3#4% {% \ProvidesClass{#1}[#2 v#3 #4]% \ExplSyntaxOn } \protected\def\ProvidesExplFile#1#2#3#4% {% \ProvidesFile{#1}[#2 v#3 #4]% \ExplSyntaxOn 202 .) \l__kernel_expl_bool The status for experimental code syntax: this is off at present.\MessageBreak please \string\usepackage\string{expl3\string} instead.dtx. This variable is documented on page 7.) 1. These functions are documented on page 6. This function is documented on page 6. This code is used by both the package and the format. 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 h*packagei \protected\def\ProvidesExplPackage {% \@ifpackageloaded{expl3} {} {% \PackageError{expl3} {Cannot load the expl3 modules separately} {% The expl3 modules cannot be loaded separately.) \ProvidesExplPackage \ProvidesExplClass \ProvidesExplFile For other packages and classes building on this one it is convenient not to need \ExplSyntaxOn each time.6 \GetIdInfo Dealing with package-mode meta-data This is implemented right at the start of l3bootstrap. 138 \expandafter\chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 0 \relax (End definition for \l__kernel_expl_bool. (End definition for \GetIdInfo.132 133 134 135 136 137 \catcode 124 = 12 \relax \catcode 126 = 10 \relax \endlinechar = 32 \relax \chardef\csname\detokenize{l__kernel_expl_bool}\endcsname = 1 \relax } h/packagei (End definition for \ExplSyntaxOff and \ExplSyntaxOn. This can be achieved by saving the current status flag at each push to a stack.) \l__expl_status_stack_tl As expl3 itself cannot be loaded with the code environment already active. These functions are documented on page 6. 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 h*packagei \edef\@pushfilename {% \edef\expandafter\noexpand \csname\detokenize{l__expl_status_stack_tl}\endcsname {% \noexpand\ifodd\expandafter\noexpand \csname\detokenize{l__kernel_expl_bool}\endcsname 1% \noexpand\else 0% \noexpand\fi \expandafter\noexpand \csname\detokenize{l__expl_status_stack_tl}\endcsname }% \ExplSyntaxOff \unexpanded\expandafter{\@pushfilename}% } \edef\@popfilename {% \unexpanded\expandafter{\@popfilename}% \noexpand\if a\expandafter\noexpand\csname \detokenize{l__expl_status_stack_tl}\endcsname a% \ExplSyntaxOff \noexpand\else \noexpand\expandafter \expandafter\noexpand\csname \detokenize{__expl_status_pop:w}\endcsname \expandafter\noexpand\csname \detokenize{l__expl_status_stack_tl}\endcsname \noexpand\@nil \noexpand\fi } h/packagei (End definition for \@pushfilename and \@popfilename. at the end of the package \ExplSyntaxOff can safely be called. These functions are documented on page ??. \ProvidesExplClass .) \@pushfilename \@popfilename The idea here is to use LATEX 2ε ’s \@pushfilename and \@popfilename to track the current syntax status. and \ProvidesExplFile. then recovering it at the pop stage and checking if the code environment should still be active. 204 205 h*packagei \@namedef{\detokenize{l__expl_status_stack_tl}}{0} 203 .168 169 } h/packagei (End definition for \ProvidesExplPackage . ) 1. 235 236 237 238 h*initexi \catcode 9 \catcode 32 \catcode 34 = 9 \relax = 9 \relax = 12 \relax 204 . there is no need for \noexpand here.% }% }% } h/packagei (End definition for \__expl_package_check:.) \__expl_status_pop:w The pop auxiliary function removes the first item from the stack.206 h/packagei (End definition for \l__expl_status_stack_tl. 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 h*packagei \expandafter\protected\expandafter\def \csname\detokenize{__expl_package_check:}\endcsname {% \@ifpackageloaded{expl3} {} {% \PackageError{expl3} {Cannot load the expl3 modules separately} {% The expl3 modules cannot be loaded separately. This function is documented on page ??. 207 208 209 210 211 212 213 214 215 216 217 218 h*packagei \expandafter\edef\csname\detokenize{__expl_status_pop:w}\endcsname#1#2\@nil {% \def\expandafter\noexpand \csname\detokenize{l__expl_status_stack_tl}\endcsname{#2}% \noexpand\ifodd#1\space \noexpand\expandafter\noexpand\ExplSyntaxOn \noexpand\else \noexpand\expandafter\ExplSyntaxOff \noexpand\fi } h/packagei (End definition for \__expl_status_pop:w.\MessageBreak please \string\usepackage\string{expl3\string} instead. this command is used to ensure that one of the l3 packages isn’t loaded on its own. As \ExplSyntaxOff is already defined as a protected macro. saves the rest of the stack and then does the test.7 The LATEX3 code environment The code environment is now set up for the format: the package deals with this using \ProvidesExplPackage.) \__expl_package_check: We want the expl3 bundle to be loaded “as one”. ) \l__kernel_expl_bool A flag to show the current syntax status. 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 h*initexi \protected \def \ExplSyntaxOn { \bool_if:NF \l__kernel_expl_bool { \cs_set_protected_nopar:Npx \ExplSyntaxOff { \char_set_catcode:nn { 9 } { \char_value_catcode:n \char_set_catcode:nn { 32 } { \char_value_catcode:n \char_set_catcode:nn { 34 } { \char_value_catcode:n \char_set_catcode:nn { 38 } { \char_value_catcode:n \char_set_catcode:nn { 58 } { \char_value_catcode:n \char_set_catcode:nn { 94 } { \char_value_catcode:n \char_set_catcode:nn { 95 } { \char_value_catcode:n \char_set_catcode:nn { 124 } { \char_value_catcode:n \char_set_catcode:nn { 126 } { \char_value_catcode:n \tex_endlinechar:D = \tex_the:D \tex_endlinechar:D \scan_stop: \bool_set_false:N \l__kernel_expl_bool \cs_set_protected_nopar:Npn \ExplSyntaxOff { } } } \char_set_catcode_ignore:n { 9 } % tab \char_set_catcode_ignore:n { 32 } % space \char_set_catcode_other:n { 34 } % double quote \char_set_catcode_alignment:n { 38 } % ampersand \char_set_catcode_letter:n { 58 } % colon \char_set_catcode_math_superscript:n { 94 } % circumflex \char_set_catcode_letter:n { 95 } % underscore \char_set_catcode_other:n { 124 } % pipe \char_set_catcode_space:n { 126 } % tilde \tex_endlinechar:D = 32 \scan_stop: \bool_set_true:N \l__kernel_expl_bool } \protected \def \ExplSyntaxOff { } h/initexi { { { { { { { { { 9 } } 32 } } 34 } } 38 } } 58 } } 94 } } 95 } } 124 } } 126 } } (End definition for \ExplSyntaxOn and \ExplSyntaxOff. These functions are documented on page 6. 205 .239 240 241 242 243 244 245 \ExplSyntaxOn \ExplSyntaxOff \catcode 58 \catcode 94 \catcode 95 \catcode 124 \catcode 126 \endlinechar h/initexi = = = = = = 11 7 11 12 10 32 \relax \relax \relax \relax \relax \relax The idea here is that multiple \ExplSyntaxOn calls are not going to mess up category codes. and that multiple calls to \ExplSyntaxOff are also not wasting time. This variable is documented on page 7. This function is documented on page ??. 206 . as that way we avoid leaving an unneeded csname in the hash table. (End definition for \tex_undefined:D.) 1.) 301 h/initex | packagei l3names implementation 2 302 303 304 305 306 h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} h/packagei The code here simply renames all of the primitives to new.282 283 284 h*initexi \chardef \l__kernel_expl_bool = 0 ~ h/initexi (End definition for \l__kernel_expl_bool. In format mode. internal. 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 h*deprecatedi \protected\edef\ExplSyntaxNamesOn {% \expandafter\noexpand \csname\detokenize{char_set_catcode_letter:n}\endcsname{58}% \expandafter\noexpand \csname\detokenize{char_set_catcode_letter:n}\endcsname{95}% } \protected\edef\ExplSyntaxNamesOff {% \expandafter\noexpand \csname\detokenize{char_set_catcode_other:n}\endcsname{58}% \expandafter\noexpand \csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{95}% } h/deprecatedi (End definition for \ExplSyntaxNamesOn and \ExplSyntaxNamesOff.) The \let primitive is renamed by hand first as it is essential for the entire process to follow. So it should be marked here as “taken”. names. \tex_undefined:D This function does not exist at all. but is the name used by the plain TEX format for an undefined function. These functions are documented on page ??. This also uses \global.8 Deprecated functions Deprecated 2012-06-19 for removal after 2012-12-31. Using an \edef here makes the definitions that bit clearer later. \ExplSyntaxNamesOn \ExplSyntaxNamesOff These can be set up early. it also deletes all of the existing names (although some do come back later). as they are not used anywhere in the package or format itself. This also allows the original names to be removed in format mode. so that they may be entered without catcode tricks.307 308 \let \tex_global:D \global \let \tex_let:D \let Everything is inside a (rather long) group. which keeps \__expl_primitive:NN trapped. all TEX primitives are given a new name of the form \tex_oldname:D. 309 \__expl_primitive:NN \begingroup A temporary function to actually do the renaming. These are given modified new names. 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \let \def \edef \gdef \xdef \chardef \countdef \dimendef \skipdef \muskipdef \mathchardef \toksdef \futurelet \advance \divide \multiply \font \fam \global \long \outer \setlanguage \globaldefs 207 \tex_let:D \tex_def:D \tex_edef:D \tex_gdef:D \tex_xdef:D \tex_chardef:D \tex_countdef:D \tex_dimendef:D \tex_skipdef:D \tex_muskipdef:D \tex_mathchardef:D \tex_toksdef:D \tex_futurelet:D \tex_advance:D \tex_divide:D \tex_multiply:D \tex_font:D \tex_fam:D \tex_global:D \tex_long:D \tex_outer:D \tex_setlanguage:D \tex_globaldefs:D . 317 318 319 \__expl_primitive:NN \ \__expl_primitive:NN \/ \__expl_primitive:NN \- \tex_space:D \tex_italiccorrection:D \tex_hyphen:D Now all the other primitives. But first three special cases which have symbolic original names.) In the current incarnation of this package. 310 311 312 313 314 315 316 \long \def \__expl_primitive:NN #1#2 { \tex_global:D \tex_let:D #2 #1 h*initexi \tex_global:D \tex_let:D #1 \tex_undefined:D h/initexi } (End definition for \__expl_primitive:NN. 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \afterassignment \aftergroup \expandafter \noexpand \begingroup \endgroup \halign \valign \cr \crcr \noalign \omit \span \tabskip \everycr \if \ifcase \ifcat \ifnum \ifodd \ifdim \ifeof \ifhbox \ifvbox \ifvoid \ifx \iffalse \iftrue \ifhmode \ifmmode \ifvmode \ifinner \else \fi \or \immediate \closeout \openin \openout \read \write \closein \newlinechar \input \endinput \inputlineno \errmessage \message \show \showthe 208 \tex_afterassignment:D \tex_aftergroup:D \tex_expandafter:D \tex_noexpand:D \tex_begingroup:D \tex_endgroup:D \tex_halign:D \tex_valign:D \tex_cr:D \tex_crcr:D \tex_noalign:D \tex_omit:D \tex_span:D \tex_tabskip:D \tex_everycr:D \tex_if:D \tex_ifcase:D \tex_ifcat:D \tex_ifnum:D \tex_ifodd:D \tex_ifdim:D \tex_ifeof:D \tex_ifhbox:D \tex_ifvbox:D \tex_ifvoid:D \tex_ifx:D \tex_iffalse:D \tex_iftrue:D \tex_ifhmode:D \tex_ifmmode:D \tex_ifvmode:D \tex_ifinner:D \tex_else:D \tex_fi:D \tex_or:D \tex_immediate:D \tex_closeout:D \tex_openin:D \tex_openout:D \tex_read:D \tex_write:D \tex_closein:D \tex_newlinechar:D \tex_input:D \tex_endinput:D \tex_inputlineno:D \tex_errmessage:D \tex_message:D \tex_show:D \tex_showthe:D . 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \showbox \showlists \errhelp \errorcontextlines \tracingcommands \tracinglostchars \tracingmacros \tracingonline \tracingoutput \tracingpages \tracingparagraphs \tracingrestores \tracingstats \pausing \showboxbreadth \showboxdepth \batchmode \errorstopmode \nonstopmode \scrollmode \end \csname \endcsname \ignorespaces \relax \the \mag \language \mark \topmark \firstmark \botmark \splitfirstmark \splitbotmark \fontname \escapechar \endlinechar \mathchoice \delimiter \mathaccent \mathchar \mskip \radical \vcenter \mkern \above \abovewithdelims \atop \atopwithdelims \over 209 \tex_showbox:D \tex_showlists:D \tex_errhelp:D \tex_errorcontextlines:D \tex_tracingcommands:D \tex_tracinglostchars:D \tex_tracingmacros:D \tex_tracingonline:D \tex_tracingoutput:D \tex_tracingpages:D \tex_tracingparagraphs:D \tex_tracingrestores:D \tex_tracingstats:D \tex_pausing:D \tex_showboxbreadth:D \tex_showboxdepth:D \tex_batchmode:D \tex_errorstopmode:D \tex_nonstopmode:D \tex_scrollmode:D \tex_end:D \tex_csname:D \tex_endcsname:D \tex_ignorespaces:D \tex_relax:D \tex_the:D \tex_mag:D \tex_language:D \tex_mark:D \tex_topmark:D \tex_firstmark:D \tex_botmark:D \tex_splitfirstmark:D \tex_splitbotmark:D \tex_fontname:D \tex_escapechar:D \tex_endlinechar:D \tex_mathchoice:D \tex_delimiter:D \tex_mathaccent:D \tex_mathchar:D \tex_mskip:D \tex_radical:D \tex_vcenter:D \tex_mkern:D \tex_above:D \tex_abovewithdelims:D \tex_atop:D \tex_atopwithdelims:D \tex_over:D . 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \overwithdelims \displaystyle \textstyle \scriptstyle \scriptscriptstyle \nonscript \eqno \leqno \abovedisplayshortskip \abovedisplayskip \belowdisplayshortskip \belowdisplayskip \displaywidowpenalty \displayindent \displaywidth \everydisplay \predisplaysize \predisplaypenalty \postdisplaypenalty \mathbin \mathclose \mathinner \mathop \displaylimits \limits \nolimits \mathopen \mathord \mathpunct \mathrel \overline \underline \left \right \binoppenalty \relpenalty \delimitershortfall \delimiterfactor \nulldelimiterspace \everymath \mathsurround \medmuskip \thinmuskip \thickmuskip \scriptspace \noboundary \accent \char \discretionary \hfil 210 \tex_overwithdelims:D \tex_displaystyle:D \tex_textstyle:D \tex_scriptstyle:D \tex_scriptscriptstyle:D \tex_nonscript:D \tex_eqno:D \tex_leqno:D \tex_abovedisplayshortskip:D \tex_abovedisplayskip:D \tex_belowdisplayshortskip:D \tex_belowdisplayskip:D \tex_displaywidowpenalty:D \tex_displayindent:D \tex_displaywidth:D \tex_everydisplay:D \tex_predisplaysize:D \tex_predisplaypenalty:D \tex_postdisplaypenalty:D \tex_mathbin:D \tex_mathclose:D \tex_mathinner:D \tex_mathop:D \tex_displaylimits:D \tex_limits:D \tex_nolimits:D \tex_mathopen:D \tex_mathord:D \tex_mathpunct:D \tex_mathrel:D \tex_overline:D \tex_underline:D \tex_left:D \tex_right:D \tex_binoppenalty:D \tex_relpenalty:D \tex_delimitershortfall:D \tex_delimiterfactor:D \tex_nulldelimiterspace:D \tex_everymath:D \tex_mathsurround:D \tex_medmuskip:D \tex_thinmuskip:D \tex_thickmuskip:D \tex_scriptspace:D \tex_noboundary:D \tex_accent:D \tex_char:D \tex_discretionary:D \tex_hfil:D . 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \hfilneg \hfill \hskip \hss \vfil \vfilneg \vfill \vskip \vss \unskip \kern \unkern \hrule \vrule \leaders \cleaders \xleaders \lastkern \lastskip \indent \par \noindent \vadjust \baselineskip \lineskip \lineskiplimit \clubpenalty \widowpenalty \exhyphenpenalty \hyphenpenalty \linepenalty \doublehyphendemerits \finalhyphendemerits \adjdemerits \hangafter \hangindent \parshape \hsize \lefthyphenmin \righthyphenmin \leftskip \rightskip \looseness \parskip \parindent \uchyph \emergencystretch \pretolerance \tolerance \spaceskip 211 \tex_hfilneg:D \tex_hfill:D \tex_hskip:D \tex_hss:D \tex_vfil:D \tex_vfilneg:D \tex_vfill:D \tex_vskip:D \tex_vss:D \tex_unskip:D \tex_kern:D \tex_unkern:D \tex_hrule:D \tex_vrule:D \tex_leaders:D \tex_cleaders:D \tex_xleaders:D \tex_lastkern:D \tex_lastskip:D \tex_indent:D \tex_par:D \tex_noindent:D \tex_vadjust:D \tex_baselineskip:D \tex_lineskip:D \tex_lineskiplimit:D \tex_clubpenalty:D \tex_widowpenalty:D \tex_exhyphenpenalty:D \tex_hyphenpenalty:D \tex_linepenalty:D \tex_doublehyphendemerits:D \tex_finalhyphendemerits:D \tex_adjdemerits:D \tex_hangafter:D \tex_hangindent:D \tex_parshape:D \tex_hsize:D \tex_lefthyphenmin:D \tex_righthyphenmin:D \tex_leftskip:D \tex_rightskip:D \tex_looseness:D \tex_parskip:D \tex_parindent:D \tex_uchyph:D \tex_emergencystretch:D \tex_pretolerance:D \tex_tolerance:D \tex_spaceskip:D . 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \xspaceskip \parfillskip \everypar \prevgraf \spacefactor \shipout \vsize \interlinepenalty \brokenpenalty \topskip \maxdeadcycles \maxdepth \output \deadcycles \pagedepth \pagestretch \pagefilstretch \pagefillstretch \pagefilllstretch \pageshrink \pagegoal \pagetotal \outputpenalty \hoffset \voffset \insert \holdinginserts \floatingpenalty \insertpenalties \lower \moveleft \moveright \raise \copy \lastbox \vsplit \unhbox \unhcopy \unvbox \unvcopy \setbox \hbox \vbox \vtop \prevdepth \badness \hbadness \vbadness \hfuzz \vfuzz 212 \tex_xspaceskip:D \tex_parfillskip:D \tex_everypar:D \tex_prevgraf:D \tex_spacefactor:D \tex_shipout:D \tex_vsize:D \tex_interlinepenalty:D \tex_brokenpenalty:D \tex_topskip:D \tex_maxdeadcycles:D \tex_maxdepth:D \tex_output:D \tex_deadcycles:D \tex_pagedepth:D \tex_pagestretch:D \tex_pagefilstretch:D \tex_pagefillstretch:D \tex_pagefilllstretch:D \tex_pageshrink:D \tex_pagegoal:D \tex_pagetotal:D \tex_outputpenalty:D \tex_hoffset:D \tex_voffset:D \tex_insert:D \tex_holdinginserts:D \tex_floatingpenalty:D \tex_insertpenalties:D \tex_lower:D \tex_moveleft:D \tex_moveright:D \tex_raise:D \tex_copy:D \tex_lastbox:D \tex_vsplit:D \tex_unhbox:D \tex_unhcopy:D \tex_unvbox:D \tex_unvcopy:D \tex_setbox:D \tex_hbox:D \tex_vbox:D \tex_vtop:D \tex_prevdepth:D \tex_badness:D \tex_hbadness:D \tex_vbadness:D \tex_hfuzz:D \tex_vfuzz:D . 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \overfullrule \boxmaxdepth \splitmaxdepth \splittopskip \everyhbox \everyvbox \nullfont \textfont \scriptfont \scriptscriptfont \fontdimen \hyphenchar \skewchar \defaulthyphenchar \defaultskewchar \number \romannumeral \string \lowercase \uppercase \meaning \penalty \unpenalty \lastpenalty \special \dump \patterns \hyphenation \time \day \month \year \jobname \everyjob \count \dimen \skip \toks \muskip \box \wd \ht \dp \catcode \delcode \sfcode \lccode \uccode \mathcode 213 \tex_overfullrule:D \tex_boxmaxdepth:D \tex_splitmaxdepth:D \tex_splittopskip:D \tex_everyhbox:D \tex_everyvbox:D \tex_nullfont:D \tex_textfont:D \tex_scriptfont:D \tex_scriptscriptfont:D \tex_fontdimen:D \tex_hyphenchar:D \tex_skewchar:D \tex_defaulthyphenchar:D \tex_defaultskewchar:D \tex_number:D \tex_romannumeral:D \tex_string:D \tex_lowercase:D \tex_uppercase:D \tex_meaning:D \tex_penalty:D \tex_unpenalty:D \tex_lastpenalty:D \tex_special:D \tex_dump:D \tex_patterns:D \tex_hyphenation:D \tex_time:D \tex_day:D \tex_month:D \tex_year:D \tex_jobname:D \tex_everyjob:D \tex_count:D \tex_dimen:D \tex_skip:D \tex_toks:D \tex_muskip:D \tex_box:D \tex_wd:D \tex_ht:D \tex_dp:D \tex_catcode:D \tex_delcode:D \tex_sfcode:D \tex_lccode:D \tex_uccode:D \tex_mathcode:D . These are all given the prefix \etex_. 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \ifdefined \ifcsname \unless \eTeXversion \eTeXrevision \marks \topmarks \firstmarks \botmarks \splitfirstmarks \splitbotmarks \unexpanded \detokenize \scantokens \showtokens \readline \tracingassigns \tracingscantokens \tracingnesting \tracingifs \currentiflevel \currentifbranch \currentiftype \tracinggroups \currentgrouplevel \currentgrouptype \showgroups \showifs \interactionmode \lastnodetype \iffontchar \fontcharht \fontchardp \fontcharwd \fontcharic \parshapeindent \parshapelength \parshapedimen \numexpr \dimexpr \glueexpr \muexpr \gluestretch \glueshrink \gluestretchorder \glueshrinkorder \gluetomu 214 \etex_ifdefined:D \etex_ifcsname:D \etex_unless:D \etex_eTeXversion:D \etex_eTeXrevision:D \etex_marks:D \etex_topmarks:D \etex_firstmarks:D \etex_botmarks:D \etex_splitfirstmarks:D \etex_splitbotmarks:D \etex_unexpanded:D \etex_detokenize:D \etex_scantokens:D \etex_showtokens:D \etex_readline:D \etex_tracingassigns:D \etex_tracingscantokens:D \etex_tracingnesting:D \etex_tracingifs:D \etex_currentiflevel:D \etex_currentifbranch:D \etex_currentiftype:D \etex_tracinggroups:D \etex_currentgrouplevel:D \etex_currentgrouptype:D \etex_showgroups:D \etex_showifs:D \etex_interactionmode:D \etex_lastnodetype:D \etex_iffontchar:D \etex_fontcharht:D \etex_fontchardp:D \etex_fontcharwd:D \etex_fontcharic:D \etex_parshapeindent:D \etex_parshapelength:D \etex_parshapedimen:D \etex_numexpr:D \etex_dimexpr:D \etex_glueexpr:D \etex_muexpr:D \etex_gluestretch:D \etex_glueshrink:D \etex_gluestretchorder:D \etex_glueshrinkorder:D \etex_gluetomu:D . we also rename the additional primitives.Since LATEX3 requires at least the ε-TEX extensions. we retain pdf at the start of the names only for directly PDF-related primitives.. 727 \__expl_primitive:NN \pdfstrcmp \pdftex_strcmp:D XETEX-specific primitives. In the case of the pdfTEX primitives. 728 \__expl_primitive:NN \XeTeXversion 215 \xetex_XeTeXversion:D .689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \mutoglue \lastlinefit \interlinepenalties \clubpenalties \widowpenalties \displaywidowpenalties \middle \savinghyphcodes \savingvdiscards \pagediscards \splitdiscards \TeXXeTstate \beginL \endL \beginR \endR \predisplaydirection \everyeof \protected \etex_mutoglue:D \etex_lastlinefit:D \etex_interlinepenalties:D \etex_clubpenalties:D \etex_widowpenalties:D \etex_displaywidowpenalties:D \etex_middle:D \etex_savinghyphcodes:D \etex_savingvdiscards:D \etex_pagediscards:D \etex_splitdiscards:D \etex_TeXXeTstate:D \etex_beginL:D \etex_endL:D \etex_beginR:D \etex_endR:D \etex_predisplaydirection:D \etex_everyeof:D \etex_protected:D The newer primitives are more complex: there are an awful lot of them. and we don’t use them all at the moment. but are not related to PDF output. as there are a lot of pdfTEX primitives that start \pdf. Note that XETEX’s \strcmp is handled earlier and is “rolled up” into \pdfstrcmp. 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \pdfcreationdate \pdfcolorstack \pdfcompresslevel \pdfdecimaldigits \pdfhorigin \pdfinfo \pdflastxform \pdfliteral \pdfminorversion \pdfobjcompresslevel \pdfoutput \pdfrefxform \pdfrestore \pdfsave \pdfsetmatrix \pdfpkresolution \pdftexrevision \pdfvorigin \pdfxform \pdftex_pdfcreationdate:D \pdftex_pdfcolorstack:D \pdftex_pdfcompresslevel:D \pdftex_pdfdecimaldigits:D \pdftex_pdfhorigin:D \pdftex_pdfinfo:D \pdftex_pdflastxform:D \pdftex_pdfliteral:D \pdftex_pdfminorversion:D \pdftex_pdfobjcompresslevel:D \pdftex_pdfoutput:D \pdftex_pdfrefxform:D \pdftex_pdfrestore:D \pdftex_pdfsave:D \pdftex_pdfsetmatrix:D \pdftex_pdfpkresolution:D \pdftex_pdftextrevision:D \pdftex_pdfvorigin:D \pdftex_pdfxform:D While these are not. So the following is selective.. These ones related to PDF output. 740 \tex_endgroup:D LATEX 2ε will have moved a few primitives. 741 742 743 744 745 746 747 748 h*packagei \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_end:D \tex_everydisplay:D \tex_everymath:D \tex_hyphen:D \tex_input:D \tex_italiccorrection:D \tex_underline:D \@@end \frozen@everydisplay \frozen@everymath \@@hyph \@@input \@@italiccorr \@@underline That is also true for the luatex package for LATEX 2ε . but we do not support those engines and so it seems most sensible to treat them as LuaTEX primitives for prefix purposes. 758 \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D h/packagei 759 h/initex | packagei 753 754 755 756 757 \luatex_bodydir:D \luatex_mathdir:D \luatex_pagedir:D \luatex_pardir:D \luatex_textdir:D \luatexbodydir \luatexmathdir \luatexpagedir \luatexpardir \luatextextdir l3basics implementation 3 760 h*initex | packagei 761 h*packagei 216 .Primitives from LuaTEX. 749 750 751 752 \tex_let:D \tex_let:D \tex_let:D \tex_let:D \luatex_catcodetable:D \luatex_initcatcodetable:D \luatex_latelua:D \luatex_savecatcodetable:D \luatexcatcodetable \luatexinitcatcodetable \luatexlatelua \luatexsavecatcodetable Which also covers those slightly odd ones. 735 736 737 738 739 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \bodydir \mathdir \pagedir \pardir \textdir \luatex_bodydir:D \luatex_mathdir:D \luatex_pagedir:D \luatex_pardir:D \luatex_textdir:D The job is done: close the group (using the primitive renamed!). These come from Omega via Aleph. so these are sorted out. 729 730 731 732 733 734 \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \__expl_primitive:NN \catcodetable \directlua \initcatcodetable \latelua \luatexversion \savecatcodetable \luatex_catcodetable:D \luatex_directlua:D \luatex_initcatcodetable:D \luatex_latelua:D \luatex_luatexversion:D \luatex_savecatcodetable:D Slightly more awkward are the directional primitives in LuaTEX. 762 763 764 765 3. \exp_not:N .) \if_mode_math: \if_mode_horizontal: \if_mode_vertical: \if_mode_inner: TEX lets us detect some if its modes. These functions are documented on page 24.1 \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Renaming some TEX primitives (again) Having given all the TEX primitives a consistent name. 217 .. 784 785 786 \tex_let:D \exp_after:wN \tex_let:D \exp_not:N \tex_let:D \exp_not:n \tex_expandafter:D \tex_noexpand:D \etex_unexpanded:D (End definition for \exp_after:wN . 766 767 768 769 770 771 772 773 774 775 \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \tex_let:D \if_true: \if_false: \or: \else: \fi: \reverse_if:N \if:w \if_charcode:w \if_catcode:w \if_meaning:w \tex_iftrue:D \tex_iffalse:D \tex_or:D \tex_else:D \tex_fi:D \etex_unless:D \tex_if:D \tex_if:D \tex_ifcat:D \tex_ifx:D (End definition for \if_true: and others.) 2 This renaming gets expensive in terms of csname usage.) \exp_after:wN \exp_not:N \exp_not:n The three \exp_ functions are used in the l3expan module where they are described.2 \if_true: \if_false: \or: \else: \fi: \reverse_if:N \if:w \if_charcode:w \if_catcode:w \if_meaning:w Then some conditionals. These functions are documented on page 24. we need to give sensible names to the ones we actually want to use. and \exp_not:n. an alternative scheme would be to just use the \tex.. These will be defined as needed in the appropriate modules. 776 777 778 779 \tex_let:D \tex_let:D \tex_let:D \tex_let:D \if_mode_math: \if_mode_horizontal: \if_mode_vertical: \if_mode_inner: \tex_ifmmode:D \tex_ifhmode:D \tex_ifvmode:D \tex_ifinner:D (End definition for \if_mode_math: and others. but do a few now.) \if_cs_exist:N \if_cs_exist:w \cs:w \cs_end: Building csnames and testing if control sequences exist. These functions are documented on page 33. just to get started. 780 781 782 783 \tex_let:D \tex_let:D \tex_let:D \tex_let:D \if_cs_exist:N \if_cs_exist:w \cs:w \cs_end: \etex_ifdefined:D \etex_ifcsname:D \tex_csname:D \tex_endcsname:D (End definition for \if_cs_exist:N and others. These functions are documented on page 17.:D name in the cases where no good alternative exists. ) \exp_args:Nc \exp_args:cc Discussed in l3expan. 795 \tex_let:D \group_insert_after:N \tex_aftergroup:D (End definition for \group_insert_after:N. and \cs_meaning:c. 790 791 792 \tex_let:D \scan_stop: \tex_let:D \group_begin: \tex_let:D \group_end: \tex_relax:D \tex_begingroup:D \tex_endgroup:D (End definition for \scan_stop: . The \cs_meaning:c command must check for an undefined control sequence to avoid defining it mistakenly. These functions are documented on page ??. Some of the necessary functions (\use_i:nn. These functions are documented on page 74. 793 794 \tex_let:D \if_int_compare:w \tex_let:D \__int_to_roman:w \tex_ifnum:D \tex_romannumeral:D (End definition for \if_int_compare:w and \__int_to_roman:w.) 218 .) \if_int_compare:w \__int_to_roman:w For integers.) \scan_stop: \group_begin: \group_end: The next three are basic functions for which there also exist versions that are safe inside alignments. 796 797 798 799 \tex_long:D \tex_def:D \exp_args:Nc #1#2 { \exp_after:wN #1 \cs:w #2 \cs_end: } \tex_long:D \tex_def:D \exp_args:cc #1#2 { \cs:w #1 \exp_after:wN \cs_end: \cs:w #2 \cs_end: } (End definition for \exp_args:Nc and \exp_args:cc. These functions are documented on page 16. \use_ii:nn. These functions are documented on page 9. These functions are documented on page ??. but needed much earlier. but will be defined before those variants are used. \group_begin: . \token_to_str:c .) \group_insert_after:N Adding material after the end of a group. and \cs_meaning:N. This function is documented on page 9. 787 788 789 \tex_let:D \token_to_meaning:N \tex_meaning:D \tex_let:D \token_to_str:N \tex_string:D \tex_let:D \cs_meaning:N \tex_meaning:D (End definition for \token_to_meaning:N .\token_to_meaning:N \token_to_str:N \cs_meaning:N Examining a control sequence or token.) \token_to_meaning:c \token_to_str:c \cs_meaning:c A small number of variants defined by hand. \token_to_str:N . and \exp_args:NNc) are not defined at that point yet. and \group_end:. These safe versions are defined in the l3prg module. 800 801 802 803 804 805 806 807 808 809 810 811 \tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } \tex_long:D \tex_def:D \cs_meaning:c #1 { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_args:Nc \cs_meaning:N {#1} } { \tl_to_str:n {undefined} } } \tex_let:D \token_to_meaning:c = \cs_meaning:c (End definition for \token_to_meaning:c . For other constants the l3int module is required but it can’t be used until the allocation has been set up properly! The actual allocation mechanism is in l3alloc and as TEX wants to reserve count registers 0–9.2 \c_minus_one \c_zero \c_sixteen \c_six \c_seven \c_twelve Defining some constants We need the constants \c_minus_one and \c_sixteen now for writing information to the log and the terminal and \c_zero which is used by some functions in the l3alloc module. the first available one is 10 so we use that for \c_minus_one.3. \c_zero .3 Defining functions We start by providing functions for the typical definition functions. the TEX primitives for assignments are and it can be a cause of problems if others aren’t. after all. The rest are defined in the l3int module – at least for the ones that can be defined with \tex_chardef:D or \tex_mathchardef:D.) \c_max_register_int This is here as this particular integer is needed both in package mode and to bootstrap l3alloc. 829 830 831 832 833 834 835 836 837 \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D \etex_protected:D \cs_set_nopar:Npn \cs_set:Npn { \tex_long:D \cs_set_nopar:Npn } \etex_protected:D \cs_set_nopar:Npn \cs_set:Npx { \tex_long:D \cs_set_nopar:Npx } \etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn { \etex_protected:D \cs_set_nopar:Npn } \etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx 219 . First the local ones. This variable is documented on page 73. 812 813 814 815 816 817 818 819 820 821 822 823 h*packagei \tex_let:D \c_minus_one \m@ne h/packagei h*initexi \tex_countdef:D \c_minus_one = 10 ~ \c_minus_one = -1 ~ h/initexi \tex_chardef:D \c_sixteen = 16 ~ \tex_chardef:D \c_zero = 0 ~ \tex_chardef:D \c_six = 6 ~ \tex_chardef:D \c_seven = 7 ~ \tex_chardef:D \c_twelve = 12 ~ (End definition for \c_minus_one . These functions are documented on page 73.) 3. 824 825 826 827 828 \etex_ifdefined:D \luatex_luatexversion:D \tex_chardef:D \c_max_register_int = 65 535 ~ \tex_else:D \tex_mathchardef:D \c_max_register_int = 32 767 ~ \tex_fi:D (End definition for \c_max_register_int. \cs_set_nopar:Npn \cs_set_nopar:Npx \cs_set:Npn \cs_set:Npx \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npx \cs_set_protected:Npn \cs_set_protected:Npx All assignment functions in LATEX3 should be naturally protected. and is documented in l3int. and \c_sixteen. This function is documented on page 17. used in defining conditionals.) 3. 857 \cs_set_nopar:Npn \l__exp_internal_tl { } (End definition for \l__exp_internal_tl.) \use:c This macro grabs its argument and returns a csname from it. These functions are documented on page ??. used by \use:x. 843 844 845 846 847 848 849 850 851 852 853 854 855 856 \tex_let:D \cs_gset_nopar:Npn \tex_gdef:D \tex_let:D \cs_gset_nopar:Npx \tex_xdef:D \cs_set_protected_nopar:Npn \cs_gset:Npn { \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn { \etex_protected:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx { \etex_protected:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected:Npn { \etex_protected:D \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected:Npx { \etex_protected:D \tex_long:D \cs_gset_nopar:Npx } (End definition for \cs_gset_nopar:Npn and others.) 220 .) \use:x Fully expands its argument and passes it to the input stream. 858 \cs_set:Npn \use:c #1 { \cs:w #1 \cs_end: } (End definition for \use:c. These functions are documented on page ??. Uses the reserved \l__exp_internal_tl which will be set up in l3expan. 859 860 861 862 863 \cs_set_protected:Npn \use:x #1 { \cs_set_nopar:Npx \l__exp_internal_tl {#1} \l__exp_internal_tl } (End definition for \use:x.838 839 840 841 842 { \etex_protected:D \cs_set_nopar:Npx } \cs_set_protected_nopar:Npn \cs_set_protected:Npn { \etex_protected:D \tex_long:D \cs_set_nopar:Npn } \cs_set_protected_nopar:Npn \cs_set_protected:Npx { \etex_protected:D \tex_long:D \cs_set_nopar:Npx } (End definition for \cs_set_nopar:Npn and others. We don’t use tl methods because l3basics is loaded earlier.) \cs_gset_nopar:Npn \cs_gset_nopar:Npx \cs_gset:Npn \cs_gset:Npx \cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:Npx \cs_gset_protected:Npn \cs_gset_protected:Npx Global versions of the above functions. This variable is documented on page 34. This function is documented on page 20.4 \l__exp_internal_tl Selecting tokens Scratch token list variable for l3expan. Very useful when you need to \use_i_delimit_by_q_stop:nw skip the rest of a mapping sequence but want an easy way to control what should be \use_i_delimit_by_q_recursion_stop:nw expanded next. 868 869 \cs_set:Npn \use_i:nn #1#2 {#1} \cs_set:Npn \use_ii:nn #1#2 {#2} (End definition for \use_i:nn and \use_ii:nn.) \use_i:nnn \use_ii:nnn \use_iii:nnn \use_i_ii:nnn \use_i:nnnn \use_ii:nnnn \use_iii:nnnn \use_iv:nnnn We also need something for picking up arguments from a longer list. 864 865 866 867 \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \use:n \use:nn \use:nnn \use:nnnn #1 #1#2 #1#2#3 #1#2#3#4 {#1} {#1#2} {#1#2#3} {#1#2#3#4} (End definition for \use:n and others. \q_stop.) \use_i:nn \use_ii:nn The equivalent to LATEX 2ε ’s \@firstoftwo and \@secondoftwo. These functions are documented on page ??.) \use_none_delimit_by_q_nil:w Functions that gobble everything until they see either \q_nil.\use:n \use:nn \use:nnn \use:nnnn These macros grab their arguments and returns them back to the input (with outer braces removed). and \use_none_delimit_by_q_recurs These functions are documented on page 47. 870 871 872 873 874 875 876 877 \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \use_i:nnn \use_ii:nnn \use_iii:nnn \use_i_ii:nnn \use_i:nnnn \use_ii:nnnn \use_iii:nnnn \use_iv:nnnn #1#2#3 {#1} #1#2#3 {#2} #1#2#3 {#3} #1#2#3 {#1#2} #1#2#3#4 {#1} #1#2#3#4 {#2} #1#2#3#4 {#3} #1#2#3#4 {#4} (End definition for \use_i:nnn and others.) 221 . respectively. \use_none_delimit_by_q_stop:w . and \use_i_delimit_by_q_recursion_sto These functions are documented on page 47. 881 882 883 \cs_set:Npn \use_i_delimit_by_q_nil:nw #1#2 \q_nil {#1} \cs_set:Npn \use_i_delimit_by_q_stop:nw #1#2 \q_stop {#1} \cs_set:Npn \use_i_delimit_by_q_recursion_stop:nw #1#2 \q_recursion_stop {#1} (End definition for \use_i_delimit_by_q_nil:nw . These functions are documented on page 19. These functions are documented on page 19.) \use_i_delimit_by_q_nil:nw Same as above but execute first argument after gobbling. \use_none_delimit_by_q_recursion_stop:w 878 \cs_set:Npn \use_none_delimit_by_q_nil:w #1 \q_nil { } 879 \cs_set:Npn \use_none_delimit_by_q_stop:w #1 \q_stop { } 880 \cs_set:Npn \use_none_delimit_by_q_recursion_stop:w #1 \q_recursion_stop { } (End definition for \use_none_delimit_by_q_nil:w . or \q_\use_none_delimit_by_q_stop:w recursion_stop. \use_i_delimit_by_q_stop:nw . Therefore. \prg_return_true: \prg_return_false: The idea here is that \__int_to_roman:w will expand fully any \else: and the \fi: that are waiting to be discarded.6 Conditional processing and definitions Underneath any predicate function (_p) or other conditional forms (TF. a simple user interface could be something like \if_meaning:w #1#2 \prg_return_true: \else: \if_meaning:w #1#3 \prg_return_true: \else: \prg_return_false: \fi: \fi: Usually. The code can then leave either the first or second argument in the input stream. etc. 884 885 886 887 888 889 890 891 892 \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn \use_none:n \use_none:nn \use_none:nnn \use_none:nnnn \use_none:nnnnn \use_none:nnnnnn \use_none:nnnnnnn \use_none:nnnnnnnn \use_none:nnnnnnnnn #1 #1#2 #1#2#3 #1#2#3#4 #1#2#3#4#5 #1#2#3#4#5#6 #1#2#3#4#5#6#7 #1#2#3#4#5#6#7#8 #1#2#3#4#5#6#7#8#9 { { { { { { { { { } } } } } } } } } (End definition for \use_none:n and others.) 3. a TEX programmer would have to insert a number of \exp_after:wNs to ensure the state value is returned at exactly the point where the last conditional is finished. before reaching the \c_zero which will leave the expansion null.) is a built-in logic saying that it after all of the testing and processing must return the hstatei this leaves TEX in. However. This means that all of the branching code has to contain at least two tokens: see how the logical tests are actually implemented to see this.5 \use_none:n \use_none:nn \use_none:nnn \use_none:nnnn \use_none:nnnnn \use_none:nnnnnn \use_none:nnnnnnn \use_none:nnnnnnnn \use_none:nnnnnnnnn Gobbling tokens from input To gobble tokens from the input we use a standard naming convention: the number of tokens gobbled is given by the number of n’s following the : in the name. Although we could define functions to remove ten arguments or more using separate calls of \use_none:nnnnn.3. this is very non-intuitive to the programmer who will assume that expanding such a function once will take care of gobbling all the tokens in one go. These functions are documented on page ??. that obscures the code and forces the TEX programmer to prove that he/she knows the 2n − 1 table. 893 894 895 896 \cs_set_nopar:Npn { \exp_after:wN \cs_set_nopar:Npn { \exp_after:wN \prg_return_true: \use_i:nn \__int_to_roman:w } \prg_return_false: \use_ii:nn \__int_to_roman:w} 222 . We therefore provide the simpler interface. and feed {hnamei} {hsignaturei} hbooleani {hset or newi} {hmaybe protectedi} {hparametersi} {TF. If the hsignaturei has more than 9 letters. Then feed {hnamei} {hsignaturei} hbooleani {hset or newi} {hmaybe protectedi} {hparametersi} {TF. The various functions only differ by which function is used for the assignment. the definition is aborted since TEX macros have at most 9 arguments.) \prg_set_conditional:Nnn \prg_new_conditional:Nnn \prg_set_protected_conditional:Nnn \prg_new_protected_conditional:Nnn \__prg_generate_conditional_count:nnNnn \__prg_generate_conditional_count:nnNnnnn The user functions for the types automatically inserting the correct parameter text based on the signature.. Provided two arguments are absorbed then the code will work.. 910 911 912 913 914 915 916 917 918 919 920 \cs_set_protected_nopar:Npn \prg_set_conditional:Nnn { \__prg_generate_conditional_count:nnNnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Nnn { \__prg_generate_conditional_count:nnNnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Nnn { \__prg_generate_conditional_count:nnNnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Nnn { \__prg_generate_conditional_count:nnNnn { new } { _protected } } \cs_set_protected:Npn \__prg_generate_conditional_count:nnNnn #1#2#3 { \__cs_split_function:NN #3 \__prg_generate_conditional_count:nnNnnnn 223 .. Then split the base function into name and signature. Split the base function into name and signature. The erroneous case where the function name contains no colon is captured later. we must grab the parameter text. (End definition for \prg_return_true: and \prg_return_false:. The various functions only differ by which function is used for the assignment. 897 898 899 900 901 902 903 904 905 906 907 908 909 \cs_set_protected_nopar:Npn \prg_set_conditional:Npnn { \__prg_generate_conditional_parm:nnNpnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Npnn { \__prg_generate_conditional_parm:nnNpnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Npnn { \__prg_generate_conditional_parm:nnNpnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Npnn { \__prg_generate_conditional_parm:nnNpnn { new } { _protected } } \cs_set_protected:Npn \__prg_generate_conditional_parm:nnNpnn #1#2#3#4# { \__cs_split_function:NN #3 \__prg_generate_conditional:nnNnnnnn {#1} {#2} {#4} } (End definition for \prg_set_conditional:Npnn and others.} {hcodei} to the auxiliary function responsible for defining all conditionals.} {hcodei} to the auxiliary function responsible for defining all conditionals. These functions are documented on page 35. The second auxiliary generates the parameter text from the number of letters in the signature. These functions are documented on page 37... reading everything up to a left brace before continuing..An extended state space could be implemented by including a more elaborate function in place of \use_i:nn/\use_ii:nn. For those Npnn type functions.) \prg_set_conditional:Npnn \prg_new_conditional:Npnn \prg_set_protected_conditional:Npnn \prg_new_protected_conditional:Npnn \__prg_generate_conditional_parm:nnNpnn The user functions for the types using parameter text from the programmer. 921 922 923 924 925 926 927 928 929 930 931 932 933 934 {#1} {#2} } \cs_set_protected:Npn \__prg_generate_conditional_count:nnNnnnn #1#2#3#4#5 { \__cs_parm_from_arg_count:nnF { \__prg_generate_conditional:nnNnnnnn {#1} {#2} #3 {#4} {#5} } { \tl_count:n {#2} } { \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } { \token_to_str:c { #1 : #2 } } { \tl_count:n {#2} } \use_none:nn } } (End definition for \prg_set_conditional:Nnn and others. \q_recursion_stop } } } Looping through the list of desired forms. and the error message is displayed (unless the form is empty. the eigth is the replacement text which we will augment when defining the forms. TF. The sixth is the parameters to use (possibly empty). \q_recursion_tail . If the form does not exist. First are six arguments and seventh is the form. 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 \cs_set_protected:Npn \__prg_generate_conditional:nnNnnnnn #1#2#3#4#5#6#7#8 { \if_meaning:w \c_false_bool #3 \__msg_kernel_error:nnx { kernel } { missing-colon } { \token_to_str:c {#1} } \exp_after:wN \use_none:nn \fi: \use:x { \exp_not:N \__prg_generate_conditional:nnnnnnw \exp_not:n { {#4} {#5} {#1} {#2} {#6} {#8} } \etex_detokenize:D {#7} \exp_not:n { . we throw an error and don’t define any conditional.e. i. The fourth and fifth arguments build up the defining function. T and F. the \use:c construction results in \relax. to allow for {T. Otherwise. 950 951 952 \cs_set_protected:Npn \__prg_generate_conditional:nnnnnnw #1#2#3#4#5#6#7 . which gives the name. p. signature and a boolean to signal whether or not there was a colon in the name. the seventh is the list of forms to define. then \use_none:nnnnnnn cleans up. Use the form to call the correct type. In the absence of a colon.. { \if_meaning:w \q_recursion_tail #7 224 . These functions are documented on page ??. The first \__prg_generate_conditional:nnnnnnw three arguments come from splitting up the base form of the conditional.) \__prg_generate_conditional:nnNnnnnn The workhorse here is going through a list of desired forms. the error message is removed by the variant form. The use of \etex_detokenize:D makes the later loop more robust. F}). . and that the TF variant will be slightly faster than the T version. Remember that the logic-returning functions expect two arguments to be present after \c_zero: notice the construction of the different variants relies on this.\exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \use:c { __prg_generate_ #7 _form:wnnnnnn } \tl_if_empty:nF {#7} { \__msg_kernel_error:nnxx { kernel } { conditional-form-unknown } {#7} { \token_to_str:c { #3 : #4 } } } \use_none:nnnnnnn \q_stop {#1} {#2} {#3} {#4} {#5} {#6} \__prg_generate_conditional:nnnnnnw {#1} {#2} {#3} {#4} {#5} {#6} 953 954 955 956 957 958 959 960 961 962 963 964 965 966 } (End definition for \__prg_generate_conditional:nnNnnnnn and \__prg_generate_conditional:nnnnnnw. The p form is only valid for expandable tests. 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 \cs_set_protected:Npn \__prg_generate_p_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { \if_meaning:w \scan_stop: #3 \scan_stop: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_args:cc { cs_ #2 #3 :Npn } { #4 _p: #5 } #6 { #7 \c_zero \c_true_bool \c_false_bool } } { \__msg_kernel_error:nnx { kernel } { protected-predicate } { \token_to_str:c { #4 _p: #5 } } } } \cs_set_protected:Npn \__prg_generate_T_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 T } #6 { #7 \c_zero \use:n \use_none:n } } \cs_set_protected:Npn \__prg_generate_F_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 F } #6 { #7 \c_zero { } } } 225 . 6: replacement. Those functions take the following arguments: 1: set or new. 3: function name 4: signature. 2: empty or _protected. we check for that by making sure that the second argument is empty.) \__prg_generate_p_form:wnnnnnn \__prg_generate_TF_form:wnnnnnn \__prg_generate_T_form:wnnnnnn \__prg_generate_F_form:wnnnnnn How to generate the various forms. 5: parameter text (or empty). otherwise we don’t know how to build conditionals.993 994 995 996 997 \cs_set_protected:Npn \__prg_generate_TF_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 TF } #6 { #7 \c_zero } } (End definition for \__prg_generate_p_form:wnnnnnn and others. These functions are documented on page 37. hence abort. At each step in the loop.) \__prg_set_eq_conditional:nnNnnNNw \__prg_set_eq_conditional_loop:nnnnNw \__prg_set_eq_conditional_p_form:nnn \__prg_set_eq_conditional_TF_form:nnn \__prg_set_eq_conditional_T_form:nnn \__prg_set_eq_conditional_F_form:nnn Split the function to be defined. \q_recursion_tail .) \prg_set_eq_conditional:NNn The setting-equal functions. \q_recursion_tail . make sure that the conditional form we copy is defined. The second auxiliary receives twice three arguments coming from splitting the function to be defined and the function to copy. Make sure that both functions contained a colon. \q_recursion_stop 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 \cs_set_protected_nopar:Npn \prg_set_eq_conditional:NNn { \__prg_set_eq_conditional:NNNn \cs_set_eq:cc } \cs_set_protected_nopar:Npn \prg_new_eq_conditional:NNn { \__prg_set_eq_conditional:NNNn \cs_new_eq:cc } \cs_set_protected:Npn \__prg_set_eq_conditional:NNNn #1#2#3#4 { \use:x { \exp_not:N \__prg_set_eq_conditional:nnNnnNNw \__cs_split_function:NN #2 \prg_do_nothing: \__cs_split_function:NN #3 \prg_do_nothing: \exp_not:N #1 \etex_detokenize:D {#4} \exp_not:n { . Split the two functions and feed a first auxiliary {hname1 i} \prg_new_eq_conditional:NNn {hsignature1 i} hboolean1 i {hname2 i} {hsignature2 i} hboolean2 i hcopying functioni hconditionsi \__prg_set_eq_conditional:NNNn . otherwise abort. Call the looping macro. with arguments {hname1 i} {hsignature1 i} {hname2 i} {hsignature2 i} hcopying functioni and followed by the comma list. and copy it. \q_recursion_stop } } } (End definition for \prg_set_eq_conditional:NNn and \prg_new_eq_conditional:NNn. 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 \cs_set_protected:Npn \__prg_set_eq_conditional:nnNnnNNw #1#2#3#4#5#6 { \if_meaning:w \c_false_bool #3 \__msg_kernel_error:nnx { kernel } { missing-colon } { \token_to_str:c {#1} } \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \if_meaning:w \c_false_bool #6 \__msg_kernel_error:nnx { kernel } { missing-colon } { \token_to_str:c {#4} } \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#4} {#5} 226 . and setup a manual clist loop over argument #6 of the first auxiliary. Later again they were changed to being numerical constants with values of 1 for true and 0 for false. I think Michael originated the idea of expandable boolean tests. { \if_meaning:w \q_recursion_tail #6 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \use:c { __prg_set_eq_conditional_ #6 _form:wNnnnn } \tl_if_empty:nF {#6} { \__msg_kernel_error:nnxx { kernel } { conditional-form-unknown } {#6} { \token_to_str:c { #1 : #2 } } } \use_none:nnnnnn \q_stop #5 {#1} {#2} {#3} {#4} \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#3} {#4} #5 } \cs_set:Npn \__prg_set_eq_conditional_p_form:wNnnnn #1 \q_stop #2#3#4#5#6 { \__chk_if_exist_cs:c { #5 _p : #6 } #2 { #3 _p : #4 } { #5 _p : #6 } } \cs_set:Npn \__prg_set_eq_conditional_TF_form:wNnnnn #1 \q_stop #2#3#4#5#6 { \__chk_if_exist_cs:c { #5 : #6 TF } #2 { #3 : #4 TF } { #5 : #6 TF } } \cs_set:Npn \__prg_set_eq_conditional_T_form:wNnnnn #1 \q_stop #2#3#4#5#6 { \__chk_if_exist_cs:c { #5 : #6 T } #2 { #3 : #4 T } { #5 : #6 T } } \cs_set:Npn \__prg_set_eq_conditional_F_form:wNnnnn #1 \q_stop #2#3#4#5#6 { \__chk_if_exist_cs:c { #5 : #6 F } #2 { #3 : #4 F } { #5 : #6 F } } (End definition for \__prg_set_eq_conditional:nnNnnNNw and \__prg_set_eq_conditional_loop:nnnnNw. so they could be used in logical operations.) All that is left is to define the canonical boolean true and false.1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 } \cs_set_protected:Npn \__prg_set_eq_conditional_loop:nnnnNw #1#2#3#4#5#6 . These functions are documented on page 37. At first these were supposed to expand into either TT or TF to be tested using \if:w but this was later changed to 00 and 01. 1065 \tex_chardef:D \c_true_bool = 1 ~ 227 . We need this from the get-go. \c_true_bool \c_false_bool Here are the canonical boolean values. while if it is non-printable then only one is present. and TEX skips to \fi:.g. This turns out to be a non-trivial matter as there a different cases: • The usual case of a printable escape character. when the value of the \escapechar is negative.7 \cs_to_str:N \__cs_to_str:N \__cs_to_str:w Dissecting a control sequence This converts a control sequence into the character string of its name.. and stops the expansion of the initial \__int_to_roman:w. \cs_to_str:N takes two expansion steps to be fully expanded. • the case of a non-printable escape characters. The character codes are different. removing the leading escape character. terminating the argument of \__int_to_roman:w. This function is documented on page 18. In this case. the test is false. 1067 1068 1069 1070 1071 1072 1073 1074 1075 \cs_set_nopar:Npn \cs_to_str:N { \__int_to_roman:w \if:w \token_to_str:N \ \__cs_to_str:w \fi: \exp_after:wN \__cs_to_str:N \token_to_str:N } \cs_set:Npn \__cs_to_str:N #1 { \c_zero } \cs_set:Npn \__cs_to_str:w #1 \__cs_to_str:N { . and the auxiliary \__cs_to_str:w comes into play. These variables are documented on page 21. • when the escape character is a space. there is an additional complication: the control sequence itself may start with a space. inserting -\__int_value:w. and TEX reads \__cs_to_str:N after turning the following control sequence into a string.) 228 .) 3. e. which expands \c_zero to the character 0. which is removed. Then the \if:w test is unfinished after reading a the space from \token_to_str:N␣\␣. So the approach adopted is a little more intricate still. then the escape character is printable. Clearly that should not be lost in the process of converting to a string. thus the \if:w test is false.1066 \tex_chardef:D \c_false_bool = 0 ~ (End definition for \c_true_bool and \c_false_bool. In all three cases. feeding . and stops the \__int_to_roman:w with \c_zero. However. a space. and the auxiliary \__cs_to_str:w is expanded. followed by the escape character. If there are two tokens. this auxiliary removes the escape character. One approach to solve this is to test how many tokens result from \token_to_str:N \a. the \if:w test is true.\__int_value:w \fi: \exp_after:wN \c_zero } (End definition for \cs_to_str:N.as a second character for the test. \token_to_str:N␣\␣ yields the escape character itself and a space. When the escape character is printable. The last case is that the escape character is itself a space. The initial \__int_to_roman:w then sees 0. which is not a terminated number. The second case is that the escape character is not printable. then performs \token_to_str:N. one for signature.\__cs_split_function:NN \__cs_split_function_auxi:w \__cs_split_function_auxii:w This function takes a function name and splits it into name with the escape char removed and argument specification. then the signature #2. In addition to this. \__cs_get_function_signature:N 1095 \cs_set:Npn \__cs_get_function_name:N #1 1096 { \__cs_split_function:NN #1 \use_i:nnn } 1097 \cs_set:Npn \__cs_get_function_signature:N #1 1098 { \__cs_split_function:NN #1 \use_ii:nnn } (End definition for \__cs_get_function_name:N and \__cs_get_function_signature:N. 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 \group_begin: \tex_lccode:D ‘\@ = ‘\: \scan_stop: \tex_catcode:D ‘\@ = 12 ~ \tex_lowercase:D { \group_end: \cs_set:Npn \__cs_split_function:NN #1 { \exp_after:wN \exp_after:wN \exp_after:wN \__cs_split_function_auxi:w \cs_to_str:N #1 \q_mark \c_true_bool @ \q_mark \c_false_bool \q_stop } \cs_set:Npn \__cs_split_function_auxi:w #1 @ #2 \q_mark #3#4 \q_stop #5 { \__cs_split_function_auxii:w #5 #1 \q_mark \q_stop {#2} #3 } \cs_set:Npn \__cs_split_function_auxii:w #1#2 \q_mark #3 \q_stop { #1 {#2} } } (End definition for \__cs_split_function:NN. and #4 cleans up until \q_stop. the auxiliary takes as #1 the function name. Lastly. This function is documented on page 25. We can’t use a literal : because it has the wrong catcode here. Otherwise. A control sequence is said to be 229 . First ensure that we actually get a properly evaluated string by expanding \cs_to_str:N twice. if the original function had no colon). If the function contained a colon.) 3. and one for the boolean. so it’s transformed from @ with \tex_lowercase:D. one for name. then \c_true_bool as #3. the second argument of \__cs_split_function:NN is supposed to be a function taking three variables. delimited by \q_mark. #3 is \c_false_bool. a third argument. delimited by the first colon. In both cases. #5 is the hprocessori.) \__cs_get_function_name:N Simple wrappers.8 Exist or free A control sequence is said to exist (to be used) if has an entry in the hash table and its meaning is different from the primitive \relax token. \__cs_split_function:NN \foo_bar:cnx \use_i:nnn as input becomes \use_i:nnn {foo_bar} {cnx} \c_true_bool. a boolean htruei or hfalsei is returned with htruei for when there is a colon in the function and hfalsei if there is not. the #1 contains the function name and \q_mark \c_true_bool. #2 is empty. The second auxiliary trims the trailing \q_mark from the function name if present (that is. For example. and #4 cleans up. T . There is no problem when inputting something like \else: or \fi: as TEX will only ever skip input in case the token tested against is \scan_stop:. 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 \prg_set_conditional:Npnn \cs_if_exist:N #1 { p .) \cs_if_free_p:N \cs_if_free_p:c \cs_if_free:NTF \cs_if_free:cTF The logical reversal of the above. These functions are documented on page ??. F . F . F . 1127 1128 1129 1130 1131 1132 1133 \prg_set_conditional:Npnn \cs_if_free:N #1 { p . TF } { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: \prg_return_false: \else: \prg_return_true: \fi: } \prg_return_false: } (End definition for \cs_if_exist:N and \cs_if_exist:c. we ensure that the second test is performed after the first one has concluded completely. 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 \prg_set_conditional:Npnn \cs_if_exist:c #1 { p . TF } { \if_meaning:w #1 \scan_stop: \prg_return_true: \else: \if_cs_exist:N #1 \prg_return_false: 230 . T . For the N form we firstly check for \scan_stop: and then if it is in the hash table. \cs_if_exist_p:N \cs_if_exist_p:c \cs_if_exist:NTF \cs_if_exist:cTF Two versions for checking existence.free (to be defined) if it does not already exist. Therefore. TF } { \if_meaning:w #1 \scan_stop: \prg_return_false: \else: \if_cs_exist:N #1 \prg_return_true: \else: \prg_return_false: \fi: \fi: } For the c form we firstly check if it is in the hash table and then for \scan_stop: so that we do not add it to the hash table unless it was already there. T . Here we have to be careful as the text to be skipped if the first test is false may contain tokens that disturb the scanner. . These functions are documented on page ??. 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 \cs_set:Npn \cs_if_exist_use:NTF #1#2 { \cs_if_exist:NTF #1 { #1 #2 } } \cs_set:Npn \cs_if_exist_use:NF #1 { \cs_if_exist:NTF #1 { #1 } } \cs_set:Npn \cs_if_exist_use:NT #1 #2 { \cs_if_exist:NTF #1 { #1 #2 } { } } \cs_set:Npn \cs_if_exist_use:N #1 { \cs_if_exist:NTF #1 { #1 } { } } \cs_set:Npn \cs_if_exist_use:cTF #1#2 { \cs_if_exist:cTF {#1} { \use:c {#1} \cs_set:Npn \cs_if_exist_use:cF #1 { \cs_if_exist:cTF {#1} { \use:c {#1} \cs_set:Npn \cs_if_exist_use:cT #1#2 { \cs_if_exist:cTF {#1} { \use:c {#1} \cs_set:Npn \cs_if_exist_use:c #1 { \cs_if_exist:cTF {#1} { \use:c {#1} #2 } } } } #2 } { } } } { } } (End definition for \cs_if_exist_use:N and \cs_if_exist_use:c. For the c variants. functions cannot be implemented as conditionals because the true branch must leave both the control sequence itself and the true code in the input stream.) \cs_if_exist_use:NTF \cs_if_exist_use:cTF \cs_if_exist_use:N \cs_if_exist_use:c The \cs_if_exist_use:.1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 \else: \prg_return_true: \fi: \fi: } \prg_set_conditional:Npnn \cs_if_free:c #1 { p . F .. we are careful not to put the control sequence in the hash table if it does not exist. TF } { \if_cs_exist:w #1 \cs_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \exp_after:wN \if_meaning:w \cs:w #1 \cs_end: \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } { \prg_return_true: } } (End definition for \cs_if_free:N and \cs_if_free:c. T .) 231 . These functions are documented on page ??. This can only happen if a coding error is made by the team.. We have to make sure we don’t put the argument into the conditional processing since it may be an \if. The definitions here are only temporary. The second type of defining functions doesn’t check if the argument is already defined. On the one hand we have functions that check if their argument doesn’t already exist._new. they are called \. \iow_log:x \iow_term:x We define a routine to write only to the log file. Before we can define them.9 Defining and checking (new) functions We provide two kinds of functions that can be used to define control sequences.) \__msg_kernel_error:nnxx \__msg_kernel_error:nnx \__msg_kernel_error:nn If an internal error occurs before LATEX3 has loaded l3msg then the code should issue a usable if terse error message and halt.~internal~LaTeX3~error! ^^J ^^J Module ~ #1 . If it is. and \__msg_kernel_error:nn. These will be redefined later by l3io.) \__chk_if_free_cs:N \__chk_if_free_cs:c This command is called by \cs_new_nopar:Npn and \cs_new_eq:NN etc.3. 1191 1192 \cs_set_nopar:Npn \msg_line_context: { on~line~ \tex_the:D \tex_inputlineno:D } (End definition for \msg_line_context:.. These functions are documented on page ??. 1171 1172 1173 1174 \cs_set_protected_nopar:Npn \iow_log:x { \tex_immediate:D \tex_write:D \c_minus_one } \cs_set_protected_nopar:Npn \iow_term:x { \tex_immediate:D \tex_write:D \c_sixteen } (End definition for \iow_log:x and \iow_term:x. type function! 232 . Otherwise an error message is issued. This function is documented on page 141.. And a similar one for writing to both the log file and the terminal. ~ message~name~"#2": ^^J Arguments~’#3’~and~’#4’ ^^J ^^J This~is~one~for~The~LaTeX3~Project:~bailing~out } \tex_end:D } \cs_set_protected:Npn \__msg_kernel_error:nnx #1#2#3 { \__msg_kernel_error:nnxx {#1} {#2} {#3} { } } \cs_set_protected:Npn \__msg_kernel_error:nn #1#2 { \__msg_kernel_error:nnxx {#1} {#2} { } { } } (End definition for \__msg_kernel_error:nnxx . they will be redefined later on.. It checks if hcsnamei is undefined or \scan_stop:. we need some auxiliary macros that allow us to generate error messages.) \msg_line_context: Another one from l3msg which will be altered later. to make sure that the argument sequence is not already in use. an error is signalled. 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 \cs_set_protected:Npn \__msg_kernel_error:nnxx #1#2#3#4 { \tex_errmessage:D { !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!~! ^^J Argh. \__msg_kernel_error:nnx . so this is a reasonable response. ) \__chk_if_exist_cs:N \__chk_if_exist_cs:c This function issues an error message when the control sequence in its argument does not exist.) 3.10 \cs_new_nopar:Npn \cs_new_nopar:Npx \cs_new:Npn \cs_new:Npx \cs_new_protected_nopar:Npn \cs_new_protected_nopar:Npx \cs_new_protected:Npn \cs_new_protected:Npx More new definitions Function which check that the control sequence is free before defining it. 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 \cs_set_protected:Npn \__chk_if_exist_cs:N #1 { \cs_if_exist:NF #1 { \__msg_kernel_error:nnx { kernel } { command-not-defined } { \token_to_str:N #1 } } } \cs_set_protected_nopar:Npn \__chk_if_exist_cs:c { \exp_args:Nc \__chk_if_exist_cs:N } (End definition for \__chk_if_exist_cs:N and \__chk_if_exist_cs:c.1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 \cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } h*packagei \tex_ifodd:D \l@expl@log@functions@bool \cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } } \fi: h/packagei \cs_set_protected_nopar:Npn \__chk_if_free_cs:c { \exp_args:Nc \__chk_if_free_cs:N } (End definition for \__chk_if_free_cs:N and \__chk_if_free_cs:c. 1226 1227 1228 1229 1230 1231 1232 \cs_set:Npn \__cs_tmp:w #1#2 { \cs_set_protected:Npn #1 ##1 { \__chk_if_free_cs:N ##1 #2 ##1 } 233 . ) 234 . These functions are documented on page ??. 1242 1243 1244 1245 1246 1247 1248 1249 \cs_set:Npn \__cs_tmp:w #1#2 { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } \__cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn \__cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx \__cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn \__cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx \__cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn \__cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx (End definition for \cs_set_nopar:cpn and others. \cs_set_nopar:cpnhstringihrep-texti will turn hstringi into a csname and then assign hrep-texti to it by using \cs_set_nopar:Npn. These functions are documented on page ??.) \cs_set_nopar:cpn \cs_set_nopar:cpx \cs_gset_nopar:cpn \cs_gset_nopar:cpx \cs_new_nopar:cpn \cs_new_nopar:cpx Like \cs_set_nopar:Npn and \cs_new_nopar:Npn. see the expansion module). except that the first argument consists of the sequence of characters that should be used to form the name of the desired control sequence (the c stands for csname argument. This means that there might be a parameter string between the two arguments. 1256 1257 1258 1259 1260 1261 \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:cpx \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:cpx \cs_new_protected_nopar:cpn \cs_new_protected_nopar:cpx \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npx \cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:Npx \cs_new_protected_nopar:Npn \cs_new_protected_nopar:Npx (End definition for \cs_set_protected_nopar:cpn and others. We may also do this globally. These functions are documented on page ??.1233 1234 1235 1236 1237 1238 1239 1240 1241 } \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \cs_new_nopar:Npn \cs_new_nopar:Npx \cs_new:Npn \cs_new:Npx \cs_new_protected_nopar:Npn \cs_new_protected_nopar:Npx \cs_new_protected:Npn \cs_new_protected:Npx \cs_gset_nopar:Npn \cs_gset_nopar:Npx \cs_gset:Npn \cs_gset:Npx \cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:Npx \cs_gset_protected:Npn \cs_gset_protected:Npx (End definition for \cs_new_nopar:Npn and others.) \cs_set:cpn \cs_set:cpx \cs_gset:cpn \cs_gset:cpx \cs_new:cpn \cs_new:cpx Variants of the \cs_set:Npn versions which make a csname out of the first arguments. 1250 1251 1252 1253 1254 1255 \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \cs_set:cpn \cs_set:cpx \cs_gset:cpn \cs_gset:cpx \cs_new:cpn \cs_new:cpx \cs_set:Npn \cs_set:Npx \cs_gset:Npn \cs_gset:Npx \cs_new:Npn \cs_new:Npx (End definition for \cs_set:cpn and others. Global versions are also provided.) \cs_set_protected_nopar:cpn \cs_set_protected_nopar:cpx \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:cpx \cs_new_protected_nopar:cpn \cs_new_protected_nopar:cpx Variants of the \cs_set_protected_nopar:Npn versions which make a csname out of the first arguments. We may also do this globally. These functions are documented on page ??. The c variant is careful not to add the control sequence to the hash table if it isn’t there yet. We may also do this globally. The = sign allows us to define funny char tokens like = itself or ␣ with this function. 1262 1263 1264 1265 1266 1267 \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \cs_set_protected:cpn \cs_set_protected:cpx \cs_gset_protected:cpn \cs_gset_protected:cpx \cs_new_protected:cpn \cs_new_protected:cpx \cs_set_protected:Npn \cs_set_protected:Npx \cs_gset_protected:Npn \cs_gset_protected:Npx \cs_new_protected:Npn \cs_new_protected:Npx (End definition for \cs_set_protected:cpn and others.) 3.) 3. and it also avoids nesting TEX conditionals in case #1 is unbalanced in this matter.11 \cs_set_eq:NN \cs_set_eq:cN \cs_set_eq:Nc \cs_set_eq:cc \cs_gset_eq:NN \cs_gset_eq:cN \cs_gset_eq:Nc \cs_gset_eq:cc \cs_new_eq:NN \cs_new_eq:cN \cs_new_eq:Nc \cs_new_eq:cc Copying definitions These macros allow us to copy the definition of a control sequence to another control sequence. 1284 1285 1286 1287 \cs_new_protected:Npn \cs_undefine:N #1 { \cs_gset_eq:NN #1 \tex_undefined:D } \cs_new_protected:Npn \cs_undefine:c #1 { 235 . These functions are documented on page ??. 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 \cs_new_protected:Npn \cs_set_eq:NN #1 { \tex_let:D #1 =~ } \cs_new_protected_nopar:Npn \cs_set_eq:cN { \exp_args:Nc \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_set_eq:Nc { \exp_args:NNc \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_set_eq:cc { \exp_args:Ncc \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:NN { \tex_global:D \cs_set_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:Nc { \exp_args:NNc \cs_gset_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:cN { \exp_args:Nc \cs_gset_eq:NN } \cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_new_eq:NN #1 { \__chk_if_free_cs:N #1 \tex_global:D \cs_set_eq:NN #1 } \cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } \cs_new_protected_nopar:Npn \cs_new_eq:Nc { \exp_args:NNc \cs_new_eq:NN } \cs_new_protected_nopar:Npn \cs_new_eq:cc { \exp_args:Ncc \cs_new_eq:NN } (End definition for \cs_set_eq:NN and others. define it long in order to throw an “already defined” error rather than “runaway argument”. These functions are documented on page ??. \cs_set_eq:NN is long to avoid problems with a literal argument of \par.12 \cs_undefine:N \cs_undefine:c Undefining functions The following function is used to free the main memory from the definition of some function that isn’t in use any longer. For the definition of \c_space_char{~} to work we need the ~ after the =. While \cs_new_eq:NN will probably never be correct with a first argument of \par.\cs_set_protected:cpn \cs_set_protected:cpx \cs_gset_protected:cpn \cs_gset_protected:cpx \cs_new_protected:cpn \cs_new_protected:cpx Variants of the \cs_set_protected:Npn versions which make a csname out of the first arguments. . #n}. If the second argument gives a result outside the range [0. but will be defined before this function is called.) 3. 9]. untouched. between 0 and 9. 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 \cs_set_protected:Npn \__cs_parm_from_arg_count:nnF #1#2 { \exp_args:Nx \__cs_parm_from_arg_count_test:nnF { \exp_after:wN \exp_not:n \if_case:w \__int_eval:w #2 \__int_eval_end: { } \or: { ##1 } \or: { ##1##2 } \or: { ##1##2##3 } \or: { ##1##2##3##4 } \or: { ##1##2##3##4##5 } \or: { ##1##2##3##4##5##6 } \or: { ##1##2##3##4##5##6##7 } \or: { ##1##2##3##4##5##6##7##8 } \or: { ##1##2##3##4##5##6##7##8##9 } \else: { \c_false_bool } \fi: } {#1} } \cs_set_protected:Npn \__cs_parm_from_arg_count_test:nnF #1#2 { \if_meaning:w \c_false_bool #1 \exp_after:wN \use_ii:nn \else: \exp_after:wN \use_i:nn \fi: { #2 {#1} } } 236 . where n is the result of evaluating the second argument (as described in \int_eval:n).13 Generating parameter text from argument count \__cs_parm_from_arg_count:nnF LATEX3 provides shorthands to define control sequences and conditionals with a simple \__cs_parm_from_arg_count_test:nnF parameter text. . Some of the functions use here are not defined yet. derived directly from the signature. normally an error message. followed by a brace group containing the parameter text {#1. or more generally from knowing the number of arguments. the third argument is returned instead.\if_cs_exist:w #1 \cs_end: \exp_after:wN \use:n \else: \exp_after:wN \use_none:n \fi: { \cs_gset_eq:cN {#1} \tex_undefined:D } 1288 1289 1290 1291 1292 1293 } 1294 (End definition for \cs_undefine:N and \cs_undefine:c. These functions are documented on page ??. This function expands to its first argument. This function is documented on page ??. 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 \cs_new:Npn \__cs_count_signature:N #1 { \int_eval:n { \__cs_split_function:NN #1 \__cs_count_signature:nnN } } \cs_new:Npn \__cs_count_signature:nnN #1#2#3 { \if_meaning:w \c_true_bool #3 \tl_count:n {#2} \else: \c_minus_one \fi: } \cs_new_nopar:Npn \__cs_count_signature:c { \exp_args:Nc \__cs_count_signature:N } (End definition for \__cs_count_signature:N and \__cs_count_signature:c. These functions are documented on page ??. ensuring the result is returned after finishing the conditional. Since this is not used in any time-critical function. Since TEX supports from zero to nine arguments. For this we need to choose the correct parameter text and then use that when \cs_generate_from_arg_count:Ncnn defining. the number of arguments the function should take. we use a simple switch to choose the correct parameter text.(End definition for \__cs_parm_from_arg_count:nnF. If it is not between zero and nine. 1346 1347 1348 1349 \cs_new_protected_nopar:Npn \cs_generate_from_arg_count:cNnn { \exp_args:Nc \cs_generate_from_arg_count:NNnn } \cs_new_protected_nopar:Npn \cs_generate_from_arg_count:Ncnn { \exp_args:NNc \cs_generate_from_arg_count:NNnn } (End definition for \cs_generate_from_arg_count:NNnn . plus one which is used elsewhere but which is most logically created here.14 \__cs_count_signature:N \__cs_count_signature:c \__cs_count_signature:nnN Defining functions from a given number of arguments Counting the number of tokens in the signature. 1: function to define. we throw an error.. \cs_generate_from_arg_count:cNnn . and \cs_generate_from_arg_count:Ncnn. we simply use \tl_count:n if there is a signature. 2: with what to define it. otherwise −1 arguments to signal an error. We need a variant form right away. i. These functions are documented on page ??.) 237 . 3: the number of args it requires and 4: the replacement text 1337 1338 1339 1340 1341 1342 1343 1344 1345 \cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 { \__cs_parm_from_arg_count:nnF { \use:nnn #2 #1 } {#3} { \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } { \token_to_str:N #1 } { \int_eval:n {#3} } } {#4} } A variant form we need right away.e.) \cs_generate_from_arg_count:NNnn We provide a constructor function for defining functions with a given number of argu\cs_generate_from_arg_count:cNnn ments.) 3. e. to define \cs_set:Nn we need just use \cs_set:Npn. Therefore. the number of arguments is read from the signature. we can make it simpler by temporarily defining a function to do this for us. We define some simpler functions with user interface \cs_set:Nn \foo_bar:nn {#1. 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 \cs_set:Npn \__cs_tmp:w #1#2#3 { \cs_new_protected_nopar:cpx { cs_ #1 : #2 } { \exp_not:N \__cs_generate_from_signature:NNn \exp_after:wN \exp_not:N \cs:w cs_ #1 : #3 \cs_end: } } \cs_new_protected:Npn \__cs_generate_from_signature:NNn #1#2 { \__cs_split_function:NN #2 \__cs_generate_from_signature:nnNNNn #1 #2 } \cs_new_protected:Npn \__cs_generate_from_signature:nnNNNn #1#2#3#4#5#6 { \bool_if:NTF #3 { \cs_generate_from_arg_count:NNnn #5 #4 { \tl_count:n {#2} } {#6} } { \__msg_kernel_error:nnx { kernel } { missing-colon } { \token_to_str:N #5 } } } Then we define the 24 variants beginning with N..#2}. 1375 1376 1377 1378 1379 1380 \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w { { { { { { set } set } set_nopar } set_nopar } set_protected } set_protected } { { { { { { 238 Nn Nx Nn Nx Nn Nx } } } } } } { { { { { { Npn Npx Npn Npx Npn Npx } } } } } } .3. \cs_set:Nn \cs_set:Nx \cs_set_nopar:Nn \cs_set_nopar:Nx \cs_set_protected:Nn \cs_set_protected:Nx \cs_set_protected_nopar:Nn \cs_set_protected_nopar:Nx \cs_gset:Nn \cs_gset:Nx \cs_gset_nopar:Nn \cs_gset_nopar:Nx \cs_gset_protected:Nn \cs_gset_protected:Nx \cs_gset_protected_nopar:Nn \cs_gset_protected_nopar:Nx \cs_new:Nn \cs_new:Nx \cs_new_nopar:Nn \cs_new_nopar:Nx \cs_new_protected:Nn \cs_new_protected:Nx \cs_new_protected_nopar:Nn \cs_new_protected_nopar:Nx We want to define \cs_set:Nn as \cs_set_protected:Npn \cs_set:Nn #1#2 { \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn { \__cs_count_signature:N #1 } {#2} } In short. i.15 Using the signature to define functions We can now combine some of the tools we have to provide a simple interface for defining functions. everything else is the same for each variant. 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w \__cs_tmp:w { { { { { { { { { { { { { { { { { { set_protected_nopar } set_protected_nopar } gset } gset } gset_nopar } gset_nopar } gset_protected } gset_protected } gset_protected_nopar } gset_protected_nopar } new } new } new_nopar } new_nopar } new_protected } new_protected } new_protected_nopar } new_protected_nopar } { { { { { { { { { { { { { { { { { { Nn Nx Nn Nx Nn Nx Nn Nx Nn Nx Nn Nx Nn Nx Nn Nx Nn Nx } } } } } } } } } } } } } } } } } } { { { { { { { { { { { { { { { { { { Npn Npx Npn Npx Npn Npx Npn Npx Npn Npx Npn Npx Npn Npx Npn Npx Npn Npx } } } } } } } } } } } } } } } } } } (End definition for \cs_set:Nn and others.) \cs_set:cn \cs_set:cx \cs_set_nopar:cn \cs_set_nopar:cx \cs_set_protected:cn \cs_set_protected:cx \cs_set_protected_nopar:cn \cs_set_protected_nopar:cx \cs_gset:cn \cs_gset:cx \cs_gset_nopar:cn \cs_gset_nopar:cx \cs_gset_protected:cn \cs_gset_protected:cx \cs_gset_protected_nopar:cn \cs_gset_protected_nopar:cx \cs_new:cn \cs_new:cx \cs_new_nopar:cn \cs_new_nopar:cx \cs_new_protected:cn \cs_new_protected:cx \cs_new_protected_nopar:cn \cs_new_protected_nopar:cx The 24 c variants simply use \exp_args:Nc. 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 \cs_set:Npn \__cs_tmp:w #1#2 { \cs_new_protected_nopar:cpx { cs_ #1 : c #2 } { \exp_not:N \exp_args:Nc \exp_after:wN \exp_not:N \cs:w cs_ #1 : N #2 \cs_end: } } \__cs_tmp:w { set } { n } \__cs_tmp:w { set } { x } \__cs_tmp:w { set_nopar } { n } \__cs_tmp:w { set_nopar } { x } \__cs_tmp:w { set_protected } { n } \__cs_tmp:w { set_protected } { x } \__cs_tmp:w { set_protected_nopar } { n } \__cs_tmp:w { set_protected_nopar } { x } \__cs_tmp:w { gset } { n } \__cs_tmp:w { gset } { x } \__cs_tmp:w { gset_nopar } { n } \__cs_tmp:w { gset_nopar } { x } \__cs_tmp:w { gset_protected } { n } \__cs_tmp:w { gset_protected } { x } \__cs_tmp:w { gset_protected_nopar } { n } \__cs_tmp:w { gset_protected_nopar } { x } \__cs_tmp:w { new } { n } \__cs_tmp:w { new } { x } \__cs_tmp:w { new_nopar } { n } \__cs_tmp:w { new_nopar } { x } \__cs_tmp:w { new_protected } { n } 239 . These functions are documented on page ??. The odd-looking \use:n gives a nicer output. T . Thus.17 \__kernel_register_show:N \__kernel_register_show:c Diagnostic functions Check that the variable exists. The output of this primitive is mimicked to some extent: a line-break is added after the first colon in the meaning (this is what TEX does for macros and five \. simply using TEX’s primitive \show could lead to overlong lines. 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 \cs_new_protected:Npn \__kernel_register_show:N #1 { \cs_if_exist:NTF #1 { \tex_showthe:D \use:n {#1} } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_protected_nopar:Npn \__kernel_register_show:c { \exp_args:Nc \__kernel_register_show:N } (End definition for \__kernel_register_show:N and \__kernel_register_show:c.1428 1429 1430 \__cs_tmp:w { new_protected } \__cs_tmp:w { new_protected_nopar } \__cs_tmp:w { new_protected_nopar } { x } { n } { x } (End definition for \cs_set:cn and others.) \cs_show:N \cs_show:c \__cs_show:www Some control sequences have a very long name or meaning. then apply the \showthe primitive to the variable. TF } { \if_meaning:w #1#2 \prg_return_true: \else: \prg_return_false: \fi: } \cs_new_nopar:Npn \cs_if_eq_p:cN { \exp_args:Nc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:cNTF { \exp_args:Nc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:cNT { \exp_args:Nc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:cNF { \exp_args:Nc \cs_if_eq:NNF } \cs_new_nopar:Npn \cs_if_eq_p:Nc { \exp_args:NNc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:NcTF { \exp_args:NNc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:NcT { \exp_args:NNc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:NcF { \exp_args:NNc \cs_if_eq:NNF } \cs_new_nopar:Npn \cs_if_eq_p:cc { \exp_args:Ncc \cs_if_eq_p:NN } \cs_new_nopar:Npn \cs_if_eq:ccTF { \exp_args:Ncc \cs_if_eq:NNTF } \cs_new_nopar:Npn \cs_if_eq:ccT { \exp_args:Ncc \cs_if_eq:NNT } \cs_new_nopar:Npn \cs_if_eq:ccF { \exp_args:Ncc \cs_if_eq:NNF } (End definition for \cs_if_eq:NN and others.) 3.) 3.mark primitives).16 \cs_if_eq_p:NN \cs_if_eq_p:cN \cs_if_eq_p:Nc \cs_if_eq_p:cc \cs_if_eq:NNTF \cs_if_eq:cNTF \cs_if_eq:NcTF \cs_if_eq:ccTF Checking control sequence equality Check if two control sequences are identical.. Then the re-built string is given 240 . F . These functions are documented on page ??. 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 \prg_new_conditional:Npnn \cs_if_eq:NN #1#2 { p .. These functions are documented on page ??. 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 \group_begin: \tex_lccode:D ‘? = ‘: \scan_stop: \tex_catcode:D ‘? = 12 \scan_stop: \tex_lowercase:D { \group_end: \cs_new_protected:Npn \cs_show:N #1 { \__msg_show_variable:n { > ~ \token_to_str:N #1 = \exp_after:wN \__cs_show:www \cs_meaning:N #1 \use_none:nn ? \prg_do_nothing: } } \cs_new:Npn \__cs_show:www #1 ? { #1 ? \\ } } \cs_new_protected_nopar:Npn \cs_show:c { \group_begin: \exp_args:NNc \group_end: \cs_show:N } (End definition for \cs_show:N and \cs_show:c. 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 \cs_new_eq:NN \luatex_if_engine:T \use_none:n \cs_new_eq:NN \luatex_if_engine:F \use:n \cs_new_eq:NN \luatex_if_engine:TF \use_ii:nn \cs_new_eq:NN \pdftex_if_engine:T \use:n \cs_new_eq:NN \pdftex_if_engine:F \use_none:n \cs_new_eq:NN \pdftex_if_engine:TF \use_i:nn \cs_new_eq:NN \xetex_if_engine:T \use_none:n \cs_new_eq:NN \xetex_if_engine:F \use:n \cs_new_eq:NN \xetex_if_engine:TF \use_ii:nn \cs_new_eq:NN \luatex_if_engine_p: \c_false_bool \cs_new_eq:NN \pdftex_if_engine_p: \c_true_bool \cs_new_eq:NN \xetex_if_engine_p: \c_false_bool \cs_if_exist:NT \xetex_XeTeXversion:D { \cs_gset_eq:NN \pdftex_if_engine:T \use_none:n \cs_gset_eq:NN \pdftex_if_engine:F \use:n \cs_gset_eq:NN \pdftex_if_engine:TF \use_ii:nn \cs_gset_eq:NN \xetex_if_engine:T \use:n \cs_gset_eq:NN \xetex_if_engine:F \use_none:n \cs_gset_eq:NN \xetex_if_engine:TF \use_i:nn \cs_gset_eq:NN \pdftex_if_engine_p: \c_false_bool 241 . These functions are documented on page ??.18 \xetex_if_engine_p: \luatex_if_engine_p: \pdftex_if_engine_p: \xetex_if_engine:TF \luatex_if_engine:TF \pdftex_if_engine:TF Engine specific definitions In some cases it will be useful to know which engine we’re running. This can all be hard-coded for speed.) 3.to \iow_wrap:nnnN for line-wrapping. The \cs_show:c command converts its argument to a control sequence within a group to avoid showing \relax for undefined control sequences. TF } { \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \str_if_eq:nn and \str_if_eq_x:nn. This test is similar to \str_if_eq:nnTF. and \pdftex_if_engine:. This set of conditionals therefore make life a bit clearer. 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 \prg_new_conditional:Npnn \str_if_eq:nn #1#2 { p . This function is documented on page 9. and return with \prg_return_true/false:.19 \prg_do_nothing: Doing nothing functions This does not fit anywhere else! 1512 \cs_new_nopar:Npn \prg_do_nothing: { } (End definition for \prg_do_nothing:.20 \str_if_eq_p:nn \str_if_eq_x_p:nn \str_if_eq:nnTF \str_if_eq_x:nnTF String comparisons Modern engines provide a direct way of comparing two token lists. The nn and xx versions are created directly as this is most efficient. These functions are documented on page 23.) 3.) 3. F . F . \luatex_if_engine: . T . TF } { \if_int_compare:w \pdftex_strcmp:D { \exp_not:n {#1} } { \exp_not:n {#2} } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \str_if_eq_x:nn #1#2 { p . These should eventually move somewhere else. but hard-coded for speed.1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 \cs_gset_eq:NN \xetex_if_engine_p: } \cs_if_exist:NT \luatex_directlua:D { \cs_gset_eq:NN \luatex_if_engine:T \cs_gset_eq:NN \luatex_if_engine:F \cs_gset_eq:NN \luatex_if_engine:TF \cs_gset_eq:NN \pdftex_if_engine:T \cs_gset_eq:NN \pdftex_if_engine:F \cs_gset_eq:NN \pdftex_if_engine:TF \cs_gset_eq:NN \luatex_if_engine_p: \cs_gset_eq:NN \pdftex_if_engine_p: } \c_true_bool \use:n \use_none:n \use_i:nn \use_none:n \use:n \use_ii:nn \c_true_bool \c_false_bool (End definition for \xetex_if_engine: .) \__str_if_eq_x_return:nn It turns out that we often need to compare a token list with the result of applying some function to it. These functions are documented on page 22. T . but returning a number. 1524 1525 1526 1527 1528 \cs_new:Npn \__str_if_eq_x_return:nn #1 #2 { \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero \prg_return_true: \else: 242 . There is a check that we close the correct loop. otherwise we continue breaking.) \str_case:nnn \str_case_x:nnn \__prg_case_end:nw \__str_case:nw \__str_case_x:nw \__str_case_end:nw No calculations for strings. These functions are documented on page 25. before the user’s code (if any). 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 \cs_new:Npn \str_case:nnn #1#2#3 { \tex_romannumeral:D \__str_case:nw {#1} #2 {#1} {#3} \q_recursion_stop } \cs_new:Npn \__str_case:nw #1#2#3 { \str_if_eq:nnTF {#1} {#2} { \__str_case_end:nw {#3} } { \__str_case:nw {#1} } } \cs_new:Npn \str_case_x:nnn #1#2#3 { \tex_romannumeral:D \__str_case_x:nw {#1} #2 {#1} {#3} \q_recursion_stop } \cs_new:Npn \__str_case_x:nw #1#2#3 { \str_if_eq_x:nnTF {#1} {#2} { \__str_case_end:nw {#3} } { \__str_case_x:nw {#1} } } Here. The breaking functions are then defined to jump to that point and perform the argument of \__prg_break_point:Nn. 1554 1555 \cs_new:Npn \__prg_case_end:nw #1#2 \q_recursion_stop { \c_zero #1 } \cs_new_eq:NN \__str_case_end:nw \__prg_case_end:nw (End definition for \str_case:nnn and \str_case_x:nnn. #2 will be any remaining case or cases. #1 will be the code needed. and the \c_zero stops the \romannumeral. the nesting level must be reset at the end of the mapping.) 3. even when the user decides to break out.\prg_return_false: \fi: 1529 1530 } 1531 (End definition for \__str_if_eq_x_return:nn.21 \__prg_break_point:Nn \__prg_map_break:Nn Breaking out of mapping functions In inline mappings. otherwise no surprises. This is done by putting the code that must be performed as an argument of \__prg_break_point:Nn. 1556 1557 1558 1559 1560 1561 \cs_new_eq:NN \__prg_break_point:Nn \use_ii:nn \cs_new:Npn \__prg_map_break:Nn #1#2#3 \__prg_break_point:Nn #4#5 { #5 \if_meaning:w #1 #4 \exp_after:wN \use_iii:nnn 243 . do not need to support nesting.22 Deprecated functions Deprecated on 2011-05-27. 1565 1566 1567 \cs_new_eq:NN \__prg_break_point: \prg_do_nothing: \cs_new:Npn \__prg_break: #1 \__prg_break_point: { } \cs_new:Npn \__prg_break:n #1#2 \__prg_break_point: {#1} (End definition for \__prg_break_point:.) 3. 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \cs_gnew_nopar:Npn \cs_gnew:Npn \cs_gnew_protected_nopar:Npn \cs_gnew_protected:Npn \cs_gnew_nopar:Npx \cs_gnew:Npx \cs_gnew_protected_nopar:Npx \cs_gnew_protected:Npx \cs_gnew_nopar:cpn \cs_gnew:cpn \cs_gnew_protected_nopar:cpn \cs_gnew_protected:cpn \cs_gnew_nopar:cpx \cs_gnew:cpx \cs_gnew_protected_nopar:cpx \cs_gnew_protected:cpx h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \cs_gnew_eq:NN \cs_gnew_eq:cN \cs_gnew_eq:Nc \cs_gnew_eq:cc \cs_new_nopar:Npn \cs_new:Npn \cs_new_protected_nopar:Npn \cs_new_protected:Npn \cs_new_nopar:Npx \cs_new:Npx \cs_new_protected_nopar:Npx \cs_new_protected:Npx \cs_new_nopar:cpn \cs_new:cpn \cs_new_protected_nopar:cpn \cs_new_protected:cpn \cs_new_nopar:cpx \cs_new:cpx \cs_new_protected_nopar:cpx \cs_new_protected:cpx h*deprecatedi \cs_new_eq:NN \cs_gundefine:N \cs_new_eq:NN \cs_gundefine:c h/deprecatedi \cs_new_eq:NN \cs_new_eq:cN \cs_new_eq:Nc \cs_new_eq:cc \cs_undefine:N \cs_undefine:c h*deprecatedi \cs_new_eq:NN \group_execute_after:N \group_insert_after:N h/deprecatedi 244 . for removal by 2011-08-31. These functions are documented on page 43. for use in fast short-term recursions which are not mappings. This function is documented on page ??.) \__prg_break_point: \__prg_break: \__prg_break:n Very simple analogues of \__prg_break_point:Nn and \__prg_map_break:Nn. and in which nothing has to be done at the end of the loop.\fi: \__prg_map_break:Nn #1 {#2} 1562 1563 } 1564 (End definition for \__prg_break_point:Nn and \__prg_map_break:Nn. ) 1622 h/initex | packagei 245 . These functions are documented on page ??. and we want to de-emphasize the use of primitive TEX conditionals.) \use_i_after_fi:nw \use_i_after_else:nw \use_i_after_or:nw \use_i_after_orelse:nw These functions return the first argument after ending the conditional.) Deprecated 2011-09-07. These functions are documented on page ??.Deprecated 2011-09-06.) Deprecated 2012-06-05 for removal after 2012-12-31. 1604 1605 1606 1607 1608 1609 h*deprecatedi \cs_set:Npn \cs_set:Npn \cs_set:Npn \cs_set:Npn h/deprecatedi \use_i_after_fi:nw #1 \fi: { \fi: #1 } \use_i_after_else:nw #1 \else: #2 \fi: { \fi: #1 } \use_i_after_or:nw #1 \or: #2 \fi: { \fi: #1 } \use_i_after_orelse:nw #1#2#3 \fi: { \fi: #1 } (End definition for \use_i_after_fi:nw and others. \str_if_eq_p:xx \str_if_eq:xxTF Not really true x-type expansion 1613 1614 1615 1616 1617 1618 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \str_if_eq_p:xx \str_if_eq:xxT \str_if_eq:xxF \str_if_eq:xxTF \str_if_eq_x_p:nn \str_if_eq_x:nnT \str_if_eq_x:nnF \str_if_eq_x:nnTF (End definition for \str_if_eq:xx. \c_pdftex_is_engine_bool \c_luatex_is_engine_bool \c_xetex_is_engine_bool Predicates are better 1599 1600 1601 1602 1603 h*deprecatedi \cs_new_eq:NN \c_luatex_is_engine_bool \luatex_if_engine_p: \cs_new_eq:NN \c_pdftex_is_engine_bool \pdftex_if_engine_p: \cs_new_eq:NN \c_xetex_is_engine_bool \xetex_if_engine_p: h/deprecatedi (End definition for \c_pdftex_is_engine_bool . This function is documented on page ??.) \chk_if_free_cs:N 1619 1620 1621 h*deprecatedi \cs_new_eq:NN \chk_if_free_cs:N \__chk_if_free_cs:N h/deprecatedi (End definition for \chk_if_free_cs:N. and \c_xetex_is_engine_bool. \c_luatex_is_engine_bool . These variables are documented on page ??. \cs_set_eq:NwN 1610 1611 1612 h*deprecatedi \tex_let:D \cs_set_eq:NwN \tex_let:D h/deprecatedi (End definition for \cs_set_eq:NwN. for removal by 2011-12-31. This is rather specialized. This function is documented on page ??. for removal by 2011-12-31. which has to grab an argument delimited by a left brace. This is just a reminder that that is the case! (End definition for \l__exp_internal_tl. This variable is documented on page 34. 1630 1631 \cs_new:Npn \__exp_arg_next:nnn #1#2#3 { #2 \::: { #3 {#1} } } \cs_new:Npn \__exp_arg_next:Nnn #1#2#3 { #2 \::: { #3 #1 } } (End definition for \__exp_arg_next:nnn. Actually.) This code uses internal functions with names that start with \:: to perform the expansions. These general expansion functions are expandable unless x is used. This auxiliary function moves #1 back after #3 in the input stream and checks if any expansion is left to be done by calling #2. #2 is the remaining argument manipulations and #3 is the current result of the expansion chain.) \::: The end marker is just another name for the identity function. typically using calls to \exp_after:wN. so far only the c of the final argument manipulation variants does not require a set of braces. (End definition for \exp_after:wN. This function is documented on page 33.2 some common cases are coded by a more direct method for efficiency.4 l3expan implementation 1623 h*initex | packagei 1624 h@@=expi We start by ensuring that the required packages are loaded. 1632 \cs_new:Npn \::: #1 {#1} 246 . and so is never going to be expandable. \l__exp_internal_tl This scratch token list variable is defined in l3basics. In by far the most cases we will require to add a set of braces to the result of an argument manipulation so it is more effective to do it directly here. (Any version of x is going to have to use one of the LATEX3 names for \cs_set_nopar:Npx at some point. One exception to this rule is \::p.) 4. as it is needed “early”. 1625 1626 1627 1628 1629 \exp_after:wN \exp_not:N \exp_not:n h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei These are defined in l3basics. An argument manipulator \::hZ i always has signature #1\:::#2#3 where #1 holds the remaining argument manipulations to be performed.3.) The definition of expansion functions with this technique happens in section 4. This function is documented on page 34. In section 4.1 General expansion In this section a general mechanism for defining functions to handle argument handling is defined. All macros are long as this turned out to be desirable since the tokens undergoing expansion may be arbitrary user input. \::: serves as an end marker for the list of manipulations. \__exp_arg_next:nnn \__exp_arg_next:Nnn #1 is the result of an expansion step. #2 is the carried over result of the previous expansion steps and #3 is the argument about to be processed. This scanning procedure is terminated once the expansion hits something non-expandable or a space. We introduce \exp_stop_f: to mark such an end of expansion marker.) \::o This function is used to expand an argument once.) \::N This function is used to skip an argument that consists of a single token and doesn’t need to be expanded. 1634 \cs_new:Npn \::N #1 \::: #2#3 { #1 \::: {#2#3} } (End definition for \::N. 1636 1637 \cs_new:Npn \::c #1 \::: #2#3 { \exp_after:wN \__exp_arg_next:Nnn \cs:w #3 \cs_end: {#1} {#2} } (End definition for \::c. In the example shown earlier the scanning was stopped once TEX had fully expanded \cs_set_eq:Nc \aaa { b \l_tmpa_tl b } into \cs_set_eq:NN \aaa = \blurb which then turned out to contain the non-expandable token \cs_set_eq:NN. only TEX has not tried to execute any of the non-expandable tokens. 1633 \cs_new:Npn \::n #1 \::: #2#3 { #1 \::: { #2 {#3} } } (End definition for \::n. this number also terminates the scanning and is left untouched.) 247 .) \::c This function is used to skip an argument that is turned into a control sequence without expansion.(End definition for \:::.) \::n This function is used to skip an argument that doesn’t need to be expanded. This is what differentiates this function from the x argument type. 1635 \cs_new:Npn \::p #1 \::: #2#3# { #1 \::: {#2#3} } (End definition for \::p. This function is documented on page 33.) \::p This function is used to skip an argument that is delimited by a left brace and doesn’t need to be expanded. we wind up with a fully expanded list. 1640 1641 1642 1643 1644 1645 1646 \cs_new:Npn \::f #1 \::: #2#3 { \exp_after:wN \__exp_arg_next:nnn \exp_after:wN { \tex_romannumeral:D -‘0 #3 } {#1} {#2} } \use:nn { \cs_new_eq:NN \exp_stop_f: } { ~ } (End definition for \::f. in case the scanner hits a number. Since the expansion of \romannumeral -‘0 is hnulli. It should not be wrapped in braces in the result. 1638 1639 \cs_new:Npn \::o #1 \::: #2#3 { \exp_after:wN \__exp_arg_next:nnn \exp_after:wN {#3} {#1} {#2} } (End definition for \::o. The underlying \romannumeral -‘0 expands everything in its way to find something terminating the number and thereby expands the function in front of it.) \::f \exp_stop_f: This function is used to expand a token list until the first unexpandable token is found. \::x This function is used to expand an argument fully. which we will terminate using \c_zero.) \::v \::V These functions return the value of a register. This function is documented on page 34. i. If it is a macro. We could let TEX do it for us but that would result in the rather obscure ! You can’t use ‘\relax’ after \the. 1647 1648 1649 1650 1651 \cs_new_protected:Npn \::x #1 \::: #2#3 { \cs_set_nopar:Npx \l__exp_internal_tl { {#3} } \exp_after:wN \__exp_arg_next:nnn \l__exp_internal_tl {#1} {#2} } (End definition for \::x. skip. dim and muskip. The technique is to compare the meaning of the register in question when it has been prefixed with \exp_not:N and the register itself. In that case we throw an error. one of tl.) \__exp_eval_register:N \__exp_eval_register:c \__exp_eval_error_msg:w This function evaluates a register. The trick is to find out when to use \the and when not to. Now a register might exist as one of two things: A parameter-less macro or a built-in TEX register such as \count. 1664 1665 1666 \cs_new:Npn \__exp_eval_register:N #1 { \exp_after:wN \if_meaning:w \exp_not:N #1 #1 If the token was not a macro it may be a malformed variable from a c expansion in which case it is equal to the primitive \scan_stop:. clist. which while quite true doesn’t give many hints as to what actually went wrong. For the TEX registers we have to utilize a \the whereas for the macros we merely have to expand them once. int. 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 \cs_new:Npn \::V #1 \::: #2#3 { \exp_after:wN \__exp_arg_next:nnn \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #3 } {#1} {#2} } \cs_new:Npn \::v # 1\::: #2#3 { \exp_after:wN \__exp_arg_next:nnn \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:c {#3} } {#1} {#2} } (End definition for \::v. What we do here is try to find out whether the token will expand to something else when hit with \exp_after:wN. The argument is returned in braces. the prefixed \exp_not:N will temporarily turn it into the primitive \scan_stop:. The primitive \romannumeral sets off an expansion similar to an f type expansion.e. The V version expects a single token whereas v like c creates a csname from its argument given in braces and then evaluates it as if it was a V. 1667 1668 1669 \if_meaning:w \scan_stop: #1 \__exp_eval_error_msg:w \fi: 248 . We provide something more sensible.. This function is documented on page 31.55 \tl_set:Nv \l_tmpa_tl {undefined_tl} 1677 1678 1679 1680 1681 1682 1683 \cs_new:Npn \__exp_eval_error_msg:w #1 \tex_the:D #2 { \fi: \fi: \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2} \c_zero } (End definition for \__exp_eval_register:N and \__exp_eval_register:c. (End definition for \exp_args:Nc and \exp_args:cc. <argument> \LaTeX3 error: Erroneous variable used! l. If it is a TEX register.) 249 .) \exp_args:Nc \exp_args:cc In l3basics. \exp_args:No \exp_args:NNo \exp_args:NNNo Those lovely runs of expansion! 1684 1685 1686 1687 1688 \cs_new:Npn \exp_args:No #1#2 { \exp_after:wN #1 \exp_after:wN {#2} } \cs_new:Npn \exp_args:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN {#3} } \cs_new:Npn \exp_args:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN#2 \exp_after:wN #3 \exp_after:wN {#4} } (End definition for \exp_args:No. we have to expand the register #1 before we do that. These functions are documented on page ??. The result is an error message looking like this: ! Undefined control sequence. 1670 1671 1672 1673 1674 1675 1676 \else: \exp_after:wN \use_i_ii:nnn \fi: \exp_after:wN \c_zero \tex_the:D #1 } \cs_new:Npn \__exp_eval_register:c #1 { \exp_after:wN \__exp_eval_register:N \cs:w #1 \cs_end: } Clean up nicely. we need to execute the sequence \exp_after:wN \c_zero \tex_the:D #1 and if it is a macro we need to execute \exp_after:wN \c_zero #1. we remove the \tex_the:D. These functions are documented on page ??. The function must be initiated by the primitive \romannumeral and we want to terminate this expansion chain by inserting the \c_zero integer constant.2 Hand-tuned definitions One of the most important features of these functions is that they are fully expandable and therefore allow to prefix them with \tex_global:D for example. then call the undefined control sequence. However. We therefore issue the longer of the two sequences and if the register is a macro.) 4.The next bit requires some explanation. and \exp_args:Nv. \exp_args:NV .) \exp_args:Nf \exp_args:NV \exp_args:Nv 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 \cs_new:Npn \exp_args:Nf #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D -‘0 #2 } } \cs_new:Npn \exp_args:Nv #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:c {#2} } } \cs_new:Npn \exp_args:NV #1#2 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #2 } } (End definition for \exp_args:Nf . 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 \cs_new:Npn \exp_args:NNf #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D -‘0 #3 } } \cs_new:Npn \exp_args:NNv #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:c {#3} } } \cs_new:Npn \exp_args:NNV #1#2#3 { \exp_after:wN #1 250 .) \exp_args:NNV \exp_args:NNv \exp_args:NNf \exp_args:NVV \exp_args:Ncf \exp_args:Nco Some more hand-tuned function with three arguments.\exp_args:NNc \exp_args:Ncc \exp_args:Nccc Here are the functions that turn their argument into csnames but are expandable. 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 \cs_new:Npn \exp_args:NNc #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 \cs:w # 3\cs_end: } \cs_new:Npn \exp_args:Ncc #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \cs:w #3 \cs_end: } \cs_new:Npn \exp_args:Nccc #1#2#3#4 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \cs:w #3 \exp_after:wN \cs_end: \cs:w #4 \cs_end: } (End definition for \exp_args:NNc . These functions are documented on page 30. If we forced that an o argument always has braces. we could implement \exp_args:Nco with less tokens and only two arguments. and \exp_args:Nccc. \exp_args:Ncc . These functions are documented on page ??. ) \exp_args:Ncco \exp_args:NcNc \exp_args:NcNo \exp_args:NNNV A few more that we can hand-tune.1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 \exp_after:wN #2 \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #3 } } \cs_new:Npn \exp_args:Nco #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN {#3} } \cs_new:Npn \exp_args:Ncf #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN { \tex_romannumeral:D -‘0 #3 } } \cs_new:Npn \exp_args:NVV #1#2#3 { \exp_after:wN #1 \exp_after:wN { \tex_romannumeral:D \exp_after:wN \__exp_eval_register:N \exp_after:wN #2 \exp_after:wN } \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #3 } } (End definition for \exp_args:NNV and others. These functions are documented on page ??. 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 \cs_new:Npn \exp_args:NNNV #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #4 } } \cs_new:Npn \exp_args:NcNc #1#2#3#4 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN #3 \cs:w #4 \cs_end: } \cs_new:Npn \exp_args:NcNo #1#2#3#4 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \exp_after:wN #3 \exp_after:wN {#4} } \cs_new:Npn \exp_args:Ncco #1#2#3#4 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: 251 . but the complexity of coding then becomes an issue.3 Definitions with the automated technique Some of these could be done more efficiently.) 252 . \exp_args:Nx 1777 \cs_new_protected_nopar:Npn \exp_args:Nx { \::x \::: } (End definition for \exp_args:Nx. using the helper functions above.) \exp_args:NNno \exp_args:NNoo \exp_args:Nnnc \exp_args:Nnno \exp_args:Nooo \exp_args:NNnx \exp_args:NNox \exp_args:Nnnx \exp_args:Nnox \exp_args:Nccx \exp_args:Ncnx \exp_args:Noox 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 \cs_new_nopar:Npn \exp_args:NNno { \::N \::n \cs_new_nopar:Npn \exp_args:NNoo { \::N \::o \cs_new_nopar:Npn \exp_args:Nnnc { \::n \::n \cs_new_nopar:Npn \exp_args:Nnno { \::n \::n \cs_new_nopar:Npn \exp_args:Nooo { \::o \::o \cs_new_protected_nopar:Npn \exp_args:NNnx { \cs_new_protected_nopar:Npn \exp_args:NNox { \cs_new_protected_nopar:Npn \exp_args:Nnnx { \cs_new_protected_nopar:Npn \exp_args:Nnox { \cs_new_protected_nopar:Npn \exp_args:Nccx { \cs_new_protected_nopar:Npn \exp_args:Ncnx { \cs_new_protected_nopar:Npn \exp_args:Noox { \::o \::o \::c \::o \::o \::N \::N \::n \::n \::c \::c \::o \::: \::: \::: \::: \::: \::n \::o \::n \::o \::c \::n \::o } } } } } \::x \::x \::x \::x \::x \::x \::x \::: \::: \::: \::: \::: \::: \::: } } } } } } } (End definition for \exp_args:NNno and others. These functions are documented on page ??.) \exp_args:Nnc \exp_args:Nfo \exp_args:Nff \exp_args:Nnf \exp_args:Nno \exp_args:NnV \exp_args:Noo \exp_args:Nof \exp_args:Noc \exp_args:NNx \exp_args:Ncx \exp_args:Nnx \exp_args:Nox \exp_args:Nxo \exp_args:Nxx Here are the actual function definitions. These functions are documented on page ??. This function is documented on page 30.) 4. Notice that the auto-generated functions are all not long: they don’t actually take any arguments themselves. These functions are documented on page ??. 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 \cs_new_nopar:Npn \exp_args:Nnc { \::n \::c \cs_new_nopar:Npn \exp_args:Nfo { \::f \::o \cs_new_nopar:Npn \exp_args:Nff { \::f \::f \cs_new_nopar:Npn \exp_args:Nnf { \::n \::f \cs_new_nopar:Npn \exp_args:Nno { \::n \::o \cs_new_nopar:Npn \exp_args:NnV { \::n \::V \cs_new_nopar:Npn \exp_args:Noo { \::o \::o \cs_new_nopar:Npn \exp_args:Nof { \::o \::f \cs_new_nopar:Npn \exp_args:Noc { \::o \::c \cs_new_protected_nopar:Npn \exp_args:NNx { \cs_new_protected_nopar:Npn \exp_args:Ncx { \cs_new_protected_nopar:Npn \exp_args:Nnx { \cs_new_protected_nopar:Npn \exp_args:Nox { \cs_new_protected_nopar:Npn \exp_args:Nxo { \cs_new_protected_nopar:Npn \exp_args:Nxx { \::: \::: \::: \::: \::: \::: \::: \::: \::: \::N \::c \::n \::o \::x \::x } } } } } } } } } \::x \::x \::x \::x \::o \::x \::: \::: \::: \::: \::: \::: } } } } } } (End definition for \exp_args:Nnc and others.\cs:w #3 \exp_after:wN \cs_end: \exp_after:wN {#4} 1774 1775 1776 } (End definition for \exp_args:Ncco and others. but the general system is in place. 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 \cs_new:Npn \exp_last_unbraced:NV #1#2 { \exp_after:wN #1 \tex_romannumeral:D \__exp_eval_register:N #2 } \cs_new:Npn \exp_last_unbraced:Nv #1#2 { \exp_after:wN #1 \tex_romannumeral:D \__exp_eval_register:c {#2} } \cs_new:Npn \exp_last_unbraced:No #1#2 { \exp_after:wN #1 #2 } \cs_new:Npn \exp_last_unbraced:Nf #1#2 { \exp_after:wN #1 \tex_romannumeral:D -‘0 #2 } \cs_new:Npn \exp_last_unbraced:Nco #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: #3 } \cs_new:Npn \exp_last_unbraced:NcV #1#2#3 { \exp_after:wN #1 \cs:w #2 \exp_after:wN \cs_end: \tex_romannumeral:D \__exp_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNV #1#2#3 { \exp_after:wN #1 253 .) \exp_last_unbraced:NV \exp_last_unbraced:Nv \exp_last_unbraced:Nf \exp_last_unbraced:No \exp_last_unbraced:Nco \exp_last_unbraced:NcV \exp_last_unbraced:NNV \exp_last_unbraced:NNo \exp_last_unbraced:NNNV \exp_last_unbraced:NNNo \exp_last_unbraced:Nno \exp_last_unbraced:Noo \exp_last_unbraced:Nfo \exp_last_unbraced:NnNo \exp_last_unbraced:Nx Now the business end: most of these are hand-tuned for speed. 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 \cs_new:Npn \__exp_arg_last_unbraced:nn #1#2 { #2#1 } \cs_new:Npn \::f_unbraced \::: #1#2 { \exp_after:wN \__exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D -‘0 #2 } {#1} } \cs_new:Npn \::o_unbraced \::: #1#2 { \exp_after:wN \__exp_arg_last_unbraced:nn \exp_after:wN {#2} {#1} } \cs_new:Npn \::V_unbraced \::: #1#2 { \exp_after:wN \__exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #2 } {#1} } \cs_new:Npn \::v_unbraced \::: #1#2 { \exp_after:wN \__exp_arg_last_unbraced:nn \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:c {#2} } {#1} } \cs_new_protected:Npn \::x_unbraced \::: #1#2 { \cs_set_nopar:Npx \l__exp_internal_tl { \exp_not:n {#1} #2 } \l__exp_internal_tl } (End definition for \__exp_arg_last_unbraced:nn. This function is documented on page ??.4. First some helper macros.4 \__exp_arg_last_unbraced:nn \::f_unbraced \::o_unbraced \::V_unbraced \::v_unbraced \::x_unbraced Last-unbraced versions There are a few places where the last argument needs to be available unbraced. for robustness this is not suitable.1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 \exp_after:wN #2 \tex_romannumeral:D \__exp_eval_register:N #3 } \cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 #3 } \cs_new:Npn \exp_last_unbraced:NNNV #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \tex_romannumeral:D \__exp_eval_register:N #4 } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 } \cs_new_nopar:Npn \exp_last_unbraced:Nno { \::n \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Noo { \::o \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Nfo { \::f \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NnNo { \::n \::N \::o_unbraced \::: } \cs_new_protected_nopar:Npn \exp_last_unbraced:Nx { \::x_unbraced \::: } (End definition for \exp_last_unbraced:NV.5 \exp_not:o \exp_not:c \exp_not:f \exp_not:V \exp_not:v 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 Preventing expansion \cs_new:Npn \exp_not:o #1 { \etex_unexpanded:D \exp_after:wN {#1} } \cs_new:Npn \exp_not:c #1 { \exp_after:wN \exp_not:N \cs:w #1 \cs_end: } \cs_new:Npn \exp_not:f #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D -‘0 #1 } } \cs_new:Npn \exp_not:V #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \__exp_eval_register:N #1 } } \cs_new:Npn \exp_not:v #1 { \etex_unexpanded:D \exp_after:wN 254 . 1865 1866 1867 1868 \cs_new:Npn \exp_last_two_unbraced:Noo #1#2#3 { \exp_after:wN \__exp_last_two_unbraced:noN \exp_after:wN {#3} {#2} #1 } \cs_new:Npn \__exp_last_two_unbraced:noN #1#2#3 { \exp_after:wN #3 #2 #1 } (End definition for \exp_last_two_unbraced:Noo.) 4. a bit of a shuffle is used to ensure that #2 can be multiple tokens.) \exp_last_two_unbraced:Noo \__exp_last_two_unbraced:noN If #2 is a single token then this can be implemented as \cs_new:Npn \exp_last_two_unbraced:Noo #1 #2 #3 { \exp_after:wN \exp_after:wN \exp_after:wN #1 \exp_after:wN #2 #3 } However. Instead. This function is documented on page 32. This function is documented on page 32. ) 4. Then we wish to iterate through the comma list of variant argument specifiers. always protected).) \__cs_generate_variant:N \__cs_generate_variant:ww \__cs_generate_variant:wwNw The goal here is to pick up protected parent functions. the first \q_mark is taken as an argument of the wwNw auxiliary. This function is documented on page 33. 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 \cs_new_protected:Npn \cs_generate_variant:Nn #1#2 { \__chk_if_exist_cs:N #1 \__cs_generate_variant:N #1 \exp_after:wN \__cs_split_function:NN \exp_after:wN #1 \exp_after:wN \__cs_generate_variant:nnNN \exp_after:wN #1 \etex_detokenize:D {#2} . 1894 1895 1896 1897 1898 1899 \group_begin: \tex_catcode:D \tex_catcode:D \tex_catcode:D \tex_catcode:D \tex_lowercase:D ‘\M ‘\A ‘\P ‘\R = = = = 12 12 12 12 \scan_stop: \scan_stop: \scan_stop: \scan_stop: 255 . which we first convert to a string: the reason is explained later. e.cx} After making sure that the base form exists. \first. We use ma rather than the full macro because the meaning of the \firstmark primitive (and four others) can contain an arbitrary string after a leading firstmark:. The ww auxiliary removes everything in the meaning string after the first ma. For non-expandable primitives. look for pr in the part we extracted: no need to look for anything longer: the only strings we can have are an empty string. \splittop. \top.c. otherwise it is \cs_new_nopar:Npx. Then. and #3 is \cs_new_protected_nopar:Npx. and can be expandable or not. \protected␣. which is then used to define all the variants (except those involving x-expansion. \long␣. The other case where variants should be protected is when the parent function is a protected macro: then protected appears in the meaning before the fist occurrence of macro.g. Split up the original base function only once. test whether it is protected or not and define \__cs_tmp:w as either \cs_new_nopar:Npx or \cs_new_protected_nopar:Npx. \scan_stop: . {Nx. There are four cases: the parent function can be a primitive or a macro. \protected\long␣.g. with \ replaced by the appropriate escape character. skipping the \else: branch is safe because all primitive TEX conditionals are expandable. This function is documented on page 28. or \splitbot. \bot.. to grab its name and signature. e.. all variants should be protected.6 1883 \cs_generate_variant:Nn Defining function variants h@@=csi #1 : Base form of a function. \q_recursion_stop } (End definition for \cs_generate_variant:Nn. If pr appears in the part before ma.{ \tex_romannumeral:D \__exp_eval_register:c {#1} } 1881 1882 } (End definition for \exp_not:o. \tl_set:Nn #2 : One or more variant argument specifiers. Base function. otherwise. Base signature.) \__cs_generate_variant:nnNN Base name.) \__cs_generate_variant:Nnnw Base function. construct a new function name using the original base name. If the boolean is \c_false_bool. Boolean. for each variant form. The original function is retained as #4 for efficiency. Beginning of variant signature.1900 { \group_end: \cs_new_protected:Npn \__cs_generate_variant:N #1 { \exp_after:wN \if_meaning:w \exp_not:N #1 #1 \cs_set_eq:NN \__cs_tmp:w \cs_new_protected_nopar:Npx \else: \exp_after:wN \__cs_generate_variant:ww \token_to_meaning:N #1 MA \q_mark \q_mark \cs_new_protected_nopar:Npx PR \q_mark \cs_new_nopar:Npx \q_stop \fi: } \cs_new_protected:Npn \__cs_generate_variant:ww #1 MA #2 \q_mark { \__cs_generate_variant:wwNw #1 } \cs_new_protected:Npn \__cs_generate_variant:wwNw #1 PR #2 \q_mark #3 #4 \q_stop { \cs_set_eq:NN \__cs_tmp:w #3 } 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 } (End definition for \__cs_generate_variant:N. Base name. the base function has no colon and we abort with an error. This function is documented on page 28. First check whether to terminate the loop over variant forms. Base signature. #1 #2 #3 #4 : : : : 1923 1924 1925 1926 1927 1928 1929 1930 1931 \cs_new_protected:Npn \__cs_generate_variant:nnNN #1#2#3#4 { \if_meaning:w \c_false_bool #3 \__msg_kernel_error:nnx { kernel } { missing-colon } { \token_to_str:c {#1} } \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \__cs_generate_variant:Nnnw #4 {#1}{#2} } (End definition for \__cs_generate_variant:nnNN. Then. the variant signature #1 #2 #3 #4 : : : : 256 . set off a loop through the desired variant forms. ) 257 . because we do not have a means to replace o-expansion by x-expansion. followed by some clean-up code (\use_none:nnnn). not \exp_args:Nox. For example. rather than a hypothetical \exp_args:NxxTF. Only n and N-type arguments can be replaced by \cs_generate_variant:Nn. All this boils down to a few rules. 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 \cs_new_protected:Npn \__cs_generate_variant:Nnnw #1#2#3#4 . { \if_meaning:w \scan_stop: #4 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: \use:x { \exp_not:N \__cs_generate_variant:wwNN \__cs_generate_variant_loop:nNwN { } #4 \__cs_generate_variant_loop_end:nwwwNNnn \q_mark #3 ~ { ~ { } \fi: \__cs_generate_variant_loop_long:wNNnn } ~ { } \q_stop \exp_not:N #1 {#2} {#4} } \__cs_generate_variant:Nnnw #1 {#2} {#3} } (End definition for \__cs_generate_variant:Nnnw. We compare the base and variant signatures one character at a time within xexpansion.consisting of l letters and the last k − l letters of the base signature (of length k). The result is given to \__cs_generate_variant:wwNN in the form hprocessed variant signaturei \q_mark herrorsi \q_stop hbase functioni hnew functioni. Other argument types are allowed to be passed unchanged from the base form to the variant: in the process they are changed to n (except for two cases: N and p-type arguments). Those are ignored by TEX when fetching the last argument for \__cs_generate_variant_loop:nNwN. the function \foo:ox should be defined using \exp_args:Nnx. A common trailing part is ignored. If all went well. • In \cs_generate_variant:Nn \foo:on {ox}. herrorsi is empty. \cs_generate_variant:Nn \foo:on {xn} should trigger an error. we wish to trim a common trailing part from the base signature and the variant signature. otherwise. Note the space after #3 and after the following brace group. we want the new signature to be cVn. but can be used as a delimiter for \__cs_generate_variant_loop_end:nwwwNNnn. There are further subtleties: • In \cs_generate_variant:Nn \foo:nnTF {xxTF}. it would be better to define \foo:xxTF using \exp_args:Nxx. • Lastly. for a base function \prop_put:Nnn which needs a cV variant form. it is a kernel error message. Thus. to avoid double o expansion. which inserts some tokens to end the conditional. call \__cs_generate_variant_loop_invalid:NNwNNnn to remove the end of the loop. 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 \cs_new:Npn \__cs_generate_variant_loop:nNwN #1#2#3 \q_mark #4 { \if:w #2 #4 \exp_after:wN \__cs_generate_variant_loop_same:w \else: \if:w N #4 \else: \if:w n #4 \else: \__cs_generate_variant_loop_invalid:NNwNNnn #4#2 \fi: \fi: 258 . Note that if the variant form has the same length as the base form. leave in the input stream whatever argument was collected. The case where the two letters are different is only allowed with a base letter of N or n. \__cs_generate_variant_same:N hletteri for each letter). which places an error as the second argument of \__cs_generate_variant:wwNN. #3 : Remainder of variant form. namely when the variant and base letters differ and the base is neither n nor N. • The loop can be interrupted early if the requested expansion is unavailable. get arguments at the end of the loop. #2 is \__cs_generate_variant_loop_end:nwwwNNnn (expanded by the conditional \if:w). and combines those into the hnew functioni to be defined. • If the end of the base form is encountered first. the argument is dropped. The loop can stop in three ways. and the next variant letter #2. Again. If the letters are distinct and the base letter is indeed n or N. and #4 as described in the second point above.\__cs_generate_variant_loop:nNwN \__cs_generate_variant_loop_same:w \__cs_generate_variant_loop_end:nwwwNNnn \__cs_generate_variant_loop_long:wNNnn \__cs_generate_variant_loop_invalid:NNwNNnn #1 : Last few (consecutive) letters common between the base and variant (in fact. and place an appropriate error message as a second argument of \__cs_generate_variant:wwNN. • If the end of the variant form is encountered first. It is flushed into the input stream whenever the two letters are different: if the loop ends before. #4 : Next base letter. then loop by calling \__cs_generate_variant_loop:nNwN. grabs the hbase namei as #7. followed by \__cs_generate_variant_loop_long:wNNnn. which means that trailing common letters are ignored. the hvariant signaturei #8. #2 : Next variant letter. the hnext base letteri #1 and the part #3 of the base signature that wasn’t read yet. Otherwise. an error is placed as the second argument of \__cs_generate_variant:wwNN. The first argument is populated by \__cs_generate_variant_loop_same:w when a variant letter and a base letter match. The \__cs_generate_variant_loop_end:nwwwNNnn breaking function takes the empty brace group in #4 as its first argument: this empty brace group produces the correct signature for the full variant. #4 is ~{}\fi: which ends the conditional (with an empty expansion). #2 is as described in the first point. ) 259 .1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 \fi: #1 \prg_do_nothing: #2 \__cs_generate_variant_loop:nNwN { } #3 \q_mark } \cs_new:Npn \__cs_generate_variant_loop_same:w #1 \prg_do_nothing: #2#3#4 { #3 { #1 \__cs_generate_variant_same:N #2 } } \cs_new:Npn \__cs_generate_variant_loop_end:nwwwNNnn #1#2 \q_mark #3 ~ #4 \q_stop #5#6#7#8 { \scan_stop: \scan_stop: \fi: \exp_not:N \q_mark \exp_not:N \q_stop \exp_not:N #6 \exp_not:c { #7 : #8 #1 #3 } } \cs_new:Npn \__cs_generate_variant_loop_long:wNNnn #1 \q_stop #2#3#4#5 { \exp_not:n { \q_mark \__msg_kernel_error:nnxx { kernel } { variant-too-long } {#5} { \token_to_str:N #3 } \use_none:nnnn \q_stop #3 #3 } } \cs_new:Npn \__cs_generate_variant_loop_invalid:NNwNNnn #1#2 \fi: \fi: \fi: #3 \q_stop #4#5#6#7 { \fi: \fi: \fi: \exp_not:n { \q_mark \__msg_kernel_error:nnxxxx { kernel } { invalid-variant } {#7} { \token_to_str:N #5 } {#1} {#2} \use_none:nnnn \q_stop #5 #5 } } (End definition for \__cs_generate_variant_loop:nNwN and others. change \__cs_tmp:w locally to \cs_new_protected_nopar:Npx. For most argument types. the result should be protected. Otherwise. If #1 contains an x (this is the place where having converted the original \__cs_generate_internal_variant_loop:n comma-list argument to a string is very important). we can use the n-type no-expansion. 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 \cs_new_protected:Npn \__cs_generate_variant:wwNN #1 \q_mark #2 \q_stop #3#4 { #2 \cs_if_free:NTF #4 { \group_begin: \__cs_generate_internal_variant:n {#1} \__cs_tmp:w #4 { \exp_not:c { exp_args:N #1 } \exp_not:N #3 } \group_end: } { \iow_log:x { Variant~\token_to_str:N #4~% already~defined. log its existence. but the N and p types require a slightly different behaviour with respect to braces. Then define the variant by combining the \exp_args:N #3 variant and the base function. 2042 \group_begin: 260 .~ not~ changing~ it~on~line~% \tex_the:D \tex_inputlineno:D } } } (End definition for \__cs_generate_variant:wwNN. 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 \cs_new:Npn \__cs_generate_variant_same:N #1 { \if:w N #1 N \else: \if:w p #1 p \else: n \fi: \fi: } (End definition for \__cs_generate_variant_same:N.) \__cs_generate_variant:wwNN If the variant form has already been defined. and if it contains x.) \__cs_generate_internal_variant:n Test if \exp_args:N #1 is already defined and if not define it via the \:: commands using \__cs_generate_internal_variant:wwnw the chars in #1. don’t do any expansion.\__cs_generate_variant_same:N When the base and variant letters are identical. make sure that the \exp_args:N #3 form is defined. and the next variant to be defined using that internal variant should be protected. } . ... We avoid tests by putting a trailing : \use_i:nn.) 4. . . This function is documented on page ??. } . 2073 2074 2075 2076 2077 2078 2079 2080 2081 \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \str_if_eq_p:nn \str_if_eq_p:nn \str_if_eq:nnT \str_if_eq:nnT \str_if_eq:nnF \str_if_eq:nnF \str_if_eq:nnTF \str_if_eq:nnTF \str_case:nnn { 261 { { { { { { { { o V nV V nV V nV V nV } . o no o no o no o no } . VV } VV } VV } VV } . . which leaves \cs_end: and removes the looping macro. .7 \str_if_eq_p:Vn \str_if_eq_p:on \str_if_eq_p:nV \str_if_eq_p:no \str_if_eq_p:VV \str_if_eq:VnTF \str_if_eq:onTF \str_if_eq:nVTF \str_if_eq:noTF \str_if_eq:VVTF \str_case:onn Variants which cannot be created earlier These cannot come earlier as they need \cs_generate_variant:Nn. 2068 2069 2070 2071 2072 \cs_new:Npn \__cs_generate_internal_variant_loop:n #1 { \exp_after:wN \exp_not:N \cs:w :: #1 \cs_end: \__cs_generate_internal_variant_loop:n } (End definition for \__cs_generate_internal_variant:n. The colon is in fact also turned into \::: so that the required structure for \exp_args:N. .2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 \tex_catcode:D ‘\X = 12 \scan_stop: \tex_lccode:D ‘\N = ‘\N \scan_stop: \tex_lowercase:D { \group_end: \cs_new_protected:Npn \__cs_generate_internal_variant:n #1 { \__cs_generate_internal_variant:wwnNwnn #1 \q_mark { \cs_set_eq:NN \__cs_tmp:w \cs_new_protected_nopar:Npx } \cs_new_protected_nopar:cpx X \q_mark { } \cs_new_nopar:cpx \q_stop { exp_args:N #1 } { \__cs_generate_internal_variant_loop:n #1 { : \use_i:nn } } } \cs_new_protected:Npn \__cs_generate_internal_variant:wwnNwnn #1 X #2 \q_mark #3 #4 #5 \q_stop #6 #7 { #3 \cs_if_free:cT {#6} { #4 {#6} {#7} } } } This command grabs char by char outputting \::#1 (not expanded further). } . commands is correctly terminated. . m3prg003. as they are needed “early”.) 5. This is just a reminder that that is the case! (End definition for \prg_set_conditional:Npnn and others. 2089 2090 \tex_let:D \if_bool:N \tex_let:D \if_predicate:w \tex_ifodd:D \tex_ifodd:D (End definition for \if_bool:N.m3prg002.) 2082 5 h/initex | packagei l3prg implementation The following test files are used for this code: m3prg001.) \bool_set_true:N \bool_set_true:c \bool_gset_true:N \bool_gset_true:c \bool_set_false:N \bool_set_false:c \bool_gset_false:N \bool_gset_false:c Setting is already pretty easy.2 \prg_set_conditional:Npnn \prg_new_conditional:Npnn \prg_set_protected_conditional:Npnn \prg_new_protected_conditional:Npnn \prg_set_conditional:Nnn \prg_new_conditional:Nnn \prg_set_protected_conditional:Nnn \prg_new_protected_conditional:Nnn \bool_new:N \prg_set_eq_conditional:NNn \bool_new:c \prg_new_eq_conditional:NNn \prg_return_true: \prg_return_false: Defining a set of conditional functions These are all defined in l3basics. This function is documented on page 42.3 2091 The boolean data type h@@=booli Boolean variables have to be initiated when they are created.(End definition for \str_if_eq:Vn and others.) 5. 2092 2093 \cs_new_protected:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool } \cs_generate_variant:Nn \bool_new:N { c } (End definition for \bool_new:N and \bool_new:c. 2083 2084 2085 2086 2087 2088 5. These functions are documented on page 37. These functions are documented on page ??. These functions are documented on page ??. They should not be used outside the kernel code. Other than that there is not much to say here.lvt.lvt.lvt.1 \if_bool:N \if_predicate:w h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Primitive conditionals Those two primitive TEX conditionals are synonyms. 2094 2095 2096 2097 2098 2099 2100 \cs_new_protected:Npn \bool_set_true:N #1 { \cs_set_eq:NN #1 \c_true_bool } \cs_new_protected:Npn \bool_set_false:N #1 { \cs_set_eq:NN #1 \c_false_bool } \cs_new_protected:Npn \bool_gset_true:N #1 { \cs_gset_eq:NN #1 \c_true_bool } \cs_new_protected:Npn \bool_gset_false:N #1 262 . These functions are documented on page ??. We use \__msg_show_variable:n to get a better output. T . this function requires its argument to start with >~.) \bool_if_p:N \bool_if_p:c \bool_if:NTF \bool_if:cTF Straight forward here. as true or false. 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 \prg_new_conditional:Npnn \bool_if:N { \if_meaning:w \c_true_bool #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \bool_if_p:N \cs_generate_variant:Nn \bool_if:NT \cs_generate_variant:Nn \bool_if:NF \cs_generate_variant:Nn \bool_if:NTF #1 { p . 2106 2107 2108 2109 2110 2111 2112 2113 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \bool_set_eq:NN \bool_set_eq:Nc \bool_set_eq:cN \bool_set_eq:cc \bool_gset_eq:NN \bool_gset_eq:Nc \bool_gset_eq:cN \bool_gset_eq:cc \cs_set_eq:NN \cs_set_eq:Nc \cs_set_eq:cN \cs_set_eq:cc \cs_gset_eq:NN \cs_gset_eq:Nc \cs_gset_eq:cN \cs_gset_eq:cc (End definition for \bool_set_eq:NN and others. These functions are documented on page ??. These functions are documented on page ??. These functions are documented on page ??.) \bool_set_eq:NN \bool_set_eq:cN \bool_set_eq:Nc \bool_set_eq:cc \bool_gset_eq:NN \bool_gset_eq:cN \bool_gset_eq:Nc \bool_gset_eq:cc The usual copy code. 2114 2115 2116 2117 2118 2119 \cs_new_protected:Npn \bool_set:Nn #1#2 { \tex_chardef:D #1 = \bool_if_p:n {#2} } \cs_new_protected:Npn \bool_gset:Nn #1#2 { \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2} } \cs_generate_variant:Nn \bool_set:Nn { c } \cs_generate_variant:Nn \bool_gset:Nn { c } (End definition for \bool_set:Nn and \bool_set:cn. 2132 2133 \cs_new_protected:Npn \bool_show:N #1 { 263 .) \bool_show:N \bool_show:c \bool_show:n Show the truth value of the boolean. We could optimize here if we wanted to as the boolean can just be input directly.) \bool_set:Nn \bool_set:cn \bool_gset:Nn \bool_gset:cn This function evaluates a boolean expression and assigns the first argument the meaning \c_true_bool or \c_false_bool.2101 2102 2103 2104 2105 { \cs_gset_eq:NN #1 \c_false_bool } \cs_generate_variant:Nn \bool_set_true:N \cs_generate_variant:Nn \bool_set_false:N \cs_generate_variant:Nn \bool_gset_true:N \cs_generate_variant:Nn \bool_gset_false:N { { { { c c c c } } } } (End definition for \bool_set_true:N and others. F . TF } { { { { c c c c } } } } (End definition for \bool_if:N and \bool_if:c. And. 264 .) \bool_if_exist_p:N \bool_if_exist_p:c \bool_if_exist:NTF \bool_if_exist:cTF Copies of the cs functions defined in l3basics. Open and Close for these operations. F . 2152 2153 (End definition for \bool_if_exist:N and \bool_if_exist:c. \bool_show:c . T . T . • If a Not is seen. and \bool_show:n. which evaluates it to the boolean value htruei or hfalsei. remove the ! and call a GetNotNext function. F .) \l_tmpa_bool \l_tmpb_bool \g_tmpa_bool \g_tmpb_bool A few booleans just if you need them. && for logical “And” and || for logical “Or”. Evaluation happens from left to right in the following manner using a GetNext function: • If an Open is seen. p } \prg_new_eq_conditional:NNn \bool_if_exist:c \cs_if_exist:c { TF . Or. reinsert the token found (this is supposed to be a predicate function) in front of an Eval function. start evaluating a new expression using the Eval function and call GetNext again.2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 \bool_if_exist:NTF #1 { \bool_show:n {#1} } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_protected:Npn \bool_show:n #1 { \bool_if:nTF {#1} { \__msg_show_variable:n { > ~ true } } { \__msg_show_variable:n { > ~ false } } } \cs_generate_variant:Nn \bool_show:N { c } (End definition for \bool_show:N . These functions are documented on page 38. These functions are documented on page ??. 2148 2149 2150 2151 \bool_new:N \bool_new:N \bool_new:N \bool_new:N \l_tmpa_bool \l_tmpb_bool \g_tmpa_bool \g_tmpb_bool (End definition for \l_tmpa_bool and others. • If none of the above. p } Boolean expressions Evaluating the truth value of a list of predicates is done using an input syntax somewhat similar to the one found in other programming languages with ( and ) for grouping. These variables are documented on page 38. which eventually reverses the logic compared to GetNext.) 5. Any expression is terminated by a Close operation. ! for logical “Not”.4 \bool_if_p:n \bool_if:nTF \prg_new_eq_conditional:NNn \bool_if_exist:N \cs_if_exist:N { TF . We shall use the terms Not. The replacement is done in three passes. stop evaluating the predicates within this sub-expression and break to the nearest Close. return htruei. We introduce an additional Stop operation with the same semantics as the Close operation.) \bool_if_p:n First issue a \group_align_safe_begin: as we are using && as syntax shorthand for \__bool_if_left_parentheses:wwwn the And operation and we need to hide it for TEX. A trailing marker ensures that the auxiliaries’ delimited arguments will not run-away. Close seen. In each case the truth value is used to determine where to go next. This will be closed at the end of the \__bool_if_right_parentheses:wwwn expression parsing (see S below). These functions are documented on page 39. htrueiOr Current truth value is true. At each pass. hfalseiAnd Current truth value is false. Or or Close. Then return hfalsei. continue with GetNext to examine truth value of next boolean (sub-)expression. for left and right parentheses and for ||. Close seen. As long as 265 . the rest lies until the first \q_mark. we transform the boolean expression by doubling each parenthesis and adding parenthesis around each ||. TF } { \if_predicate:w \bool_if_p:n {#1} \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \bool_if:n. but to the next || or closing parenthesis when hfalsei&& is seen. This ensures that && will bind tighter than ||. logical And seen. stop evaluating the predicates within this sub-expression and break to the nearest Close. logical Or seen. logical Or seen. \__bool_if_or:wwwn Minimal (“short-circuit”) evaluation of boolean expressions requires skipping to the end of the current parenthesized group when htruei|| is seen.The Eval function then contains a post-processing operation which grabs the instruction following the predicate. htrueiClose Current truth value is true. The following situations can arise: htrueiAnd Current truth value is true. the part of the expression that has been transformed is stored before \q_nil. This is either And. F . logical And seen. return htruei. To avoid having separate functions for the two cases. followed by an empty brace group. htrueiStop Current truth value is true. The reasons for this follow below. hfalseiOr Current truth value is false. continue with GetNext to examine truth value of next boolean (sub-)expression. hfalseiClose Current truth value is false. return hfalsei. 2154 2155 2156 2157 2158 2159 2160 2161 \prg_new_conditional:Npnn \bool_if:n #1 { T . hfalseiStop Current truth value is false. Then return htruei. return hfalsei. ) \__bool_get_next:NN The GetNext operation. Afterwards. #4 is the next auxiliary. For this we call the Stop operation. start evaluating.) \__bool_if_parse:NNNww After removing extra tokens from the transformation phase. we will need to finish the special align_safe group before finally returning a \c_true_bool or \c_false_bool as there might otherwise be something left in front in the input stream. At the end. the trailing marker is taken as a delimiter. The last step calls \__bool_if_parse:NNNww which cleans up and triggers the evaluation of the expression itself. 2182 2183 2184 2185 2186 2187 2188 2189 2190 \cs_new:Npn \__bool_get_next:NN #1#2 { \use:c { __bool_ \if_meaning:w !#2 ! \else: \if_meaning:w (#2 ( \else: p \fi: \fi: :Nw } #1 #2 266 . 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 \cs_new:Npn \bool_if_p:n #1 { \group_align_safe_begin: \__bool_if_left_parentheses:wwwn \q_nil #1 \q_mark { } ( \q_mark { \__bool_if_right_parentheses:wwwn \q_nil } ) \q_mark { \__bool_if_or:wwwn \q_nil } || \q_mark \__bool_if_parse:NNNww \q_stop } \cs_new:Npn \__bool_if_left_parentheses:wwwn #1 \q_nil #2 ( #3 \q_mark #4 { #4 \__bool_if_left_parentheses:wwwn #1 #2 (( \q_nil #3 \q_mark {#4} } \cs_new:Npn \__bool_if_right_parentheses:wwwn #1 \q_nil #2 ) #3 \q_mark #4 { #4 \__bool_if_right_parentheses:wwwn #1 #2 )) \q_nil #3 \q_mark {#4} } \cs_new:Npn \__bool_if_or:wwwn #1 \q_nil #2 || #3 \q_mark #4 { #4 \__bool_if_or:wwwn #1 #2 )||( \q_nil #3 \q_mark {#4} } (End definition for \bool_if_p:n. otherwise it is \use_i:nn. we assume it is a predicate. material is moved before \q_nil and we continue. The first argument is \use_ii:nn if the logic must eventually be reversed (after a !). This function eventually expand to the truth value \c_true_bool or \c_false_bool of the expression which follows until the next unmatched closing parenthesis. 2178 2179 2180 2181 \cs_new:Npn \__bool_if_parse:NNNww #1#2#3#4 \q_mark #5 \q_stop { \__bool_get_next:NN \use_i:nn (( #4 )) S } (End definition for \__bool_if_parse:NNNww. which indicates that nothing has been treated at this pass. This function is documented on page 39. immediately followed by a new \q_nil delimiter. denoted simply by a S following the last Close operation. This is a switch: if what follows is neither ! nor (.the delimiter matches inside the expression. Close or Stop. The arguments are 1: \use_i:nn or \use_ii:nn.) \__bool_choose:NNN Branching the eight-way switch.) \__bool_!:Nw The Not operation reverses the logic: discard the ! token and call the GetNext operation with its first argument reversed. The canonical true and false values have numerical values 1 and 0 respectively. evaluate the predicate using the primitive \__int_value:w. 2: 0 or 1 encoding the current truth value. Or or Close afterwards. 3: the next operation. 2210 2211 2212 2213 \cs_new_nopar:cpn \cs_new_nopar:cpn \cs_new_nopar:cpn \cs_new_nopar:cpn { { { { __bool_)_0:w __bool_)_1:w __bool_S_0:w __bool_S_1:w } } } } { { { { \c_false_bool } \c_true_bool } \group_align_safe_end: \c_false_bool } \group_align_safe_end: \c_true_bool } (End definition for \__bool_)_0:w and others.) 267 . 2194 2195 2196 2197 2198 \cs_new:cpn { __bool_(:Nw } #1#2 { \exp_after:wN \__bool_choose:NNN \exp_after:wN #1 \__int_value:w \__bool_get_next:NN \use_i:nn } (End definition for \__bool_(:Nw. And. This is done by calling GetNext.2191 } (End definition for \__bool_get_next:NN. If #1 is \use_ii:nn. Or or Close afterwards. 2199 2200 \cs_new:cpn { __bool_p:Nw } #1 { \exp_after:wN \__bool_choose:NNN \exp_after:wN #1 \__int_value:w } (End definition for \__bool_p:Nw.) \__bool_p:Nw If what follows GetNext is neither ! nor (. The Stop operation is similar except it closes the special alignment group before returning the boolean. 2201 2202 2203 2204 2205 2206 2207 2208 2209 \cs_new:Npn \__bool_choose:NNN #1#2#3 { \use:c { __bool_ #3 _ #1 #2 { \if_meaning:w 0 #2 1 \else: 0 \fi: } :w } } (End definition for \__bool_choose:NNN.) \__bool_)_0:w \__bool_)_1:w \__bool_S_0:w \__bool_S_1:w Closing a group is just about returning the result. Or. Look for And. 2192 2193 \cs_new:cpn { __bool_!:Nw } #1#2 { \exp_after:wN \__bool_get_next:NN #1 \use_ii:nn \use_i:nn } (End definition for \__bool_!:Nw.) \__bool_(:Nw The Open operation starts a sub-expression after discarding the token. the logic of #2 must be reversed. with a post-processing step which looks for And. we realize we must skip everything after the first And.) \__bool_&_0:w When the truth value has already been decided. We must remove the second & or |.\__bool_&_1:w \__bool_|_0:w Two cases where we simply continue scanning. \__bool_eval_skip_to_end_auxii:Nw 2216 \cs_new_nopar:cpn { __bool_&_0:w } & { \__bool_eval_skip_to_end_auxi:Nw \c_false_bool } \__bool_eval_skip_to_end_auxiii:Nw 2217 \cs_new_nopar:cpn { __bool_|_1:w } | { \__bool_eval_skip_to_end_auxi:Nw \c_true_bool } There is always at least one ) waiting. giving us abc && xyz && ((xyz) && (def))) Again we read up to a Close and again find Open tokens: abc && xyz && ((xyz Further reduction gives us (xyz && (def))) and then (xyz && (def with reduction to 268 . This gives us the list we first read up until the first right parenthesis so we are looking at the token list ((abc This contains two Open markers so we must remove two groups. This is slightly tricky as there \__bool_eval_skip_to_end_auxi:Nw are no braces so we have to play match the () manually. we have to throw away the remainder \__bool_|_1:w of the current group as we are doing minimal evaluation. \c_false_bool && ((abc) && xyz) && ((xyz) && (def))) First read up to the first Close. Since no evaluation of the contents is to be carried out. This function is documented on page 39. After evaluating the following. we are facing the problem that there may be more than one that need to be finished off and we have to detect the correct number of them. namely the outer one. Here is a complicated example showing how this is done. However. 2214 2215 \cs_new_nopar:cpn { __bool_&_1:w } & { \__bool_get_next:NN \use_i:nn } \cs_new_nopar:cpn { __bool_|_0:w } | { \__bool_get_next:NN \use_i:nn } (End definition for \__bool_&_1:w. We therefore first remove a () pair and what preceded the Open – but leave the contents as it may contain Open tokens itself – leaving (abc && xyz) && ((xyz) && (def))) Another round of this gives us (abc && xyz which still contains an Open so we remove another () pair. it doesn’t matter how we remove the groups as long as we wind up with the correct result. Note the extra Close at the end. This function is documented on page 39. Not even particularly useful to have it when the infix notation is easier to use. throw away anything up to the ( as it is irrelevant. This function is documented on page 40. return the boolean #1. 2218 2219 2220 2221 2222 2223 2224 %% ( \cs_new:Npn \__bool_eval_skip_to_end_auxi:Nw #1#2 ) { \__bool_eval_skip_to_end_auxii:Nw #1#2 ( % ) \q_no_value \q_stop {#2} } If no right parenthesis.xyz && (def)) and ultimately we arrive at no Open tokens being skipped and we can finally close the group nicely. If the boolean expressions have same truth value. 2236 2237 2238 2239 2240 2241 \cs_new:Npn \bool_xor_p:nn #1#2 { \int_compare:nNnTF { \bool_if_p:n {#1} } = { \bool_if_p:n {#2} } \c_false_bool \c_true_bool } (End definition for \bool_xor_p:nn.) 269 . 2235 \cs_new:Npn \bool_not_p:n #1 { \bool_if_p:n { ! ( #1 ) } } (End definition for \bool_not_p:n.) \bool_not_p:n The Not variant just reverses the outcome of \bool_if_p:n. If there is. otherwise return true.) \bool_xor_p:nn Exclusive or. we need to grab a () pair and then recurse 2225 2226 2227 2228 2229 2230 \cs_new:Npn \__bool_eval_skip_to_end_auxii:Nw #1#2 ( #3#4 \q_stop #5 % ) { \quark_if_no_value:NTF #3 {#1} { \__bool_eval_skip_to_end_auxiii:Nw #1 #5 } } Keep the boolean. This function is documented on page 40. remove a () pair but remember to reinsert #3 as it may contain ( tokens! 2231 2232 2233 2234 \cs_new:Npn \__bool_eval_skip_to_end_auxiii:Nw #1#2 ( #3 ) { % ( \__bool_eval_skip_to_end_auxi:Nw #1#3 ) } (End definition for \__bool_&_0:w. Can be optimized but this is nice and simple and according to the implementation plan. return false. then #3 is no_value and we are done. The “while” version executes the code as long as the boolean is true.5.) \bool_do_while:Nn \bool_do_while:cn \bool_do_until:Nn \bool_do_until:cn A do-while loop where the body is performed at least once and the boolean is tested after executing the body. 2242 2243 2244 2245 2246 2247 \cs_new:Npn \bool_while_do:Nn #1#2 { \bool_if:NT #1 { #2 \bool_while_do:Nn \cs_new:Npn \bool_until_do:Nn #1#2 { \bool_if:NF #1 { #2 \bool_until_do:Nn \cs_generate_variant:Nn \bool_while_do:Nn \cs_generate_variant:Nn \bool_until_do:Nn #1 {#2} } } #1 {#2} } } { c } { c } (End definition for \bool_while_do:Nn and \bool_while_do:cn.) \bool_while_do:nn \bool_do_while:nn \bool_until_do:nn \bool_do_until:nn Loop functions with the test either before or after the first body expansion. the “until” version executes the code as long as the boolean is false. These functions are documented on page ??. 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 \cs_new:Npn \bool_while_do:nn #1#2 { \bool_if:nT {#1} { #2 \bool_while_do:nn {#1} {#2} } } \cs_new:Npn \bool_do_while:nn #1#2 { #2 \bool_if:nT {#1} { \bool_do_while:nn {#1} {#2} } } \cs_new:Npn \bool_until_do:nn #1#2 { \bool_if:nF {#1} { #2 \bool_until_do:nn {#1} {#2} } } \cs_new:Npn \bool_do_until:nn #1#2 { 270 . 2248 2249 2250 2251 2252 2253 \cs_new:Npn \bool_do_while:Nn #1#2 { #2 \bool_if:NT #1 { \bool_do_while:Nn \cs_new:Npn \bool_do_until:Nn #1#2 { #2 \bool_if:NF #1 { \bool_do_until:Nn \cs_generate_variant:Nn \bool_do_while:Nn \cs_generate_variant:Nn \bool_do_until:Nn #1 {#2} } } #1 {#2} } } { c } { c } (End definition for \bool_do_while:Nn and \bool_do_while:cn. These functions are documented on page ??. Otherwise identical to the above functions.5 \bool_while_do:Nn \bool_while_do:cn \bool_until_do:Nn \bool_until_do:cn Logical loops A while loop where the boolean is tested before executing the statement. 6 2280 \prg_replicate:nn \__prg_replicate:N \__prg_replicate_first:N \__prg_replicate_ \__prg_replicate_0:n \__prg_replicate_1:n \__prg_replicate_2:n \__prg_replicate_3:n \__prg_replicate_4:n \__prg_replicate_5:n \__prg_replicate_6:n \__prg_replicate_7:n \__prg_replicate_8:n \__prg_replicate_9:n \__prg_replicate_first_-:n \__prg_replicate_first_0:n \__prg_replicate_first_1:n \__prg_replicate_first_2:n \__prg_replicate_first_3:n \__prg_replicate_first_4:n \__prg_replicate_first_5:n \__prg_replicate_first_6:n \__prg_replicate_first_7:n \__prg_replicate_first_8:n \__prg_replicate_first_9:n Producing n copies h@@=prgi This function uses a cascading csname technique by David Kastrup (who else :-) The idea is to make the input 25 result in first adding five. Also. it is possible to write \prg_replicate:nn{1000}{\prg_replicate:nn{1000}{hcodei} An alternative approach is to create a string of m’s with \__int_to_roman:w which can be done with just four macros but that method has its own problems since it can exhaust the string pool. These functions are documented on page 40. The first function takes :n as a parameter. In order to avoid the last function to insert say. This is exactly what happens here: in the example with 25 then the next function is the one that inserts two copies but it sees the ten copies handed down by the previous function. and if necessary. 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 \cs_new:Npn \prg_replicate:nn #1 { \__int_to_roman:w \exp_after:wN \__prg_replicate_first:N \__int_value:w \__int_eval:w #1 \__int_eval_end: \cs_end: } \cs_new:Npn \__prg_replicate:N #1 { \cs:w __prg_replicate_#1 :n \__prg_replicate:N } \cs_new:Npn \__prg_replicate_first:N #1 { \cs:w __prg_replicate_first_ #1 :n \__prg_replicate:N } Then comes all the functions that do the hard work of inserting all the copies. it is considerably slower than what we use here so the few extra csnames are well spent I would say.) 5. This is important here (and other places) because it means that we can for instance make the function that inserts five copies of something to also hand down ten to the next function in line. 2292 2293 2294 2295 2296 \cs_new:Npn \cs_new:cpn \cs_new:cpn \cs_new:cpn \cs_new:cpn \__prg_replicate_ :n #1 { __prg_replicate_0:n } { __prg_replicate_1:n } { __prg_replicate_2:n } { __prg_replicate_3:n } { \cs_end: } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 } #1 271 . and then 20 copies of the code to be replicated. Now I don’t think this is a real limitation for any ordinary use. which ensures that \prg_replicate:nn only requires two steps of expansion. This function has one flaw though: Since it constantly passes down ten copies of its previous argument it will severely affect the main memory once you start demanding hundreds of thousands of copies. These functions also close the expansion of \__int_to_roman:w. 100 copies of the original argument just to gobble them again we define separate functions to be inserted first. The technique uses cascading csnames which means that we start building several csnames so we end up with a list of functions to be called in reverse order.#2 \bool_if:nF {#1} { \bool_do_until:nn {#1} {#2} 2277 2278 2279 } } (End definition for \bool_while_do:nn and others. .) 5. that as long as we are just talking about returning true and false states. These functions are documented on page 41. These functions are documented on page 41. 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 \cs_new:cpn { __prg_replicate_first_-:n { \c_zero \__msg_kernel_expandable_error:nn { } \cs_new:cpn { __prg_replicate_first_0:n \cs_new:cpn { __prg_replicate_first_1:n \cs_new:cpn { __prg_replicate_first_2:n \cs_new:cpn { __prg_replicate_first_3:n \cs_new:cpn { __prg_replicate_first_4:n \cs_new:cpn { __prg_replicate_first_5:n \cs_new:cpn { __prg_replicate_first_6:n \cs_new:cpn { __prg_replicate_first_7:n \cs_new:cpn { __prg_replicate_first_8:n \cs_new:cpn { __prg_replicate_first_9:n } #1 kernel } { negative-replication } } } } } } } } } } } #1 #1 #1 #1 #1 #1 #1 #1 #1 #1 { { { { { { { { { { \c_zero \c_zero \c_zero \c_zero \c_zero \c_zero \c_zero \c_zero \c_zero \c_zero } #1 } #1#1 } #1#1#1 } #1#1#1#1 } #1#1#1#1#1 } #1#1#1#1#1#1 } #1#1#1#1#1#1#1 } #1#1#1#1#1#1#1#1 } #1#1#1#1#1#1#1#1#1 } (End definition for \prg_replicate:nn. 2325 2326 \prg_new_conditional:Npnn \mode_if_vertical: { p . we can just use the primitive conditionals for this and gobbling the \c_zero in the input stream. T . TF } { \if_mode_horizontal: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \mode_if_horizontal:. 2327 2328 \prg_new_conditional:Npnn \mode_if_horizontal: { p . Strikes me here on the bus with David. F . T . F .) \mode_if_horizontal_p: \mode_if_horizontal:TF For testing horizontal mode.) 272 . . However this requires knowledge of the implementation so we keep things nice and clean and use the return statements.7 \mode_if_vertical_p: \mode_if_vertical:TF Detecting TEX’s mode For testing vertical mode. TF } { \if_mode_vertical: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \mode_if_vertical:.2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_4:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_5:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_6:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_7:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_8:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} \cs_new:cpn { __prg_replicate_9:n } { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 } #1 #1#1#1#1 } #1 #1#1#1#1#1 } #1 #1#1#1#1#1#1 } #1 #1#1#1#1#1#1#1 } #1 #1#1#1#1#1#1#1#1 } #1 #1#1#1#1#1#1#1#1#1 } Users shouldn’t ask for something to be replicated once or even not at all but. This function is documented on page 41. F . this required inserting \scan_stop:. T . We place the \if_false: { \fi: part at that place so that the successive expansions of \group_align_safe_begin/end: are always brace balanced. We can thus use an empty protected macro to stop TEX.) \mode_if_math_p: \mode_if_math:TF For testing math mode. . . The following functions help with this by using code documented only in Appendix D of The TEXbook. We don’t want to insert a \scan_stop: every time as that will destroy kerning between letters3 Unfortunately there is no way to detect if we’re in the beginning of an alignment cell as they have different characteristics depending 3 Unless we enforce an extra pass with an appropriate value of \pretolerance.8 \group_align_safe_begin: \group_align_safe_end: Internal programming functions TEX’s alignment structures present many problems. . since protected macros are not expanded anymore at the beginning of an alignment cell. 2337 \cs_new_protected_nopar:Npn \scan_align_safe_stop: { } Let us now explain the earlier version. or even worse: it could be the \endtemplate token causing even more trouble! To solve this we have to open a special group so that TEX still thinks it’s on safe ground but at the same time we don’t want to introduce any brace group that may find its way to the output. This could be a &4 giving a message like ! Misplaced \cr. 2333 2334 2335 2336 \cs_new_nopar:Npn \group_align_safe_begin: { \if_int_compare:w \if_false: { \fi: ‘} = \c_zero \fi: } \cs_new_nopar:Npn \group_align_safe_end: { \if_int_compare:w ‘{ = \c_zero } \fi: } (End definition for \group_align_safe_begin: and \group_align_safe_end:. 2329 2330 \prg_new_conditional:Npnn \mode_if_inner: { p . TF } { \if_mode_inner: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \mode_if_inner:. These functions are documented on page 41. As Knuth says himself in TEX: The Program: “It’s sort of a miracle whenever \halign or \valign work. If the next token happens to be a & with category code 4 we will get some sort of weird error message because the underlying \futurelet will store the token at the end of the alignment template. ]” One problem relates to commands that internally issues a \cr but also peek ahead for the next character for use in. This is no longer needed with a newer ε-TEX. These functions are documented on page 41. T . At the beginning of an alignment cell. Thus an \ifmmode test at the start of an array cell (where math mode is introduced by the preamble. F . say. 273 . but not in all cases (see below). TF } { \if_mode_math: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \mode_if_math:.) \scan_align_safe_stop: When TEX is in the beginning of an align cell (right after the \cr or &) it is in a somewhat strange mode as it is looking ahead to find an \omit or \noalign and hasn’t looked at the preamble yet.\mode_if_inner_p: \mode_if_inner:TF For testing inner mode. . an optional argument.) 5. With ε-TEX’s first version. 2331 2332 \prg_new_conditional:Npnn \mode_if_math: { p . [. not in the cell itself) will always fail unless we stop TEX from scanning ahead. the programmer should insert \scan_align_safe_stop: before the test. What is done here is that \scan_stop: is only inserted if an only if a) we’re in the outer part of an alignment cell and b) the last node wasn’t a char node or a ligature node.) 2338 \__prg_variable_get_scope:N \__prg_variable_get_scope:w \__prg_variable_get_type:N \__prg_variable_get_type:w h@@=prgi Expandable functions to find the type of a variable. and to return g if the variable is global. etc. as there are places where the \scan_stop: ends up in the result. 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 \group_begin: \tex_lccode:D ‘* = ‘g \scan_stop: \tex_catcode:D ‘* = \c_twelve \tl_to_lowercase:n { \group_end: \cs_new:Npn \__prg_variable_get_scope:N #1 { \exp_after:wN \exp_after:wN \exp_after:wN \__prg_variable_get_scope:w \cs_to_str:N #1 \exp_stop_f: \q_stop } \cs_new:Npn \__prg_variable_get_scope:w #1#2 \q_stop { \token_if_eq_meaning:NNT * #1 { g } } } \group_begin: \tex_lccode:D ‘* = ‘_ \scan_stop: \tex_catcode:D ‘* = \c_twelve \tl_to_lowercase:n { \group_end: \cs_new:Npn \__prg_variable_get_type:N #1 274 . The trick for \__prg_variable_get_scope:N is the same as that in \__cs_split_function:NN. However we can detect if we’re in an alignment cell by checking the current group type and we can also check if the previous node was a character or ligature. Thus an older definition here was \cs_new_nopar:Npn \scan_align_safe_stop: { \int_compare:nNnT \etex_currentgrouptype:D = \c_six { \int_compare:nNnF \etex_lastnodetype:D = \c_zero { \int_compare:nNnF \etex_lastnodetype:D = \c_seven { \scan_stop: } } } } However. but it can be simplified as the requirements here are less complex. (End definition for \scan_align_safe_stop:. this is not truly expandable.on column number. and will be removed entirely by 2012-05-31. #2 and #3 are the tokens enclosing the argument.) \__prg_break_point: \__prg_break: \__prg_break:n Also done in l3basics as in format mode these are needed within l3alloc. When doing the first pass. This function is documented on page ??. 2372 \int_new:N \g__prg_map_int (End definition for \g__prg_map_int. (End definition for \__prg_break_point:. Firstly we define the function for parsing the initial list and then the braced list afterwards. so one additionally has to define \cs_set_nopar:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n} For details on the implementation see “Sorting in TEX’s Mouth” by Bernd Raichle.) 5. This is just a reminder that that is the case! (End definition for \__prg_break_point:Nn.) \__prg_break_point:Nn \__prg_map_break:Nn These are defined in l3basics. This variable is documented on page 43. This function is documented on page 42. It is up to the programmer to define these functions when needed. \prg_define_quicksort:nnn #1 is the name.9 Deprecated functions These were deprecated on 2012-02-08.) \g__prg_map_int A nesting counter for mapping. This function is documented on page 43. the algorithm wraps all elements in braces and then uses a generic quicksort which works on token lists. As an example \prg_define_quicksort:nnn{seq}{\seq_elt:w}{\seq_elt_end:w} defines the user function \seq_quicksort:n and furthermore expects to use the two functions \seq_quicksort_compare:nnTF which compares the items and \seq_quicksort_function:n which is placed before each sorted item.{ 2361 \exp_after:wN \__prg_variable_get_type:w \token_to_str:N #1 * a \q_stop 2362 2363 } \cs_new:Npn \__prg_variable_get_type:w #1 * #2#3 \q_stop { \token_if_eq_meaning:NNTF a #2 {#1} { \__prg_variable_get_type:w #2#3 \q_stop } } 2364 2365 2366 2367 2368 2369 2370 2371 } (End definition for \__prg_variable_get_scope:N. as they are needed “early”. For the somewhat strange hclisti type which doesn’t enclose the items but uses a separator we define it by hand afterwards. 2373 2374 h*deprecatedi \cs_new_protected:Npn \prg_define_quicksort:nnn #1#2#3 { 275 . For the seq type a sequence is a token list variable. 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 \cs_set:cpx{#1_quicksort:n}##1{ \exp_not:c{#1_quicksort_start_partition:w} ##1 \exp_not:n{#2\q_nil#3\q_stop} } \cs_set:cpx{#1_quicksort_braced:n}##1{ \exp_not:c{#1_quicksort_start_partition_braced:n} ##1 \exp_not:N\q_nil\exp_not:N\q_stop } \cs_set:cpx {#1_quicksort_start_partition:w} #2 ##1 #3{ \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w \exp_not:c{#1_quicksort_do_partition_i:nnnw} {##1}{}{} } \cs_set:cpx {#1_quicksort_start_partition_braced:n} ##1 { \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn} {##1}{}{} } h/deprecatedi Now for doing the partitions. 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 h*deprecatedi \cs_set:cpx {#1_quicksort_do_partition_i:nnnw} ##1##2##3 #2 ##4 #3 { \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} { \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4} \exp_not:c{#1_quicksort_partition_greater_ii:nnnn} \exp_not:c{#1_quicksort_partition_less_ii:nnnn} } {##1}{##2}{##3}{##4} } \cs_set:cpx {#1_quicksort_do_partition_i_braced:nnnn} ##1##2##3##4 { \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} { \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4} \exp_not:c{#1_quicksort_partition_greater_ii_braced:nnnn} \exp_not:c{#1_quicksort_partition_less_ii_braced:nnnn} } {##1}{##2}{##3}{##4} } \cs_set:cpx {#1_quicksort_do_partition_ii:nnnw} ##1##2##3 #2 ##4 #3 { \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} { \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1} \exp_not:c{#1_quicksort_partition_less_i:nnnn} \exp_not:c{#1_quicksort_partition_greater_i:nnnn} } {##1}{##2}{##3}{##4} } \cs_set:cpx {#1_quicksort_do_partition_ii_braced:nnnn} ##1##2##3##4 { \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw} { 276 . Again we will also have to do it braced. and places the function \prg_quicksort_function:n in front of each of them. 2448 2449 2450 2451 2452 2453 2454 2455 h*deprecatedi \cs_set:cpx {#1_do_quicksort_braced:nnnnw} ##1##2##3##4\q_stop { \exp_not:c{#1_quicksort_braced:n}{##2} \exp_not:c{#1_quicksort_function:n}{##1} \exp_not:c{#1_quicksort_braced:n}{##3} } } h/deprecatedi (End definition for \prg_define_quicksort:nnn. 2456 2457 2458 h*deprecatedi \prg_define_quicksort:nnn {prg}{}{} h/deprecatedi (End definition for \prg_quicksort:n.) \prg_quicksort:n A simple version. 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 h*deprecatedi \cs_set:cpx {#1_quicksort_partition_less_i:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}} \cs_set:cpx {#1_quicksort_partition_less_ii:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}} \cs_set:cpx {#1_quicksort_partition_greater_i:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}} \cs_set:cpx {#1_quicksort_partition_greater_ii:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}} \cs_set:cpx {#1_quicksort_partition_less_i_braced:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}} \cs_set:cpx {#1_quicksort_partition_less_ii_braced:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}} \cs_set:cpx {#1_quicksort_partition_greater_i_braced:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}} \cs_set:cpx {#1_quicksort_partition_greater_ii_braced:nnnn} ##1##2##3##4{ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2{##4}}{##3}} h/deprecatedi Finally.2423 2424 2425 2426 2427 2428 2429 \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1} \exp_not:c{#1_quicksort_partition_less_i_braced:nnnn} \exp_not:c{#1_quicksort_partition_greater_i_braced:nnnn} } {##1}{##2}{##3}{##4} } h/deprecatedi This part of the code handles the two branches in each sorting. the big kahuna! This is where the sub-lists are sorted. This function is documented on page ??.) \prg_quicksort_function:n \prg_quicksort_compare:nnTF 2459 h*deprecatedi 277 . Sorts a list of tokens. uses the function \prg_quicksort_compare:nnTF to compare items. These functions are documented on page ??.) These were deprecated on 2011-05-27 and will be removed entirely by 2011-08-31. \prg_stepwise_inline:nnnn .) Deprecated 2012-06-03 for removal after 2012-12-31. These functions are documented on page ??. 2481 2482 2483 2484 2485 2486 h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 278 . \prg_case_int:nnn \prg_case_str:nnn \prg_case_str:onn \prg_case_str:xxn \prg_case_tl:Nnn \prg_case_tl:cnn Moved to more sensible modules. these are no longer needed. This function is documented on page ??. This function is documented on page ??. 2463 2464 2465 2466 h*deprecatedi \cs_new_protected:Npn \prg_new_map_functions:Nn #1#2 { \deprecated } \cs_new_protected:Npn \prg_set_map_functions:Nn #1#2 { \deprecated } h/deprecatedi (End definition for \prg_new_map_functions:Nn.) Deprecated 2012-06-04 for removal after 2012-12-31. \prg_new_map_functions:Nn \prg_set_map_functions:Nn As we have restructured the structured variables. \prg_stepwise_function:nnnN \prg_stepwise_inline:nnnn \prg_stepwise_variable:nnnNn 2475 2476 2477 2478 2479 h*deprecatedi \cs_new_eq:NN \prg_stepwise_function:nnnN \int_step_function:nnnN \cs_new_eq:NN \prg_stepwise_inline:nnnn \int_step_inline:nnnn \cs_new_eq:NN \prg_stepwise_variable:nnnNn \int_step_variable:nnnNn h/deprecatedi (End definition for \prg_stepwise_function:nnnN . 2467 2468 2469 2470 2471 2472 2473 2474 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \prg_case_int:nnn \prg_case_str:nnn \prg_case_str:onn \prg_case_str:xxn \prg_case_tl:Nnn \prg_case_tl:cnn \int_case:nnn \str_case:nnn \str_case:onn \str_case_x:nnn \tl_case:Nnn \tl_case:cnn (End definition for \prg_case_int:nnn and others.lvt. and \prg_stepwise_variable:nnnNn.) 2480 6 h/initex | packagei l3quark implementation The following test files are used for this code: m3quark001.2460 2461 2462 \cs_set:Npn \prg_quicksort_function:n {\ERROR} \cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR} h/deprecatedi (End definition for \prg_quicksort_function:n. \q_stop is an “end of argument” marker. meaning it is added as a proper list item with whatever list separator is in use. This function is documented on page 46. In this case. a dedicated end marker is used each time a recursion is set up.) \q_nil \q_mark \q_no_value \q_stop Some “public” quarks. there is just a dedicated copy of the standard quark test. These variables are documented on page 46. This function is documented on page 45. To avoid this.6. \q_nil is a empty value and \q_no_value marks an empty argument. Only ever used there! \q_recursion_tail is appended to whatever list structure we are doing recursion on. 2488 2489 2490 2491 \quark_new:N \quark_new:N \quark_new:N \quark_new:N \q_nil \q_mark \q_no_value \q_stop (End definition for \q_nil and others.) \q_recursion_tail \q_recursion_stop Quarks for ending recursions. The simple case is when the test can guarantee that only a single token is being tested.) 279 . it is easy to spend a lot of time testing if the end marker has \quark_if_recursion_tail_stop_do:Nn been found. 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 \cs_new:Npn \quark_if_recursion_tail_stop:N #1 { \if_meaning:w \q_recursion_tail #1 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: } \cs_new:Npn \quark_if_recursion_tail_stop_do:Nn #1 { \if_meaning:w \q_recursion_tail #1 \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw \else: \exp_after:wN \use_none:n \fi: } (End definition for \quark_if_recursion_tail_stop:N. Thus if the marker is found everything can be wrapper up and finished off. Both a gobbling version and one inserting end code are provided. These variables are documented on page 45. 2492 2493 \quark_new:N \q_recursion_tail \quark_new:N \q_recursion_stop (End definition for \q_recursion_tail and \q_recursion_stop.) \quark_if_recursion_tail_stop:N When doing recursions. 2487 \cs_new_protected:Npn \quark_new:N #1 { \tl_const:Nn #1 {#1} } (End definition for \quark_new:N.1 \quark_new:N Quarks Allocate a new quark. \q_recursion_stop is placed directly after the list. .\quark_if_recursion_tail_stop:n The same idea applies when testing multiple tokens. functions. This function is documented on page ??.) \quark_if_nil_p:N \quark_if_nil:NTF \quark_if_no_value_p:N \quark_if_no_value_p:c \quark_if_no_value:NTF \quark_if_no_value:cTF Here we test if we found a special quark as the first argument. T . We better start with \q_no_value as the first argument since the whole thing may otherwise loop if #1 is wrongly given a string like aabc instead of a single token.) \__quark_if_recursion_tail_break:NN Analogs of the \quark_if_recursion_tail_stop. TF } { \if_meaning:w \q_nil #1 \prg_return_true: may still loop in special circumstances however! 280 . Break the mapping \__quark_if_recursion_tail_break:nN using #2.. 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 \cs_new:Npn \__quark_if_recursion_tail_break:NN #1#2 { \if_meaning:w \q_recursion_tail #1 \exp_after:wN #2 \fi: } \cs_new:Npn \__quark_if_recursion_tail_break:nN #1#2 { \if_int_compare:w \pdftex_strcmp:D { \exp_not:N \q_recursion_tail } { \exp_not:n {#1} } = \c_zero \exp_after:wN #2 \fi: } (End definition for \__quark_if_recursion_tail_break:NN. \quark_if_recursion_tail_stop_do:nn 2508 \cs_new:Npn \quark_if_recursion_tail_stop:n #1 \quark_if_recursion_tail_stop_do:on 2509 { 2510 \if_int_compare:w \pdftex_strcmp:D 2511 { \exp_not:N \q_recursion_tail } { \exp_not:n {#1} } = \c_zero 2512 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w 2513 \fi: 2514 } 2515 \cs_new:Npn \quark_if_recursion_tail_stop_do:nn #1 2516 { 2517 \if_int_compare:w \pdftex_strcmp:D 2518 { \exp_not:N \q_recursion_tail } { \exp_not:n {#1} } = \c_zero 2519 \exp_after:wN \use_i_delimit_by_q_recursion_stop:nw 2520 \else: 2521 \exp_after:wN \use_none:n 2522 \fi: 2523 } 2524 \cs_generate_variant:Nn \quark_if_recursion_tail_stop:n { o } 2525 \cs_generate_variant:Nn \quark_if_recursion_tail_stop_do:nn { o } (End definition for \quark_if_recursion_tail_stop:n and \quark_if_recursion_tail_stop:o. but here we just compare the token \quark_if_recursion_tail_stop:o list to \q_recursion_tail as a string. These functions are documented on page ??.4 2539 2540 2541 2542 4 It \prg_new_conditional:Nnn \quark_if_nil:N { p. F . T . . F . These variables are documented on page ??. { \if_int_compare:w \pdftex_strcmp:D { \exp_not:N \q_nil } { \exp_not:n {#1} \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Nnn \quark_if_no_value:n { \if_int_compare:w \pdftex_strcmp:D { \exp_not:N \q_no_value } { \exp_not:n \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \quark_if_nil_p:n { V \cs_generate_variant:Nn \quark_if_nil:nTF { V \cs_generate_variant:Nn \quark_if_nil:nT { V \cs_generate_variant:Nn \quark_if_nil:nF { V T .2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 \else: \prg_return_false: \fi: } \prg_new_conditional:Nnn \quark_if_no_value:N { p. hence their definition is deferred. TF } } = \c_zero { p. These functions are documented on page ??. and \quark_if_nil:o. o o o o } } } } (End definition for \quark_if_nil:n . F . TF } } } } } (End definition for \quark_if_nil:N. These functions are documented on page 45. . .) 281 . 2581 2582 \quark_new:N \q__tl_act_mark \quark_new:N \q__tl_act_stop (End definition for \q__tl_act_mark and \q__tl_act_stop. 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 \prg_new_conditional:Nnn \quark_if_nil:n { p. TF } {#1} } = \c_zero . F . but that is loaded before the quark module. { \if_meaning:w \q_no_value #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \quark_if_no_value_p:N { c \cs_generate_variant:Nn \quark_if_no_value:NT { c \cs_generate_variant:Nn \quark_if_no_value:NF { c \cs_generate_variant:Nn \quark_if_no_value:NTF { c T .) \q__tl_act_mark \q__tl_act_stop These private quarks are needed by l3tl. \quark_if_nil:V .) \quark_if_nil_p:n \quark_if_nil_p:V \quark_if_nil_p:o \quark_if_nil:nTF \quark_if_nil:VTF \quark_if_nil:oTF \quark_if_no_value_p:n \quark_if_no_value:nTF These are essentially \str_if_eq:nn tests but done directly. 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 \cs_new_protected:Npn \__scan_new:N #1 { \tl_if_in:NnTF \g__scan_marks_tl { #1 } { \__msg_kernel_error:nnx { kernel } { scanmark-already-defined } { \token_to_str:N #1 } } { \tl_gput_right:Nn \g__scan_marks_tl {#1} \cs_new_eq:NN #1 \scan_stop: } } (End definition for \__scan_new:N. These functions are documented on page ??. 2584 \tl_new:N \g__scan_marks_tl (End definition for \g__scan_marks_tl.2 2583 \g__scan_marks_tl Scan marks h@@=scani The list of all scan marks currently declared.) 6.) 2603 h/initex | packagei 282 . This variable is documented on page ??. more can be defined by specific modules. 2599 2600 2601 2602 \cs_new:Npn \quark_if_recursion_tail_break:N #1 { \__quark_if_recursion_tail_break:NN #1 \prg_break: } \cs_new:Npn \quark_if_recursion_tail_break:n #1 { \__quark_if_recursion_tail_break:nN {#1} \prg_break: } (End definition for \quark_if_recursion_tail_break:N and \quark_if_recursion_tail_break:n. 2597 \__scan_new:N \s__stop (End definition for \s__stop.) \__use_none_delimit_by_s__stop:w Similar to \use_none_delimit_by_q_stop:w.) \s__stop We only declare one scan mark here.) \__scan_new:N Check whether the variable is already a scan mark. so I’m picking one some\quark_if_recursion_tail_break:n what arbitrarily. 2598 \cs_new:Npn \__use_none_delimit_by_s__stop:w #1 \s__stop { } (End definition for \__use_none_delimit_by_s__stop:w.3 Deprecated quark functions \quark_if_recursion_tail_break:N It’s not clear what breaking function we should be using here. This variable is documented on page 48.6. then declare it to be equal to \scan_stop: globally. 7 2604 h*initex | packagei 2605 h@@=tokeni 2606 2607 2608 2609 2610 7. 2611 2612 2613 2614 2615 2616 \cs_new_protected:Npn \char_set_catcode:nn #1#2 { \tex_catcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_catcode:n #1 { \tex_the:D \tex_catcode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_catcode:n #1 { \tex_showthe:D \tex_catcode:D \__int_eval:w #1 \__int_eval_end: } (End definition for \char_set_catcode:nn.1 \char_set_catcode:nn \char_value_catcode:n \char_show_value_catcode:n l3token implementation h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Character tokens Category code changes. This function is documented on page 51.) \char_set_catcode_escape:N \char_set_catcode_group_begin:N \char_set_catcode_group_end:N \char_set_catcode_math_toggle:N \char_set_catcode_alignment:N \char_set_catcode_end_line:N \char_set_catcode_parameter:N \char_set_catcode_math_superscript:N \char_set_catcode_math_subscript:N \char_set_catcode_ignore:N \char_set_catcode_space:N \char_set_catcode_letter:N \char_set_catcode_other:N \char_set_catcode_active:N \char_set_catcode_comment:N \char_set_catcode_invalid:N 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 \cs_new_protected:Npn \char_set_catcode_escape:N #1 { \char_set_catcode:nn { ‘#1 } \c_zero } \cs_new_protected:Npn \char_set_catcode_group_begin:N #1 { \char_set_catcode:nn { ‘#1 } \c_one } \cs_new_protected:Npn \char_set_catcode_group_end:N #1 { \char_set_catcode:nn { ‘#1 } \c_two } \cs_new_protected:Npn \char_set_catcode_math_toggle:N #1 { \char_set_catcode:nn { ‘#1 } \c_three } \cs_new_protected:Npn \char_set_catcode_alignment:N #1 { \char_set_catcode:nn { ‘#1 } \c_four } \cs_new_protected:Npn \char_set_catcode_end_line:N #1 { \char_set_catcode:nn { ‘#1 } \c_five } \cs_new_protected:Npn \char_set_catcode_parameter:N #1 { \char_set_catcode:nn { ‘#1 } \c_six } \cs_new_protected:Npn \char_set_catcode_math_superscript:N #1 { \char_set_catcode:nn { ‘#1 } \c_seven } \cs_new_protected:Npn \char_set_catcode_math_subscript:N #1 { \char_set_catcode:nn { ‘#1 } \c_eight } \cs_new_protected:Npn \char_set_catcode_ignore:N #1 { \char_set_catcode:nn { ‘#1 } \c_nine } \cs_new_protected:Npn \char_set_catcode_space:N #1 { \char_set_catcode:nn { ‘#1 } \c_ten } \cs_new_protected:Npn \char_set_catcode_letter:N #1 { \char_set_catcode:nn { ‘#1 } \c_eleven } \cs_new_protected:Npn \char_set_catcode_other:N #1 { \char_set_catcode:nn { ‘#1 } \c_twelve } \cs_new_protected:Npn \char_set_catcode_active:N #1 283 . but necessary! 2681 2682 2683 2684 \cs_new_protected:Npn \char_set_mathcode:nn #1#2 { \tex_mathcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_mathcode:n #1 { \tex_the:D \tex_mathcode:D \__int_eval:w #1\__int_eval_end: } 284 . These functions are documented on page 50.2644 2645 2646 2647 2648 { \char_set_catcode:nn { ‘#1 } \c_thirteen } \cs_new_protected:Npn \char_set_catcode_comment:N #1 { \char_set_catcode:nn { ‘#1 } \c_fourteen } \cs_new_protected:Npn \char_set_catcode_invalid:N #1 { \char_set_catcode:nn { ‘#1 } \c_fifteen } (End definition for \char_set_catcode_escape:N and others. These functions are documented on page 50.) \char_set_catcode_escape:n \char_set_catcode_group_begin:n \char_set_catcode_group_end:n \char_set_catcode_math_toggle:n \char_set_catcode_alignment:n \char_set_catcode_end_line:n \char_set_catcode_parameter:n \char_set_catcode_math_superscript:n \char_set_catcode_math_subscript:n \char_set_catcode_ignore:n \char_set_catcode_space:n \char_set_catcode_letter:n \char_set_catcode_other:n \char_set_catcode_active:n \char_set_catcode_comment:n \char_set_catcode_invalid:n 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 \cs_new_protected:Npn \char_set_catcode_escape:n #1 { \char_set_catcode:nn {#1} \c_zero } \cs_new_protected:Npn \char_set_catcode_group_begin:n #1 { \char_set_catcode:nn {#1} \c_one } \cs_new_protected:Npn \char_set_catcode_group_end:n #1 { \char_set_catcode:nn {#1} \c_two } \cs_new_protected:Npn \char_set_catcode_math_toggle:n #1 { \char_set_catcode:nn {#1} \c_three } \cs_new_protected:Npn \char_set_catcode_alignment:n #1 { \char_set_catcode:nn {#1} \c_four } \cs_new_protected:Npn \char_set_catcode_end_line:n #1 { \char_set_catcode:nn {#1} \c_five } \cs_new_protected:Npn \char_set_catcode_parameter:n #1 { \char_set_catcode:nn {#1} \c_six } \cs_new_protected:Npn \char_set_catcode_math_superscript:n #1 { \char_set_catcode:nn {#1} \c_seven } \cs_new_protected:Npn \char_set_catcode_math_subscript:n #1 { \char_set_catcode:nn {#1} \c_eight } \cs_new_protected:Npn \char_set_catcode_ignore:n #1 { \char_set_catcode:nn {#1} \c_nine } \cs_new_protected:Npn \char_set_catcode_space:n #1 { \char_set_catcode:nn {#1} \c_ten } \cs_new_protected:Npn \char_set_catcode_letter:n #1 { \char_set_catcode:nn {#1} \c_eleven } \cs_new_protected:Npn \char_set_catcode_other:n #1 { \char_set_catcode:nn {#1} \c_twelve } \cs_new_protected:Npn \char_set_catcode_active:n #1 { \char_set_catcode:nn {#1} \c_thirteen } \cs_new_protected:Npn \char_set_catcode_comment:n #1 { \char_set_catcode:nn {#1} \c_fourteen } \cs_new_protected:Npn \char_set_catcode_invalid:n #1 { \char_set_catcode:nn {#1} \c_fifteen } (End definition for \char_set_catcode_escape:n and others.) \char_set_mathcode:nn \char_value_mathcode:n \char_show_value_mathcode:n \char_set_lccode:nn \char_value_lccode:n \char_show_value_lccode:n \char_set_uccode:nn \char_value_uccode:n \char_show_value_uccode:n \char_set_sfcode:nn \char_value_sfcode:n \char_show_value_sfcode:n Pretty repetitive. 2 \token_to_meaning:N \token_to_meaning:c \token_to_str:N \token_to_str:c \token_new:Nn Generic tokens These are all defined in l3basics. This function is documented on page 53. This function is documented on page 53.2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 \cs_new_protected:Npn \char_show_value_mathcode:n #1 { \tex_showthe:D \tex_mathcode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_lccode:nn #1#2 { \tex_lccode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_lccode:n #1 { \tex_the:D \tex_lccode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_lccode:n #1 { \tex_showthe:D \tex_lccode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_uccode:nn #1#2 { \tex_uccode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_uccode:n #1 { \tex_the:D \tex_uccode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_uccode:n #1 { \tex_showthe:D \tex_uccode:D \__int_eval:w #1 \__int_eval_end: } \cs_new_protected:Npn \char_set_sfcode:nn #1#2 { \tex_sfcode:D #1 = \__int_eval:w #2 \__int_eval_end: } \cs_new:Npn \char_value_sfcode:n #1 { \tex_the:D \tex_sfcode:D \__int_eval:w #1\__int_eval_end: } \cs_new_protected:Npn \char_show_value_sfcode:n #1 { \tex_showthe:D \tex_sfcode:D \__int_eval:w #1 \__int_eval_end: } (End definition for \char_set_mathcode:nn.) Creates a new token.) \c_group_begin_token \c_group_end_token \c_math_toggle_token \c_alignment_token \c_parameter_token \c_math_superscript_token \c_math_subscript_token \c_space_token \c_catcode_letter_token \c_catcode_other_token We define these useful tokens. We have to do it by hand with the brace tokens for obvious reasons.) 7. as they are needed “early”. 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 \cs_new_eq:NN \c_group_begin_token { \cs_new_eq:NN \c_group_end_token } \group_begin: \char_set_catcode_math_toggle:N \* \token_new:Nn \c_math_toggle_token { * } \char_set_catcode_alignment:N \* \token_new:Nn \c_alignment_token { * } \token_new:Nn \c_parameter_token { # } \token_new:Nn \c_math_superscript_token { ^ } \char_set_catcode_math_subscript:N \* \token_new:Nn \c_math_subscript_token { * } \token_new:Nn \c_space_token { ~ } \token_new:Nn \c_catcode_letter_token { a } \token_new:Nn \c_catcode_other_token { 1 } \group_end: 285 . This is just a reminder that that is the case! (End definition for \token_to_meaning:N and \token_to_meaning:c. 2705 \cs_new_protected:Npn \token_new:Nn #1#2 { \cs_new_eq:NN #1 #2 } (End definition for \token_new:Nn. These functions are documented on page ??. The second longer list is for “special” characters more generally. We use the constant \c_group_begin_token for this. 2745 2746 2747 2748 2749 \prg_new_conditional:Npnn \token_if_group_begin:N #1 { p . These functions are documented on page 53. The only complication is dealing with _. and contains the active characters themselves to allow easy redefinition.3 \token_if_group_begin_p:N \token_if_group_begin:NTF Token conditionals Check if token is a begin group token.) 286 . T . These variables are documented on page 53. This variable is documented on page 53. and these are escaped so that for example bulk code assignments can be carried out. In both cases. the order is by ascii character code (as is done in for example \ExplSyntaxOn).) 7.) \l_char_active_seq \l_char_special_seq Two sequences for dealing with special characters.) \c_catcode_active_tl Not an implicit token! 2721 2722 2723 2724 \group_begin: \char_set_catcode_active:N \* \tl_const:Nn \c_catcode_active_tl { \exp_not:N * } \group_end: (End definition for \c_catcode_active_tl. 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 \seq_new:N \l_char_active_seq \use:n { \group_begin: \char_set_catcode_active:N \" \char_set_catcode_active:N \$ \char_set_catcode_active:N \& \char_set_catcode_active:N \^ \char_set_catcode_active:N \_ \char_set_catcode_active:N \~ \use:nn { \group_end: \seq_set_split:Nnn \l_char_active_seq { } } } { { " $ & ^ _ ~ } } %$ \seq_new:N \l_char_special_seq \seq_set_split:Nnn \l_char_special_seq { } { \ \" \# \$ \% \& \\ \^ \_ \{ \} \~ } (End definition for \l_char_active_seq and \l_char_special_seq. The first is characters which may be active. { \if_catcode:w \exp_not:N #1 \c_group_begin_token \prg_return_true: \else: \prg_return_false: \fi: } F . which requires the use of \use:n and \use:nn.(End definition for \c_group_begin_token and others. These functions are documented on page 54. TF } (End definition for \token_if_group_begin:N. \token_if_group_end_p:N \token_if_group_end:NTF Check if token is a end group token. TF } (End definition for \token_if_group_end:N.) \token_if_math_superscript_p:N Check if token is a math superscript token. We use the constant \c_math_toggle_token for this. T . { \if_catcode:w \exp_not:N #1 \c_math_superscript_token \prg_return_true: \else: \prg_return_false: \fi: } F . We have to trick TEX a bit to avoid an error message: within a group we prevent \c_parameter_token from behaving like a macro parameter character. TF } (End definition for \token_if_alignment:N. T . These functions are documented on page 54. These functions are documented on page 55.) \token_if_parameter_p:N \token_if_parameter:NTF Check if token is a parameter token. so they will remain after the group. These functions are documented on page 54. We use the constant \c_parameter_token for this. T . 2755 2756 2757 2758 2759 \prg_new_conditional:Npnn \token_if_math_toggle:N #1 { p . TF } (End definition for \token_if_math_toggle:N.) \token_if_math_toggle_p:N \token_if_math_toggle:NTF Check if token is a math shift token. TF } (End definition for \token_if_math_superscript:N. { \if_catcode:w \exp_not:N #1 \c_math_toggle_token \prg_return_true: \else: \prg_return_false: \fi: } F . We use the constant \c_alignment_token for this. { \if_catcode:w \exp_not:N #1 \c_alignment_token \prg_return_true: \else: \prg_return_false: \fi: } F . T . 2750 2751 2752 2753 2754 \prg_new_conditional:Npnn \token_if_group_end:N #1 { p . T . The definitions of \prg_new_conditional:Npnn are global. 2765 2766 2767 2768 2769 2770 2771 2772 \group_begin: \cs_set_eq:NN \c_parameter_token \scan_stop: \prg_new_conditional:Npnn \token_if_parameter:N #1 { p . These functions are documented on page 55. 2760 2761 2762 2763 2764 \prg_new_conditional:Npnn \token_if_alignment:N #1 { p . We use the constant \c_group_end_token for this.) 287 . These functions are documented on page 54.) \token_if_alignment_p:N \token_if_alignment:NTF Check if token is an alignment tab token. 2773 2774 2775 2776 2777 \prg_new_conditional:Npnn \token_if_math_superscript:N #1 { p . { \if_catcode:w \exp_not:N #1 \c_group_end_token \prg_return_true: \else: \prg_return_false: \fi: } F . TF } (End definition for \token_if_parameter:N. We use the constant \c_math_superscript_\token_if_math_superscript:NTF token for this. { \if_catcode:w \exp_not:N #1 \c_parameter_token \prg_return_true: \else: \prg_return_false: \fi: } \group_end: F . These functions are documented on page 55. T . { \if_catcode:w \exp_not:N #1 \c_math_subscript_token \prg_return_true: \else: \prg_return_false: \fi: } F . TF } (End definition for \token_if_active:N. 2798 2799 2800 2801 2802 \prg_new_conditional:Npnn \token_if_active:N #1 { p . We use the constant \c_catcode_active_tl for this. T . 2783 2784 2785 2786 2787 \prg_new_conditional:Npnn \token_if_space:N #1 { p . 2793 2794 2795 2796 2797 \prg_new_conditional:Npnn \token_if_other:N #1 { p . TF } (End definition for \token_if_space:N. We use the constant \c_space_token for this. { \if_catcode:w \exp_not:N #1 \c_catcode_other_token \prg_return_true: \else: \prg_return_false: \fi: } F .) \token_if_space_p:N \token_if_space:NTF Check if token is a space token. These functions are documented on page 55. { \if_catcode:w \exp_not:N #1 \c_catcode_letter_token \prg_return_true: \else: \prg_return_false: \fi: } F . where * is active.) \token_if_active_p:N \token_if_active:NTF Check if token is an active char token. We use the constant \c_catcode_letter_token for this. We use the constant \c_math_subscript_token for this. 2778 2779 2780 2781 2782 \prg_new_conditional:Npnn \token_if_math_subscript:N #1 { p . TF } (End definition for \token_if_other:N. These functions are documented on page 55. TF } (End definition for \token_if_letter:N.\token_if_math_subscript_p:N \token_if_math_subscript:NTF Check if token is a math subscript token. A technical point is that \c_catcode_active_tl is in fact a macro expanding to \exp_not:N *. { \if_catcode:w \exp_not:N #1 \c_space_token \prg_return_true: \else: \prg_return_false: \fi: } F . These functions are documented on page 55. TF } (End definition for \token_if_math_subscript:N. We use the constant \c_catcode_other_token for this. T . T . These functions are documented on page 55.) \token_if_other_p:N \token_if_other:NTF Check if token is an other char token. { \if_catcode:w \exp_not:N #1 \c_catcode_active_tl \prg_return_true: \else: \prg_return_false: \fi: } F .) 288 .) \token_if_letter_p:N \token_if_letter:NTF Check if token is a letter token. 2788 2789 2790 2791 2792 \prg_new_conditional:Npnn \token_if_letter:N #1 { p . T . macros can have any combination of \long. TF } (End definition for \token_if_eq_meaning:NN. \protected. TF } (End definition for \token_if_eq_catcode:NN. and analyse what is left. However..) \token_if_eq_catcode_p:NN \token_if_eq_catcode:NNTF Check if the tokens #1 and #2 have same category code. Both ma and : must be of category code 12 (other).. The string can also be cro parameter character for a colon with a weird category code (namely the usual category code of #). The problem is that the huser materiali can contain ->. However. 2813 2814 2815 2816 2817 \prg_new_conditional:Npnn \token_if_eq_charcode:NN #1#2 { p .) \token_if_macro_p:N \token_if_macro:NTF \__token_if_macro_p:w When a token is a macro. If this string is cro. then we have a macro. this can fail the five \. 2808 2809 2810 2811 2812 \prg_new_conditional:Npnn \token_if_eq_catcode:NN #1#2 { p . \outer cannot contain ma. However. The idea is thus to grab until the first :. If the string is rk. and marks can contain the colon character. T . { \if_charcode:w \exp_not:N #1 \exp_not:N #2 \prg_return_true: \else: \prg_return_false: \fi: } F . TF } (End definition for \token_if_eq_charcode:NN.\token_if_eq_meaning_p:NN \token_if_eq_meaning:NNTF Check if the tokens #1 and #2 have same meaning. 2803 2804 2805 2806 2807 \prg_new_conditional:Npnn \token_if_eq_meaning:NN #1#2 { p . then we have a mark. even if the escape character is m. These functions are documented on page 56. Otherwise. macros. This relies on the fact that \long. \token_to_meaning:N will always output something like \long macro:#1->#1 so we could naively check to see if the meaning contains ->. and we achieve using the standard lowercasing technique. \char_set_lccode:nn { ‘\T \char_set_lccode:nn { ‘\F \tl_to_lowercase:n { \M \A } { ‘\: } } { ‘\T } } { ‘\F } 289 .mark primitives. We thus only select the part of the meaning between the first ma and the first following :. 2818 2819 2820 2821 2822 2823 2824 2825 \group_begin: \char_set_catcode_other:N \char_set_catcode_other:N \char_set_lccode:nn { ‘\. \protected or \outer (not used in LATEX3) before the string macro:. only characters. { \if_catcode:w \exp_not:N #1 \exp_not:N #2 \prg_return_true: \else: \prg_return_false: \fi: } F . { \if_meaning:w #1 #2 \prg_return_true: \else: \prg_return_false: \fi: } F . whose meaning has the form .mark:huser materiali. it is empty..) \token_if_eq_charcode_p:NN \token_if_eq_charcode:NNTF Check if the tokens #1 and #2 have same character code.. T . regardless of the escape character. T . These functions are documented on page 55. These functions are documented on page 55. . . TF } { \if_catcode:w \exp_not:N #1 \scan_stop: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \token_if_cs:N.) \token_if_cs_p:N \token_if_cs:NTF Check if token has same catcode as a control sequence. TF } (End definition for \token_if_expandable:N. T . These functions are documented on page 56. An undefined token is not considered as expandable. . \q_stop } \cs_new:Npn \__token_if_macro_p:w #1 MA #2 . 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 \prg_new_conditional:Npnn \token_if_expandable:N #1 { p . T . These functions are documented on page 56.) \token_if_chardef_p:N \token_if_mathchardef_p:N \token_if_dim_register_p:N \token_if_int_register_p:N \token_if_muskip_register_p:N \token_if_skip_register_p:N \token_if_toks_register_p:N \token_if_long_macro_p:N \token_if_protected_macro_p:N \token_if_protected_long_macro_p:N \token_if_chardef:NTF \token_if_mathchardef:NTF \token_if_dim_register:NTF \token_if_int_register:NTF Most of these functions have to check the meaning of the token in question so we need to do some checkups on which characters are output by \token_to_meaning:N. 2841 2842 2843 2844 2845 \prg_new_conditional:Npnn \token_if_cs:N #1 { p . These functions are documented on page 56. . F . { \exp_after:wN \if_meaning:w \exp_not:N #1 #1 \prg_return_false: \else: \if_cs_exist:N #1 \prg_return_true: \else: \prg_return_false: \fi: \fi: } F . these characters have catcode 12 so we must do some serious substitutions in the code below. #3 \q_stop { \if_int_compare:w \pdftex_strcmp:D { #2 } { cro } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 } (End definition for \token_if_macro:N. No problem nesting the conditionals. As usual.\group_end: \prg_new_conditional:Npnn \token_if_macro:N #1 { p . 290 . This follows the same pattern as for \token_if_letter:N etc. F . We use \scan_stop: for this. TF } { \exp_after:wN \__token_if_macro_p:w \token_to_meaning:N #1 MA. We use the fact that TEX will temporarily convert \exp_not:N htokeni into \scan_stop: if htokeni is expandable. since the third #1 is only skipped if it is non-expandable (hence not part of TEX’s conditional apparatus).) \token_if_expandable_p:N \token_if_expandable:NTF Check if token is expandable. T . TF } { \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_chardef:w \token_to_meaning:N #1 CHAR" \q_stop } { \token_to_str:N \char } } \prg_new_conditional:Npnn \token_if_mathchardef:N #1 { p . 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 \prg_new_conditional:Npnn \token_if_chardef:N #1 { p . 2866 2867 2868 \tl_to_lowercase:n { \group_end: First up is checking if something has been defined with \chardef or \mathchardef. This is easy since TEX thinks of such tokens as hexadecimal so it stores them as \char"hhex numberi or \mathchar"hhex numberi. Grab until the first occurrence of char". TF } . F . T . T .2858 2859 2860 2861 2862 2863 2864 2865 \group_begin: \char_set_lccode:nn { ‘T } { ‘T } \char_set_lccode:nn { ‘F } { ‘F } \char_set_lccode:nn { ‘X } { ‘n } \char_set_lccode:nn { ‘Y } { ‘t } \char_set_lccode:nn { ‘Z } { ‘d } \tl_map_inline:nn { A C E G H I K L M O P R S U X Y Z R " } { \char_set_catcode:nn { ‘#1 } \c_twelve } We convert the token list to lower case and restore the catcode and lowercase code changes. TF } { \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_chardef:w \token_to_meaning:N #1 CHAR" \q_stop } { \token_to_str:N \mathchar } } \cs_new:Npn \__token_if_chardef:w #1 CHAR" #2 \q_stop { #1 CHAR } Dim registers are a little more difficult since their \meaning has the form \dimenhnumberi. F . namely \char or \mathchar (the auxiliary adds the char back). and we must take care of the two primitives \dimen and \dimendef. and compare what preceeds with \ or \math. the escape character may not be a backslash. { \if_meaning:w \tex_dimen:D #1 \prg_return_false: \else: \if_meaning:w \tex_dimendef:D #1 \prg_return_false: 291 F . 2888 2889 2890 2891 2892 2893 2894 \prg_new_conditional:Npnn \token_if_dim_register:N #1 { p . so we compare with the result of converting some other control sequence to a string. T . In fact. { \if_meaning:w \tex_muskip:D #1 \prg_return_false: \else: \if_meaning:w \tex_muskipdef:D #1 \prg_return_false: \else: \__str_if_eq_x_return:nn { 292 F .2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 \else: \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_dim_register:w \token_to_meaning:N #1 ZIMEX \q_stop } { \token_to_str:N \ } \fi: \fi: } \cs_new:Npn \__token_if_dim_register:w #1 ZIMEX #2 \q_stop { #1 ~ } Integer registers are one step harder since constants are implemented differently from variables. 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 \prg_new_conditional:Npnn \token_if_int_register:N #1 { p . TF } { % \token_if_chardef:NTF #1 { \prg_return_true: } % { % \token_if_mathchardef:NTF #1 { \prg_return_true: } % { \if_meaning:w \tex_count:D #1 \prg_return_false: \else: \if_meaning:w \tex_countdef:D #1 \prg_return_false: \else: \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_int_register:w \token_to_meaning:N #1 COUXY \q_stop } { \token_to_str:N \ } \fi: \fi: % } % } } \cs_new:Npn \__token_if_int_register:w #1 COUXY #2 \q_stop { #1 ~ } Muskip registers are done the same way as the dimension registers. F . T . TF } . 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 \prg_new_conditional:Npnn \token_if_muskip_register:N #1 { p . T . and we also have to take care of the primitives \count and \countdef. 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 \prg_new_conditional:Npnn \token_if_skip_register:N #1 { p . 2984 \prg_new_conditional:Npnn \token_if_protected_macro:N #1 293 . 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 \prg_new_conditional:Npnn \token_if_toks_register:N #1 { p . F . T . TF } { \if_meaning:w \tex_toks:D #1 \prg_return_false: \else: \if_meaning:w \tex_toksdef:D #1 \prg_return_false: \else: \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_toks_register:w \token_to_meaning:N #1 YOKS \q_stop } { \token_to_str:N \ } \fi: \fi: } \cs_new:Npn \__token_if_toks_register:w #1 YOKS #2 \q_stop { #1 ~ } Protected macros. TF } { \if_meaning:w \tex_skip:D #1 \prg_return_false: \else: \if_meaning:w \tex_skipdef:D #1 \prg_return_false: \else: \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_skip_register:w \token_to_meaning:N #1 SKIP \q_stop } { \token_to_str:N \ } \fi: \fi: } \cs_new:Npn \__token_if_skip_register:w #1 SKIP #2 \q_stop { #1 ~ } Toks registers. F .\exp_after:wN \__token_if_muskip_register:w \token_to_meaning:N #1 MUSKIP \q_stop 2940 2941 2942 2943 2944 2945 2946 2947 } { \token_to_str:N \ \fi: \fi: } } \cs_new:Npn \__token_if_muskip_register:w #1 MUSKIP #2 \q_stop { #1 ~ } Skip registers. T . but have non-letters in their meaning. TF } { \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_long_macro:w \token_to_meaning:N #1 LOXG~MACRO \q_stop } { \token_to_str:N \protected \token_to_str:N \ } } \cs_new:Npn \__token_if_long_macro:w #1 LOXG~MACRO #2 \q_stop { #1 ~ } 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 Finally the \tl_to_lowercase:n ends! 3016 } (End definition for \token_if_chardef:N and others. \topmark. \firstmark. We start by removing the two first (non-space) characters from the meaning. \botmark. This removes the escape character (which may be inexistent depending on \endlinechar). TF } { \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_long_macro:w \token_to_meaning:N #1 LOXG~MACRO \q_stop } { \token_to_str:N \ } } \prg_new_conditional:Npnn \token_if_protected_long_macro:N #1 { p . F . and takes care of three of the exceptions: \space. T . \splitfirstmark. Ten exceptions: on the one hand.g.g. \italiccorr. the letter A). because they cause endless trouble later otherwise.. T . Primitives are almost distinguished by the fact that the result of \token_to_meaning:N is formed from letters only. \space. These functions are documented on page 56. only letters. and \nullfont are primitives... and \q_stop.g. \prg_new_conditional:Npnn \token_if_long_macro:N #1 { p . F .{ p . a digit (e. \char"A). on the other hand. This leaves a string terminated by some :. whose meaning is at most two characters.) \token_if_primitive_p:N \token_if_primitive:NTF \__token_if_primitive:NNw \__token_if_primitive_space:w \__token_if_primitive_nullfont:N \__token_if_primitive_loop:N \__token_if_primitive:Nw \__token_if_primitive_undefined:N We filter out macros first. F . Every other token has either a space (e. \splitbotmark. \count123) or a double quote (e. T . \hyphen. \italiccorr and \hyphen. TF } { \__str_if_eq_x_return:nn { \exp_after:wN \__token_if_protected_macro:w \token_to_meaning:N #1 PROYECYEZ~MACRO \q_stop } { \token_to_str:N \ } } \cs_new:Npn \__token_if_protected_macro:w #1 PROYECYEZ~MACRO #2 \q_stop { #1 ~ } 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 Long macros and protected long macros share an auxiliary. but its meaning is undefined. 294 . \tex_undefined:D is not a primitive. \q_stop #1 } } \cs_new:Npn \__token_if_primitive:NNw #1#2 #3 . If this first character is : then we have a primitive. Two exceptions remain: \tex_undefined:D. we test for \nullfont. Spaces cannot be grabbed in an undelimited way.. it contains only letters. \q_stop } { \__token_if_primitive_nullfont:N } } } \cs_new:Npn \__token_if_primitive_space:w #1 ~ { } \cs_new:Npn \__token_if_primitive_nullfont:N #1 { \if_meaning:w \tex_nullfont:D #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_new:Npn \__token_if_primitive_loop:N #1 { \if_int_compare:w ‘#1 < \c_token_A_int % 295 . .mark primitives has the form hlettersi:huser materiali. and \nullfont. or a space. or \tex_undefined:D. . but is close enough to work in this context). In other words. TF } { \token_if_macro:NTF #1 \prg_return_false: { \exp_after:wN \__token_if_primitive:NNw \token_to_meaning:N #1 .The meaning of each one of the five \. If there is a space. we go through characters one by one. \char_set_lccode:nn { ‘\.. For non-primitives. 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 \tex_chardef:D \c_token_A_int = ‘A ~ % \group_begin: \char_set_catcode_other:N \. We are now left with a string. and if it is " or a digit. so we check them separately. #4 \q_stop { \tl_if_empty:oTF { \__token_if_primitive_space:w #3 ~ } { \__token_if_primitive_loop:N #3 . We remove everything after the first colon. or a digit. Otherwise. then the token is not a primitive. which is not a primitive. T . which is a primitive. the first non-letter is a colon. and stop at the first character less than ‘A (this is not quite a test for “only letters”. For primitives. which we must analyze. F . it contains either ". } { ‘\: } \char_set_lccode:nn { ‘\T } { ‘\T } \char_set_lccode:nn { ‘\F } { ‘\F } \tl_to_lowercase:n { \group_end: \prg_new_conditional:Npnn \token_if_primitive:N #1 { p . peek at the next token. peek at the next token and remove it. 4. This variable is documented on page ??.) 7.) 296 . 3079 \cs_new_eq:NN \l__peek_search_token ? (End definition for \l__peek_search_token. This function is documented on page 58. The outer level provides a defined interface to the lower level material. These functions are documented on page 57.) \l__peek_search_token The token to search for as an implicit token: cf. peek at the next non-space token and remove it. peek at the next non-space token. There are four cases: 1.3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 \exp_after:wN \__token_if_primitive:Nw \exp_after:wN #1 \else: \exp_after:wN \__token_if_primitive_loop:N \fi: } \cs_new:Npn \__token_if_primitive:Nw #1 #2 \q_stop { \if:w : #1 \exp_after:wN \__token_if_primitive_undefined:N \else: \prg_return_false: \exp_after:wN \use_none:n \fi: } \cs_new:Npn \__token_if_primitive_undefined:N #1 { \if_cs_exist:N #1 \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \token_if_primitive:N. This allows a large amount of code to be shared. 3. 3077 3078 \cs_new_eq:NN \l_peek_token ? \cs_new_eq:NN \g_peek_token ? (End definition for \l_peek_token. 2. \l__peek_search_tl.4 3076 Peeking ahead at the next token h@@=peeki Peeking ahead is implemented using a two part mechanism. \l_peek_token \g_peek_token Storage tokens which are publicly documented: the token peeked. 3089 3090 3091 3092 3093 3094 \cs_new_protected:Npn \__peek_true_remove:w { \group_align_safe_end: \tex_afterassignment:D \__peek_true_aux:w \cs_set_eq:NN \__peek_tmp:w } (End definition for \__peek_true_remove:w. This function is documented on page 58. more or less.) \__peek_true:w \__peek_true_aux:w \__peek_false:w \__peek_tmp:w Functions used by the branching and space-stripping code. and the true and false code as token lists. The two branches have to be absorbed here as the input stream needs to be cleared for the peek function itself. 3085 3086 3087 3088 \cs_new_protected_nopar:Npn \peek_after:Nw { \tex_futurelet:D \l_peek_token } \cs_new_protected_nopar:Npn \peek_gafter:Nw { \tex_global:D \tex_futurelet:D \g_peek_token } (End definition for \peek_after:Nw.) \__peek_true_remove:w A function to remove the next token and then regain control. \l__peek_search_token. This variable is documented on page ??.) \peek_after:Nw \peek_gafter:Nw Simple wrappers for \futurelet: no arguments absorbed here. 3081 3082 3083 3084 \cs_new_nopar:Npn \__peek_true:w { } \cs_new_nopar:Npn \__peek_true_aux:w { } \cs_new_nopar:Npn \__peek_false:w { } \cs_new:Npn \__peek_tmp:w { } (End definition for \__peek_true:w and others. 3080 \tl_new:N \l__peek_search_tl (End definition for \l__peek_search_tl.) \__peek_token_generic:NNTF The generic function stores the test token in both implicit and explicit modes.\l__peek_search_tl The token to search for as an explicit token: cf. 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 \cs_new_protected:Npn \__peek_token_generic:NNTF #1#2#3#4 { \cs_set_eq:NN \l__peek_search_token #2 \tl_set:Nn \l__peek_search_tl {#2} \cs_set_nopar:Npx \__peek_true:w { \exp_not:N \group_align_safe_end: \exp_not:n {#3} } \cs_set_nopar:Npx \__peek_false:w { \exp_not:N \group_align_safe_end: \exp_not:n {#4} } \group_align_safe_begin: \peek_after:Nw #1 } \cs_new_protected:Npn \__peek_token_generic:NNT #1#2#3 297 . For our purposes. macro.g. and in order to use the same auxiliaries we do something a little bit odd.) \__peek_execute_branches_meaning: The meaning test is straight forward.) \__peek_execute_branches_catcode: \__peek_execute_branches_charcode: \__peek_execute_branches_catcode_aux: \__peek_execute_branches_catcode_auxii:N \__peek_execute_branches_catcode_auxiii: The catcode and charcode tests are very similar. primitive).g. 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 \cs_new_protected:Npn \__peek_token_remove_generic:NNTF #1#2#3#4 { \cs_set_eq:NN \l__peek_search_token #2 \tl_set:Nn \l__peek_search_tl {#2} \cs_set_eq:NN \__peek_true:w \__peek_true_remove:w \cs_set_nopar:Npx \__peek_true_aux:w { \exp_not:n {#3} } \cs_set_nopar:Npx \__peek_false:w { \exp_not:N \group_align_safe_end: \exp_not:n {#4} } \group_align_safe_begin: \peek_after:Nw #1 } \cs_new_protected:Npn \__peek_token_remove_generic:NNT #1#2#3 { \__peek_token_remove_generic:NNTF #1 #2 {#3} { } } \cs_new_protected:Npn \__peek_token_remove_generic:NNF #1#2#3 { \__peek_token_remove_generic:NNTF #1 #2 { } {#3} } (End definition for \__peek_token_remove_generic:NNTF. This function is documented on page ??.3113 3114 3115 { \__peek_token_generic:NNTF #1 #2 {#3} { } } \cs_new_protected:Npn \__peek_token_generic:NNF #1#2#3 { \__peek_token_generic:NNTF #1 #2 { } {#3} } (End definition for \__peek_token_generic:NNTF. primitive)... • active characters which are not equal to a non-active character token (e. 298 . 3134 3135 3136 3137 3138 3139 3140 3141 \cs_new_nopar:Npn \__peek_execute_branches_meaning: { \if_meaning:w \l_peek_token \l__peek_search_token \exp_after:wN \__peek_true:w \else: \exp_after:wN \__peek_false:w \fi: } (End definition for \__peek_execute_branches_meaning:.) \__peek_token_remove_generic:NNTF For token removal there needs to be a call to the auxiliary function which does the work. firing \if_catcode:w and \if_charcode:w before finding the operands for those tests. This function is documented on page ??. three kinds of tokens may follow the peeking function: • control sequences which are not equal to a non-active character token (e. which will only be given in in the auxii:N and auxiii: auxiliaries. macro. This function is documented on page ??. In those cases. \l_peek_token is good enough for the test. We directly use the primitive meaning 299 . These functions are documented on page ??. Just like the peek token. The \exp_not:N prevents outer macros (coming from non-LATEX3 code) from blowing up. and compare it explicitly with the explicit search token stored in \l__peek_search_tl. hence the need to use the explicit token that was given to the peek function. we grab the following token. and calls \__peek_execute_branches: when encountering the first non-space token. and we compare it again with the explicit search token. detected thanks to a comparison with \scan_stop:. the search token may be of any of the three types above.• explicit non-active character tokens. 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 \cs_new_nopar:Npn \__peek_execute_branches_catcode: { \if_catcode:w \__peek_execute_branches_catcode_aux: } \cs_new_nopar:Npn \__peek_execute_branches_charcode: { \if_charcode:w \__peek_execute_branches_catcode_aux: } \cs_new_nopar:Npn \__peek_execute_branches_catcode_aux: { \if_catcode:w \exp_not:N \l_peek_token \scan_stop: \exp_after:wN \exp_after:wN \exp_after:wN \__peek_execute_branches_catcode_auxii:N \exp_after:wN \exp_not:N \else: \exp_after:wN \__peek_execute_branches_catcode_auxiii: \fi: } \cs_new:Npn \__peek_execute_branches_catcode_auxii:N #1 { \exp_not:N #1 \exp_after:wN \exp_not:N \l__peek_search_tl \exp_after:wN \__peek_true:w \else: \exp_after:wN \__peek_false:w \fi: #1 } \cs_new_nopar:Npn \__peek_execute_branches_catcode_auxiii: { \exp_not:N \l_peek_token \exp_after:wN \exp_not:N \l__peek_search_tl \exp_after:wN \__peek_true:w \else: \exp_after:wN \__peek_false:w \fi: } (End definition for \__peek_execute_branches_catcode: and \__peek_execute_branches_charcode:. The first two cases are not distinguishable simply using TEX’s \futurelet.) \__peek_ignore_spaces_execute_branches: This function removes one space token at a time. because we can only access the \meaning of tokens in that way. In the third case. or control sequences or active characters set equal to a non-active character token. This function is documented on page ??.test rather than \token_if_eq_meaning:NNTF because \l_peek_token may be an outer macro (coming from non-LATEX3 packages). First for category codes. As a result. Spaces are removed using a side-effect of f-expansion: \tex_romannumeral:D -‘0 removes one space. everything is done inside a group. This function is documented on page ??. 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 \group_begin: \cs_set:Npn \__peek_def:nnnn #1#2#3#4 { \__peek_def:nnnnn {#1} {#2} {#3} {#4} { TF } \__peek_def:nnnnn {#1} {#2} {#3} {#4} { T } \__peek_def:nnnnn {#1} {#2} {#3} {#4} { F } } \cs_set:Npn \__peek_def:nnnnn #1#2#3#4#5 { \cs_new_protected_nopar:cpx { #1 #5 } { \tl_if_empty:nF {#2} { \exp_not:n { \cs_set_eq:NN \__peek_execute_branches: #2 } } \exp_not:c { #3 #5 } \exp_not:n {#4} } } (End definition for \__peek_def:nnnn. \peek_catcode_ignore_spaces:NTF 3202 \__peek_def:nnnn { peek_catcode:N } \peek_catcode_remove:NTF 3203 { } 3204 { __peek_token_generic:NN } \peek_catcode_remove_ignore_spaces:NTF 3205 { \__peek_execute_branches_catcode: } 3206 \__peek_def:nnnn { peek_catcode_ignore_spaces:N } 3207 { \__peek_execute_branches_catcode: } 3208 { __peek_token_generic:NN } 3209 { \__peek_ignore_spaces_execute_branches: } 3210 \__peek_def:nnnn { peek_catcode_remove:N } 3211 { } 300 . 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 \cs_new_protected_nopar:Npn \__peek_ignore_spaces_execute_branches: { \if_meaning:w \l_peek_token \c_space_token \exp_after:wN \peek_after:Nw \exp_after:wN \__peek_ignore_spaces_execute_branches: \tex_romannumeral:D -‘0 \else: \exp_after:wN \__peek_execute_branches: \fi: } (End definition for \__peek_ignore_spaces_execute_branches:.) \__peek_def:nnnn \__peek_def:nnnnn The public functions themselves cannot be defined using \prg_new_conditional:Npnn and so a couple of auxiliary functions are used. As a result things are a bit complicated.) \peek_catcode:NTF With everything in place the definitions can take place. \peek_meaning_ignore_spaces:NTF 3234 \__peek_def:nnnn { peek_meaning:N } \peek_meaning_remove:NTF 3235 { } 3236 { __peek_token_generic:NN } \peek_meaning_remove_ignore_spaces:NTF 3237 { \__peek_execute_branches_meaning: } 3238 \__peek_def:nnnn { peek_meaning_ignore_spaces:N } 3239 { \__peek_execute_branches_meaning: } 3240 { __peek_token_generic:NN } 3241 { \__peek_ignore_spaces_execute_branches: } 3242 \__peek_def:nnnn { peek_meaning_remove:N } 3243 { } 3244 { __peek_token_remove_generic:NN } 3245 { \__peek_execute_branches_meaning: } 3246 \__peek_def:nnnn { peek_meaning_remove_ignore_spaces:N } 3247 { \__peek_execute_branches_meaning: } 3248 { __peek_token_remove_generic:NN } 3249 { \__peek_ignore_spaces_execute_branches: } 3250 \group_end: (End definition for \peek_meaning:NTF and others. \peek_charcode_ignore_spaces:NTF 3218 \__peek_def:nnnn { peek_charcode:N } \peek_charcode_remove:NTF 3219 { } \peek_charcode_remove_ignore_spaces:NTF 3220 { __peek_token_generic:NN } 3221 { \__peek_execute_branches_charcode: } 3222 \__peek_def:nnnn { peek_charcode_ignore_spaces:N } 3223 { \__peek_execute_branches_charcode: } 3224 { __peek_token_generic:NN } 3225 { \__peek_ignore_spaces_execute_branches: } 3226 \__peek_def:nnnn { peek_charcode_remove:N } 3227 { } 3228 { __peek_token_remove_generic:NN } 3229 { \__peek_execute_branches_charcode: } 3230 \__peek_def:nnnn { peek_charcode_remove_ignore_spaces:N } 3231 { \__peek_execute_branches_charcode: } 3232 { __peek_token_remove_generic:NN } 3233 { \__peek_ignore_spaces_execute_branches: } (End definition for \peek_charcode:NTF and others.) 301 . These functions are documented on page 60.) \peek_charcode:NTF Then for character codes. These functions are documented on page 59. These functions are documented on page 60. with the group closed to remove the temporary definition functions.) \peek_meaning:NTF Finally for meaning.3212 3213 3214 3215 3216 3217 { __peek_token_remove_generic:NN } { \__peek_execute_branches_catcode: } \__peek_def:nnnn { peek_catcode_remove_ignore_spaces:N } { \__peek_execute_branches_catcode: } { __peek_token_remove_generic:NN } { \__peek_ignore_spaces_execute_branches: } (End definition for \peek_catcode:NTF and others. the argument specification. we cannot just expand the macro blindly as it may have arguments and none might be present.) 7. the token \scan_stop: is returned instead. However. All of this information is returned as characters with catcode 12. or the replacement text from a macro. 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 \exp_args:Nno \use:nn { \cs_new:Npn \__peek_get_prefix_arg_replacement:wN #1 } { \tl_to_str:n { macro : } #2 -> #3 \q_stop #4 } { #4 {#1} {#2} {#3} } \cs_new:Npn \token_get_prefix_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \__peek_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_i:nnn } { \scan_stop: } } \cs_new:Npn \token_get_arg_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \__peek_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_ii:nnn } { \scan_stop: } } \cs_new:Npn \token_get_replacement_spec:N #1 { \token_if_macro:NTF #1 { \exp_after:wN \__peek_get_prefix_arg_replacement:wN \token_to_meaning:N #1 \q_stop \use_iii:nnn } { \scan_stop: } } (End definition for \token_get_prefix_spec:N. Therefore we define these functions to pick either the prefix(es).6 Deprecated functions Deprecated on 2011-05-27. 3282 3283 3284 h*deprecatedi \cs_new_eq:NN \char_set_catcode:w \tex_catcode:D \cs_new_eq:NN \char_set_mathcode:w \tex_mathcode:D 302 .5 \token_get_prefix_spec:N \token_get_arg_spec:N \token_get_replacement_spec:N \__peek_get_prefix_arg_replacement:wN Decomposing a macro definition We sometimes want to test if a control sequence can be expanded to reveal a hidden value. \char_set_catcode:w \char_set_mathcode:w \char_set_lccode:w \char_set_uccode:w \char_set_sfcode:w Primitives renamed. for removal by 2011-08-31.7. If the token in question isn’t a macro. This function is documented on page 61. 3285 3286 3287 3288 \cs_new_eq:NN \char_set_lccode:w \cs_new_eq:NN \char_set_uccode:w \cs_new_eq:NN \char_set_sfcode:w h/deprecatedi \tex_lccode:D \tex_uccode:D \tex_sfcode:D (End definition for \char_set_catcode:w.) \peek_after:NN \peek_gafter:NN The second argument here must be w. 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 h*deprecatedi \cs_new_nopar:Npn \char_value_catcode:w { \tex_the:D \char_set_catcode:w } \cs_new_nopar:Npn \char_show_value_catcode:w { \tex_showthe:D \char_set_catcode:w } \cs_new_nopar:Npn \char_value_mathcode:w { \tex_the:D \char_set_mathcode:w } \cs_new_nopar:Npn \char_show_value_mathcode:w { \tex_showthe:D \char_set_mathcode:w } \cs_new_nopar:Npn \char_value_lccode:w { \tex_the:D \char_set_lccode:w } \cs_new_nopar:Npn \char_show_value_lccode:w { \tex_showthe:D \char_set_lccode:w } \cs_new_nopar:Npn \char_value_uccode:w { \tex_the:D \char_set_uccode:w } \cs_new_nopar:Npn \char_show_value_uccode:w { \tex_showthe:D \char_set_uccode:w } \cs_new_nopar:Npn \char_value_sfcode:w { \tex_the:D \char_set_sfcode:w } \cs_new_nopar:Npn \char_show_value_sfcode:w { \tex_showthe:D \char_set_sfcode:w } h/deprecatedi (End definition for \char_value_catcode:w. This function is documented on page ??. This function is documented on page ??. This function is documented on page ??. This function is documented on page ??.) Functions deprecated 2011-05-28 for removal by 2011-08-31.) 303 . \c_alignment_tab_token \c_math_shift_token \c_letter_token \c_other_char_token 3310 3311 3312 3313 3314 3315 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \c_alignment_tab_token \c_math_shift_token \c_letter_token \c_other_char_token \c_alignment_token \c_math_toggle_token \c_catcode_letter_token \c_catcode_other_token (End definition for \c_alignment_tab_token.) \char_value_catcode:w \char_show_value_catcode:w \char_value_mathcode:w \char_show_value_mathcode:w \char_value_lccode:w \char_show_value_lccode:w \char_value_uccode:w \char_show_value_uccode:w \char_value_sfcode:w \char_show_value_sfcode:w More w functions we should not have.) \c_active_char_token An odd one: this was never a token! 3316 3317 3318 h*deprecatedi \cs_new_eq:NN \c_active_char_token \c_catcode_active_tl h/deprecatedi (End definition for \c_active_char_token. This function is documented on page ??. 3306 3307 3308 3309 h*deprecatedi \cs_new_eq:NN \peek_after:NN \peek_after:Nw \cs_new_eq:NN \peek_gafter:NN \peek_gafter:Nw h/deprecatedi (End definition for \peek_after:NN. \char_make_escape:N Two renames in one block! \char_make_group_begin:N 3319 h*deprecatedi \char_make_group_end:N 3320 \cs_new_eq:NN \char_make_escape:N \char_make_math_toggle:N 3321 \cs_new_eq:NN \char_make_begin_group:N 3322 \cs_new_eq:NN \char_make_end_group:N \char_make_alignment:N 3323 \cs_new_eq:NN \char_make_math_shift:N \char_make_end_line:N 3324 \cs_new_eq:NN \char_make_alignment_tab:N \char_make_parameter:N 3325 \cs_new_eq:NN \char_make_end_line:N \char_make_math_superscript:N 3326 \cs_new_eq:NN \char_make_parameter:N \char_make_math_subscript:N 3327 \cs_new_eq:NN \char_make_math_superscript:N \char_make_ignore:N 3328 \char_set_catcode_math_superscript:N \char_make_space:N 3329 \cs_new_eq:NN \char_make_math_subscript:N \char_make_letter:N 3330 \char_set_catcode_math_subscript:N \char_make_other:N 3331 \cs_new_eq:NN \char_make_ignore:N \char_make_active:N 3332 \cs_new_eq:NN \char_make_space:N 3333 \cs_new_eq:NN \char_make_letter:N \char_make_comment:N 3334 \cs_new_eq:NN \char_make_other:N \char_make_invalid:N 3335 \cs_new_eq:NN \char_make_active:N \char_make_escape:n 3336 \cs_new_eq:NN \char_make_comment:N \char_make_group_begin:n 3337 \cs_new_eq:NN \char_make_invalid:N \char_make_group_end:n 3338 \cs_new_eq:NN \char_make_escape:n \char_make_math_toggle:n 3339 \cs_new_eq:NN \char_make_begin_group:n \char_make_alignment:n 3340 \cs_new_eq:NN \char_make_end_group:n \char_make_end_line:n 3341 \cs_new_eq:NN \char_make_math_shift:n \char_make_parameter:n 3342 \cs_new_eq:NN \char_make_alignment_tab:n \char_make_math_superscript:n 3343 \cs_new_eq:NN \char_make_end_line:n \char_make_math_subscript:n 3344 \cs_new_eq:NN \char_make_parameter:n 3345 \cs_new_eq:NN \char_make_math_superscript:n \char_make_ignore:n 3346 \char_set_catcode_math_superscript:n \char_make_space:n 3347 \cs_new_eq:NN \char_make_math_subscript:n \char_make_letter:n 3348 \char_set_catcode_math_subscript:n \char_make_other:n 3349 \cs_new_eq:NN \char_make_ignore:n \char_make_active:n 3350 \cs_new_eq:NN \char_make_space:n \char_make_comment:n 3351 \cs_new_eq:NN \char_make_letter:n \char_make_invalid:n 3352 \cs_new_eq:NN \char_make_other:n 3353 \cs_new_eq:NN \char_make_active:n 3354 \cs_new_eq:NN \char_make_comment:n 3355 \cs_new_eq:NN \char_make_invalid:n 3356 h/deprecatedi \char_set_catcode_escape:N \char_set_catcode_group_begin:N \char_set_catcode_group_end:N \char_set_catcode_math_toggle:N \char_set_catcode_alignment:N \char_set_catcode_end_line:N \char_set_catcode_parameter:N \char_set_catcode_ignore:N \char_set_catcode_space:N \char_set_catcode_letter:N \char_set_catcode_other:N \char_set_catcode_active:N \char_set_catcode_comment:N \char_set_catcode_invalid:N \char_set_catcode_escape:n \char_set_catcode_group_begin:n \char_set_catcode_group_end:n \char_set_catcode_math_toggle:n \char_set_catcode_alignment:n \char_set_catcode_end_line:n \char_set_catcode_parameter:n \char_set_catcode_ignore:n \char_set_catcode_space:n \char_set_catcode_letter:n \char_set_catcode_other:n \char_set_catcode_active:n \char_set_catcode_comment:n \char_set_catcode_invalid:n (End definition for \char_make_escape:N and others. These functions are documented on page ??.) \token_if_alignment_tab_p:N \token_if_alignment_tab:NTF \token_if_math_shift_p:N \token_if_math_shift:NTF \token_if_other_char_p:N \token_if_other_char:NTF \token_if_active_char_p:N \token_if_active_char:NTF 3357 3358 3359 3360 3361 3362 3363 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \token_if_alignment_tab_p:N \token_if_alignment_p:N \token_if_alignment_tab:NT \token_if_alignment:NT \token_if_alignment_tab:NF \token_if_alignment:NF \token_if_alignment_tab:NTF \token_if_alignment:NTF \token_if_math_shift_p:N \token_if_math_toggle_p:N \token_if_math_shift:NT \token_if_math_toggle:NT 304 . This function is documented on page 74.) Here are the remaining primitives for number comparisons and expressions. 3378 3379 3380 3381 3382 \__int_to_roman:w \if_int_compare:w \__int_value:w \__int_eval:w \__int_eval_end: \if_int_odd:w \if_case:w h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Done in l3basics.m3int03. 3383 3384 3385 3386 3387 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \__int_value:w \__int_eval:w \__int_eval_end: \if_int_odd:w \if_case:w \tex_number:D \etex_numexpr:D \tex_relax:D \tex_ifodd:D \tex_ifcase:D (End definition for \__int_value:w. This function is documented on page 74.) 3375 8 h/initex | packagei l3int implementation 3376 h*initex | packagei 3377 h@@=inti The following test files are used for this code: m3int001.m3int002. Can be used in an integer expression or directly in the input stream. 3388 3389 3390 3391 3392 3393 h*initexi \cs_set:Npn \int_eval:n #1 { \__int_value:w \__int_eval:w #1 \__int_eval_end: } h/initexi h*packagei \cs_new:Npn \int_eval:n #1 { \__int_value:w \__int_eval:w #1 \__int_eval_end: } h/packagei 305 . there is already a definition in l3alloc for bookstrapping. These functions are documented on page ??. (End definition for \__int_to_roman:w.1 \int_eval:n Integer expressions Wrapper for \__int_eval:w. In format mode.3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \token_if_math_shift:NF \token_if_math_toggle:NF \token_if_math_shift:NTF \token_if_math_toggle:NTF \token_if_other_char_p:N \token_if_other_p:N \token_if_other_char:NT \token_if_other:NT \token_if_other_char:NF \token_if_other:NF \token_if_other_char:NTF \token_if_other:NTF \token_if_active_char_p:N \token_if_active_p:N \token_if_active_char:NT \token_if_active:NT \token_if_active_char:NF \token_if_active:NF \token_if_active_char:NTF \token_if_active:NTF (End definition for \token_if_alignment_tab:N. which is therefore corrected to the “real” version here.) 8. max. and absolute value with only one evaluation. 3426 3427 \cs_new:Npn \int_div_truncate:nn #1#2 { 306 . which we round away from zero.#1 \else: \exp_after:wN #1 \fi: } \cs_set:Npn \int_max:nn #1#2 { \__int_value:w \exp_after:wN \__int_maxmin:wwN \int_use:N \__int_eval:w #1 \exp_after:wN . \int_use:N \__int_eval:w #2 . This function is documented on page 63. \int_use:N \__int_eval:w #2 . shift the numerator #1#2 towards 0 by (|#3#4|−1)/2. Otherwise. \tl_count:n). This function is documented on page 62. The details are thanks to Heiko Oberdiek: getting things right in all cases is not so easy. > \exp_stop_f: } \cs_set:Npn \int_min:nn #1#2 { \__int_value:w \exp_after:wN \__int_maxmin:wwN \int_use:N \__int_eval:w #1 \exp_after:wN . It turns out that this quantity exactly compensates the difference between ε-TEX’s rounding and the truncating behaviour that we want.. < \exp_stop_f: } \cs_new:Npn \__int_maxmin:wwN #1 . We use an auxiliary to make sure numerator and denominator are only evaluated once: this comes in handy when those are more expressions are expensive to evaluate (e. then we divide 0 by the denominator (this ensures that 0/0 is correctly reported as an error). 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 \cs_new:Npn \int_abs:n #1 { \__int_value:w \exp_after:wN \__int_abs:N \int_use:N \__int_eval:w #1 \__int_eval_end: \exp_stop_f: } \cs_new:Npn \__int_abs:N #1 { \if_meaning:w . The absolute value is obtained by removing a leading sign if any. All three functions expand in two steps. If the numerator #1#2 is 0. #2 .) \int_div_truncate:nn \int_div_round:nn \int_mod:nn \__int_div_truncate:NwNw \__int_mod:ww As \__int_eval:w rounds the result of a division we also provide a version that truncates the result.g. #3 { \if_int_compare:w #1 #3 #2 ~ #1 \else: #2 \fi: } (End definition for \int_abs:n.(End definition for \int_eval:n.) \int_abs:n \__int_abs:N \int_max:nn \int_min:nn \__int_maxmin:wwN Functions for min. 2 \int_new:N \int_new:c Creating and initialising integers Two ways to do this: one for the format and one for the LATEX 2ε package.\fi: #3#4 . ) * #2 } (End definition for \int_div_truncate:nn.\fi: ( \if_meaning:w .#3 .( \__int_div_truncate:NwNw #1 . #2 . 3449 3450 3451 3452 3453 3454 3455 3456 3457 \cs_new:Npn \int_mod:nn #1#2 { \__int_value:w \__int_eval:w \exp_after:wN \__int_mod:ww \__int_value:w \__int_eval:w #1 \exp_after:wN .) 8. \__int_eval_end: } \cs_new:Npn \__int_div_truncate:NwNw #1#2. #2.#1 + \else: . #3#4. { #1 . \__int_eval_end: } \cs_new:Npn \__int_mod:ww #1.\c_one ) / \c_two ) \fi: / #3#4 } For the sake of completeness: 3447 3448 \cs_new:Npn \int_div_round:nn #1#2 { \__int_value:w \__int_eval:w ( #1 ) / ( #2 ) \__int_eval_end: } Finally there’s the modulus operation. This function is documented on page 63. \int_use:N \__int_eval:w #2 . \__int_value:w \__int_eval:w #2 .) 307 . { \if_meaning:w 0 #1 \c_zero \else: ( #1#2 \if_meaning:w . These functions are documented on page ??.3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 \int_use:N \__int_eval:w \exp_after:wN \__int_div_truncate:NwNw \int_use:N \__int_eval:w #1 \exp_after:wN . 3458 3459 3460 3461 3462 3463 3464 3465 h*packagei \cs_new_protected:Npn \int_new:N #1 { \__chk_if_free_cs:N #1 \newcount #1 } h/packagei \cs_generate_variant:Nn \int_new:N { c } (End definition for \int_new:N and \int_new:c. \int_const:Nn \int_const:cn \__int_constdef:Nw \c__max_constdef_int As stated. most constants can be defined as \chardef or \mathchardef but that’s engine dependent. These functions are documented on page ??. As a result.) \int_zero:N \int_zero:c \int_gzero:N \int_gzero:c Functions that reset an hintegeri register to zero. These functions are documented on page ??.) 308 . 3500 3501 3502 3503 3504 3505 \cs_new_protected:Npn \int_zero_new:N #1 { \int_if_exist:NTF #1 { \int_zero:N #1 } { \int_new:N #1 } } \cs_new_protected:Npn \int_gzero_new:N #1 { \int_if_exist:NTF #1 { \int_gzero:N #1 } { \int_new:N #1 } } \cs_generate_variant:Nn \int_zero_new:N { c } \cs_generate_variant:Nn \int_gzero_new:N { c } (End definition for \int_zero_new:N and others. otherwise clear it. 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 \cs_new_protected:Npn \int_const:Nn #1#2 { \int_compare:nNnTF {#2} > \c_minus_one { \int_compare:nNnTF {#2} > \c__max_constdef_int { \int_new:N #1 \int_gset:Nn #1 {#2} } { \__chk_if_free_cs:N #1 \tex_global:D \__int_constdef:Nw #1 = \__int_eval:w #2 \__int_eval_end: } } { \int_new:N #1 \int_gset:Nn #1 {#2} } } \cs_generate_variant:Nn \int_const:Nn { c } \pdftex_if_engine:TF { \cs_new_eq:NN \__int_constdef:Nw \tex_mathchardef:D \tex_mathchardef:D \c__max_constdef_int 32 767 ~ } { \cs_new_eq:NN \__int_constdef:Nw \tex_chardef:D \tex_chardef:D \c__max_constdef_int 1 114 111 ~ } (End definition for \int_const:Nn and \int_const:cn. These functions are documented on page ??. 3496 3497 3498 3499 \cs_new_protected:Npn \int_zero:N #1 { #1 = \c_zero } \cs_new_protected:Npn \int_gzero:N #1 { \tex_global:D #1 = \c_zero } \cs_generate_variant:Nn \int_zero:N { c } \cs_generate_variant:Nn \int_gzero:N { c } (End definition for \int_zero:N and \int_zero:c.) \int_zero_new:N \int_zero_new:c \int_gzero_new:N \int_gzero_new:c Create a register if needed. there is some set up code to determine what can be done. 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 \cs_new_protected:Npn \int_add:Nn #1#2 { \tex_advance:D #1 by \__int_eval:w #2 \__int_eval_end: } \cs_new_protected:Npn \int_sub:Nn #1#2 { \tex_advance:D #1 by . These functions are documented on page ??. cc } \cs_new_protected:Npn \int_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } \cs_generate_variant:Nn \int_gset_eq:NN { c } \cs_generate_variant:Nn \int_gset_eq:NN { Nc .3 \int_add:Nn \int_add:cn \int_gadd:Nn \int_gadd:cn \int_sub:Nn \int_sub:cn \int_gsub:Nn \int_gsub:cn \cs_new_protected:Npn \int_set_eq:NN #1#2 { #1 = #2 } \cs_generate_variant:Nn \int_set_eq:NN { c } \cs_generate_variant:Nn \int_set_eq:NN { Nc . T .) 309 . . These functions are documented on page ??.) 8. p } (End definition for \int_if_exist:N and \int_if_exist:c. 3506 3507 3508 3509 3510 3511 (End definition for \int_set_eq:NN and others.) \int_incr:N \int_incr:c \int_gincr:N \int_gincr:c \int_decr:N \int_decr:c \int_gdecr:N \int_gdecr:c Incrementing and decrementing of integer registers is done with the following functions. 3512 3513 \prg_new_eq_conditional:NNn \int_if_exist:N \cs_if_exist:N { TF . These functions are documented on page ??. 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 \cs_new_protected:Npn \int_incr:N #1 { \tex_advance:D #1 \c_one } \cs_new_protected:Npn \int_decr:N #1 { \tex_advance:D #1 \c_minus_one } \cs_new_protected_nopar:Npn \int_gincr:N { \tex_global:D \int_incr:N } \cs_new_protected_nopar:Npn \int_gdecr:N { \tex_global:D \int_decr:N } \cs_generate_variant:Nn \int_incr:N { c \cs_generate_variant:Nn \int_decr:N { c \cs_generate_variant:Nn \int_gincr:N { c \cs_generate_variant:Nn \int_gdecr:N { c } } } } (End definition for \int_incr:N and \int_incr:c. F . These functions are documented on page ??. cc } Setting and incrementing integers Adding and subtracting to and from a counter . T .\int_set_eq:NN \int_set_eq:cN \int_set_eq:Nc \int_set_eq:cc \int_gset_eq:NN \int_gset_eq:cN \int_gset_eq:Nc \int_gset_eq:cc \int_if_exist_p:N \int_if_exist_p:c \int_if_exist:NTF \int_if_exist:cTF Setting equal means using one integer inside the set function of another. p } \prg_new_eq_conditional:NNn \int_if_exist:c \cs_if_exist:c { TF .\__int_eval:w #2 \__int_eval_end: } \cs_new_protected_nopar:Npn \int_gadd:Nn { \tex_global:D \int_add:Nn } \cs_new_protected_nopar:Npn \int_gsub:Nn { \tex_global:D \int_sub:Nn } \cs_generate_variant:Nn \int_add:Nn { c } \cs_generate_variant:Nn \int_gadd:Nn { c } \cs_generate_variant:Nn \int_sub:Nn { c } \cs_generate_variant:Nn \int_gsub:Nn { c } (End definition for \int_add:Nn and \int_add:cn. F . .) Copies of the cs functions defined in l3basics. but if the relation symbol is missing from the test’s argument. The tests first evaluate their left-hand side.5 \__prg_compare_error: \__prg_compare_error:NNw Integer expression conditionals Those functions are used for comparison tests which use a simple syntax where only one set of braces is required and additional operators such as != and >= are supported. then a judiciously placed \__prg_compare_error:Nw gets expanded.4 \int_use:N \int_use:c Using integers Here is how counters are accessed: 3543 3544 \cs_new_eq:NN \int_use:N \tex_the:D \cs_new:Npn \int_use:c #1 { \int_use:N \cs:w #1 \cs_end: } (End definition for \int_use:N and \int_use:c. If the first token which appears after evaluating and removing the left-hand side is not a known relation symbol. 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 \cs_new_protected_nopar:Npn \__prg_compare_error: { \if_int_compare:w \c_zero \c_zero \fi: = \__prg_compare_error: } \cs_new:Npn \__prg_compare_error:Nw #1#2 \q_stop { { } \c_zero \fi: \__msg_kernel_expandable_error:nnn { kernel } { unknown-comparison } {#1} \prg_return_false: } (End definition for \__prg_compare_error: and \__prg_compare_error:NNw.) \int_compare_p:n \int_compare:nTF \__int_compare:w \__int_compare:Nw \__int_compare:NNw \__int_compare:nnN \__int_compare_end_=:NNw \__int_compare_=:NNw \__int_compare_<:NNw \__int_compare_>:NNw \__int_compare_==:NNw \__int_compare_!=:NNw \__int_compare_<=:NNw \__int_compare_>=:NNw Comparison tests using a simple syntax where only one set of braces is required. and multiple comparisons can be performed at once. These functions are documented on page ??. for instance 0 < 5 <= 1. then the marker inserts = (and itself) after triggering the relevant TEX error. The looping auxiliary \__int_compare:Nw reads one hoperandi and one hcomparisoni symbol. Thus there is no need for the checking code seen with token list variables.) 8. cleaning up the end of the test and telling the user what the problem was. This marker is normally not expanded.\int_set:Nn \int_set:cn \int_gset:Nn \int_gset:cn As integers are register-based TEX will issue an error if they are not defined. 3538 3539 3540 3541 3542 \cs_new_protected:Npn \int_set:Nn #1#2 { #1 ~ \__int_eval:w #2\__int_eval_end: } \cs_new_protected_nopar:Npn \int_gset:Nn { \tex_global:D \int_set:Nn } \cs_generate_variant:Nn \int_set:Nn { c } \cs_generate_variant:Nn \int_gset:Nn { c } (End definition for \int_set:Nn and \int_set:cn. finding one operand at a time. These functions are documented on page ??. with a trailing \__prg_compare_error:. The idea is to loop through the argument.) 8. and leaves roughly 310 . additional operators such as != and >= are supported. and comparing it to the previous one. \__prg_compare_error: is expanded. with a trailing \q_stop used to grab the entire argument when necessary. and \__prg_compare_error:Nw raises an error. after making sure that the argument becomes non-positive: its roman numeral representation is then empty. >.hoperandi \prg_return_false: \fi: \reverse_if:N \if_int_compare:w hoperandi hcomparisoni \__int_compare:Nw in the input stream. We first let TEX evaluate this left hand side of the (in)equality using \__int_eval:w. the first step is to make sure that there is at least one relation symbol. which will be ended by the two odd-looking items e and {=nd_}. The hoperandi is already evaluated. T . so we add an \if_false: and expand by hand with \__int_value:w. We then setup the loop. building a control sequence from it. Since the relation symbols <. If the argument contains no relation symbol. There is no TEX conditional waiting the first operand. If the relation symbol is unknown. the true branch of the TEX conditional is taken (because of \reverse_if:N). thus skipping \prg_return_false: on the first iteration. Each call to this auxiliary provides the second operand of the last call’s \if_int_compare:w. but we cannot yet grab it as an argument.0 #2 \q_mark #1#2 \q_stop } \cs_new:Npn \__int_compare:NNw #1#2#3 \q_mark { \etex_unexpanded:D \use:c { __int_compare_ #1 \if_meaning:w = #2 = 311 \fi: :NNw } . Before starting the loop. F . immediately returning false as the result of the test. Then probe the first two tokens with \__int_compare:NNw to determine the relation symbol. a relation symbol. inserting = and itself after an error. In all cases. If one of the hcomparisonsi is false. then the control sequence is turned by TEX into \scan_stop:. All the extended forms have an extra = hence the test for that as a second token. To access the following relation symbol. and some more tokens. = and ! are not allowed in integer expressions. we remove the number by applying \__int_to_roman:w. they will terminate it. ignored thanks to \unexpanded. \__int_compare:w receives as its argument an integer. 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 \cs_new:Npn \__int_compare:Nw #1#2 \q_stop { \exp_after:wN \__int_compare:NNw \__int_to_roman:w . TF } { \exp_after:wN \__int_compare:w \int_use:N \__int_eval:w #1 \__prg_compare_error: } \cs_new:Npn \__int_compare:w #1 \__prg_compare_error: { \exp_after:wN \if_false: \__int_value:w \__int_compare:Nw #1 e { = nd_ } \q_stop } The goal here is to find an hoperandi and a hcomparisoni. 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 \prg_new_conditional:Npnn \int_compare:n #1 { p . we leave the hoperandi for the previous conditional. As announced earlier. These functions are documented on page 66. \__int_compare:NNw receives e and =nd_ as arguments. F . the appropriate auxiliary calls \__int_compare:nnN where #1 is \if_int_compare:w or \reverse_if:N \if_int_compare:w. 3608 3609 3610 \prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p . TF } { \if_int_compare:w \__int_eval:w #1 #2 \__int_eval:w #3 \__int_eval_end: 312 . after evaluating the following expression. or >. and call \__int_compare:Nw to look for additional operands. #2 is the hoperandi.) \int_compare_p:nNn \int_compare:nNnTF More efficient but less natural in typing. 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 \cs_new:cpn { __int_compare_=:NNw } #1#2#3 = { \__int_compare:nnN { \reverse_if:N \if_int_compare:w \cs_new:cpn { __int_compare_<:NNw } #1#2#3 < { \__int_compare:nnN { \reverse_if:N \if_int_compare:w \cs_new:cpn { __int_compare_>:NNw } #1#2#3 > { \__int_compare:nnN { \reverse_if:N \if_int_compare:w \cs_new:cpn { __int_compare_==:NNw } #1#2#3 == { \__int_compare:nnN { \reverse_if:N \if_int_compare:w \cs_new:cpn { __int_compare_!=:NNw } #1#2#3 != { \__int_compare:nnN { \if_int_compare:w } {#3} = } \cs_new:cpn { __int_compare_<=:NNw } #1#2#3 <= { \__int_compare:nnN { \if_int_compare:w } {#3} > } \cs_new:cpn { __int_compare_>=:NNw } #1#2#3 >= { \__int_compare:nnN { \if_int_compare:w } {#3} < } } {#3} = } } {#3} < } } {#3} > } } {#3} = } (End definition for \int_compare:n. 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 \cs_new:cpn { __int_compare_end_=:NNw } #1#2#3 e #4 \q_stop { {#3} \exp_stop_f: \prg_return_false: \else: \prg_return_true: \fi: } \cs_new:Npn \__int_compare:nnN #1#2#3 { {#2} \exp_stop_f: \prg_return_false: \exp_after:wN \use_none_delimit_by_q_stop:w \fi: #1 #2 #3 \exp_after:wN \__int_compare:Nw \__int_value:w \__int_eval:w } The actual comparisons are then simple function calls. hence calling \__int_compare_end_=:NNw to end the loop: return the result of the last comparison (involving the operand that we just found). so we remove all tokens and return false. T . using the relation as delimiter for a delimited argument and discarding \__prg_compare_error:Nw htokeni responsible for error detection. we apply the conditional #1 to the hoperandi #2 and the comparison #3. If this conditional is true the result of the test is known. When a normal relation is found. Otherwise. =. and #3 is one of <.\__prg_compare_error:Nw #1 3580 3581 } When the last hoperandi is seen. TF} { \if_int_odd:w \__int_eval:w #1 \__int_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \int_if_even:n #1 { p . 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 \cs_new:Npn \int_case:nnn #1 { \tex_romannumeral:D \exp_args:Nf \__int_case:nnn { \int_eval:n {#1} } } \cs_new:Npn \__int_case:nnn #1#2#3 { \__int_case:nw {#1} #2 {#1} {#3} \q_recursion_stop } \cs_new:Npn \__int_case:nw #1#2#3 { \int_compare:nNnTF {#1} = {#2} { \__int_case_end:nw {#3} } { \__int_case:nw {#1} } } \cs_new_eq:NN \__int_case_end:nw \__prg_case_end:nw (End definition for \int_case:nnn. F . After that. which will fire the “else” pathway. This function is documented on page 67. These functions are documented on page 65. T . These functions are documented on page 67.\prg_return_true: \else: \prg_return_false: \fi: 3611 3612 3613 3614 3615 } (End definition for \int_compare:nNn. T . F . 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 \prg_new_conditional:Npnn \int_if_odd:n #1 { p . TF} { \if_int_odd:w \__int_eval:w #1 \__int_eval_end: \prg_return_false: \else: \prg_return_true: \fi: } (End definition for \int_if_odd:n.) 313 . a loop is started to compare each possible value and stop if the test is true. The leading \romannumeral triggers an expansion which is then stopped in \__int_case_end:nw.) \int_case:nnn \__int_case:nnn \__int_case:nw \__int_case_end:nw For integer cases.) \int_if_odd_p:n \int_if_odd:nTF \int_if_even_p:n \int_if_even:nTF A predicate function. The tested value is put at the end to ensure that there is necessarily a match. the first task to fully expand the check condition. The while versions test first and then execute the body. 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 \cs_new:Npn \int_while_do:nn #1#2 { \int_compare:nT {#1} { #2 \int_while_do:nn {#1} {#2} } } \cs_new:Npn \int_until_do:nn #1#2 { \int_compare:nF {#1} { #2 \int_until_do:nn {#1} {#2} } } \cs_new:Npn \int_do_while:nn #1#2 { #2 \int_compare:nT {#1} { \int_do_while:nn {#1} {#2} } } \cs_new:Npn \int_do_until:nn #1#2 { #2 \int_compare:nF {#1} { \int_do_until:nn {#1} {#2} } } (End definition for \int_while_do:nn.) \int_while_do:nNnn \int_until_do:nNnn \int_do_while:nNnn \int_do_until:nNnn As above but not using the more natural syntax.6 \int_while_do:nn \int_until_do:nn \int_do_while:nn \int_do_until:nn Integer expression loops These are quite easy given the above functions. 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 \cs_new:Npn \int_while_do:nNnn #1#2#3#4 { \int_compare:nNnT {#1} #2 {#3} { #4 \int_while_do:nNnn {#1} #2 {#3} {#4} } } \cs_new:Npn \int_until_do:nNnn #1#2#3#4 { \int_compare:nNnF {#1} #2 {#3} { #4 \int_until_do:nNnn {#1} #2 {#3} {#4} 314 . This function is documented on page 68.8. The do_while does it the other way round. 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 \cs_new:Npn \int_step_function:nnnN #1#2#3#4 { \int_compare:nNnTF {#2} > \c_zero { \exp_args:NNf \__int_step:NnnnN > } { \int_compare:nNnTF {#2} = \c_zero { \__msg_kernel_expandable_error:nnn { kernel } { zero-step } {#4} \use_none:nnnn } { \exp_args:NNf \__int_step:NnnnN < } } { \int_eval:n {#1} } {#2} {#3} #4 } \cs_new:Npn \__int_step:NnnnN #1#2#3#4#5 { \int_compare:nNnF {#2} #1 {#4} { #5 {#2} \exp_args:NNf \__int_step:NnnnN #1 { \int_eval:n { #2 + #3 } } {#3} {#4} #5 } } (End definition for \int_step_function:nnnN. It would be more symmetrical to test for a step size of zero before checking the sign.) \int_step_inline:nnnn \int_step_variable:nnnNn \__int_step:NNnnnn The approach here is to build a function. After that. This function is documented on page 69. This function is documented on page 67. do the function for the start value then step and loop around. with a global integer required to make the nesting safe (as seen in other in line functions).3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 } } \cs_new:Npn \int_do_while:nNnn #1#2#3#4 { #4 \int_compare:nNnT {#1} #2 {#3} { \int_do_while:nNnn {#1} #2 {#3} {#4} } } \cs_new:Npn \int_do_until:nNnn #1#2#3#4 { #4 \int_compare:nNnF {#1} #2 {#3} { \int_do_until:nNnn {#1} #2 {#3} {#4} } } (End definition for \int_while_do:nNnn. and map that function using \int_315 . but we optimize for the most frequent case (positive step).) 8.7 \int_step_function:nnnN \__int_step:NnnnN Integer step functions Repeating a function by steps first needs a check on the direction of the steps. ) 8. This function is documented on page 69. The input number (#1) is compared to the total number of symbols available at each place (#2). 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 \cs_new_protected_nopar:Npn \int_step_inline:nnnn { \int_gincr:N \g__prg_map_int \exp_args:NNc \__int_step:NNnnnn \cs_gset_nopar:Npn { __prg_map_ \int_use:N \g__prg_map_int :w } } \cs_new_protected:Npn \int_step_variable:nnnNn #1#2#3#4#5 { \int_gincr:N \g__prg_map_int \exp_args:NNc \__int_step:NNnnnn \cs_gset_nopar:Npx { __prg_map_ \int_use:N \g__prg_map_int :w } {#1}{#2}{#3} { \tl_set:Nn \exp_not:N #4 {##1} \exp_not:n {#5} } } \cs_new_protected:Npn \__int_step:NNnnnn #1#2#3#4#5#6 { #1 #2 ##1 {#6} \int_step_function:nnnN {#3} {#4} {#5} #2 \__prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__prg_map_int } } (End definition for \int_step_inline:nnnn. 3751 3752 3753 3754 \cs_new:Npn \int_to_symbols:nnn #1#2#3 { \int_compare:nNnTF {#1} > {#2} { 316 . if the initial input was small enough then there is no problem and everything is easy. this is done so that the system is recursive. If the input is larger than the total number of symbols available then the modulus is needed. 3750 \cs_new:Npn \int_to_arabic:n #1 { \int_eval:n {#1} } (End definition for \int_to_arabic:n. We put a \__prg_break_point:Nn so that map_break functions from other modules correctly decrement \g__prg_map_int before looking for their own break point. so no breaking function will recognize this break point as its own. The actual conversion function therefore gets a ‘nice’ number at each stage.) \int_to_symbols:nnn \__int_to_symbols:nnnn For conversion of integers to arbitrary symbols the method is in general as follows.8 \int_to_arabic:n Formatting integers Nothing exciting here. The first argument is \scan_stop:. with one added so that the positions don’t have to number from zero. Of course. This function is documented on page 69.step_function:nnnN. Using an f-type expansion. 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 \cs_new:Npn \int_to_alph:n #1 { \int_to_symbols:nnn {#1} { 26 } { { 1 } { a } { 2 } { b } { 3 } { c } { 4 } { d } { 5 } { e } { 6 } { f } { 7 } { g } { 8 } { h } { 9 } { i } { 10 } { j } { 11 } { k } { 12 } { l } { 13 } { m } { 14 } { n } { 15 } { o } { 16 } { p } { 17 } { q } { 18 } { r } { 19 } { s } { 20 } { t } { 21 } { u } { 22 } { v } { 23 } { w } { 24 } { x } { 25 } { y } 317 .1 } {#2} } {#3} { } } {#1} {#2} {#3} } { \int_case:nnn {#1} {#3} { } } } \cs_new:Npn \__int_to_symbols:nnnn #1#2#3#4 { \exp_args:Nf \int_to_symbols:nnn { \int_div_truncate:nn { #2 .1 } {#3} } {#3} {#4} #1 } (End definition for \int_to_symbols:nnn.3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 \exp_args:NNo \exp_args:No \__int_to_symbols:nnnn { \int_case:nnn { 1 + \int_mod:nn { #1 .) \int_to_alph:n \int_to_Alph:n These both use the above function with input functions that make sense for the alphabet in English. This function is documented on page 70. we shouldn’t perform it twice.{ 26 } { z } 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 } } \cs_new:Npn \int_to_Alph:n #1 { \int_to_symbols:nnn {#1} { 26 } { { 1 } { A } { 2 } { B } { 3 } { C } { 4 } { D } { 5 } { E } { 6 } { F } { 7 } { G } { 8 } { H } { 9 } { I } { 10 } { J } { 11 } { K } { 12 } { L } { 13 } { M } { 14 } { N } { 15 } { O } { 16 } { P } { 17 } { Q } { 18 } { R } { 19 } { S } { 20 } { T } { 21 } { U } { 22 } { V } { 23 } { W } { 24 } { X } { 25 } { Y } { 26 } { Z } } } (End definition for \int_to_alph:n and \int_to_Alph:n. 3835 3836 3837 3838 3839 3840 3841 3842 \cs_new:Npn \int_to_base:nn #1 { \exp_args:Nf \__int_to_base:nn { \int_eval:n {#1} } } \cs_new:Npn \__int_to_base:nn #1#2 { \int_compare:nNnTF {#1} < \c_zero { \exp_args:No \__int_to_base:nnN { \use_none:n #1 } {#2} .} { \__int_to_base:nnN {#1} {#2} \c_empty_tl } } 318 . These functions are documented on page 70. store it.or \c_empty_tl. Then check the sign.) \int_to_base:nn \__int_to_base:nn \__int_to_base:nnN \__int_to_base:nnnN \__int_to_letter:n Converting from base ten (#1) to a second base (#2) starts with computing #1: if it is a complicated calculation. either . and feed the absolute value to the next auxiliary function. the cases are contiguous.\c_ten \__int_eval_end: A \or: B \or: C \or: D \or: E \or: F \or: G \or: H \or: I \or: J \or: K \or: L 319 . On the other hand. and the remainder is carried forward to the next round. At each pass. then it is converted directly.Here. but in our case. The modulus is converted to a symbol and put on the right. If it is. 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 \cs_new:Npn \__int_to_base:nnN #1#2#3 { \int_compare:nNnTF {#1} < {#2} { \exp_last_unbraced:Nf #3 { \__int_to_letter:n {#1} } } { \exp_args:Nf \__int_to_base:nnnN { \__int_to_letter:n { \int_mod:nn {#1} {#2} } } {#1} {#2} #3 } } \cs_new:Npn \__int_to_base:nnnN #1#2#3#4 { \exp_args:Nf \__int_to_base:nnN { \int_div_truncate:nn {#2} {#3} } {#3} #4 #1 } Convert to a letter only if necessary. jumping to the correct case. the value in #1 is checked to see if it is less than the new base (#2). we need to evaluate it properly. and expand the trailing \fi:. the second one expands after the resulting character to close the conditional. The output is built up after the end of the function. Since #1 might be an expression. It would be cleaner to use \int_case:nnn. The first \exp_after:wN expands the conditional. the idea is to provide a recursive system to deal with the input. otherwise simply return the value unchanged. so it is forty times faster to use the \if_case:w primitive. putting the sign back in front. 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 \cs_new:Npn \__int_to_letter:n #1 { \exp_after:wN \exp_after:wN \if_case:w \__int_eval:w #1 . if the value to convert is greater than or equal to the new base then the modulus and remainder values are found. and not directly a single digit. The approach here is to convert the output of the primitive into letters using appropriate control sequence names. 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 \cs_new:Npn \int_to_roman:n #1 { \exp_after:wN \__int_to_roman:N \__int_to_roman:w \int_eval:n {#1} Q } \cs_new:Npn \__int_to_roman:N #1 { \use:c { __int_to_roman_ #1 :w } \__int_to_roman:N } \cs_new:Npn \int_to_Roman:n #1 { \exp_after:wN \__int_to_Roman_aux:N \__int_to_roman:w \int_eval:n {#1} Q } \cs_new:Npn \__int_to_Roman_aux:N #1 320 . what is actually wanted is letters. \int_to_hexadecimal:n . The loop will be terminated by the conversion of the Q.\or: M \or: N \or: O \or: P \or: Q \or: R \or: S \or: T \or: U \or: V \or: W \or: X \or: Y \or: Z \else: \__int_value:w \__int_eval:w #1 \exp_after:wN \__int_eval_end: \fi: 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 } (End definition for \int_to_base:nn.) \int_to_binary:n \int_to_hexadecimal:n \int_to_octal:n Wrappers around the generic function. That keeps everything expandable. These functions are documented on page 71. This function is documented on page 71. Usually.) \int_to_roman:n \int_to_Roman:n \__int_to_roman:N \__int_to_roman:N \__int_to_roman_i:w \__int_to_roman_v:w \__int_to_roman_x:w \__int_to_roman_l:w \__int_to_roman_c:w \__int_to_roman_d:w \__int_to_roman_m:w \__int_to_roman_Q:w \__int_to_Roman_i:w \__int_to_Roman_v:w \__int_to_Roman_x:w \__int_to_Roman_l:w \__int_to_Roman_c:w \__int_to_Roman_d:w \__int_to_Roman_m:w \__int_to_Roman_Q:w The \__int_to_roman:w primitive creates tokens of category code 12 (other). 3896 3897 3898 3899 3900 3901 \cs_new:Npn \int_to_binary:n #1 { \int_to_base:nn {#1} { 2 } } \cs_new:Npn \int_to_hexadecimal:n #1 { \int_to_base:nn {#1} { 16 } } \cs_new:Npn \int_to_octal:n #1 { \int_to_base:nn {#1} { 8 } } (End definition for \int_to_binary:n . and \int_to_octal:n. ) 8. These functions are documented on page 71. 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 \cs_new:Npn \__int_get_sign:n #1 { \__int_get_sign_and_digits:nNNN {#1} \c_true_bool \c_true_bool \c_false_bool } \cs_new:Npn \__int_get_digits:n #1 { \__int_get_sign_and_digits:nNNN {#1} \c_true_bool \c_false_bool \c_true_bool } The auxiliary loops through. The sign of the input is tracked by the first Boolean used by the auxiliary function. This is done by working through token by token until there is something else at the start of the input.3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 { \use:c { __int_to_Roman_ #1 :w } \__int_to_Roman_aux:N } \cs_new_nopar:Npn \__int_to_roman_i:w { i } \cs_new_nopar:Npn \__int_to_roman_v:w { v } \cs_new_nopar:Npn \__int_to_roman_x:w { x } \cs_new_nopar:Npn \__int_to_roman_l:w { l } \cs_new_nopar:Npn \__int_to_roman_c:w { c } \cs_new_nopar:Npn \__int_to_roman_d:w { d } \cs_new_nopar:Npn \__int_to_roman_m:w { m } \cs_new_nopar:Npn \__int_to_roman_Q:w #1 { } \cs_new_nopar:Npn \__int_to_Roman_i:w { I } \cs_new_nopar:Npn \__int_to_Roman_v:w { V } \cs_new_nopar:Npn \__int_to_Roman_x:w { X } \cs_new_nopar:Npn \__int_to_Roman_l:w { L } \cs_new_nopar:Npn \__int_to_Roman_c:w { C } \cs_new_nopar:Npn \__int_to_Roman_d:w { D } \cs_new_nopar:Npn \__int_to_Roman_m:w { M } \cs_new:Npn \__int_to_Roman_Q:w #1 { } (End definition for \int_to_roman:n and \int_to_Roman:n.symbols. 3948 3949 3950 3951 3952 3953 3954 \cs_new:Npn \__int_get_sign_and_digits:nNNN #1#2#3#4 { \exp_args:Nf \tl_if_head_eq_charcode:nNTF {#1} { \bool_if:NTF #2 { \__int_get_sign_and_digits:oNNN 321 . finding sign tokens and removing them. The sign itself is carried through as a flag.9 \__int_get_sign:n \__int_get_digits:n \__int_get_sign_and_digits:nNNN \__int_get_sign_and_digits:oNNN Converting from other formats to integers Finding a number and its sign requires dealing with an arbitrary list of + and . ) \int_from_base:nn \__int_from_base:nn \__int_from_base:nnN \__int_from_base:N Conversion to base ten means stripping off the sign then iterating through the input one token at a time. 3993 3994 \cs_new:Npn \int_from_base:nn #1#2 { 322 . but this needs a different final auxiliary.\int_compare:nNnTF { ‘#1 } < { 91 } { 64 } { 96 } } } (End definition for \int_from_alph:n. This function is documented on page 71. The total number is then added up as the code loops.} \bool_if:NT #4 {#1} } } } \cs_generate_variant:Nn \__int_get_sign_and_digits:nNNN { o } (End definition for \__int_get_sign:n. The same approach is also used for base conversion.{ \use_none:n #1 } \c_false_bool #3#4 3955 } { 3956 3957 \__int_get_sign_and_digits:oNNN { \use_none:n #1 } \c_true_bool #3#4 3958 3959 } 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 } { \exp_args:Nf \tl_if_head_eq_charcode:nNTF {#1} + { \__int_get_sign_and_digits:oNNN { \use_none:n #1 } #2#3#4 } { \bool_if:NT #3 { \bool_if:NF #2 . This function is documented on page ??.) \int_from_alph:n \__int_from_alph:n \__int_from_alph:nN \__int_from_alph:N The aim here is to iterate through the input. 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 \cs_new:Npn \int_from_alph:n #1 { \int_eval:n { \__int_get_sign:n {#1} \exp_args:Nf \__int_from_alph:n { \__int_get_digits:n {#1} } } } \cs_new:Npn \__int_from_alph:n #1 { \__int_from_alph:nN { 0 } #1 \q_nil } \cs_new:Npn \__int_from_alph:nN #1#2 { \quark_if_nil:NTF #2 {#1} { \exp_args:Nf \__int_from_alph:nN { \int_eval:n { #1 * 26 + \__int_from_alph:N #2 } } } } \cs_new:Npn \__int_from_alph:N #1 { \int_eval:n { ‘#1 . converting one letter at a time to a number. 4029 4030 4031 4032 4033 4034 \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn { { { { { { c__int_from_roman_i_int c__int_from_roman_v_int c__int_from_roman_x_int c__int_from_roman_l_int c__int_from_roman_c_int c__int_from_roman_d_int 323 } } } } } } { { { { { { 1 } 5 } 10 } 50 } 100 } 500 } . These functions are documented on page 72. 4023 4024 4025 4026 4027 4028 \cs_new:Npn \int_from_binary:n #1 { \int_from_base:nn {#1} \c_two } \cs_new:Npn \int_from_hexadecimal:n #1 { \int_from_base:nn {#1} \c_sixteen } \cs_new:Npn \int_from_octal:n #1 { \int_from_base:nn {#1} \c_eight } (End definition for \int_from_binary:n . 4014 4015 4016 4017 4018 4019 4020 4021 4022 \cs_new:Npn \__int_from_base:N #1 { \int_compare:nNnTF { ‘#1 } < { 58 } {#1} { \int_eval:n { ‘#1 .\int_compare:nNnTF { ‘#1 } < { 91 } { 55 } { 87 } } } } (End definition for \int_from_base:nn. This function is documented on page 72. hence the two-part nature of the function.) \int_from_binary:n \int_from_hexadecimal:n \int_from_octal:n Wrappers around the generic function. \int_from_hexadecimal:n .) \c__int_from_roman_i_int \c__int_from_roman_v_int \c__int_from_roman_x_int \c__int_from_roman_l_int \c__int_from_roman_c_int \c__int_from_roman_d_int \c__int_from_roman_m_int \c__int_from_roman_I_int \c__int_from_roman_V_int \c__int_from_roman_X_int \c__int_from_roman_L_int \c__int_from_roman_C_int \c__int_from_roman_D_int \c__int_from_roman_M_int Constants used to convert from Roman numerals to integers. and \int_from_octal:n.3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 \int_eval:n { \__int_get_sign:n {#1} \exp_args:Nf \__int_from_base:nn { \__int_get_digits:n {#1} } {#2} } } \cs_new:Npn \__int_from_base:nn #1#2 { \__int_from_base:nnN { 0 } { #2 } #1 \q_nil } \cs_new:Npn \__int_from_base:nnN #1#2#3 { \quark_if_nil:NTF #3 {#1} { \exp_args:Nf \__int_from_base:nnN { \int_eval:n { #1 * #2 + \__int_from_base:N #3 } } {#2} } } The conversion here will take lower or upper case letters and turn them into the appropriate number. finding the appropriate value for each letter and building up a sum.4035 4036 4037 4038 4039 4040 4041 4042 \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn \int_const:cn { { { { { { { { c__int_from_roman_m_int c__int_from_roman_I_int c__int_from_roman_V_int c__int_from_roman_X_int c__int_from_roman_L_int c__int_from_roman_C_int c__int_from_roman_D_int c__int_from_roman_M_int } } } } } } } } { { { { { { { { 1000 } 1 } 5 } 10 } 50 } 100 } 500 } 1000 } (End definition for \c__int_from_roman_i_int and others.) \int_from_roman:n \__int_from_roman:NN \__int_from_roman_end:w \__int_from_roman_clean_up:w The method here is to iterate through the input. These variables are documented on page ??.\use:c { c__int_from_roman_ #1 _int } \__int_from_roman:NN } { 324 . This is then evaluated by TEX. 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 \cs_new:Npn \int_from_roman:n #1 { \tl_if_blank:nF {#1} { \exp_after:wN \__int_from_roman_end:w \__int_value:w \__int_eval:w \__int_from_roman:NN #1 Q \q_stop } } \cs_new:Npn \__int_from_roman:NN #1#2 { \str_if_eq:nnTF {#1} { Q } {#1#2} { \str_if_eq:nnTF {#2} { Q } { \int_if_exist:cF { c__int_from_roman_ #1 _int } { \__int_from_roman_clean_up:w } + \use:c { c__int_from_roman_ #1 _int } #2 } { \int_if_exist:cF { c__int_from_roman_ #1 _int } { \__int_from_roman_clean_up:w } \int_if_exist:cF { c__int_from_roman_ #2 _int } { \__int_from_roman_clean_up:w } \int_compare:nNnTF { \use:c { c__int_from_roman_ #1 _int } } < { \use:c { c__int_from_roman_ #2 _int } } { + \use:c { c__int_from_roman_ #2 _int } . and so is in l3basics (End definition for \c_minus_one. 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \int_const:Nn \c_one \c_two \c_three \c_four \c_five \c_eight \c_nine \c_ten \c_eleven \c_thirteen \c_fourteen \c_fifteen { { { { { { { { { { { { 1 2 3 4 5 8 9 10 11 13 14 15 } } } } } } } } } } } } 325 . This variable is documented on page 73.11 \c_minus_one Constant integers This is needed early. (End definition for \c_six and \c_seven. These functions are documented on page 73.) Low-number values not previously defined.) \c_zero Again. These functions are documented on page ??. 4091 4092 \cs_new_protected:Npn \int_show:n #1 { \etex_showtokens:D \exp_after:wN { \int_use:N \__int_eval:w #1 } } (End definition for \int_show:n. This function is documented on page 72. one in l3basics for obvious reasons.) 8.) 8. since the closing brace is read by the integer expression in all cases. (End definition for \c_zero.+ \use:c { c__int_from_roman_ #1 _int } \__int_from_roman:NN #2 4080 4081 } 4082 } 4083 4084 4085 4086 4087 4088 } } \cs_new:Npn \__int_from_roman_end:w #1 Q #2 \q_stop { \tl_if_empty:nTF {#2} {#1} {#2} } \cs_new:Npn \__int_from_roman_clean_up:w #1 Q { + 0 Q -1 } (End definition for \int_from_roman:n.) \int_show:n We don’t use the TEX primitive \showthe to show integer expressions: this gives a more unified output.10 \int_show:N \int_show:c 4089 4090 Viewing integer \cs_new_eq:NN \int_show:N \__kernel_register_show:N \cs_new_eq:NN \int_show:c \__kernel_register_show:c (End definition for \int_show:N and \int_show:c. This variable is documented on page 73. in l3basics.) \c_six \c_seven \c_twelve \c_one \c_sixteen \c_two \c_three \c_four \c_five \c_eight \c_nine \c_ten \c_eleven \c_thirteen \c_fourteen \c_fifteen Once again. This function is documented on page 72. 12 \l_tmpa_int \l_tmpb_int \g_tmpa_int \g_tmpb_int Scratch integers We provide two local and two global scratch counters. These variables are documented on page 73. These variables are documented on page 73.) 326 .) 8.) \c_max_int The largest number allowed is 231 − 1 4111 \int_const:Nn \c_max_int { 2 147 483 647 } (End definition for \c_max_int. maybe we need more or less. These variables are documented on page 73.) \c_thirty_two One middling value. for removal by 2011-08-31.) \c_two_hundred_fifty_five \c_two_hundred_fifty_six Two classic mid-range integer constants. 4112 4113 4114 4115 \int_new:N \int_new:N \int_new:N \int_new:N \l_tmpa_int \l_tmpb_int \g_tmpa_int \g_tmpb_int (End definition for \l_tmpa_int and \l_tmpb_int. 4105 \int_const:Nn \c_thirty_two { 32 } (End definition for \c_thirty_two. 4106 4107 \int_const:Nn \c_two_hundred_fifty_five { 255 } \int_const:Nn \c_two_hundred_fifty_six { 256 } (End definition for \c_two_hundred_fifty_five and \c_two_hundred_fifty_six.13 Deprecated functions Deprecated on 2011-05-27. This function is documented on page ??. 4108 4109 4110 \int_const:Nn \c_one_hundred { 100 } \int_const:Nn \c_one_thousand { 1000 } \int_const:Nn \c_ten_thousand { 10000 } (End definition for \c_one_hundred . and \c_ten_thousand.) \c_one_hundred \c_one_thousand \c_ten_thousand Simple runs of powers of ten. These functions are documented on page 73. This variable is documented on page 73. \int_convert_from_base_ten:nn Some simple renames. This variable is documented on page 73. \c_one_thousand .) 8.(End definition for \c_one and others. \int_convert_to_symbols:nnn 4116 h*deprecatedi \int_convert_to_base_ten:nn 4117 \cs_new_eq:NN \int_convert_from_base_ten:nn \int_to_base:nn 4118 \cs_new_eq:NN \int_convert_to_symbols:nnn \int_to_symbols:nnn 4119 \cs_new_eq:NN \int_convert_to_base_ten:nn \int_from_base:nn 4120 h/deprecatedi (End definition for \int_convert_from_base_ten:nn. ) \l_tmpc_int Deprecated 2012-07-04 for removal after 2012-12-31.\int_to_symbol:n \int_to_symbol_math:n \int_to_symbol_text:n This is rather too tied to LATEX 2ε . 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 h*deprecatedi \cs_new_nopar:Npn \int_to_symbol:n { \scan_align_safe_stop: \mode_if_math:TF { \int_to_symbol_math:n } { \int_to_symbol_text:n } } \cs_new:Npn \int_to_symbol_math:n #1 { \int_to_symbols:nnn {#1} { 9 } { { 1 } { * } { 2 } { \dagger } { 3 } { \ddagger } { 4 } { \mathsection } { 5 } { \mathparagraph } { 6 } { \| } { 7 } { ** } { 8 } { \dagger \dagger } { 9 } { \ddagger \ddagger } } } \cs_new:Npn \int_to_symbol_text:n #1 { \int_to_symbols:nnn {#1} { 9 } { { 1 } { \textasteriskcentered { 2 } { \textdagger { 3 } { \textdaggerdbl { 4 } { \textsection { 5 } { \textparagraph { 6 } { \textbardbl { 7 } { \textasteriskcentered \textasteriskcentered { 8 } { \textdagger \textdagger { 9 } { \textdaggerdbl \textdaggerdbl } } h/deprecatedi (End definition for \int_to_symbol:n. This function is documented on page ??.) \if_num:w Deprecated 2012-05-30 for removal after 2012-11-30. This function is documented on page ??. 327 } } } } } } } } } . 4160 4161 4162 h*deprecatedi \cs_new_eq:NN \if_num:w \if_int_compare:w h/deprecatedi (End definition for \if_num:w. ) 4173 9 l3skip implementation 4174 h*initex | packagei 4175 h@@=dimi 4176 4177 4178 4179 4180 9. These functions are documented on page ??. 4181 4182 4183 \cs_new_eq:NN \if_dim:w \tex_ifdim:D \cs_new_eq:NN \__dim_eval:w \etex_dimexpr:D \cs_new_eq:NN \__dim_eval_end: \tex_relax:D (End definition for \if_dim:w. 4170 4171 4172 h*deprecatedi \cs_new_eq:NN \int_value:w \__int_value:w h/deprecatedi (End definition for \int_value:w. This variable is documented on page ??.4163 4164 4165 h*deprecatedi \int_new:N \l_tmpc_int h/deprecatedi (End definition for \l_tmpc_int. . 4166 4167 4168 4169 h*deprecatedi \cs_new_eq:NN \int_eval:w \__int_eval:w \cs_new_eq:NN \int_eval_end: \__int_eval_end: h/deprecatedi (End definition for \int_eval:w and \int_eval_end:. 4184 4185 4186 4187 4188 4189 4190 4191 h*packagei \cs_new_protected:Npn \dim_new:N #1 { \__chk_if_free_cs:N #1 \newdimen #1 } h/packagei \cs_generate_variant:Nn \dim_new:N { c } 328 . This function is documented on page 89. This function is documented on page ??.) \int_value:w Deprecated 2012-07-14 for removal after 2012-12-31.1 \if_dim:w \__dim_eval:w \__dim_eval_end: h/initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Length primitives renamed Primitives renamed.2 \dim_new:N \dim_new:c Creating and initialising dim variables Allocating hdimi registers .) \int_eval:w \int_eval_end: Deprecated 2012-07-13 for removal after 2012-12-31.) 9. . ) \dim_zero:N \dim_zero:c \dim_gzero:N \dim_gzero:c Reset the register to zero.) \dim_if_exist_p:N \dim_if_exist_p:c \dim_if_exist:NTF \dim_if_exist:cTF Copies of the cs functions defined in l3basics. 4202 4203 4204 4205 4206 4207 \cs_new_protected:Npn \dim_zero_new:N #1 { \dim_if_exist:NTF #1 { \dim_zero:N #1 } { \dim_new:N #1 } } \cs_new_protected:Npn \dim_gzero_new:N #1 { \dim_if_exist:NTF #1 { \dim_gzero:N #1 } { \dim_new:N #1 } } \cs_generate_variant:Nn \dim_zero_new:N { c } \cs_generate_variant:Nn \dim_gzero_new:N { c } (End definition for \dim_zero_new:N and others. 4210 4211 4212 4213 4214 \cs_new_protected:Npn \dim_set:Nn #1#2 { #1 ~ \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \dim_gset:Nn { \tex_global:D \dim_set:Nn } \cs_generate_variant:Nn \dim_set:Nn { c } \cs_generate_variant:Nn \dim_gset:Nn { c } (End definition for \dim_set:Nn and \dim_set:cn.) \dim_zero_new:N \dim_zero_new:c \dim_gzero_new:N \dim_gzero_new:c Create a register if needed. p } \prg_new_eq_conditional:NNn \dim_if_exist:c \cs_if_exist:c { TF .) \dim_const:Nn \dim_const:cn Contrarily to integer constants. These functions are documented on page ??. F .) 9. These functions are documented on page ??. otherwise clear it. These functions are documented on page ??. T . These functions are documented on page ??. 4192 4193 4194 4195 4196 4197 \cs_new_protected:Npn \dim_const:Nn #1 { \dim_new:N #1 \dim_gset:Nn #1 } \cs_generate_variant:Nn \dim_const:Nn { c } (End definition for \dim_const:Nn and \dim_const:cn.3 \dim_set:Nn \dim_set:cn \dim_gset:Nn \dim_gset:cn \prg_new_eq_conditional:NNn \dim_if_exist:N \cs_if_exist:N { TF . p } Setting dim variables Setting dimensions is easy enough. cc } 329 .) \dim_set_eq:NN \dim_set_eq:cN \dim_set_eq:Nc \dim_set_eq:cc \dim_gset_eq:NN \dim_gset_eq:cN \dim_gset_eq:Nc \dim_gset_eq:cc All straightforward. even for constants. we cannot avoid using a register. 4198 4199 4200 4201 \cs_new_protected:Npn \dim_zero:N #1 \cs_new_protected:Npn \dim_gzero:N { \cs_generate_variant:Nn \dim_zero:N \cs_generate_variant:Nn \dim_gzero:N { #1 \c_zero_dim } \tex_global:D \dim_zero:N } { c } { c } (End definition for \dim_zero:N and \dim_zero:c. These functions are documented on page ??. T . cc } \cs_new_protected:Npn \dim_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } \cs_generate_variant:Nn \dim_gset_eq:NN { c } \cs_generate_variant:Nn \dim_gset_eq:NN { Nc . These functions are documented on page ??.(End definition for \dim_new:N and \dim_new:c. F . 4215 4216 4217 4218 4219 4220 \cs_new_protected:Npn \dim_set_eq:NN #1#2 { #1 = #2 } \cs_generate_variant:Nn \dim_set_eq:NN { c } \cs_generate_variant:Nn \dim_set_eq:NN { Nc . 4208 4209 (End definition for \dim_if_exist:N and \dim_if_exist:c. #1 \else: \exp_after:wN #1 \fi: } \cs_set:Npn \dim_max:nn #1#2 { \dim_use:N \__dim_eval:w \exp_after:wN \__dim_maxmin:wwN \dim_use:N \__dim_eval:w #1 \exp_after:wN . The absolute value is evaluated by removing a leading . and absolute value with only one evaluation.) 9. > \__dim_eval_end: } \cs_set:Npn \dim_min:nn #1#2 { \dim_use:N \__dim_eval:w \exp_after:wN \__dim_maxmin:wwN \dim_use:N \__dim_eval:w #1 \exp_after:wN .4 \dim_abs:n \__dim_abs:N \dim_max:nn \dim_min:nn \__dim_maxmin:wwN Utilities for dimension calculations Functions for min.(End definition for \dim_set_eq:NN and others. 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 \cs_new_protected:Npn \dim_add:Nn #1#2 { \tex_advance:D #1 by \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \dim_gadd:Nn { \tex_global:D \dim_add:Nn } \cs_generate_variant:Nn \dim_add:Nn { c } \cs_generate_variant:Nn \dim_gadd:Nn { c } \cs_new_protected:Npn \dim_sub:Nn #1#2 { \tex_advance:D #1 by . These functions are documented on page ??. < \__dim_eval_end: } \cs_new:Npn \__dim_maxmin:wwN #1 .) \dim_add:Nn \dim_add:cn \dim_gadd:Nn \dim_gadd:cn \dim_sub:Nn \dim_sub:cn \dim_gsub:Nn \dim_gsub:cn Using by here deals with the (incorrect) case \dimen123.if present. \dim_use:N \__dim_eval:w #2 . These functions are documented on page ??. \dim_use:N \__dim_eval:w #2 .\__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \dim_gsub:Nn { \tex_global:D \dim_sub:Nn } \cs_generate_variant:Nn \dim_sub:Nn { c } \cs_generate_variant:Nn \dim_gsub:Nn { c } (End definition for \dim_add:Nn and \dim_add:cn. max. 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 \cs_new:Npn \dim_abs:n #1 { \exp_after:wN \__dim_abs:N \dim_use:N \__dim_eval:w #1 \__dim_eval_end: } \cs_new:Npn \__dim_abs:N #1 { \if_meaning:w . #3 { \if_dim:w #1 #3 #2 ~ #1 \else: #2 \fi: 330 . #2 . and >. T . avoiding any decimal parts.4261 } (End definition for \dim_abs:n. It is actually easier to grab a dimension operand than an integer one. 4266 4267 4268 4269 4270 \prg_new_conditional:Npnn \dim_compare:nNn #1#2#3 { p . This function is documented on page 77. because once evaluated. TF } { \exp_after:wN \__dim_compare:w \dim_use:N \__dim_eval:w #1 \__prg_compare_error: } \cs_new:Npn \__dim_compare:w #1 \__prg_compare_error: { \exp_after:wN \if_false: \tex_romannumeral:D -‘0 \__dim_compare:wNN #1 ? { = \__dim_compare_end:w \else: } \q_stop } \exp_args:Nno \use:nn { \cs_new:Npn \__dim_compare:wNN #1 } { \tl_to_str:n {pt} } #2#3 { \if_meaning:w = #3 \use:c { __dim_compare_#2:w } \fi: #1 pt \exp_stop_f: 331 . First make sure that there is at least one relation operator. something like 10 pt * ( 5 pt / 10 pt ) will not work. Using \__int_value:w forces everything into sp. TF } { \if_dim:w \__dim_eval:w #1 #2 \__dim_eval:w #3 \__dim_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \dim_compare:nNn. =. Just like for integers. F . the looping auxiliary \__dim_compare:wNN closes a primitive conditional and opens a new one. These functions are documented on page 78. T . F . 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 \prg_new_conditional:Npnn \dim_compare:n #1 { p . Instead. 4262 4263 4264 4265 \cs_new:Npn \dim_ratio:nn #1#2 { \__dim_ratio:n {#1} / \__dim_ratio:n {#2} } \cs_new:Npn \__dim_ratio:n #1 { \__int_value:w \__dim_eval:w #1 \__dim_eval_end: } (End definition for \dim_ratio:nn. the ratio part needs to be converted to an integer expression.) \dim_compare_p:n \dim_compare:nTF \__dim_compare:w \__dim_compare:wNN \__dim_compare_=:w \__dim_compare_!:w \__dim_compare_<:w \__dim_compare_>:w This code is adapted from the \int_compare:nTF function. dimensions all end with pt (with category other).5 \dim_compare_p:nNn \dim_compare:nNnTF Dimension expression conditionals Simple comparison. This function is documented on page 78. by evaluating a dimension expression with a trailing \__prg_compare_error:.) 9. Thus we do not need specific auxiliaries for the three “simple” relations <.) \dim_ratio:nn \__dim_ratio:n With dimension expressions. 4321 4322 4323 4324 4325 4326 4327 4328 4329 \cs_set:Npn \dim_while_do:nn #1#2 { \dim_compare:nT {#1} { #2 \dim_while_do:nn {#1} {#2} } } \cs_set:Npn \dim_until_do:nn #1#2 332 . 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 \cs_new:Npn \dim_case:nnn #1 { \tex_romannumeral:D \exp_args:Nf \__dim_case_aux:nnn { \dim_eval:n {#1} } } \cs_new:Npn \__dim_case_aux:nnn #1#2#3 { \__dim_case_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop } \cs_new:Npn \__dim_case_aux:nw #1#2#3 { \dim_compare:nNnTF {#1} = {#2} { \__dim_case_end:nw {#3} } { \__dim_case_aux:nw {#1} } } \cs_new_eq:NN \__dim_case_end:nw \__prg_case_end:nw (End definition for \dim_case:nnn.6 \dim_while_do:nn \dim_until_do:nn \dim_do_while:nn \dim_do_until:nn Dimension expression loops while_do and do_while functions for dimensions. Same as for the int type only the names have changed. This function is documented on page 80.) 9. These functions are documented on page 79.) \dim_case:nnn \__dim_case_aux:nnn \__dim_case_aux:nw \__dim_case_end:nw The dimension function is the same as the int version.4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 \prg_return_false: \exp_after:wN \use_none_delimit_by_q_stop:w \fi: \reverse_if:N \if_dim:w #1 pt #2 \exp_after:wN \__dim_compare:wNN \dim_use:N \__dim_eval:w #3 } \cs_new:cpn { __dim_compare_ ! :w } #1 \reverse_if:N #2 ! #3 = { #1 #2 = #3 } \cs_new:cpn { __dim_compare_ = :w } #1 \__dim_eval:w = { #1 \__dim_eval:w } \cs_new:cpn { __dim_compare_ < :w } #1 \reverse_if:N #2 < #3 = { #1 #2 > #3 } \cs_new:cpn { __dim_compare_ > :w } #1 \reverse_if:N #2 > #3 = { #1 #2 < #3 } \cs_new:Npn \__dim_compare_end:w #1 \prg_return_false: #2 \q_stop { #1 \prg_return_false: \else: \prg_return_true: \fi: } (End definition for \dim_compare:n. so there is not much to say here. This function is documented on page 81.4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 { \dim_compare:nF {#1} { #2 \dim_until_do:nn {#1} {#2} } } \cs_set:Npn \dim_do_while:nn #1#2 { #2 \dim_compare:nT {#1} { \dim_do_while:nn {#1} {#2} } } \cs_set:Npn \dim_do_until:nn #1#2 { #2 \dim_compare:nF {#1} { \dim_do_until:nn {#1} {#2} } } (End definition for \dim_while_do:nn. Same as for the int type only the names have changed. 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 \cs_set:Npn \dim_while_do:nNnn #1#2#3#4 { \dim_compare:nNnT {#1} #2 {#3} { #4 \dim_while_do:nNnn {#1} #2 {#3} {#4} } } \cs_set:Npn \dim_until_do:nNnn #1#2#3#4 { \dim_compare:nNnF {#1} #2 {#3} { #4 \dim_until_do:nNnn {#1} #2 {#3} {#4} } } \cs_set:Npn \dim_do_while:nNnn #1#2#3#4 { #4 \dim_compare:nNnT {#1} #2 {#3} { \dim_do_while:nNnn {#1} #2 {#3} {#4} } } \cs_set:Npn \dim_do_until:nNnn #1#2#3#4 { #4 \dim_compare:nNnF {#1} #2 {#3} 333 .) \dim_while_do:nNnn \dim_until_do:nNnn \dim_do_while:nNnn \dim_do_until:nNnn while_do and do_while functions for dimensions. ) 334 .) 9. This function is documented on page 89.) \__dim_strip_bp:n 4379 4380 \cs_new:Npn \__dim_strip_bp:n #1 { \__dim_strip_pt:n { 0.{ \dim_do_until:nNnn {#1} #2 {#3} {#4} } 4375 4376 } (End definition for \dim_while_do:nNnn.) \dim_use:N \dim_use:c Accessing a hdimi. but can be given in other units. These functions are documented on page ??. ##2 \tl_to_str:n { pt } ##3 \exp_not:N \q_stop { ##1 \exp_not:N \int_compare:nNnT {##2} > \c_zero { . The idea here is that the input is assumed to be in pt. 4396 4397 \cs_new_eq:NN \dim_use:N \tex_the:D \cs_generate_variant:Nn \dim_use:N { c } (End definition for \dim_use:N and \dim_use:c. while the output is the value of the dimension in pt but with no units given. 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 \cs_new:Npn \__dim_strip_pt:n #1 { \exp_after:wN \__dim_strip_pt:w \dim_use:N \__dim_eval:w #1 \__dim_eval_end: \q_stop } \use:x { \cs_new:Npn \exp_not:N \__dim_strip_pt:w ##1 . This function is documented on page 80. ##2 } } } (End definition for \__dim_strip_pt:n. 4377 4378 \cs_new:Npn \dim_eval:n #1 { \dim_use:N \__dim_eval:w #1 \__dim_eval_end: } (End definition for \dim_eval:n. This is used a lot by low-level manipulations.996 26 \__dim_eval:w #1 \__dim_eval_end: } } (End definition for \__dim_strip_bp:n.7 \dim_eval:n Using dim expressions and variables Evaluating a dimension expression expandably. This function is documented on page 81.) \__dim_strip_pt:n \__dim_strip_pt:w A function which comes up often enough to deserve a place in the kernel. ) 9. since the closing brace is read by the dimension expression in all cases.) 335 . 4404 4405 4406 4407 \dim_new:N \dim_new:N \dim_new:N \dim_new:N \l_tmpa_dim \l_tmpb_dim \g_tmpa_dim \g_tmpb_dim (End definition for \l_tmpa_dim and \l_tmpb_dim. 4402 4403 \dim_const:Nn \c_zero_dim { 0 pt } \dim_const:Nn \c_max_dim { 16383.) 9. These variables are documented on page 82. This function is documented on page 82. 4408 4409 4410 4411 4412 4413 4414 4415 h*packagei \cs_new_protected:Npn \skip_new:N #1 { \__chk_if_free_cs:N #1 \newskip #1 } h/packagei \cs_generate_variant:Nn \skip_new:N { c } (End definition for \skip_new:N and \skip_new:c.9 \c_zero_dim \c_max_dim Constant dimensions Constant dimensions: in package mode.10 \l_tmpa_dim \l_tmpb_dim \g_tmpa_dim \g_tmpb_dim Scratch dimensions We provide two local and two global scratch registers.9. These functions are documented on page ??. maybe we need more or less. 4398 4399 \cs_new_eq:NN \dim_show:N \__kernel_register_show:N \cs_generate_variant:Nn \dim_show:N { c } (End definition for \dim_show:N and \dim_show:c. These functions are documented on page ??.) \dim_show:n Diagnostics.8 \dim_show:N \dim_show:c Viewing dim variables Diagnostics. We don’t use the TEX primitive \showthe to show dimension expressions: this gives a more unified output. a couple of registers can be saved. 4400 4401 \cs_new_protected:Npn \dim_show:n #1 { \etex_showtokens:D \exp_after:wN { \dim_use:N \__dim_eval:w #1 } } (End definition for \dim_show:n.11 \skip_new:N \skip_new:c Creating and initialising skip variables Allocation of a new internal registers.99999 pt } (End definition for \c_zero_dim and \c_max_dim. These functions are documented on page 82.) 9. These functions are documented on page ??. 4432 4433 \prg_new_eq_conditional:NNn \skip_if_exist:N \cs_if_exist:N { TF . p } \prg_new_eq_conditional:NNn \skip_if_exist:c \cs_if_exist:c { TF . T . T .) \skip_zero:N \skip_zero:c \skip_gzero:N \skip_gzero:c Reset the register to zero.\skip_const:Nn \skip_const:cn Contrarily to integer constants. 4416 4417 4418 4419 4420 4421 \cs_new_protected:Npn \skip_const:Nn #1 { \skip_new:N #1 \skip_gset:Nn #1 } \cs_generate_variant:Nn \skip_const:Nn { c } (End definition for \skip_const:Nn and \skip_const:cn. These functions are documented on page ??. 4439 4440 4441 4442 4443 4444 \cs_new_protected:Npn \skip_set_eq:NN #1#2 { #1 = #2 } \cs_generate_variant:Nn \skip_set_eq:NN { c } \cs_generate_variant:Nn \skip_set_eq:NN { Nc . These functions are documented on page ??.) 9. otherwise clear it. cc } \cs_new_protected:Npn \skip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } \cs_generate_variant:Nn \skip_gset_eq:NN { c } \cs_generate_variant:Nn \skip_gset_eq:NN { Nc . we cannot avoid using a register. These functions are documented on page ??. F . F .) \skip_set_eq:NN \skip_set_eq:cN \skip_set_eq:Nc \skip_set_eq:cc \skip_gset_eq:NN \skip_gset_eq:cN \skip_gset_eq:Nc \skip_gset_eq:cc All straightforward.12 \skip_set:Nn \skip_set:cn \skip_gset:Nn \skip_gset:cn Setting skip variables Much the same as for dimensions. These functions are documented on page ??.) \skip_if_exist_p:N \skip_if_exist_p:c \skip_if_exist:NTF \skip_if_exist:cTF Copies of the cs functions defined in l3basics. 4422 4423 4424 4425 \cs_new_protected:Npn \skip_zero:N #1 \cs_new_protected:Npn \skip_gzero:N { \cs_generate_variant:Nn \skip_zero:N \cs_generate_variant:Nn \skip_gzero:N { #1 \c_zero_skip } \tex_global:D \skip_zero:N } { c } { c } (End definition for \skip_zero:N and \skip_zero:c.) \skip_zero_new:N \skip_zero_new:c \skip_gzero_new:N \skip_gzero_new:c Create a register if needed. 4434 4435 4436 4437 4438 \cs_new_protected:Npn \skip_set:Nn #1#2 { #1 ~ \etex_glueexpr:D #2 \scan_stop: } \cs_new_protected:Npn \skip_gset:Nn { \tex_global:D \skip_set:Nn } \cs_generate_variant:Nn \skip_set:Nn { c } \cs_generate_variant:Nn \skip_gset:Nn { c } (End definition for \skip_set:Nn and \skip_set:cn. cc } 336 . p } (End definition for \skip_if_exist:N and \skip_if_exist:c. even for constants. 4426 4427 4428 4429 4430 4431 \cs_new_protected:Npn \skip_zero_new:N #1 { \skip_if_exist:NTF #1 { \skip_zero:N #1 } { \skip_new:N #1 } } \cs_new_protected:Npn \skip_gzero_new:N #1 { \skip_if_exist:NTF #1 { \skip_gzero:N #1 } { \skip_new:N #1 } } \cs_generate_variant:Nn \skip_zero_new:N { c } \cs_generate_variant:Nn \skip_gzero_new:N { c } (End definition for \skip_zero_new:N and others. ##3 ##4 \q_stop {##3} } \exp_args:No \__cs_tmp:w { \tl_to_str:n { fil } } (End definition for \skip_if_finite:n. These functions are documented on page 84. we have an easy access to the order of infinities of the stretch and shrink components of a skip. and then testing them. These functions are documented on page ??.) 9. \prg_return_false: #1 . T . T . 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 \prg_new_conditional:Npnn \skip_if_eq:nn #1#2 { p .\etex_glueexpr:D #2 \scan_stop: } \cs_new_protected:Npn \skip_gsub:Nn { \tex_global:D \skip_sub:Nn } \cs_generate_variant:Nn \skip_sub:Nn { c } \cs_generate_variant:Nn \skip_gsub:Nn { c } (End definition for \skip_add:Nn and \skip_add:cn. These functions are documented on page ??.) 337 .(End definition for \skip_set_eq:NN and others. it is quicker to make it search for the string fil which characterizes infinite glue. 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 \cs_set_protected:Npn \__cs_tmp:w #1 { \prg_new_conditional:Npnn \skip_if_finite:n ##1 { p . only equality is tested. 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 \cs_new_protected:Npn \skip_add:Nn #1#2 { \tex_advance:D #1 by \etex_glueexpr:D #2 \scan_stop: } \cs_new_protected:Npn \skip_gadd:Nn { \tex_global:D \skip_add:Nn } \cs_generate_variant:Nn \skip_add:Nn { c } \cs_generate_variant:Nn \skip_gadd:Nn { c } \cs_new_protected:Npn \skip_sub:Nn #1#2 { \tex_advance:D #1 by . These functions are documented on page 84. TF } { \if_int_compare:w \pdftex_strcmp:D { \skip_eval:n { #1 } } { \skip_eval:n { #2 } } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \skip_if_eq:nn. or evaluate it. we either need to evaluate the expression twice. then call an auxiliary to extract both pieces of information from the result. Since we are going to need an auxiliary anyways. to access both.) \skip_if_finite_p:n \skip_if_finite:nTF \__skip_if_finite:wwNw With ε-TEX. \prg_return_true: \q_stop } \cs_new:Npn \__skip_if_finite:wwNw ##1 #1 ##2 . However.13 \skip_if_eq_p:nn \skip_if_eq:nnTF Skip expression conditionals Comparing skips means doing two expansions to make strings. TF } { \exp_after:wN \__skip_if_finite:wwNw \skip_use:N \etex_glueexpr:D ##1 . F . As a result. F .) \skip_add:Nn \skip_add:cn \skip_gadd:Nn \skip_gadd:cn \skip_sub:Nn \skip_sub:cn \skip_gsub:Nn \skip_gsub:cn Using by here deals with the (incorrect) case \skip123. ) 9. \skip_horizontal:c . 4480 4481 4482 4483 4484 4485 4486 4487 \cs_new_eq:NN \skip_horizontal:N \tex_hskip:D \cs_new:Npn \skip_horizontal:n #1 { \skip_horizontal:N \etex_glueexpr:D #1 \scan_stop: } \cs_new_eq:NN \skip_vertical:N \tex_vskip:D \cs_new:Npn \skip_vertical:n #1 { \skip_vertical:N \etex_glueexpr:D #1 \scan_stop: } \cs_generate_variant:Nn \skip_horizontal:N { c } \cs_generate_variant:Nn \skip_vertical:N { c } (End definition for \skip_horizontal:N .17 \c_zero_skip \c_max_skip Constant skips Skips with no rubber component are just dimensions but need to terminate correctly. 4488 4489 \cs_new_eq:NN \skip_show:N \__kernel_register_show:N \cs_generate_variant:Nn \skip_show:N { c } (End definition for \skip_show:N and \skip_show:c. 4492 4493 \skip_const:Nn \c_zero_skip { \c_zero_dim } \skip_const:Nn \c_max_skip { \c_max_dim } (End definition for \c_zero_skip and \c_max_skip.) \skip_use:N \skip_use:c Accessing a hskipi. 4490 4491 \cs_new_protected:Npn \skip_show:n #1 { \etex_showtokens:D \exp_after:wN { \tex_the:D \etex_glueexpr:D #1 } } (End definition for \skip_show:n.16 \skip_show:N \skip_show:c Viewing skip variables Diagnostics. We don’t use the TEX primitive \showthe to show skip expressions: this gives a more unified output.) 338 . 4476 4477 \cs_new:Npn \skip_eval:n #1 { \skip_use:N \etex_glueexpr:D #1 \scan_stop: } (End definition for \skip_eval:n. This function is documented on page 85. since the closing brace is read by the skip expression in all cases. 4478 4479 \cs_new_eq:NN \skip_use:N \tex_the:D \cs_generate_variant:Nn \skip_use:N { c } (End definition for \skip_use:N and \skip_use:c.) 9.14 \skip_eval:n Using skip expressions and variables Evaluating a skip expression expandably.15 \skip_horizontal:N \skip_horizontal:c \skip_horizontal:n \skip_vertical:N \skip_vertical:c \skip_vertical:n Inserting skips into the output Inserting skips. These functions are documented on page ??. and \skip_horizontal:n.) 9.9. This function is documented on page 84. These functions are documented on page 85.) \skip_show:n Diagnostics. These functions are documented on page ??. These functions are documented on page ??. 4517 4518 4519 4520 4521 4522 \cs_new_protected:Npn \muskip_zero_new:N #1 { \muskip_if_exist:NTF #1 { \muskip_zero:N #1 } { \muskip_new:N #1 } } \cs_new_protected:Npn \muskip_gzero_new:N #1 { \muskip_if_exist:NTF #1 { \muskip_gzero:N #1 } { \muskip_new:N #1 } } \cs_generate_variant:Nn \muskip_zero_new:N { c } \cs_generate_variant:Nn \muskip_gzero_new:N { c } (End definition for \muskip_zero_new:N and others.19 \muskip_new:N \muskip_new:c Creating and initialising muskip variables And then we add muskips.) 339 . These functions are documented on page 85. even for constants.) \muskip_zero_new:N \muskip_zero_new:c \muskip_gzero_new:N \muskip_gzero_new:c Create a register if needed. 4494 4495 4496 4497 \skip_new:N \skip_new:N \skip_new:N \skip_new:N \l_tmpa_skip \l_tmpb_skip \g_tmpa_skip \g_tmpb_skip (End definition for \l_tmpa_skip and \l_tmpb_skip.) \muskip_const:Nn \muskip_const:cn Contrarily to integer constants. 4506 4507 4508 4509 4510 4511 \cs_new_protected:Npn \muskip_const:Nn #1 { \muskip_new:N #1 \muskip_gset:Nn #1 } \cs_generate_variant:Nn \muskip_const:Nn { c } (End definition for \muskip_const:Nn and \muskip_const:cn. 4498 4499 4500 4501 4502 4503 4504 4505 h*packagei \cs_new_protected:Npn \muskip_new:N #1 { \__chk_if_free_cs:N #1 \newmuskip #1 } h/packagei \cs_generate_variant:Nn \muskip_new:N { c } (End definition for \muskip_new:N and \muskip_new:c. otherwise clear it.) \muskip_zero:N \muskip_zero:c \muskip_gzero:N \muskip_gzero:c Reset the register to zero.) 9. 4512 4513 4514 4515 4516 \cs_new_protected:Npn \muskip_zero:N #1 { #1 \c_zero_muskip } \cs_new_protected:Npn \muskip_gzero:N { \tex_global:D \muskip_zero:N } \cs_generate_variant:Nn \muskip_zero:N { c } \cs_generate_variant:Nn \muskip_gzero:N { c } (End definition for \muskip_zero:N and \muskip_zero:c. maybe we need more or less. we cannot avoid using a register.18 \l_tmpa_skip \l_tmpb_skip \g_tmpa_skip \g_tmpb_skip Scratch skips We provide two local and two global scratch registers. These functions are documented on page ??. These functions are documented on page ??. These functions are documented on page ??.9. These functions are documented on page ??. 4525 4526 4527 4528 4529 \cs_new_protected:Npn \muskip_set:Nn #1#2 { #1 ~ \etex_muexpr:D #2 \scan_stop: } \cs_new_protected:Npn \muskip_gset:Nn { \tex_global:D \muskip_set:Nn } \cs_generate_variant:Nn \muskip_set:Nn { c } \cs_generate_variant:Nn \muskip_gset:Nn { c } (End definition for \muskip_set:Nn and \muskip_set:cn. p } (End definition for \muskip_if_exist:N and \muskip_if_exist:c. T .) 340 . These functions are documented on page ??. These functions are documented on page ??.\muskip_if_exist_p:N \muskip_if_exist_p:c \muskip_if_exist:NTF \muskip_if_exist:cTF Copies of the cs functions defined in l3basics. cc } (End definition for \muskip_set_eq:NN and others. These functions are documented on page ??.) \muskip_use:N \muskip_use:c Accessing a hmuskipi. F .\etex_muexpr:D #2 \scan_stop: } \cs_new_protected:Npn \muskip_gsub:Nn { \tex_global:D \muskip_sub:Nn } \cs_generate_variant:Nn \muskip_sub:Nn { c } \cs_generate_variant:Nn \muskip_gsub:Nn { c } (End definition for \muskip_add:Nn and \muskip_add:cn.) 9. 4523 4524 \prg_new_eq_conditional:NNn \muskip_if_exist:N \cs_if_exist:N { TF .) 9. 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 \cs_new_protected:Npn \muskip_add:Nn #1#2 { \tex_advance:D #1 by \etex_muexpr:D #2 \scan_stop: } \cs_new_protected:Npn \muskip_gadd:Nn { \tex_global:D \muskip_add:Nn } \cs_generate_variant:Nn \muskip_add:Nn { c } \cs_generate_variant:Nn \muskip_gadd:Nn { c } \cs_new_protected:Npn \muskip_sub:Nn #1#2 { \tex_advance:D #1 by . 4530 4531 4532 4533 4534 4535 \cs_new_protected:Npn \muskip_set_eq:NN #1#2 { #1 = #2 } \cs_generate_variant:Nn \muskip_set_eq:NN { c } \cs_generate_variant:Nn \muskip_set_eq:NN { Nc . F .) \muskip_set_eq:NN \muskip_set_eq:cN \muskip_set_eq:Nc \muskip_set_eq:cc \muskip_gset_eq:NN \muskip_gset_eq:cN \muskip_gset_eq:Nc \muskip_gset_eq:cc \muskip_add:Nn \muskip_add:cn \muskip_gadd:Nn \muskip_gadd:cn \muskip_sub:Nn \muskip_sub:cn \muskip_gsub:Nn \muskip_gsub:cn All straightforward.20 \muskip_set:Nn \muskip_set:cn \muskip_gset:Nn \muskip_gset:cn Setting muskip variables This should be pretty familiar. These functions are documented on page ??.21 \muskip_eval:n Using muskip expressions and variables Evaluating a muskip expression expandably. 4548 4549 \cs_new_eq:NN \muskip_use:N \tex_the:D \cs_generate_variant:Nn \muskip_use:N { c } (End definition for \muskip_use:N and \muskip_use:c. This function is documented on page 87.) Using by here deals with the (incorrect) case \muskip123. cc } \cs_new_protected:Npn \muskip_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } \cs_generate_variant:Nn \muskip_gset_eq:NN { c } \cs_generate_variant:Nn \muskip_gset_eq:NN { Nc . p } \prg_new_eq_conditional:NNn \muskip_if_exist:c \cs_if_exist:c { TF . T . These functions are documented on page ??. 4546 4547 \cs_new:Npn \muskip_eval:n #1 { \muskip_use:N \etex_muexpr:D #1 \scan_stop: } (End definition for \muskip_eval:n. ) \muskip_show:n Diagnostics. since the closing brace is read by the muskip expression in all cases.) 9.23 \c_zero_muskip \c_max_muskip Constant muskips Constant muskips given by their value. 4560 4561 4562 4563 h*deprecatedi \prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p . These functions are documented on page 88. We don’t use the TEX primitive \showthe to show muskip expressions: this gives a more unified output. 4552 4553 \cs_new_protected:Npn \muskip_show:n #1 { \etex_showtokens:D \exp_after:wN { \tex_the:D \etex_muexpr:D #1 } } (End definition for \muskip_show:n.24 \l_tmpa_muskip \l_tmpb_muskip \g_tmpa_muskip \g_tmpb_muskip Scratch muskips We provide two local and two global scratch registers. for removal by 2012-08-31.25 Deprecated functions Deprecated on 2012-05-10.) Deprecated 2012-06-03 for removal after 2012-12-31. These functions are documented on page ??.99999 mu } (End definition for \c_zero_muskip. This function is documented on page 88. 4550 4551 \cs_new_eq:NN \muskip_show:N \__kernel_register_show:N \cs_generate_variant:Nn \muskip_show:N { c } (End definition for \muskip_show:N and \muskip_show:c. 4554 4555 \muskip_const:Nn \c_zero_muskip { 0 mu } \muskip_const:Nn \c_max_muskip { 16383. 4564 4565 4566 h*deprecatedi \cs_new_eq:NN \prg_case_dim:nnn \dim_case:nnn h/deprecatedi (End definition for \prg_case_dim:nnn. T . This function is documented on page 88.9. \prg_case_dim:nnn Moved here. This function is documented on page ??. F .) 341 .22 \muskip_show:N \muskip_show:c Viewing muskip variables Diagnostics. \skip_if_infinite_glue_p:n \skip_if_infinite_glue:nTF Reverse of \skip_if_finite:nTF.) 9. maybe we need more or less. These functions are documented on page ??. 4556 4557 4558 4559 \muskip_new:N \muskip_new:N \muskip_new:N \muskip_new:N \l_tmpa_muskip \l_tmpb_muskip \g_tmpa_muskip \g_tmpb_muskip (End definition for \l_tmpa_muskip and \l_tmpb_muskip.) 9. TF } { \skip_if_finite:nTF {#1} \prg_return_false: \prg_return_true: } h/deprecatedi (End definition for \skip_if_infinite_glue:n. was in l3prg but load order means we define it here now. including #. 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 h*deprecatedi \cs_new_protected_nopar:Npn \dim_set_max:Nn { \__dim_set_max:NNNn < \dim_set:Nn } \cs_new_protected_nopar:Npn \dim_gset_max:Nn { \__dim_set_max:NNNn < \dim_gset:Nn } \cs_new_protected_nopar:Npn \dim_set_min:Nn { \__dim_set_max:NNNn > \dim_set:Nn } \cs_new_protected_nopar:Npn \dim_gset_min:Nn { \__dim_set_max:NNNn > \dim_gset:Nn } \cs_new_protected:Npn \__dim_set_max:NNNn #1#2#3#4 { \dim_compare:nNnT {#3} #1 {#4} { #2 #3 {#4} } } \cs_generate_variant:Nn \dim_set_max:Nn { c } \cs_generate_variant:Nn \dim_gset_max:Nn { c } \cs_generate_variant:Nn \dim_set_min:Nn { c } \cs_generate_variant:Nn \dim_gset_min:Nn { c } h/deprecatedi (End definition for \dim_set_max:Nn and \dim_set_max:cn. 4595 4596 \cs_new_protected:Npn \tl_new:N #1 { 342 . These functions are documented on page ??. 10.) 4587 h/initex | packagei l3tl implementation 10 4588 h*initex | packagei 4589 h@@=tli 4590 4591 4592 4593 4594 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei A token list variable is a TEX macro that holds tokens. These functions are documented on page ??. By using the ε-TEX primitive \unexpanded inside a TEX \edef it is possible to store any tokens.1 \tl_new:N \tl_new:c Functions Creating new token list variables is a case of checking for an existing definition and doing the definition.) \dim_set_max:Nn \dim_set_max:cn \dim_set_min:Nn \dim_set_min:cn \dim_gset_max:Nn \dim_gset_max:cn \dim_gset_min:Nn \dim_gset_min:cn \__dim_set_max:NNNn Deprecated on 2012-09-09 for removal after 2012-12-31.\dim_eval:w \dim_eval_end: 4567 4568 4569 4570 h*deprecatedi \cs_new_eq:NN \dim_eval:w \__dim_eval:w \cs_new_eq:NN \dim_eval_end: \__dim_eval_end: h/deprecatedi (End definition for \dim_eval:w and \dim_eval_end:. in this way. 4625 4626 4627 4628 4629 4630 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \tl_set_eq:NN \tl_set_eq:cN \tl_set_eq:Nc \tl_set_eq:cc \tl_gset_eq:NN \tl_gset_eq:cN \cs_set_eq:NN \cs_set_eq:cN \cs_set_eq:Nc \cs_set_eq:cc \cs_gset_eq:NN \cs_gset_eq:cN 343 .) \tl_const:Nn \tl_const:Nx \tl_const:cn \tl_const:cx Constants are also easy to generate. Error checking will be sorted out by the parent function. These functions are documented on page ??.4597 4598 4599 4600 \__chk_if_free_cs:N #1 \cs_gset_eq:NN #1 \c_empty_tl } \cs_generate_variant:Nn \tl_new:N { c } (End definition for \tl_new:N and \tl_new:c. 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 \cs_new_protected:Npn \tl_const:Nn #1#2 { \__chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_const:Nx #1#2 { \__chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 {#2} } \cs_generate_variant:Nn \tl_const:Nn { c } \cs_generate_variant:Nn \tl_const:Nx { c } (End definition for \tl_const:Nn and others. 4619 4620 4621 4622 4623 4624 \cs_new_protected:Npn \tl_clear_new:N #1 { \tl_if_exist:NTF #1 { \tl_clear:N #1 } { \tl_new:N #1 } } \cs_new_protected:Npn \tl_gclear_new:N #1 { \tl_if_exist:NTF #1 { \tl_gclear:N #1 } { \tl_new:N #1 } } \cs_generate_variant:Nn \tl_clear_new:N { c } \cs_generate_variant:Nn \tl_gclear_new:N { c } (End definition for \tl_clear_new:N and \tl_clear_new:c. Error checking will be sorted out by the parent function.) \tl_clear_new:N \tl_clear_new:c \tl_gclear_new:N \tl_gclear_new:c Clearing a token list variable means setting it to an empty value.) \tl_set_eq:NN \tl_set_eq:Nc \tl_set_eq:cN \tl_set_eq:cc \tl_gset_eq:NN \tl_gset_eq:Nc \tl_gset_eq:cN \tl_gset_eq:cc For setting token list variables equal to each other. These functions are documented on page ??. These functions are documented on page ??. These functions are documented on page ??. 4613 4614 4615 4616 4617 4618 \cs_new_protected:Npn \tl_clear:N #1 { \tl_set_eq:NN #1 \c_empty_tl } \cs_new_protected:Npn \tl_gclear:N #1 { \tl_gset_eq:NN #1 \c_empty_tl } \cs_generate_variant:Nn \tl_clear:N { c } \cs_generate_variant:Nn \tl_gclear:N { c } (End definition for \tl_clear:N and \tl_clear:c.) \tl_clear:N \tl_clear:c \tl_gclear:N \tl_gclear:c Clearing a token list variable means setting it to an empty value. 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 h*initexi \luatex_if_engine:T { \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \lua_now_x:n { dofile ( assert ( kpse.) \c_job_name_tl Inherited from the LATEX3 name for the primitive: this needs to actually contain the text of the job name rather than the name of the primitive. These functions are documented on page ??. 4639 4640 \prg_new_eq_conditional:NNn \tl_if_exist:N \cs_if_exist:N { TF .find_file ("lualatexquotejobname. T . T .2 \c_empty_tl Constant token lists Never full. 4633 4634 4635 4636 4637 4638 \cs_new_protected:Npn \tl_concat:NNN #1#2#3 { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } \cs_new_protected:Npn \tl_gconcat:NNN #1#2#3 { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } \cs_generate_variant:Nn \tl_concat:NNN { ccc } \cs_generate_variant:Nn \tl_gconcat:NNN { ccc } (End definition for \tl_concat:NNN and \tl_concat:ccc.) 10. This variable is documented on page 102. F .) 344 . These functions are documented on page ??. 4641 \tl_const:Nn \c_empty_tl { } (End definition for \c_empty_tl. p } \prg_new_eq_conditional:NNn \tl_if_exist:c \cs_if_exist:c { TF . of course. LuaTEX does not quote file names containing spaces. whereas pdfTEX and XETEX do.lua" ) ) ) } } } \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \tl_const:Nx \c_job_name_tl { \tex_jobname:D } } h/initexi h*packagei \tl_const:Nx \c_job_name_tl { \tex_jobname:D } h/packagei (End definition for \c_job_name_tl.) \tl_if_exist_p:N \tl_if_exist_p:c \tl_if_exist:NTF \tl_if_exist:cTF Copies of the cs functions defined in l3basics.4631 4632 \cs_new_eq:NN \tl_gset_eq:Nc \cs_gset_eq:Nc \cs_new_eq:NN \tl_gset_eq:cc \cs_gset_eq:cc (End definition for \tl_set_eq:NN and others. F . We need to define that constant before using \tl_new:N.) \tl_concat:NNN \tl_concat:ccc \tl_gconcat:NNN \tl_gconcat:ccc Concatenating token lists is easy. So there may be a correction to make in the LuaTEX case. p } (End definition for \tl_if_exist:N and \tl_if_exist:c. This variable is documented on page 102. These functions are documented on page ??. 4661 \tl_const:Nn \c_space_tl { ~ } (End definition for \c_space_tl.) 10. 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 \cs_new_protected:Npn \tl_put_left:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:NV #1#2 { \cs_set_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:Nx #1#2 { \cs_set_nopar:Npx #1 { #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:NV #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:Nx #1#2 { \cs_gset_nopar:Npx #1 { #2 \exp_not:o {#1} } } \cs_generate_variant:Nn \tl_put_left:Nn { c } \cs_generate_variant:Nn \tl_put_left:NV { c } 345 . Nv . cV \cs_generate_variant:Nn \tl_gset:Nn { NV \cs_generate_variant:Nn \tl_gset:Nx { c } \cs_generate_variant:Nn \tl_gset:Nn { c. co . 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 \cs_new_protected:Npn \tl_set:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_set:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o {#2} } } \cs_new_protected:Npn \tl_set:Nx #1#2 { \cs_set_nopar:Npx #1 {#2} } \cs_new_protected:Npn \tl_gset:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_gset:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} } } \cs_new_protected:Npn \tl_gset:Nx #1#2 { \cs_gset_nopar:Npx #1 {#2} } \cs_generate_variant:Nn \tl_set:Nn { NV \cs_generate_variant:Nn \tl_set:Nx { c } \cs_generate_variant:Nn \tl_set:Nn { c. The \tl_set:No version is done “by hand” as it is used quite a lot. Nv .\c_space_tl A space as a token list (as opposed to as a character). Nf } . This variable is documented on page 102. Nf } .) Adding to the left is done directly to gain a little performance. cV . cv . co . These functions are documented on page ??. cf } . which makes the token list registers provided by TEX more or less redundant. cv .3 \tl_set:Nn \tl_set:NV \tl_set:Nv \tl_set:No \tl_set:Nf \tl_set:Nx \tl_set:cn \tl_set:cV \tl_set:cv \tl_set:co \tl_set:cf \tl_set:cx \tl_gset:Nn \tl_gset:NV \tl_gset:Nv \tl_gset:No \tl_gset:Nf \tl_gset:Nx \tl_gset:cn \tl_gset:cV \tl_gset:cv \tl_gset:co \tl_put_left:Nn \tl_gset:cf \tl_put_left:NV \tl_gset:cx \tl_put_left:No \tl_put_left:Nx \tl_put_left:cn \tl_put_left:cV \tl_put_left:co \tl_put_left:cx \tl_gput_left:Nn \tl_gput_left:NV \tl_gput_left:No \tl_gput_left:Nx \tl_gput_left:cn \tl_gput_left:cV \tl_gput_left:co \tl_gput_left:cx Adding to token list variables By using \exp_not:n token list variables can contain # tokens. cf } (End definition for \tl_set:Nn and others. ) \tl_put_right:Nn \tl_put_right:NV \tl_put_right:No \tl_put_right:Nx \tl_put_right:cn \tl_put_right:cV \tl_put_right:co \tl_put_right:cx \tl_gput_right:Nn \tl_gput_right:NV \tl_gput_right:No \tl_gput_right:Nx \tl_gput_right:cn \tl_gput_right:cV \tl_gput_right:co \tl_gput_right:cx The same on the right. 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 \group_begin: \tex_lccode:D ‘\A = ‘\@ \scan_stop: \tex_lccode:D ‘\B = ‘\@ \scan_stop: \tex_catcode:D ‘\A = 8 \scan_stop: \tex_catcode:D ‘\B = 3 \scan_stop: \tex_lowercase:D { \group_end: \tl_const:Nn \c__tl_rescan_marker_tl { A B } } 346 .4698 4699 4700 4701 4702 4703 \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \tl_put_left:No \tl_put_left:Nx \tl_gput_left:Nn \tl_gput_left:NV \tl_gput_left:No \tl_gput_left:Nx { { { { { { c c c c c c } } } } } } (End definition for \tl_put_left:Nn and others. These functions are documented on page ??.4 \c__tl_rescan_marker_tl Reassigning token list category codes The rescanning code needs a special token list containing the same character with two different category codes. while the detail is described below. This is set up here. 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 \cs_new_protected:Npn \tl_put_right:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } \cs_new_protected:Npn \tl_put_right:NV #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } \cs_new_protected:Npn \tl_put_right:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } \cs_new_protected:Npn \tl_put_right:Nx #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 #2 } } \cs_new_protected:Npn \tl_gput_right:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } \cs_new_protected:Npn \tl_gput_right:NV #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } \cs_new_protected:Npn \tl_gput_right:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } \cs_new_protected:Npn \tl_gput_right:Nx #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#1} #2 } } \cs_generate_variant:Nn \tl_put_right:Nn { c } \cs_generate_variant:Nn \tl_put_right:NV { c } \cs_generate_variant:Nn \tl_put_right:No { c } \cs_generate_variant:Nn \tl_put_right:Nx { c } \cs_generate_variant:Nn \tl_gput_right:Nn { c } \cs_generate_variant:Nn \tl_gput_right:NV { c } \cs_generate_variant:Nn \tl_gput_right:No { c } \cs_generate_variant:Nn \tl_gput_right:Nx { c } (End definition for \tl_put_right:Nn and others.) 10. These functions are documented on page ??. and without the correct settings a TEX error occurs: ! File ended while scanning definition of . because all @ present in the token list are read with the same category code. The rescanned token list cannot contain the end marker.) \tl_set_rescan:Nnn \tl_set_rescan:Nno \tl_set_rescan:Nnx \tl_set_rescan:cnn \tl_set_rescan:cno \tl_set_rescan:cnx \tl_gset_rescan:Nnn \tl_gset_rescan:Nno \tl_gset_rescan:Nnx \tl_gset_rescan:cnn \tl_gset_rescan:cno \tl_gset_rescan:cnx \tl_rescan:nn \__tl_set_rescan:NNnn \__tl_rescan:w The idea here is to deal cleanly with the problem that \scantokens treats the argument as a file. When expanding a token list this can be handled using \exp_not:N but this fails if the token list is not being expanded. So instead a delimited argument is used with an end marker which cannot appear within the token list which is scanned: two @ symbols with different category codes. 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 \cs_new_protected_nopar:Npn \tl_set_rescan:Nnn { \__tl_set_rescan:NNnn \tl_set:Nn } \cs_new_protected_nopar:Npn \tl_gset_rescan:Nnn { \__tl_set_rescan:NNnn \tl_gset:Nn } \cs_new_protected_nopar:Npn \tl_rescan:nn { \__tl_set_rescan:NNnn \prg_do_nothing: \use:n } \cs_new_protected:Npn \__tl_set_rescan:NNnn #1#2#3#4 { \group_begin: \exp_args:No \etex_everyeof:D { \c__tl_rescan_marker_tl \exp_not:N } \tex_endlinechar:D \c_minus_one \tex_newlinechar:D \c_minus_one #3 \use:x { \group_end: #1 \exp_not:N #2 { \exp_after:wN \__tl_rescan:w \exp_after:wN \prg_do_nothing: \etex_scantokens:D {#4} } } } \use:x { \cs_new:Npn \exp_not:N \__tl_rescan:w ##1 \c__tl_rescan_marker_tl { \exp_not:N \exp_not:o { ##1 } } } \cs_generate_variant:Nn \tl_set_rescan:Nnn { Nno . and an extra \endlinechar is added at the end. Nnx } \cs_generate_variant:Nn \tl_gset_rescan:Nnn { c . “unprintable”. Nnx } \cs_generate_variant:Nn \tl_set_rescan:Nnn { c .) 347 . cno } (End definition for \tl_set_rescan:Nnn and others. These functions are documented on page 93. As every character with charcode \newlinechar is replaced by the \endlinechar. cnx } \cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nno . This variable is documented on page ??. cno ..(End definition for \c__tl_rescan_marker_tl.. we need to set both of those to −1. which ends the recursion cleanly. At the end. We use an auxiliary function \__tl_tmp:w. How do we detect that we have reached the last occurrence of hsearch tokensi? The last replacement is characterized by the fact that the argument of \__tl_tmp:w contains \q_mark. which essentially replaces the next hsearch tokensi by hreplacement tokensi. and removes the following token. 4772 4773 4774 4775 \cs_new_protected:Npn \tl_to_lowercase:n #1 { \tex_lowercase:D {#1} } \cs_new_protected:Npn \tl_to_uppercase:n #1 { \tex_uppercase:D {#1} } (End definition for \tl_to_lowercase:n.10. to be included in the x-expanding definition. hsearch tokensi. and leaves the hreplacement tokensi. this gobbles \q_mark \use_none_delimit_by_q_stop:w which appear in the definition of \__tl_tmp:w.) 10. Before we reach the end. 4788 4789 4790 4791 4792 4793 4794 4795 \cs_new_protected:Npn \__tl_replace:NNNnn #1#2#3#4#5 { \tl_if_empty:nTF {#4} { \__msg_kernel_error:nnx { kernel } { empty-search-pattern } { \tl_to_str:n {#5} } } { 348 . \tl_(g)set:Nx. repeating until the end. To avoid runaway arguments. we expand something like \__tl_tmp:w htoken listi \q_mark hsearch tokensi \q_stop. whose arguments are: hfunctioni. In the code below. leaving \use_none_delimit_by_q_stop:w. the first \q_mark is within the argument of \__tl_tmp:w. This function is documented on page 94. The replacement happens within an x-type expansion. hreplacement tokensi.5 \tl_to_lowercase:n \tl_to_uppercase:n Reassigning token list character codes Just some names for a few primitives: we take care or wrapping the argument in braces. and \__tl_replace:w gobbles the second \q_mark as well.6 \tl_replace_all:Nnn \tl_replace_all:cnn \tl_greplace_all:Nnn \tl_greplace_all:cnn \tl_replace_once:Nnn \tl_replace_once:cnn \tl_greplace_once:Nnn \tl_greplace_once:cnn \__tl_replace:NNNnn \__tl_replace:w \__tl_replace_all: \__tl_replace_once: \__tl_replace_once_end:w Modifying token list variables All of the replace functions are based on \__tl_replace:NNNnn. \__tl_replace:w takes an argument delimited by \q_mark. passed to \exp_not:n. htl vari. 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 \cs_new_protected_nopar:Npn \tl_replace_once:Nnn { \__tl_replace:NNNnn \__tl_replace_once: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_once:Nnn { \__tl_replace:NNNnn \__tl_replace_once: \tl_gset:Nx } \cs_new_protected_nopar:Npn \tl_replace_all:Nnn { \__tl_replace:NNNnn \__tl_replace_all: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_all:Nnn { \__tl_replace:NNNnn \__tl_replace_all: \tl_gset:Nx } \cs_generate_variant:Nn \tl_replace_once:Nnn { c } \cs_generate_variant:Nn \tl_greplace_once:Nnn { c } \cs_generate_variant:Nn \tl_replace_all:Nnn { c } \cs_generate_variant:Nn \tl_greplace_all:Nnn { c } The idea is easier to understand by considering the case of \tl_replace_all:Nnn. Note also that we build \__tl_tmp:w within an x-expansion so that the hreplacement tokensi can contain #.4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 \group_align_safe_begin: \cs_set:Npx \__tl_tmp:w ##1##2 #4 { ##2 \exp_not:N \q_mark \exp_not:N \use_none_delimit_by_q_stop:w \exp_not:n { \exp_not:n {#5} } ##1 } \group_align_safe_end: #2 #3 { \exp_after:wN #1 #3 \q_mark #4 \q_stop } } } \cs_new:Npn \__tl_replace:w #1 \q_mark #2 { \exp_not:o {#1} } The first argument of \__tl_tmp:w is responsible for repeating the replacement in the case of replace_all. These functions are documented on page ??.) \tl_remove_once:Nn \tl_remove_once:cn \tl_gremove_once:Nn \tl_gremove_once:cn Removal is just a special case of replacement. The second \exp_not:n ensures that the hreplacement tokensi are not expanded by \tl_(g)set:Nx. 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 \cs_new_nopar:Npn \__tl_replace_all: { \exp_after:wN \__tl_replace:w \__tl_tmp:w \__tl_replace_all: \prg_do_nothing: } \cs_new_nopar:Npn \__tl_replace_once: { \exp_after:wN \__tl_replace:w \__tl_tmp:w { \__tl_replace_once_end:w \prg_do_nothing: } \prg_do_nothing: } \cs_new:Npn \__tl_replace_once_end:w #1 \q_mark #2 \q_stop { \exp_not:o {#1} } (End definition for \tl_replace_all:Nnn and \tl_replace_all:cnn. and stopping it early for replace_once. The \prg_do_nothing: and accompanying o-expansion ensure that we don’t lose braces in case the tokens between two occurrences of the hsearch tokensi form a brace group. Now on to the difference between “once” and “all”. 4826 4827 4828 4829 4830 4831 \cs_new_protected:Npn \tl_remove_once:Nn #1#2 { \tl_replace_once:Nnn #1 {#2} { } } \cs_new_protected:Npn \tl_gremove_once:Nn #1#2 { \tl_greplace_once:Nnn #1 {#2} { } } \cs_generate_variant:Nn \tl_remove_once:Nn { c } \cs_generate_variant:Nn \tl_gremove_once:Nn { c } 349 . T . For performance reasons.) \tl_if_empty_p:N \tl_if_empty_p:c \tl_if_empty:NTF \tl_if_empty:cTF These functions check whether the token list in the argument is empty and execute the proper code from their argument(s).(End definition for \tl_remove_once:Nn and \tl_remove_once:cn. These functions are documented on page ??.. we hardcode the emptyness test done in \tl_if_empty:n(TF): convert to harmless characters with \tl_to_str:n. 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 \prg_new_conditional:Npnn \tl_if_blank:n #1 { p . Thus. TF } { { { { c c c c } } } } .7 \tl_if_blank_p:n \tl_if_blank_p:V \tl_if_blank_p:o \tl_if_blank:nTF \tl_if_blank:VTF \tl_if_blank:oTF \__tl_if_blank_p:NNw Token list conditionals TEX skips spaces when reading a non-delimited arguments. F . a htoken listi is blank if and only if \use_none:n htoken listi ? is empty. \q_nil. These functions are documented on page ??. T . 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 \prg_new_conditional:Npnn \tl_if_empty:N { \if_meaning:w #1 \c_empty_tl \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_empty_p:N \cs_generate_variant:Nn \tl_if_empty:NT \cs_generate_variant:Nn \tl_if_empty:NF \cs_generate_variant:Nn \tl_if_empty:NTF 350 #1 { p . 4832 4833 4834 4835 4836 4837 \cs_new_protected:Npn \tl_remove_all:Nn #1#2 { \tl_replace_all:Nnn #1 {#2} { } } \cs_new_protected:Npn \tl_gremove_all:Nn #1#2 { \tl_greplace_all:Nnn #1 {#2} { } } \cs_generate_variant:Nn \tl_remove_all:Nn { c } \cs_generate_variant:Nn \tl_gremove_all:Nn { c } 10.) \tl_remove_all:Nn \tl_remove_all:cn \tl_gremove_all:Nn \tl_gremove_all:cn Removal is just a special case of replacement.. F . The similar construction \exp_after:wN \use_none:n \tl_to_str:n {htoken listi} ? would fail if the token list contains the control sequence \. while \escapechar is a space or is unprintable. TF } { \__tl_if_empty_return:o { \use_none:n #1 ? } } \cs_generate_variant:Nn \tl_if_blank_p:n { V } \cs_generate_variant:Nn \tl_if_blank:nT { V } \cs_generate_variant:Nn \tl_if_blank:nF { V } \cs_generate_variant:Nn \tl_if_blank:nTF { V } \cs_generate_variant:Nn \tl_if_blank_p:n { o } \cs_generate_variant:Nn \tl_if_blank:nT { o } \cs_generate_variant:Nn \tl_if_blank:nF { o } \cs_generate_variant:Nn \tl_if_blank:nTF { o } (End definition for \tl_remove_all:Nn and \tl_remove_all:cn. and then use \if_meaning:w \q_nil . Note that converting to a string is done after reading the delimited argument for \use_none:n. . the \fi: ends it and the \q_nil at the end starts executing. Note that this works because \tl_to_str:n expands tokens that follow until reading a catcode 1 (begin-group) token.(End definition for \tl_if_empty:N and \tl_if_empty:c. it fails on a token list starting with \q_nil of course but more troubling is the case where argument is a complete conditional such as \if_true: a \else: b \fi: because then \if_true: is used by \if_meaning:w. F } { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n {#1} \q_nil \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_empty_p:n { V } \cs_generate_variant:Nn \tl_if_empty:nTF { V } \cs_generate_variant:Nn \tl_if_empty:nT { V } \cs_generate_variant:Nn \tl_if_empty:nF { V } (End definition for \tl_if_empty:n and \tl_if_empty:V.) \tl_if_empty_p:o \tl_if_empty:oTF \__tl_if_empty_return:o The auxiliary function \__tl_if_empty_return:o is for use in conditionals on token lists. 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 \cs_new:Npn \__tl_if_empty_return:o #1 { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n \exp_after:wN {#1} \q_nil \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \tl_if_empty:o #1 { p . TF . . This way the test will even accept \q_nil as the first token. as this auxiliary function is used in many places.) \tl_if_eq_p:NN \tl_if_eq_p:Nc \tl_if_eq_p:cN \tl_if_eq_p:cc \tl_if_eq:NNTF \tl_if_eq:NcTF \tl_if_eq:cNTF \tl_if_eq:ccTF Returns \c_true_bool if and only if the two token list variables are equal.) \tl_if_empty_p:n \tl_if_empty_p:V \tl_if_empty:nTF \tl_if_empty:VTF It would be tempting to just use \if_meaning:w \q_nil #1 \q_nil as a test since this works really well. A safer route is to convert the entire token list into harmless characters first and then compare that. T . These functions are documented on page ??. 4883 4884 4885 4886 \prg_new_conditional:Npnn \tl_if_eq:NN #1#2 { p . but the expansion is hard-coded for efficiency. 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 \prg_new_conditional:Npnn \tl_if_empty:n #1 { p . the test turns out false. These functions are documented on page ??. TF . TF } { \if_meaning:w #1 #2 \prg_return_true: 351 . The test for emptiness is based on \tl_if_empty:n(TF). These functions are documented on page ??. the \else: executes the false branch. T . F } { \__tl_if_empty_return:o {#1} } (End definition for \tl_if_empty:o. F . T . which mostly reduce to testing if a given token list is empty after applying a simple function to it. However. c c c c . 4916 \prg_new_protected_conditional:Npnn \tl_if_in:nn #1#2 { T 352 . and the test is false. The function \__tl_tmp:w removes tokens until the first occurrence of #2. This marker may not appear in #2 because of TEX limitations on what can delimit a parameter. we insert {}{} between the two token lists. Otherwise some tokens remain. To cater for this case.) \tl_if_in:NnTF \tl_if_in:cnTF See \tl_if_in:nn(TF) for further comments.4887 4888 4889 4890 4891 4892 4893 4894 \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn \tl_if_eq_p:NN \tl_if_eq:NNTF \tl_if_eq:NNT \tl_if_eq:NNF { { { { Nc Nc Nc Nc . cc cc cc cc } } } } (End definition for \tl_if_eq:NN and others. { \group_begin: \tl_set:Nn \l__tl_internal_a_tl {#1} \tl_set:Nn \l__tl_internal_b_tl {#2} \if_meaning:w \l__tl_internal_a_tl \l__tl_internal_b_tl \group_end: \prg_return_true: \else: \group_end: \prg_return_false: \fi: } \tl_new:N \l__tl_internal_a_tl \tl_new:N \l__tl_internal_b_tl TF } (End definition for \tl_if_eq:nn. leaving an empty token list. hence we are safe. These functions are documented on page ??. then the final #2 is removed.) \tl_if_eq:nnTF \l__tl_internal_a_tl \l__tl_internal_b_tl A simple store and compare routine. . . TF } . F . 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 \prg_new_protected_conditional:Npnn \tl_if_eq:nn #1#2 { T . .) \tl_if_in:nnTF \tl_if_in:VnTF \tl_if_in:onTF \tl_if_in:noTF Once more. . If this does not appear in #1. This function is documented on page ??. See \tl_if_empty:n(TF) for details on the emptyness test. Here we simply expand the token list variable and pass it to \tl_if_in:nn(TF). These functions are documented on page ??. 4910 4911 4912 4913 4914 4915 \cs_new_protected_nopar:Npn \tl_if_in:NnT { \exp_args:No \tl_if_in:nnT } \cs_new_protected_nopar:Npn \tl_if_in:NnF { \exp_args:No \tl_if_in:nnF } \cs_new_protected_nopar:Npn \tl_if_in:NnTF { \exp_args:No \tl_if_in:nnTF } \cs_generate_variant:Nn \tl_if_in:NnT { c } \cs_generate_variant:Nn \tl_if_in:NnF { c } \cs_generate_variant:Nn \tl_if_in:NnTF { c } (End definition for \tl_if_in:NnTF and \tl_if_in:cnTF. . Using two brace groups makes the test work also for empty arguments. . the test relies on \tl_to_str:n for robustness. where #1#2 contains #2 before the end. F . Special care is needed to treat correctly cases like \tl_if_in:nnTF {a state}{states}. The naive version of this test would do \use_none:n #1. no } (End definition for \tl_if_in:nnTF and others.) 10. this will fail when the token list is empty. These functions are documented on page 95. F .) \tl_if_single_p:N \tl_if_single:NTF Expand the token list and feed it to \tl_if_single:n.) \tl_if_single_p:n \tl_if_single:nTF A token list has exactly one item if it is a single token or a single brace group. no } \cs_generate_variant:Nn \tl_if_in:nnTF { V . These have the advantage of not needing to test if the argument is empty. because if it is. and test if the result is empty. the stop marker will be read immediately and the loop terminated. o .8 \tl_map_function:nN \tl_map_function:NN \tl_map_function:cN \__tl_map_function:Nn Mapping to token lists Expandable loop macro for token lists. it does not allow optional trailing spaces. These functions are documented on page 95. 4944 4945 \cs_new:Npn \tl_map_function:nN #1#2 { 353 . 4929 4930 \prg_new_conditional:Npnn \tl_if_single:n #1 { p . T . surrounded by optional explicit spaces.{ 4917 \cs_set:Npn \__tl_tmp:w ##1 #2 { } \tl_if_empty:oTF { \__tl_tmp:w #1 {} {} #2 } { \prg_return_false: } { \prg_return_true: } 4918 4919 4920 4921 4922 4923 4924 } \cs_generate_variant:Nn \tl_if_in:nnT { V . o . However. 4925 4926 4927 4928 \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \tl_if_single_p:N \tl_if_single:NT \tl_if_single:NF \tl_if_single:NTF { { { { \exp_args:No \exp_args:No \exp_args:No \exp_args:No \tl_if_single_p:n \tl_if_single:nT \tl_if_single:nF \tl_if_single:nTF } } } } (End definition for \tl_if_single:N. These functions are documented on page ??. no } \cs_generate_variant:Nn \tl_if_in:nnF { V .) \tl_case:Nnn \tl_case:cnn \__tl_case:Nw \__tl_case_end:nw 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 \cs_new:Npn \tl_case:Nnn #1#2#3 { \tex_romannumeral:D \__tl_case:Nw #1 #2 #1 {#3} \q_recursion_stop } \cs_new:Npn \__tl_case:Nw #1#2#3 { \tl_if_eq:NNTF #1 #2 { \__tl_case_end:nw {#3} } { \__tl_case:Nw #1 } } \cs_generate_variant:Nn \tl_case:Nnn { c } \cs_new_eq:NN \__tl_case_end:nw \__prg_case_end:nw (End definition for \tl_case:Nnn and \tl_case:cnn. These functions are documented on page ??. Furthermore. o . TF } { \__str_if_eq_x_return:nn { \exp_not:o { \use_none:nn #1 ?? } } {?} } (End definition for \tl_if_single:n. 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 \cs_new_protected:Npn \tl_map_inline:nn #1#2 { \int_gincr:N \g__prg_map_int \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2} \exp_args:Nc \__tl_map_function:Nn { __prg_map_ \int_use:N \g__prg_map_int :w } #1 \q_recursion_tail \__prg_break_point:Nn \tl_map_break: { \int_gdecr:N \g__prg_map_int } } \cs_new_protected:Npn \tl_map_inline:Nn { \exp_args:No \tl_map_inline:nn } \cs_generate_variant:Nn \tl_map_inline:Nn { c } (End definition for \tl_map_inline:nn.) \tl_map_inline:nn \tl_map_inline:Nn \tl_map_inline:cn The inline functions are straight forward by now. We can also make use of \__tl_map_function:Nn from before.) \tl_map_variable:nNn \tl_map_variable:NNn \tl_map_variable:cNn \__tl_map_variable:Nnn \tl_map_variable:nNn htoken listi htempi hactioni assigns htempi to each element and executes hactioni. We use a little trick with the counter \g__prg_map_int to make them nestable. This function is documented on page ??.4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 \__tl_map_function:Nn #2 #1 \q_recursion_tail \__prg_break_point:Nn \tl_map_break: { } } \cs_new_nopar:Npn \tl_map_function:NN { \exp_args:No \tl_map_function:nN } \cs_new:Npn \__tl_map_function:Nn #1#2 { \__quark_if_recursion_tail_break:nN {#2} \tl_map_break: #1 {#2} \__tl_map_function:Nn #1 } \cs_generate_variant:Nn \tl_map_function:NN { c } (End definition for \tl_map_function:nN. This function is documented on page ??. 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 \cs_new_protected:Npn \tl_map_variable:nNn #1#2#3 { \__tl_map_variable:Nnn #2 {#3} #1 \q_recursion_tail \__prg_break_point:Nn \tl_map_break: { } } \cs_new_protected_nopar:Npn \tl_map_variable:NNn { \exp_args:No \tl_map_variable:nNn } \cs_new_protected:Npn \__tl_map_variable:Nnn #1#2#3 { \tl_set:Nn #1 {#3} \__quark_if_recursion_tail_break:NN #1 \tl_map_break: \use:n {#2} \__tl_map_variable:Nnn #1 {#2} } \cs_generate_variant:Nn \tl_map_variable:NNn { c } 354 . (End definition for \tl_map_variable:nNn. This function is documented on page 97. 4990 \cs_new_eq:NN \tl_to_str:n \etex_detokenize:D (End definition for \tl_to_str:n. No such luck for ones equal to \scan_stop: so instead a test is made and if there is an issue an error is forced.) \tl_use:N \tl_use:c Token lists which are simply not defined will give a clear TEX error here. These functions are documented on page ??. These functions are documented on page ??. This function is documented on page ??.) \tl_to_str:N \tl_to_str:c These functions return the replacement text of a token list as a string.) \tl_map_break: \tl_map_break:n The break statements use the general \__prg_map_break:Nn. 4993 4994 4995 4996 4997 4998 \cs_new:Npn \tl_use:N #1 { \tl_if_exist:NTF #1 {#1} { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } } \cs_generate_variant:Nn \tl_use:N { c } (End definition for \tl_use:N and \tl_use:c. The 0 to ensure it works on an empty list.10 \tl_count:n \tl_count:V \tl_count:o \tl_count:N \tl_count:c \__tl_count:n Working with the contents of token lists Count number of elements within a token list or token list variable.) 10. 4991 4992 \cs_new:Npn \tl_to_str:N #1 { \etex_detokenize:D \exp_after:wN {#1} } \cs_generate_variant:Nn \tl_to_str:N { c } (End definition for \tl_to_str:N and \tl_to_str:c.9 \tl_to_str:n Using token lists Another name for a primitive. Spaces are ignored. 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 \cs_new:Npn \tl_count:n #1 { \int_eval:n { 0 \tl_map_function:nN {#1} \__tl_count:n } } \cs_new:Npn \tl_count:N #1 { \int_eval:n { 0 \tl_map_function:NN #1 \__tl_count:n } } \cs_new:Npn \__tl_count:n #1 { + \c_one } \cs_generate_variant:Nn \tl_count:n { V .) 10. o } \cs_generate_variant:Nn \tl_count:N { c } 355 . 4986 4987 4988 4989 \cs_new_nopar:Npn \tl_map_break: { \__prg_map_break:Nn \tl_map_break: { } } \cs_new_nopar:Npn \tl_map_break:n { \__prg_map_break:Nn \tl_map_break: } (End definition for \tl_map_break:. Brace groups within the list are read as a single element. This function is documented on page 97. \__tl_count:n grabs the element and replaces it by +1. This function is documented on page 98.(End definition for \tl_count:n . and \tl_count:o. and whose second argument is a hcontinuationi. we nest those in \__tl_tmp:w. These functions are documented on page ??. This hands the relevant tokens to the loop \__tl_trim_spaces_auxiii:w. so that space trimming will behave correctly within an x-type expansion. and feeds this to the hcontinuationi. augmented by an initial \q_mark.) Trimming spaces from around the input is done using delimited arguments and quarks. 5036 \cs_set:Npn \__tl_tmp:w #1 356 . which then receives a single space as its argument: #1 is ␣. This function is documented on page ??. 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 \cs_new:Npn \tl_reverse_items:n #1 { \__tl_reverse_items:nwNwn #1 ? \q_mark \__tl_reverse_items:nwNwn \q_mark \__tl_reverse_items:wn \q_stop { } } \cs_new:Npn \__tl_reverse_items:nwNwn #1 #2 \q_mark #3 #4 \q_stop #5 { #3 #2 \q_mark \__tl_reverse_items:nwNwn \q_mark \__tl_reverse_items:wn \q_stop { {#1} #5 } } \cs_new:Npn \__tl_reverse_items:wn #1 \q_stop #2 { \exp_not:o { \use_none:nn #2 } } (End definition for \tl_reverse_items:n. \tl_count:V . with \use_none:n placed there to gobble a lingering \q_mark.) \tl_trim_spaces:n \tl_trim_spaces:N \tl_trim_spaces:c \tl_gtrim_spaces:N \tl_gtrim_spaces:c \__tl_trim_spaces:nn \__tl_trim_spaces_auxi:w l_trim_spaces_auxii:w\__tl_trim_spaces_auxiii:w \__tl_trim_spaces_auxiv:w Trimming spaces from around the input is deferred to an internal function whose first argument is the token list to trim.) \tl_reverse_items:n \__tl_reverse_items:nwNwn \__tl_reverse_items:wn Reversal of a token list is done by taking one item at a time and putting it after \q_stop. The end is reached when ␣ \q_nil matches the one present in the definition of \tl_trim_spacs:n. Removing leading spaces is done with \__tl_trim_spaces_auxi:w. which will receive as a braced argument \use_none:n \q_mark htrimmed token listi. Then \__tl_trim_spaces_auxiv:w puts the token list into a group. we take \exp_not:o as our continuation. which loops until \q_mark␣ matches the end of the token list: then ##1 is the token list and ##3 is \__tl_trim_spaces_auxii:w. responsible for trimming trailing spaces. and to get spaces at odd places in the definitions. In the case at hand. 5028 5029 5030 5031 5032 5033 5034 5035 \cs_new:Npn \tl_trim_spaces:n #1 { \__tl_trim_spaces:nn { \q_mark #1 } \exp_not:o } \cs_new_protected:Npn \tl_trim_spaces:N #1 { \tl_set:Nx #1 { \exp_args:No \tl_trim_spaces:n {#1} } } \cs_new_protected:Npn \tl_gtrim_spaces:N #1 { \tl_gset:Nx #1 { \exp_args:No \tl_trim_spaces:n {#1} } } \cs_generate_variant:Nn \tl_trim_spaces:N { c } \cs_generate_variant:Nn \tl_gtrim_spaces:N { c } (End definition for \tl_trim_spaces:n. ) 10.) \__tl_act:NNNnn \__tl_act_output:n \__tl_act_reverse_output:n \__tl_act_loop:w \__tl_act_normal:NwnNNN \__tl_act_group:nwnNNN \__tl_act_space:wwnNNN \__tl_act_end:w To help control the expansion. in the token list. These variables are documented on page ??. we use two private quarks. even quarks.Only \q___tl_act_mark and \q___tl_act_stop may not appear in the token lists manipulated by \__tl_act:NNNnn functions. This function is documented on page 103.{ 5037 \cs_new:Npn \__tl_trim_spaces:nn ##1 { \__tl_trim_spaces_auxi:w ##1 \q_nil \q_mark #1 { } \q_mark \__tl_trim_spaces_auxii:w \__tl_trim_spaces_auxiii:w #1 \q_nil \__tl_trim_spaces_auxiv:w \q_stop } \cs_new:Npn \__tl_trim_spaces_auxi:w ##1 \q_mark #1 ##2 \q_mark ##3 { ##3 \__tl_trim_spaces_auxi:w \q_mark ##2 \q_mark #1 {##1} } \cs_new:Npn \__tl_trim_spaces_auxii:w \__tl_trim_spaces_auxi:w \q_mark \q_mark ##1 { \__tl_trim_spaces_auxiii:w ##1 } \cs_new:Npn \__tl_trim_spaces_auxiii:w ##1 #1 \q_nil ##2 { ##2 ##1 \q_nil \__tl_trim_spaces_auxiii:w } \cs_new:Npn \__tl_trim_spaces_auxiv:w ##1 \q_nil ##2 \q_stop ##3 { ##3 { \use_none:n ##1 } } 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 } \__tl_tmp:w { ~ } (End definition for \__tl_trim_spaces:nn.11 \q___tl_act_mark \q___tl_act_stop Token by token changes The \tl_act functions may be applied to any token list. (End definition for \q___tl_act_mark and \q___tl_act_stop. to allow any token. \__tl_act:NNNnn should always be proceeded by \romannumeral and ends by producing \c_zero once the result has been obtained. Hence. Then 357 . The quarks are effectively defined in l3quark. to terminate the expansion of \romannumeral. In the “normal” case. The marker \q___tl_act_mark is used both to avoid losing outer braces and to detect the end of the token list more easily. 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 \cs_new:Npn \__tl_act_loop:w #1 \q___tl_act_stop { \tl_if_head_is_N_type:nTF {#1} { \__tl_act_normal:NwnNNN } { \tl_if_head_is_group:nTF {#1} { \__tl_act_group:nwnNNN } { \__tl_act_space:wwnNNN } } #1 \q___tl_act_stop } \cs_new:Npn \__tl_act_normal:NwnNNN #1 #2 \q___tl_act_stop #3#4 { \if_meaning:w \q___tl_act_mark #1 \exp_after:wN \__tl_act_end:wn \fi: #4 {#3} #1 \__tl_act_loop:w #2 \q___tl_act_stop {#3} #4 } \cs_new:Npn \__tl_act_end:wn #1 \__tl_act_result:n #2 { \group_align_safe_end: \c_zero #2 } \cs_new:Npn \__tl_act_group:nwnNNN #1 #2 \q___tl_act_stop #3#4#5 { #5 {#3} {#1} \__tl_act_loop:w #2 \q___tl_act_stop {#3} #4 #5 } \exp_last_unbraced:NNo \cs_new:Npn \__tl_act_space:wwnNNN \c_space_tl #1 \q___tl_act_stop #2#3#4#5 { 358 . Otherwise. Then leave \c_zero and the result in the input stream. apply the relevant function to the “arguments”. we may have reached \q___tl_act_mark. Then repeat the loop. 5074 5075 5076 5077 5078 5079 5080 \cs_new:Npn \__tl_act:NNNnn #1#2#3#4#5 { \group_align_safe_begin: \__tl_act_loop:w #5 \q___tl_act_mark \q___tl_act_stop {#4} #1 #2 #3 \__tl_act_result:n { } } In the loop. and spaces in #5. we check how the token list begins and act accordingly. The result is stored as an argument for the dummy function \__tl_act_result:n. groups.loop over tokens. the end of the list. Some extra work is needed to make \__tl_act_space:wwnNNN gobble the space. #3 and to the head of the token list. The scheme is the same if the token list starts with a group or with a space. leaving \exp_stop_f: in front. This is done using the general internal function \__tl_act:NNNnn. the output is done to the right of what was already output.#5 {#2} \__tl_act_loop:w #1 \q___tl_act_stop {#2} #3 #4 #5 5112 5113 5114 5115 } Typically.) \tl_reverse:N \tl_reverse:c \tl_greverse:N \tl_greverse:c This reverses the list. 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 \cs_new:Npn \tl_reverse:n #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \__tl_act:NNNnn \__tl_reverse_normal:nN \__tl_reverse_group_preserve:nn \__tl_reverse_space:n { } {#1} } } \cs_generate_variant:Nn \tl_reverse:n { o . V } \cs_new:Npn \__tl_reverse_normal:nN #1#2 { \__tl_act_reverse_output:n {#2} } \cs_new:Npn \__tl_reverse_group_preserve:nn #1#2 { \__tl_act_reverse_output:n { {#2} } } \cs_new:Npn \__tl_reverse_space:n #1 { \__tl_act_reverse_output:n { ~ } } (End definition for \tl_reverse:n . it should be done to the left. but for the \__tl_act_reverse functions. All of the internal functions here drop one argument: this is needed by \__tl_act:NNNnn when changing case (to record which direction the change is in). Spaces and “normal” tokens are output on the left of the current output. This function is documented on page ??. but not when reversing the tokens.) \tl_reverse:n \tl_reverse:o \tl_reverse:V \__tl_reverse_normal:nN \__tl_reverse_group_preserve:nn \__tl_reverse_space:n The goal here is to reverse without losing spaces nor braces. 5116 5117 5118 5119 \cs_new:Npn \__tl_act_output:n #1 #2 \__tl_act_result:n #3 { #2 \__tl_act_result:n { #3 #1 } } \cs_new:Npn \__tl_act_reverse_output:n #1 #2 \__tl_act_result:n #3 { #2 \__tl_act_result:n { #1 #3 } } (End definition for \__tl_act:NNNnn. using \__tl_act_output:n. Grouped tokens are output to the left but without any reversal within the group.) 359 . 5140 5141 5142 5143 5144 5145 \cs_new_protected:Npn \tl_reverse:N #1 { \tl_set:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } \cs_new_protected:Npn \tl_greverse:N #1 { \tl_gset:Nx #1 { \exp_args:No \tl_reverse:n { #1 } } } \cs_generate_variant:Nn \tl_reverse:N { c } \cs_generate_variant:Nn \tl_greverse:N { c } (End definition for \tl_reverse:N and others. and \tl_reverse:V. These functions are documented on page ??. These functions are documented on page ??. \tl_reverse:o . which stops the f-expansion. there is a loop.com/a/70168. which is fine as this is consistent with for example mapping to a list. this would leave some tokens “banned” in the input. While we could optimise the test here. we can see if what we are grabbing is exactly the marker. the simple definition \cs_new:Npn \tl_tail:n #1 { \tl_tail:w #1 \q_stop } \cs_new:Npn \tl_tail:w #1#2 \q_stop will give the wrong result for \tl_tail:n { a { bc } } (the braces will be stripped). More detail in http://tex.e. it’s important not to absorb any of the tail part as an argument.10. or there is anything else to deal with. that the argument is not blank) and assuming there is to dispose of the first item. f } \cs_new:Npn \tl_head:w #1#2 \q_stop {#1} \cs_new_nopar:Npn \tl_head:N { \exp_args:No \tl_head:n } To corrected leave the tail of a token list.12 \tl_head:N \tl_head:n \tl_head:V \tl_head:v \tl_head:f \__tl_head_auxi:nw \__tl_head_auxii:nw \tl_head:w \tl_tail:N \tl_tail:n \tl_tail:V \tl_tail:v \tl_tail:f The first token from a token list Finding the head of a token list expandably will always strip braces. Thus the only safe way to proceed is to first check that there is an item to grab (i. The result is returned within the \unexpanded primitive. The empty brace groups in \tl_head:n ensure that a blank argument gives an empty result. v . As with \tl_head:n. tidy up and leave the item in the output stream. which we do not have with this definition. 5167 5168 5169 5170 \cs_new:Npn \tl_tail:n #1 { \etex_unexpanded:D \tl_if_blank:nTF {#1} 360 . as any other token would not be able to parse it’s own code. the result is protected from further expansion by \etex_unexpanded:D. For example.stackexchange. Is there is. Using a marker. If not. 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 \cs_new:Npn \tl_head:n #1 { \etex_unexpanded:D \if_false: { \fi: \__tl_head_auxi:nw #1 { } \q_stop } } \cs_new:Npn \__tl_head_auxi:nw #1#2 \q_stop { \exp_after:wN \__tl_head_auxii:nw \exp_after:wN { \if_false: } \fi: {#1} } \cs_new:Npn \__tl_head_auxii:nw #1 { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n \exp_after:wN { \use_none:n #1 } \q_nil \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: {#1} { \if_false: { \fi: \__tl_head_auxi:nw #1 } } } \cs_generate_variant:Nn \tl_head:n { V . The approach here is to use \if_false: to allow us to use } as the closing delimiter: this is the only safe choice. v . If the argument was empty. the first X is taken by \if_charcode:w. These functions are documented on page ??.) \tl_if_head_eq_meaning_p:nN \tl_if_head_eq_meaning:nNTF \tl_if_head_eq_charcode_p:nN \tl_if_head_eq_charcode:nNTF \tl_if_head_eq_charcode_p:fN \tl_if_head_eq_charcode:fNTF \tl_if_head_eq_catcode_p:nN \tl_if_head_eq_catcode:nNTF Accessing the first token of a token list is tricky in three cases: when it has category code 1 (begin-group token). when it is an explicit space. \if_charcode:w \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop \exp_not:N #2 361 . and then only use \tl_head:w. These functions are documented on page 100. which has category code 10. Here. then \__str_tail:w returns everything until the first X (with category code letter. If the argument was non-empty. then passed to \exp_not:N. except the space. no risk of confusing with the user input). Directly using \tl_head:w would thus lose leading spaces. we return an empty result. If the string started with a space. it returns the first token of #1. we take an argument delimited by an explicit space. and nothing is returned. all with category code 12. 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 \cs_new:Npn \str_head:n #1 { \exp_after:wN \__str_head:w \tl_to_str:n {#1} { { } } ~ \q_stop } \cs_new:Npn \__str_head:w #1 ~ % { \tl_head:w #1 { ~ } } \cs_new:Npn \str_tail:n #1 { \exp_after:wN \__str_tail:w \reverse_if:N \if_charcode:w \scan_stop: \tl_to_str:n {#1} X X \q_stop } \cs_new:Npn \__str_tail:w #1 X #2 \q_stop { \fi: #1 } (End definition for \str_head:n and \str_tail:n. always false for characters. and the function correctly returns a space character. or when the token list is empty (obviously). then the argument of \__str_head:w is empty. with category code 10 and character code 32. which is the first token of the string. Otherwise. Instead. \tl_head:w yields the first token of the token list. we have a list of character tokens. Forgetting temporarily about this issue we would use the following test in \tl_if_head_eq_charcode:nN.) \str_head:n \str_tail:n \__str_head:w \__str_tail:w After \tl_to_str:n. rather than a quark because the test \if_charcode:w \scan_stop: hmarkeri has to be false.5171 5172 5173 5174 5175 { { } } { \exp_after:wN { \use_none:n #1 } } } \cs_generate_variant:Nn \tl_tail:n { V . We use X as a hmarkeri. f } \cs_new_nopar:Npn \tl_tail:N { \exp_args:No \tl_tail:n } (End definition for \tl_head:N and others. To remove the first character of \tl_to_str:n {#1}. we test it using \if_charcode:w \scan_stop:. If the string is empty. either \c_group_begin_token or \c_space_token. again we detect special cases with a \tl_if_head_is_N_type:n. Then we need to test if the first token is a begin-group token or an explicit space token. F . T . 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 \prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN { \if_charcode:w \exp_not:N #2 \tl_if_head_is_N_type:nTF { #1 ? } { \exp_after:wN \exp_not:N \tl_head:w #1 { ? \use_none:nn } \q_stop } { \str_head:n {#1} } \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF #1#2 { p . the first token is a character. we can use \str_head:n to access it (this works even if it is a space character). An empty argument will result in \tl_head:w leaving two tokens: ? which is taken in the \if_charcode:w test. for an empty argument. a hack is used. Again. In those cases. removing \prg_return_true: and \else: with \use_none:nn in case the catcode test with the (arbitrarily chosen) ? is true. and produce the relevant token. T . 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 \prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1 #2 { p . F . and \use_none:nn. TF } { \if_catcode:w \exp_not:N #2 \tl_if_head_is_N_type:nTF { #1 ? } { \exp_after:wN \exp_not:N \tl_head:w #1 { ? \use_none:nn } \q_stop } { \tl_if_head_is_group:nTF {#1} { \c_group_begin_token } { \c_space_token } } \prg_return_true: \else: 362 . and since we only care about its character code. which ensures that \prg_return_false: is returned regardless of whether the charcode test was true or false. TF } { { { { f f f f } } } } For \tl_if_head_eq_catcode:nN.The two first special cases are detected by testing if the token list starts with an N-type token (the extra ? sends empty token lists to the true branch of this test). since \if_meaning:w causes no expansion. With an empty argument. In the special cases. 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 \prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p . we know that the first token is a character. We combine them in some order. hence \if_charcode:w and \if_catcode:w together are enough. T . F . TF } { \tl_if_head_is_N_type:nTF { #1 ? } { \__tl_if_head_eq_meaning_normal:nN } { \__tl_if_head_eq_meaning_special:nN } {#1} #2 } \cs_new:Npn \__tl_if_head_eq_meaning_normal:nN #1 #2 { \exp_after:wN \if_meaning:w \tl_head:w #1 { ?? \use_none:nnn } \q_stop #2 \prg_return_true: \else: \prg_return_false: \fi: } \cs_new:Npn \__tl_if_head_eq_meaning_special:nN #1 #2 { \if_charcode:w \str_head:n {#1} \exp_not:N #2 \exp_after:wN \use:n \else: \prg_return_false: \exp_after:wN \use_none:n \fi: { \if_catcode:w \exp_not:N #2 \tl_if_head_is_group:nTF {#1} { \c_group_begin_token } { \c_space_token } \prg_return_true: \else: \prg_return_false: \fi: } } (End definition for \tl_if_head_eq_meaning:nN.\prg_return_false: \fi: 5226 5227 5228 } For \tl_if_head_eq_meaning:nN. These functions are documented on page 100. or an explicit space token (catcode 10 and charcode 32). In the normal case. the test is true. a begin-group token (catcode 1). detect special cases. with no \exp_not:N this time. hopefully faster than the reverse.) \tl_if_head_is_N_type_p:n \tl_if_head_is_N_type:nTF The first token of a token list can be either an N-type argument. Tests are not nested because the arguments may contain unmatched primitive conditionals. The latter two cases 363 . and \use_none:nnn removes #2 and the usual \prg_return_true: and \else:. use \tl_head:w. again. . F . i. but we don’t: if we hope to ever have an e-type argument. keeping the token list brace balanced at all times. It is false if the token list is empty. T . The extra ? caters for an empty argument. such as \c_space_token. if the first token is an implicit space token. TF } { \__str_if_eq_x_return:nn { \exp_not:o { \use:n #1 { } } } { \exp_not:n { #1 { } } } } (End definition for \tl_if_head_is_N_type:n.) \tl_if_head_is_group_p:n \tl_if_head_is_group:nTF Pass the first token of #1 through \token_to_str:N. These functions are documented on page 101. These functions are documented on page 101. F . 5264 5265 5266 5267 5268 5269 \prg_new_conditional:Npnn \tl_if_head_is_N_type:n #1 { p . 364 . or any token other than an explicit space.5 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 \prg_new_conditional:Npnn \tl_if_head_is_group:n #1 { p . we need all brace “tricks” to happen in one step of expansion. hence changing its string representation (no token can have an empty string representation). The slightly convoluted approach with \romannumeral ensures that each expansion step gives a balanced token list. T .) \tl_if_head_is_space_p:n \tl_if_head_is_space:nTF \__tl_if_head_is_space:w If the first token of the token list is an explicit space. The extra brace group covers the case of an empty argument. TF } { \if_catcode:w * \exp_after:wN \use_none:n \exp_after:wN { \exp_after:wN { \token_to_str:N #1 ? } } * \prg_return_false: \else: \prg_return_true: \fi: } (End definition for \tl_if_head_is_group:n. 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 \prg_new_conditional:Npnn \tl_if_head_is_space:n #1 { p . then this test will be true.e. T .are characterized by the fact that \use:n removes some tokens from #1. TF } { \tex_romannumeral:D \if_false: { \fi: \__tl_if_head_is_space:w ? #1 ? ~ } } \cs_new:Npn \__tl_if_head_is_space:w #1 ~ { \tl_if_empty:oTF { \use_none:n #1 } { \exp_after:wN \c_zero \exp_after:wN \prg_return_true: } { \exp_after:wN \c_zero \exp_after:wN \prg_return_false: } 5 Bruno: this could be made faster. F . a character token with character code 32 and category code 10. whose head is not “normal”. then check for the brace balance. 5307 5308 \cs_new_protected:Npn \tl_show:n #1 { \__msg_show_variable:n { > ~ \tl_to_str:n {#1} } } (End definition for \tl_show:n. then shows the result using the \etex_showtokens:D primitive. They are supposed to be set and used immediately. 5309 5310 \tl_new:N \g_tmpa_tl \tl_new:N \g_tmpb_tl (End definition for \g_tmpa_tl and \g_tmpb_tl.) \tl_show:n The \__msg_show_variable:n internal function performs line-wrapping.) 10.\exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: 5295 } 5296 (End definition for \tl_if_head_is_space:n. These variables are documented on page 102.) \l_tmpa_tl \l_tmpb_tl These are local temporary token list variables. 5311 5312 \tl_new:N \l_tmpa_tl \tl_new:N \l_tmpb_tl (End definition for \l_tmpa_tl and \l_tmpb_tl.) 365 . These functions are documented on page ??. with no delay between the definition and the use because you can’t count on other macros not to redefine them from under you. This function is documented on page 102.) 10.13 \tl_show:N \tl_show:c Viewing token lists Showing token list variables is done after checking that the variable is defined (see \__kernel_register_show:N. Be sure not to assume that the value you put into them will survive for long—see discussion above.14 \g_tmpa_tl \g_tmpb_tl Scratch token lists Global temporary token list variables. Since \tl_to_str:n is expanded within the line-wrapping code. These functions are documented on page 101. removes a leading >␣. 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 \cs_new_protected:Npn \tl_show:N #1 { \tl_if_exist:NTF #1 { \cs_show:N #1 } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_generate_variant:Nn \tl_show:N { c } (End definition for \tl_show:N and \tl_show:c. These variables are documented on page 102. the escape character is always a backslash. 5313 5314 5315 5316 5317 5318 5319 5320 5321 h*deprecatedi \cs_new_protected:Npn \tl_new:Nn #1#2 { \tl_new:N #1 \tl_gset:Nn #1 {#2} } \cs_generate_variant:Nn \tl_new:Nn { c } \cs_generate_variant:Nn \tl_new:Nn { Nx } h/deprecatedi (End definition for \tl_new:Nn .) \tl_remove_in:Nn \tl_remove_in:cn \tl_gremove_in:Nn \tl_gremove_in:cn \tl_remove_all_in:Nn \tl_remove_all_in:cn \tl_gremove_all_in:Nn \tl_gremove_all_in:cn Also renamed. but nowadays does not make much sense. \tl_new:cn . 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \tl_replace_in:Nnn \tl_replace_once:Nnn \tl_replace_in:cnn \tl_replace_once:cnn \tl_greplace_in:Nnn \tl_greplace_once:Nnn \tl_greplace_in:cnn \tl_greplace_once:cnn \tl_replace_all_in:Nnn \tl_replace_all:Nnn \tl_replace_all_in:cnn \tl_replace_all:cnn \tl_greplace_all_in:Nnn \tl_greplace_all:Nnn \tl_greplace_all_in:cnn \tl_greplace_all:cnn (End definition for \tl_replace_in:Nnn and \tl_replace_in:cnn. These functions are documented on page ??.) \tl_gset:Nc \tl_set:Nc This was useful once. These functions are documented on page ??.10.15 \tl_new:Nn \tl_new:cn \tl_new:Nx Deprecated functions Use either \tl_const:Nn or \tl_new:N. 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \tl_remove_in:Nn \tl_remove_once:Nn \tl_remove_in:cn \tl_remove_once:cn \tl_gremove_in:Nn \tl_gremove_once:Nn \tl_gremove_in:cn \tl_gremove_once:cn \tl_remove_all_in:Nn \tl_remove_all:Nn \tl_remove_all_in:cn \tl_remove_all:cn \tl_gremove_all_in:Nn \tl_gremove_all:Nn \tl_gremove_all_in:cn \tl_gremove_all:cn 366 . and \tl_new:Nx. This function is documented on page ??. 5322 5323 5324 5325 5326 5327 h*deprecatedi \cs_new_protected_nopar:Npn \tl_gset:Nc { \tex_global:D \tl_set:Nc } \cs_new_protected:Npn \tl_set:Nc #1#2 { \tl_set:No #1 { \cs:w #2 \cs_end: } } h/deprecatedi (End definition for \tl_gset:Nc.) \tl_replace_in:Nnn \tl_replace_in:cnn \tl_greplace_in:Nnn \tl_greplace_in:cnn \tl_replace_all_in:Nnn \tl_replace_all_in:cnn \tl_greplace_all_in:Nnn \tl_greplace_all_in:cnn These are renamed. F . TF } { \__str_if_eq_x_return:nn { } {#1} } h/deprecatedi 367 . These functions are documented on page ??. These functions are documented on page ??.) Deprecated on 2012-05-13 for removal by 2012-08-31. 5348 5349 5350 5351 5352 5353 5354 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \tl_elt_count:n \tl_elt_count:V \tl_elt_count:o \tl_elt_count:N \tl_elt_count:c \tl_count:n \tl_count:V \tl_count:o \tl_count:N \tl_count:c (End definition for \tl_elt_count:n . \tl_if_empty_p:x \tl_if_empty:xTF We can test expandably the emptiness of an expanded token list thanks to the primitive \pdfstrcmp which expands its argument: a token list is empty if and only if its string representation is empty. \tl_length:N \tl_length:c \tl_length:n \tl_length:V \tl_length:o Renames. These functions are documented on page ??. 5355 5356 5357 5358 5359 5360 5361 h*deprecatedi \cs_new_eq:NN \tl_head_i:n \tl_head:n \cs_new_eq:NN \tl_head_i:w \tl_head:w \cs_new:Npn \tl_head_iii:n #1 { \tl_head_iii:w #1 \q_stop } \cs_generate_variant:Nn \tl_head_iii:n { f } \cs_new:Npn \tl_head_iii:w #1#2#3#4 \q_stop {#1#2#3} h/deprecatedi (End definition for \tl_head_i:n. and \tl_elt_count:o.) \tl_elt_count:n \tl_elt_count:V \tl_elt_count:o \tl_elt_count:N \tl_elt_count:c Another renaming job. \tl_elt_count:V . 5372 5373 5374 5375 h*deprecatedi \prg_new_conditional:Npnn \tl_if_empty:x #1 { p .) Deprecated 2012-05-13 for removal by 2012-11-31. This function is documented on page ??. and a few that are rather too specialised. This function is documented on page ??. \tl_length_tokens:n 5362 5363 5364 h*deprecatedi \cs_new_eq:NN \tl_length_tokens:n \tl_count_tokens:n h/deprecatedi (End definition for \tl_length_tokens:n.) \tl_head_i:n \tl_head_i:w \tl_head_iii:n \tl_head_iii:f \tl_head_iii:w Two renames. T .) Deprecated 2012-06-05 for removal after 2012-12-31. 5365 5366 5367 5368 5369 5370 5371 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \tl_length:N \tl_length:c \tl_length:n \tl_length:V \tl_length:o \tl_count:N \tl_count:c \tl_count:n \tl_count:V \tl_count:o (End definition for \tl_length:N and others.(End definition for \tl_remove_in:Nn and \tl_remove_in:cn. 5395 5396 5397 5398 5399 \cs_new:Npn \__seq_item:n { \__msg_kernel_expandable_error:nn { kernel } { misused-sequence } \use_none:n } 368 . F . T . These functions are documented on page ??. . TF } h/deprecatedi (End definition for \tl_if_head_group:n. TF } \prg_new_eq_conditional:NNn \tl_if_head_N_type:n \tl_if_head_is_N_type:n { p .(End definition for \tl_if_empty:x. F . but is not suitable for items containing {. and also leads to the loss of surrounding braces around items. .m3seq003. T . F .) 5387 11 h/initex | packagei l3seq implementation The following test files are used for this code: m3seq002. \tl_if_head_group_p:n \tl_if_head_group:nTF \tl_if_head_N_type_p:n \tl_if_head_N_type:nTF \tl_if_head_space_p:n \tl_if_head_space:nTF 5376 5377 5378 5379 5380 5381 5382 5383 h*deprecatedi \prg_new_eq_conditional:NNn \tl_if_head_group:n \tl_if_head_is_group:n { p . T . 5384 5385 5386 h*deprecatedi \cs_new:Npn \tl_tail:w #1#2 \q_stop {#2} h/deprecatedi (End definition for \tl_tail:w.) \tl_tail:w Deprecated 2012-09-01 for removal after 2012-12-31. This is broken as it will strip braces from a case such as a{bc}.) Deprecated 2012-07-08 for removal after 2012-10-31. . This allows rapid searching using a delimited function. 5388 h*initex | packagei 5389 h@@=seqi 5390 5391 5392 5393 5394 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei A sequence is a control sequence whose top-level expansion is of the form “\__seq_item:n {hitem1 i} . but when used incorrectly simply removes its argument and hits an undefined control sequence to raise an error. } and # tokens. This function is documented on page ??. \__seq_item:n The delimiter is always defined. These functions are documented on page ??. TF } \prg_new_eq_conditional:NNn \tl_if_head_space:n \tl_if_head_is_space:n { p . \seq_elt:w hitemn i \seq_elt_end:”. \__seq_item:n {hitemn i}”. An earlier implementation used the structure “\seq_elt:w hitem1 i \seq_elt_end: . . ) \seq_set_eq:NN \seq_set_eq:cN \seq_set_eq:Nc \seq_set_eq:cc \seq_gset_eq:NN \seq_gset_eq:cN \seq_gset_eq:Nc \seq_gset_eq:cc Once again. 5403 5404 \cs_new_eq:NN \seq_new:N \tl_new:N \cs_new_eq:NN \seq_new:c \tl_new:c (End definition for \seq_new:N and \seq_new:c. 5400 5401 \tl_new:N \l__seq_internal_a_tl \tl_new:N \l__seq_internal_b_tl (End definition for \l__seq_internal_a_tl and \l__seq_internal_b_tl.) 369 . These variables are documented on page ??.) \c_empty_seq Simply copy the empty token list. These functions are documented on page ??. 5405 5406 5407 5408 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_clear:N \seq_clear:c \seq_gclear:N \seq_gclear:c \tl_clear:N \tl_clear:c \tl_gclear:N \tl_gclear:c (End definition for \seq_clear:N and \seq_clear:c. 5409 5410 5411 5412 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_clear_new:N \seq_clear_new:c \seq_gclear_new:N \seq_gclear_new:c \tl_clear_new:N \tl_clear_new:c \tl_gclear_new:N \tl_gclear_new:c (End definition for \seq_clear_new:N and \seq_clear_new:c. 5413 5414 5415 5416 5417 5418 5419 5420 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_set_eq:NN \seq_set_eq:Nc \seq_set_eq:cN \seq_set_eq:cc \seq_gset_eq:NN \seq_gset_eq:Nc \seq_gset_eq:cN \seq_gset_eq:cc \tl_set_eq:NN \tl_set_eq:Nc \tl_set_eq:cN \tl_set_eq:cc \tl_gset_eq:NN \tl_gset_eq:Nc \tl_gset_eq:cN \tl_gset_eq:cc (End definition for \seq_set_eq:NN and others. sequences are just token lists.) 11. 5402 \cs_new_eq:NN \c_empty_seq \c_empty_tl (End definition for \c_empty_seq. These functions are documented on page ??. This variable is documented on page 111. These functions are documented on page ??.) \seq_clear:N \seq_clear:c \seq_gclear:N \seq_gclear:c Clearing sequences is just the same as clearing token lists.1 \seq_new:N \seq_new:c Allocation and initialisation Internally.) \seq_clear_new:N \seq_clear_new:c \seq_gclear_new:N \seq_gclear_new:c Once again a copy from the token list functions. these are simple copies from the token list functions.) \l__seq_internal_a_tl \l__seq_internal_b_tl Scratch space for various internal uses.(End definition for \__seq_item:n. These functions are documented on page ??. In the first step. and remove one set of outer braces if after removing leading and trailing spaces the item is enclosed within braces. After \tl_replace_all:Nnn. This is then converted to the l3seq internal structure by another x-expansion. and leaves its result as \__seq_set_split_auxii:w htrimmed itemi \__seq_set_split_end:.\seq_set_split:Nnn \seq_set_split:NnV \seq_gset_split:Nnn \seq_gset_split:NnV \__seq_set_split:NNnn \__seq_set_split_auxi:w \__seq_set_split_auxii:w \__seq_set_split_end: The goal is to split a given token list at a marker. These functions are documented on page ??. The second step is solely there to strip braces which are outermost after space trimming. x-expansion causes \__seq_set_split_auxi:w to trim spaces. 5455 \cs_new_eq:NN \seq_concat:NNN \tl_concat:NNN 370 . strip spaces from each item. we insert \prg_do_nothing: to avoid losing braces too early: that would cause space trimming to act within those lost braces. 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 \cs_new_protected_nopar:Npn \seq_set_split:Nnn { \__seq_set_split:NNnn \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_split:Nnn { \__seq_set_split:NNnn \tl_gset:Nx } \cs_new_protected:Npn \__seq_set_split:NNnn #1 #2 #3 #4 { \tl_if_empty:nTF {#3} { #1 #2 { \tl_map_function:nN {#4} \__seq_wrap_item:n } } { \tl_set:Nn \l__seq_internal_a_tl { \__seq_set_split_auxi:w \prg_do_nothing: #4 \__seq_set_split_end: } \tl_replace_all:Nnn \l__seq_internal_a_tl { #3 } { \__seq_set_split_end: \__seq_set_split_auxi:w \prg_do_nothing: } \tl_set:Nx \l__seq_internal_a_tl { \l__seq_internal_a_tl } #1 #2 { \l__seq_internal_a_tl } } } \cs_new:Npn \__seq_set_split_auxi:w #1 \__seq_set_split_end: { \exp_not:N \__seq_set_split_auxii:w \exp_args:No \tl_trim_spaces:n {#1} \exp_not:N \__seq_set_split_end: } \cs_new:Npn \__seq_set_split_auxii:w #1 \__seq_set_split_end: { \__seq_wrap_item:n {#1} } \cs_generate_variant:Nn \seq_set_split:Nnn { NnV } \cs_generate_variant:Nn \seq_gset_split:Nnn { NnV } (End definition for \seq_set_split:Nnn and others. the token list \l__seq_internal_a_tl is a repetition of the pattern \__seq_set_split_auxi:w \prg_do_nothing: hitem with spacesi \__seq_set_split_end:. Then.) \seq_concat:NNN \seq_concat:ccc \seq_gconcat:NNN \seq_gconcat:ccc Concatenating sequences is easy. .) The same for global addition. These functions are documented on page ??. T . 5469 5470 5471 5472 5473 5474 5475 5476 \cs_new_protected:Npn \seq_gput_left:Nn #1#2 { \tl_gput_left:Nn #1 { \__seq_item:n {#2} } } \cs_new_protected:Npn \seq_gput_right:Nn #1#2 { \tl_gput_right:Nn #1 { \__seq_item:n {#2} } } \cs_generate_variant:Nn \seq_gput_left:Nn { NV \cs_generate_variant:Nn \seq_gput_left:Nn { c . . These functions are documented on page ??. Nx cx Nx cx } } } } (End definition for \seq_put_left:Nn and others. 5459 5460 \prg_new_eq_conditional:NNn \seq_if_exist:N \cs_if_exist:N { TF . p } \prg_new_eq_conditional:NNn \seq_if_exist:c \cs_if_exist:c { TF . cV \cs_generate_variant:Nn \seq_put_right:Nn { NV \cs_generate_variant:Nn \seq_put_right:Nn { c . This variable is documented on page ??. cV . . No co No co . These functions are documented on page ??.) 11. . 5478 \seq_new:N \l__seq_remove_seq (End definition for \l__seq_remove_seq. . . . Nx cx Nx cx } } } } (End definition for \seq_gput_left:Nn and others. . . 5461 5462 5463 5464 5465 5466 5467 5468 \cs_new_protected:Npn \seq_put_left:Nn #1#2 { \tl_put_left:Nn #1 { \__seq_item:n {#2} } } \cs_new_protected:Npn \seq_put_right:Nn #1#2 { \tl_put_right:Nn #1 { \__seq_item:n {#2} } } \cs_generate_variant:Nn \seq_put_left:Nn { NV \cs_generate_variant:Nn \seq_put_left:Nn { c . . cV . . . . F .) 371 . .) \seq_if_exist_p:N \seq_if_exist_p:c \seq_if_exist:NTF \seq_if_exist:cTF Copies of the cs functions defined in l3basics. .3 Modifying sequences This function converts its argument to a proper sequence item in an x-expansion context. These functions are documented on page ??. cV \cs_generate_variant:Nn \seq_gput_right:Nn { NV \cs_generate_variant:Nn \seq_gput_right:Nn { c . . .) 11. p } (End definition for \seq_if_exist:N and \seq_if_exist:c.5456 5457 5458 \cs_new_eq:NN \seq_gconcat:NNN \tl_gconcat:NNN \cs_new_eq:NN \seq_concat:ccc \tl_concat:ccc \cs_new_eq:NN \seq_gconcat:ccc \tl_gconcat:ccc (End definition for \seq_concat:NNN and \seq_concat:ccc. Nv cv Nv cv . Nv cv Nv cv . 5477 \cs_new:Npn \__seq_wrap_item:n #1 { \exp_not:n { \__seq_item:n {#1} } } (End definition for \__seq_wrap_item:n.) An internal sequence for the removal routines. . F .2 \seq_put_left:Nn \seq_put_left:NV \seq_put_left:Nv \seq_put_left:No \seq_put_left:Nx \seq_put_left:cn \seq_put_left:cV \seq_put_left:cv \seq_put_left:co \seq_put_left:cx \seq_put_right:Nn \seq_gput_left:Nn \seq_put_right:NV \seq_gput_left:NV \seq_put_right:Nv \seq_gput_left:Nv \seq_put_right:No \seq_gput_left:No \seq_put_right:Nx \seq_gput_left:Nx \seq_put_right:cn \seq_gput_left:cn \seq_put_right:cV \seq_gput_left:cV \seq_put_right:cv \seq_gput_left:cv \seq_put_right:co \seq_gput_left:co \seq_put_right:cx \seq_gput_left:cx \seq_gput_right:Nn \seq_gput_right:NV \seq_gput_right:Nv \__seq_wrap_item:n \seq_gput_right:No \seq_gput_right:Nx \seq_gput_right:cn \seq_gput_right:cV \l__seq_remove_seq \seq_gput_right:cv \seq_gput_right:co \seq_gput_right:cx Appending data to either end The code here is just a wrapper for adding to token lists. No co No co . T . including all of the items copied already. The approach taken is therefore similar to that in \__seq_pop_right_aux:NNN. These functions are documented on page ??. This will happen repeatedly until the entire sequence has been scanned. using a “flexible” x-type expansion to do most of the work. First. The code is set up to avoid needing and intermediate scratch list: the lead-off x-type expansion (#1 #2 {#2}) will ensure that nothing is lost.\seq_remove_duplicates:N \seq_remove_duplicates:c \seq_gremove_duplicates:N \seq_gremove_duplicates:c \__seq_remove_duplicates:NN Removing duplicates means making a new list then copying it. the x-type expansion uses \str_if_eq:nnT to find potential matches. a two-part strategy is needed. The x-type is started again.) \seq_remove_all:Nn \seq_remove_all:cn \seq_gremove_all:Nn \seq_gremove_all:cn \__seq_remove_all_aux:NNn The idea of the code here is to avoid a relatively expensive addition of items one at a time to an intermediate sequence. If one is found. 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 \cs_new_protected:Npn \seq_remove_duplicates:N { \__seq_remove_duplicates:NN \seq_set_eq:NN } \cs_new_protected:Npn \seq_gremove_duplicates:N { \__seq_remove_duplicates:NN \seq_gset_eq:NN } \cs_new_protected:Npn \__seq_remove_duplicates:NN #1#2 { \seq_clear:N \l__seq_remove_seq \seq_map_inline:Nn #2 { \seq_if_in:NnF \l__seq_remove_seq {##1} { \seq_put_right:Nn \l__seq_remove_seq {##1} } } #1 #2 \l__seq_remove_seq } \cs_generate_variant:Nn \seq_remove_duplicates:N { c } \cs_generate_variant:Nn \seq_gremove_duplicates:N { c } (End definition for \seq_remove_duplicates:N and \seq_remove_duplicates:c. the expansion is halted and the necessary set up takes place to use the \tl_if_eq:NNT test. As \tl_if_eq:nnT is not expandable. 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 \cs_new_protected:Npn \seq_remove_all:Nn { \__seq_remove_all_aux:NNn \tl_set:Nx } \cs_new_protected:Npn \seq_gremove_all:Nn { \__seq_remove_all_aux:NNn \tl_gset:Nx } \cs_new_protected:Npn \__seq_remove_all_aux:NNn #1#2#3 { \__seq_push_item_def:n { \str_if_eq:nnT {##1} {#3} { \if_false: { \fi: } \tl_set:Nn \l__seq_internal_b_tl {##1} #1 #2 { \if_false: } \fi: \exp_not:o {#2} \tl_if_eq:NNT \l__seq_internal_a_tl \l__seq_internal_b_tl { \use_none:nn } } \__seq_wrap_item:n {##1} 372 . Nx } \cs_generate_variant:Nn \seq_if_in:NnT { c . TF } \prg_new_eq_conditional:NNn \seq_if_empty:c \tl_if_empty:c { p . No . the mapping is terminated and \group_end: \prg_return_true: is inserted after skipping over the rest of the recursion. Nx } 373 . 5521 5522 5523 5524 \prg_new_eq_conditional:NNn \seq_if_empty:N \tl_if_empty:N { p . No . co .) \seq_if_in:NnTF \seq_if_in:NVTF \seq_if_in:NvTF \seq_if_in:NoTF \seq_if_in:NxTF \seq_if_in:cnTF \seq_if_in:cVTF \seq_if_in:cvTF \seq_if_in:coTF \seq_if_in:cxTF \__seq_if_in: The approach here is to define \__seq_item:n to compare its argument with the test sequence. co . if there is no match then the loop will break returning \prg_return_false:. cx } \cs_generate_variant:Nn \seq_if_in:NnF { NV . TF } (End definition for \seq_if_empty:N and \seq_if_empty:c. T . Nv . These functions are documented on page ??. Nv . If the two items are equal.4 \seq_if_empty_p:N \seq_if_empty_p:c \seq_if_empty:NTF \seq_if_empty:cTF Sequence conditionals Simple copies from the token list variable material.) 11. cx } \cs_generate_variant:Nn \seq_if_in:NnTF { NV . Nx } \cs_generate_variant:Nn \seq_if_in:NnF { c . 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 \prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2 { T . Everything is inside a group so that \__seq_item:n is preserved in nested situations.} \tl_set:Nn \l__seq_internal_a_tl {#3} #1 #2 {#2} \__seq_pop_item_def: 5514 5515 5516 5517 5518 5519 5520 } \cs_generate_variant:Nn \seq_remove_all:Nn { c } \cs_generate_variant:Nn \seq_gremove_all:Nn { c } (End definition for \seq_remove_all:Nn and \seq_remove_all:cn. F . No . cV . On the other hand. These functions are documented on page ??. Nv . F . F . cV . T . cv . cv . TF } { \group_begin: \tl_set:Nn \l__seq_internal_a_tl {#2} \cs_set_protected:Npn \__seq_item:n ##1 { \tl_set:Nn \l__seq_internal_b_tl {##1} \if_meaning:w \l__seq_internal_a_tl \l__seq_internal_b_tl \exp_after:wN \__seq_if_in: \fi: } #1 \group_end: \prg_return_false: \__prg_break_point: } \cs_new_nopar:Npn \__seq_if_in: { \__prg_break:n { \group_end: \prg_return_true: } } \cs_generate_variant:Nn \seq_if_in:NnT { NV . This makes it more sensible to use an auxiliary function for the local and global cases. cx } (End definition for \seq_if_in:Nn and others. with the only difference being that the sequence itself has to be redefined. cv . These functions are documented on page ??. We first append a \q_no_value item to cover the case of an empty sequence 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 \cs_new_protected:Npn \seq_get_left:NN #1#2 { \tl_set:Nx #2 { \exp_after:wN \__seq_get_left:Nnw #1 \__seq_item:n { \q_no_value } \q_stop } } \cs_new:Npn \__seq_get_left:Nnw \__seq_item:n #1#2 \q_stop { \exp_not:n {#1} } \cs_generate_variant:Nn \seq_get_left:NN { c } (End definition for \seq_get_left:NN and \seq_get_left:cN. co . We also use a common emptiness test for all branching get and pop functions.) 11.5 \__seq_pop:NNNN \__seq_pop_TF:NNNN Recovering data from sequences The two pop functions share their emptiness tests.5549 \cs_generate_variant:Nn \seq_if_in:NnTF { c . cV . These functions are documented on page ??. 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 \cs_new_protected:Npn \__seq_pop:NNNN #1#2#3#4 { \if_meaning:w #3 \c_empty_seq \tl_set:Nn #4 { \q_no_value } \else: #1#2#3#4 \fi: } \cs_new_protected:Npn \__seq_pop_TF:NNNN #1#2#3#4 { \if_meaning:w #3 \c_empty_seq % \tl_set:Nn #4 { \q_no_value } \prg_return_false: \else: #1#2#3#4 \prg_return_true: \fi: } (End definition for \__seq_pop:NNNN and \__seq_pop_TF:NNNN. 5579 \cs_new_protected_nopar:Npn \seq_pop_left:NN 374 .) \seq_pop_left:NN \seq_pop_left:cN \seq_gpop_left:NN \seq_gpop_left:cN \__seq_pop_left:NNN \__seq_pop_left:NnwNNN The approach to popping an item is pretty similar to that to get an item.) \seq_get_left:NN \seq_get_left:cN \__seq_get_left:NnwN Getting an item from the left of a sequence is pretty easy: just trim off the first item after removing the \__seq_item:n at the start. and the assignment is placed before the right-most item. What is needed is a “flexible length” way to set a token list variable. The \afterassignment primitive places \use_none:n to get rid of a trailing \__seq_get_right_loop:nn. the closing bracket for the assignment is inserted. These functions are documented on page ??. That needs a loop of unknown length. hence using the strange \if_false: way of including brackets. 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 \cs_new_protected:Npn \seq_get_right:NN #1#2 { \exp_after:wN \__seq_get_right_loop:nn \exp_after:wN \q_no_value #1 { ?? \tex_afterassignment:D \use_none:n \tl_set:Nn #2 } } \cs_new_protected:Npn \__seq_get_right_loop:nn #1#2 { \use_none:nn #2 {#1} \__seq_get_right_loop:nn } \cs_generate_variant:Nn \seq_get_right:NN { c } (End definition for \seq_get_right:NN and \seq_get_right:cN. the left-most n − 1 entries in a sequence of n items will be stored back in the sequence. When the last item of the sequence is reached. then take two arguments at a time. .) \seq_get_right:NN \seq_get_right:cN \__seq_get_right_loop:nn First prepend \q_no_value. This is supplied by the { \if_false: } \fi: . and \tl_set:Nn #3 is inserted 375 . Apart from the righthand end of the sequence. this be a brace group followed by \__seq_item:n. . The \use_none:nn removes both of those.) \seq_pop_right:NN \seq_pop_right:cN \seq_gpop_right:NN \seq_gpop_right:cN \__seq_pop_right_aux:NNN \__seq_pop_right_loop:nn The approach to popping from the right is a bit more involved. These functions are documented on page ??. Using an x-type expansion and a “non-expanding” definition for \__seq_item:n.5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 { \__seq_pop:NNNN \__seq_pop_left:NNN \tl_set:Nn } \cs_new_protected_nopar:Npn \seq_gpop_left:NN { \__seq_pop:NNNN \__seq_pop_left:NNN \tl_gset:Nn } \cs_new_protected:Npn \__seq_pop_left:NNN #1#2#3 { \exp_after:wN \__seq_pop_left:NnwNNN #2 \q_stop #1#2#3 } \cs_new_protected:Npn \__seq_pop_left:NnwNNN \__seq_item:n #1#2 \q_stop #3#4#5 { #3 #4 {#2} \tl_set:Nn #5 {#1} } \cs_generate_variant:Nn \seq_pop_left:NN { c } \cs_generate_variant:Nn \seq_gpop_left:NN { c } (End definition for \seq_pop_left:NN and \seq_pop_left:cN. \if_false: { \fi: } construct. the two question marks are taken by \use_none:nn. At the end of the sequence. but does use some of the same ideas as getting from the right. These functions are documented on page ??. TF } { \__seq_pop_TF:NNNN \prg_do_nothing: \seq_get_left:NN #1#2 } \prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T . TF } { \__seq_pop_TF:NNNN \prg_do_nothing: \seq_get_right:NN #1#2 } \cs_generate_variant:Nn \seq_get_left:NNT { c } \cs_generate_variant:Nn \seq_get_left:NNF { c } \cs_generate_variant:Nn \seq_get_left:NNTF { c } \cs_generate_variant:Nn \seq_get_right:NNT { c } \cs_generate_variant:Nn \seq_get_right:NNF { c } \cs_generate_variant:Nn \seq_get_right:NNTF { c } (End definition for \seq_get_left:NN and \seq_get_left:cN. 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 \cs_new_protected_nopar:Npn \seq_pop_right:NN { \__seq_pop:NNNN \__seq_pop_right_aux:NNN \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gpop_right:NN { \__seq_pop:NNNN \__seq_pop_right_aux:NNN \tl_gset:Nx } \cs_new_protected:Npn \__seq_pop_right_aux:NNN #1#2#3 { \cs_set_eq:NN \seq_tmp:w \__seq_item:n \cs_set_eq:NN \__seq_item:n \scan_stop: #1 #2 { \if_false: } \fi: \exp_after:wN \exp_after:wN \exp_after:wN \__seq_pop_right_loop:nn \exp_after:wN \use_none:n #2 { \if_false: { \fi: } \tex_afterassignment:D \use_none:n \tl_set:Nx #3 } \cs_set_eq:NN \__seq_item:n \seq_tmp:w } \cs_new:Npn \__seq_pop_right_loop:nn #1#2 { #2 { \exp_not:n {#1} } \__seq_pop_right_loop:nn } \cs_generate_variant:Nn \seq_pop_right:NN { c } \cs_generate_variant:Nn \seq_gpop_right:NN { c } (End definition for \seq_pop_right:NN and \seq_pop_right:cN.) \seq_pop_left:NNTF \seq_pop_left:cNTF \seq_gpop_left:NNTF \seq_gpop_left:cNTF \seq_pop_right:NNTF \seq_pop_right:cNTF \seq_gpop_right:NNTF \seq_gpop_right:cNTF More or less the same for popping. The first argument to \__seq_pop_TF:NNNN is left unused. 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 \prg_new_protected_conditional:Npnn \seq_get_left:NN #1#2 { T .) \seq_get_left:NNTF \seq_get_left:cNTF \seq_get_right:NNTF \seq_get_right:cNTF Getting from the left or right with a check on the results. This therefore does the pop assignment. F .in front of the final entry. F . 376 . These functions are documented on page ??. The trailing looping macro is removed by placing a \use_none:n using the \afterassignment primitive. This function is documented on page 109. F . This is done as by noting that every odd token in the sequence must be \__seq_item:n. TF } { \__seq_pop_TF:NNNN \__seq_pop_left:NNN \tl_set:Nn #1 #2 } \prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T .) 11.) \seq_map_function:NN \seq_map_function:cN \__seq_map_function:NNn The idea here is to apply the code of #2 to each item in the sequence without altering the definition of \__seq_item:n.5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 \prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T . F . which therefore breaks the loop without needing to do a (relatively-expensive) quark test. Any ending code is then inserted before the return value of \seq_map_break:n is inserted. At the end of the loop. 5671 5672 5673 5674 5675 5676 5677 5678 5679 \cs_new:Npn \seq_map_function:NN #1#2 { \exp_after:wN \__seq_map_function:NNn \exp_after:wN #2 #1 { ? \seq_map_break: } { } \__prg_break_point:Nn \seq_map_break: { } } \cs_new:Npn \__seq_map_function:NNn #1#2#3 { \use_none:n #2 377 . which can be gobbled by \use_none:n. F . TF } { \__seq_pop_TF:NNNN \__seq_pop_left:NNN \tl_gset:Nn #1 #2 } \prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T . TF } { \__seq_pop_TF:NNNN \__seq_pop_right_aux:NNN \tl_set:Nx #1 #2 } \prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T . #2 is instead ? \seq_map_break:.6 \seq_map_break: \seq_map_break:n Mapping to sequences To break a function. the special token \__prg_break_point:Nn is used to find the end of the code. These functions are documented on page ??. F . TF } { \__seq_pop_TF:NNNN \__seq_pop_right_aux:NNN \tl_gset:Nx #1 #2 } \cs_generate_variant:Nn \seq_pop_left:NNT { c } \cs_generate_variant:Nn \seq_pop_left:NNF { c } \cs_generate_variant:Nn \seq_pop_left:NNTF { c } \cs_generate_variant:Nn \seq_gpop_left:NNT { c } \cs_generate_variant:Nn \seq_gpop_left:NNF { c } \cs_generate_variant:Nn \seq_gpop_left:NNTF { c } \cs_generate_variant:Nn \seq_pop_right:NNT { c } \cs_generate_variant:Nn \seq_pop_right:NNF { c } \cs_generate_variant:Nn \seq_pop_right:NNTF { c } \cs_generate_variant:Nn \seq_gpop_right:NNT { c } \cs_generate_variant:Nn \seq_gpop_right:NNF { c } \cs_generate_variant:Nn \seq_gpop_right:NNTF { c } (End definition for \seq_pop_left:NN and \seq_pop_left:cN. 5667 5668 5669 5670 \cs_new_nopar:Npn \seq_map_break: { \__prg_map_break:Nn \seq_map_break: { } } \cs_new_nopar:Npn \seq_map_break:n { \__prg_map_break:Nn \seq_map_break: } (End definition for \seq_map_break:. 378 . this approach uses global assignments. 5706 5707 5708 5709 5710 5711 5712 \cs_new_protected:Npn \seq_map_inline:Nn #1#2 { \__seq_push_item_def:n {#2} #1 \__prg_break_point:Nn \seq_map_break: { \__seq_pop_item_def: } } \cs_generate_variant:Nn \seq_map_inline:Nn { c } (End definition for \seq_map_inline:Nn and \seq_map_inline:cn. These functions are documented on page 112.) \seq_map_variable:NNn \seq_map_variable:Ncn \seq_map_variable:cNn \seq_map_variable:ccn This is just a specialised version of the in-line mapping function.5680 5681 5682 5683 #1 {#3} \__seq_map_function:NNn #1 } \cs_generate_variant:Nn \seq_map_function:NN { c } (End definition for \seq_map_function:NN and \seq_map_function:cN. These functions are documented on page ??.) \__seq_push_item_def:n \__seq_push_item_def:x \__seq_push_item_def: \__seq_pop_item_def: The definition of \__seq_item:n needs to be saved and restored at various points within the mapping and manipulation code.) \seq_map_inline:Nn \seq_map_inline:cn The idea here is that \__seq_item:n is already “applied” to each item in a sequence. 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 \cs_new_protected:Npn \__seq_push_item_def:n { \__seq_push_item_def: \cs_gset:Npn \__seq_item:n ##1 } \cs_new_protected:Npn \__seq_push_item_def:x { \__seq_push_item_def: \cs_gset:Npx \__seq_item:n ##1 } \cs_new_protected:Npn \__seq_push_item_def: { \int_gincr:N \g__prg_map_int \cs_gset_eq:cN { __prg_map_ \int_use:N \g__prg_map_int :w } \__seq_item:n } \cs_new_protected_nopar:Npn \__seq_pop_item_def: { \cs_gset_eq:Nc \__seq_item:n { __prg_map_ \int_use:N \g__prg_map_int :w } \int_gdecr:N \g__prg_map_int } (End definition for \__seq_push_item_def:n and \__seq_push_item_def:x. using an x-type expansion for the code set up so that the number of # tokens required is as expected. That is handled here: as always. These functions are documented on page ??. and so an in-line mapping is just a case of redefining \__seq_item:n. 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 \cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 { \__seq_push_item_def:x { \tl_set:Nn \exp_not:N #2 {##1} \exp_not:n {#3} } #1 \__prg_break_point:Nn \seq_map_break: { \__seq_pop_item_def: } } \cs_generate_variant:Nn \seq_map_variable:NNn { Nc } \cs_generate_variant:Nn \seq_map_variable:NNn { c . but with the correct naming. These functions are documented on page ??. cc } (End definition for \seq_map_variable:NNn and others. 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_push:Nn \seq_push:NV \seq_push:Nv \seq_push:No \seq_push:Nx \seq_push:cn \seq_push:cV \seq_push:cv \seq_push:co \seq_push:cx \seq_gpush:Nn \seq_gpush:NV \seq_gpush:Nv \seq_gpush:No \seq_gpush:Nx \seq_put_left:Nn \seq_put_left:NV \seq_put_left:Nv \seq_put_left:No \seq_put_left:Nx \seq_put_left:cn \seq_put_left:cV \seq_put_left:cv \seq_put_left:co \seq_put_left:cx \seq_gput_left:Nn \seq_gput_left:NV \seq_gput_left:Nv \seq_gput_left:No \seq_gput_left:Nx 379 . \seq_push:Nn \seq_push:NV \seq_push:Nv \seq_push:No \seq_push:Nx \seq_push:cn \seq_push:cV \seq_push:cV \seq_push:co \seq_push:cx \seq_gpush:Nn \seq_gpush:NV \seq_gpush:Nv \seq_gpush:No \seq_gpush:Nx \seq_gpush:cn \seq_gpush:cV \seq_gpush:cv \seq_gpush:co \seq_gpush:cx Pushing to a sequence is the same as adding on the left.) 11.) \seq_count:N \seq_count:c \__seq_count:n Counting the items in a sequence is done using the same approach as for other count functions: turn each entry into a +1 then use integer evaluation to actually do the mathematics. 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 \cs_new:Npn \seq_count:N #1 { \int_eval:n { 0 \seq_map_function:NN #1 \__seq_count:n } } \cs_new:Npn \__seq_count:n #1 { + \c_one } \cs_generate_variant:Nn \seq_count:N { c } (End definition for \seq_count:N and \seq_count:c.7 Sequence stacks The same functions as for sequences. These functions are documented on page ??. 9 \l_tmpa_seq \l_tmpb_seq \g_tmpa_seq \g_tmpb_seq Scratch sequences Temporary comma list variables. . .) 11.) \seq_get:NNTF \seq_get:cNTF \seq_pop:NNTF \seq_pop:cNTF \seq_gpop:NNTF \seq_gpop:cNTF More copies. These functions are documented on page ??. . getting items from the stack does not need to specify that this is from the left. These functions are documented on page ??. . 5773 5774 5775 5776 \seq_new:N \seq_new:N \seq_new:N \seq_new:N \l_tmpa_seq \l_tmpb_seq \g_tmpa_seq \g_tmpb_seq (End definition for \l_tmpa_seq and others.) 380 . 5755 5756 5757 5758 5759 5760 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_get:NN \seq_get_left:NN \seq_get:cN \seq_get_left:cN \seq_pop:NN \seq_pop_left:NN \seq_pop:cN \seq_pop_left:cN \seq_gpop:NN \seq_gpop_left:NN \seq_gpop:cN \seq_gpop_left:cN (End definition for \seq_get:NN and \seq_get:cN. . .) 11. So alias are provided.5750 5751 5752 5753 5754 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \seq_gpush:cn \seq_gpush:cV \seq_gpush:cv \seq_gpush:co \seq_gpush:cx \seq_gput_left:cn \seq_gput_left:cV \seq_gput_left:cv \seq_gput_left:co \seq_gput_left:cx (End definition for \seq_push:Nn and others. .) \seq_get:NN \seq_get:cN \seq_pop:NN \seq_pop:cN \seq_gpop:NN \seq_gpop:cN In most cases. These functions are documented on page ??. 5767 5768 5769 5770 5771 5772 \cs_new_protected:Npn \seq_show:N #1 { \__msg_show_variable:Nnn #1 { seq } { \seq_map_function:NN #1 \__msg_show_item:n } } \cs_generate_variant:Nn \seq_show:N { c } (End definition for \seq_show:N and \seq_show:c. These functions are documented on page ??. . .8 \seq_show:N \seq_show:c Viewing sequences Apply the general \__msg_show_variable:Nnn. F F F F F F . TF TF TF TF TF TF } } } } } } (End definition for \seq_get:NN and \seq_get:cN. . 5761 5762 5763 5764 5765 5766 \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \seq_get:NN \seq_get:cN \seq_pop:NN \seq_pop:cN \seq_gpop:NN \seq_gpop:cN \seq_get_left:NN \seq_get_left:cN \seq_pop_left:NN \seq_pop_left:cN \seq_gpop_left:NN \seq_gpop_left:cN { { { { { { T T T T T T . These variables are documented on page 111. \seq_length:N \seq_length:c 5785 5786 5787 5788 h*deprecatedi \cs_new_eq:NN \seq_length:N \seq_count:N \cs_new_eq:NN \seq_length:c \seq_count:c h/deprecatedi (End definition for \seq_length:N and \seq_length:c. \seq_use:N \seq_use:c A simple short cut for a mapping. These functions are documented on page ??. and will be removed entirely by 2011-07-20. 5777 5778 5779 5780 h*deprecatedi \cs_new_eq:NN \seq_top:NN \seq_get_left:NN \cs_new_eq:NN \seq_top:cN \seq_get_left:cN h/deprecatedi (End definition for \seq_top:NN and \seq_top:cN.11. These functions are documented on page ??.) 5793 12 h/initex | packagei l3clist implementation The following test files are used for this code: m3clist002. \seq_top:NN \seq_top:cN These are old stack functions. 5794 h*initex | packagei 5795 h@@=clisti 5796 5797 5798 5799 5800 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 381 . 5781 5782 5783 5784 h*deprecatedi \cs_new_eq:NN \seq_display:N \seq_show:N \cs_new_eq:NN \seq_display:c \seq_show:c h/deprecatedi (End definition for \seq_display:N and \seq_display:c.) \seq_display:N \seq_display:c An older name for \seq_show:N.) Deprecated 2012-05-13 for removal by 2012-11-30. These functions are documented on page ??.) Deprecated 2012-05-23 for removal by 2012-08-30. These functions are documented on page ??. 5789 5790 5791 5792 h*deprecatedi \cs_new:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } \cs_generate_variant:Nn \seq_use:N { c } h/deprecatedi (End definition for \seq_use:N and \seq_use:c.10 Deprecated interfaces A few functions which are no longer documented: these were moved here on or before 2011-04-20. This variable is documented on page 120. 5810 5811 5812 5813 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \clist_clear_new:N \clist_clear_new:c \clist_gclear_new:N \clist_gclear_new:c \tl_clear_new:N \tl_clear_new:c \tl_gclear_new:N \tl_gclear_new:c (End definition for \clist_clear_new:N and \clist_clear_new:c.) \clist_set_eq:NN \clist_set_eq:cN \clist_set_eq:Nc \clist_set_eq:cc \clist_gset_eq:NN \clist_gset_eq:cN \clist_gset_eq:Nc \clist_gset_eq:cc Once again.) \clist_clear_new:N \clist_clear_new:c \clist_gclear_new:N \clist_gclear_new:c Once again a copy from the token list functions. These functions are documented on page ??. 5806 5807 5808 5809 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \clist_clear:N \clist_clear:c \clist_gclear:N \clist_gclear:c \tl_clear:N \tl_clear:c \tl_gclear:N \tl_gclear:c (End definition for \clist_clear:N and \clist_clear:c. These functions are documented on page ??. 5814 5815 5816 5817 5818 5819 5820 5821 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \clist_set_eq:NN \clist_set_eq:Nc \clist_set_eq:cN \clist_set_eq:cc \clist_gset_eq:NN \clist_gset_eq:Nc \clist_gset_eq:cN \clist_gset_eq:cc \tl_set_eq:NN \tl_set_eq:Nc \tl_set_eq:cN \tl_set_eq:cc \tl_gset_eq:NN \tl_gset_eq:Nc \tl_gset_eq:cN \tl_gset_eq:cc (End definition for \clist_set_eq:NN and others. 5804 5805 \cs_new_eq:NN \clist_new:N \tl_new:N \cs_new_eq:NN \clist_new:c \tl_new:c (End definition for \clist_new:N and \clist_new:c. 5801 \cs_new_eq:NN \c_empty_clist \c_empty_tl (End definition for \c_empty_clist.\c_empty_clist An empty comma list is simply an empty token list.) \clist_clear:N \clist_clear:c \clist_gclear:N \clist_gclear:c Clearing comma lists is just the same as clearing token lists.1 \clist_new:N \clist_new:c Allocation and initialisation Internally. comma lists are just token lists. This comma list variable cannot be declared as such because it comes before \clist_new:N 5802 \tl_new:N \l__clist_internal_clist (End definition for \l__clist_internal_clist. These functions are documented on page ??. these are simple copies from the token list functions.) 382 .) \__clist_tmp:w A temporary function for various purposes.) 12. These functions are documented on page ??.) \l__clist_internal_clist Scratch space for various internal uses. 5803 \cs_new_protected:Npn \__clist_tmp:w { } (End definition for \__clist_tmp:w. This variable is documented on page ??. So a little work to do. } } \exp_not:o #4 } } \cs_generate_variant:Nn \clist_concat:NNN { ccc } \cs_generate_variant:Nn \clist_gconcat:NNN { ccc } (End definition for \clist_concat:NNN and \clist_concat:ccc. namely. followed by a brace group containing the hitemi. These functions are documented on page ??. The calling function is responsible for inserting \q_mark in front of the hitemi. then feeds the result (after having to do an o-type expansion) to \__clist_trim_spaces_generic:nn which places the hcodei in front of the htrimmed itemi. and also prevents empty arguments from finding their way into the output. 5839 5840 5841 5842 5843 5844 \cs_new:Npn \__clist_trim_spaces_generic:nw #1#2 .) \clist_if_exist_p:N \clist_if_exist_p:c \clist_if_exist:NTF \clist_if_exist:cTF Copies of the cs functions defined in l3basics. T . 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 \cs_new_protected_nopar:Npn \clist_concat:NNN { \__clist_concat:NNNN \tl_set:Nx } \cs_new_protected_nopar:Npn \clist_gconcat:NNN { \__clist_concat:NNNN \tl_gset:Nx } \cs_new_protected:Npn \__clist_concat:NNNN #1#2#3#4 { #1 #2 { \exp_not:o #3 \clist_if_empty:NF #3 { \clist_if_empty:NF #4 { . whose first argument must start with \q_mark. and later a comma.) 12. These functions are documented on page ??. 5845 5846 \cs_new:Npn \__clist_trim_spaces:n #1 { 383 .) \__clist_trim_spaces:n \__clist_trim_spaces:nn The first argument of \__clist_trim_spaces:nn is initially empty. p } (End definition for \clist_if_exist:N and \clist_if_exist:c. as well as testing for the end of the list.2 Removing spaces around items \__clist_trim_spaces_generic:nw This expands to the hcodei. That trims the item #2. F . We reuse a l3tl internal function. 5837 5838 \prg_new_eq_conditional:NNn \clist_if_exist:N \cs_if_exist:N { TF . as there needs to be the correct addition of a comma to the output. F . p } \prg_new_eq_conditional:NNn \clist_if_exist:c \cs_if_exist:c { TF . T . as soon as we have added an item to the resulting list. The auxiliary tests for the end of the list. { \__tl_trim_spaces:nn {#2} { \exp_args:No \__clist_trim_spaces_generic:nn } {#1} } \cs_new:Npn \__clist_trim_spaces_generic:nn #1#2 { #2 {#1} } (End definition for \__clist_trim_spaces_generic:nw. with leading \__clist_trim_spaces_generic:nn and trailing spaces removed. This function is documented on page ??.\clist_concat:NNN \clist_concat:ccc \clist_gconcat:NNN \clist_gconcat:ccc \__clist_concat:NNNN Concatenating comma lists is not quite as easy as it seems. cV . c . co .3 \clist_set:Nn \clist_set:NV \clist_set:No \clist_set:Nx \clist_set:cn \clist_set:cV \clist_set:co \clist_set:cx \clist_gset:Nn \clist_put_left:Nn \clist_gset:NV \clist_put_left:NV \clist_gset:No \clist_put_left:No \clist_gset:Nx \clist_put_left:Nx \clist_gset:cn \clist_put_left:cn \clist_gset:cV \clist_put_left:cV \clist_gset:co \clist_put_left:co \clist_gset:cx \clist_put_left:cx \clist_gput_left:Nn \clist_gput_left:NV \clist_gput_left:No \clist_gput_left:Nx \clist_gput_left:cn \clist_gput_left:cV \clist_gput_left:co \clist_gput_left:cx \__clist_put_left:NNNn 5866 5867 5868 5869 5870 5871 Adding data to comma lists \cs_new_protected:Npn \clist_set:Nn #1#2 { \tl_set:Nx #1 { \__clist_trim_spaces:n {#2} } } \cs_new_protected:Npn \clist_gset:Nn #1#2 { \tl_gset:Nx #1 { \__clist_trim_spaces:n {#2} } } \cs_generate_variant:Nn \clist_set:Nn { NV . co . \q_recursion_tail. cx } } } } (End definition for \clist_put_left:Nn and others. cV . co . Nx . } } \q_mark } } (End definition for \__clist_trim_spaces:n. No . Nx \cs_generate_variant:Nn \clist_put_left:Nn { c .) 384 . 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 \cs_new_protected_nopar:Npn \clist_put_left:Nn { \__clist_put_left:NNNn \clist_concat:NNN \clist_set:Nn } \cs_new_protected_nopar:Npn \clist_gput_left:Nn { \__clist_put_left:NNNn \clist_gconcat:NNN \clist_set:Nn } \cs_new_protected:Npn \__clist_put_left:NNNn #1#2#3#4 { #2 \l__clist_internal_clist {#4} #1 #3 \l__clist_internal_clist #3 } \cs_generate_variant:Nn \clist_put_left:Nn { NV . Nx . \q_recursion_stop 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 } \cs_new:Npn \__clist_trim_spaces:nn #1 #2 { \quark_if_recursion_tail_stop:n {#2} \tl_if_empty:nTF {#2} { \__clist_trim_spaces_generic:nw { \__clist_trim_spaces:nn {#1} } \q_mark } { #1 \exp_not:n {#2} \__clist_trim_spaces_generic:nw { \__clist_trim_spaces:nn { .\__clist_trim_spaces_generic:nw { \__clist_trim_spaces:nn { } } \q_mark #1 . Nx \cs_generate_variant:Nn \clist_gput_left:Nn { c .) 12. This function is documented on page ??. No . cx } \cs_generate_variant:Nn \clist_gset:Nn { NV . co . cx } (End definition for \clist_set:Nn and others. cV . These functions are documented on page ??. c . cx \cs_generate_variant:Nn \clist_gput_left:Nn { NV . No .) Comma lists cannot hold empty values: there are therefore a couple of sanity checks to avoid accumulating commas. These functions are documented on page ??. No . cV . Nx \cs_generate_variant:Nn \clist_put_right:Nn { c . cV . cx \cs_generate_variant:Nn \clist_gput_right:Nn { NV . These functions are documented on page ??. #2 \q_stop #3 { \tl_set:Nn #3 {#1} } \cs_generate_variant:Nn \clist_get:NN { c } (End definition for \clist_get:NN and \clist_get:cN. \q_stop #2 \fi: } \cs_new_protected:Npn \__clist_get:wN #1 .) 12. 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 \cs_new_protected_nopar:Npn \clist_pop:NN { \__clist_pop:NNN \tl_set:Nx } \cs_new_protected_nopar:Npn \clist_gpop:NN { \__clist_pop:NNN \tl_gset:Nx } \cs_new_protected:Npn \__clist_pop:NNN #1#2#3 { \if_meaning:w #2 \c_empty_clist \tl_set:Nn #3 { \q_no_value } \else: \exp_after:wN \__clist_pop:wwNNN #2 . unless the original clist contained exactly one item: then the argument is just \q_mark. These functions are documented on page ??. ensuring that the result can safely be an empty comma list. \q_mark \q_stop #1#2#3 385 . No . co . otherwise grab until the first comma and assign to the variable. cx } } } } (End definition for \clist_put_right:Nn and others. No . The next auxiliary picks either \exp_not:n or \use_none:n as #2. Nx \cs_generate_variant:Nn \clist_gput_right:Nn { c . The second argument of \__clist_pop:wwNNN is a comma list ending in a comma and \q_mark. co .4 Comma lists as stacks Getting an item from the left of a comma list is pretty easy: just trim off the first item using the comma. 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 \cs_new_protected:Npn \clist_get:NN #1#2 { \if_meaning:w #1 \c_empty_clist \tl_set:Nn #2 { \q_no_value } \else: \exp_after:wN \__clist_get:wN #1 . cV .\clist_put_right:Nn \clist_put_right:NV \clist_put_right:No \clist_put_right:Nx \clist_put_right:cn \clist_put_right:cV \clist_put_right:co \clist_put_right:cx \clist_gput_right:Nn \clist_gput_right:NV \clist_gput_right:No \clist_gput_right:Nx \clist_gput_right:cn \clist_gput_right:cV \clist_gput_right:co \clist_gput_right:cx \__clist_put_right:NNNn \clist_get:NN \clist_get:cN \__clist_get:wN 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 \cs_new_protected_nopar:Npn \clist_put_right:Nn { \__clist_put_right:NNNn \clist_concat:NNN \clist_set:Nn } \cs_new_protected_nopar:Npn \clist_gput_right:Nn { \__clist_put_right:NNNn \clist_gconcat:NNN \clist_set:Nn } \cs_new_protected:Npn \__clist_put_right:NNNn #1#2#3#4 { #2 \l__clist_internal_clist {#4} #1 #3 #3 \l__clist_internal_clist } \cs_generate_variant:Nn \clist_put_right:Nn { NV .) \clist_pop:NN \clist_pop:cN \clist_gpop:NN \clist_gpop:cN \__clist_pop:NNN \__clist_pop:wwNNN \__clist_pop:wN An empty clist leads to \q_no_value. #2 \q_stop #3#4#5 #2 #3 \q_stop { #2 {#1} } c } c } (End definition for \clist_pop:NN and \clist_pop:cN. These functions are documented on page ??. F . \q_mark \cs_generate_variant:Nn \clist_pop:NN { \cs_generate_variant:Nn \clist_gpop:NN { #1 . F . 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 \prg_new_protected_conditional:Npnn \clist_get:NN #1#2 { T . \q_mark \use_none:n \q_stop } } \cs_new:Npn \__clist_pop:wN #1 . TF } { \if_meaning:w #1 \c_empty_clist \prg_return_false: \else: \exp_after:wN \__clist_get:wN #1 . TF } { \__clist_pop_TF:NNN \tl_gset:Nx #1 #2 } \cs_new_protected:Npn \__clist_pop_TF:NNN #1#2#3 { \if_meaning:w #2 \c_empty_clist \prg_return_false: \else: \exp_after:wN \__clist_pop:wwNNN #2 . F . \q_mark \q_stop #1#2#3 \prg_return_true: \fi: } \cs_generate_variant:Nn \clist_pop:NNT { c } \cs_generate_variant:Nn \clist_pop:NNF { c } \cs_generate_variant:Nn \clist_pop:NNTF { c } \cs_generate_variant:Nn \clist_gpop:NNT { c } \cs_generate_variant:Nn \clist_gpop:NNF { c } \cs_generate_variant:Nn \clist_gpop:NNTF { c } 386 . \q_stop #2 \prg_return_true: \fi: } \cs_generate_variant:Nn \clist_get:NNT { c } \cs_generate_variant:Nn \clist_get:NNF { c } \cs_generate_variant:Nn \clist_get:NNTF { c } \prg_new_protected_conditional:Npnn \clist_pop:NN #1#2 { T .5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 \fi: } \cs_new_protected:Npn \__clist_pop:wwNNN { \tl_set:Nn #5 {#1} #3 #4 { \__clist_pop:wN \prg_do_nothing: #2 \exp_not:o .) \clist_get:NNTF \clist_get:cNTF \clist_pop:NNTF \clist_pop:cNTF \clist_gpop:NNTF \clist_gpop:cNTF \__clist_pop_TF:NNN The same. TF } { \__clist_pop_TF:NNN \tl_set:Nx #1 #2 } \prg_new_protected_conditional:Npnn \clist_gpop:NN #1#2 { T . as branching code: very similar to the above. These functions are documented on page ??. These functions are documented on page ??.) \clist_remove_duplicates:N Removing duplicates means making a new list then copying it. 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \clist_push:Nn \clist_push:NV \clist_push:No \clist_push:Nx \clist_push:cn \clist_push:cV \clist_push:co \clist_push:cx \clist_gpush:Nn \clist_gpush:NV \clist_gpush:No \clist_gpush:Nx \clist_gpush:cn \clist_gpush:cV \clist_gpush:co \clist_gpush:cx \clist_put_left:Nn \clist_put_left:NV \clist_put_left:No \clist_put_left:Nx \clist_put_left:cn \clist_put_left:cV \clist_put_left:co \clist_put_left:cx \clist_gput_left:Nn \clist_gput_left:NV \clist_gput_left:No \clist_gput_left:Nx \clist_gput_left:cn \clist_gput_left:cV \clist_gput_left:co \clist_gput_left:cx (End definition for \clist_push:Nn and others. 5982 \clist_new:N \l__clist_internal_remove_clist (End definition for \l__clist_internal_remove_clist.) \clist_push:Nn \clist_push:NV \clist_push:No \clist_push:Nx \clist_push:cn \clist_push:cV \clist_push:co \clist_push:cx \clist_gpush:Nn \clist_gpush:NV \clist_gpush:No \clist_gpush:Nx \clist_gpush:cn \clist_gpush:cV \clist_gpush:co \clist_gpush:cx Pushing to a comma list is the same as adding on the left.(End definition for \clist_get:NN and \clist_get:cN.) 387 . These functions are documented on page ??. \clist_remove_duplicates:c 5983 \cs_new_protected:Npn \clist_remove_duplicates:N \clist_gremove_duplicates:N 5984 { \__clist_remove_duplicates:NN \clist_set_eq:NN } \clist_gremove_duplicates:c 5985 \cs_new_protected:Npn \clist_gremove_duplicates:N 5986 { \__clist_remove_duplicates:NN \clist_gset_eq:NN } \__clist_remove_duplicates:NN 5987 \cs_new_protected:Npn \__clist_remove_duplicates:NN #1#2 5988 { 5989 \clist_clear:N \l__clist_internal_remove_clist 5990 \clist_map_inline:Nn #2 5991 { 5992 \clist_if_in:NnF \l__clist_internal_remove_clist {##1} 5993 { \clist_put_right:Nn \l__clist_internal_remove_clist {##1} } 5994 } 5995 #1 #2 \l__clist_internal_remove_clist 5996 } 5997 \cs_generate_variant:Nn \clist_remove_duplicates:N { c } 5998 \cs_generate_variant:Nn \clist_gremove_duplicates:N { c } (End definition for \clist_remove_duplicates:N and \clist_remove_duplicates:c.5 Modifying comma lists \l__clist_internal_remove_clist An internal comma list for the removal routines.) 12. This variable is documented on page ??. The loop is controlled by the argument grabbed by \__clist_remove_all:w: when the item was found. At the end. 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 \cs_new_protected:Npn \clist_remove_all:Nn { \__clist_remove_all:NNn \tl_set:Nx } \cs_new_protected:Npn \clist_gremove_all:Nn { \__clist_remove_all:NNn \tl_gset:Nx } \cs_new_protected:Npn \__clist_remove_all:NNn #1#2#3 { \cs_set:Npn \__clist_tmp:w ##1 . The result of the first assignment has an extra leading comma. the final hitemi is grabbed. and lets \use_none_delimit_by_q_stop:w act. { \exp_not:n {#1} } \cs_generate_variant:Nn \clist_remove_all:Nn { c } \cs_generate_variant:Nn \clist_gremove_all:Nn { c } (End definition for \clist_remove_all:Nn and \clist_remove_all:cn. \q_mark . and call that function followed by the expanded comma list. \use_none_delimit_by_q_stop:w . which we remove in a second assignment. \q_mark . and the second step removes it. Two exceptions: if the clist lost all of its elements. the result is empty. { ##1 . #2 . No brace is lost because items are always grabbed with a leading comma. \__clist_remove_all:w removes the second \q_mark (inserted by \__clist_tmp:w). surrounded with commas. #3 . #3 . and the argument of \__clist_tmp:w contains \q_mark: in that case. and another copy of the hitemi. } \cs_new:Npn \__clist_remove_all:w #1 . if the clist started up empty. Build a function delimited by the hitemi that should be removed. These functions are documented on page ??. \q_stop } \clist_if_empty:NF #2 { #1 #2 { \exp_args:No \exp_not:o { \exp_after:wN \use_none:n #2 } } } } \cs_new:Npn \__clist_remove_all: { \exp_after:wN \__clist_remove_all:w \__clist_tmp:w . and we shouldn’t remove anything. and \use_none_delimit_by_q_stop:w is deleted. \q_mark . the first step happens to turn it into a single comma.) 388 . \__clist_remove_all: } #1 #2 { \exp_after:wN \__clist_remove_all: #2 .\clist_remove_all:Nn \clist_remove_all:cn \clist_gremove_all:Nn \clist_gremove_all:cn \__clist_remove_all:NNn \__clist_remove_all:w \__clist_remove_all: The method used here is very similar to \tl_replace_all:Nnn. the \q_mark delimiter used is the one inserted by \__clist_tmp:w. T . No } \cs_generate_variant:Nn \clist_if_in:NnT { c . 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 \prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 { T . F . cV . no } \cs_generate_variant:Nn \clist_if_in:nnTF { nV . No } \cs_generate_variant:Nn \clist_if_in:NnTF { c . 6057 6058 6059 6060 6061 \cs_new:Npn \clist_map_function:NN #1#2 { \clist_if_empty:NF #1 { \exp_last_unbraced:NNo \__clist_map_function:Nw #2 #1 389 . co } \cs_generate_variant:Nn \clist_if_in:NnTF { NV . TF } (End definition for \clist_if_empty:N and \clist_if_empty:c. with commas. TF } { \clist_set:Nn \l__clist_internal_clist {#1} \exp_args:No \__clist_if_in_return:nn \l__clist_internal_clist {#2} } \cs_new_protected:Npn \__clist_if_in_return:nn #1#2 { \cs_set:Npn \__clist_tmp:w ##1 . co } \cs_generate_variant:Nn \clist_if_in:nnT { nV .6 \clist_if_empty_p:N \clist_if_empty_p:c \clist_if_empty:NTF \clist_if_empty:cTF \clist_if_in:NnTF \clist_if_in:NVTF \clist_if_in:NoTF \clist_if_in:cnTF \clist_if_in:cVTF \clist_if_in:coTF \clist_if_in:nnTF \clist_if_in:nVTF \clist_if_in:noTF \__clist_if_in_return:nn Comma list conditionals Simple copies from the token list variable material. F . The end is marked by \q_recursion_tail. These functions are documented on page ??. T . and the item. grabbing one comma-delimited item at a time. cV . cV . Change with care.7 \clist_map_function:NN \clist_map_function:cN \__clist_map_function:Nw Mapping to comma lists If the variable is empty. no } \cs_generate_variant:Nn \clist_if_in:nnF { nV . TF } { \exp_args:No \__clist_if_in_return:nn #1 {#2} } \prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 { T . {} {} .#1. co } \cs_generate_variant:Nn \clist_if_in:NnF { NV . F . the mapping is skipped (otherwise.12. No } \cs_generate_variant:Nn \clist_if_in:NnF { c .) See description of the \tl_if_in:Nn function for details. that comma-list would be seen as consisting of one empty item). } { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \clist_if_in:NnT { NV . The auxiliary function \__clist_map_function:Nw is used directly in \clist_map_inline:Nn. no } (End definition for \clist_if_in:Nn and others. We simply surround the comma list. TF } \prg_new_eq_conditional:NNn \clist_if_empty:c \tl_if_empty:c { p . These functions are documented on page ??. { } \tl_if_empty:oTF { \__clist_tmp:w .) 12. F .#2.#2. 6030 6031 \prg_new_eq_conditional:NNn \clist_if_empty:N \tl_if_empty:N { p . Then loop over the comma-list. 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 . We don’t need a different comma-list for each nesting level: the comma-list is expanded before the mapping starts. Since the mapping is non-expandable. \q_recursion_tail . Space trimming is again based on \__clist_trim_spaces_generic:nw. then one level of braces is removed by \__clist_map_unbrace:Nw. } \__clist_trim_spaces_generic:nw { \__clist_map_function_n:Nn #1 } \q_mark } \cs_new:Npn \__clist_map_unbrace:Nw #1 #2. \__prg_break_point:Nn \clist_map_break: { } } } \cs_new:Npn \__clist_map_function:Nw #1#2 . { #1 {#2} } (End definition for \clist_map_function:nN. since spaces must be trimmed from each item. \__prg_break_point:Nn \clist_map_break: { } } \cs_new:Npn \__clist_map_function_n:Nn #1 #2 { \__quark_if_recursion_tail_break:nN {#2} \clist_map_break: \tl_if_empty:nF {#2} { \__clist_map_unbrace:Nw #1 #2. { \__quark_if_recursion_tail_break:nN {#2} \clist_map_break: #1 {#2} \__clist_map_function:Nw #1 } \cs_generate_variant:Nn \clist_map_function:NN { c } (End definition for \clist_map_function:NN and \clist_map_function:cN. \q_recursion_tail. 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 \cs_new:Npn \clist_map_function:nN #1#2 { \__clist_trim_spaces_generic:nw { \__clist_map_function_n:Nn #2 } \q_mark #1. We use a different function for each level of nesting. The auxiliary \__clist_map_function_n:Nn receives as arguments the function. Empty items are ignored. we can perform the space-trimming needed by the n version simply by storing the comma-list in a variable. This function is documented on page ??. These functions are documented on page ??. and the result of removing leading and trailing spaces from the item which lies until the next comma.) \clist_map_function:nN \__clist_map_function_n:Nn \__clist_map_unbrace:Nw The n-type mapping function is a bit more awkward. 6087 6088 6089 6090 6091 6092 \cs_new_protected:Npn \clist_map_inline:Nn #1#2 { \clist_if_empty:NF #1 { \int_gincr:N \g__prg_map_int \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1 {#2} 390 .) \clist_map_inline:Nn \clist_map_inline:cn \clist_map_inline:nn Inline mapping is done by creating a suitable function “on the fly”: this is done globally to avoid any issues with TEX’s groups. ) \clist_map_variable:NNn \clist_map_variable:cNn \clist_map_variable:nNn \__clist_map_variable:Nnw As for other comma-list mappings. Same approach as \clist_map_function:Nn.) \clist_map_break: \clist_map_break:n The break statements use the general \__prg_map_break:Nn mechanism. { \tl_set:Nn #1 {#3} \quark_if_recursion_tail_stop:N #1 \use:n {#2} \__clist_map_variable:Nnw #1 {#2} } \cs_generate_variant:Nn \clist_map_variable:NNn { c } (End definition for \clist_map_variable:NNn and \clist_map_variable:cNn. These functions are documented on page ??. additionally we store each item in the given variable.6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 \exp_last_unbraced:Nco \__clist_map_function:Nw { __prg_map_ \int_use:N \g__prg_map_int :w } #1 . \q_recursion_stop \__prg_break_point:Nn \clist_map_break: { } } } \cs_new_protected:Npn \clist_map_variable:nNn #1 { \clist_set:Nn \l__clist_internal_clist {#1} \clist_map_variable:NNn \l__clist_internal_clist } \cs_new_protected:Npn \__clist_map_variable:Nnw #1#2#3. space trimming for the n variant is done by storing the comma list in a variable. \q_recursion_tail . filter out the case of an empty list. 6130 \cs_new_nopar:Npn \clist_map_break: 391 . \__prg_break_point:Nn \clist_map_break: { \int_gdecr:N \g__prg_map_int } } } \cs_new_protected:Npn \clist_map_inline:nn #1 { \clist_set:Nn \l__clist_internal_clist {#1} \clist_map_inline:Nn \l__clist_internal_clist } \cs_generate_variant:Nn \clist_map_inline:Nn { c } (End definition for \clist_map_inline:Nn and \clist_map_inline:cn. As for inline mappings. \q_recursion_tail . These functions are documented on page ??. 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 \cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 { \clist_if_empty:NF #1 { \exp_args:Nno \use:nn { \__clist_map_variable:Nnw #2 {#3} } #1 . \clist_count:c . 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 \cs_new:Npn \clist_count:N #1 { \int_eval:n { 0 \clist_map_function:NN #1 \__clist_count:n } } \cs_generate_variant:Nn \clist_count:N { c } \cs_new:Npx \clist_count:n #1 { \exp_not:N \int_eval:n { 0 \exp_not:N \__clist_count:w \c_space_tl #1 \exp_not:n { . because it carefully removes spaces. first store it in a scratch variable. These functions are documented on page 118. we loop manually. Instead. and skip blank items (but not {}. \q_recursion_tail . then show that variable: The message takes care of omitting its name. 6159 6160 6161 6162 6163 \cs_new_protected:Npn \clist_show:N #1 { \__msg_show_variable:Nnn #1 { clist } { \clist_map_function:NN #1 \__msg_show_item:n } } 392 .6131 6132 6133 { \__prg_map_break:Nn \clist_map_break: { } } \cs_new_nopar:Npn \clist_map_break:n { \__prg_map_break:Nn \clist_map_break: } (End definition for \clist_map_break: and \clist_map_break:n. and \clist_count:n. { \exp_not:n { \exp_args:Nf \quark_if_recursion_tail_stop:n } {#1} \exp_not:N \tl_if_blank:nF {#1} { + \c_one } \exp_not:N \__clist_count:w \c_space_tl } (End definition for \clist_count:N . but that is very slow.) 12. In the case of an n-type comma-list. we could of course use \clist_map_function:nN. hence the extra spaces).8 \clist_show:N \clist_show:c \clist_show:n Viewing comma lists Apply the general \__msg_show_variable:Nnn. In the case of an n-type comma-list. \q_recursion_stop } } } \cs_new:Npn \__clist_count:n #1 { + \c_one } \cs_new:Npx \__clist_count:w #1 .) \clist_count:N \clist_count:c \clist_count:n \__clist_count:n \__clist_count:w Counting the items in a comma list is done using the same approach as for other token count functions: turn each entry into a +1 then use integer evaluation to actually do the mathematics. These functions are documented on page ??. 9 \l_tmpa_clist \l_tmpb_clist \g_tmpa_clist \g_tmpb_clist Scratch comma lists Temporary comma list variables.10 Deprecated interfaces Deprecated on 2011-05-27. These functions are documented on page 120.) 12. 393 . These functions are documented on page ??.) \clist_remove_element:Nn \clist_gremove_element:Nn An older name for \clist_remove_all:Nn. These functions are documented on page ??. 6174 6175 6176 6177 h*deprecatedi \cs_new_eq:NN \clist_top:NN \clist_get:NN \cs_new_eq:NN \clist_top:cN \clist_get:cN h/deprecatedi (End definition for \clist_top:NN and \clist_top:cN. 6182 6183 6184 6185 h*deprecatedi \cs_new_eq:NN \clist_display:N \clist_show:N \cs_new_eq:NN \clist_display:c \clist_show:c h/deprecatedi (End definition for \clist_display:N and \clist_display:c. 6170 6171 6172 6173 \clist_new:N \clist_new:N \clist_new:N \clist_new:N \l_tmpa_clist \l_tmpb_clist \g_tmpa_clist \g_tmpb_clist (End definition for \l_tmpa_clist and \l_tmpb_clist.) Deprecated on 2011-09-05. \clist_top:NN \clist_top:cN These are old stack functions. for removal by 2011-08-31. These functions are documented on page ??.6164 6165 6166 6167 6168 6169 \cs_new_protected:Npn \clist_show:n #1 { \clist_set:Nn \l__clist_internal_clist {#1} \clist_show:N \l__clist_internal_clist } \cs_generate_variant:Nn \clist_show:N { c } (End definition for \clist_show:N and \clist_show:c. 6178 6179 6180 6181 h*deprecatedi \cs_new_eq:NN \clist_remove_element:Nn \clist_remove_all:Nn \cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn h/deprecatedi (End definition for \clist_remove_element:Nn and \clist_gremove_element:Nn. for removal by 2011-12-31.) \clist_display:N \clist_display:c An older name for \clist_show:N. These functions are documented on page 119.) 12. \clist_if_eq_p:NN \clist_if_eq_p:Nc \clist_if_eq_p:cN \clist_if_eq_p:cc \clist_if_eq:NNTF \clist_if_eq:NcTF \clist_if_eq:cNTF \clist_if_eq:ccTF Simple copies from the token list variable material. . . .\clist_trim_spaces:N \clist_trim_spaces:c \clist_gtrim_spaces:N \clist_gtrim_spaces:c Since clist items are now always stripped from their surrounding spaces. .) Deprecated 2012-05-19 for removal by 2012-11-31. and \clist_length:n. it is redundant to provide these functions. 6186 6187 6188 6189 6190 6191 h*deprecatedi \cs_new_protected:Npn \clist_trim_spaces:N #1 { \clist_set:No #1 {#1} } \cs_new_protected:Npn \clist_gtrim_spaces:N #1 { \clist_gset:No #1 {#1} } \cs_generate_variant:Nn \clist_trim_spaces:N { c } \cs_generate_variant:Nn \clist_gtrim_spaces:N { c } h/deprecatedi (End definition for \clist_trim_spaces:N and others. . . The \__clist_trim_spaces:n function is now internal. \clist_length:N \clist_length:c \clist_length:n 6198 6199 6200 6201 6202 h*deprecatedi \cs_new_eq:NN \clist_length:N \clist_count:N \cs_new_eq:NN \clist_length:n \clist_count:c \cs_new_eq:NN \clist_length:c \clist_count:n h/deprecatedi (End definition for \clist_length:N . 6192 6193 6194 6195 6196 6197 h*deprecatedi \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn h/deprecatedi \clist_if_eq:NN \clist_if_eq:Nc \clist_if_eq:cN \clist_if_eq:cc \tl_if_eq:NN \tl_if_eq:Nc \tl_if_eq:cN \tl_if_eq:cc { { { { p p p p . deprecated for use outside the kernel. . These functions are documented on page ??. T T T T .) 6207 h/initex | packagei 394 .) Deprecated on 2012-05-10. . \clist_use:N \clist_use:c 6203 6204 6205 6206 h*deprecatedi \cs_new_eq:NN \clist_use:N \tl_use:N \cs_new_eq:NN \clist_use:c \tl_use:c h/deprecatedi (End definition for \clist_use:N and \clist_use:c. \clist_length:c . F F F F . TF TF TF TF } } } } (End definition for \clist_if_eq:NN and others. .) Deprecated 2012-05-13 for removal by 2012-11-31. These functions are documented on page ??. These functions are documented on page ??. These functions are documented on page ??. for removal by 2012-08-31. l3prop implementation 13 The following test files are used for this code: m3prop001. m3prop003. These functions are documented on page ??.1 \prop_new:N \prop_new:c Allocation and initialisation Internally. \s__prop hkeyn i \s__prop {hvaluen i} \s__prop A private scan mark is used as a marker surrounding each key.) 13. This variable is documented on page 126. This variable is documented on page 126. 6208 h*initex | packagei 6209 h@@=propi 6210 6211 6212 6213 6214 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei A property list is a macro whose top-level expansion is for the form \s__prop hkey1 i \s__prop {hvalue1 i} .) \c_empty_prop An empty prop is an empty token list. m3show001.) \prop_clear:N \prop_clear:c \prop_gclear:N \prop_gclear:c The same idea for clearing. 6220 6221 6222 6223 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \prop_clear:N \prop_clear:c \prop_gclear:N \prop_gclear:c \tl_clear:N \tl_clear:c \tl_gclear:N \tl_gclear:c (End definition for \prop_clear:N and \prop_clear:c. These functions are documented on page ??.) 395 .. property lists are just token lists. m3prop004. 6218 6219 \cs_new_eq:NN \prop_new:N \tl_new:N \cs_new_eq:NN \prop_new:c \tl_new:c (End definition for \prop_new:N and \prop_new:c. 6216 \tl_new:N \l__prop_internal_tl (End definition for \l__prop_internal_tl. m3prop002. 6217 \cs_new_eq:NN \c_empty_prop \c_empty_tl (End definition for \c_empty_prop..) \l__prop_internal_tl Token list used to store the new key–value pair inserted by \prop_put:Nnn and friends. 6215 \__scan_new:N \s__prop (End definition for \s__prop. then the hfunctioni is \use_ii:nn.) 13. These functions are documented on page ??. and can use the parameters #1. These functions are documented on page 126. If the hkeyi is not there. This is done using a delimited function. 6236 6237 6238 6239 \prop_new:N \prop_new:N \prop_new:N \prop_new:N \l_tmpa_prop \l_tmpb_prop \g_tmpa_prop \g_tmpb_prop (End definition for \l_tmpa_prop and \l_tmpb_prop. which keeps the hfalse codei. It receives a hproperty listi. \__prop_split_aux:w’s #1 is the part before the hkeyi. a htrue codei and a hfalse codei. 6240 6241 \cs_new_protected:Npn \__prop_split:NnTF #1#2 { \exp_args:NNo \__prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } } 396 . and hence must be fast. these are simply copies from the token list functions. #2. #3 for the three parts of the property list as desired.) \l_tmpa_prop \l_tmpb_prop \g_tmpa_prop \g_tmpb_prop We can now initialize the scratch variables.2 \__prop_split:NnTF \__prop_split_aux:NnTF \__prop_split_aux:w Accessing data in property lists This function is used by most of the module. 6228 6229 6230 6231 6232 6233 6234 6235 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \prop_set_eq:NN \prop_set_eq:Nc \prop_set_eq:cN \prop_set_eq:cc \prop_gset_eq:NN \prop_gset_eq:Nc \prop_gset_eq:cN \prop_gset_eq:cc \tl_set_eq:NN \tl_set_eq:Nc \tl_set_eq:cN \tl_set_eq:cc \tl_gset_eq:NN \tl_gset_eq:Nc \tl_gset_eq:cN \tl_gset_eq:cc (End definition for \prop_set_eq:NN and others. #3 is the part after the hkeyi.\prop_clear_new:N \prop_clear_new:c \prop_gclear_new:N \prop_gclear_new:c Once again a simple copy from the token list functions. a hkeyi. whose definition is as follows. These functions are documented on page ??. #4 is \use_i:nn.) \prop_set_eq:NN \prop_set_eq:cN \prop_set_eq:Nc \prop_set_eq:cc \prop_gset_eq:NN \prop_gset_eq:cN \prop_gset_eq:Nc \prop_gset_eq:cc Once again. \cs_set:Npn \__prop_split_aux:w #1 \s__prop hkeyi \s__prop #2 #3 \q_mark #4 #5 \q_stop { #4 {htrue codei} {hfalse codei} } If the hkeyi is present in the property list. where the hkeyi is turned into a string. The htrue codei is left in the input stream. The aim is to split the hproperty listi at the given hkeyi into the hextract1 i before the key–value pair. #2 is the hvaluei. and #5 is additional tokens that we do not care about. the hvaluei associated with the hkeyi and the hextract2 i after the key–value pair. 6224 6225 6226 6227 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \prop_clear_new:N \prop_clear_new:c \prop_gclear_new:N \prop_gclear_new:c \tl_clear_new:N \tl_clear_new:c \tl_gclear_new:N \tl_gclear_new:c (End definition for \prop_clear_new:N and \prop_clear_new:c. If the key is present. save \q_no_value in the token list.) \prop_pop:NnN \prop_pop:NoN \prop_pop:cnN \prop_pop:coN \prop_gpop:NnN \prop_gpop:NoN \prop_gpop:cnN \prop_gpop:coN Popping a value also starts by doing the split. nothing happens. These functions are documented on page ??. No } \cs_generate_variant:Nn \prop_get:NnN { c . the returned value is ignored. otherwise to \q_no_value. These functions are documented on page ??. If the key is missing.) \prop_remove:Nn \prop_remove:NV \prop_remove:cn \prop_remove:cV \prop_gremove:Nn \prop_gremove:NV \prop_gremove:cn \prop_gremove:cV Deleting from a property starts by splitting the list. cV .6242 6243 6244 6245 6246 6247 6248 6249 6250 \cs_new_protected:Npn \__prop_split_aux:NnTF #1#2#3#4 { \cs_set:Npn \__prop_split_aux:w ##1 \s__prop #2 \s__prop ##2 ##3 \q_mark ##4 ##5 \q_stop { ##4 {#3} {#4} } \exp_after:wN \__prop_split_aux:w #1 \q_mark \use_i:nn \s__prop #2 \s__prop { } \q_mark \use_ii:nn \q_stop } \cs_new:Npn \__prop_split_aux:w { } (End definition for \__prop_split:NnTF. cV } (End definition for \prop_remove:Nn and others. 6275 6276 6277 \cs_new_protected:Npn \prop_pop:NnN #1#2#3 { \__prop_split:NnTF #1 {#2} 397 . save the value in the token list and update the property list as when deleting. This function is documented on page 126. If the key is present in the property list. co } (End definition for \prop_get:NnN and others. if the key is in the property list. just set the token list variable to the return value.) \prop_get:NnN \prop_get:NVN \prop_get:NoN \prop_get:cnN \prop_get:cVN \prop_get:coN Getting an item from a list is very easy: after splitting. If the key is missing. 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 \cs_new_protected:Npn \prop_remove:Nn #1#2 { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #1 { ##1 ##3 } } { } } \cs_new_protected:Npn \prop_gremove:Nn #1#2 { \__prop_split:NnTF #1 {#2} { \tl_gset:Nn #1 { ##1 ##3 } } { } } \cs_generate_variant:Nn \prop_remove:Nn { NV } \cs_generate_variant:Nn \prop_remove:Nn { c . 6267 6268 6269 6270 6271 6272 6273 6274 \cs_new_protected:Npn \prop_get:NnN #1#2#3 { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #3 {##2} } { \tl_set:Nn #3 { \q_no_value } } } \cs_generate_variant:Nn \prop_get:NnN { NV . cV } \cs_generate_variant:Nn \prop_gremove:Nn { NV } \cs_generate_variant:Nn \prop_gremove:Nn { c . \prg_return_true: is used after the assignments. \cs_generate_variant:Nn \prop_gpop:NnN { \cs_generate_variant:Nn \prop_gpop:NnN { c . No co No co } } } } (End definition for \prop_pop:NnN and others. Otherwise. nor the token list are altered. TF } { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #3 {##2} \tl_gset:Nn #1 { ##1 ##3 } \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \prop_pop:NnNT { c } \cs_generate_variant:Nn \prop_pop:NnNF { c } \cs_generate_variant:Nn \prop_pop:NnNTF { c } \cs_generate_variant:Nn \prop_gpop:NnNT { c } \cs_generate_variant:Nn \prop_gpop:NnNF { c } 398 . F . 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 \prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T . neither the property list.) \prop_pop:NnNTF \prop_pop:cnNTF \prop_gpop:NnNTF \prop_gpop:cnNTF Popping an item from a property list. These functions are documented on page ??. keeping track of whether the key was present or not. F . If the key was missing.6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 { \tl_set:Nn #3 {##2} \tl_set:Nn #1 { ##1 ##3 } } { \tl_set:Nn #3 { \q_no_value } } } \cs_new_protected:Npn \prop_gpop:NnN #1#2#3 { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #3 {##2} \tl_gset:Nn #1 { ##1 ##3 } } { \tl_set:Nn #3 { \q_no_value } } } \cs_generate_variant:Nn \prop_pop:NnN { \cs_generate_variant:Nn \prop_pop:NnN { c . is implemented as a conditional. TF } { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #3 {##2} \tl_set:Nn #1 { ##1 ##3 } \prg_return_true: } { \prg_return_false: } } \prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T . append the new key–value to the list. NVV . cnx . These functions are documented on page ??. Nnx . coo } (End definition for \prop_put:Nnn and others. cnx . cnV . and since the hkeyi and new hvaluei may contain arbitrary tokens. No . preserving the order of entries. 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 \cs_new_protected_nopar:Npn \prop_put:Nnn { \__prop_put:NNNnn \tl_set:Nx \tl_put_right:Nx } \cs_new_protected_nopar:Npn \prop_gput:Nnn { \__prop_put:NNNnn \tl_gset:Nx \tl_gput_right:Nx } \cs_new_protected:Npn \__prop_put:NNNnn #1#2#3#4#5 { \tl_set:Nn \l__prop_internal_tl { \s__prop \tl_to_str:n {#4} \s__prop { \exp_not:n {#5} } } \__prop_split:NnTF #3 {#4} { #1 #3 { \exp_not:n {##1} \l__prop_internal_tl \exp_not:n {##3} } } { #2 #3 { \l__prop_internal_tl } } } \cs_generate_variant:Nn \prop_put:Nnn { NnV . cV . We thus start by storing in \l__prop_internal_tl tokens which (after x-expansion) encode the key–value pair. NV . cVV . the three brace groups given by \__prop_split:NnTF are removed. If the hkeyi was absent. NVV . Otherwise concatenate the extracts ##1 and ##3 with the new key–value pair \l__prop_internal_tl.) \prop_put:Nnn \prop_put:NnV \prop_put:Nno \prop_put:Nnx \prop_put:NVn \prop_put:NVV \prop_put:Non \prop_put:Noo \prop_put:cnn \prop_put:cnV \prop_put:cno \prop_put:cnx \prop_put:cVn \prop_put:cVV \prop_put:con \prop_put:coo \prop_gput:Nnn \prop_gput:NnV \prop_gput:Nno \prop_gput:Nnx \prop_gput:NVn \prop_gput:NVV \prop_gput:Non \prop_gput:Noo \prop_gput:cnn \prop_gput:cnV \prop_gput:cno \prop_gput:cnx \prop_gput:cVn \prop_put_if_new:Nnn \prop_gput:cVV \prop_put_if_new:cnn \prop_gput:con \prop_gput_if_new:Nnn \prop_gput:coo \prop_gput_if_new:cnn \__prop_put:NNNnn \__prop_put_if_new:NNnn Since the branches of \__prop_split:NnTF are used as the replacement text of an internal macro. being careful to convert the key to a string using \tl_to_str:n. Nnx . Nno . co .6322 \cs_generate_variant:Nn \prop_gpop:NnNTF { c } (End definition for \prop_pop:NnNTF and others. coo } \cs_generate_variant:Nn \prop_gput:Nnn { NnV . No . cnV . NV .) Adding conditionally also splits. If the key is new. cV . If the key is already present. cno . Noo } \cs_generate_variant:Nn \prop_gput:Nnn { c . cVV . Nno . it is not safe to include them in the argument of \__prop_split:NnTF. then the value is added. This variable can safely be used in \__prop_split:NnTF. 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 \cs_new_protected_nopar:Npn \prop_put_if_new:Nnn { \__prop_put_if_new:NNnn \tl_put_right:Nx } \cs_new_protected_nopar:Npn \prop_gput_if_new:Nnn { \__prop_put_if_new:NNnn \tl_gput_right:Nx } \cs_new_protected:Npn \__prop_put_if_new:NNnn #1#2#3#4 { \tl_set:Nn \l__prop_internal_tl { \s__prop \tl_to_str:n {#3} \s__prop \exp_not:n { {#4} } } \__prop_split:NnTF #2 {#3} { } { #1 #2 { \l__prop_internal_tl } } } 399 . The updated entry is placed at the same spot as the original hkeyi in the property list. cno . co . Noo } \cs_generate_variant:Nn \prop_put:Nnn { c . These functions are documented on page ??. TF } \prg_new_eq_conditional:NNn \prop_if_empty:c \tl_if_empty:c { p .6355 6356 \cs_generate_variant:Nn \prop_put_if_new:Nnn { c } \cs_generate_variant:Nn \prop_gput_if_new:Nnn { c } (End definition for \prop_put_if_new:Nnn and \prop_put_if_new:cnn. but only when included in the \str_if_eq_x:nn. T . since it can only map a single token. p } (End definition for \prop_if_exist:N and \prop_if_exist:c. T . we test the next token: it is either \s__prop or \q_recursion_tail in the case of a missing key. T . To terminate the mapping.3 Property list conditionals \prop_if_exist_p:N \prop_if_exist_p:c \prop_if_exist:NTF \prop_if_exist:cTF Copies of the cs functions defined in l3basics. F . It cannot make the breaking mechanism choke.) 13.) 6359 6360 6361 6362 \prg_new_eq_conditional:NNn \prop_if_empty:N \tl_if_empty:N { p . p } \prg_new_eq_conditional:NNn \prop_if_exist:c \cs_if_exist:c { TF . which is expandable. This second \tl_to_str:n is not expanded at the start. \prop_map_function:NN is not sufficient for the mapping. and a faster test would be \prg_new_protected_conditional:Npnn \prop_if_in:Nn #1 #2 { \@@_split:NnTF #1 {#2} { \prg_return_true: \use_none:nnn } { \prg_return_false: } } but \__prop_split:NnTF is non-expandable. These functions are documented on page ??. F . because the arbitrary token list material is enclosed in braces. 6363 6364 6365 6366 6367 \prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p . F . T . This is rather slow. F . TF } (End definition for \prop_if_empty:N and \prop_if_empty:c. we append to the property list the key that is searched for. and cannot carry the key that is searched for.) \prop_if_in_p:Nn \prop_if_in_p:NV \prop_if_in_p:No \prop_if_in_p:cn \prop_if_in_p:cV \prop_if_in_p:co \prop_if_in:NnTF \prop_if_in:NVTF \prop_if_in:NoTF \prop_if_in:cnTF \prop_if_in:cVTF \prop_if_in:coTF \__prop_if_in:nwn \__prop_if_in:N Testing expandably if a key is in a property list requires to go through the key–value pairs one by one. Here. When ending. F . Instead. These functions are documented on page ??. These functions are documented on page ??. TF } { \exp_last_unbraced:Noo \__prop_if_in:nwn { \tl_to_str:n {#2} } #1 \s__prop \tl_to_str:n {#2} \s__prop { } 400 . T . 6357 6358 \prg_new_eq_conditional:NNn \prop_if_exist:N \cs_if_exist:N { TF . the key is compared to each key in turn using \str_if_eq_x:nn. \prop_if_empty_p:N \prop_if_empty_p:c \prop_if_empty:NTF \prop_if_empty:cTF Same test as for token lists. co } \cs_generate_variant:Nn \prop_get:NnNF { c . the token list is not altered. cV NV . No } \cs_generate_variant:Nn \prop_get:NnNTF { NV . cV NV . These functions are documented on page ??. TF } { \__prop_split:NnTF #1 {#2} { \tl_set:Nn #3 {##2} \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \prop_get:NnNT { NV . cV . . is implemented as a conditional (with side effects). . . No } \cs_generate_variant:Nn \prop_get:NnNT { c .4 \prop_get:NnNTF \prop_get:NVNTF \prop_get:NoNTF \prop_get:cnNTF \prop_get:cVNTF \prop_get:coNTF Recovering values from property lists with branching Getting the value corresponding to a key. cV . cV .) 13. These functions are documented on page ??. 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 \prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T . cV . co } (End definition for \prop_get:NnNTF and others. No co No co No co No co } } } } } } } } (End definition for \prop_if_in:Nn and others. No } \cs_generate_variant:Nn \prop_get:NnNF { NV . cV NV .\q_recursion_tail \__prg_break_point: 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 } \cs_new:Npn \__prop_if_in:nwn #1 \s__prop #2 { \str_if_eq_x:nnTF {#1} {#2} { \__prop_if_in:N } { \__prop_if_in:nwn {#1} } } \cs_new:Npn \__prop_if_in:N #1 { \if_meaning:w \s__prop #1 \prg_return_true: \else: \prg_return_false: \fi: \__prg_break: } \cs_generate_variant:Nn \prop_if_in_p:Nn { \cs_generate_variant:Nn \prop_if_in_p:Nn { c \cs_generate_variant:Nn \prop_if_in:NnT { \cs_generate_variant:Nn \prop_if_in:NnT { c \cs_generate_variant:Nn \prop_if_in:NnF { \cs_generate_variant:Nn \prop_if_in:NnF { c \cs_generate_variant:Nn \prop_if_in:NnTF { \cs_generate_variant:Nn \prop_if_in:NnTF { c \s__prop #3 NV . F .) 401 . keeping track of whether the key was present or not. . . . If the key was absent. . co } \cs_generate_variant:Nn \prop_get:NnNTF { c . 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 \cs_new:Npn \prop_map_function:NN #1#2 { \exp_last_unbraced:NNo \__prop_map_function:Nwn #1 \s__prop \q_recursion_tail \s__prop { } \__prg_break_point:Nn \prop_map_break: { } } \cs_new:Npn \__prop_map_function:Nwn #1 \s__prop #2 { \if_meaning:w \q_recursion_tail #2 \exp_after:wN \prop_map_break: \fi: #1 {#2} {#3} \__prop_map_function:Nwn #1 } \cs_generate_variant:Nn \prop_map_function:NN { \cs_generate_variant:Nn \prop_map_function:NN { c . A special case to note is when the key #2 is empty: then \q_recursion_tail is compared to \exp_after:wN.) \prop_map_inline:Nn \prop_map_inline:cn Mapping in line requires a nesting level counter. These functions are documented on page ??. This function is documented on page 125.5 \prop_map_function:NN \prop_map_function:Nc \prop_map_function:cN \prop_map_function:cc \__prop_map_function:Nwn Mapping to property lists The fastest way to do a recursion here is to use an \if_meaning:w test: the keys are strings.13. also different.) \prop_map_break: \prop_map_break:n The break statements are based on the general \__prg_map_break:Nn. These functions are documented on page ??. and thus cannot match the marker \q_recursion_tail. #2 \s__prop #3 Nc } cc } (End definition for \prop_map_function:NN and others. 6436 6437 6438 6439 \cs_new_nopar:Npn \prop_map_break: { \__prg_map_break:Nn \prop_map_break: { } } \cs_new_nopar:Npn \prop_map_break:n { \__prg_map_break:Nn \prop_map_break: } (End definition for \prop_map_break:.) 402 . 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 \cs_new_protected:Npn \prop_map_inline:Nn #1#2 { \int_gincr:N \g__prg_map_int \cs_gset:cpn { __prg_map_ \int_use:N \g__prg_map_int :w } ##1##2 {#2} \exp_last_unbraced:Nco \__prop_map_function:Nwn { __prg_map_ \int_use:N \g__prg_map_int :w } #1 \s__prop \q_recursion_tail \s__prop { } \__prg_break_point:Nn \prop_map_break: { \int_gdecr:N \g__prg_map_int } } \cs_generate_variant:Nn \prop_map_inline:Nn { c } (End definition for \prop_map_inline:Nn and \prop_map_inline:cn. 6440 6441 6442 6443 6444 6445 \cs_new_protected:Npn \prop_show:N #1 { \__msg_show_variable:Nnn #1 { prop } { \prop_map_function:NN #1 \__msg_show_item:nn } } \cs_generate_variant:Nn \prop_show:N { c } (End definition for \prop_show:N and \prop_show:c. \prop_display:N \prop_display:c An older name for \prop_show:N.13.6 \prop_show:N \prop_show:c Viewing property lists Apply the general \__msg_show_variable:Nnn. Contrarily to sequences and comma lists. These functions are documented on page ??. for removal by 2011-08-31.) 13. 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 h*deprecatedi \tl_new:N \l__prop_internal_tl \cs_new_protected:Npn \prop_gget:NnN #1#2#3 { \prop_get:NnN #1 {#2} \l__prop_internal_tl \tl_gset_eq:NN #3 \l__prop_internal_tl } \cs_generate_variant:Nn \prop_gget:NnN { NV } \cs_generate_variant:Nn \prop_gget:NnN { c .) \prop_if_in:ccTF A hang-over from an ancient implementation 6463 6464 6465 6466 6467 h*deprecatedi \cs_generate_variant:Nn \prop_if_in:NnT { cc } \cs_generate_variant:Nn \prop_if_in:NnF { cc } \cs_generate_variant:Nn \prop_if_in:NnTF { cc } h/deprecatedi 403 . we use \__msg_show_item:nn to format both the key and the value for each pair.) \prop_get_gdel:NnN This name seems very odd. This function is documented on page ??. cV } h/deprecatedi (End definition for \prop_gget:NnN and others. 6446 6447 6448 6449 h*deprecatedi \cs_new_eq:NN \prop_display:N \prop_show:N \cs_new_eq:NN \prop_display:c \prop_show:c h/deprecatedi (End definition for \prop_display:N and \prop_display:c. 6460 6461 6462 h*deprecatedi \cs_new_eq:NN \prop_get_gdel:NnN \prop_gpop:NnN h/deprecatedi (End definition for \prop_get_gdel:NnN. These functions are documented on page ??.7 Deprecated interfaces Deprecated on 2011-05-27.) \prop_gget:NnN \prop_gget:NVN \prop_gget:cnN \prop_gget:cVN \prop_gget_aux:Nnnn Getting globally is no longer supported: this is a conceptual change. These functions are documented on page ??. so the necessary code for the transition is provided directly. . F F F F . . .(End definition for \prop_if_in:ccTF.) 6487 h/initex | packagei l3box implementation 14 6488 h*initex | packagei 6489 h@@=boxi 6490 6491 6492 6493 6494 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei The code in this module is very straight forward so I’m not going to comment it very extensively. This function is documented on page ??. for removal by 2012-11-30.lvt. . . .) \prop_if_eq_p:NN \prop_if_eq_p:Nc \prop_if_eq_p:cN \prop_if_eq_p:cc \prop_if_eq:NNTF \prop_if_eq:NcTF \prop_if_eq:cNTF \prop_if_eq:ccTF These ones do no even make sense! 6471 6472 6473 6474 6475 6476 h*deprecatedi \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn \prg_new_eq_conditional:NNn h/deprecatedi \prop_if_eq:NN \prop_if_eq:cN \prop_if_eq:Nc \prop_if_eq:cc \tl_if_eq:NN \tl_if_eq:cN \tl_if_eq:Nc \tl_if_eq:cc { { { { p p p p . These functions are documented on page ??. TF TF TF TF } } } } (End definition for \prop_if_eq:NN and others.1 Creating and initialising boxes The following test files are used for this code: m3box001. 404 . . This function is documented on page ??. \prop_del:Nn \prop_del:NV \prop_del:cn \prop_del:cV \prop_gdel:Nn \prop_gdel:NV \prop_gdel:cn \prop_gdel:cV 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \prop_del:Nn \prop_remove:Nn \prop_del:NV \prop_remove:NV \prop_del:cn \prop_remove:cn \prop_del:cV \prop_remove:cV \prop_gdel:Nn \prop_gremove:Nn \prop_gdel:NV \prop_gremove:NV \prop_gdel:cn \prop_gremove:cn \prop_gdel:cV \prop_gremove:cV (End definition for \prop_del:Nn and others. .) Deprecated on 2012-05-12. 14. These functions are documented on page ??.) \prop_gput:ccx Another one. T T T T . . 6468 6469 6470 h*deprecatedi \cs_generate_variant:Nn \prop_gput:Nnn { ccx } h/deprecatedi (End definition for \prop_gput:ccx. T . 6521 6522 6523 6524 6525 6526 \cs_new_protected:Npn \box_set_eq_clear:NN #1#2 { \tex_setbox:D #1 \tex_box:D #2 } \cs_new_protected:Npn \box_gset_eq_clear:NN { \tex_global:D \box_set_eq_clear:NN } \cs_generate_variant:Nn \box_set_eq_clear:NN { c .\box_new:N \box_new:c Defining a new hboxi register: remember that box 255 is not generally available. 6512 \box_set_eq:NN \box_set_eq:cN \box_set_eq:Nc \box_set_eq:cc \box_gset_eq:NN \box_gset_eq:cN \box_gset_eq:Nc \box_gset_eq:cc \box_set_eq_clear:NN \box_set_eq_clear:cN \box_set_eq_clear:Nc \box_set_eq_clear:cc \box_gset_eq_clear:NN \box_gset_eq_clear:cN \box_gset_eq_clear:Nc \box_gset_eq_clear:cc h*packagei \cs_new_protected:Npn \box_new:N #1 { \__chk_if_free_cs:N #1 \newbox #1 } h/packagei \cs_generate_variant:Nn \box_new:N { c } \cs_new_protected:Npn \box_clear_new:N #1 { \box_if_exist:NTF #1 { \box_clear:N #1 } { \box_new:N #1 } } \cs_new_protected:Npn \box_gclear_new:N #1 { \box_if_exist:NTF #1 { \box_gclear:N #1 } { \box_new:N #1 } } \cs_generate_variant:Nn \box_clear_new:N { c } \cs_generate_variant:Nn \box_gclear_new:N { c } Assigning the contents of a box to be another box. p } \prg_new_eq_conditional:NNn \box_if_exist:c \cs_if_exist:c { TF . cc } Copies of the cs functions defined in l3basics. This clears the second box globally (that’s how TEX does it). Nc . F . cc } \cs_generate_variant:Nn \box_gset_eq:NN { c . 6503 6504 6505 6506 6507 6508 \box_clear_new:N \box_clear_new:c \box_gclear_new:N \box_gclear_new:c 6509 6510 6511 6513 6514 \box_if_exist_p:N \box_if_exist_p:c \box_if_exist:NTF \box_if_exist:cTF \cs_new_protected:Npn \box_clear:N #1 { \box_set_eq:NN #1 \c_empty_box } \cs_new_protected:Npn \box_gclear:N #1 { \box_gset_eq:NN #1 \c_empty_box } \cs_generate_variant:Nn \box_clear:N { c } \cs_generate_variant:Nn \box_gclear:N { c } Clear or new. 6495 6496 6497 6498 6499 6500 6501 6502 \box_clear:N \box_clear:c \box_gclear:N \box_gclear:c Clear a hboxi register. cc } Assigning the contents of a box to be another box. Nc . T . 6527 6528 \prg_new_eq_conditional:NNn \box_if_exist:N \cs_if_exist:N { TF . F . p } 405 . cc } \cs_generate_variant:Nn \box_gset_eq_clear:NN { c . Nc . 6515 6516 6517 6518 6519 6520 \cs_new_protected:Npn \box_set_eq:NN #1#2 { \tex_setbox:D #1 \tex_copy:D #2 } \cs_new_protected:Npn \box_gset_eq:NN { \tex_global:D \box_set_eq:NN } \cs_generate_variant:Nn \box_set_eq:NN { c . Nc . and width of a hboxi register. 6529 6530 6531 6532 6533 6534 \box_set_ht:Nn \box_set_ht:cn \box_set_dp:Nn \box_set_dp:cn \box_set_wd:Nn \box_set_wd:cn \cs_new_eq:NN \box_ht:N \cs_new_eq:NN \box_dp:N \cs_new_eq:NN \box_wd:N \cs_generate_variant:Nn \cs_generate_variant:Nn \cs_generate_variant:Nn 6535 6536 6537 6538 6540 6541 6542 6543 \cs_new_protected:Npn \box_set_dp:Nn #1#2 { \box_dp:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \box_set_ht:Nn #1#2 { \box_ht:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_new_protected:Npn \box_set_wd:Nn #1#2 { \box_wd:N #1 \__dim_eval:w #2 \__dim_eval_end: } \cs_generate_variant:Nn \box_set_ht:Nn { c } \cs_generate_variant:Nn \box_set_dp:Nn { c } \cs_generate_variant:Nn \box_set_wd:Nn { c } 14. depth. These primitives are not expandable. 6539 \box_use_clear:N \box_use_clear:c \box_use:N \box_use:c Measuring and setting box dimensions Box conditionals The primitives for testing if a hboxi is empty/void or which type of box it is. These are just TEX primitives with meaningful names.4 \if_hbox:N \if_vbox:N \if_box_empty:N Using boxes Using a hboxi.14. 6548 6549 6550 6551 6552 6553 6554 6555 \cs_new_protected:Npn \box_move_left:nn #1#2 { \tex_moveleft:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_right:nn #1#2 { \tex_moveright:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_up:nn #1#2 { \tex_raise:D \__dim_eval:w #1 \__dim_eval_end: #2 } \cs_new_protected:Npn \box_move_down:nn #1#2 { \tex_lower:D \__dim_eval:w #1 \__dim_eval_end: #2 } 14. 6547 \box_move_left:nn \box_move_right:nn \box_move_up:nn \box_move_down:nn \tex_ht:D \tex_dp:D \tex_wd:D \box_ht:N { c } \box_dp:N { c } \box_wd:N { c } Measuring is easy: all primitive work.2 \box_ht:N \box_ht:c \box_dp:N \box_dp:c \box_wd:N \box_wd:c Accessing the height. so the derived functions are not either. 6556 6557 6558 \cs_new_eq:NN \if_hbox:N \tex_ifhbox:D \cs_new_eq:NN \if_vbox:N \tex_ifvbox:D \cs_new_eq:NN \if_box_empty:N \tex_ifvoid:D 406 .3 6544 6545 6546 \cs_new_eq:NN \box_use_clear:N \tex_box:D \cs_new_eq:NN \box_use:N \tex_copy:D \cs_generate_variant:Nn \box_use_clear:N { c } \cs_generate_variant:Nn \box_use:N { c } Move box material in different directions. F . T .) 14. T . 6571 6572 6573 6574 6575 6576 \prg_new_conditional:Npnn \box_if_empty:N #1 { p . 6584 6585 6586 6587 \box_new:N \box_new:N \box_new:N \box_new:N \l_tmpa_box \l_tmpb_box \g_tmpa_box \g_tmpb_box (End definition for \l_tmpa_box and others. 6577 6578 6579 6580 6581 6582 \cs_new_protected:Npn \box_set_to_last:N #1 { \tex_setbox:D #1 \tex_lastbox:D } \cs_new_protected:Npn \box_gset_to_last:N { \tex_global:D \box_set_to_last:N } \cs_generate_variant:Nn \box_set_to_last:N { c } \cs_generate_variant:Nn \box_gset_to_last:N { c } (End definition for \box_set_to_last:N and \box_set_to_last:c. F .6 \c_empty_box Constant boxes A box we never use. These variables are documented on page 130. F { \if_hbox:N #1 \prg_return_true: \else: \prg_return_false: \prg_new_conditional:Npnn \box_if_vertical:N #1 { p .\box_if_horizontal_p:N \box_if_horizontal_p:c \box_if_horizontal:NTF \box_if_horizontal:cTF \box_if_vertical_p:N \box_if_vertical_p:c \box_if_vertical:NTF \box_if_vertical:cTF 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 \box_if_empty_p:N \box_if_empty_p:c \box_if_empty:NTF \box_if_empty:cTF \prg_new_conditional:Npnn \box_if_horizontal:N #1 { p .5 \box_set_to_last:N \box_set_to_last:c \box_gset_to_last:N \box_gset_to_last:c The last box inserted Set a box to the previous box.) 407 . { \if_vbox:N #1 \prg_return_true: \else: \prg_return_false: \cs_generate_variant:Nn \box_if_horizontal_p:N { c } \cs_generate_variant:Nn \box_if_horizontal:NT { c } \cs_generate_variant:Nn \box_if_horizontal:NF { c } \cs_generate_variant:Nn \box_if_horizontal:NTF { c } \cs_generate_variant:Nn \box_if_vertical_p:N { c } \cs_generate_variant:Nn \box_if_vertical:NT { c } \cs_generate_variant:Nn \box_if_vertical:NF { c } \cs_generate_variant:Nn \box_if_vertical:NTF { c } . This variable is documented on page 130. TF } { \if_box_empty:N #1 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \box_if_empty_p:N { c } \cs_generate_variant:Nn \box_if_empty:NT { c } \cs_generate_variant:Nn \box_if_empty:NF { c } \cs_generate_variant:Nn \box_if_empty:NTF { c } (End definition for \box_new:N and \box_new:c. 6583 \box_new:N \c_empty_box (End definition for \c_empty_box. These functions are documented on page ??.) 14. T . TF } \fi: } TF } \fi: } Testing if a hboxi is empty/void. These functions are documented on page ??.) 14.7 \l_tmpa_box \l_tmpb_box \g_tmpa_box \g_tmpb_box Scratch boxes Scratch boxes. 6588 6589 6590 6591 6592 6593 \cs_new_protected:Npn \box_show:N #1 { \box_show:Nnn #1 \c_max_int \c_max_int } \cs_generate_variant:Nn \box_show:N { c } \cs_new_protected_nopar:Npn \box_show:Nnn { \__box_show:NNnn \c_one } \cs_generate_variant:Nn \box_show:Nnn { c } (End definition for \box_show:N and \box_show:c. and it is also inconsistent with other LATEX3 show functions as it does not actually shows material in the terminal. These functions are documented on page ??.) \__box_show:NNnn The internal auxiliary to actually do the output uses a group to deal with breadth and depth values. These functions are documented on page ??.) \box_log:N \box_log:c \box_log:Nnn \box_log:cnn Getting TEX to write to the log without interruption the run is done by altering the interaction mode. So we provide a richer set of functionality. Setting \tex_tracingonline:D is used to control what appears in the terminal. For that. the ε-TEX extensions are needed. \box_show:N \box_show:c \box_show:Nnn \box_show:cnn Essentially a wrapper around the internal function. The \use:n here gives better output appearance. 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 \cs_new_protected:Npn \box_log:N #1 { \box_log:Nnn #1 \c_max_int \c_max_int } \cs_generate_variant:Nn \box_log:N { c } \cs_new_protected:Npn \box_log:Nnn #1#2#3 { \use:x { \etex_interactionmode:D \c_zero \__box_show:NNnn \c_zero \exp_not:N #1 { \int_eval:n {#2} } { \int_eval:n {#3} } \etex_interactionmode:D = \tex_the:D \etex_interactionmode:D \scan_stop: } } \cs_generate_variant:Nn \box_log:Nnn { c } (End definition for \box_log:N and \box_log:c.14.8 Viewing box contents TEX’s \tex_showbox:D is not really that helpful in many cases. 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 \cs_new_protected:Npn \__box_show:NNnn #1#2#3#4 { \group_begin: \int_set:Nn \tex_showboxbreadth:D {#3} \int_set:Nn \tex_showboxdepth:D {#4} \int_set_eq:NN \tex_tracingonline:D #1 \box_if_exist:NTF #2 { \tex_showbox:D \use:n {#2} } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #2 } } 408 . \group_end: 6621 } 6622 (End definition for \__box_show:NNnn. 6623 \cs_new_protected:Npn \hbox:n { \tex_hbox:D \scan_stop: } (End definition for \hbox:n. This type is useful in environment definitions.) 409 .) Put a horizontal box directly into the input stream. These functions are documented on page ??. 6634 6635 6636 6637 6638 6639 6640 6641 \cs_new_protected:Npn \hbox_set:Nw #1 { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token } \cs_new_protected:Npn \hbox_gset:Nw { \tex_global:D \hbox_set:Nw } \cs_generate_variant:Nn \hbox_set:Nw { c } \cs_generate_variant:Nn \hbox_gset:Nw { c } \cs_new_eq:NN \hbox_set_end: \c_group_end_token \cs_new_eq:NN \hbox_gset_end: \c_group_end_token (End definition for \hbox_set:Nw and \hbox_set:cw.lvt. These functions are documented on page ??. is m3box002.) 14. These functions are documented on page ??.) \hbox_set:Nn \hbox_set:cn \hbox_gset:Nn \hbox_gset:cn 6624 6625 6626 6627 \cs_new_protected:Npn \hbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_hbox:D {#2} } \cs_new_protected:Npn \hbox_gset:Nn { \tex_global:D \hbox_set:Nn } \cs_generate_variant:Nn \hbox_set:Nn { c } \cs_generate_variant:Nn \hbox_gset:Nn { c } (End definition for \hbox_set:Nn and \hbox_set:cn. 6628 6629 6630 6631 6632 6633 \cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3 { \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end: {#3} } \cs_new_protected:Npn \hbox_gset_to_wd:Nnn { \tex_global:D \hbox_set_to_wd:Nnn } \cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c } \cs_generate_variant:Nn \hbox_gset_to_wd:Nnn { c } (End definition for \hbox_set_to_wd:Nnn and \hbox_set_to_wd:cnn. This function is documented on page 131. 6642 6643 6644 6645 6646 6647 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \hbox_set_inline_begin:N \hbox_set_inline_begin:c \hbox_set_inline_end: \hbox_gset_inline_begin:N \hbox_gset_inline_begin:c \hbox_gset_inline_end: \hbox_set:Nw \hbox_set:cw \hbox_set_end: \hbox_gset:Nw \hbox_gset:cw \hbox_gset_end: (End definition for \hbox_set_inline_begin:N and \hbox_set_inline_begin:c. and others in this file. These functions are documented on page 132.) \hbox_set_to_wd:Nnn \hbox_set_to_wd:cnn \hbox_gset_to_wd:Nnn \hbox_gset_to_wd:cnn Storing material in a horizontal box with a specified width.9 \hbox:n Horizontal mode boxes (The test suite for this command.) \hbox_set:Nw \hbox_set:cw \hbox_gset:Nw \hbox_gset:cw \hbox_set_end: \hbox_gset_end: Storing material in a horizontal box.) \hbox_set_inline_begin:N \hbox_set_inline_begin:c \hbox_gset_inline_begin:N \hbox_gset_inline_begin:c \hbox_set_inline_end: \hbox_gset_inline_end: Renamed September 2011. 10 Vertical mode boxes TEX ends these boxes directly with the internal end_graf routine. 6651 6652 6653 6654 \cs_new_protected:Npn { \hbox_to_zero:n { \cs_new_protected:Npn { \hbox_to_zero:n { \hbox_overlap_left:n #1 \tex_hss:D #1 } } \hbox_overlap_right:n #1 #1 \tex_hss:D } } (End definition for \hbox_overlap_left:n and \hbox_overlap_right:n. 6659 6660 \cs_new_protected:Npn \vbox:n #1 { \tex_vbox:D { #1 \par } } \cs_new_protected:Npn \vbox_top:n #1 { \tex_vtop:D { #1 \par } } (End definition for \vbox:n. These functions are documented on page ??. \vbox_top:n The following test files are used for this code: m3box003. 6661 6662 6663 6664 \cs_new_protected:Npn \vbox_to_ht:nn #1#2 { \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end: { #2 \par } } \cs_new_protected:Npn \vbox_to_zero:n #1 { \tex_vbox:D to \c_zero_dim { #1 \par } } (End definition for \vbox_to_ht:nn and \vbox_to_zero:n.) \hbox_unpack:N \hbox_unpack:c \hbox_unpack_clear:N \hbox_unpack_clear:c Unpacking a box and if requested also clear it. Put a vertical box directly into the input stream.\hbox_to_wd:nn \hbox_to_zero:n Put a horizontal box directly into the input stream.) \vbox_set:Nn \vbox_set:cn \vbox_gset:Nn \vbox_gset:cn Storing material in a vertical box with a natural height.) \vbox_to_ht:nn \vbox_to_zero:n \vbox_to_ht:nn \vbox_to_zero:n Put a vertical box directly into the input stream.lvt.lvt. These functions are documented on page 133. 6665 6666 6667 6668 6669 \cs_new_protected:Npn \vbox_set:Nn #1#2 { \tex_setbox:D #1 \tex_vbox:D { #2 \par } } \cs_new_protected:Npn \vbox_gset:Nn { \tex_global:D \vbox_set:Nn } \cs_generate_variant:Nn \vbox_set:Nn { c } \cs_generate_variant:Nn \vbox_gset:Nn { c } 410 .) \hbox_overlap_left:n \hbox_overlap_right:n Put a zero-sized box with the contents pushed against one side (which makes it stick out on the other) directly into the input stream. 6655 6656 6657 6658 \cs_new_eq:NN \hbox_unpack:N \tex_unhcopy:D \cs_new_eq:NN \hbox_unpack_clear:N \tex_unhbox:D \cs_generate_variant:Nn \hbox_unpack:N { c } \cs_generate_variant:Nn \hbox_unpack_clear:N { c } (End definition for \hbox_unpack:N and \hbox_unpack:c. This means that there is no \par at the end of vertical boxes unless we insert one. \vbox:n The following test files are used for this code: m3box003. This function is documented on page 131.) 14. This function is documented on page 132. 6648 6649 6650 \cs_new_protected:Npn \hbox_to_wd:nn #1#2 { \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end: {#2} } \cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_dim {#1} } (End definition for \hbox_to_wd:nn. These functions are documented on page 131. 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 \cs_new_protected:Npn \vbox_set:Nw #1 { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token } \cs_new_protected:Npn \vbox_gset:Nw { \tex_global:D \vbox_set:Nw } \cs_generate_variant:Nn \vbox_set:Nw { c } \cs_generate_variant:Nn \vbox_gset:Nw { c } \cs_new_protected:Npn \vbox_set_end: { \par \c_group_end_token } \cs_new_eq:NN \vbox_gset_end: \vbox_set_end: (End definition for \vbox_set:Nw and \vbox_set:cw. These functions are documented on page ??. These functions are documented on page ??.) \vbox_set_inline_begin:N \vbox_set_inline_begin:c \vbox_gset_inline_begin:N \vbox_gset_inline_begin:c \vbox_set_inline_end: \vbox_gset_inline_end: Renamed September 2011.) \vbox_set_top:Nn \vbox_set_top:cn \vbox_gset_top:Nn \vbox_gset_top:cn Storing material in a vertical box with a natural height and reference point at the baseline of the first object in the box. These functions are documented on page 133. 6694 6695 6696 6697 6698 6699 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \vbox_set_inline_begin:N \vbox_set:Nw \vbox_set_inline_begin:c \vbox_set:cw \vbox_set_inline_end: \vbox_set_end: \vbox_gset_inline_begin:N \vbox_gset:Nw \vbox_gset_inline_begin:c \vbox_gset:cw \vbox_gset_inline_end: \vbox_gset_end: (End definition for \vbox_set_inline_begin:N and \vbox_set_inline_begin:c.) \vbox_set:Nw \vbox_set:cw \vbox_gset:Nw \vbox_gset:cw \vbox_set_end: \vbox_gset_end: Storing material in a vertical box. These functions are documented on page ??. These functions are documented on page ??.) 411 . 6676 6677 6678 6679 6680 6681 \cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3 { \tex_setbox:D #1 \tex_vbox:D to \__dim_eval:w #2 \__dim_eval_end: { #3 \par } } \cs_new_protected:Npn \vbox_gset_to_ht:Nnn { \tex_global:D \vbox_set_to_ht:Nnn } \cs_generate_variant:Nn \vbox_set_to_ht:Nnn { c } \cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c } (End definition for \vbox_set_to_ht:Nnn and \vbox_set_to_ht:cnn.(End definition for \vbox_set:Nn and \vbox_set:cn.) \vbox_set_to_ht:Nnn \vbox_set_to_ht:cnn \vbox_gset_to_ht:Nnn \vbox_gset_to_ht:cnn Storing material in a vertical box with a specified height. This type is useful in environment definitions. 6670 6671 6672 6673 6674 6675 \cs_new_protected:Npn \vbox_set_top:Nn #1#2 { \tex_setbox:D #1 \tex_vtop:D { #2 \par } } \cs_new_protected:Npn \vbox_gset_top:Nn { \tex_global:D \vbox_set_top:Nn } \cs_generate_variant:Nn \vbox_set_top:Nn { c } \cs_generate_variant:Nn \vbox_gset_top:Nn { c } (End definition for \vbox_set_top:Nn and \vbox_set_top:cn. 6720 6721 6722 6723 6724 \prop_new:N \c__coffin_corners_prop \prop_put:Nnn \c__coffin_corners_prop \prop_put:Nnn \c__coffin_corners_prop \prop_put:Nnn \c__coffin_corners_prop \prop_put:Nnn \c__coffin_corners_prop 412 { { { { tl tr bl br } } } } { { { { { { { { 0 0 0 0 pt pt pt pt } } } } { { { { 0 0 0 0 pt pt pt pt } } } } } } } } . as opposed to the TEX bounding box. This function is documented on page ??.) 6709 h/initex | packagei l3coffins Implementation 15 6710 h*initex | packagei 6711 h@@=coffini 6712 6713 6714 6715 6716 h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 15. 6704 6705 \cs_new_protected:Npn \vbox_set_split_to_ht:NNn #1#2#3 { \tex_setbox:D #1 \tex_vsplit:D #2 to \__dim_eval:w #3 \__dim_eval_end: } (End definition for \vbox_set_split_to_ht:NNn.\vbox_unpack:N \vbox_unpack:c \vbox_unpack_clear:N \vbox_unpack_clear:c Unpacking a box and if requested also clear it.) \c__coffin_corners_prop The “corners”.) 14. of course.) \vbox_set_split_to_ht:NNn Splitting a vertical box in two. This function is documented on page 133. 6700 6701 6702 6703 \cs_new_eq:NN \vbox_unpack:N \tex_unvcopy:D \cs_new_eq:NN \vbox_unpack_clear:N \tex_unvbox:D \cs_generate_variant:Nn \vbox_unpack:N { c } \cs_generate_variant:Nn \vbox_unpack_clear:N { c } (End definition for \vbox_unpack:N and \vbox_unpack:c. They all start off in the same place. These functions are documented on page ??. of a coffin define the real content. This variable is documented on page ??. 6706 6707 6708 h*deprecatedi \cs_new_eq:NN \l_last_box \tex_lastbox:D h/deprecatedi (End definition for \l_last_box.11 \l_last_box Deprecated functions Deprecated 2011-11-13. 6717 6718 6719 \box_new:N \l__coffin_internal_box \dim_new:N \l__coffin_internal_dim \tl_new:N \l__coffin_internal_tl (End definition for \l__coffin_internal_box.1 \l__coffin_internal_box \l__coffin_internal_dim \l__coffin_internal_tl Coffins: data structures and general variables Scratch variables. for removal by 2012-02-28. vertical and reference-point based values. These values are corrected from those requested in an alignment for the positions of the handles. 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 \prop_new:N \c__coffin_poles_prop \tl_set:Nn \l__coffin_internal_tl { \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \tl_set:Nn \l__coffin_internal_tl { \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop \prop_put:Nno \c__coffin_poles_prop { { { { { { { { { { { 0 pt l } hc } r } 0 pt b } vc } t } B } H } T } } { { { } { { { { { { { 0 pt } { 0 pt } { 1000 pt } } \l__coffin_internal_tl } \l__coffin_internal_tl } \l__coffin_internal_tl } { 0 pt } { 1000 pt } { 0 pt } } \l__coffin_internal_tl } \l__coffin_internal_tl } \l__coffin_internal_tl } \l__coffin_internal_tl } \l__coffin_internal_tl } \l__coffin_internal_tl } (End definition for \c__coffin_poles_prop.) \c__coffin_poles_prop Pole positions are given for horizontal.) 413 .) \l__coffin_offset_x_dim \l__coffin_offset_y_dim The offset between two sets of coffin handles when typesetting. This function is documented on page ??. This function is documented on page ??. 6742 6743 \tl_new:N \l__coffin_pole_a_tl \tl_new:N \l__coffin_pole_b_tl (End definition for \l__coffin_pole_a_tl.) \l__coffin_error_bool For propagating errors so that parts of the code can work around them.) \l__coffin_slope_x_fp \l__coffin_slope_y_fp Used for calculations of intersections.) \l__coffin_pole_a_tl \l__coffin_pole_b_tl Needed for finding the intersection of two poles. This variable is documented on page ??.) \l__coffin_x_dim \l__coffin_y_dim \l__coffin_x_prime_dim \l__coffin_y_prime_dim For calculating intersections and so forth. This variable is documented on page ??. 6737 6738 \fp_new:N \l__coffin_slope_x_fp \fp_new:N \l__coffin_slope_y_fp (End definition for \l__coffin_slope_x_fp. This variable is documented on page ??. This function is documented on page ??. 6739 \bool_new:N \l__coffin_error_bool (End definition for \l__coffin_error_bool. 6740 6741 \dim_new:N \l__coffin_offset_x_dim \dim_new:N \l__coffin_offset_y_dim (End definition for \l__coffin_offset_x_dim.(End definition for \c__coffin_corners_prop. 6744 6745 6746 6747 \dim_new:N \dim_new:N \dim_new:N \dim_new:N \l__coffin_x_dim \l__coffin_y_dim \l__coffin_x_prime_dim \l__coffin_y_prime_dim (End definition for \l__coffin_x_dim. This function is documented on page ??. A cleaner way to handle this is provided here: both the box and the coffin structure are checked.) \coffin_clear:N \coffin_clear:c Clearing coffins means emptying the box and resetting all of the structures. So a wrapper is provided to deal with this correctly. TF } { \cs_if_exist:NTF #1 { \cs_if_exist:cTF { l__coffin_poles_ \__int_value:w #1 _prop } { \prg_return_true: } { \prg_return_false: } } { \prg_return_false: } } \cs_generate_variant:Nn \coffin_if_exist_p:N { c } \cs_generate_variant:Nn \coffin_if_exist:NT { c } \cs_generate_variant:Nn \coffin_if_exist:NF { c } \cs_generate_variant:Nn \coffin_if_exist:NTF { c } (End definition for \coffin_if_exist:N and \coffin_if_exist:c. 6762 6763 6764 6765 6766 6767 6768 6769 6770 \cs_new_protected:Npn \__coffin_if_exist:NT #1#2 { \coffin_if_exist:NTF #1 { #2 } { \__msg_kernel_error:nnx { kernel } { unknown-coffin } { \token_to_str:N #1 } } } (End definition for \__coffin_if_exist:NT. 6771 6772 6773 6774 6775 6776 6777 6778 6779 \cs_new_protected:Npn \coffin_clear:N #1 { \__coffin_if_exist:NT #1 { \box_clear:N #1 \__coffin_reset_structure:N #1 } } \cs_generate_variant:Nn \coffin_clear:N { c } 414 .15.2 Basic coffin functions There are a number of basic functions needed for creating coffins and placing material in them. F .) \__coffin_if_exist:NT Several of the higher-level coffin functions will give multiple errors if the coffin does not exist. T . 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 \prg_new_conditional:Npnn \coffin_if_exist:N #1 { p . This function is documented on page ??. \coffin_if_exist_p:N \coffin_if_exist_p:c \coffin_if_exist:NTF \coffin_if_exist:cTF Several of the higher-level coffin functions will give multiple errors if the coffin does not exist. This all relies on the following data structures. issuing an error on erroneous use. These functions are documented on page ??. These are created globally. used to do the measuring). the material is typeset with a given width..(End definition for \coffin_clear:N and \coffin_clear:c. No \color_ensure_current: here as that would add a whatsit to the start of the vertical box and mess up the location of the T pole (see TEX by Topic for discussion of the \vtop primitive. variables has to be broken. reset the structures then update the handle positions. This means that the usual rule about \l_. First.) \hcoffin_set:Nn \hcoffin_set:cn Horizontal coffins are relatively easy: set the appropriate box. 6808 6809 \cs_new_protected:Npn \vcoffin_set:Nnn #1#2#3 { 415 . These functions are documented on page ??. as there is a need to avoid any strange effects if the coffin is created inside a group. The default handles and poles are set as for a horizontal coffin. 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 \cs_new_protected:Npn \hcoffin_set:Nn #1#2 { \__coffin_if_exist:NT #1 { \hbox_set:Nn #1 { \color_group_begin: \color_ensure_current: #2 \color_group_end: } \__coffin_reset_structure:N #1 \__coffin_update_poles:N #1 \__coffin_update_corners:N #1 } } \cs_generate_variant:Nn \hcoffin_set:Nn { c } (End definition for \hcoffin_set:Nn and \hcoffin_set:cn. These functions are documented on page ??.) \vcoffin_set:Nnn \vcoffin_set:cnn Setting vertical coffins is more complex. before finding the top baseline using a temporary box.) \coffin_new:N \coffin_new:c Creating a new coffin means making the underlying box and adding the data structures. These functions are documented on page ??.. 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 \cs_new_protected:Npn \coffin_new:N #1 { \box_new:N #1 \prop_clear_new:c { l__coffin_corners_ \__int_value:w #1 _prop } \prop_clear_new:c { l__coffin_poles_ \__int_value:w #1 _prop } \prop_gset_eq:cN { l__coffin_corners_ \__int_value:w #1 _prop } \c__coffin_corners_prop \prop_gset_eq:cN { l__coffin_poles_ \__int_value:w #1 _prop } \c__coffin_poles_prop } \cs_generate_variant:Nn \coffin_new:N { c } (End definition for \coffin_new:N and \coffin_new:c. \box_ht:N \l__coffin_internal_box } } { 1000 pt } { 0 pt } } \box_clear:N \l__coffin_internal_box } } \cs_generate_variant:Nn \vcoffin_set:Nnn { c } (End definition for \vcoffin_set:Nnn and \vcoffin_set:cnn.6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 \__coffin_if_exist:NT #1 { \vbox_set:Nn #1 { \dim_set:Nn \tex_hsize:D {#2} h*packagei \dim_set_eq:NN \linewidth \tex_hsize:D \dim_set_eq:NN \columnwidth \tex_hsize:D h/packagei \color_group_begin: #3 \color_group_end: } \__coffin_reset_structure:N #1 \__coffin_update_poles:N #1 \__coffin_update_corners:N #1 \vbox_set_top:Nn \l__coffin_internal_box { \vbox_unpack:N #1 } \__coffin_set_pole:Nnx #1 { T } { { 0 pt } { \dim_eval:n { \box_ht:N #1 . These functions are documented on page ??.) \hcoffin_set:Nw \hcoffin_set:cw \hcoffin_set_end: These are the “begin”/“end” versions of the above: watch the grouping! 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 \cs_new_protected:Npn \hcoffin_set:Nw #1 { \__coffin_if_exist:NT #1 { \hbox_set:Nw #1 \color_group_begin: \color_ensure_current: \cs_set_protected_nopar:Npn \hcoffin_set_end: { \color_group_end: \hbox_set_end: \__coffin_reset_structure:N #1 \__coffin_update_poles:N #1 \__coffin_update_corners:N #1 } } } \cs_new_protected_nopar:Npn \hcoffin_set_end: { } \cs_generate_variant:Nn \hcoffin_set:Nw { c } 416 . ) \vcoffin_set:Nnw \vcoffin_set:cnw \vcoffin_set_end: The same for vertical coffins.\box_ht:N \l__coffin_internal_box } } { 1000 pt } { 0 pt } } \box_clear:N \l__coffin_internal_box } } } \cs_new_protected_nopar:Npn \vcoffin_set_end: { } \cs_generate_variant:Nn \vcoffin_set:Nnw { c } (End definition for \vcoffin_set:Nnw and \vcoffin_set:cnw. 6889 6890 6891 6892 6893 6894 6895 6896 \cs_new_protected:Npn \coffin_set_eq:NN #1#2 { \__coffin_if_exist:NT #1 { \box_set_eq:NN #1 #2 \__coffin_set_eq_structure:NN #1 #2 } } 417 .) \coffin_set_eq:NN \coffin_set_eq:Nc \coffin_set_eq:cN \coffin_set_eq:cc Setting two coffins equal is just a wrapper around other functions.(End definition for \hcoffin_set:Nw and \hcoffin_set:cw. These functions are documented on page 136. These functions are documented on page 136. 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 \cs_new_protected:Npn \vcoffin_set:Nnw #1#2 { \__coffin_if_exist:NT #1 { \vbox_set:Nw #1 \dim_set:Nn \tex_hsize:D {#2} h*packagei \dim_set_eq:NN \linewidth \tex_hsize:D \dim_set_eq:NN \columnwidth \tex_hsize:D h/packagei \color_group_begin: \color_ensure_current: \cs_set_protected:Npn \vcoffin_set_end: { \color_group_end: \vbox_set_end: \__coffin_reset_structure:N #1 \__coffin_update_poles:N #1 \__coffin_update_corners:N #1 \vbox_set_top:Nn \l__coffin_internal_box { \vbox_unpack:N #1 } \__coffin_set_pole:Nnx #1 { T } { { 0 pt } { \dim_eval:n { \box_ht:N #1 . 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 \cs_new_protected:Npn \__coffin_get_pole:NnN #1#2#3 { \prop_get:cnNF { l__coffin_poles_ \__int_value:w #1 _prop } {#2} #3 { \__msg_kernel_error:nnxx { kernel } { unknown-coffin-pole } {#2} { \token_to_str:N #1 } \tl_set:Nn #3 { { 0 pt } { 0 pt } { 0 pt } { 0 pt } } } } (End definition for \__coffin_get_pole:NnN. However.4 \__coffin_get_pole:NnN Coffins: handle and pole management A simple wrapper around the recovery of a coffin pole. 6904 6905 6906 6907 6908 6909 \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \coffin_dp:N \coffin_dp:c \coffin_ht:N \coffin_ht:c \coffin_wd:N \coffin_wd:c \box_dp:N \box_dp:c \box_ht:N \box_ht:c \box_wd:N \box_wd:c (End definition for \coffin_dp:N and others. These variables are documented on page 138.) \c_empty_coffin Special coffins: these cannot be set up earlier as they need \coffin_new:N.6897 \cs_generate_variant:Nn \coffin_set_eq:NN { c . 6902 6903 \coffin_new:N \l_tmpa_coffin \coffin_new:N \l_tmpb_coffin (End definition for \l_tmpa_coffin and \l_tmpb_coffin.) 418 . This function is documented on page ??. 6898 6899 6900 6901 \coffin_new:N \hbox_set:Nn \coffin_new:N \coffin_new:N \c_empty_coffin \c_empty_coffin { } \l__coffin_aligned_coffin \l__coffin_aligned_internal_coffin (End definition for \c_empty_coffin. The empty \l__coffin_aligned_coffin coffin is set as a box as the full coffin-setting system needs some material which is not \l__coffin_aligned_internal_coffin yet available. These functions are documented on page ??. This function is documented on page ??.) 15.) 15. with some error checking and recovery built-in. These functions are documented on page ??. cc } (End definition for \coffin_set_eq:NN and others. semantically a separate set of functions are required. Nc .3 \coffin_dp:N \coffin_dp:c \coffin_ht:N \coffin_ht:c \coffin_wd:N \coffin_wd:c Measuring coffins Coffins are just boxes when it comes to measurement.) \l_tmpa_coffin \l_tmpb_coffin The usual scratch space. The three-argument version is used internally to do a direct setting. \coffin_set_vertical_pole:cnn 6941 \cs_new_protected:Npn \coffin_set_horizontal_pole:Nnn #1#2#3 \__coffin_set_pole:Nnn 6942 { \__coffin_set_pole:Nnx 6943 \__coffin_if_exist:NT #1 6944 { 6945 \__coffin_set_pole:Nnx #1 {#2} 6946 { 6947 { 0 pt } { \dim_eval:n {#3} } 6948 { 1000 pt } { 0 pt } 6949 } 6950 } 6951 } 6952 \cs_new_protected:Npn \coffin_set_vertical_pole:Nnn #1#2#3 6953 { 6954 \__coffin_if_exist:NT #1 6955 { 6956 \__coffin_set_pole:Nnx #1 {#2} 6957 { 6958 { \dim_eval:n {#3} } { 0 pt } 419 . The idea \coffin_set_horizontal_pole:cnn here is to provide a reasonable interface to the system.) These \coffin_set_horizontal_pole:Nnn Setting the pole of a coffin at the user/designer level requires a bit more care. functions are documented on page ??. 6920 6921 6922 6923 6924 6925 6926 \cs_new_protected:Npn \__coffin_reset_structure:N #1 { \prop_set_eq:cN { l__coffin_corners_ \__int_value:w #1 _prop } \c__coffin_corners_prop \prop_set_eq:cN { l__coffin_poles_ \__int_value:w #1 _prop } \c__coffin_poles_prop } (End definition for \__coffin_reset_structure:N.\__coffin_reset_structure:N Resetting the structure is a simple copy job. then to do the setting with full \coffin_set_vertical_pole:Nnn expansion. This function is documented on page ??. \__coffin_gset_eq_structure:NN 6927 \cs_new_protected:Npn \__coffin_set_eq_structure:NN #1#2 6928 { 6929 \prop_set_eq:cc { l__coffin_corners_ \__int_value:w #1 _prop } 6930 { l__coffin_corners_ \__int_value:w #2 _prop } 6931 \prop_set_eq:cc { l__coffin_poles_ \__int_value:w #1 _prop } 6932 { l__coffin_poles_ \__int_value:w #2 _prop } 6933 } 6934 \cs_new_protected:Npn \__coffin_gset_eq_structure:NN #1#2 6935 { 6936 \prop_gset_eq:cc { l__coffin_corners_ \__int_value:w #1 _prop } 6937 { l__coffin_corners_ \__int_value:w #2 _prop } 6938 \prop_gset_eq:cc { l__coffin_poles_ \__int_value:w #1 _prop } 6939 { l__coffin_poles_ \__int_value:w #2 _prop } 6940 } (End definition for \__coffin_set_eq_structure:NN and \__coffin_gset_eq_structure:NN.) \__coffin_set_eq_structure:NN Setting coffin structures equal simply means copying the property list. and updates the poles to reflect the nature of size of the box. It also does not set poles which are relevant only to vertical coffins. These functions are documented on page ??.{ 0 pt } { 1000 pt } 6959 6960 6961 6962 6963 6964 6965 6966 6967 } } } \cs_new_protected:Npn \__coffin_set_pole:Nnn #1#2#3 { \prop_put:cnn { l__coffin_poles_ \__int_value:w #1 _prop } {#2} {#3} } \cs_generate_variant:Nn \coffin_set_horizontal_pole:Nnn { c } \cs_generate_variant:Nn \coffin_set_vertical_pole:Nnn { c } \cs_generate_variant:Nn \__coffin_set_pole:Nnn { Nnx } (End definition for \coffin_set_horizontal_pole:Nnn and \coffin_set_horizontal_pole:cnn.5 \box_wd:N #1 } } { 0 pt } { 0 pt } { 1000 pt } } \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { r } { { \dim_use:N \box_wd:N #1 } { 0 pt } { 0 pt } { 1000 pt } } \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { vc } { { 0 pt } { \dim_eval:n { ( \box_ht:N #1 . 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 \cs_new_protected:Npn \__coffin_update_corners:N #1 { \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { { { 0 pt } { \dim_use:N \box_ht:N #1 } } \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { { { \dim_use:N \box_wd:N #1 } { \dim_use:N \box_ht:N #1 } } \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { { { 0 pt } { \dim_eval:n { .\box_dp:N #1 ) / 2 } } { 1000 pt } { 0 pt } 420 .\box_dp:N #1 } } } \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } { { { \dim_use:N \box_wd:N #1 } { \dim_eval:n { . 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 \cs_new_protected:Npn \__coffin_update_poles:N #1 { \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { hc } { { \dim_eval:n { 0.) \__coffin_update_corners:N Updating the corners of a coffin is straight-forward as at this stage there can be no rotation.) \__coffin_update_poles:N This function is called when a coffin is set. Thus this function only alters poles where the default position is dependent on the size of the box.\box_dp:N #1 } tl } tr } bl } br } } } } (End definition for \__coffin_update_corners:N. So the corners of the content are just those of the underlying TEX box. This function is documented on page ??. ) 15.\box_dp:N #1 } } { 1000 pt } { 0 pt } } 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 } 7012 (End definition for \__coffin_update_poles:N. b. d. c0 and d0 will be zero and a special case is needed. 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 \cs_new_protected:Npn \__coffin_calculate_intersection:Nnn #1#2#3 { \__coffin_get_pole:NnN #1 {#2} \l__coffin_pole_a_tl \__coffin_get_pole:NnN #1 {#3} \l__coffin_pole_b_tl \bool_set_false:N \l__coffin_error_bool \exp_last_two_unbraced:Noo \__coffin_calculate_intersection:nnnnnnnn \l__coffin_pole_a_tl \l__coffin_pole_b_tl \bool_if:NT \l__coffin_error_bool { \__msg_kernel_error:nn { kernel } { no-pole-intersection } \dim_zero:N \l__coffin_x_dim \dim_zero:N \l__coffin_y_dim } } The two poles passed here each have four values (as dimensions). which are given by d/c and d0 /c0 .5 Coffins: calculation of pole intersections \__coffin_calculate_intersection:Nnn The lead off in finding intersections is to recover the two poles and then hand off to the \__coffin_calculate_intersection:nnnnnnnn auxiliary for the actual calculation. respectively. for which \__coffin_calculate_intersection_aux:nnnnnN an error trap is needed. In both cases a and b are the co-ordinates of a point on the pole and c and d define the direction of the pole. 7028 7029 7030 7031 \cs_new_protected:Npn \__coffin_calculate_intersection:nnnnnnnn #1#2#3#4#5#6#7#8 { \dim_compare:nNnTF {#3} = { \c_zero_dim } 421 . d) and (a0 . There may of course not be an intersection.} \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { t } { { 0 pt } { \dim_use:N \box_ht:N #1 } { 1000 pt } { 0 pt } } \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } { b } { { 0 pt } { \dim_eval:n { . c. (a. c0 . Finding the intersection depends on the directions of the poles. However. if one of the poles is either horizontal or vertical then one or more of c. b0 . These are arguments 1–4 and 5–8. d0 ). This function is documented on page ??. { 7036 \dim_compare:nNnTF {#8} = \c_zero_dim { \dim_set:Nn \l__coffin_y_dim {#6} } { \__coffin_calculate_intersection_aux:nnnnnN {#1} {#5} {#6} {#7} {#8} \l__coffin_y_dim } 7037 7038 7039 7040 7041 7042 } 7043 7044 } If the first pole is not vertical then it may be horizontal. 422 . There is then a test on the second pole: if it is also vertical then there is an error. which may be a special case. { 7054 \__coffin_calculate_intersection_aux:nnnnnN {#2} {#6} {#5} {#8} {#7} \l__coffin_x_dim 7055 7056 } 7057 } 7058 7059 } The first pole is neither horizontal nor vertical. the calculations are the same as above with the first and second poles interchanged. d0 y = 0 (x − a0 ) + b0 c with the x-component already known to be #1. then the procedure is essentially the same as that already done but with the x. If not. For those possibilities. 7045 7046 7047 7048 7049 7050 7051 7052 7053 { \dim_compare:nNnTF {#4} = \c_zero_dim { \dim_set:Nn \l__coffin_y_dim {#2} \dim_compare:nNnTF {#8} = { \c_zero_dim } { \bool_set_true:N \l__coffin_error_bool } { \dim_compare:nNnTF {#7} = \c_zero_dim { \dim_set:Nn \l__coffin_x_dim {#5} } The formula for the case where the second pole is neither horizontal nor vertical is x= c0 (y − b0 ) + a0 d0 which is again handled by the same auxiliary.and y-components interchanged. If so. in which case the y-component of the intersection will be b0 . So the x-component of the interaction will be at a. 7032 { \dim_set:Nn \l__coffin_x_dim {#1} \dim_compare:nNnTF {#7} = \c_zero_dim { \bool_set_true:N \l__coffin_error_bool } 7033 7034 7035 The second pole may still be horizontal. This still leaves the second pole. This calculation is done as a generalised auxiliary.The case where the first pole is vertical. ( \dim_to_fp:n {#5} * \l__coffin_slope_y_fp ) \dim_to_fp:n {#2} + \dim_to_fp:n {#6} ) / ( \l__coffin_slope_x_fp . 7074 7075 7076 7077 7078 7079 7080 7081 { \fp_set:Nn \l__coffin_slope_x_fp { \dim_to_fp:n {#4} / \dim_to_fp:n {#3} } \fp_set:Nn \l__coffin_slope_y_fp { \dim_to_fp:n {#8} / \dim_to_fp:n {#7} } \fp_compare:nNnTF \l__coffin_slope_x_fp = \l__coffin_slope_y_fp { \bool_set_true:N \l__coffin_error_bool } All of the tests pass.7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 { \dim_compare:nNnTF {#7} = \c_zero_dim { \dim_set:Nn \l__coffin_x_dim {#5} \__coffin_calculate_intersection_aux:nnnnnN {#5} {#1} {#2} {#3} {#4} \l__coffin_y_dim } { \dim_compare:nNnTF {#8} = \c_zero_dim { \dim_set:Nn \l__coffin_x_dim {#6} \__coffin_calculate_intersection_aux:nnnnnN {#6} {#2} {#1} {#4} {#3} \l__coffin_x_dim } If none of the special cases apply then there is still a need to check that there is a unique intersection between the two pole. The y-values is then worked out using the standard auxiliary starting from the x-position. 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 { \dim_set:Nn \l__coffin_x_dim { \fp_to_dim:n { ( \dim_to_fp:n {#1} * \l__coffin_slope_x_fp . There is quite a bit of shuffling from dimensions to floating points in order to do the work. so there is the full complexity of the calculation: x= a(d/c) − a0 (d0 /c0 ) − b + b0 (d/c) − (d0 /c0 ) and noting that the two ratios are already worked out from the test just performed.\l__coffin_slope_y_fp ) } } 423 . This is the case if they have different slopes. 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 \cs_new_protected:Npn \__coffin_calculate_intersection_aux:nnnnnN #1#2#3#4#5#6 { \dim_set:Nn #6 { \fp_to_dim:n { \dim_to_fp:n {#4} * ( \dim_to_fp:n {#1} . First. The formula here is #1 − #2 #6 = #4 · #3 #5 Thus #4 and #5 should be the directions of the pole while #2 and #3 are co-ordinates. 7123 7124 7125 7126 \hbox_set:Nn \l__coffin_aligned_coffin { \dim_compare:nNnT { \l__coffin_offset_x_dim } < \c_zero_dim { \tex_kern:D -\l__coffin_offset_x_dim } 424 . On the right side the first box might stick out. which is corrected using a kern. This function is documented on page ??. which will show up if it is wider than the sum of the x-offset and the width of the second box.\__coffin_calculate_intersection_aux:nnnnnN { \l__coffin_x_dim } {#5} {#6} {#8} {#7} \l__coffin_y_dim 7097 7098 7099 } 7100 } 7101 } 7102 } 7103 } 7104 } 7105 The formula for finding the intersection point is in most cases the same.6 \coffin_join:NnnNnnnn \coffin_join:cnnNnnnn \coffin_join:Nnncnnnn \coffin_join:cnncnnnn Aligning and typesetting of coffins This command joins two coffins.\dim_to_fp:n {#2} ) / \dim_to_fp:n {#5} + \dim_to_fp:n {#3} } } } (End definition for \__coffin_calculate_intersection:Nnn. using a horizontal and vertical pole from each coffin and making an offset between the two. the more basic alignment function is used to get things started. If the x-offset is negative then the reference point of the second box is to the left of that of the first.) 15. So a second kern may be needed. 7119 7120 7121 7122 \cs_new_protected:Npn \coffin_join:NnnNnnnn #1#2#3#4#5#6#7#8 { \__coffin_align:NnnNnnnnN #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l__coffin_aligned_coffin Correct the placement of the reference point. The result is stored as the as a third coffin. which will have all of its handles reset to standard values. \box_wd:N #1 + \box_wd:N #4 } \dim_compare:nNnT \l__coffin_internal_dim < \c_zero_dim { \tex_kern:D -\l__coffin_internal_dim } 7127 7128 7129 7130 7131 7132 } The coffin structure is reset. These functions are documented on page ??.\hbox_unpack:N \l__coffin_aligned_coffin \dim_set:Nn \l__coffin_internal_dim { \l__coffin_offset_x_dim . which requires that the appropriate offsets are applied. cnnc } (End definition for \coffin_join:NnnNnnnn and others. The function used when marking a position is hear also as it is similar but without the structure updates. 7133 7134 7135 7136 \__coffin_reset_structure:N \l__coffin_aligned_coffin \prop_clear:c { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _ prop } \__coffin_update_poles:N \l__coffin_aligned_coffin The structures of the parent coffins are now transferred to the new coffin. 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 \dim_compare:nNnTF \l__coffin_offset_x_dim < \c_zero_dim { \__coffin_offset_poles:Nnn #1 { -\l__coffin_offset_x_dim } { 0 pt } \__coffin_offset_poles:Nnn #4 { 0 pt } { \l__coffin_offset_y_dim } \__coffin_offset_corners:Nnn #1 { -\l__coffin_offset_x_dim } { 0 pt } \__coffin_offset_corners:Nnn #4 { 0 pt } { \l__coffin_offset_y_dim } } { \__coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt } \__coffin_offset_poles:Nnn #4 { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim } \__coffin_offset_corners:Nnn #1 { 0 pt } { 0 pt } \__coffin_offset_corners:Nnn #4 { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim } } \__coffin_update_vertical_poles:NNN #1 #4 \l__coffin_aligned_coffin \coffin_set_eq:NN #1 \l__coffin_aligned_coffin } \cs_generate_variant:Nn \coffin_join:NnnNnnnn { c . This means that the work here is rather simplified compared to the above code. Nnnc . That will then depend on whether any shift was needed. 7156 7157 7158 7159 7160 7161 7162 7163 \cs_new_protected:Npn \coffin_attach:NnnNnnnn #1#2#3#4#5#6#7#8 { \__coffin_align:NnnNnnnnN #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l__coffin_aligned_coffin \box_set_ht:Nn \l__coffin_aligned_coffin { \box_ht:N #1 } \box_set_dp:Nn \l__coffin_aligned_coffin { \box_dp:N #1 } \box_set_wd:Nn \l__coffin_aligned_coffin { \box_wd:N #1 } \__coffin_reset_structure:N \l__coffin_aligned_coffin 425 . as it simply uses the size of the first coffin for the new one.) \coffin_attach:NnnNnnnn \coffin_attach:cnnNnnnn \coffin_attach:Nnncnnnn \coffin_attach:cnncnnnn \coffin_attach_mark:NnnNnnnn A more simple version of the above. and the corners are cleared: only those from the two parent coffins are needed. as this allows the ‘primed’ storage area to be used for the second coffin. Nnnc .\l__coffin_y_prime_dim + #8 } \hbox_set:Nn \l__coffin_aligned_internal_coffin { \box_use:N #1 \tex_kern:D -\box_wd:N #1 \tex_kern:D \l__coffin_offset_x_dim \box_move_up:nn { \l__coffin_offset_y_dim } { \box_use:N #4 } } \coffin_set_eq:NN #9 \l__coffin_aligned_internal_coffin } (End definition for \__coffin_align:NnnNnnnnN. before using these to re-box the input coffins. The ‘real’ box offsets are then calculated. but the final result will depend on how the bounding box is being handled.) 426 . This function is documented on page ??.\l__coffin_x_prime_dim + #7 } \dim_set:Nn \l__coffin_offset_y_dim { \l__coffin_y_dim . The default poles are then set up.7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 \prop_set_eq:cc { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _prop } { l__coffin_corners_ \__int_value:w #1 _prop } \__coffin_update_poles:N \l__coffin_aligned_coffin \__coffin_offset_poles:Nnn #1 { 0 pt } { 0 pt } \__coffin_offset_poles:Nnn #4 { \l__coffin_offset_x_dim } { \l__coffin_offset_y_dim } \__coffin_update_vertical_poles:NNN #1 #4 \l__coffin_aligned_coffin \coffin_set_eq:NN #1 \l__coffin_aligned_coffin } \cs_new_protected:Npn \coffin_attach_mark:NnnNnnnn #1#2#3#4#5#6#7#8 { \__coffin_align:NnnNnnnnN #1 {#2} {#3} #4 {#5} {#6} {#7} {#8} \l__coffin_aligned_coffin \box_set_ht:Nn \l__coffin_aligned_coffin { \box_ht:N #1 } \box_set_dp:Nn \l__coffin_aligned_coffin { \box_dp:N #1 } \box_set_wd:Nn \l__coffin_aligned_coffin { \box_wd:N #1 } \box_set_eq:NN #1 \l__coffin_aligned_coffin } \cs_generate_variant:Nn \coffin_attach:NnnNnnnn { c . but performs no corrections on the resulting coffin poles. The process begins by finding the points of intersection for the poles for each of the input coffins. cnnc } (End definition for \coffin_attach:NnnNnnnn and others. These functions are documented on page ??.) \__coffin_align:NnnNnnnnN The internal function aligns the two coffins into a third one. 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 \cs_new_protected:Npn \__coffin_align:NnnNnnnnN #1#2#3#4#5#6#7#8#9 { \__coffin_calculate_intersection:Nnn #4 {#5} {#6} \dim_set:Nn \l__coffin_x_prime_dim { \l__coffin_x_dim } \dim_set:Nn \l__coffin_y_prime_dim { \l__coffin_y_dim } \__coffin_calculate_intersection:Nnn #1 {#2} {#3} \dim_set:Nn \l__coffin_offset_x_dim { \l__coffin_x_dim . Those for the first coffin are worked out after those for the second coffin. This function is documented on page ??.} { \tl_set:Nn \l__coffin_internal_tl { {#2} } } { \tl_set:Nn \l__coffin_internal_tl { { #1 . This is done by mapping to the property list of the source coffins. 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 \cs_new_protected:Npn \__coffin_offset_poles:Nnn #1#2#3 { \prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop } { \__coffin_offset_pole:Nnnnnnn #1 {##1} ##2 {#2} {#3} } } \cs_new_protected:Npn \__coffin_offset_pole:Nnnnnnn #1#2#3#4#5#6#7#8 { \dim_set:Nn \l__coffin_x_dim { #3 + #7 } \dim_set:Nn \l__coffin_y_dim { #4 + #8 } \tl_if_in:nnTF {#2} { .#2 } { { \dim_eval:n { #3 + #5 } } { \dim_eval:n { #4 + #6 } } } } (End definition for \__coffin_offset_corners:Nnn.#2 } } } \exp_last_unbraced:NNo \__coffin_set_pole:Nnx \l__coffin_aligned_coffin { \l__coffin_internal_tl } { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } {#5} {#6} } } (End definition for \__coffin_offset_poles:Nnn. except that there is no need to worry \__coffin_offset_corner:Nnnnn about naming: every corner can be saved here as order is unimportant. 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 \cs_new_protected:Npn \__coffin_offset_corners:Nnn #1#2#3 { \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_offset_corner:Nnnnn #1 {##1} ##2 {#2} {#3} } } \cs_new_protected:Npn \__coffin_offset_corner:Nnnnn #1#2#3#4#5#6 { \prop_put:cnx { l__coffin_corners_ \__int_value:w \l__coffin_aligned_coffin _prop } { #1 . The test for a .) 427 . and that multiple alignments do not result in a whole set of values. The pay off for this is that .should not be used in coffin pole or handle names. This function is documented on page ??.) \__coffin_offset_corners:Nnn Saving the offset corners of a coffin is very similar.\__coffin_offset_poles:Nnn Transferring structures from one coffin to another requires that the positions are updated \__coffin_offset_pole:Nnnnnnn by the offset between the two coffins. moving as appropriate and saving to the new coffin data structures.means that the structures from the parent coffins are uniquely labelled and do not depend on the order of alignment. These functions find the \__coffin_update_T:nnnnnnnnN larger absolute value for the poles. but this is of course only logical when the poles are \__coffin_update_B:nnnnnnnnN horizontal. As well as aligning to the empty coffin. 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 \cs_new_protected:Npn \__coffin_update_vertical_poles:NNN #1#2#3 { \__coffin_get_pole:NnN #3 { #1 -T } \l__coffin_pole_a_tl \__coffin_get_pole:NnN #3 { #2 -T } \l__coffin_pole_b_tl \exp_last_two_unbraced:Noo \__coffin_update_T:nnnnnnnnN \l__coffin_pole_a_tl \l__coffin_pole_b_tl #3 \__coffin_get_pole:NnN #3 { #1 -B } \l__coffin_pole_a_tl \__coffin_get_pole:NnN #3 { #2 -B } \l__coffin_pole_b_tl \exp_last_two_unbraced:Noo \__coffin_update_B:nnnnnnnnN \l__coffin_pole_a_tl \l__coffin_pole_b_tl #3 } \cs_new_protected:Npn \__coffin_update_T:nnnnnnnnN #1#2#3#4#5#6#7#8#9 { \dim_compare:nNnTF {#2} < {#6} { \__coffin_set_pole:Nnx #9 { T } { { 0 pt } {#6} { 1000 pt } { 0 pt } } } { \__coffin_set_pole:Nnx #9 { T } { { 0 pt } {#2} { 1000 pt } { 0 pt } } } } \cs_new_protected:Npn \__coffin_update_B:nnnnnnnnN #1#2#3#4#5#6#7#8#9 { \dim_compare:nNnTF {#2} < {#6} { \__coffin_set_pole:Nnx #9 { B } { { 0 pt } {#2} { 1000 pt } { 0 pt } } } { \__coffin_set_pole:Nnx #9 { B } { { 0 pt } {#6} { 1000 pt } { 0 pt } } } } (End definition for \__coffin_update_vertical_poles:NNN. 7272 7273 7274 7275 7276 7277 \cs_new_protected:Npn \coffin_typeset:Nnnnn #1#2#3#4#5 { \hbox_unpack:N \c_empty_box \__coffin_align:NnnNnnnnN \c_empty_coffin { H } { l } #1 {#2} {#3} {#4} {#5} \l__coffin_aligned_coffin \box_use:N \l__coffin_aligned_coffin 428 .\__coffin_update_vertical_poles:NNN The T and B poles will need to be recalculated after alignment. which is done using a coffin with no content at all.) \coffin_typeset:Nnnnn \coffin_typeset:cnnnn Typesetting a coffin means aligning it with the current position. if necessary. This function is documented on page ??. there is also a need to leave vertical mode. 7 Coffin diagnostics \l__coffin_display_coffin Used for printing coffins with data structures attached. \l__coffin_display_coord_coffin 7280 \coffin_new:N \l__coffin_display_coffin \l__coffin_display_pole_coffin 7281 \coffin_new:N \l__coffin_display_coord_coffin 7282 \coffin_new:N \l__coffin_display_pole_coffin (End definition for \l__coffin_display_coffin. which therefore acts as a scale-factor. These functions are documented on page ??. 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 \prop_new:N \l__coffin_display_handles_prop \prop_put:Nnn \l__coffin_display_handles_prop { { b } { r } { -1 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { b } { hc } { 0 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { b } { l } { 1 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { r } { -1 } { 0 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { hc } { 0 } { 0 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { l } { 1 } { 0 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { r } { -1 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { hc } { 0 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { l } { 1 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { r } { -1 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { hc } { 0 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { t } { l } { 1 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { r } { -1 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { hc } { 0 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { vc } { l } { 1 } { 1 } } \prop_put:Nnn \l__coffin_display_handles_prop { { b } { r } { -1 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop 429 { tl } { thc } { tr } { vcl } { vchc } { vcr } { bl } { bhc } { br } { Tl } { Thc } { Tr } { Hl } { Hhc } { Hr } { Bl } { Bhc } .7278 7279 } \cs_generate_variant:Nn \coffin_typeset:Nnnnn { c } (End definition for \coffin_typeset:Nnnnn and \coffin_typeset:cnnnn.) \l__coffin_display_handles_prop This property list is used to print coffin handles at suitable positions. The offsets are expressed as multiples of the basic offset value. This function is documented on page ??.) 15. The standard attachment function is used.) \l__coffin_display_font_tl Stores the settings used to print coffin data: this keeps things flexible. 7322 7323 \dim_new:N \l__coffin_display_x_dim \dim_new:N \l__coffin_display_y_dim (End definition for \l__coffin_display_x_dim. This is done by saving the intersection into two dedicated values. However. This variable is documented on page ??.) \l__coffin_display_offset_dim The standard offset for the label from the handle position when displaying handles. 7320 7321 \dim_new:N \l__coffin_display_offset_dim \dim_set:Nn \l__coffin_display_offset_dim { 2 pt } (End definition for \l__coffin_display_offset_dim. This function is documented on page ??. 7324 \prop_new:N \l__coffin_display_poles_prop (End definition for \l__coffin_display_poles_prop.7317 7318 7319 { { b } { hc } { 0 } { -1 } } \prop_put:Nnn \l__coffin_display_handles_prop { Br } { { b } { l } { 1 } { -1 } } (End definition for \l__coffin_display_handles_prop. there is a need to avoid repetition. This variable is documented on page ??. This variable is documented on page ??.) \l__coffin_display_poles_prop A property list for printing poles: various things need to be deleted from this to get a “nice” output. Contrast with the more optimised version for showing all handles which comes next. 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 \cs_new_protected:Npn \coffin_mark_handle:Nnnn #1#2#3#4 { \hcoffin_set:Nn \l__coffin_display_pole_coffin { h*initexi \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO h/initexi h*packagei \color {#4} \rule { 1 pt } { 1 pt } h/packagei } 430 . this is likely to be \__coffin_mark_handle_aux:nnnnNnn okay given the load expected. This variable is documented on page ??.) \coffin_mark_handle:Nnnn Marking a single handle is relatively easy. \coffin_mark_handle:cnnn meaning that there are two calculations for the location.) \l__coffin_display_x_dim \l__coffin_display_y_dim As the intersections of poles have to be calculated to find which ones to print. 7325 7326 7327 7328 7329 7330 7331 \tl_new:N \l__coffin_display_font_tl h*initexi \tl_set:Nn \l__coffin_display_font_tl { } % TODO h/initexi h*packagei \tl_set:Nn \l__coffin_display_font_tl { \sffamily \tiny } h/packagei (End definition for \l__coffin_display_font_tl. for which the H poles is used as \coffin_display_handles:cn the definitive version for the baseline and bottom. These functions are documented on page ??.7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 \coffin_attach_mark:NnnNnnnn #1 {#2} {#3} \l__coffin_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt } \hcoffin_set:Nn \l__coffin_display_coord_coffin { h*initexi % TODO h/initexi h*packagei \color {#4} h/packagei \l__coffin_display_font_tl ( \tl_to_str:n { #2 . Two loops are then used to find the \__coffin_display_handles_aux:nnnnnn combinations of handles for all of these poles. This is done such that poles are removed \__coffin_display_handles_aux:nnnn \__coffin_display_attach:Nnnnn 431 .) \coffin_display_handles:Nn Printing the poles starts by removing any duplicates. #3 } ) } \prop_get:NnN \l__coffin_display_handles_prop { #2 #3 } \l__coffin_internal_tl \quark_if_no_value:NTF \l__coffin_internal_tl { \prop_get:NnN \l__coffin_display_handles_prop { #3 #2 } \l__coffin_internal_tl \quark_if_no_value:NTF \l__coffin_internal_tl { \coffin_attach_mark:NnnNnnnn #1 {#2} {#3} \l__coffin_display_coord_coffin { l } { vc } { 1 pt } { 0 pt } } { \exp_last_unbraced:No \__coffin_mark_handle_aux:nnnnNnn \l__coffin_internal_tl #1 {#2} {#3} } } { \exp_last_unbraced:No \__coffin_mark_handle_aux:nnnnNnn \l__coffin_internal_tl #1 {#2} {#3} } } \cs_new_protected:Npn \__coffin_mark_handle_aux:nnnnNnn #1#2#3#4#5#6#7 { \coffin_attach_mark:NnnNnnnn #5 {#6} {#7} \l__coffin_display_coord_coffin {#1} {#2} { #3 \l__coffin_display_offset_dim } { #4 \l__coffin_display_offset_dim } } \cs_generate_variant:Nn \coffin_mark_handle:Nnnn { c } (End definition for \coffin_mark_handle:Nnnn and \coffin_mark_handle:cnnn. The successful values are stored and used to align the pole coffin with the main coffin for output. 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 \cs_new_protected:Npn \__coffin_display_handles_aux:nnnnnn #1#2#3#4#5#6 { \prop_map_inline:Nn \l__coffin_display_poles_prop { \bool_set_false:N \l__coffin_error_bool \__coffin_calculate_intersection:nnnnnnnn {#2} {#3} {#4} {#5} ##2 \bool_if:NF \l__coffin_error_bool { \dim_set:Nn \l__coffin_display_x_dim { \l__coffin_x_dim } \dim_set:Nn \l__coffin_display_y_dim { \l__coffin_y_dim } \__coffin_display_attach:Nnnnn \l__coffin_display_pole_coffin { hc } { vc } { 0 pt } { 0 pt } \hcoffin_set:Nn \l__coffin_display_coord_coffin { h*initexi 432 .during the loops to avoid duplication. 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 \cs_new_protected:Npn \coffin_display_handles:Nn #1#2 { \hcoffin_set:Nn \l__coffin_display_pole_coffin { h*initexi \hbox:n { \tex_vrule:D width 1 pt height 1 pt \scan_stop: } % TODO h/initexi h*packagei \color {#2} \rule { 1 pt } { 1 pt } h/packagei } \prop_set_eq:Nc \l__coffin_display_poles_prop { l__coffin_poles_ \__int_value:w #1 _prop } \__coffin_get_pole:NnN #1 { H } \l__coffin_pole_a_tl \__coffin_get_pole:NnN #1 { T } \l__coffin_pole_b_tl \tl_if_eq:NNT \l__coffin_pole_a_tl \l__coffin_pole_b_tl { \prop_remove:Nn \l__coffin_display_poles_prop { T } } \__coffin_get_pole:NnN #1 { B } \l__coffin_pole_b_tl \tl_if_eq:NNT \l__coffin_pole_a_tl \l__coffin_pole_b_tl { \prop_remove:Nn \l__coffin_display_poles_prop { B } } \coffin_set_eq:NN \l__coffin_display_coffin #1 \prop_map_inline:Nn \l__coffin_display_poles_prop { \prop_remove:Nn \l__coffin_display_poles_prop {##1} \__coffin_display_handles_aux:nnnnnn {##1} ##2 {#2} } \box_use:N \l__coffin_display_coffin } For each pole there is a check for an intersection. which here does not give an error if none is found. The positions are recovered from the preset list if available. As the intersection is already known and stored for the display coffin the code simply uses it directly.% TODO 7432 7433 7434 h/initexi h*packagei \color {#6} 7435 7436 h/packagei \l__coffin_display_font_tl ( \tl_to_str:n { #1 . 7473 7474 7475 7476 7477 \cs_new_protected:Npn \__coffin_display_attach:Nnnnn #1#2#3#4#5 { \__coffin_calculate_intersection:Nnn #1 {#2} {#3} \dim_set:Nn \l__coffin_x_prime_dim { \l__coffin_x_dim } \dim_set:Nn \l__coffin_y_prime_dim { \l__coffin_y_dim } 433 . ##1 } ) 7437 7438 } \prop_get:NnN \l__coffin_display_handles_prop { #1 ##1 } \l__coffin_internal_tl \quark_if_no_value:NTF \l__coffin_internal_tl { \prop_get:NnN \l__coffin_display_handles_prop { ##1 #1 } \l__coffin_internal_tl \quark_if_no_value:NTF \l__coffin_internal_tl { \__coffin_display_attach:Nnnnn \l__coffin_display_coord_coffin { l } { vc } { 1 pt } { 0 pt } } { \exp_last_unbraced:No \__coffin_display_handles_aux:nnnn \l__coffin_internal_tl } } { \exp_last_unbraced:No \__coffin_display_handles_aux:nnnn \l__coffin_internal_tl } 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 } 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 } } \cs_new_protected:Npn \__coffin_display_handles_aux:nnnn #1#2#3#4 { \__coffin_display_attach:Nnnnn \l__coffin_display_coord_coffin {#1} {#2} { #3 \l__coffin_display_offset_dim } { #4 \l__coffin_display_offset_dim } } \cs_generate_variant:Nn \coffin_display_handles:Nn { c } This is a dedicated version of \coffin_attach:NnnNnnnn with a hard-wired first coffin. with no calculation. 8 7510 7511 7512 7513 7514 7515 7516 Messages \__msg_kernel_new:nnnn { kernel } { no-pole-intersection } { No~intersection~between~coffin~poles. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~find~the~intersection~between~two~poles.) 15.) \coffin_show_structure:N \coffin_show_structure:c For showing the various internal structures attached to a coffin in a way that keeps things relatively readable.\l__coffin_y_prime_dim + #5 } \hbox_set:Nn \l__coffin_aligned_coffin { \box_use:N \l__coffin_display_coffin \tex_kern:D -\box_wd:N \l__coffin_display_coffin \tex_kern:D \l__coffin_offset_x_dim \box_move_up:nn { \l__coffin_offset_y_dim } { \box_use:N #1 } } \box_set_ht:Nn \l__coffin_aligned_coffin { \box_ht:N \l__coffin_display_coffin } \box_set_dp:Nn \l__coffin_aligned_coffin { \box_dp:N \l__coffin_display_coffin } \box_set_wd:Nn \l__coffin_aligned_coffin { \box_wd:N \l__coffin_display_coffin } \box_set_eq:NN \l__coffin_display_coffin \l__coffin_aligned_coffin 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 } 7496 (End definition for \coffin_display_handles:Nn and \coffin_display_handles:cn.~ but~they~do~not~have~a~unique~meeting~point:~ the~value~(0~pt.~0~pt)~will~be~used. 434 . These functions are documented on page ??. If there is no apparent structure then the code complains. These functions are documented on page ??.\dim_set:Nn \l__coffin_offset_x_dim { \l__coffin_display_x_dim . 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 \cs_new_protected:Npn \coffin_show_structure:N #1 { \__coffin_if_exist:NT #1 { \__msg_show_variable:Nnn #1 { coffins } { \prop_map_function:cN { l__coffin_poles_ \__int_value:w #1 _prop } \__msg_show_item_unbraced:nn } } } \cs_generate_variant:Nn \coffin_show_structure:N { c } (End definition for \coffin_show_structure:N and \coffin_show_structure:c.\l__coffin_x_prime_dim + #4 } \dim_set:Nn \l__coffin_offset_y_dim { \l__coffin_display_y_dim . which in horizontal mode does nothing.) \color_ensure_current: A driver-independent wrapper for setting the foreground color to the current color “now”. } \__msg_kernel_new:nnn { kernel } { show-coffins } { Size~of~coffin~\token_to_str:N #1 : \\ > ~ ht~=~\dim_use:N \box_ht:N #1 \\ > ~ dp~=~\dim_use:N \box_dp:N #1 \\ > ~ wd~=~\dim_use:N \box_wd:N #1 \\ Poles~of~coffin~\token_to_str:N #1 : } 7536 h/initex | packagei 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 16 7537 7538 7539 7540 7541 7542 \color_group_begin: \color_group_end: l3color Implementation h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei Grouping for color is almost the same as using the basic \group_begin: and \group_end: functions.7535 } \__msg_kernel_new:nnnn { kernel } { unknown-coffin } { Unknown~coffin~’#1’. 7543 7544 7545 7546 7547 7548 \cs_new_eq:NN \color_group_begin: \group_begin: \cs_new_protected_nopar:Npn \color_group_end: { \tex_par:D \group_end: } (End definition for \color_group_begin: and \color_group_end:. in vertical mode the end-of-group needs a \par.~ but~either~the~coffin~does~not~exist~or~the~pole~name~is~wrong. However. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~find~a~typesetting~pole~for~a~coffin. These functions are documented on page 139. } \__msg_kernel_new:nnnn { kernel } { unknown-coffin-pole } { Pole~’#1’~unknown~for~coffin~’#2’. } { The~coffin~’#1’~was~never~defined. 7549 7550 7551 7552 h*initexi \cs_new_protected_nopar:Npn \color_ensure_current: { \__driver_color_ensure_current: } h/initexi 435 . ) 436 . This variable is documented on page ??.In package mode. These variables are documented on page ??. as there is not actually a lot to do. 7577 7578 \tl_const:Nn \c__msg_text_prefix_tl { msg~text~>~ } \tl_const:Nn \c__msg_more_text_prefix_tl { msg~extra~text~>~ } (End definition for \c__msg_text_prefix_tl and \c__msg_more_text_prefix_tl. a mechanism for creating message text. This function is documented on page 139. the driver code may not be loaded. This is pretty simple. 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 h*packagei \cs_new_protected_nopar:Npn \color_ensure_current: { } \AtBeginDocument { \cs_if_exist:NTF \__driver_color_ensure_current: { \cs_set_protected_nopar:Npn \color_ensure_current: { \__driver_color_ensure_current: } } { \cs_if_exist:NT \set@color { \cs_set_protected_nopar:Npn \color_ensure_current: { \set@color } } } } h/packagei (End definition for \color_ensure_current:. so there two parts to the code here. First.1 Creating messages Messages are created and used separately. if there is no driver code available and no \set@color then color is not in use and this function can be a no-op. 7576 \tl_new:N \l__msg_internal_tl (End definition for \l__msg_internal_tl. \c__msg_text_prefix_tl \c__msg_more_text_prefix_tl Locations for the text of messages.) 17. To keep down dependencies.) 7568 h/initex | packagei l3msg implementation 17 7569 h*initex | packagei 7570 h@@=msgi 7571 7572 7573 7574 7575 \l__msg_internal_tl h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei A general scratch for the module. F .) \__chk_if_free_msg:nn This auxiliary is similar to \__chk_if_free_cs:N. T . TF } { \cs_if_exist:cTF { \c__msg_text_prefix_tl #1 / #2 } { \prg_return_true: } { \prg_return_false: } } (End definition for \msg_if_exist:nn. 7579 7580 7581 7582 7583 \prg_new_conditional:Npnn \msg_if_exist:nn #1#2 { p . 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 \cs_new_protected:Npn \__chk_if_free_msg:nn #1#2 { \msg_if_exist:nnT {#1} {#2} { \__msg_kernel_error:nnxx { kernel } { message-already-defined } {#1} {#2} } } h*packagei \tex_ifodd:D \l@expl@log@functions@bool \cs_gset_protected:Npn \__chk_if_free_msg:nn #1#2 { \msg_if_exist:nnT {#1} {#2} { \__msg_kernel_error:nnxx { kernel } { message-already-defined } {#1} {#2} } \iow_log:x { Defining~message~ #1 / #2 ~\msg_line_context: } } \fi: h/packagei (End definition for \__chk_if_free_msg:nn. 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 \cs_new_protected:Npn \msg_new:nnnn #1#2 { \__chk_if_free_msg:nn {#1} {#2} \msg_gset:nnnn {#1} {#2} } \cs_new_protected:Npn \msg_new:nnn #1#2#3 { \msg_new:nnnn {#1} {#2} {#3} { } } \cs_new_protected:Npn \msg_set:nnnn #1#2#3#4 { \cs_set:cpn { \c__msg_text_prefix_tl #1 / #2 } ##1##2##3##4 {#3} \cs_set:cpn { \c__msg_more_text_prefix_tl #1 / #2 } 437 . These functions are documented on page 141.) \msg_new:nnnn \msg_new:nnn \msg_gset:nnnn \msg_gset:nnn \msg_set:nnnn \msg_set:nnn Setting a message simply means saving the appropriate text into two functions. but the experimental l3trace module needs to disable this check when reloading a package with the extra tracing information. A sanity check first. It could be inlined in \msg_new:nnnn.\msg_if_exist_p:nn \msg_if_exist:nnTF Test whether the control sequence containing the message text exists or not. and is used when defining messages with \msg_new:nnnn. \\ \\ } \tl_const:Nn \c_msg_continue_text_tl { Type~<return>~to~continue } \tl_const:Nn \c_msg_critical_text_tl { Reading~the~current~file~will~stop } \tl_const:Nn \c_msg_fatal_text_tl { This~is~a~fatal~error:~LaTeX~will~abort } \tl_const:Nn \c_msg_help_text_tl { For~immediate~help~type~H~<return> } \tl_const:Nn \c_msg_no_info_text_tl { LaTeX~does~not~know~anything~more~about~this~error.~sorry.) 17.2 \c_msg_coding_error_text_tl \c_msg_continue_text_tl \c_msg_critical_text_tl \c_msg_fatal_text_tl \c_msg_help_text_tl \c_msg_no_info_text_tl \c_msg_on_line_text_tl \c_msg_return_text_tl \c_msg_trouble_text_tl Messages: support functions and text Simple pieces of text for messages. 438 . These functions are documented on page ??.7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 ##1##2##3##4 {#4} } \cs_new_protected:Npn \msg_set:nnn #1#2#3 { \msg_set:nnnn {#1} {#2} {#3} { } } \cs_new_protected:Npn \msg_gset:nnnn #1#2#3#4 { \cs_gset:cpn { \c__msg_text_prefix_tl #1 / #2 } ##1##2##3##4 {#3} \cs_gset:cpn { \c__msg_more_text_prefix_tl #1 / #2 } ##1##2##3##4 {#4} } \cs_new_protected:Npn \msg_gset:nnn #1#2#3 { \msg_gset:nnnn {#1} {#2} {#3} { } } (End definition for \msg_new:nnnn and \msg_new:nnn. \c_msg_return_text_tl } \tl_const:Nn \c_msg_on_line_text_tl { on~line } \tl_const:Nn \c_msg_return_text_tl { \\ \\ Try~typing~<return>~to~proceed.~type~X~<return>~to~quit. 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 \tl_const:Nn \c_msg_coding_error_text_tl { This~is~a~coding~error. \\ If~that~doesn’t~work. } \tl_const:Nn \c_msg_trouble_text_tl { \\ \\ More~errors~will~almost~certainly~follow: \\ the~LaTeX~run~should~be~aborted. 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 \cs_new_protected:Npn \msg_interrupt:nnn #1#2#3 { \tl_if_empty:nTF {#3} { \__msg_interrupt_wrap:nn { \\ \c_msg_no_info_text_tl } {#1 \\\\ #2 \\\\ \c_msg_continue_text_tl } } { \__msg_interrupt_wrap:nn { \\ #3 } {#1 \\\\ #2 \\\\ \c_msg_help_text_tl } } } (End definition for \msg_interrupt:nnn. unfortunately. then build a nice-looking error message with #2.) \msg_line_number: \msg_line_context: For writing the line number nicely. The auxiliary \__msg_interrupt_more_text:n receives its argument as a line-wrapped string. We feed the extra help text and the message itself to a wrapping auxiliary. 7681 7682 7683 7684 7685 7686 7687 \cs_new_protected:Npn \__msg_interrupt_wrap:nn #1#2 { \iow_wrap:nnnN {#1} { | ~ } { } \__msg_interrupt_more_text:n \iow_wrap:nnnN {#2} { ! ~ } { } \__msg_interrupt_text:n } \cs_new_protected:Npn \__msg_interrupt_more_text:n #1 { 439 .) 17.3 \msg_interrupt:nnn Showing messages: low level mechanism The low-level interruption macro is rather opaque. in this order because we must first setup TEX’s \errhelp register before issuing an \errmessage. Depending on the availability of more information there is a choice of how to set up the further help. \msg_line_context: was set up earlier. so this is not new. which is thus unaffected by expansion. These functions are documented on page 141. Everything is done using x-type expansion as the new line markers are different for the two type of text and need to be correctly set up.) \__msg_interrupt_wrap:nn \__msg_interrupt_more_text:n First setup TEX’s \errhelp register with the extra help #1.} 7661 (End definition for \c_msg_coding_error_text_tl and others. These variables are documented on page ??. 7662 7663 7664 7665 7666 7667 7668 \cs_new_nopar:Npn \msg_line_number: { \int_use:N \tex_inputlineno:D } \cs_gset_nopar:Npn \msg_line_context: { \c_msg_on_line_text_tl \c_space_tl \msg_line_number: } (End definition for \msg_line_number: and \msg_line_context:. This function is documented on page 145. ........ We use an active ! to call the \errmessage primitive......\exp_args:Nx \tex_errhelp:D { |’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ #1 \iow_newline: |............... Two trailing closing braces are turned into spaces to hide them as well.) \__msg_interrupt_text:n The business end of the process starts by producing some visual separation of the message from the main part of the log...... } } } \exp_after:wN \group_end: & } 440 ... and the end of the argument of the \errmessage..... and end its argument with \use_none:n {hdotsi} which fills the output with dots.............. This function is documented on page 145. } 7688 7689 7690 7691 7692 7693 7694 } (End definition for \__msg_interrupt_wrap:nn............. including the closing brace........ 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 \group_begin: \char_set_lccode:nn {‘\{} {‘\ } \char_set_lccode:nn {‘\}} {‘\ } \char_set_lccode:nn {‘\&} {‘\!} \char_set_catcode_active:N \& \tl_to_lowercase:n { \group_end: \cs_new_protected:Npn \__msg_interrupt_text:n #1 { \iow_term:x { \iow_newline: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \iow_newline: ! } \group_begin: \cs_set_protected_nopar:Npn & { \tex_errmessage:D { #1 \use_none:n { ................ The error message needs to be printed with everything made “invisible”: TEX’s own information involves the macro in which \errmessage is called... The group in which we alter the definition of the active ! is closed before producing the message: this ensures that tokens inserted by typing I in the command-line will bee inserted after the message is entirely cleaned up... ................) \msg_see_documentation_text:n Contextual footer information.......} 7726 (End definition for \__msg_interrupt_text:n............4 Displaying messages LATEX is handling error messages and so the TEX ones are disabled.. A bit of simple visual work sets things off nicely.....) \msg_log:n \msg_term:n Printing to the log or terminal without a stop is rather easier.... 7747 7748 7749 7750 7751 7752 \cs_new:Npn \msg_see_documentation_text:n #1 { \\ \\ See~the~ \str_if_eq:nnTF {#1} { LaTeX } { LaTeX3 } {#1} ~ documentation~for~further~information... The LATEX module only comprises LATEX3 code... This is already done by the LATEX 2ε kernel.. 7742 7743 7744 7745 7746 \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \msg_fatal_text:n #1 { Fatal~#1~error } \msg_critical_text:n #1 { Critical~#1~error } \msg_error_text:n #1 { #1~error } \msg_warning_text:n #1 { #1~warning } \msg_info_text:n #1 { #1~info } (End definition for \msg_fatal_text:n and others..... 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 \cs_new_protected:Npn \msg_log:n #1 { \iow_log:n { .. This function is documented on page 142..... These functions are documented on page 142.....) 17.... 7739 7740 7741 \msg_fatal_text:n \msg_critical_text:n \msg_error_text:n \msg_warning_text:n \msg_info_text:n h*initexi \int_gset_eq:NN \tex_errorcontextlines:D \c_minus_one h/initexi A function for issuing messages: both the text and order could in principle vary..... ~ } { } \iow_log:n \iow_log:n { ..) 441 ........... so we refer to the LATEX3 documentation rather than simply “LATEX”..... This function is documented on page 146. } (End definition for \msg_see_documentation_text:n........ } } \cs_new_protected:Npn \msg_term:n #1 { \iow_term:n { ************************************************* } \iow_wrap:nnnN { * ~ #1} { * ~ } { } \iow_term:n \iow_term:n { ************************************************* } } (End definition for \msg_log:n. ~ #1} { .... } \iow_wrap:nnnN { .... so to avoid messing up any deliberate change by a user this is only set in format mode... ) \msg_fatal:nnnnnn \msg_fatal:nnnnn \msg_fatal:nnnn \msg_fatal:nnn \msg_fatal:nn \msg_fatal:nnxxxx \msg_fatal:nnxxx \msg_fatal:nnxx \msg_fatal:nnx For fatal errors. 7791 7792 7793 7794 7795 7796 7797 \__msg_class_new:nn { fatal } { \msg_interrupt:nnn { \msg_fatal_text:n {#1} : ~ "#2" } { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} \msg_see_documentation_text:n {#1} 442 . after the error message TEX bails out. This function is documented on page ??.\__msg_class_new:nn 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 \group_begin: \cs_set_protected:Npn \__msg_class_new:nn #1#2 { \prop_new:c { l__msg_redirect_ #1 _prop } \cs_new_protected:cpn { __msg_ #1 _code:nnnnnn } ##1##2##3##4##5##6 {#2} \cs_new_protected:cpn { msg_ #1 :nnnnnn } ##1##2##3##4##5##6 { \use:x { \exp_not:n { \__msg_use:nnnnnnn {#1} {##1} {##2} } { \tl_to_str:n {##3} } { \tl_to_str:n {##4} } { \tl_to_str:n {##5} } { \tl_to_str:n {##6} } } } \cs_new_protected:cpx { msg_ #1 :nnnnn } ##1##2##3##4##5 { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} { } } \cs_new_protected:cpx { msg_ #1 :nnnn } ##1##2##3##4 { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { } } \cs_new_protected:cpx { msg_ #1 :nnn } ##1##2##3 { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} { } { } { } } \cs_new_protected:cpx { msg_ #1 :nn } ##1##2 { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} { } { } { } { } } \cs_new_protected:cpx { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 { \use:x { \exp_not:N \exp_not:n { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} } {##3} {##4} {##5} {##6} } } \cs_new_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } } \cs_new_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } } \cs_new_protected:cpx { msg_ #1 :nnx } ##1##2##3 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } } (End definition for \__msg_class_new:nn. These functions are documented on page ??.) \msg_error:nnnnnn \msg_error:nnnnn \msg_error:nnnn \msg_error:nnn \msg_error:nn \msg_error:nnxxxx \msg_error:nnxxx \msg_error:nnxx \msg_error:nnx \__msg_error:cnnnnn \__msg_no_more_text:nnnn For an error. We check if there is a “more text” by comparing that control sequence with a permanently empty text.) \msg_critical:nnnnnn \msg_critical:nnnnn \msg_critical:nnnn \msg_critical:nnn \msg_critical:nn \msg_critical:nnxxxx \msg_critical:nnxxx \msg_critical:nnxx \msg_critical:nnx Not quite so bad: just end the current file. 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 \__msg_class_new:nn { error } { \__msg_error:cnnnnn { \c__msg_more_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} { \msg_interrupt:nnn { \msg_error_text:n {#1} : ~ "#2" } { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} \msg_see_documentation_text:n {#1} } } } \cs_new_protected:Npn \__msg_error:cnnnnn #1#2#3#4#5#6 { \cs_if_eq:cNTF {#1} \__msg_no_more_text:nnnn { #6 { } } { #6 { \use:c {#1} {#2} {#3} {#4} {#5} } } } \cs_new:Npn \__msg_no_more_text:nnnn #1#2#3#4 { } (End definition for \msg_error:nnnnnn and others. These functions are documented on page ??.) \msg_warning:nnnnnn \msg_warning:nnnnn \msg_warning:nnnn \msg_warning:nnn \msg_warning:nn \msg_warning:nnxxxx \msg_warning:nnxxx \msg_warning:nnxx \msg_warning:nnx Warnings are printed to the terminal. These functions are documented on page ??. 7834 7835 7836 \__msg_class_new:nn { warning } { \msg_term:n 443 . 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 \__msg_class_new:nn { critical } { \msg_interrupt:nnn { \msg_critical_text:n {#1} : ~ "#2" } { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} \msg_see_documentation_text:n {#1} } { \c_msg_critical_text_tl } \tex_endinput:D } (End definition for \msg_critical:nnnnnn and others. the interrupt routine is called.} { \c_msg_fatal_text_tl } \tex_end:D 7798 7799 7800 7801 } (End definition for \msg_fatal:nnnnnn and others. These functions are documented on page ??. 7856 \__msg_class_new:nn { none } { } (End definition for \msg_none:nnnnnn and others. These functions are documented on page ??.) The none message type is needed so that input can be gobbled.{ 7837 \msg_warning_text:n {#1} : ~ "#2" \\ \\ \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} 7838 7839 } 7840 7841 } (End definition for \msg_warning:nnnnnn and others. but with no extras added. 7858 7859 7860 7861 7862 \cs_new:Npn \__msg_class_chk_exist:nT #1 { \cs_if_free:cTF { __msg_ #1 _code:nnnnnn } { \__msg_kernel_error:nnx { kernel } { message-class-unknown } {#1} } } (End definition for \__msg_class_chk_exist:nT. These functions are documented on page ??. These variables are documented on page ??. These functions are documented on page ??.) End the group to eliminate \__msg_class_new:nn.) \l__msg_class_tl \l__msg_current_class_tl Support variables needed for the redirection system.) “Log” data is very similar to information.) 444 . 7850 7851 7852 7853 7854 7855 \__msg_class_new:nn { log } { \iow_wrap:nnnN { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } { } { } \iow_log:n } (End definition for \msg_log:nnnnnn and others. 7857 \group_end: Checking that a message class exists.) \msg_info:nnnnnn \msg_info:nnnnn \msg_info:nnnn \msg_info:nnn \msg_info:nn \msg_info:nnxxxx \msg_info:nnxxx \msg_info:nnxx \msg_info:nnx \msg_log:nnnnnn \msg_log:nnnnn \msg_log:nnnn \msg_log:nnn \msg_log:nn \msg_log:nnxxxx \msg_log:nnxxx \msg_log:nnxx \msg_log:nnx \msg_none:nnnnnn \msg_none:nnnnn \msg_none:nnnn \msg_none:nnn \msg_none:nn \msg_none:nnxxxx \msg_none:nnxxx \__msg_class_chk_exist:nT \msg_none:nnxx \msg_none:nnx Information only goes into the log. We build this from \cs_if_free:cTF rather than \cs_if_exist:cTF because that avoids reading the second argument earlier than necessary. 7842 7843 7844 7845 7846 7847 7848 7849 \__msg_class_new:nn { info } { \msg_log:n { \msg_info_text:n {#1} : ~ "#2" \\ \\ \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } } (End definition for \msg_info:nnnnnn and others. 7863 7864 \tl_new:N \l__msg_class_tl \tl_new:N \l__msg_current_class_tl (End definition for \l__msg_class_tl and \l__msg_current_class_tl. This variable is documented on page ??. {/module}. 7889 7890 7891 \cs_new_protected:Npn \__msg_use_redirect_name:n #1 { \prop_get:NnNTF \l__msg_redirect_prop { / #1 } \l__msg_class_tl 445 . and store {/module/submodule}. {/module} and {} into \l__msg_hierarchy_seq. 7867 \seq_new:N \l__msg_class_loop_seq (End definition for \l__msg_class_loop_seq. This variable is documented on page ??. 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 \cs_new_protected:Npn \__msg_use:nnnnnnn #1#2#3#4#5#6#7 { \msg_if_exist:nnTF {#2} {#3} { \__msg_class_chk_exist:nT {#1} { \tl_set:Nn \l__msg_current_class_tl {#1} \cs_set_protected_nopar:Npx \__msg_use_code: { \exp_not:n { \use:c { __msg_ \l__msg_class_tl _code:nnnnnn } {#2} {#3} {#4} {#5} {#6} {#7} } } \__msg_use_redirect_name:n { #2 / #3 } } } { \__msg_kernel_error:nnxx { kernel } { message-unknown } {#2} {#3} } } \cs_new_protected_nopar:Npn \__msg_use_code: { } The first check is for a individual message redirection. The message is eventually produced with whatever \l__msg_class_tl is when \__msg_use_code: is called. split the message name into module/submodule/message (with an arbitrary number of slashes). The assignment to \__msg_use_code: is similar to \tl_set:Nn.) \l__msg_class_loop_seq Classes encountered when following redirections to check for loops. applying the most specific redirection. 7866 \seq_new:N \l__msg_hierarchy_seq (End definition for \l__msg_hierarchy_seq. We will then map through this sequence. First. If this applies then no further redirection is attempted. and {}. some safety checks on the message and class requested. split the message name into a sequence with items {/module/submodule}.) \l__msg_hierarchy_seq During redirection. This variable is documented on page ??. The code and arguments are then stored to avoid passing them around.) \__msg_use:nnnnnnn \__msg_use_redirect_name:n \__msg_use_hierarchy:nwwN \__msg_use_redirect_module:n \__msg_use_code: Actually using a message is a multi-step process.\l__msg_redirect_prop For redirection of individually-named messages 7865 \prop_new:N \l__msg_redirect_prop (End definition for \l__msg_redirect_prop. Otherwise. When a redirection is found. Loop through the sequence to find the most specific redirection. with module ##1. the items of \l__msg_hierarchy_seq are the various levels at which we should look for a redirection. /module for a module redirection. 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 \cs_new_protected:Npn \__msg_use_redirect_module:n #1 { \seq_map_inline:Nn \l__msg_hierarchy_seq { \prop_get:cnNTF { l__msg_redirect_ \l__msg_current_class_tl _prop } {##1} \l__msg_class_tl { \seq_map_break:n { \tl_if_eq:NNTF \l__msg_current_class_tl \l__msg_class_tl { \__msg_use_code: } { \tl_set_eq:NN \l__msg_current_class_tl \l__msg_class_tl \__msg_use_redirect_module:n {##1} } } } { \str_if_eq:nnT {##1} {#1} { \tl_set_eq:NN \l__msg_class_tl \l__msg_current_class_tl \seq_map_break:n { \__msg_use_code: } } 446 . The loop is interrupted after testing for a redirection for ##1 equal to the argument #1 (least specific redirection allowed). and search for further redirections. then if the redirection targets the same class. and otherwise set the target as the new current class. This argument is empty for a class redirection. Redirections which are less specific than the argument of \__msg_use_redirect_module:n are not attempted. break the mapping.7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 { \__msg_use_code: } { \seq_clear:N \l__msg_hierarchy_seq \__msg_use_hierarchy:nwwN { } #1 \q_mark \__msg_use_hierarchy:nwwN / \q_mark \use_none_delimit_by_q_stop:w \q_stop \__msg_use_redirect_module:n { } } } \cs_new_protected:Npn \__msg_use_hierarchy:nwwN #1#2 / #3 \q_mark #4 { \seq_put_left:Nn \l__msg_hierarchy_seq {#1} #4 { #1 / #2 } #3 \q_mark #4 } At this point. Those redirections should be at least as specific as ##1. etc. output the code with that class. 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 \cs_new_protected_nopar:Npn \msg_redirect_class:nn { \__msg_redirect:nnn { } } \cs_new_protected:Npn \msg_redirect_module:nnn #1 { \__msg_redirect:nnn { / #1 } } \cs_new_protected:Npn \__msg_redirect:nnn #1#2#3 { \__msg_class_chk_exist:nT {#2} { \tl_if_empty:nTF {#3} { \prop_remove:cn { l__msg_redirect_ #2 _prop } {#1} } { \__msg_class_chk_exist:nT {#3} { \prop_put:cnn { l__msg_redirect_ #2 _prop } {#1} {#3} \tl_set:Nn \l__msg_current_class_tl {#2} \seq_clear:N \l__msg_class_loop_seq \__msg_redirect_loop_chk:nnn {#2} {#3} {#1} } } } } Since multiple redirections can only happen with increasing specificity. We must then check for a loop: as an initialization. This function is documented on page 145. This function is documented on page ??. and keep track in \l__msg_class_loop_seq of the various classes encountered. A redirection to the 447 . or the absence of redirection both mean that there is no loop.) \msg_redirect_class:nn \msg_redirect_module:nnn \__msg_redirect:nnn \__msg_redirect_loop_chk:nnn \__msg_redirect_loop_list:n If the target class is empty. and not submodules. #1. eliminate the corresponding redirection. Otherwise. The new redirection can thus only create a loop with other redirections for the exact same module. we start by storing the initial class in \l__msg_current_class_tl. follow redirections with \l__msg_class_tl.) \msg_redirect_name:nnn Named message will always use the given class even if that class is redirected further. add the redirection. a loop requires that all steps are of the same specificity. An empty target class cancels any existing redirection for that message. A redirection from a class to itself. 7933 7934 7935 7936 7937 7938 7939 7940 7941 \cs_new_protected:Npn \msg_redirect_name:nnn #1#2#3 { \tl_if_empty:nTF {#3} { \prop_remove:Nn \l__msg_redirect_prop { / #1 / #2 } } { \__msg_class_chk_exist:nT {#3} { \prop_put:Nnn \l__msg_redirect_prop { / #1 / #2 } {#3} } } } (End definition for \msg_redirect_name:nnn. After some initialization above.} 7930 } 7931 7932 } (End definition for \__msg_use:nnnnnnn. 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 \cs_new_protected:Npn \__msg_redirect_loop_chk:nnn #1#2#3 { \seq_put_right:Nn \l__msg_class_loop_seq {#1} \prop_get:cnNT { l__msg_redirect_ #1 _prop } {#3} \l__msg_class_tl { \str_if_eq_x:nnF { \l__msg_class_tl } {#1} { \tl_if_eq:NNTF \l__msg_class_tl \l__msg_current_class_tl { \prop_put:cnn { l__msg_redirect_ #2 _prop } {#3} {#2} \__msg_kernel_warning:nnxxxx { kernel } { message-redirect-loop } { \seq_item:Nn \l__msg_class_loop_seq { \c_one } } { \seq_item:Nn \l__msg_class_loop_seq { \c_two } } {#3} { \seq_map_function:NN \l__msg_class_loop_seq \__msg_redirect_loop_list:n { \seq_item:Nn \l__msg_class_loop_seq { \c_one } } } } { \__msg_redirect_loop_chk:onn \l__msg_class_tl {#2} {#3} } } } } \cs_generate_variant:Nn \__msg_redirect_loop_chk:nnn { o } \cs_new:Npn \__msg_redirect_loop_list:n #1 { {#1} ~ => ~ } (End definition for \msg_redirect_class:nn and \msg_redirect_module:nnn. Two functions are provided: one more general and one which only has the short text part. These are created using pre-built functions.5 \__msg_kernel_new:nnnn \__msg_kernel_new:nnn \__msg_kernel_set:nnnn \__msg_kernel_set:nnn Kernel-specific functions The kernel needs some messages of its own. we must decide which redirection to cancel. We thus remove the redirection starting from #2. target of the new redirection. To break it. The user most likely wants the newly added redirection to hold with no further redirection. Note that no message is emitted by any of the underlying functions: otherwise we may get an infinite loop because of a message from the message system itself.) 17. These functions are documented on page 145.) 448 .initial class marks a loop. These functions are documented on page ??. 7989 7990 7991 7992 7993 7994 7995 7996 \cs_new_protected:Npn \__msg_kernel_new:nnnn #1#2 { \msg_new:nnnn { LaTeX } { #1 / #2 } } \cs_new_protected:Npn \__msg_kernel_new:nnn #1#2 { \msg_new:nnn { LaTeX } { #1 / #2 } } \cs_new_protected:Npn \__msg_kernel_set:nnnn #1#2 { \msg_set:nnnn { LaTeX } { #1 / #2 } } \cs_new_protected:Npn \__msg_kernel_set:nnn #1#2 { \msg_set:nnn { LaTeX } { #1 / #2 } } (End definition for \__msg_kernel_new:nnnn and \__msg_kernel_new:nnn. 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 \group_begin: \cs_set_protected:Npn \__msg_kernel_class_new:nN #1 { \__msg_kernel_class_new_aux:nN { kernel_ #1 } } \cs_set_protected:Npn \__msg_kernel_class_new_aux:nN #1#2 { \cs_new_protected:cpn { __msg_ #1 :nnnnnn } ##1##2##3##4##5##6 { \use:x { \exp_not:n { #2 { LaTeX } { ##1 / ##2 } } { \tl_to_str:n {##3} } { \tl_to_str:n {##4} } { \tl_to_str:n {##5} } { \tl_to_str:n {##6} } } } \cs_new_protected:cpx { __msg_ #1 :nnnnn } ##1##2##3##4##5 { \exp_not:c { __msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} \cs_new_protected:cpx { __msg_ #1 :nnnn } ##1##2##3##4 { \exp_not:c { __msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { \cs_new_protected:cpx { __msg_ #1 :nnn } ##1##2##3 { \exp_not:c { __msg_ #1 :nnnnnn } {##1} {##2} {##3} { } { } { } \cs_new_protected:cpx { __msg_ #1 :nn } ##1##2 { \exp_not:c { __msg_ #1 :nnnnnn } {##1} {##2} { } { } { } { } } \cs_new_protected:cpx { __msg_ #1 :nnxxxx } ##1##2##3##4##5##6 { \use:x { \exp_not:N \exp_not:n { \exp_not:c { __msg_ #1 :nnnnnn } {##1} {##2} } {##3} {##4} {##5} {##6} } } \cs_new_protected:cpx { __msg_ #1 :nnxxx } ##1##2##3##4##5 { \exp_not:c { __msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} \cs_new_protected:cpx { __msg_ #1 :nnxx } ##1##2##3##4 { \exp_not:c { __msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { \cs_new_protected:cpx { __msg_ #1 :nnx } ##1##2##3 { \exp_not:c { __msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } } { } } } } } { } } } } } (End definition for \__msg_kernel_class_new:nN.\__msg_kernel_class_new:nN All the functions for kernel messages come in variants ranging from 0 to 4 arguments. in a way very similar to \__msg_class_new:nn. Three functions are already defined by l3basics. We directly use the code for (non-kernel) fatal errors and errors.) \__msg_kernel_fatal:nnnnnn \__msg_kernel_fatal:nnnnn \__msg_kernel_fatal:nnnn \__msg_kernel_fatal:nnn \__msg_kernel_fatal:nn \__msg_kernel_fatal:nnxxxx \__msg_kernel_fatal:nnxxx \__msg_kernel_fatal:nnxx \__msg_kernel_fatal:nnx \__msg_kernel_error:nnnnnn \__msg_kernel_error:nnnnn \__msg_kernel_error:nnnn \__msg_kernel_error:nnn \__msg_kernel_error:nn \__msg_kernel_error:nnxxxx Neither fatal kernel errors nor kernel errors can be redirected. 8035 8036 \__msg_kernel_class_new:nN { fatal } \__msg_fatal_code:nnnnnn \cs_undefine:N \__msg_kernel_error:nnxx 449 . \__msg_kernel_class_new_aux:nN Those with less than 4 arguments are defined in terms of the 4-argument variant. adding the “LATEX” module name. This function is documented on page ??. we need to undefine them to avoid errors. This auxiliary is destroyed at the end of the group. These functions are documented on page ??. 8042 \group_end: Error messages needed to actually implement the message system itself. 8040 8041 \__msg_kernel_class_new:nN { warning } \msg_warning:nnxxxx \__msg_kernel_class_new:nN { info } \msg_info:nnxxxx (End definition for \__msg_kernel_warning:nnnnnn and others.) End the group to eliminate \__msg_kernel_class_new:nN.) \__msg_kernel_warning:nnnnnn \__msg_kernel_warning:nnnnn \__msg_kernel_warning:nnnn \__msg_kernel_warning:nnn \__msg_kernel_warning:nn \__msg_kernel_warning:nnxxxx \__msg_kernel_warning:nnxxx \__msg_kernel_warning:nnxx \__msg_kernel_warning:nnx \__msg_kernel_info:nnnnnn \__msg_kernel_info:nnnnn \__msg_kernel_info:nnnn \__msg_kernel_info:nnn \__msg_kernel_info:nn \__msg_kernel_info:nnxxxx \__msg_kernel_info:nnxxx \__msg_kernel_info:nnxx \__msg_kernel_info:nnx Kernel messages which can be redirected simply use the machinery for normal messages.8037 8038 8039 \cs_undefine:N \__msg_kernel_error:nnx \cs_undefine:N \__msg_kernel_error:nn \__msg_kernel_class_new:nN { error } \__msg_error_code:nnnnnn (End definition for \__msg_kernel_fatal:nnnnnn and others. } { Adding~the~message~redirection~ {#1} ~=>~ {#2} \tl_if_empty:nF {#3} { ~for~the~module~’ \use_none:n #3 ’ } ~ created~an~infinite~loop\\\\ \iow_indent:n { #4 \\\\ } } 450 . } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~display~a~message~called~’#2’\\ by~the~module~’#1’:~this~message~does~not~exist. } { LaTeX~has~been~asked~to~redirect~messages~to~a~class~’#1’:\\ this~was~never~defined. 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 \__msg_kernel_new:nnnn { kernel } { message-already-defined } { Message~’#2’~for~module~’#1’~already~defined. \c_msg_return_text_tl } \__msg_kernel_new:nnnn { kernel } { message-redirect-loop } { Message~redirection~loop~caused~by~ {#1} ~=>~ {#2} \tl_if_empty:nF {#3} { ~for~module~’ \use_none:n #3 ’ } . \c_msg_return_text_tl } \__msg_kernel_new:nnnn { kernel } { message-class-unknown } { Unknown~message~class~’#1’. These functions are documented on page ??. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~define~a~new~message~called~’#2’\ by~the~module~’#1’:~this~message~already~exists. with the module name “LATEX”. \c_msg_return_text_tl } \__msg_kernel_new:nnnn { kernel } { message-unknown } { Unknown~message~’#2’~for~module~’#1’. } \__msg_kernel_new:nnnn { kernel } { command-already-defined } { Control~sequence~#1~already~defined.~but~this~has~not~ been~defined~yet.~or~when~building~a~ parameter~text~from~the~number~of~arguments~of~the~function.~ TeX~allows~between~0~and~9~arguments~for~a~single~function. } { \c_msg_coding_error_text_tl Code-level~functions~must~contain~’:’~to~separate~the~ argument~specification~from~the~function~name.~ This~run~will~be~aborted~now. } \__msg_kernel_new:nnnn { kernel } { protected-predicate } 451 . } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~use~a~command~#1. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~replace~an~empty~pattern~by~’#1’:~that~ would~lead~to~an~infinite~loop! } \__msg_kernel_new:nnnn { kernel } { out-of-registers } { No~room~for~a~new~#1. } \__msg_kernel_new:nnnn { kernel } { empty-search-pattern } { Empty~search~pattern. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~create~a~new~control~sequence~’#1’~ but~this~name~has~already~been~used~elsewhere.Messages for earlier kernel modules. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~define~a~function~’#1’~with~ #2~arguments.~This~is~ needed~when~defining~conditionals~or~variants.~All~the~#1~registers~have~been~used. } { TeX~only~supports~\int_use:N \c_max_register_int \ of~each~type. } \__msg_kernel_new:nnnn { kernel } { missing-colon } { Function~’#1’~contains~no~’:’. \\ \\ The~current~meaning~is:\\ \ \ #2 } \__msg_kernel_new:nnnn { kernel } { command-not-defined } { Control~sequence~#1~undefined. 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 \__msg_kernel_new:nnnn { kernel } { bad-number-of-arguments } { Function~’#1’~cannot~be~defined~with~#2~arguments. ~but~this~has~not~ been~defined~yet.8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 { Predicate~’#1’~must~be~expandable.~but~cannot~change~an~argument~ from~type~’#3’~to~type~’#4’. } 452 . } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~define~the~conditional~form~’#1’~of~ the~function~’#2’. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~define~’#1’~as~a~protected~predicate. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~create~a~variant~of~the~function~’#2’~ with~a~signature~starting~with~’#1’. } \__msg_kernel_new:nnnn { kernel } { conditional-form-unknown } { Conditional~form~’#1’~for~function~’#2’~unknown.~but~that~is~longer~than~ the~signature~(part~after~the~colon)~of~’#2’.~’F’. hence don’t need a “more-text” argument. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~create~a~variant~of~the~function~’#2’~ with~a~signature~starting~with~’#1’. } \__msg_kernel_new:nnnn { kernel } { variant-too-long } { Variant~form~’#1’~longer~than~base~signature~of~’#2’. } \__msg_kernel_new:nnnn { kernel } { scanmark-already-defined } { Scan~mark~#1~already~defined.~but~only~’TF’.~ Only~expandable~tests~can~have~a~predicate~version. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~show~a~variable~#1. } Some errors only appear in expandable settings. 8168 8169 8170 8171 \__msg_kernel_new:nnn { kernel } { bad-variable } { Erroneous~variable~#1 used! } \__msg_kernel_new:nnn { kernel } { misused-sequence } { A~sequence~was~misused.~’T’.~and~’p’~forms~exist. } \__msg_kernel_new:nnnn { kernel } { invalid-variant } { Variant~form~’#1’~invalid~for~base~form~’#2’. } \__msg_kernel_new:nnnn { kernel } { variable-not-defined } { Variable~#1~undefined. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~create~a~new~scan~mark~’#1’~ but~this~name~has~already~been~used~for~a~scan~mark. ~>. } Messages used by the “show” functions. The \c_zero prevents losing braces around the user-inserted text if any. Thus we also use an odd space character (with category code 7) and keep tokens until that space character. In fact. and stops the expansion of \romannumeral. there is an extra subtlety: if the user inserts tokens for error recovery. dropping everything else until \q_stop.~>=. 453 .~==. and shows the context.6 \__msg_expandable_error:n \__msg_expandable_error:w Expandable errors In expansion only context. we cannot use the normal means of reporting errors. In other words. they should be kept. which thanks to the odd-looking \use:n is <argument> \LaTeX3 error: The error message.~!=. 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 \__msg_kernel_new:nnn { kernel } { show-clist } { The~comma~list~ \str_if_eq:nnF {#1} { \l__clist_internal_clist } { \token_to_str:N #1~} \clist_if_empty:NTF #1 { is~empty } { contains~the~items~(without~outer~braces): } } \__msg_kernel_new:nnn { kernel } { show-prop } { The~property~list~\token_to_str:N #1~ \prop_if_empty:NTF #1 { is~empty } { contains~the~pairs~(without~outer~braces): } } \__msg_kernel_new:nnn { kernel } { show-seq } { The~sequence~\token_to_str:N #1~ \seq_if_empty:NTF #1 { is~empty } { contains~the~items~(without~outer~braces): } } \__msg_kernel_new:nnn { kernel } { show-no-stream } { No~ #1 ~streams~are~open } \__msg_kernel_new:nnn { kernel } { show-open-streams } { The~following~ #1 ~streams~are~in~use: } 17. TEX is processing the argument of \use:n. Then \__msg_expandable_error:w cleans up. It is thus interrupted. Instead. which is \LaTeX3 error: herror messagei. } \__msg_kernel_new:nnn { kernel } { unknown-comparison } { Relation~symbol~’#1’~unknown:~use~=. } \__msg_kernel_new:nnn { kernel } { zero-step } { Zero~step~size~for~step~function~#1. we feed TEX an undefined control sequence.~<=. \LaTeX3 error:.8172 8173 8174 8175 8176 8177 \__msg_kernel_new:nnn { kernel } { negative-replication } { Negative~argument~for~\prg_replicate:nn.~<. \__msg_kernel_expandable_error:nnnn 8227 \cs_new:Npn \__msg_kernel_expandable_error:nnnnnn #1#2#3#4#5#6 \__msg_kernel_expandable_error:nnn 8228 { \__msg_kernel_expandable_error:nn 8229 \exp_args:Nf \__msg_expandable_error:n 8230 { 8231 \exp_args:NNc \exp_after:wN \exp_stop_f: 8232 { \c__msg_text_prefix_tl LaTeX / #1 / #2 } 8233 {#3} {#4} {#5} {#6} 8234 } 8235 } 8236 \cs_new:Npn \__msg_kernel_expandable_error:nnnnn #1#2#3#4#5 8237 { 8238 \__msg_kernel_expandable_error:nnnnnn 8239 {#1} {#2} {#3} {#4} {#5} { } 8240 } 8241 \cs_new:Npn \__msg_kernel_expandable_error:nnnn #1#2#3#4 8242 { 8243 \__msg_kernel_expandable_error:nnnnnn 8244 {#1} {#2} {#3} {#4} { } { } 8245 } 8246 \cs_new:Npn \__msg_kernel_expandable_error:nnn #1#2#3 8247 { 8248 \__msg_kernel_expandable_error:nnnnnn 454 .) \__msg_kernel_expandable_error:nnnnnn The command built from the csname \c_@@_text_prefix_tl LaTeX / #1 / #2 takes \__msg_kernel_expandable_error:nnnnn four arguments and builds the error text. This function is documented on page 148. which is fed to \__msg_expandable_error:n.8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 \group_begin: \char_set_catcode_math_superscript:N \^ \char_set_lccode:nn { ‘^ } { ‘\ } \char_set_lccode:nn { ‘L } { ‘L } \char_set_lccode:nn { ‘T } { ‘T } \char_set_lccode:nn { ‘X } { ‘X } \tl_to_lowercase:n { \cs_new:Npx \__msg_expandable_error:n #1 { \exp_not:n { \tex_romannumeral:D \exp_after:wN \exp_after:wN \exp_after:wN \__msg_expandable_error:w \exp_after:wN \exp_after:wN \exp_after:wN \c_zero } \exp_not:N \use:n { \exp_not:c { LaTeX3~error: } ^ #1 } ^ } \cs_new:Npn \__msg_expandable_error:w #1 ^ #2 ^ { #1 } } \group_end: (End definition for \__msg_expandable_error:n. These functions are documented on page ??. and the space would then disappear. as well as a space following it (via f-expansion). l3file. Note that we cannot remove the space as a delimiter for the w-type auxiliary. the resulting token list 455 .7 Showing variables Functions defined in this section are used for diagnostic functions in l3clist. This wraps the contents (with leading >␣) to a fixed number of characters per line.8249 8250 8251 8252 8253 8254 8255 {#1} {#2} {#3} { } { } { } } \cs_new:Npn \__msg_kernel_expandable_error:nn #1#2 { \__msg_kernel_expandable_error:nnnnnn {#1} {#2} { } { } { } { } } (End definition for \__msg_kernel_expandable_error:nnnnnn and others. is removed using a w-type auxiliary.) \__msg_show_variable:Nnn \__msg_show_variable:n \__msg_show_variable_aux:n \__msg_show_variable_aux:w The arguments of \__msg_show_variable:Nnn are • The hvariablei to be shown. because a line-break may be taken there. These functions are documented on page ??. The expansion of #3 may either be empty or start with >␣. then show the contents #3 using \__msg_show_variable:n. if present. As for \__kernel_register_show:N. l3prop. Finally. output the introductory message.) 17. 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 \cs_new_protected:Npn \__msg_term:nnnnnn #1#2#3#4#5#6 { \iow_wrap:nnnN { \use:c { \c__msg_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} } { } { } \iow_term:n } \cs_generate_variant:Nn \__msg_term:nnnnnn { nnnnnV } \cs_new_protected:Npn \__msg_term:nnnnn #1#2#3#4#5 { \__msg_term:nnnnnn {#1} {#2} {#3} {#4} {#5} { } } \cs_new_protected:Npn \__msg_term:nnn #1#2#3 { \__msg_term:nnnnnn {#1} {#2} {#3} { } { } { } } \cs_new_protected:Npn \__msg_term:nn #1#2 { \__msg_term:nnnnnn {#1} {#2} { } { } { } { } } (End definition for \__msg_term:nnnnnn and \__msg_term:nnnnnV. • A mapping of the form \seq_map_function:NN hvariablei \__msg_show_item:n. • The type of the variable. which produces the formatted string. xtemplate \__msg_term:nnnnnn \__msg_term:nnnnnV \__msg_term:nnnnn \__msg_term:nnn \__msg_term:nn Print the text of a message to the terminal without formatting: short cuts around \iow_wrap:nnnN. l3seq. A leading >. check that the variable is defined. If it is. This function is documented on page 148.\l__msg_internal_tl is displayed to the terminal. with an odd \exp_after:wN which expands the closing brace to improve the output slightly. 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 \cs_new_protected:Npn \__msg_show_variable:Nnn #1#2#3 { \cs_if_exist:NTF #1 { \__msg_term:nnn { LaTeX / kernel } { show. This function is documented on page 148.) \__msg_show_item:n \__msg_show_item:nn \__msg_show_item_unbraced:nn Each item in the variable is formatted using one of the following functions. for removal by 2011-08-31. 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 \cs_new:Npn \__msg_show_item:n #1 { \\ > \ \ \{ \tl_to_str:n {#1} \} } \cs_new:Npn \__msg_show_item:nn #1#2 { \\ > \ \ \{ \tl_to_str:n {#1} \} \ \ => \ \ \{ \tl_to_str:n {#2} \} } \cs_new:Npn \__msg_show_item_unbraced:nn #1#2 { \\ > \ \ \tl_to_str:n {#1} \ \ => \ \ \tl_to_str:n {#2} } (End definition for \__msg_show_item:n.) 17.#2 } {#1} \__msg_show_variable:n {#3} } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_protected:Npn \__msg_show_variable:n #1 { \iow_wrap:nnnN {#1} { } { } \__msg_show_variable_aux:n } \cs_new_protected:Npn \__msg_show_variable_aux:n #1 { \tl_if_empty:nTF {#1} { \tl_clear:N \l__msg_internal_tl } { \tl_set:Nf \l__msg_internal_tl { \__msg_show_variable_aux:w #1 } } \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN { \exp_after:wN \l__msg_internal_tl } } \cs_new:Npn \__msg_show_variable_aux:w #1 > { } (End definition for \__msg_show_variable:Nnn. 456 .8 Deprecated functions Deprecated on 2011-05-27. 8316 8317 8318 8319 8320 8321 8322 8323 8324 h*deprecatedi \cs_new_protected:Npn \cs_new_protected:Npn \cs_new_protected:Npn \cs_new_protected:Npn \cs_new_protected:Npn \cs_new_protected:Npn \cs_new_protected:Npn h/deprecatedi \msg_generic_new:nnn #1#2#3 { \deprecated } \msg_generic_new:nn #1#2 { \deprecated } \msg_generic_set:nnn #1#2#3 { \deprecated } \msg_generic_set:nn #1#2 { \deprecated } \msg_direct_interrupt:xxxxx #1#2#3#4#5 { \deprecated } \msg_direct_log:xx #1#2 { \deprecated } \msg_direct_term:xx #1#2 { \deprecated } (End definition for \msg_generic_new:nnn. 8306 8307 8308 h*deprecatedi \cs_new_eq:NN \msg_class_new:nn \msg_class_set:nn h/deprecatedi (End definition for \msg_class_new:nn. \\ This~probably~needs~examining~by~an~expert. These functions are documented on page ??. \c_msg_return_text_tl } h/deprecatedi 457 .\msg_class_new:nn This is only ever used in a set fashion. This function is documented on page ??.) \__msg_kernel_bug:x \c__msg_kernel_bug_text_tl \c__msg_kernel_bug_more_text_tl 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 h*deprecatedi \cs_set_protected:Npn \__msg_kernel_bug:x #1 { \msg_interrupt:nnn { \c__msg_kernel_bug_text_tl } { #1 \msg_see_documentation_text:n { LaTeX3 } } { \c__msg_kernel_bug_more_text_tl } } \tl_const:Nn \c__msg_kernel_bug_text_tl { This~is~a~LaTeX~bug:~check~coding! } \tl_const:Nn \c__msg_kernel_bug_more_text_tl { There~is~a~coding~bug~somewhere~around~here.) \msg_generic_new:nnn \msg_generic_new:nn \msg_generic_set:nnn \msg_generic_set:nn \msg_direct_interrupt:xxxxx \msg_direct_log:xx \msg_direct_term:xx These were all too low-level. This function is documented on page ??. 8309 8310 8311 8312 8313 8314 8315 h*deprecatedi \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN \cs_new_eq:NN h/deprecatedi \msg_trace:nnxxxx \msg_trace:nnxxx \msg_trace:nnxx \msg_trace:nnx \msg_trace:nn \msg_log:nnxxxx \msg_log:nnxxx \msg_log:nnxx \msg_log:nnx \msg_log:nn (End definition for \msg_trace:nnxxxx and others. so let’s be realistic.) \msg_trace:nnxxxx \msg_trace:nnxxx \msg_trace:nnxx \msg_trace:nnx \msg_trace:nn The performance here is never going to be good enough for tracing code. 8344 8345 8346 8347 h*deprecatedi \cs_new_nopar:Npn \msg_newline: { ^^J } \cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J } h/deprecatedi (End definition for \msg_newline: and \msg_two_newlines:.) \msg_log:x \msg_term:x \msg_interrupt:xxx These were all misnamed. 8348 8349 8350 8351 8352 h*deprecatedi \cs_generate_variant:Nn \msg_log:n { x } \cs_generate_variant:Nn \msg_term:n { x } \cs_generate_variant:Nn \msg_interrupt:nnn { xxx } h/deprecatedi (End definition for \msg_log:x and \msg_term:x. These functions are documented on page ??. Any existing redirection is cleared.(End definition for \__msg_kernel_bug:x.) Deprecated on 2012-06-29. 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 h*deprecatedi \cs_new_protected:Npn \msg_class_set:nn #1#2 { \cs_if_exist:cTF { __msg_ #1 _code:nnnnnn } \cs_set_protected:cpn \cs_new_protected:cpn { __msg_ #1 _code:nnnnnn } ##1##2##3##4##5##6 {#2} \prop_clear_new:c { l__msg_redirect_ #1 _prop } \cs_set_protected_nopar:cpn { msg_ #1 :nnxxxx } { \__msg_use:nnnnnnn {#1} } \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } } h/deprecatedi (End definition for \msg_class_set:nn.) 8373 h/initex | packagei 458 {##5} { } } { } { } } } { } } { } } . and the various message functions are created to simply use the code stored for the message. This function is documented on page ??. \msg_class_set:nn Setting up a message class does two tasks. for removal by 2012-12-31. for removal by 2012-12-31. This function is documented on page ??. These functions are documented on page ??. \msg_newline: \msg_two_newlines: New lines are printed in the same way as for low-level file writing.) Deprecated on 2012-06-28. l3keys Implementation 18 8374 8375 8376 8377 8378 8379 h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 18.. The input is then handed off to the element by element system. This variable is documented on page ??.) \l__keyval_sanitise_tl \l__keyval_parse_tl Token list variables for dealing with awkward category codes in the input.) \l__keyval_key_tl \l__keyval_value_tl The current key name and value. so that there are no odd events. 8382 8383 \tl_new:N \l__keyval_key_tl \tl_new:N \l__keyval_value_tl (End definition for \l__keyval_key_tl and \l__keyval_value_tl. For nesting purposes an integer is needed for the current level. 8384 8385 \tl_new:N \l__keyval_sanitise_tl \tl_new:N \l__keyval_parse_tl (End definition for \l__keyval_sanitise_tl. This function is documented on page ??. } \char_set_lccode:nn { ‘\8 } { ‘\= } \char_set_lccode:nn { ‘\9 } { ‘\.) \__keyval_parse:n The parsing function first deals with the category codes for = and . } \tl_to_lowercase:n { \group_end: \cs_new_protected:Npn \__keyval_parse:n #1 { \group_begin: \tl_clear:N \l__keyval_sanitise_tl \tl_set:Nn \l__keyval_sanitise_tl {#1} \tl_replace_all:Nnn \l__keyval_sanitise_tl { = } { 8 } \tl_replace_all:Nnn \l__keyval_sanitise_tl { . } { 9 } \tl_clear:N \l__keyval_parse_tl \exp_after:wN \__keyval_parse_elt:w \exp_after:wN \q_nil \l__keyval_sanitise_tl 9 \q_recursion_tail 9 \q_recursion_stop 459 .1 8380 \g__keyval_level_int Low-level interface h@@=keyvali For historical reasons this code uses the ‘keyval’ module prefix. 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 \group_begin: \char_set_catcode_active:n { ‘\= } \char_set_catcode_active:n { ‘\. 8381 \int_new:N \g__keyval_level_int (End definition for \g__keyval_level_int. These variables are documented on page ??. Then a check is need to see if there is a value at all: if not then the key name is simply added to the output.\exp_after:wN \group_end: \l__keyval_parse_tl 8404 8405 } 8406 8407 } (End definition for \__keyval_parse:n. there is an hand-off to find the value: the \q_nil is there to prevent loss of braces. If this is the case. Hence the blank test here can always be used to find a totally empty argument. the system loops round. If there is something to parse. { \tl_if_blank:oTF { \use_none:n #1 } { \__keyval_parse_elt:w \q_nil } { \quark_if_recursion_tail_stop:o { \use_ii:nn #1 } \__keyval_split_key_value:w #1 = = \q_stop \__keyval_parse_elt:w \q_nil } } (End definition for \__keyval_parse_elt:w. there is a check for the end of the input before handing off. If there is a value then there is a check to ensure that there was only one = in the input (remembering some extra ones are around at the moment to prevent errors). This function is documented on page ??. This function is documented on page ??. All being well.) \__keyval_parse_elt:w Each item to be parsed will have \q_nil added to the front. 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 \cs_new_protected:Npn \__keyval_parse_elt:w #1 .) \__keyval_split_key_value:w The key and value are handled separately. 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 \cs_new_protected:Npn \__keyval_split_key_value:w #1 = #2 \q_stop { \__keyval_split_key:n {#1} \str_if_eq:nnTF {#2} { = } { \tl_put_right:Nx \l__keyval_parse_tl { \exp_not:c { __keyval_key_no_value_elt_ \int_use:N \g__keyval_level_int :n } { \exp_not:o \l__keyval_key_tl } } } { \__keyval_split_key_value:wTF #2 \q_no_value \q_stop { \__keyval_split_value:w \q_nil #2 } { \__msg_kernel_error:nn { kernel } { misplaced-equals-sign } } } } \cs_new:Npn \__keyval_split_key_value:wTF #1 = #2#3 \q_stop { \tl_if_head_eq_meaning:nNTF {#3} \q_no_value } 460 . First the key is grabbed and saved as \l__\__keyval_split_key_value:wTF keyval_key_tl. ) \__keyval_split_value:w Here the value has to be separated from the equals signs and the leading \q_nil added in to keep the brace levels. In that case. in which case the \use_none:nnn #1 \q_nil \q_nil will yield \q_nil. if the value is entirely contained within a set of braces then \l__keyval_value_tl will contain \q_nil only. 461 . and so an empty group can be added to the parsed list. This function is documented on page ??. This function is documented on page ??. (This code does not have to cover the case with no key.(End definition for \__keyval_split_key_value:w. the braces and any spaces around the outside with \use_ii:nnn. Fist the processing function can be added to the output list. On the other hand. There. as that’s already taken out above. If there is no value.) \__keyval_split_key:n \__keyval_split_key:w There are two possible cases here. we can remove the leading \q_nil. which also deals with any spaces. setting \l__keyval_value_tl with three groups removed will leave nothing at all. The first case is that #1 is surrounded by braces. On the other hand. 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 \cs_new_protected:Npn \__keyval_split_value:w #1 = = { \tl_put_right:Nx \l__keyval_parse_tl { \exp_not:c { __keyval_key_value_elt_ \int_use:N \g__keyval_level_int :nn } { \exp_not:o \l__keyval_key_tl } } \tl_set:Nx \l__keyval_value_tl { \exp_not:o { \use_none:nnn #1 \q_nil \q_nil } } \tl_if_empty:NTF \l__keyval_value_tl { \tl_put_right:Nn \l__keyval_parse_tl { { } } } { \quark_if_nil:NTF \l__keyval_value_tl { \tl_put_right:Nx \l__keyval_parse_tl { { \exp_not:o { \use_ii:nnn #1 \q_nil } } } } { \__keyval_split_value_aux:w #1 \q_stop } } } A similar idea to the key code: remove the spaces from each end and deal with one set of braces. strip off the leading quark using \use_ii:nnn.) 8438 8439 8440 8441 8442 8443 8444 8445 \cs_new_protected:Npn \__keyval_split_key:n #1 { \quark_if_nil:oTF { \use_none:nnn #1 \q_nil \q_nil } { \tl_set:Nx \l__keyval_key_tl { \exp_not:o { \use_ii:nnn #1 \q_nil } } } { \__keyval_split_key:w #1 \q_stop } } \cs_new_protected:Npn \__keyval_split_key:w \q_nil #1 \q_stop { \tl_set:Nx \l__keyval_key_tl { \tl_trim_spaces:n {#1} } } (End definition for \__keyval_split_key:n. if there are no braces then the second branch removes the leading \q_nil and any surrounding spaces. ) \keyval_parse:NNn The outer parsing routine just sets up the processing functions and hands off. 8493 8494 \tl_const:Nn \c__keys_value_forbidden_tl { forbidden } \tl_const:Nn \c__keys_value_required_tl { required } (End definition for \c__keys_value_forbidden_tl and \c__keys_value_required_tl.) One message for the low level parsing system.) \c__keys_props_root_tl The prefix for storing properties.2 8489 \c__keys_code_root_tl \c__keys_vars_root_tl Constants and variables h@@=keysi The prefixes for the code and variables of the keys themselves. These variables are documented on page ??. 8490 8491 \tl_const:Nn \c__keys_code_root_tl { key~code~>~ } \tl_const:Nn \c__keys_vars_root_tl { key~var~>~ } (End definition for \c__keys_code_root_tl and \c__keys_vars_root_tl. This function is documented on page 159. } 18.) \c__keys_value_forbidden_tl \c__keys_value_required_tl Two marker token lists. 8483 8484 8485 8486 8487 8488 \__msg_kernel_new:nnnn { kernel } { misplaced-equals-sign } { Misplaced~equals~sign~in~key-value~input~\msg_line_number: } { LaTeX~is~attempting~to~parse~some~key-value~input~but~found~ two~equals~signs~not~separated~by~a~comma. 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 \cs_new_protected:Npn \keyval_parse:NNn #1#2#3 { \int_gincr:N \g__keyval_level_int \cs_gset_eq:cN { __keyval_key_no_value_elt_ \int_use:N \g__keyval_level_int :n } #1 \cs_gset_eq:cN { __keyval_key_value_elt_ \int_use:N \g__keyval_level_int :nn } #2 \__keyval_parse:n {#3} \int_gdecr:N \g__keyval_level_int } (End definition for \keyval_parse:NNn.) 462 .8467 8468 8469 8470 8471 8472 \cs_new_protected:Npn \__keyval_split_value_aux:w \q_nil #1 \q_stop { \tl_set:Nx \l__keyval_value_tl { \tl_trim_spaces:n {#1} } \tl_put_right:Nx \l__keyval_parse_tl { { \exp_not:o \l__keyval_value_tl } } } (End definition for \__keyval_split_value:w. This function is documented on page ??. 8492 \tl_const:Nn \c__keys_props_root_tl { key~prop~>~ } (End definition for \c__keys_props_root_tl. These variables are documented on page ??. This variable is documented on page ??. \l_keys_choice_int \l_keys_choice_tl Publicly accessible data on which choice is being used when several are generated as a set.) \l__keys_unknown_clist Used when setting only known keys to store those left over. This variable is documented on page ??. 8497 \tl_new:N \l_keys_key_tl (End definition for \l_keys_key_tl. This variable is documented on page 157. 8503 \tl_new:N \l_keys_value_tl (End definition for \l_keys_value_tl.) 463 . This variable is documented on page ??. 8502 \tl_new:N \l__keys_unknown_clist (End definition for \l__keys_unknown_clist. These variables are documented on page 155. 8499 \bool_new:N \l__keys_no_value_bool (End definition for \l__keys_no_value_bool.) \l__keys_property_tl The “property” begin set for a key at definition time is stored here. This variable is documented on page 157. This variable is documented on page ??.) \l__keys_no_value_bool A marker is needed internally to show if only a key or a key plus a value was seen: this is recorded here. This variable is documented on page ??. 8495 8496 \int_new:N \l_keys_choice_int \tl_new:N \l_keys_choice_tl (End definition for \l_keys_choice_int and \l_keys_choice_tl. 8500 \tl_new:N \l_keys_path_tl (End definition for \l_keys_path_tl. This variable is documented on page 157.) \l_keys_path_tl The “path” of the current key is stored here: this is available to the programmer and so is public.) \l_keys_key_tl The name of a key itself: needed when setting keys. 8498 \tl_new:N \l__keys_module_tl (End definition for \l__keys_module_tl. 8501 \tl_new:N \l__keys_property_tl (End definition for \l__keys_property_tl.) \l__keys_module_tl The module for an entire set of keys.) \l_keys_value_tl The value given for a key: may be empty if no value was given. The outer function is designed to keep a track of the current module. so there is no problem using an x-type expansion. This function is documented on page ??.) \__keys_define_elt:n \__keys_define_elt:nn \__keys_define_elt_aux:nn The outer functions here record whether a value was given and then converge on a common internal mechanism. This function is documented on page 150. 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 \cs_new_protected:Npn \__keys_define_elt:n #1 { \bool_set_true:N \l__keys_no_value_bool \__keys_define_elt_aux:nn {#1} { } } \cs_new_protected:Npn \__keys_define_elt:nn #1#2 { \bool_set_false:N \l__keys_no_value_bool \__keys_define_elt_aux:nn {#1} {#2} } \cs_new_protected:Npn \__keys_define_elt_aux:nn #1#2 { \__keys_property_find:n {#1} \cs_if_exist:cTF { \c__keys_props_root_tl \l__keys_property_tl } { \__keys_define_key:n {#2} } { \__msg_kernel_error:nnxx { kernel } { property-unknown } { \l__keys_property_tl } { \l_keys_path_tl } } } (End definition for \__keys_define_elt:n.3 \keys_define:nn \__keys_define:nnn \__keys_define:onn The key defining mechanism The public function for definitions is just a wrapper for the lower level mechanism.18. The module is set removing any leading / (which is not needed here). There is first a search for a property in the current key name. in the input.) \__keys_property_find:n \__keys_property_find:w Searching for a property means finding the last . and storing the text before and after it. 8504 8505 8506 8507 8508 8509 8510 8511 8512 \cs_new_protected:Npn \keys_define:nn { \__keys_define:onn \l__keys_module_tl } \cs_new_protected:Npn \__keys_define:nnn #1#2#3 { \tl_set:Nx \l__keys_module_tl { \tl_to_str:n {#2} } \keyval_parse:NNn \__keys_define_elt:n \__keys_define_elt:nn {#3} \tl_set:Nn \l__keys_module_tl {#1} } \cs_generate_variant:Nn \__keys_define:nnn { o } (End definition for \keys_define:nn. to allow safe nesting. then a check to make sure it is known before the code hands off to the next step. Everything is turned into strings. } { \__keys_property_find:w #1 \q_stop } 464 . more or less. 8533 8534 8535 8536 8537 \cs_new_protected:Npn \__keys_property_find:n #1 { \tl_set:Nx \l_keys_path_tl { \l__keys_module_tl / } \tl_if_in:nnTF {#1} { . This function is documented on page ??. 8567 8568 8569 8570 8571 8572 8573 \cs_new:Npn \__keys_bool_set:NN #1#2 { \bool_if_exist:NF #1 { \bool_new:N #1 } \__keys_choice_make: \__keys_cmd_set:nx { \l_keys_path_tl / true } { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } \__keys_cmd_set:nx { \l_keys_path_tl / false } 465 . but all done by hand. If not.) 18. then just use the function. #2 \q_stop { \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } \tl_if_in:nnTF {#2} { .4 \__keys_bool_set:NN Turning properties into actions Boolean keys are really just choices.) \__keys_define_key:n \__keys_define_key:w Two possible cases. } \__keys_property_find:w #2 \q_stop } { \tl_set:Nn \l__keys_property_tl { . There is no need to check for a : as if it is missing the earlier tests will have failed. The second argument here is the scope: either empty or g for global.8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 { \__msg_kernel_error:nnx { kernel } { key-no-property } {#1} } } \cs_new_protected:Npn \__keys_property_find:w #1 . If there should be one then complain. 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 \cs_new_protected:Npn \__keys_define_key:n #1 { \bool_if:NTF \l__keys_no_value_bool { \exp_after:wN \__keys_define_key:w \l__keys_property_tl \q_stop { \use:c { \c__keys_props_root_tl \l__keys_property_tl } } { \__msg_kernel_error:nnxx { kernel } { property-requires-value } { \l__keys_property_tl } { \l_keys_path_tl } } } { \use:c { \c__keys_props_root_tl \l__keys_property_tl } {#1} } } \cs_new_protected:Npn \__keys_define_key:w #1 : #2 \q_stop { \tl_if_empty:nTF {#2} } (End definition for \__keys_define_key:n. } { \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . then a check to make sure there is no need for a value with the property. This function is documented on page ??. #2 } } } (End definition for \__keys_property_find:n. If there is a value for the key. otherwise execute it. 8607 8608 8609 8610 8611 8612 \cs_new_protected:Npn \__keys_choices_make:nn #1#2 { \__keys_choice_make: \int_zero:N \l_keys_choice_int \clist_map_inline:nn {#1} { 466 . 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 \cs_new_protected_nopar:Npn \__keys_choice_make: { \__keys_cmd_set:nn { \l_keys_path_tl } { \__keys_choice_find:n {##1} } \__keys_cmd_set:nn { \l_keys_path_tl / unknown } { \__msg_kernel_error:nnxx { kernel } { key-choice-unknown } { \l_keys_path_tl } {##1} } } (End definition for \__keys_choice_make:. and set the unknown key. two steps: set the code.) \__keys_bool_set_inverse:NN Inverse boolean setting is much the same. 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 \cs_new:Npn \__keys_bool_set_inverse:NN #1#2 { \bool_if_exist:NF #1 { \bool_new:N #1 } \__keys_choice_make: \__keys_cmd_set:nx { \l_keys_path_tl / true } { \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } \__keys_cmd_set:nx { \l_keys_path_tl / false } { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } \__keys_cmd_set:nn { \l_keys_path_tl / unknown } { \__msg_kernel_error:nnx { kernel } { boolean-values-only } { \l_keys_key_tl } } \__keys_default_set:n { true } } (End definition for \__keys_bool_set_inverse:NN. then defining each choice in turn.) \__keys_choice_make: To make a choice from a key.) \__keys_choices_make:nn Auto-generating choices means setting up the root key as a choice.{ \exp_not:c { bool_ #2 set_false:N } \exp_not:N #1 } \__keys_cmd_set:nn { \l_keys_path_tl / unknown } { \__msg_kernel_error:nnx { kernel } { boolean-values-only } { \l_keys_key_tl } } \__keys_default_set:n { true } 8574 8575 8576 8577 8578 8579 8580 8581 } (End definition for \__keys_bool_set:NN. 8649 8650 8651 8652 8653 8654 \cs_new_protected:Npn \__keys_choice_code_store:n #1 { \cs_if_exist:cF { \c__keys_vars_root_tl \l_keys_path_tl . 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 \cs_new_protected:Npn \__keys_choices_generate:n #1 { \cs_if_exist:cTF { \c__keys_vars_root_tl \l_keys_path_tl .) \__keys_choice_code_store:n \__keys_choice_code_store:x The code for making multiple choices is stored in a token list. This function is documented on page ??.) \__keys_choices_generate:n Creating multiple-choices means setting up the “indicator” code. then applying whatever \__keys_choices_generate_aux:n the user wanted.choice~code } } } (End definition for \__keys_choices_generate:n.\int_incr:N \l_keys_choice_int \__keys_cmd_set:nx { \l_keys_path_tl / ##1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {##1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:n {#2} } 8613 8614 8615 8616 8617 8618 8619 8620 } 8621 8622 } (End definition for \__keys_choices_make:nn.choice~code } { \__keys_choice_make: \int_zero:N \l_keys_choice_int \clist_map_function:nN {#1} \__keys_choices_generate_aux:n } { \__msg_kernel_error:nnx { kernel } { generate-choices-before-code } { \l_keys_path_tl } } } \cs_new_protected:Npn \__keys_choices_generate_aux:n #1 { \int_incr:N \l_keys_choice_int \__keys_cmd_set:nx { \l_keys_path_tl / #1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {#1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:v { \c__keys_vars_root_tl \l_keys_path_tl .choice~code } { \tl_new:c 467 . \__keys_cmd_set:nx .) \__keys_cmd_set:nn \__keys_cmd_set:nx \__keys_cmd_set:Vo \__keys_cmd_set:n Creating a new command means tidying up the properties and then making the internal function which actually does the work.) 468 .) \__keys_default_set:n \__keys_default_set:V Setting a default value is easy.default } \tl_set:cn { \c__keys_vars_root_tl #1 . At this stage.) \__keys_initialise:n \__keys_initialise:V \__keys_initialise:wn A set up for initialisation from which the key system requires that the path is split up into a module and a key name. These functions are documented on page ??.choice~code } {#1} } \cs_generate_variant:Nn \__keys_choice_code_store:n { x } (End definition for \__keys_choice_code_store:n and \__keys_choice_code_store:x.default } {#1} } \cs_generate_variant:Nn \__keys_default_set:n { V } (End definition for \__keys_default_set:n and \__keys_default_set:V. 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 \cs_new_protected:Npn \__keys_cmd_set:nn #1#2 { \__keys_cmd_set:n {#1} \cs_set:cpn { \c__keys_code_root_tl #1 } ##1 {#2} } \cs_new_protected:Npn \__keys_cmd_set:nx #1#2 { \__keys_cmd_set:n {#1} \cs_set:cpx { \c__keys_code_root_tl #1 } ##1 {#2} } \cs_generate_variant:Nn \__keys_cmd_set:nn { Vo } \cs_new_protected:Npn \__keys_cmd_set:n #1 { \tl_clear_new:c { \c__keys_vars_root_tl #1 . and \__keys_cmd_set:Vo.8655 8656 8657 8658 8659 8660 { \c__keys_vars_root_tl \l_keys_path_tl .choice~code } } \tl_set:cn { \c__keys_vars_root_tl \l_keys_path_tl . 8681 8682 8683 8684 8685 8686 8687 8688 \cs_new_protected:Npn \__keys_initialise:n #1 { \use:x { \exp_after:wN \__keys_initialise:wn \l_keys_path_tl \q_stop {#1} } } \cs_generate_variant:Nn \__keys_initialise:n { V } \cs_new:Npn \__keys_initialise:wn #1 / #2 \q_stop #3 { \keys_set:nn {#1} { #2 = \exp_not:n { {#3} } } } (End definition for \__keys_initialise:n and \__keys_initialise:V. \l_keys_path_tl will contain / so a split is easy to do. These functions are documented on page ??.default } { \q_no_value } \tl_clear_new:c { \c__keys_vars_root_tl #1 . 8678 8679 8680 \cs_new_protected:Npn \__keys_default_set:n #1 { \tl_set:cn { \c__keys_vars_root_tl \l_keys_path_tl .req } } (End definition for \__keys_cmd_set:nn . These functions are documented on page ??.\__keys_meta_make:n \__keys_meta_make:x To create a meta-key.) \__keys_multichoice_find:n \__keys_multichoice_make: \__keys_multichoices_make:nn Choices where several values can be selected are very similar to normal exclusive choices. 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 \cs_new_protected:Npn \__keys_meta_make:n #1 { \__keys_cmd_set:Vo \l_keys_path_tl { \exp_after:wN \keys_set:nn \exp_after:wN { \l__keys_module_tl } {#1} } } \cs_new_protected:Npn \__keys_meta_make:x #1 { \__keys_cmd_set:nx { \l_keys_path_tl } { \exp_not:N \keys_set:nn { \l__keys_module_tl } {#1} } } (End definition for \__keys_meta_make:n and \__keys_meta_make:x. 8727 \cs_new_protected:Npn \__keys_value_requirement:n #1 469 . This then requires that the appropriate set up takes place elsewhere. 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 \cs_new:Npn \__keys_multichoice_find:n #1 { \clist_map_function:nN {#1} \__keys_choice_find:n } \cs_new_protected_nopar:Npn \__keys_multichoice_make: { \__keys_cmd_set:nn { \l_keys_path_tl } { \__keys_multichoice_find:n {##1} } \__keys_cmd_set:nn { \l_keys_path_tl / unknown } { \__msg_kernel_error:nnxx { kernel } { key-choice-unknown } { \l_keys_path_tl } {##1} } } \cs_new_protected:Npn \__keys_multichoices_make:nn #1#2 { \__keys_multichoice_make: \int_zero:N \l_keys_choice_int \clist_map_inline:nn {#1} { \int_incr:N \l_keys_choice_int \__keys_cmd_set:nx { \l_keys_path_tl / ##1 } { \tl_set:Nn \exp_not:N \l_keys_choice_tl {##1} \int_set:Nn \exp_not:N \l_keys_choice_int { \int_use:N \l_keys_choice_int } \exp_not:n {#2} } } } (End definition for \__keys_multichoice_find:n. There is just a slight change in implementation to map across a comma-separated list. This function is documented on page ??.) \__keys_value_requirement:n Values can be required or forbidden by having the appropriate marker set. simply set up to pass data through. bool_gset:N One function for this.) 470 .generate_choices:n. This function is documented on page 151.choice:.) .bool_gset:N } #1 #1 g } (End definition for .bool_set_inverse:N } #1 { \__keys_bool_set_inverse:NN #1 { } } \cs_new_protected:cpn { \c__keys_props_root_tl .) .bool_set:N .bool_set_inverse:N .) 18. 8747 8748 8749 8750 \cs_new_protected:cpn { \c__keys_props_root_tl . . This function is documented on page 150.bool_gset_inverse:N } #1 { \__keys_bool_set_inverse:NN #1 g } (End definition for . This function is documented on page 151. as it is also needed by . These functions are documented on page ??. meaning that things stay readable and can also be altered later on. 8751 8752 \cs_new_protected_nopar:cpn { \c__keys_props_root_tl .choice: } { \__keys_choice_make: } (End definition for .) \__keys_variable_set:NnNN \__keys_variable_set:cnNN \__keys_variable_set:NnN \__keys_variable_set:cnN Setting a variable takes the type and scope separately so that it is easy to make a new variable if needed.bool_set_inverse:N.bool_set:N. 8743 8744 8745 8746 \cs_new_protected:cpn { { \__keys_bool_set:NN \cs_new_protected:cpn { { \__keys_bool_set:NN \c__keys_props_root_tl . The three-argument version is set up so that the use of { } as an N-type variable is only done once! 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 \cs_new_protected:Npn \__keys_variable_set:NnNN #1#2#3#4 { \use:c { #2_if_exist:NF } #1 { \use:c { #2 _new:N } #1 } \__keys_cmd_set:nx { \l_keys_path_tl } { \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1} } } \cs_new_protected:Npn \__keys_variable_set:NnN #1#2#3 { \__keys_variable_set:NnNN #1 {#2} { } #3 } \cs_generate_variant:Nn \__keys_variable_set:NnNN { c } \cs_generate_variant:Nn \__keys_variable_set:NnN { c } (End definition for \__keys_variable_set:NnNN and \__keys_variable_set:cnNN.bool_set:N } #1 #1 { } } \c__keys_props_root_tl .choice: Making a choice is handled internally.{ 8728 \tl_set_eq:cc { \c__keys_vars_root_tl \l_keys_path_tl .5 Creating key properties The key property functions are all wrappers for internal functions.req } { c__keys_value_ #1 _tl } 8729 8730 8731 } 8732 (End definition for \__keys_value_requirement:n.bool_gset_inverse:N One function for this. choice_code:n } #1 { \__keys_choice_code_store:n {#1} } \cs_new_protected:cpn { \c__keys_props_root_tl .clist_set:N and .clist_gset:N } #1 { \__keys_variable_set:NnNN #1 { clist } g n } \cs_new_protected:cpn { \c__keys_props_root_tl . 8753 8754 \cs_new_protected:cpn { \c__keys_props_root_tl . These functions are documented on page 151. These functions are documented on page 152. 8755 8756 8757 8758 \cs_new_protected:cpn { \c__keys_props_root_tl .dim_gset:N } #1 .choice_code:n and .choices:nn.) .clist_set:N .default:n .dim_set:N } #1 .) .choice_code:x } #1 { \__keys_choice_code_store:x {#1} } (End definition for . Here.choices:nn } #1 { \__keys_choices_make:nn #1 } (End definition for .) .clist_set:c.default:n and .) .code:x.dim_gset:c Setting a variable is very easy: just pass the data along.default:V } #1 { \__keys_default_set:V #1 } (End definition for .choice_code:x Storing the code for choices 8759 8760 8761 8762 \cs_new_protected:cpn { \c__keys_props_root_tl .dim_set:c.dim_set:N . These functions are documented on page 151.code:n and .code:n } #1 { \__keys_cmd_set:nn { \l_keys_path_tl } {#1} } \cs_new_protected:cpn { \c__keys_props_root_tl .default:n } #1 { \__keys_default_set:n {#1} } \cs_new_protected:cpn { \c__keys_props_root_tl . #1 will consist of two separate arguments.dim_gset:c } #1 } (End definition for .code:n .code:x } #1 { \__keys_cmd_set:nx { \l_keys_path_tl } {#1} } (End definition for .choice_code:n .choice_code:x.dim_set:N and .dim_set:c . hence the slightly odd-looking implementation.default:V. These functions are documented on page 151.clist_gset:c 8763 8764 8765 8766 8767 8768 8769 8770 \cs_new_protected:cpn { \c__keys_props_root_tl . This function is documented on page 151.dim_gset:N .) .dim_set:c } #1 .clist_gset:c } #1 { \__keys_variable_set:cnNN {#1} { clist } g n } (End definition for .clist_gset:N .code:x Creating code is simply a case of passing through to the underlying set function.) 471 . These functions are documented on page 152.clist_set:N } #1 { \__keys_variable_set:NnN #1 { clist } n } \cs_new_protected:cpn { \c__keys_props_root_tl . 8771 8772 8773 8774 \cs_new_protected:cpn { \c__keys_props_root_tl .clist_set:c } #1 { \__keys_variable_set:cnN {#1} { clist } n } \cs_new_protected:cpn { \c__keys_props_root_tl .clist_set:c .choices:nn For auto-generation of a series of mutually-exclusive choices.default:V Expansion is left to the internal functions. 8775 8776 8777 8778 8779 8780 8781 8782 \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:NnN #1 { dim } n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:cnN {#1} { dim } n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:NnNN #1 { dim } g n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:cnNN {#1} { dim } g n .. This function is documented on page 152.initial:n .initial:V.int_set:N .initial:V The standard hand-off approach.initial:n and .) . 8793 8794 8795 8796 \cs_new_protected:cpn { \c__keys_props_root_tl .generate_choices:n Making choices is easy. These functions are documented on page 153.fp_gset:c } #1 { \__keys_variable_set:cnNN {#1} { fp } g n } (End definition for . 8805 8806 8807 8808 \cs_new_protected:cpn { { \__keys_meta_make:n \cs_new_protected:cpn { { \__keys_meta_make:x \c__keys_props_root_tl . 8783 8784 8785 8786 8787 8788 8789 8790 \cs_new_protected:cpn { \c__keys_props_root_tl . These functions are documented on page 152.int_set:N and .int_gset:N .meta:n .multichoices:nn } #1 { \__keys_multichoices_make:nn #1 } (End definition for .fp_gset:N ..fp_gset:c Setting a variable is very easy: just pass the data along. These functions are documented on page 152.) .) .fp_gset:N } #1 { \__keys_variable_set:NnNN #1 { fp } g n } \cs_new_protected:cpn { \c__keys_props_root_tl .int_gset:c } #1 } (End definition for .initial:V } #1 { \__keys_initialise:V #1 } (End definition for .fp_set:N . but where more than one choice is allowed.int_set:c.fp_set:c } #1 { \__keys_variable_set:cnN {#1} { fp } n } \cs_new_protected:cpn { \c__keys_props_root_tl .int_gset:N } #1 . This function is documented on page 153.int_set:c .fp_set:c. These functions are documented on page 152.multichoices:nn The same idea as .int_gset:c Setting a variable is very easy: just pass the data along.multichoice:.fp_set:c .int_set:N } #1 .fp_set:N } #1 { \__keys_variable_set:NnN #1 { fp } n } \cs_new_protected:cpn { \c__keys_props_root_tl .meta:x Making a meta is handled internally.) .int_set:c } #1 .multichoice: } { \__keys_multichoice_make: } \cs_new_protected:cpn { \c__keys_props_root_tl .choices:nn.initial:n } #1 { \__keys_initialise:n {#1} } \cs_new_protected:cpn { \c__keys_props_root_tl .multichoice: .meta:x. 8809 8810 8811 8812 \cs_new_protected_nopar:cpn { \c__keys_props_root_tl .meta:x } #1 {#1} } (End definition for . 8791 8792 \cs_new_protected:cpn { \c__keys_props_root_tl .fp_set:N and .choice: and .) . 8797 8798 8799 8800 8801 8802 8803 8804 \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:NnN #1 { int } n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:cnN {#1} { int } n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:NnNN #1 { int } g n } \cs_new_protected:cpn { \c__keys_props_root_tl { \__keys_variable_set:cnNN {#1} { int } g n .generate_choices:n } #1 { \__keys_choices_generate:n {#1} } (End definition for .) 472 .generate_choices:n.meta:n and .meta:n } #1 {#1} } \c__keys_props_root_tl . tl_gset:N .tl_set_x:N .tl_set:c . These functions are documented on page 153.tl_gset_x:N } #1 { \__keys_variable_set:NnNN #1 { tl } g x } \cs_new_protected:cpn { \c__keys_props_root_tl .value_forbidden: } { \__keys_value_requirement:n { forbidden } } \cs_new_protected_nopar:cpn { \c__keys_props_root_tl . so both call the same function.tl_set:N and .tl_set:N } #1 { \__keys_variable_set:NnN #1 { tl } n } \cs_new_protected:cpn { \c__keys_props_root_tl .skip_gset:N .skip_gset:c } #1 { \__keys_variable_set:cnNN {#1} { skip } g n } (End definition for .tl_set_x:c } #1 { \__keys_variable_set:cnN {#1} { tl } x } \cs_new_protected:cpn { \c__keys_props_root_tl .) .value_forbidden: .skip_set:N . 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 \cs_new_protected:cpn { \c__keys_props_root_tl .6 \keys_set:nn \keys_set:nV \keys_set:nv \keys_set:no \__keys_set:nnn \__keys_set:onn Setting keys A simple wrapper again.tl_gset:N } #1 { \__keys_variable_set:NnNN #1 { tl } g n } \cs_new_protected:cpn { \c__keys_props_root_tl . These functions are documented on page 153.value_required: } { \__keys_value_requirement:n { required } } (End definition for .) 18.skip_set:c } #1 { \__keys_variable_set:cnN {#1} { skip } n } \cs_new_protected:cpn { \c__keys_props_root_tl .tl_gset_x:N .tl_gset:c } #1 { \__keys_variable_set:cnNN {#1} { tl } g n } \cs_new_protected:cpn { \c__keys_props_root_tl .skip_gset:N } #1 { \__keys_variable_set:NnNN #1 { skip } g n } \cs_new_protected:cpn { \c__keys_props_root_tl .) .skip_set:N and .tl_gset_x:c } #1 { \__keys_variable_set:cnNN {#1} { tl } g x } (End definition for .tl_set:c } #1 { \__keys_variable_set:cnN {#1} { tl } n } \cs_new_protected:cpn { \c__keys_props_root_tl .skip_gset:c Setting a variable is very easy: just pass the data along.tl_gset:c .skip_set:N } #1 { \__keys_variable_set:NnN #1 { skip } n } \cs_new_protected:cpn { \c__keys_props_root_tl . 8813 8814 8815 8816 8817 8818 8819 8820 \cs_new_protected:cpn { \c__keys_props_root_tl . 8837 8838 8839 8840 \cs_new_protected_nopar:cpn { \c__keys_props_root_tl .tl_set:c.tl_set_x:c .skip_set:c. This function is documented on page 153.value_required: These are very similar..value_forbidden:.tl_set_x:N } #1 { \__keys_variable_set:NnN #1 { tl } x } \cs_new_protected:cpn { \c__keys_props_root_tl . 8841 8842 8843 8844 8845 8846 8847 8848 \cs_new_protected:Npn \keys_set:nn { \__keys_set:onn { \l__keys_module_tl } } \cs_new_protected:Npn \__keys_set:nnn #1#2#3 { \tl_set:Nx \l__keys_module_tl { \tl_to_str:n {#2} } \keyval_parse:NNn \__keys_set_elt:n \__keys_set_elt:nn {#3} \tl_set:Nn \l__keys_module_tl {#1} } 473 .tl_gset_x:c Setting a variable is very easy: just pass the data along.tl_set:N .skip_set:c . 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 \cs_new_protected:Npn \__keys_set_elt:n #1 { \bool_set_true:N \l__keys_no_value_bool \__keys_set_elt_aux:nn {#1} { } } \cs_new_protected:Npn \__keys_set_elt:nn #1#2 { \bool_set_false:N \l__keys_no_value_bool \__keys_set_elt_aux:nn {#1} {#2} } \cs_new_protected:Npn \__keys_set_elt_aux:nn #1#2 { \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } \tl_set:Nx \l_keys_path_tl { \l__keys_module_tl / \l_keys_key_tl } \__keys_value_or_default:n {#2} \bool_if:nTF { \__keys_if_value_p:n { required } && \l__keys_no_value_bool } { \__msg_kernel_error:nnx { kernel } { value-required } { \l_keys_path_tl } } { 474 .) \keys_set_known:nnN \keys_set_known:nVN \keys_set_known:nvN \keys_set_known:noN \__keys_set_known:nnnN \__keys_set_known:onnN 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 \cs_new_protected:Npn \keys_set_known:nnN { \__keys_set_known:onnN { \l__keys_module_tl } } \cs_new_protected:Npn \__keys_set_known:nnnN #1#2#3#4 { \tl_set:Nx \l__keys_module_tl { \tl_to_str:n {#2} } \clist_clear:N \l__keys_unknown_clist \cs_set_eq:NN \__keys_execute_unknown: \__keys_execute_unknown_alt: \keyval_parse:NNn \__keys_set_elt:n \__keys_set_elt:nn {#3} \cs_set_eq:NN \__keys_execute_unknown: \__keys_execute_unknown_std: \tl_set:Nn \l__keys_module_tl {#1} \clist_set_eq:NN #4 \l__keys_unknown_clist } \cs_generate_variant:Nn \keys_set_known:nnN { nV . These functions are documented on page ??. There are then checks to see if the a value is required or forbidden. nv . set the current path and add a default if needed. If everything passes. no } \cs_generate_variant:Nn \__keys_set_known:nnnN { o } (End definition for \keys_set_known:nnN and others.) \__keys_set_elt:n \__keys_set_elt:nn \__keys_set_elt_aux:nn A shared system once again. nv . no } \cs_generate_variant:Nn \__keys_set:nnn { o } (End definition for \keys_set:nn and others. move on to execute the code. First. These functions are documented on page ??.8849 8850 \cs_generate_variant:Nn \keys_set:nn { nV . complain.default } } } } } (End definition for \__keys_value_or_default:n. return it as #1. A simple check for the existence of the appropriate marker.) \__keys_execute: \__keys_execute_unknown: \__keys_execute_unknown_std: \__keys_execute_unknown_alt: \__keys_execute:nn Actually executing a key is done in two parts.default } { \cs_if_exist:cT { \c__keys_vars_root_tl \l_keys_path_tl .\bool_if:nTF { \__keys_if_value_p:n { forbidden } && ! \l__keys_no_value_bool } { \__msg_kernel_error:nnxx { kernel } { value-forbidden } { \l_keys_path_tl } { \l_keys_value_tl } } { \__keys_execute: } 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 } 8900 8901 } (End definition for \__keys_set_elt:n and \__keys_set_elt:nn. These functions are documented on page ??. otherwise send a default if available.default } { \tl_set_eq:Nc \l_keys_value_tl { \c__keys_vars_root_tl \l_keys_path_tl . 8924 8925 8926 \cs_new_nopar:Npn \__keys_execute: { \__keys_execute:nn { \l_keys_path_tl } { \__keys_execute_unknown: } } \cs_new_nopar:Npn \__keys_execute_unknown: 475 . If both of these fail. 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 \cs_new_protected:Npn \__keys_value_or_default:n #1 { \tl_set:Nn \l_keys_value_tl {#1} \bool_if:NT \l__keys_no_value_bool { \quark_if_no_value:cF { \c__keys_vars_root_tl \l_keys_path_tl . 8917 8918 8919 8920 8921 8922 8923 \prg_new_conditional:Npnn \__keys_if_value:n #1 { p } { \tl_if_eq:ccTF { c__keys_value_ #1 _tl } { \c__keys_vars_root_tl \l_keys_path_tl . First. look for the key itself.) \__keys_value_or_default:n If a value is given.) \__keys_if_value_p:n To test if a value is required or forbidden.req } { \prg_return_true: } { \prg_return_false: } } (End definition for \__keys_if_value_p:n. then look for the unknown key with the same path. These functions are documented on page 157.) \__keys_choice_find:n Executing a choice has two parts.7 \keys_if_exist_p:nn \keys_if_exist:nnTF Utilities A utility for others to see if a key exists. try the choice given.) 18. then if that fails call the unknown key. So there is no need for any escape code. 8958 8959 8960 8961 8962 8963 \prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p . as it is created when a choice is first made. First. This function is documented on page ??. 8953 8954 8955 8956 8957 \cs_new:Npn \__keys_choice_find:n #1 { \__keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } { \__keys_execute:nn { \l_keys_path_tl / unknown } { } } } (End definition for \__keys_choice_find:n. That will exist. F . TF } { \cs_if_exist:cTF { \c__keys_code_root_tl #1 / #2 } { \prg_return_true: } { \prg_return_false: } } (End definition for \keys_if_exist:nn. T .{ 8927 \__keys_execute:nn { \l__keys_module_tl / unknown } { \__msg_kernel_error:nnxx { kernel } { key-unknown } { \l_keys_path_tl } { \l__keys_module_tl } } 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 } \cs_new_eq:NN \__keys_execute_unknown_std: \__keys_execute_unknown: \cs_new_nopar:Npn \__keys_execute_unknown_alt: { \clist_put_right:Nx \l__keys_unknown_clist { \exp_not:o \l_keys_key_tl \bool_if:NF \l__keys_no_value_bool { = { \exp_not:o \l_keys_value_tl } } } } \cs_new:Npn \__keys_execute:nn #1#2 { \cs_if_exist:cTF { \c__keys_code_root_tl #1 } { \exp_args:Nc \exp_args:No { \c__keys_code_root_tl #1 } \l_keys_value_tl } {#2} } (End definition for \__keys_execute:.) 476 . choice_code:x’. } \__msg_kernel_new:nnnn { kernel } { generate-choices-before-code } { No~code~available~to~generate~choices~for~key~’#1’.~’#2’.8 Messages For when there is a need to complain. } { \c_msg_coding_error_text_tl Before~using~.) 18. } { The~key~’#1’~only~accepts~the~values~’true’~and~’false’. } \__msg_kernel_new:nnnn { kernel } { key-no-property } { No~property~given~in~definition~of~key~’#1’. } { \c_msg_coding_error_text_tl Inside~\keys_define:nn each~key~name needs~a~property: \\ ~ ~ #1 . 8964 8965 8966 8967 8968 8969 \prg_new_conditional:Npnn \keys_if_choice_exist:nnn #1#2#3 { p . } { The~key~’#1’~takes~a~limited~number~of~values.\\ Check~that~you~have~spelled~the~key~name~correctly. 8970 8971 \cs_new:Npn \keys_show:nn #1#2 { \cs_show:c { \c__keys_code_root_tl #1 / \tl_to_str:n {#2} } } (End definition for \keys_show:nn.~is~not~on~the~list~accepted. F . } \__msg_kernel_new:nnnn { kernel } { choice-unknown } { Choice~’#2’~unknown~for~key~’#1’.generate_choices:n~the~code~should~be~defined~ with~’.<property> \\ LaTeX~did~not~find~a~’. TF } { \cs_if_exist:cTF { \c__keys_code_root_tl #1 / #2 / #3 } { \prg_return_true: } { \prg_return_false: } } (End definition for \keys_if_choice_exist:nnn. These functions are documented on page 157.\\ The~input~given. } \__msg_kernel_new:nnnn { kernel } { key-unknown } { The~key~’#1’~is~unknown~and~is~being~ignored.\keys_if_choice_exist_p:nnn \keys_if_choice_exist:nnnTF Just an alternative view on \keys_if_exist:nn(TF). } \__msg_kernel_new:nnnn { kernel } { property-requires-value } 477 . } { The~module~’#2’~does~not~have~a~key~called~#1’.choice_code:n’~or~’.’~to~indicate~the~start~of~a~property. 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 \__msg_kernel_new:nnnn { kernel } { boolean-values-only } { Key~’#1’~accepts~boolean~values~only. T .) \keys_show:nn Showing a key is just a question of using the correct name. This function is documented on page 157. 9036 h*deprecatedi \cs_new_eq:NN \c_keys_code_root_tl \c__keys_code_root_tl h/deprecatedi 9037 h/initex | packagei 9034 9035 19 l3file implementation The following test files are used for this code: m3file001.\\ LaTeX~will~ignore~the~given~value~’#2’. \KV_process_space_removal_sanitize:NNn There is just one function for this now.9 Deprecated functions Deprecated on 2011-05-27. } { The~key~’#1’~must~have~a~value.\\ No~value~was~given~for~the~property.) Internal material for removal by 2012-12-31.\\ No~value~was~present:~the~key~will~be~ignored. } \__msg_kernel_new:nnnn { kernel } { property-unknown } { The~key~property~’#1’~is~unknown.~and~one~is~required. \KV_process_space_removal_no_sanitize:NNn 9029 h*deprecatedi \KV_process_no_space_removal_no_sanitize:NNn 9030 \cs_new_eq:NN \KV_process_space_removal_sanitize:NNn \keyval_parse:NNn 9031 \cs_new_eq:NN \KV_process_space_removal_no_sanitize:NNn \keyval_parse:NNn 9032 \cs_new_eq:NN \KV_process_no_space_removal_no_sanitize:NNn \keyval_parse:NNn 9033 h/deprecatedi (End definition for \KV_process_space_removal_sanitize:NNn. } { \c_msg_coding_error_text_tl LaTeX~has~been~asked~to~set~the~property~’#1’~for~key~’#2’:~ this~property~is~not~defined. for removal by 2011-08-31. } \__msg_kernel_new:nnnn { kernel } { value-required } { The~key~’#1’~requires~a~value.9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 { The~property~’#1’~requires~a~value. 9038 h*initex | packagei 478 . } \__msg_kernel_new:nnnn { kernel } { value-forbidden } { The~key~’#1’~does~not~taken~a~value. } { The~key~’#1’~should~be~given~without~a~value. } 18. This function is documented on page ??. } { \c_msg_coding_error_text_tl LaTeX~was~asked~to~set~property~’#2’~for~key~’#1’. This variable is documented on page ??. This variable is documented on page ??.) \l__file_internal_tl Used as a short-term scratch variable.) 479 . 9065 \tl_new:N \l__file_internal_tl (End definition for \l__file_internal_tl.9039 9040 9041 9042 9043 9044 h@@=filei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 19. 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 \tl_new:N \g_file_current_name_tl h*initexi \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \tl_gset:Nx \g_file_current_name_tl { \tex_jobname:D } } h/initexi h*packagei \tl_gset_eq:NN \g_file_current_name_tl \@currname h/packagei (End definition for \g_file_current_name_tl. This variable is documented on page 160. It may be possible to reuse \l__file_internal_name_tl there. The current file name should be included in the file list! In format mode. 9056 \seq_new:N \g__file_stack_seq (End definition for \g__file_stack_seq. This variable is documented on page ??. 9057 9058 9059 9060 9061 9062 9063 9064 \seq_new:N \g__file_record_seq h*initexi \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \seq_gput_right:NV \g__file_record_seq \g_file_current_name_tl } h/initexi (End definition for \g__file_record_seq.) \g__file_stack_seq The input list of files is stored as a sequence stack. In package mode we will eventually copy the contents of \@filelist. this is done at the very start of the TEX run.) \g__file_record_seq The total list of files used is recorded separately from the current file stack. as nothing is ever popped from this list. In package mode the current file name is collected from LATEX 2ε .1 \g_file_current_name_tl File operations The name of the current file should be available at all times. For the format the file name needs to be picked up at the start of the file. This variable is documented on page 165. This variable is documented on page ??. 9066 \tl_new:N \l__file_internal_name_tl (End definition for \l__file_internal_name_tl. 9071 9072 9073 h*packagei \seq_new:N \l__file_internal_seq h/packagei (End definition for \l__file_internal_seq. 9067 \seq_new:N \l__file_search_path_seq (End definition for \l__file_search_path_seq. 9068 9069 9070 h*packagei \seq_new:N \l__file_saved_search_path_seq h/packagei (End definition for \l__file_saved_search_path_seq.) \l__file_search_path_seq The current search path. This variable is documented on page ??. 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 \cs_new_protected:Npn \__file_name_sanitize:nn #1#2 { \group_begin: \seq_map_inline:Nn \l_char_active_seq { \cs_set_nopar:Npx ##1 { \token_to_str:N ##1 } } \tl_set:Nx \l__file_internal_name_tl {#1} \tl_set:Nx \l__file_internal_name_tl { \tl_to_str:N \l__file_internal_name_tl } \tl_if_in:NnT \l__file_internal_name_tl { ~ } { \__msg_kernel_error:nnx { kernel } { space-in-file-name } { \l__file_internal_name_tl } \tl_remove_all:Nn \l__file_internal_name_tl { ~ } } \use:x { \group_end: \exp_not:n {#2} { \l__file_internal_name_tl } } } (End definition for \__file_name_sanitize:nn.) \__file_name_sanitize:nn For converting a token list to a string where active characters are treated as strings from the start.) \l__file_internal_seq Scratch space for comma list conversion in package mode. This variable is documented on page ??.\l__file_internal_name_tl Used to return the fully-qualified name of a file.) \l__file_saved_search_path_seq The current search path has to be saved for package use.) 480 . this is straight-forward. #2 is returned empty. If the file was found. TF } { \file_add_path:nN {#1} \l__file_internal_name_tl 481 . For other locations. For files which are in the current directory. F . } \input@path \seq_concat:NNN \l__file_search_path_seq \l__file_search_path_seq \l__file_internal_seq } h/packagei \seq_map_inline:Nn \l__file_search_path_seq { \__ior_open:Nn \g__file_internal_ior { ##1 #1 } \ior_if_eof:NF \g__file_internal_ior { \tl_set:Nx #2 { ##1 #1 } \seq_map_break: } } h*packagei \cs_if_exist:NT \input@path { \seq_set_eq:NN \l__file_search_path_seq \l__file_saved_search_path_seq } h/packagei } (End definition for \file_add_path:nN. If nothing is found. This function is documented on page 160. 9130 9131 9132 \prg_new_protected_conditional:Npnn \file_if_exist:n #1 { T . 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 \cs_new_protected:Npn \file_add_path:nN #1 { \__file_name_sanitize:nn {#1} { \__file_add_path:nN } } \cs_new_protected:Npn \__file_add_path:nN #1#2 { \__ior_open:Nn \g__file_internal_ior {#1} \ior_if_eof:NTF \g__file_internal_ior { \__file_add_path_search:nN {#1} #2 } { \tl_set:Nn #2 {#1} } \ior_close:N \g__file_internal_ior } \cs_new_protected:Npn \__file_add_path_search:nN #1#2 { \tl_set:Nn #2 { \q_no_value } h*packagei \cs_if_exist:NT \input@path { \seq_set_eq:NN \l__file_saved_search_path_seq \l__file_search_path_seq \seq_set_split:NnV \l__file_internal_seq { . The first location is of course treated as the correct one. whereas if the file was not located then the return value will be \q_no_value. the path will contain something. a search has to be made looking at each potential path in turn.) \file_if_exist:nTF The test for the existence of a file is a wrapper around the function to add a path to a file.\file_add_path:nN \__file_add_path:nN \__file_add_path_search:nN The way to test if a file exists is to try to open it: if it does not exist then TEX will report end-of-file. ) \file_input:n Loading a file is done in a safe way. Push the file name on the \g__file_stack_seq. } 9150 { \__file_input_aux:n {#1} } 9151 { \__file_input_aux:o { \tl_to_str:n { #1 . or \@filelist in package mode. \__file_input_aux:n either \g__file_record_seq. This function is documented on page 160. checking first that the file exists and loading only \__file_input:n\__file_input:V if it does.\quark_if_no_value:NTF \l__file_internal_name_tl { \prg_return_false: } { \prg_return_true: } 9133 9134 9135 9136 } (End definition for \file_if_exist:nTF.) \file_path_include:n \file_path_remove:n \__file_path_include:n Wrapper functions to manage the search path. tex } } } 9152 } 9153 \cs_generate_variant:Nn \__file_input:n { V } 9154 \cs_new_protected:Npn \__file_input_aux:n #1 9155 { 9156 h*initexi 9157 \seq_gput_right:Nn \g__file_record_seq {#1} 9158 h/initexi 9159 h*packagei 9160 \clist_if_exist:NTF \@filelist 9161 { \@addtofilelist {#1} } 9162 { \seq_gput_right:Nn \g__file_record_seq {#1} } 9163 h/packagei 9164 \seq_gpush:No \g__file_stack_seq \g_file_current_name_tl 9165 \tl_gset:Nn \g_file_current_name_tl {#1} 9166 \tex_input:D #1 \c_space_tl 9167 \seq_gpop:NN \g__file_stack_seq \l__file_internal_tl 9168 \tl_gset_eq:NN \g_file_current_name_tl \l__file_internal_tl 9169 } 9170 \cs_generate_variant:Nn \__file_input_aux:n { o } (End definition for \file_input:n. and add it to the file list. \__file_input_aux:o 9137 \cs_new_protected:Npn \file_input:n #1 9138 { 9139 \file_add_path:nN {#1} \l__file_internal_name_tl 9140 \quark_if_no_value:NTF \l__file_internal_name_tl 9141 { 9142 \__file_name_sanitize:nn {#1} 9143 { \__msg_kernel_error:nnx { kernel } { file-not-found } } 9144 } 9145 { \__file_input:V \l__file_internal_name_tl } 9146 } 9147 \cs_new_protected:Npn \__file_input:n #1 9148 { 9149 \tl_if_in:nnTF {#1} { . 9171 9172 9173 \cs_new_protected:Npn \file_path_include:n #1 { \__file_name_sanitize:nn {#1} { \__file_path_include:n } } \cs_new_protected:Npn \__file_path_include:n #1 482 . This function is documented on page 160. File names recorded in \@filelist must be turned to strings before being added to \g__file_record_seq.) When used as a package.{ 9174 \seq_if_in:NnF \l__file_search_path_seq {#1} { \seq_put_right:Nn \l__file_search_path_seq {#1} } 9175 9176 9177 9178 9179 9180 9181 9182 } \cs_new_protected:Npn \file_path_remove:n #1 { \__file_name_sanitize:nn {#1} { \seq_remove_all:Nn \l__file_search_path_seq } } (End definition for \file_path_include:n. In package mode. there is a need to hold onto the standard file list as well as the new one here. This function is documented on page 161. turning each file name into a string.) \file_list: A function to list all files used to the log. 9201 9202 9203 9204 9205 9206 9207 h*packagei \AtBeginDocument { \clist_map_inline:Nn \@filelist { \seq_gput_right:No \g__file_record_seq { \tl_to_str:n {#1} } } } h/packagei 19. This function is documented on page 161. 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 \cs_new_protected_nopar:Npn \file_list: { \seq_set_eq:NN \l__file_internal_seq \g__file_record_seq h*packagei \clist_if_exist:NT \@filelist { \clist_map_inline:Nn \@filelist { \seq_put_right:No \l__file_internal_seq { \tl_to_str:n {##1} } } } h/packagei \seq_remove_duplicates:N \l__file_internal_seq \iow_log:n { *~File~List~* } \seq_map_inline:Nn \l__file_internal_seq { \iow_log:n {##1} } \iow_log:n { ************* } } (End definition for \file_list:. if \@filelist is still defined. we need to take it into account (we capture it \AtBeginDocument into \g__file_record_seq). without duplicates.2 9208 Input operations h@@=iori 483 . 11 . so the starting point varies! 9210 9211 9212 9213 9214 \seq_new:N \g__ior_streams_seq h*initexi \seq_gset_split:Nnn \g__ior_streams_seq { . 7 . 9 .2. 8 .) 19. In format mode. This variable is documented on page ??.) \g__ior_streams_prop The name of the file attached to each stream is tracked in a property list. If those two tests pass. The file name is sanitized to deal with active characters. Unlike writing.2 \ior_new:N \ior_new:c Stream management Reserving a new stream is done by defining the name as equal to using the terminal. 5 . 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 \cs_new_protected:Npn \ior_open:Nn #1#2 { \__file_name_sanitize:nn {#2} { \__ior_open_aux:Nn #1 } } \cs_generate_variant:Nn \ior_open:Nn { c } \cs_new_protected:Npn \__ior_open_aux:Nn #1#2 { \file_add_path:nN {#2} \l__file_internal_name_tl \quark_if_no_value:NTF \l__file_internal_name_tl { \__msg_kernel_error:nnx { kernel } { file-not-found } {#2} } { \__ior_open:No #1 \l__file_internal_name_tl } } 484 . then pass the information on to the lower-level function which deals with streams. 3 . 6 .2. 13 . 9215 \tl_new:N \l__ior_stream_tl (End definition for \l__ior_stream_tl. 9209 \cs_new_eq:NN \c_term_ior \c_sixteen (End definition for \c_term_ior. 12 . These functions are documented on page ??. 4 .) \g__ior_streams_seq A list of the currently-available input streams to be used as a stack. 9220 9221 \cs_new_protected:Npn \ior_new:N #1 { \cs_new_eq:NN #1 \c_term_ior } \cs_generate_variant:Nn \ior_new:N { c } (End definition for \ior_new:N and \ior_new:c. 2 . } { 0 . 1 . 14 . This variable is documented on page ??. This variable is documented on page 165. while the package requests streams to LATEX 2ε as they are needed (initially none are needed).1 \c_term_ior Variables and constants Reading from the terminal (with a prompt) is done using a positive but non-existent stream number. there is no concept of reading from the log. 15 } h/initexi (End definition for \g__ior_streams_seq. all streams (from 0 to 15) are available. This variable is documented on page ??. 10 .) \l__ior_stream_tl Used to recover the raw stream number from the stack.19.) \ior_open:Nn \ior_open:cn \__ior_open_aux:Nn Opening an input stream requires a bit of pre-processing. before an auxiliary adds a path and checks that the file really exists. 9216 9217 9218 9219 \prop_new:N \g__ior_streams_prop h*packagei \prop_gput:Nnn \g__ior_streams_prop { 0 } { LaTeX2e~reserved } h/packagei (End definition for \g__ior_streams_prop. (End definition for \ior_open:Nn and \ior_open:cn. These functions are documented on page ??.) \ior_open:NnTF \ior_open:cnTF \__ior_open_aux:NnTF Much the same idea for opening a read with a conditional, except the auxiliary function does not issue an error if the file is not found. 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 \prg_new_protected_conditional:Npnn \ior_open:Nn #1#2 { T , F , TF } { \__file_name_sanitize:nn {#2} { \__ior_open:NnTF #1 } } \cs_generate_variant:Nn \ior_open:NnT { c } \cs_generate_variant:Nn \ior_open:NnF { c } \cs_generate_variant:Nn \ior_open:NnTF { c } \cs_new_protected:Npn \__ior_open_aux:NnTF #1#2 { \file_add_path:nN {#2} \l__file_internal_name_tl \quark_if_no_value:NTF \l__file_internal_name_tl { \prg_return_false: } { \__ior_open:No #1 \l__file_internal_name_tl \prg_return_true: } } (End definition for \ior_open:Nn and \ior_open:cn. These functions are documented on page ??.) \__ior_open:Nn \__ior_open:No \__ior_open_stream:Nn The stream allocation itself uses the fact that there is a list of all of those available, so allocation is simply a question of using the number at the top of the list. In package mode, life gets more complex as it’s important to keep things in sync. That is done using a two-part approach: any streams that have already been taken up by ior but are now free are tracked, so we first try those. If that fails, ask LATEX 2ε for a new stream and use that number (after a bit of conversion). 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 \cs_new_protected:Npn \__ior_open:Nn #1#2 { \ior_close:N #1 \seq_gpop:NNTF \g__ior_streams_seq \l__ior_stream_tl { \__ior_open_stream:Nn #1 {#2} } h*initexi { \__msg_kernel_fatal:nn { kernel } { input-streams-exhausted } } h/initexi h*packagei { \newread #1 \tl_set:Nx \l__ior_stream_tl { \int_eval:n {#1} } \__ior_open_stream:Nn #1 {#2} } h/packagei } \cs_generate_variant:Nn \__ior_open:Nn { No } \cs_new_protected:Npn \__ior_open_stream:Nn #1#2 { \tex_global:D \tex_chardef:D #1 = \l__ior_stream_tl \scan_stop: \prop_gput:NVn \g__ior_streams_prop #1 {#2} \tex_openin:D #1 #2 \scan_stop: 485 } 9269 (End definition for \__ior_open:Nn and \__ior_open:No. These functions are documented on page ??.) \ior_close:N \ior_close:c Closing a stream means getting rid of it at the TEX level and removing from the various data structures. Unless the name passed is an invalid stream number (outside the range [0, 15]), it can be closed. On the other hand, it only gets added to the stack if it was not already there, to avoid duplicates building up. 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 \cs_new_protected:Npn \ior_close:N #1 { \int_compare:nT { \c_minus_one < #1 < \c_sixteen } { \tex_closein:D #1 \prop_gremove:NV \g__ior_streams_prop #1 \seq_if_in:NVF \g__ior_streams_seq #1 { \seq_gpush:NV \g__ior_streams_seq #1 } \cs_gset_eq:NN #1 \c_term_ior } } \cs_generate_variant:Nn \ior_close:N { c } (End definition for \ior_close:N and \ior_close:c. These functions are documented on page ??.) \ior_list_streams: \__ior_list_streams:Nn Show the property lists, but with some “pretty printing”. See the l3msg module. If there are no open read streams, issue the message show-no-stream, and show an empty token list. If there are open read streams, format them with \__msg_show_item_unbraced:nn, and with the message show-open-streams. 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 \cs_new_protected_nopar:Npn \ior_list_streams: { \__ior_list_streams:Nn \g__ior_streams_prop { input } } \cs_new_protected:Npn \__ior_list_streams:Nn #1#2 { \__msg_term:nnn { LaTeX / kernel } { \prop_if_empty:NTF #1 { show-no-stream } { show-open-streams } } {#2} \__msg_show_variable:n { \prop_map_function:NN #1 \__msg_show_item_unbraced:nn } } (End definition for \ior_list_streams:. This function is documented on page 162.) 19.2.3 \if_eof:w Reading input The primitive conditional 9292 \cs_new_eq:NN \if_eof:w \tex_ifeof:D (End definition for \if_eof:w.) \ior_if_eof_p:N \ior_if_eof:NTF To test if some particular input stream is exhausted the following conditional is provided. 9293 9294 9295 9296 \prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } { \cs_if_exist:NTF #1 { 486 \if_int_compare:w #1 = \c_sixteen \prg_return_true: \else: \if_eof:w #1 \prg_return_true: \else: \prg_return_false: \fi: \fi: 9297 9298 9299 9300 9301 9302 9303 9304 9305 } { \prg_return_true: } 9306 9307 } 9308 (End definition for \ior_if_eof:N. These functions are documented on page 163.) \ior_get:NN And here we read from files. 9309 9310 \cs_new_protected:Npn \ior_get:NN #1#2 { \tex_read:D #1 to #2 } (End definition for \ior_get:NN. This function is documented on page 162.) \ior_get_str:NN Reading as strings is a more complicated wrapper, as we wish to remove the endline character. 9311 9312 9313 9314 9315 9316 9317 9318 9319 \cs_new_protected:Npn \ior_get_str:NN #1#2 { \use:x { \int_set_eq:NN \tex_endlinechar:D \c_minus_one \exp_not:n { \etex_readline:D #1 to #2 } \int_set:Nn \tex_endlinechar:D { \int_use:N \tex_endlinechar:D } } } (End definition for \ior_get_str:NN. This function is documented on page 162.) \g__file_internal_ior Needed by the higher-level code, but cannot be created until here. 9320 \ior_new:N \g__file_internal_ior (End definition for \g__file_internal_ior. This variable is documented on page ??.) 19.3 9321 Output operations h@@=iowi There is a lot of similarity here to the input operations, at least for many of the basics. Thus quite a bit is copied from the earlier material with minor alterations. 19.3.1 Variables and constants \c_log_iow \c_term_iow Here we allocate two output streams for writing to the transcript file only (\c_log_iow) and to both the terminal and transcript file (\c_term_iow). 9322 9323 \cs_new_eq:NN \c_log_iow \c_minus_one \cs_new_eq:NN \c_term_iow \c_sixteen (End definition for \c_log_iow and \c_term_iow. These variables are documented on page 165.) 487 \g__iow_streams_seq A list of the currently-available input streams to be used as a stack. Things are done differently in format and package mode, so the starting point varies! 9324 9325 9326 9327 \seq_new:N \g__iow_streams_seq h*initexi \seq_gset_eq:NN \g__iow_streams_seq \g__ior_streams_seq h/initexi (End definition for \g__iow_streams_seq. This variable is documented on page ??.) \l__iow_stream_tl Used to recover the raw stream number from the stack. 9328 \tl_new:N \l__iow_stream_tl (End definition for \l__iow_stream_tl. This variable is documented on page ??.) \g__iow_streams_prop As for reads, but with more reserved as LATEX 2ε takes up a few here. 9329 9330 9331 9332 9333 9334 \prop_new:N \g__iow_streams_prop h*packagei \prop_put:Nnn \g__iow_streams_prop { 0 } { LaTeX2e~reserved } \prop_put:Nnn \g__iow_streams_prop { 1 } { LaTeX2e~reserved } \prop_put:Nnn \g__iow_streams_prop { 2 } { LaTeX2e~reserved } h/packagei (End definition for \g__iow_streams_prop. This variable is documented on page ??.) 19.4 \iow_new:N \iow_new:c Stream management Reserving a new stream is done by defining the name as equal to writing to the terminal: odd but at least consistent. 9335 9336 \cs_new_protected:Npn \iow_new:N #1 { \cs_new_eq:NN #1 \c_term_iow } \cs_generate_variant:Nn \iow_new:N { c } (End definition for \iow_new:N and \iow_new:c. These functions are documented on page ??.) \iow_open:Nn \iow_open:cn \__iow_open:Nn \__iow_open_stream:Nn The same idea as for reading, but without the path and without the need to allow for a conditional version. 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 \cs_new_protected:Npn \iow_open:Nn #1#2 { \__file_name_sanitize:nn {#2} { \__iow_open:Nn #1 } } \cs_generate_variant:Nn \iow_open:Nn { c } \cs_new_protected:Npn \__iow_open:Nn #1#2 { \iow_close:N #1 \seq_gpop:NNTF \g__iow_streams_seq \l__iow_stream_tl { \__iow_open_stream:Nn #1 {#2} } h*initexi { \__msg_kernel_fatal:nn { kernel } { output-streams-exhausted } } h/initexi h*packagei { \newwrite #1 \tl_set:Nx \l__iow_stream_tl { \int_eval:n {#1} } \__iow_open_stream:Nn #1 {#2} } 488 9354 9355 9356 9357 9358 9359 9360 9361 9362 h/packagei } \cs_generate_variant:Nn \__iow_open:Nn { No } \cs_new_protected:Npn \__iow_open_stream:Nn #1#2 { \tex_global:D \tex_chardef:D #1 = \l__iow_stream_tl \scan_stop: \prop_gput:NVn \g__iow_streams_prop #1 {#2} \tex_immediate:D \tex_openout:D #1 #2 \scan_stop: } (End definition for \iow_open:Nn and \iow_open:cn. These functions are documented on page ??.) \iow_close:N \iow_close:c Closing a stream is not quite the reverse of opening one. First, the close operation is easier than the open one, and second as the stream is actually a number we can use it directly to show that the slot has been freed up. 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 \cs_new_protected:Npn \iow_close:N #1 { \int_compare:nT { \c_minus_one < #1 < \c_sixteen } { \tex_immediate:D \tex_closeout:D #1 \prop_gremove:NV \g__iow_streams_prop #1 \seq_if_in:NVF \g__iow_streams_seq #1 { \seq_gpush:NV \g__iow_streams_seq #1 } \cs_gset_eq:NN #1 \c_term_ior } } \cs_generate_variant:Nn \iow_close:N { c } (End definition for \iow_close:N and \iow_close:c. These functions are documented on page ??.) \iow_list_streams: \__iow_list_streams:Nn Done as for input, but with a copy of the auxiliary so the name is correct. 9375 9376 9377 \cs_new_protected_nopar:Npn \iow_list_streams: { \__iow_list_streams:Nn \g__iow_streams_prop { output } } \cs_new_eq:NN \__iow_list_streams:Nn \__ior_list_streams:Nn (End definition for \iow_list_streams:. This function is documented on page ??.) 19.4.1 \iow_shipout_x:Nn \iow_shipout_x:Nx Deferred writing First the easy part, this is the primitive, which expects its argument to be braced. 9378 9379 9380 \cs_new_protected:Npn \iow_shipout_x:Nn #1#2 { \tex_write:D #1 {#2} } \cs_generate_variant:Nn \iow_shipout_x:Nn { Nx } (End definition for \iow_shipout_x:Nn and \iow_shipout_x:Nx. These functions are documented on page ??.) \iow_shipout:Nn \iow_shipout:Nx With ε-TEX available deferred writing without expansion is easy. 9381 9382 9383 \cs_new_protected:Npn \iow_shipout:Nn #1#2 { \tex_write:D #1 { \exp_not:n {#2} } } \cs_generate_variant:Nn \iow_shipout:Nn { Nx } (End definition for \iow_shipout:Nn and \iow_shipout:Nx. These functions are documented on page ??.) 489 19.4.2 \iow_now:Nn \iow_now:Nx Immediate writing This routine writes the second argument onto the output stream without expansion. If this stream isn’t open, the output goes to the terminal instead. If the first argument is no output stream at all, we get an internal error. We don’t use the expansion done by \write to get the Nx variant, because it differs in subtle ways from x-expansion, namely, macro parameter characters would not need to be doubled. 9384 9385 9386 \cs_new_protected:Npn \iow_now:Nn #1#2 { \tex_immediate:D \tex_write:D #1 { \exp_not:n {#2} } } \cs_generate_variant:Nn \iow_now:Nn { Nx } (End definition for \iow_now:Nn and \iow_now:Nx. These functions are documented on page ??.) \iow_log:n \iow_log:x \iow_term:n \iow_term:x Writing to the log and the terminal directly are relatively easy. 9387 9388 9389 9390 \cs_set_protected_nopar:Npn \cs_new_protected_nopar:Npn \cs_set_protected_nopar:Npn \cs_new_protected_nopar:Npn \iow_log:x \iow_log:n \iow_term:x \iow_term:n { { { { \iow_now:Nx \iow_now:Nn \iow_now:Nx \iow_now:Nn \c_log_iow \c_log_iow \c_term_iow \c_term_iow } } } } (End definition for \iow_log:n and \iow_log:x. These functions are documented on page ??.) 19.4.3 \iow_newline: Special characters for writing Global variable holding the character that forces a new line when something is written to an output stream 9391 \cs_new_nopar:Npn \iow_newline: { ^^J } (End definition for \iow_newline:. This function is documented on page 164.) \iow_char:N Function to write any escaped char to an output stream. 9392 \cs_new_eq:NN \iow_char:N \cs_to_str:N (End definition for \iow_char:N. This function is documented on page 163.) 19.4.4 Hard-wrapping lines to a character count The code here implements a generic hard-wrapping function. This is used by the messaging system, but is designed such that it is available for other uses. \l_iow_line_count_int This is the “raw” number of characters in a line which can be written to the terminal. The standard value is the line length typically used by TEXLive and MikTEX. 9393 9394 \int_new:N \l_iow_line_count_int \int_set:Nn \l_iow_line_count_int { 78 } (End definition for \l_iow_line_count_int. This variable is documented on page 165.) \l__iow_target_count_int This stores the target line count: the full number of characters in a line, minus any part for a leader at the start of each line. 9395 \int_new:N \l__iow_target_count_int (End definition for \l__iow_target_count_int.) 490 \l__iow_current_line_int These store the number of characters in the line and word currently being constructed, \l__iow_current_word_int and the current indentation, respectively. \l__iow_current_indentation_int 9396 \int_new:N \l__iow_current_line_int 9397 \int_new:N \l__iow_current_word_int 9398 \int_new:N \l__iow_current_indentation_int (End definition for \l__iow_current_line_int , \l__iow_current_word_int , and \l__iow_current_indentation_int.) \l__iow_current_line_tl These hold the current line of text and current word, and a number of spaces for inden\l__iow_current_word_tl tation, respectively. \l__iow_current_indentation_tl 9399 \tl_new:N \l__iow_current_line_tl 9400 \tl_new:N \l__iow_current_word_tl 9401 \tl_new:N \l__iow_current_indentation_tl (End definition for \l__iow_current_line_tl , \l__iow_current_word_tl , and \l__iow_current_indentation_tl.) \l__iow_wrap_tl Used for the expansion step before detokenizing, and for the output from wrapping text: fully expanded and with lines which are not overly long. 9402 \tl_new:N \l__iow_wrap_tl (End definition for \l__iow_wrap_tl.) \l__iow_newline_tl The token list inserted to produce the new line, with the hrun-on texti. 9403 \tl_new:N \l__iow_newline_tl (End definition for \l__iow_newline_tl.) \l__iow_line_start_bool Boolean to avoid adding a space at the beginning of forced newlines, and to know when to add the indentation. 9404 \bool_new:N \l__iow_line_start_bool (End definition for \l__iow_line_start_bool.) \c_catcode_other_space_tl Lowercase a character with category code 12 to produce an “other” space. We can do everything within the group, because \tl_const:Nn defines its argument globally. 9405 9406 9407 9408 9409 \group_begin: \char_set_catcode_other:N \* \char_set_lccode:nn {‘\*} {‘\ } \tl_to_lowercase:n { \tl_const:Nn \c_catcode_other_space_tl { * } } \group_end: (End definition for \c_catcode_other_space_tl. This function is documented on page 165.) \c__iow_wrap_marker_tl \c__iow_wrap_end_marker_tl \c__iow_wrap_newline_marker_tl \c__iow_wrap_indent_marker_tl \c__iow_wrap_unindent_marker_tl Every special action of the wrapping code is preceeded by the same recognizable string, \c__iow_wrap_marker_tl. Upon seeing that “word”, the wrapping code reads one spacedelimited argument to know what operation to perform. The setting of \escapechar here is not very important, but makes \c__iow_wrap_marker_tl look nicer. 9410 9411 9412 9413 9414 9415 \group_begin: \int_set_eq:NN \tex_escapechar:D \c_minus_one \tl_const:Nx \c__iow_wrap_marker_tl { \tl_to_str:n { \^^I \^^O \^^W \^^_ \^^W \^^R \^^A \^^P } } \group_end: \tl_map_inline:nn 491 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 { { end } { newline } { indent } { unindent } } { \tl_const:cx { c__iow_wrap_ #1 _marker_tl } { \c_catcode_other_space_tl \c__iow_wrap_marker_tl \c_catcode_other_space_tl #1 \c_catcode_other_space_tl } } (End definition for \c__iow_wrap_marker_tl. This function is documented on page 165.) \iow_indent:n \__iow_indent:n We give a dummy (protected) definition to \iow_indent:n when outside messages. Within wrapped message, it places the instruction for increasing the indentation before its argument, and the instruction for unindenting afterwards. Note that there will be no forced line-break, so the indentation only changes when the next line is started. 9427 9428 9429 9430 9431 9432 9433 \cs_new_protected:Npn \iow_indent:n #1 { } \cs_new:Npx \__iow_indent:n #1 { \c__iow_wrap_indent_marker_tl #1 \c__iow_wrap_unindent_marker_tl } (End definition for \iow_indent:n. This function is documented on page 164.) \iow_wrap:nnnN The main wrapping function works as follows. First give \\, \␣ and other formatting commands the correct definition for messages, before fully-expanding the input. In package mode, the expansion uses LATEX 2ε ’s \protect mechanism. Afterwards, set the newline marker (two assignments to fully expand, then convert to a string) and its length, and initialize some registers. There is then a loop over each word in the input, which will do the actual wrapping. After the loop, the resulting text is passed on to the function which has been given as a post-processor. The argument #4 is available for additional set up steps for the output. The definition of \\ and \␣ use an “other” space rather than a normal space, because the latter might be absorbed by TEX to end a number or other f-type expansions. The \tl_to_str:N step converts the “other” space back to a normal space. 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 \cs_new_protected:Npn \iow_wrap:nnnN #1#2#3#4 { \group_begin: \int_set_eq:NN \tex_escapechar:D \c_minus_one \cs_set_nopar:Npx \{ { \token_to_str:N \{ } \cs_set_nopar:Npx \# { \token_to_str:N \# } \cs_set_nopar:Npx \} { \token_to_str:N \} } \cs_set_nopar:Npx \% { \token_to_str:N \% } \cs_set_nopar:Npx \~ { \token_to_str:N \~ } \int_set:Nn \tex_escapechar:D { 92 } \cs_set_eq:NN \\ \c__iow_wrap_newline_marker_tl 492 9445 9446 9447 9448 9449 9450 9451 9452 9453 \cs_set_eq:NN \ \c_catcode_other_space_tl \cs_set_eq:NN \iow_indent:n \__iow_indent:n #3 h*initexi \tl_set:Nx \l__iow_wrap_tl {#1} h/initexi h*packagei \protected@edef \l__iow_wrap_tl {#1} h/packagei This is a bit of a hack to measure the string length of the run on text without the l3str module (which is still experimental). This should be replaced once the string module is finalised with something a little cleaner. \tl_set:Nx \l__iow_newline_tl { \iow_newline: #2 } \tl_set:Nx \l__iow_newline_tl { \tl_to_str:N \l__iow_newline_tl } \tl_replace_all:Nnn \l__iow_newline_tl { ~ } { \c_space_tl } \int_set:Nn \l__iow_target_count_int { \l_iow_line_count_int - \tl_count:N \l__iow_newline_tl + \c_one } \int_zero:N \l__iow_current_indentation_int \tl_clear:N \l__iow_current_indentation_tl \int_zero:N \l__iow_current_line_int \tl_clear:N \l__iow_current_line_tl \bool_set_true:N \l__iow_line_start_bool \use:x { \exp_not:n { \tl_clear:N \l__iow_wrap_tl } \__iow_wrap_loop:w \tl_to_str:N \l__iow_wrap_tl \tl_to_str:N \c__iow_wrap_end_marker_tl \c_space_tl \c_space_tl \exp_not:N \q_stop } \exp_args:NNo \group_end: #4 \l__iow_wrap_tl 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 } (End definition for \iow_wrap:nnnN. This function is documented on page 164.) \__iow_wrap_loop:w The loop grabs one word in the input, and checks whether it is the special marker, or a normal word. 9476 9477 9478 9479 9480 9481 9482 \cs_new_protected:Npn \__iow_wrap_loop:w #1 ~ % { \tl_set:Nn \l__iow_current_word_tl {#1} \tl_if_eq:NNTF \l__iow_current_word_tl \c__iow_wrap_marker_tl { \__iow_wrap_special:w } { \__iow_wrap_word: } } (End definition for \__iow_wrap_loop:w.) \__iow_wrap_word: \__iow_wrap_word_fits: \__iow_wrap_word_newline: For a normal word, update the line count, then test if the current word would fit in the current line, and call the appropriate function. If the word fits in the current line, 493 add it to the line, preceded by a space unless it is the first word of the line. Otherwise, the current line is added to the result, with the run-on text. The current word (and its character count) are then put in the new line. 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 \cs_new_protected_nopar:Npn \__iow_wrap_word: { \int_set:Nn \l__iow_current_word_int { \__str_count_ignore_spaces:N \l__iow_current_word_tl } \int_add:Nn \l__iow_current_line_int { \l__iow_current_word_int } \int_compare:nNnTF \l__iow_current_line_int < \l__iow_target_count_int { \__iow_wrap_word_fits: } { \__iow_wrap_word_newline: } \__iow_wrap_loop:w } \cs_new_protected_nopar:Npn \__iow_wrap_word_fits: { \bool_if:NTF \l__iow_line_start_bool { \bool_set_false:N \l__iow_line_start_bool \tl_put_right:Nx \l__iow_current_line_tl { \l__iow_current_indentation_tl \l__iow_current_word_tl } \int_add:Nn \l__iow_current_line_int { \l__iow_current_indentation_int } } { \tl_put_right:Nx \l__iow_current_line_tl { ~ \l__iow_current_word_tl } \int_incr:N \l__iow_current_line_int } } \cs_new_protected_nopar:Npn \__iow_wrap_word_newline: { \tl_put_right:Nx \l__iow_wrap_tl { \l__iow_current_line_tl \l__iow_newline_tl } \int_set:Nn \l__iow_current_line_int { \l__iow_current_word_int + \l__iow_current_indentation_int } \tl_set:Nx \l__iow_current_line_tl { \l__iow_current_indentation_tl \l__iow_current_word_tl } } (End definition for \__iow_wrap_word:. This function is documented on page 164.) \__iow_wrap_special:w \__iow_wrap_newline:w \__iow_wrap_indent:w \__iow_wrap_unindent:w \__iow_wrap_end:w When the “special” marker is encountered, read what operation to perform, as a spacedelimited argument, perform it, and remember to loop. In fact, to avoid spurious spaces when two special actions follow each other, we look ahead for another copy of the marker. Forced newlines are almost identical to those caused by overflow, except that here the word is empty. To indent more, add four spaces to the start of the indentation token list. 494 To reduce indentation, rebuild the indentation token list using \prg_replicate:nn. At the end, we simply save the last line (without the run-on text), and prevent the loop. 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 \cs_new_protected:Npn \__iow_wrap_special:w #1 ~ #2 ~ #3 ~ % { \use:c { __iow_wrap_#1: } \str_if_eq_x:nnTF { #2~#3 } { ~ \c__iow_wrap_marker_tl } { \__iow_wrap_special:w } { \__iow_wrap_loop:w #2 ~ #3 ~ } } \cs_new_protected_nopar:Npn \__iow_wrap_newline: { \tl_put_right:Nx \l__iow_wrap_tl { \l__iow_current_line_tl \l__iow_newline_tl } \int_zero:N \l__iow_current_line_int \tl_clear:N \l__iow_current_line_tl \bool_set_true:N \l__iow_line_start_bool } \cs_new_protected_nopar:Npx \__iow_wrap_indent: { \int_add:Nn \l__iow_current_indentation_int \c_four \tl_put_right:Nx \exp_not:N \l__iow_current_indentation_tl { \c_space_tl \c_space_tl \c_space_tl \c_space_tl } } \cs_new_protected_nopar:Npn \__iow_wrap_unindent: { \int_sub:Nn \l__iow_current_indentation_int \c_four \tl_set:Nx \l__iow_current_indentation_tl { \prg_replicate:nn \l__iow_current_indentation_int { ~ } } } \cs_new_protected_nopar:Npn \__iow_wrap_end: { \tl_put_right:Nx \l__iow_wrap_tl { \l__iow_current_line_tl } \use_none_delimit_by_q_stop:w } (End definition for \__iow_wrap_special:w. This function is documented on page 164.) \__str_count_ignore_spaces:N \__str_count_ignore_spaces:n \__str_count_loop:NNNNNNNNN The wrapping code requires to measure the number of character in each word. This could be done with \tl_count:n, but it is ten times faster (literally) to use the code below. 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 \cs_new_nopar:Npn \__str_count_ignore_spaces:N { \exp_args:No \__str_count_ignore_spaces:n } \cs_new:Npn \__str_count_ignore_spaces:n #1 { \__int_value:w \__int_eval:w \exp_after:wN \__str_count_loop:NNNNNNNNN \tl_to_str:n {#1} { X8 } { X7 } { X6 } { X5 } { X4 } { X3 } { X2 } { X1 } { X0 } \q_stop \__int_eval_end: } \cs_new:Npn \__str_count_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 495 { 9564 \if_catcode:w X #9 \exp_after:wN \use_none_delimit_by_q_stop:w \else: 9 + \exp_after:wN \__str_count_loop:NNNNNNNNN \fi: 9565 9566 9567 9568 9569 9570 } 9571 (End definition for \__str_count_ignore_spaces:N. This function is documented on page 164.) 19.5 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 Messages \__msg_kernel_new:nnnn { kernel } { file-not-found } { File~’#1’~not~found. } { The~requested~file~could~not~be~found~in~the~current~directory,~ in~the~TeX~search~path~or~in~the~LaTeX~search~path. } \__msg_kernel_new:nnnn { kernel } { input-streams-exhausted } { Input~streams~exhausted } { TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ All~16~are~currently~in~use,~and~something~wanted~to~open~ another~one. } \__msg_kernel_new:nnnn { kernel } { output-streams-exhausted } { Output~streams~exhausted } { TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ All~16~are~currently~in~use,~and~something~wanted~to~open~ another~one. } \__msg_kernel_new:nnnn { kernel } { space-in-file-name } { Space~in~file~name~’#1’. } { Spaces~are~not~permitted~in~files~loaded~by~LaTeX: \\ Further~errors~may~follow! } 19.6 Deprecated functions Deprecated on 2012-06-28, for removal by 2012-12-31. \iow_wrap:xnnnN This was renamed and one unneed argument was removed. 9598 9599 9600 9601 h*deprecatedi \cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 { \iow_wrap:nnnN {#1} {#2} {#4} #5 } h/deprecatedi (End definition for \iow_wrap:xnnnN. This function is documented on page ??.) Deprecated on 2012-06-24, for removal by 2012-12-31. 496 \l_iow_line_length_int Simple rename. Here we copy the TEX register. 9602 9603 9604 h*deprecatedi \cs_new_eq:NN \l_iow_line_length_int \l_iow_line_count_int h/deprecatedi (End definition for \l_iow_line_length_int. This variable is documented on page ??.) \ior_to:NN \ior_gto:NN \ior_str_to:NN \ior_str_gto:NN The local variants are renames, while the global variants are deprecated and add the TEX primitive \global. 9605 9606 9607 9608 \cs_new_eq:NN \ior_to:NN \ior_get:NN \cs_new_protected_nopar:Npn \ior_gto:NN { \tex_global:D \ior_to:NN } \cs_new_eq:NN \ior_str_to:NN \ior_get_str:NN \cs_new_protected_nopar:Npn \ior_str_gto:NN { \tex_global:D \ior_str_to:NN } (End definition for \ior_to:NN and others. These functions are documented on page ??.) Deprecated on 2012-02-10, for removal by 2012-05-31. \iow_now_when_avail:Nn \iow_now_when_avail:Nx For writing only if the stream requested is open at all. 9609 9610 9611 9612 9613 9614 h*deprecatedi \cs_new_protected:Npn \iow_now_when_avail:Nn #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 } } \cs_new_protected:Npn \iow_now_when_avail:Nx #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 } } h/deprecatedi (End definition for \iow_now_when_avail:Nn and \iow_now_when_avail:Nx. These functions are documented on page ??.) Deprecated on 2011-05-27, for removal by 2011-08-31. \iow_now_buffer_safe:Nn \iow_now_buffer_safe:Nx This is much more easily done using the wrapping system: there is an expansion there, so a bit of a hack is needed. 9615 9616 9617 9618 9619 9620 h*deprecatedi \cs_new_protected:Npn \iow_now_buffer_safe:Nn #1#2 { \iow_wrap:xnnnN { \exp_not:n {#2} } { } \c_zero { } \iow_now:Nn #1 } \cs_new_protected:Npn \iow_now_buffer_safe:Nx #1#2 { \iow_wrap:xnnnN {#2} { } \c_zero { } \iow_now:Nn #1 } h/deprecatedi (End definition for \iow_now_buffer_safe:Nn and \iow_now_buffer_safe:Nx. These functions are documented on page ??.) \ior_open_streams: \iow_open_streams: Slightly misleading names. 9621 9622 9623 9624 h*deprecatedi \cs_new_eq:NN \ior_open_streams: \ior_list_streams: \cs_new_eq:NN \iow_open_streams: \iow_list_streams: h/deprecatedi (End definition for \ior_open_streams:. This function is documented on page ??.) 9625 h/initex | packagei 497 l3fp implementation 20 9626 h*packagei 9629 \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: 9630 h/packagei 9627 9628 l3fp-aux implementation 21 9631 h*initex | packagei 9632 h@@=fpi 22 Internal storage of floating points numbers A floating point number hX i is stored as \s__fp \__fp_chk:w hcasei hsigni hbodyi ; Here, hcasei is 0 for ±0, 1 for normal numbers, 2 for ±∞, and 3 for nan, and hsigni is 0 for positive numbers, 1 for nans, and 2 for negative numbers. The hbodyi of normal numbers is {hexponenti} {hX1 i} {hX2 i} {hX3 i} {hX4 i}, with X hX i = (−1)hsigni 10−hexponenti hXi i10−4i . i Calculations are done in base 10000, i.e. one myriad. The hexponenti lies between ±\c__fp_max_exponent_int = ±10000 inclusive. Additionally, positive and negative floating point numbers may only be stored with 1000 ≤ hX1 i < 10000. This requirement is necessary in order to preserve accuracy and speed. 22.1 \__fp_use_none_stop_f:n Using arguments and semicolons This function removes an argument (typically a digit) and replaces it by \exp_stop_f:, a marker which stops f-type expansion. 9633 \cs_new:Npn \__fp_use_none_stop_f:n #1 { \exp_stop_f: } (End definition for \__fp_use_none_stop_f:n.) \__fp_use_s:n \__fp_use_s:nn Those functions place a semicolon after one or two arguments (typically digits). 9634 9635 \cs_new:Npn \__fp_use_s:n #1 { #1; } \cs_new:Npn \__fp_use_s:nn #1#2 { #1#2; } (End definition for \__fp_use_s:n and \__fp_use_s:nn.) \__fp_use_none_until_s:w \__fp_use_i_until_s:nw \__fp_use_ii_until_s:nnw Those functions select specific arguments among a set of arguments delimited by a semicolon. 9636 9637 9638 \cs_new:Npn \__fp_use_none_until_s:w #1; { } \cs_new:Npn \__fp_use_i_until_s:nw #1#2; {#1} \cs_new:Npn \__fp_use_ii_until_s:nnw #1#2#3; {#2} 498 (End definition for \__fp_use_none_until_s:w , \__fp_use_i_until_s:nw , and \__fp_use_ii_until_s:nnw.) \__fp_reverse_args:Nww Many internal functions take arguments delimited by semicolons, and it is occasionally useful to swap two such arguments. 9639 \cs_new:Npn \__fp_reverse_args:Nww #1 #2; #3; { #1 #3; #2; } (End definition for \__fp_reverse_args:Nww.) 22.2 \s__fp \__fp_chk:w Constants, and structure of floating points Floating points numbers all start with \s__fp \__fp_chk:w, where \s__fp is equal to the TEX primitive \relax, and \__fp_chk:w is protected. The rest of the floating point number is made of characters (or \relax). This ensures that nothing expands under f-expansion, nor under x-expansion. However, when typeset, \s__fp does nothing, and \__fp_chk:w is expanded. We define \__fp_chk:w to produce an error. 9640 9641 9642 9643 9644 9645 \__scan_new:N \s__fp \cs_new_protected:Npn \__fp_chk:w #1 ; { \__msg_kernel_error:nnx { kernel } { misused-fp } { \fp_to_tl:n { \s__fp \__fp_chk:w #1 ; } } } (End definition for \s__fp and \__fp_chk:w.) \s__fp_mark \s__fp_stop Aliases of \tex_relax:D, used to terminate expressions. 9646 9647 \__scan_new:N \s__fp_mark \__scan_new:N \s__fp_stop (End definition for \s__fp_mark and \s__fp_stop.) \s__fp_invalid \s__fp_underflow \s__fp_overflow \s__fp_division \s__fp_exact A couple of scan marks used to indicate where special floating point numbers come from. 9648 9649 9650 9651 9652 \__scan_new:N \__scan_new:N \__scan_new:N \__scan_new:N \__scan_new:N \s__fp_invalid \s__fp_underflow \s__fp_overflow \s__fp_division \s__fp_exact (End definition for \s__fp_invalid and others.) \c_zero_fp \c_minus_zero_fp \c_inf_fp \c_minus_inf_fp \c_nan_fp The special floating points. All of them have the form \s__fp \__fp_chk:w hcasei hsigni \s__fp_... ; where the dots in \s__fp_... are one of invalid, underflow, overflow, division, exact, describing how the floating point was created. We define the floating points here as “exact”. 9653 9654 9655 9656 9657 \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \c_zero_fp \c_minus_zero_fp \c_inf_fp \c_minus_inf_fp \c_nan_fp { { { { { \s__fp \s__fp \s__fp \s__fp \s__fp \__fp_chk:w \__fp_chk:w \__fp_chk:w \__fp_chk:w \__fp_chk:w 0 0 2 2 3 0 2 0 2 1 \s__fp_exact \s__fp_exact \s__fp_exact \s__fp_exact \s__fp_exact (End definition for \c_zero_fp and others. These variables are documented on page ??.) 499 ; ; ; ; ; } } } } } ) \__fp_zero_fp:N \__fp_inf_fp:N In case of overflow or underflow. 9659 9660 \cs_new:Npn \__fp_zero_fp:N #1 { \s__fp \__fp_chk:w 0 #1 \s__fp_underflow . we need to evaluate log(a · 10n ) = log(a) + n log(10) as a fixed point number.) \__fp_exponent:w For normal numbers. the function expands to the exponent. } \cs_new:Npn \__fp_max_fp:N #1 { \s__fp \__fp_chk:w 1 #1 { \int_use:N \c__fp_max_exponent_int } {9999} {9999} {9999} {9999} .) \__fp_neg_sign:N When appearing in an integer expression or after \__int_value:w. we need to output the smallest or biggest positive or negative finite numbers. Larger numbers are rounded to ±∞. } \cs_new:Npn \__fp_inf_fp:N #1 { \s__fp \__fp_chk:w 2 #1 \s__fp_overflow .\c__fp_max_exponent_int Normal floating point numbers have an exponent at most max_exponent in absolute value.\c__fp_max_exponent_int } } {1000} {0000} {0000} {0000} . 9673 9674 9675 9676 9677 9678 9679 9680 9681 \cs_new:Npn \__fp_exponent:w \s__fp \__fp_chk:w #1 { \if_meaning:w 1 #1 \exp_after:wN \__fp_use_ii_until_s:nnw \else: \exp_after:wN \__fp_use_i_until_s:nw \exp_after:wN 0 \fi: } (End definition for \__fp_exponent:w. because we can multiply n with each block safely. numbers are rounded to zero. namely 0 (positive) is turned to 2 (negative). 9658 \int_const:Nn \c__fp_max_exponent_int { 10000 } (End definition for \c__fp_max_exponent_int.#1 \__int_eval_end: } 500 . 1 (nan) to 1. and digits beyond 10−max_exponent are rounded away. } (End definition for \__fp_zero_fp:N and \__fp_inf_fp:N. Why this choice of limits? When computing (a · 10n )( b · 10p ). and 2 to 0. we have to output a zero or infinity with a given sign. hence the true minimum exponent is −max_exponent − 16. which we manipulate as blocks of 4 digits. otherwise to 0. Multiplying such a fixed point number by n < 10000 is much cheaper than larger n. } (End definition for \__fp_max_fp:N and \__fp_min_fp:N.) \__fp_max_fp:N \__fp_min_fp:N In some cases. beyond this. 9682 9683 \cs_new:Npn \__fp_neg_sign:N #1 { \__int_eval:w \c_two . 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 \cs_new:Npn \__fp_min_fp:N #1 { \s__fp \__fp_chk:w 1 #1 { \int_eval:n { . this expands to the sign opposite to #1. Smaller numbers are subnormal (not implemented yet). and leaves the floating point number unchanged. possibly underflowed to ±0 or overflowed to ±∞. Outputs the corresponding floating point number. and exact zero Expects the sign and the exponent in some order. from the much simpler special floating points. 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 \cs_new:Npn \__fp_sanitize:Nw #1 #2.(End definition for \__fp_neg_sign:N.\c__fp_max_exponent_int \c_two \else: \if_meaning:w 1 #1 \c_three \else: \c_zero \fi: \fi: \fi: \or: \exp_after:wN \__fp_overflow:w \or: \exp_after:wN \__fp_underflow:w \or: \exp_after:wN \__fp_sanitize_zero:w \fi: \s__fp \__fp_chk:w 1 #1 {#2} } \cs_new:Npn \__fp_sanitize:wN #1.) 22. then the significand (which we don’t touch). 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 \cs_new:Npn \__fp_exp_after_o:w \s__fp \__fp_chk:w #1 { \if_meaning:w 1 #1 \exp_after:wN \__fp_exp_after_normal:nNNw \else: \exp_after:wN \__fp_exp_after_special:nNNw \fi: { } #1 } \cs_new:Npn \__fp_exp_after_o:nw #1 \s__fp \__fp_chk:w #2 { \if_meaning:w 1 #2 \exp_after:wN \__fp_exp_after_normal:nNNw \else: \exp_after:wN \__fp_exp_after_special:nNNw \fi: 501 .3 \__fp_sanitize:Nw \__fp_sanitize:wN \__fp_sanitize_zero:w Overflow. } \cs_new:Npn \__fp_sanitize_zero:w \s__fp \__fp_chk:w #1 #2 #3. { \if_case:w \if_int_compare:w #2 > \c__fp_max_exponent_int \c_one \else: \if_int_compare:w #2 < . underflow. We first distinguish normal floating points.) 22. then hits those tokens with either o-expansion (one \exp_after:wN) or f-expansion. #2 { \__fp_sanitize:Nw #2 #1. The functions \__fp_underflow:w and \__fp_overflow:w are defined in l3fp-traps.4 \__fp_exp_after_o:w \__fp_exp_after_o:nw \__fp_exp_after_f:nw Expanding after a floating point number Places htokensi (empty in the case of \__fp_exp_after_o:w) between the hfloating pointi and the hmore tokensi. which have a significand. { \c_zero_fp } (End definition for \__fp_sanitize:Nw and \__fp_sanitize:wN. These functions are documented on page ??. since we have many tokens to jump over. { \s__fp \__fp_chk:w 1 #1 {#2} {#3} {#4} {#5} {#6} . #1 } \cs_new:Npn \__fp_exp_after_normal:Nwwwww #1 #2. That may be changed some day.) \__fp_exp_after_special:nNNw Special floating point numbers are easy to jump over since they contain few tokens. \__int_value:w 1 #4 \exp_after:wN . { \exp_after:wN \__fp_exp_after_normal:Nwwwww \exp_after:wN #2 \__int_value:w #3 \exp_after:wN . \__int_value:w 1 #5 \exp_after:wN . This function is documented on page ??.) \__fp_exp_after_array_f:w \__fp_exp_after_stop_f:nw 9750 9751 \cs_new:Npn \__fp_exp_after_array_f:w #1 { 502 .) \__fp_exp_after_normal:nNNw For normal floating point numbers. 1 #3 . 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 \cs_new:Npn \__fp_exp_after_normal:nNNw #1 1 #2 #3 #4#5#6#7. } (End definition for \__fp_exp_after_normal:nNNw. Here it would be slightly better if the digits were not braced but instead were delimited arguments (for instance delimited by . #1 } (End definition for \__fp_exp_after_special:nNNw. 1 #6 .9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 { #1 } #2 } \cs_new:Npn \__fp_exp_after_f:nw #1 \s__fp \__fp_chk:w #2 { \if_meaning:w 1 #2 \exp_after:wN \__fp_exp_after_normal:nNNw \else: \exp_after:wN \__fp_exp_after_special:nNNw \fi: { \tex_romannumeral:D -‘0 #1 } #2 } (End definition for \__fp_exp_after_o:w.). 1 #4 . 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 \cs_new:Npn \__fp_exp_after_special:nNNw #1#2#3#4. 1 #5 . \__int_value:w 1 #7 \exp_after:wN . { \exp_after:wN \s__fp \exp_after:wN \__fp_chk:w \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN #4 \exp_after:wN . life is slightly harder. \__int_value:w 1 #6 \exp_after:wN . in turn. the auxiliary inserts + #1#2#3#4#5 . { {#2#3#4#5} {#6} } \exp_after:wN \pack:NNNNNw \int_use:N \__int_eval:w 1 0000 0000 + #1 . expands \exp_after:wN which triggers the third computation. The third computation’s value is 5 0000 0000 + 12345 × 8899. 503 . This method is very heavily relied upon in l3fp-basics. which allows us to compute several blocks of 4 digits in a nested manner. expanded after the result is computed. Adding 5 · 108 to the product allowed us to know how many digits to expect as long as the numbers to multiply are not too big. With simplified names. The idea is that adding 108 to the number ensures that it has exactly 9 digits. which combines the carry with the previous computation.\cs:w __fp_exp_after \__fp_type_from_scan:N #1 _f:nw \cs_end: { \__fp_exp_after_array_f:w } #1 9752 9753 9754 9755 9756 } \cs_new_eq:NN \__fp_exp_after_stop_f:nw \use_none:nn (End definition for \__fp_exp_after_array_f:w. and leaves + h5 digitsi for the initial computation. \cs_new:Npn \pack:NNNNNw #1 #2#3#4#5 #6. This function is documented on page ??. the result of this second computation will have 9 digits. and can then easily find which digits correspond to what position in the number. performing carries on the fly.5 Packing digits When a positive integer #1 is known to be less than 108 .) 22. moves the semi-colon delimiter. we would do \exp_after:wN \post_processing:w \int_use:N \__int_eval:w . The shifts nicely combine into 5 0000 0000/104 + 4 9995 0000 = 5 0000 0000. which starts a first computation. which triggers the nested computation \int_use:N \__int_eval:w with starting value 4 9995 0000 (the “middle shift”). The “leading shift” cancels the combination of the other shifts. More specifically. whose initial value is −5 0000 (the “leading shift”). In that computation appears an \exp_after:wN. The corresponding pack function. That. it will also work to some extent with negative results.5 0000 \exp_after:wN \pack:NNNNNw \int_use:N \__int_eval:w 4 9995 0000 + 12345 * 6677 \exp_after:wN \pack:NNNNNw \int_use:N \__int_eval:w 5 0000 0000 + 12345 * 8899 . padding with zeros on the left. Of course. which has 9 digits. braces the last 4 digits. As long as the operands are in some range. this can be modified for any number of digits less or equal to 9 (we are limited by TEX’s integers). and the \post_processing:w takes care of packing the last few digits. Say we want to compute 1 2345 × 6677 8899. the following trick will split it into two blocks of 4 digits. {#6}. The \exp_after:wN triggers \int_use:N \__int_eval:w. The pack function puts the last 4 of those 9 digits into a brace group. and inserts a +. #2#3#4#5 #6#7#8#9 { #1 {#2#3#4#5} {#6#7#8#9} . #7 { + #1#2#3#4#5 .) \__fp_pack_twice_four:wNNNNNNNN Grabs two sets of 4 digits and places them before the semi-colon delimiter. Note that the upper bound is due to TEX’s limit of 231 − 1 on integers. The shifts are chosen to be roughly the mid-point of 109 and 231 . {#7} } (End definition for \__fp_pack_Bigg:NNNNNNw. \c__fp_Bigg_middle_shift_int 9770 \int_const:Nn \c__fp_Bigg_leading_shift_int { . { + #1#2#3#4#5#6 . this is used so much that we provide different sets of packing functions and shifts. \__fp_pack:NNNNNw \__fp_pack:NNNNNwn \c__fp_trailing_shift_int \c__fp_middle_shift_int \c__fp_leading_shift_int This set of shifts allows for computations involving results in the range [−4·108 .) 504 . {#7} } \cs_new:Npn \__fp_pack_big:NNNNNNwn #1#2 #3#4#5#6 #7. These functions are documented on page ??. the two bounds on 10-digit integers in TEX. 147483647]. 5·108 −1]. These functions are documented on page ??.5 0000 } \int_const:Nn \c__fp_middle_shift_int { 5 0000 * 9999 } \int_const:Nn \c__fp_trailing_shift_int { 5 0000 * 10000 } \cs_new:Npn \__fp_pack:NNNNNw #1 #2#3#4#5 #6.Admittedly. } (End definition for \__fp_pack_twice_four:wNNNNNNNN.) \__fp_pack_big:NNNNNNw \__fp_pack_big:NNNNNNwn \c__fp_big_trailing_shift_int \c__fp_big_middle_shift_int \c__fp_big_leading_shift_int This set of shifts allows for computations involving results in the range [−5·108 .20 0000 } \c__fp_Bigg_leading_shift_int 9771 \int_const:Nn \c__fp_Bigg_middle_shift_int { 20 0000 * 9999 } 9772 \int_const:Nn \c__fp_Bigg_trailing_shift_int { 20 0000 * 10000 } 9773 \cs_new:Npn \__fp_pack_Bigg:NNNNNNw #1#2 #3#4#5#6 #7. #8 { + #1#2#3#4#5#6 . 6·108 −1] (actually a bit more). 9774 { + #1#2#3#4#5#6 . Putting several copies of this function before a semicolon will pack more digits since each will take the digits packed by the others in its first argument. Shifted values all have exactly 10 digits.) \__fp_pack_Bigg:NNNNNNw This set of shifts allows for computations involving results in the range [−1·109 . This function is documented on page ??. { + #1#2#3#4#5 . 9757 9758 9759 9760 9761 9762 \int_const:Nn \c__fp_leading_shift_int { . depending on ranges of input. \c__fp_Bigg_trailing_shift_int the end-point is 231 − 1 − 2 · 109 ' 1. {#7} {#6} } (End definition for \__fp_pack:NNNNNw and \__fp_pack:NNNNNwn. {#6} } \cs_new:Npn \__fp_pack:NNNNNwn #1 #2#3#4#5 #6. 9763 9764 9765 9766 9767 9768 9769 \int_const:Nn \c__fp_big_leading_shift_int { . In fact. The \__fp_pack:NNNNNwn function brings a braced hcontinuationi up through the levels of expansion. Shifted values all have exactly 9 digits. this is quite intricate. 9775 9776 \cs_new:Npn \__fp_pack_twice_four:wNNNNNNNN #1.15 2374 } \int_const:Nn \c__fp_big_middle_shift_int { 15 2374 * 9999 } \int_const:Nn \c__fp_big_trailing_shift_int { 15 2374 * 10000 } \cs_new:Npn \__fp_pack_big:NNNNNNw #1#2 #3#4#5#6 #7. {#8} {#7} } (End definition for \__fp_pack_big:NNNNNNw and \__fp_pack_big:NNNNNNwn.47 · 108 . It is probably the key in making l3fp as fast as other pure TEX floating point units despite its increased precision. Shifted values all have exactly 10 digits. Otherwise. hroundingi is 1 (not 0).) 22. ! 4 X hXi i · 10−4i · 10−hshifti − hX’1 i · 10−8 + hX’2 i · 10−16 ∈ [0. If the shift is 1. or too big.) 505 . i=1 To round properly later. } \cs_new:Npn \__fp_decimate_tiny:Nnnnn #1 #2#3#4#5 { #1 1 { 0000 0000 } { 0000 0000 } 0 #2#3#4#5 . #2#3#4#5 #6#7#8#9 { #1 {#2#3#4#5#6#7#8#9} . life is very easy. In particular. 10−16 ).5 · 10−16 . we need to remember some information about the difference. The first argument determines by how much we shift the digits. but the choice we make involves less reshuffling. 9777 9778 \cs_new:Npn \__fp_pack_eight:wNNNNNNNN #1. Putting several copies of this function before a semicolon will pack more digits since each will take the digits packed by the others in its first argument. if the shift is 17 or more. all the digits are dropped. 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 \cs_new:Npn \__fp_decimate:nNnnnn #1 { \cs:w __fp_decimate_ \if_int_compare:w \__int_eval:w #1 > \c_sixteen tiny \else: \tex_romannumeral:D \__int_eval:w #1 \fi: :Nnnnn \cs_end: } Each of the auxiliaries see the function hf1 i. In other words. } (End definition for \__fp_decimate_:Nnnnn and \__fp_decimate_tiny:Nnnnn. hf1 i is called as follows: where 0 ≤ hX’i i < 108 − 1 are 8 digit numbers. It would be more natural for the hroundingi digit to be placed after the hXi i. forming the truncation of our number. 9791 9792 9793 9794 \cs_new:Npn \__fp_decimate_:Nnnnn #1 #2#3#4#5 { #1 0 {#2#3} {#4#5} . } (End definition for \__fp_pack_eight:wNNNNNNNN. and 1000 ≤ hX1 i < 9999. and hX’1 i hX’2 i are both zero. The hroundingi digit is 0 if and only if the difference is exactly 0.) \__fp_decimate_:Nnnnn \__fp_decimate_tiny:Nnnnn If the hshifti is zero. and 5 if and only if the difference is exactly 0. the hroundingi digit is simply the only digit that was pushed out of the brace groups (this is important for subtraction).\__fp_pack_eight:wNNNNNNNN Grabs one set of 8 digits and places them before the semi-colon delimiter as a single group. followed by 4 blocks of 4 digits.6 \__fp_decimate:nNnnnn Decimate (dividing by a power of 10) Each hXi i consists in 4 digits exactly. non-5) digit closest to 1017 times the difference. Note that this function fails for negative hshifti. it is the (non-0. (End definition for \__fp_decimate:nNnnnn. the argument spec is not a mistake: the function calls an auxiliary to do half of the job. which expands the following functions. } } \__fp_tmp:w {i} {\use_none:nnn #50} { 0{#2}#3{#4}#5 \__fp_tmp:w {ii} {\use_none:nn #5 } { 00{#2}#3{#4}#5 \__fp_tmp:w {iii} {\use_none:n #5 } { 000{#2}#3{#4}#5 \__fp_tmp:w {iv} { #5 } { {0000}#2{#3}#4 #5 \__fp_tmp:w {v} {\use_none:nnn #4#5 } { 0{0000}#2{#3}#4 #5 \__fp_tmp:w {vi} {\use_none:nn #4#5 } { 00{0000}#2{#3}#4 #5 \__fp_tmp:w {vii} {\use_none:n #4#5 } { 000{0000}#2{#3}#4 #5 \__fp_tmp:w {viii}{ #4#5 } { {0000}0000{#2}#3 #4 #5 \__fp_tmp:w {ix} {\use_none:nnn #3#4+#5} { 0{0000}0000{#2}#3 #4 #5 \__fp_tmp:w {x} {\use_none:nn #3#4+#5} { 00{0000}0000{#2}#3 #4 #5 \__fp_tmp:w {xi} {\use_none:n #3#4+#5} { 000{0000}0000{#2}#3 #4 #5 \__fp_tmp:w {xii} { #3#4+#5} { {0000}0000{0000}#2 #3 #4 #5 \__fp_tmp:w {xiii}{\use_none:nnn#2#3+#4#5} { 0{0000}0000{0000}#2 #3 #4 #5 \__fp_tmp:w {xiv} {\use_none:nn #2#3+#4#5} { 00{0000}0000{0000}#2 #3 #4 #5 \__fp_tmp:w {xv} {\use_none:n #2#3+#4#5} { 000{0000}0000{0000}#2 #3 #4 #5 \__fp_tmp:w {xvi} { #2#3+#4#5} {{0000}0000{0000}0000 #2 #3 #4 #5 (End definition for \\__fp_decimate_auxi:Nnnnn and others. separated by +.) \__fp_round_digit:Nw \__fp_round_digit:Nw will receive the “extra digits” as its argument. The sixteen functions are very similar. and repack digits into two blocks of 8. such that 6 No. though.\\__fp_decimate_auxi:Nnnnn \\__fp_decimate_auxii:Nnnnn \\__fp_decimate_auxiii:Nnnnn \\__fp_decimate_auxiv:Nnnnn \\__fp_decimate_auxv:Nnnnn \\__fp_decimate_auxvi:Nnnnn \\__fp_decimate_auxvii:Nnnnn \\__fp_decimate_auxviii:Nnnnn \\__fp_decimate_auxix:Nnnnn \\__fp_decimate_auxx:Nnnnn \\__fp_decimate_auxxi:Nnnnn \\__fp_decimate_auxxii:Nnnnn \\__fp_decimate_auxxiii:Nnnnn \\__fp_decimate_auxxiv:Nnnnn \\__fp_decimate_auxxv:Nnnnn \\__fp_decimate_auxxvi:Nnnnn Shifting happens in two steps: compute the hroundingi digit. This triggers the f-expansion of \__fp_decimate_pack:nnnnnnnnnnw. and this may overflow TEX’s integers. because there may be more than 10 “extra digits”. Hence the first \__int_eval:w here. after one step of expansion. we need to add 1 to that leading digit to get the rounding digit. This allows us to repack nicely the digits we keep. Otherwise. For this to work. #2 yields the “extra digits” which are then converted by \__fp_round_digit:Nw to the hroundingi digit. they come split into several blocks. #3 alternates between braced and unbraced blocks of 4 digits. and defined through \__fp_tmp:w. The arguments are as follows: #1 indicates which function is being defined. 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 \cs_new:Npn \__fp_tmp:w #1 #2 #3 { \cs_new:cpn { __fp_decimate_ #1 :Nnnnn } ##1 ##2##3##4##5 { \exp_after:wN ##1 \__int_value:w \exp_after:wN \__fp_round_digit:Nw #2 .6 responsible for building two blocks of 8 digits. in such a way that the 5 first and 5 next token groups yield the correct blocks of 8 digits. then it is the hroundingi digit. Some caution is required. and its expansion \__fp_decimate_pack:nnnnnnnnnnw is triggered by \__int_value:w. if the remaining digits are not all zero. The computation of the hroundingi digit leaves an unfinished \__int_value:w. Instead of feeding the digits directly to \__fp_round_digit:Nw. 506 } } } } } } } } } } } } } } } } . If the first digit is neither 0 nor 5. Those digits come as an alternation of unbraced and braced blocks of 4 digits. \__fp_decimate_pack:nnnnnnnnnnw #3 . and removing the rest. performing some other operation on the hfloating pointi. \__fp_case_use:nw This function ends a TEX conditional. and one brace group (in some order). { \fi: #1 } (End definition for \__fp_case_return:nw.7 Functions for use within primitive conditional branches The functions described in this section are not pretty and can easily be misused. and expand hsomethingi next. and places its first argument in the input stream. 9826 \cs_new:Npn \__fp_case_return:nw #1#2 \fi: #3 . In other cases. { \fi: \exp_after:wN #1 } (End definition for \__fp_case_return_o:Nw.) 507 . means that the hjunki may not contain semicolons. 9821 9822 9823 9824 \cs_new:Npn \__fp_decimate_pack:nnnnnnnnnnw #1#2#3#4#5 { \__fp_decimate_pack:nnnnnnw { #1#2#3#4#5 } } \cs_new:Npn \__fp_decimate_pack:nnnnnnw #1 #2#3#4#5#6 { {#1} {#2#3#4#5#6} } (End definition for \__fp_round_digit:Nw and \__fp_decimate_pack:nnnnnnnnnnw. simply anything ending in a semicolon. We provide similar functions with two trailing hfloating pointsi. This is often done in an \if_case:w statement or another conditional statement. When correctly used. removes junk and a floating point. in turn. to perform some operation on the floating point. removes junk until the next floating point.the first 5 groups of token consist in 4 single digits. removes junk and a floating point.) 22.) \__fp_case_return_o:Nw This function ends a TEX conditional. and puts one back as part of its replacement text. Case 3 will close the conditional. This. and only a few cases lead to actual computations: most of the special cases are treated using a few standard functions which we define now. and the next 5 have the same structure. This is followed by some digits and a semicolon. Case 2 will return the hfloating pointi without modifying it. A quirk is that we don’t define this function requiring a floating point to follow. the “hjunki” is expanded. remove the hjunki and the hfloating pointi. removing the hjunki and expanding once after. the case 0 will return the floating point hfp vari. and places its first argument before that floating point. 9827 9828 \cs_new:Npn \__fp_case_return_o:Nw #1#2 \fi: #3 \s__fp #4 . each of them removes one \fi: as part of its parameter text.) \__fp_case_return:nw This function ends a TEX conditional. Many computation functions in l3fp must perform tests on the type of floating points that they receive. and returns its first argument (an hfp vari) then expands once after it. expanding once after that floating point. A typical use context for those functions would be In this example. 9825 \cs_new:Npn \__fp_case_use:nw #1#2 \fi: #3 \s__fp { \fi: #1 \s__fp } (End definition for \__fp_case_use:nw. Case 1 will do hsome computationi using the hfloating pointi (presumably compute the operation requested by the user in that nontrivial case). 9829 9830 \cs_new:Npn \__fp_case_return_same_o:w #1 \fi: #2 \s__fp { \fi: \__fp_exp_after_o:w \s__fp } (End definition for \__fp_case_return_same_o:w.) \__fp_case_return_o:Nww Same as \__fp_case_return_o:Nw but with two trailing floating points. and returns the following floating point. { \if_int_compare:w #2 > \c_zero \if_int_compare:w #2 > \c_eight \exp_after:wN \exp_after:wN 508 . } \cs_new:Npn \__fp_case_return_ii_o:ww #1 \fi: #2 \s__fp #3 . expanding once after it. the result of the conversion is fed as a braced argument to the htrue codei. 9833 9834 9835 9836 \cs_new:Npn \__fp_case_return_i_o:ww #1 \fi: #2 \s__fp #3 . 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 \cs_new:Npn \__fp_small_int:wTF \s__fp \__fp_chk:w #1 { \if_case:w #1 \exp_stop_f: \__fp_case_return:nw { \__fp_small_int_true:wTF 0 . and test the digits after the decimal separator. The \use_iii:nnn remove a trailing . { \fi: \exp_after:wN #1 } (End definition for \__fp_case_return_o:Nww. removes junk. and the true branch. #2#3 { #2 {#1} } \cs_new:Npn \__fp_small_int_normal:NnwTF #1#2#3. expanding once after the result. but this returns the first or second of two trailing floating point numbers.. That integer is fed to \__fp_small_int_true:wTF which places it as a braced argument of the true branch. { \fi: \__fp_exp_after_o:w } (End definition for \__fp_case_return_i_o:ww and \__fp_case_return_ii_o:ww. #5 . } \or: \exp_after:wN \__fp_small_int_normal:NnwTF \else: \__fp_case_return:nw \use_ii:nn \fi: } \cs_new:Npn \__fp_small_int_true:wTF #1. If it is.\__fp_case_return_same_o:w This function ends a TEX conditional. \s__fp #4 . Normal numbers with a non-positive exponent are never integers. Otherwise.) 22.) \__fp_case_return_i_o:ww \__fp_case_return_ii_o:ww Similar to \__fp_case_return_same_o:w. First filter special cases: neither nan nor infinities are integers.8 \__fp_small_int:wTF \__fp_small_int_true:wTF \__fp_small_int_normal:NnwTF \__fp_small_int_test:NnnwNTF Small integer floating points This function tests if its floating point argument is an integer in the range [−99999999. 99999999]. When the exponent is greater than 8. decimate. the hfalse codei is performed. taking the false branch. The \__int_value:w appearing in the case where the normal floating point is an integer takes care of expanding all the conditionals until the trailing . 9831 9832 \cs_new:Npn \__fp_case_return_o:Nww #1#2 \fi: #3 \s__fp #4 . leaving only the false branch. The \use_i:nn in \__fp_small_int_test:NnnwNTF removes the top-level \else: coming from \__fp_small_int_normal:NnwTF. hence will call the \use_iii:nnn which follows. { \fi: \__fp_exp_after_o:w \s__fp #3 . Otherwise. the number is too large for the range. then the leading item (often a single character token) is moved to a storage area after \s__fp_mark. The argument is f-expanded. Multiple tokens which do not need expansion can be inserted within braces. This function is documented on page ??.9 \__fp_array_count:n \__fp_array_count_loop:Nw Length of a floating point array Count the number of items in an array of floating points.) 22. but with the loop built-in.\exp_after:wN \use_iii:nnn \else: \__fp_decimate:nNnnnn { \c_sixteen .) 22.10 \__fp_expand:n \__fp_expand_loop:nwnN x-like expansion expandably This expandable function behaves in a way somewhat similar to \use:x.\fi: #3 \else: \exp_after:wN \use_i:nn \fi: } (End definition for \__fp_small_int:wTF. unless surrounded with braces. repeating until the argument is empty. { \use_none:n #1 + \c_one \__fp_array_count_loop:Nw } (End definition for \__fp_array_count:n. 9880 \cs_new:Npn \__fp_expand:n #1 509 . but much less robust. 9871 9872 9873 9874 9875 9876 9877 9878 9879 \cs_new:Npn \__fp_array_count:n #1 { \int_use:N \__int_eval:w \c_zero \__fp_array_count_loop:Nw #1 { ? \__prg_break: } . and f-expansion is applied again. The result built one piece at a time is then inserted in the input stream. The technique is very similar to \tl_count:n. Checking for the end of the loop is done with the \use_none:n #1 construction. This function is documented on page ??. \__prg_break_point: \__int_eval_end: } \cs_new:Npn \__fp_array_count_loop:Nw #1#2.#2 } \__fp_small_int_test:NnnwNTF #3 #1 \fi: \else: \exp_after:wN \use_iii:nnn \fi: . #5 { \if_meaning:w 0 #1 \exp_after:wN \__fp_small_int_true:wTF \__int_value:w \if_meaning:w 2 #5 . 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 } \cs_new:Npn \__fp_small_int_test:NnnwNTF #1#2#3#4. Note that spaces are ignored by this procedure. } { To~obtain~the~value~of~a~floating~point~variable.) 22.11 Messages Using a floating point directly is an error. 510 . among • invalid_operation • division_by_zero • overflow • underflow • inexact (actually never used).~or~other~ conversion~functions.~ ’\token_to_str:N \fp_to_scientific:N’. 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 } \cs_new:Npn \__fp_expand_loop:nwnN #1#2 \s__fp_mark #3 #4 { \exp_after:wN #4 \tex_romannumeral:D -‘0 #2 \s__fp_mark { #3 #1 } #4 } (End definition for \__fp_expand:n.{ 9881 \__fp_expand_loop:nwnN { } #1 \prg_do_nothing: \s__fp_mark { } \__fp_expand_loop:nwnN \s__fp_mark { } \__fp_use_i_until_s:nw . } 9901 h/initex | packagei 9893 9894 9895 9896 9897 9898 9899 23 l3fp-traps Implementation 9902 h*initex | packagei 9903 h@@=fpi Exceptions should be accessed by an n-type argument.~use~ ’\token_to_str:N \fp_to_decimal:N’. This function is documented on page ??. 9900 \__msg_kernel_new:nnnn { kernel } { misused-fp } { A~floating~point~with~value~’#1’~was~misused. • \__fp_invalid_operation_o:Nww. the function name (multiple letters for prefix operations. Currently. This function is documented on page 174. This function is documented on page 174. 9908 9909 9910 9911 9912 9913 9914 9915 \prg_new_conditional:Npnn \fp_if_flag_on:n #1 { p . false otherwise. \l__fp_overflow_flag_token 9916 \cs_new_eq:NN \l__fp_invalid_operation_flag_token \tex_undefined:D \l__fp_underflow_flag_token 9917 \cs_new_eq:NN \l__fp_division_by_zero_flag_token \tex_undefined:D 9918 \cs_new_eq:NN \l__fp_overflow_flag_token \tex_undefined:D 9919 \cs_new_eq:NN \l__fp_underflow_flag_token \tex_undefined:D (End definition for \l__fp_invalid_operation_flag_token and others.1 \fp_flag_off:n Flags Function to turn a flag off. When an overflow or underflow is trapped. 511 . and the operand(s). The behaviour when an exception occurs is controlled by the definitions of the functions • \__fp_invalid_operation:nnw. the inexact exception is entirely ignored. the trap receives the resulting overly large or small floating point number if it is not too big. the trap receives as arguments the result as an N -type floating point number. 9904 9905 \cs_new_protected:Npn \fp_flag_off:n #1 { \cs_set_eq:cN { l__fp_ #1 _flag_token } \tex_undefined:D } (End definition for \fp_flag_off:n.) \fp_flag_on:n Function to turn a flag on expandably: use TEX’s automatic assignment to \scan_stop:.23. or a single symbol for infix operations). We currently don’t support the “inexact” \l__fp_division_by_zero_flag_token exception. These functions are documented on page 174. otherwise it receives +∞.) 23. 9906 9907 \cs_new:Npn \fp_flag_on:n #1 { \exp_args:Nc \use_none:n { l__fp_ #1 _flag_token } } (End definition for \fp_flag_on:n. F . • \__fp_invalid_operation_tl_o:nf.) \l__fp_invalid_operation_flag_token The ieee standard defines five exceptions.2 Traps Exceptions can be trapped to obtain custom behaviour. When an invalid operation or a division by zero is trapped. TF } { \if_cs_exist:w l__fp_ #1 _flag_token \cs_end: \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \fp_if_flag_on:n.) \fp_if_flag_on_p:n \fp_if_flag_on:nTF Returns true if the flag is on. T . Simply undefine it. } 9944 { 9945 #1 9946 \__fp_error:nnfn { invalid } {##2} { \fp_to_tl:n { ##3.) \__fp_trap_invalid_operation_set_error: We provide three types of trapping for invalid operations: either produce an error and \__fp_trap_invalid_operation_set_flag: raise the relevant flag. \__fp_trap_invalid_operation_set:N 9934 \cs_new_protected_nopar:Npn \__fp_trap_invalid_operation_set_error: 9935 { \__fp_trap_invalid_operation_set:N \prg_do_nothing: } 9936 \cs_new_protected_nopar:Npn \__fp_trap_invalid_operation_set_flag: 9937 { \__fp_trap_invalid_operation_set:N \use_none:nnnnn } 9938 \cs_new_protected_nopar:Npn \__fp_trap_invalid_operation_set_none: 9939 { \__fp_trap_invalid_operation_set:N \use_none:nnnnnnn } 9940 \cs_new_protected:Npn \__fp_trap_invalid_operation_set:N #1 9941 { 9942 \exp_args:Nno \use:n 9943 { \cs_set:Npn \__fp_invalid_operation:nnw ##1##2##3. division_by_zero . \__fp_trap_invalid_operation_set_none: the function produces as a result its first argument. or don’t even raise the flag. \fp_trap:nn 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 \cs_new_protected:Npn \fp_trap:nn #1#2 { \cs_if_exist_use:cF { __fp_trap_#1_set_#2: } { \clist_if_in:nnTF { invalid_operation . possibly with post-expansion. underflow } {#1} { \__msg_kernel_error:nnxx { kernel } { unknown-fpu-trap-type } {#1} {#2} } { \__msg_kernel_error:nnx { kernel } { unknown-fpu-exception } {#1} } } } (End definition for \fp_trap:nn. • \__fp_overflow:w. overflow . where the hway of trappingi is one of error. Rather than changing them directly. } } { } 9947 \fp_flag_on:n { invalid_operation } 9948 ##1 9949 } 512 . we provide a user interface as \fp_trap:nn {hexceptioni} {hway of trappingi}. flag. defined in terms of \__fp_invalid_operation:nnw. We also provide \__fp_invalid_operation_o:nw.• \__fp_division_by_zero_o:Nnw. This function is documented on page 174. In most cases. • \__fp_underflow:w. • \__fp_division_by_zero_o:NNww. or none. or only raise the flag. } { #1 \__fp_error:nffn { invalid-ii } { \fp_to_tl:n { ##2.) \__fp_trap_division_by_zero_set_error: \__fp_trap_division_by_zero_set_flag: \__fp_trap_division_by_zero_set_none: \__fp_trap_division_by_zero_set:N We provide three types of trapping for invalid operations and division by zero: either produce an error and raise the relevant flag. ##4. } } { \fp_to_tl:n { ##4. } { #1 \__fp_error:nnfn { zero-div } {##2} { \fp_to_tl:n { ##3. } } { \fp_to_tl:n { ##3. } { #1 \__fp_error:nffn { zero-div-ii } { \fp_to_tl:n { ##3. In all cases. namely its first argument. } } { } \fp_flag_on:n { division_by_zero } \exp_after:wN ##1 } \exp_args:Nno \use:n { \cs_set:Npn \__fp_division_by_zero_o:NNww ##1##2##3. or don’t even raise the flag. the function must produce a result. } } {##1} \fp_flag_on:n { invalid_operation } \exp_after:wN \c_nan_fp } \exp_args:Nno \use:n { \cs_set:Npn \__fp_invalid_operation_tl_o:nf ##1##2 } { #1 \__fp_error:nnfn { invalid } {##1} {##2} { } \fp_flag_on:n { invalid_operation } \exp_after:wN \c_nan_fp } 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 } (End definition for \__fp_trap_invalid_operation_set_error: and others. 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 \cs_new_protected_nopar:Npn \__fp_trap_division_by_zero_set_error: { \__fp_trap_division_by_zero_set:N \prg_do_nothing: } \cs_new_protected_nopar:Npn \__fp_trap_division_by_zero_set_flag: { \__fp_trap_division_by_zero_set:N \use_none:nnnnn } \cs_new_protected_nopar:Npn \__fp_trap_division_by_zero_set_none: { \__fp_trap_division_by_zero_set:N \use_none:nnnnnnn } \cs_new_protected:Npn \__fp_trap_division_by_zero_set:N #1 { \exp_args:Nno \use:n { \cs_set:Npn \__fp_division_by_zero_o:Nnw ##1##2##3. } } {##2} \fp_flag_on:n { division_by_zero } \exp_after:wN ##1 } 513 . or only raise the flag.\exp_args:Nno \use:n { \cs_set:Npn \__fp_invalid_operation_o:Nww ##1##2. ##3. ±∞ or nan. and \__fp_overflow:w receives ±∞ (\__fp_underflow:w would receive ±0).) \__fp_trap_overflow_set_error: \__fp_trap_overflow_set_flag: \__fp_trap_overflow_set_none: \__fp_trap_overflow_set:N \__fp_trap_underflow_set_error: \__fp_trap_underflow_set_flag: \__fp_trap_underflow_set_none: \__fp_trap_underflow_set:N \__fp_trap_overflow_set:NnNn Just as for invalid operations and division by zero. and the error message thus displays that number together with the result to which it overflowed or underflowed. the three different behaviours are obtained by feeding \prg_do_nothing:. then we cannot do better than simply say an overflow or underflow occurred. the exponent would be too large for TEX. In most cases. } } { \token_if_eq_meaning:NNF 0 ##2 { . with a further auxiliary common to overflow and underflow functions. These functions are documented on page 174. overflow.} #4 } {#2} \fp_flag_on:n {#2} #3 ##2 } } (End definition for \__fp_trap_overflow_set_error: and others. 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 \cs_new_protected_nopar:Npn \__fp_trap_overflow_set_error: { \__fp_trap_overflow_set:N \prg_do_nothing: } \cs_new_protected_nopar:Npn \__fp_trap_overflow_set_flag: { \__fp_trap_overflow_set:N \use_none:nnnnn } \cs_new_protected_nopar:Npn \__fp_trap_overflow_set_none: { \__fp_trap_overflow_set:N \use_none:nnnnnnn } \cs_new_protected:Npn \__fp_trap_overflow_set:N #1 { \__fp_trap_overflow_set:NnNn #1 { overflow } \__fp_inf_fp:N { inf } } \cs_new_protected_nopar:Npn \__fp_trap_underflow_set_error: { \__fp_trap_underflow_set:N \prg_do_nothing: } \cs_new_protected_nopar:Npn \__fp_trap_underflow_set_flag: { \__fp_trap_underflow_set:N \use_none:nnnnn } \cs_new_protected_nopar:Npn \__fp_trap_underflow_set_none: { \__fp_trap_underflow_set:N \use_none:nnnnnnn } \cs_new_protected:Npn \__fp_trap_underflow_set:N #1 { \__fp_trap_overflow_set:NnNn #1 { underflow } \__fp_zero_fp:N { 0 } } \cs_new_protected:Npn \__fp_trap_overflow_set:NnNn #1#2#3#4 { \exp_args:Nno \use:n { \cs_set:cpn { __fp_ #2 :w } \s__fp \__fp_chk:w ##1##2##3. the argument of the \__fp_overflow:w and \__fp_underflow:w functions will be an (almost) normal number (with an exponent outside the allowed range). For extreme cases such as 10 ** 1e9999. } { #1 \__fp_error:nffn { flow \if_meaning:w 1 ##1 -to \fi: } { \fp_to_tl:n { \s__fp \__fp_chk:w ##1##2##3. and underflow to act silently \__fp_invalid_operation_tl_o:nf on their flag. \__fp_division_by_zero_o:Nnw \__fp_division_by_zero_o:NNww 514 \__fp_overflow:w \__fp_underflow:w . and division by zero.) \__fp_invalid_operation:nnw Initialize the two control sequences (to log properly their existence).9993 } (End definition for \__fp_trap_division_by_zero_set_error: and others. \use_none:nnnnn or \use_none:nnnnnnn to an auxiliary. Then set invalid \__fp_invalid_operation_o:Nww operations to trigger an error. { } \__fp_invalid_operation_o:Nww #1#2. and expanding after. nff } (End definition for \__fp_error:nnnn . \__fp_error:nnfn .3 \__fp_error:nnnn \__fp_error:nnfn \__fp_error:nffn 10038 10039 10040 Errors \cs_new:Npn \__fp_error:nnnn #1 { \__msg_kernel_expandable_error:nnnnn { kernel } { fp .#1 } } \cs_generate_variant:Nn \__fp_error:nnnn { nnf. { } \__fp_invalid_operation_tl_o:nf #1 #2 { } \__fp_division_by_zero_o:Nnw #1#2#3. { } \__fp_overflow:w { } \__fp_underflow:w { } { invalid_operation } { error } { division_by_zero } { flag } { overflow } { flag } { underflow } { flag } (End definition for \__fp_invalid_operation:nnw and others. 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 \__msg_kernel_new:nnnn { kernel } { unknown-fpu-exception } { The~FPU~exception~’#1’~is~not~known:~that~trap~will~never~be~triggered. #3. } { The~trap~type~must~be~one~of \\ \iow_indent:n { 515 . #4.) 23.) \__fp_invalid_operation_o:nw Convenient short-hands for returning \c_nan_fp for a unary or binary operation. } { The~only~exceptions~to~which~traps~can~be~attached~are \\ \iow_indent:n { * ~ invalid_operation \\ * ~ division_by_zero \\ * ~ overflow \\ * ~ underflow } } \__msg_kernel_new:nnnn { kernel } { unknown-fpu-trap-type } { The~FPU~trap~type~’#2’~is~not~known. { } \__fp_division_by_zero_o:NNww #1#2#3.4 Messages Some messages.) 23. and \__fp_error:nffn. 10036 10037 \cs_new_nopar:Npn \__fp_invalid_operation_o:nw { \__fp_invalid_operation:nnw { \exp_after:wN \c_nan_fp } } (End definition for \__fp_invalid_operation_o:nw.10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \cs_new:Npn \fp_trap:nn \fp_trap:nn \fp_trap:nn \fp_trap:nn \__fp_invalid_operation:nnw #1#2#3. This is not fully implemented in l3fp yet. • Round towards positive infinity: round to the least floating point number not smaller than the exact result. } \__msg_kernel_new:nnn { kernel } { fp-zero-div } { Division~by~zero~in~ #1 (#2) } \__msg_kernel_new:nnn { kernel } { fp-zero-div-ii } { Division~by~zero~in~ (#1) #3 (#2) } \__msg_kernel_new:nnn { kernel } { fp-invalid } { Invalid~operation~ #1 (#2) } \__msg_kernel_new:nnn { kernel } { fp-invalid-ii } { Invalid~operation~ (#1) #3 (#2) } 10076 h/initex | packagei 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 l3fp-round implementation 24 10077 h*initex | packagei 10078 h@@=fpi 24. • Round towards zero: round to a floating point number with the same sign as the exact result. In that case. 516 .1 Rounding tools Floating point operations often yield a result that cannot be exactly represented in a significand with 16 digits.* ~ error \\ * ~ flag \\ * ~ none 10059 10060 10061 10075 } } \__msg_kernel_new:nnn { kernel } { fp-flow } { An ~ #3 ~ occurred. with the largest absolute value not larger than the absolute value of the exact result. which can be redefined to change their rounding behaviour (but there is not interface for that yet). round to the floating point number whose last digit is even. If the exact result lies exactly at the mid-point between two consecutive representable floating point numbers. we need to round the exact result to a representable number. } \__msg_kernel_new:nnn { kernel } { fp-flow-to } { #1 ~ #3 ed ~ to ~ #2 . • Round towards negative infinity: round to the greatest floating point number not larger than the exact result. The ieee standard defines four rounding modes: • Round to nearest: round to the representable floating point number whose absolute difference with the exact result is the smallest. All rounding for basic algebra is done through the functions defined in this module. and transcendental functions fall back on the “round to nearest” mode. hdigit2 i to an integer rounds it towards zero (truncates it). this function expands to \c_zero. ties to even” mode. round down. or \c_one . and 2 for negative. Typically used within the scope of an \__int_eval:w. • \__fp_round_s:NNNw hsigni hdigit1 i hdigit2 i hmore digitsi . If it is less than 5. then round such that hdigit1 i plus the result is even. which instead returns \c_one. • \__fp_round:NNN hsigni hdigit1 i hdigit2 i can expand to \c_zero or \c_one. this is not really useful. can expand to \c_zero . • \__fp_round_neg:NNN hsigni hdigit1 i hdigit2 i can expand to \c_zero or \c_one. and otherwise to \c_one. the functions below return \c_zero. but this is superseded by \__fp_round_return_one:. Also recall that hfinal signi is 0 for positive. and thereby round correctly. but it prepares us for the “round to nearest. In other words.. See implementation comments for details on the syntax. the result will be incorrect in the case of rounding towards −∞ or towards +∞. 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 \cs_new:Npn \__fp_round_return_one: { \exp_after:wN \c_one \tex_romannumeral:D } \cs_new:Npn \__fp_round_to_ninf:NNN #1 #2 #3 { \if_meaning:w 2 #1 \if_int_compare:w #3 > \c_zero \__fp_round_return_one: \fi: \fi: \c_zero } \cs_new:Npn \__fp_round_to_zero:NNN #1 #2 #3 { \c_zero } \cs_new:Npn \__fp_round_to_pinf:NNN #1 #2 #3 { \if_meaning:w 0 #1 \if_int_compare:w #3 > \c_zero \__fp_round_return_one: \fi: \fi: \c_zero } \cs_new:Npn \__fp_round_to_nearest:NNN #1 #2 #3 517 . If it is exactly 5. It is very important that hfinal signi be the final sign of the result. In the case of rounding towards ±∞ or towards 0. \__fp_round:NNN \__fp_round_to_nearest:NNN \__fp_round_to_ninf:NNN \__fp_round_to_zero:NNN \__fp_round_to_pinf:NNN If rounding the number hfinal signihdigit1 i. The result depends on the rounding mode. If the hdigit2 i is larger than 5. round up if hdigit1 i is odd. which expands to \c_zero or \c_one depending on whether the final result should be rounded up or down. then round up. Otherwise.The rounding tools available in this module are many variations on a base function \__fp_round:NNN. By default. The “round to nearest” mode is the default. expanding everything and removing \c_zero in the process. to add 1 if needed. { \exp_after:wN \__fp_round:NNN \exp_after:wN #1 \exp_after:wN #2 \int_use:N \__int_eval:w \if_int_odd:w 0 \if_meaning:w 0 #3 1 \fi: \if_meaning:w 5 #3 1 \fi: \exp_stop_f: \if_int_compare:w \__int_eval:w #4 > \c_zero 1 + \fi: \fi: #3 .hmore digitsi to an integer truncates. { \if_int_odd:w \if_meaning:w 0 #1 \c_one \else: \if_meaning:w 5 #1 \c_one \else: \c_zero \fi: \fi: \if_int_compare:w \__int_eval:w #2 > \c_zero \__int_eval:w \c_one + 518 . This function is documented on page ??. and to \c_one . this function expands to \c_zero . followed by something that does not overflow a \int_use:N \__int_eval:w construction. otherwise. if rounding hfinal signihdigiti. it may add an extra \__int_eval:w. The hmore digitsi part must be a digit.) \__fp_round_digit:Nw This function should always be called within an \__int_value:w or \__int_eval:w expansion.10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 { \if_int_compare:w #3 > \c_five \__fp_round_return_one: \else: \if_meaning:w 5 #3 \if_int_odd:w #2 \exp_stop_f: \__fp_round_return_one: \fi: \fi: \fi: \c_zero } \cs_new_eq:NN \__fp_round:NNN \__fp_round_to_nearest:NNN (End definition for \__fp_round:NNN.) \__fp_round_s:NNNw Similar to \__fp_round:NNN. } (End definition for \__fp_round_s:NNNw. which means that the integer or integer expression should not be ended with a synonym of \relax. 10130 10131 10132 10133 10134 10135 10136 \cs_new:Npn \__fp_round_digit:Nw #1 #2. 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 \cs_new:Npn \__fp_round_s:NNNw #1 #2 #3 #4. but with a semi-colon for instance. but with an extra semicolon. The only relevant information about this piece is whether it is zero or not. This function is documented on page ??. Consider a number of the form hfinal signi. where there are 16 zeros. #3 . .X .\fi: \fi: #1 10137 10138 10139 } 10140 (End definition for \__fp_round_digit:Nw.e. and subtract from it hfinal signi. then this function returns \c_zero. If in the current rounding mode the result should be rounded down.0 .. { \__fp_round:Nwn #1#2. . . . 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 \cs_new:Npn \__fp_round_to_ninf_neg:NNN #1 #2 #3 { \if_meaning:w 0 #1 \if_int_compare:w #3 > \c_zero \__fp_round_return_one: \fi: \fi: \c_zero } \cs_new:Npn \__fp_round_to_zero_neg:NNN #1 #2 #3 { \if_int_compare:w #3 > \c_zero \__fp_round_return_one: \fi: \c_zero } \cs_new:Npn \__fp_round_to_pinf_neg:NNN #1 #2 #3 { \if_meaning:w 2 #1 \if_int_compare:w #3 > \c_zero \__fp_round_return_one: \fi: \fi: \c_zero } \cs_new_eq:NN \__fp_round_to_nearest_neg:NNN \__fp_round_to_nearest:NNN \cs_new_eq:NN \__fp_round_neg:NNN \__fp_round_to_nearest_neg:NNN (End definition for \__fp_round_neg:NNN. 0hdigit2 i.2 \__fp_round:Nww \__fp_round:Nwn \__fp_round_normal:NwNNnw \__fp_round_normal:NnnwNNnn \__fp_round_pack:Nw \__fp_round_normal:NNwNnn \__fp_round_normal_end:wwNnn \__fp_round_special:NwwNnn \__fp_round_special_aux:Nw 10168 10169 10170 The round function \cs_new:Npn \__fp_round:Nww #1#2 .) \__fp_round_neg:NNN \__fp_round_to_nearest_neg:NNN \__fp_round_to_ninf_neg:NNN \__fp_round_to_zero_neg:NNN \__fp_round_to_pinf_neg:NNN This expands to \c_zero or \c_one. { \__fp_small_int:wTF #3. then this function returns \c_one. And this is the default mode. if the result is rounded back to the first operand.) 24. } 519 . i. Xhdigit1 i with exactly 15 (non-all-zero) digits before hdigit1 i. Otherwise. It turns out that this negative “round to nearest” is identical to the positive one. } \cs_new:Npn \__fp_round_normal:NwNNnw #1#2 \s__fp \__fp_chk:w 1#3#4#5. #5 { \if_meaning:w 1 #2 \exp_after:wN \__fp_round_normal:NwNNnw \exp_after:wN #1 \__int_value:w #5 \else: \exp_after:wN \__fp_exp_after_o:w \fi: \s__fp \__fp_chk:w #2#3#4.10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 { \__fp_invalid_operation_tl_o:nf { round } { \__fp_array_to_clist:n { #2. #3. { \__fp_decimate:nNnnnn { \c_sixteen . #5#6 { \exp_after:wN \__fp_round_normal:NNwNnn \int_use:N \__int_eval:w \if_int_compare:w #2 > \c_zero 1 \__int_value:w #2 \exp_after:wN \__fp_round_pack:Nw \int_use:N \__int_eval:w 1#3 + \else: \if_int_compare:w #3 > \c_zero 1 \__int_value:w #3 + \fi: \fi: \exp_after:wN #5 \exp_after:wN #6 \use_none:nnnnnnn #3 #1 \__int_eval_end: 0000 0000 0000 0000 . } } } } \cs_new:Npn \__fp_round:Nwn #1 \s__fp \__fp_chk:w #2#3#4. #6 } \cs_new:Npn \__fp_round_pack:Nw #1 { \if_meaning:w 2 #1 + \c_one \fi: \__int_eval_end: } \cs_new:Npn \__fp_round_normal:NNwNnn #1 #2 { \if_meaning:w 0 #2 \exp_after:wN \__fp_round_special:NwwNnn \exp_after:wN #1 \fi: \__fp_pack_twice_four:wNNNNNNNN 520 .#4 .#2 } \__fp_round_normal:NnnwNNnn #5 #1 #3 {#4} {#2} } \cs_new:Npn \__fp_round_normal:NnnwNNnn #1#2#3#4. 15 Function calls expecting exactly one argument. #1 . { \exp_after:wN \__fp_exp_after_o:w \tex_romannumeral:D -‘0 \__fp_sanitize:Nw #1#2. These functions are documented on page ??.#3#4#5 { \exp_after:wN \__fp_exp_after_o:w \tex_romannumeral:D -‘0 \__fp_sanitize:Nw #3 #4 . {1000}{0000}{0000}{0000}. 14 Binary ** and ^ (right to left).#3.) 10248 25 h/initex | packagei l3fp-parse implementation 10249 h*initex | packagei 10250 h@@=fpi 26 Precedences In order of evaluation (some distinctions are irrelevant for the order of evaluation. but serve as signals). } (End definition for \__fp_round:Nww and \__fp_round:Nwn. 521 .#2. } \cs_new:Npn \__fp_round_special_aux:Nw #1#2. #2 } \cs_new:Npn \__fp_round_normal_end:wwNnn #1. 16 Function calls with multiple arguments. 32 Juxtaposition for implicit multiplication. } \cs_new:Npn \__fp_round_special:NwwNnn #1#2.#4#5#6 { \if_meaning:w 0 #1 \__fp_case_return:nw { \exp_after:wN \__fp_zero_fp:N \exp_after:wN #4 } \else: \exp_after:wN \__fp_round_special_aux:Nw \exp_after:wN #4 \int_use:N \__int_eval:w \c_one \if_meaning:w 1 #1 -#6 \else: +#5 \fi: \fi: .10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 \__fp_pack_twice_four:wNNNNNNNN \__fp_round_normal_end:wwNnn . and some previous failed attempts have shown me that the code ends up giving unreadable logs.) are automatically unpacked. Let us thus first discuss precisely the design before starting to write the code. -. we first consider expressions with integers only. but this has several drawbacks: 7 Bruno: describe what happens in cases like 2\c_three = 6. 1 Commas. 27 \__fp_parse:n Evaluating an expression This f-expands to the internal floating point number obtained by evaluating the hfloating point expressioni. so we’d better get it (almost) right the first time. 0 Parentheses expecting exactly one argument. each token is fully f-expanded. / and %. 5 Logical and.) 28 Work plan The task at hand is non-trivial. ! (right to left).7 (End definition for \__fp_parse:n. denoted by ||. 3 Ternary operator ?:. and parentheses accepting commas. 10 Binary *. 522 . -1 Start and end of the expression.12 Unary +. 4 Logical or. 7 Comparisons. piece ?. piece :. 28. denoted by &&. etc. 2 Ternary operator ?:. To simplify matters.1 Storing results The main issue in parsing expressions expandably is: “where in the input stream should the result be put?” One option is to place the result at the end of the expression. Invalid tokens remaining after f-expansion will lead to unrecoverable low-level TeX errors. During this evaluation. toks. TEXhackers note: Registers (integers. without requiring a function such as \int_use:N. 9 Binary + and -. and carry it as an argument of each macro.. we could note that if we were to continue parsing the expression. 333444 ... . and stops expanding. But since \__fp_parse:n does not assume that its argument is expanded._o:ww expand what follows once. The other natural option is to store the result at the start of the expression.g. then the following number should also be cleaned up before the next use of a binary operation such as \add:ww.dtx for an explanation). which can be rather expensive. this closing parenthesis may be hidden in a macro. Now. Assume that one number has already been found. Just like \__int_value:w 12345 \exp_after:wN . or registers. and \__int_value:w has already seen 12345. 333444 . causing the second \exp_after:wN to expand. But this requires adding many \exp_after:wN to the result at each step. causing havoc. This comes at the cost of leaving tokens in the input stack. which can safely perform the addition by grabbing two arguments delimited by . This is also true in our real application: all the functions of the form \__fp_. \__int_value:w sees the .. • secondly. also an expensive process. 12345. and we are left with \add:ww 12345 .. Assume then that \clean:w is such that it expands hstuff i to e. and we will need to be careful to waste as little as possible of this precious memory. we need \add:ww to do the calculation. when parsing parenthesized sub-expressions. expanded what follows once. and not present yet. On this toy example. which reads an integer. and in the process to expand the following once. A toy model that illustrates this idea is to try and add some positive integers which may be hidden within macros.. This integer is unfinished. which triggers the primitive \__int_value:w. Hence. . The current status of the code may look as follows. where in fact \exp_after:wN has already been expanded. we would naturally place the result after the corresponding closing parenthesis. \tex_romannumeral:D -‘0 \clean:w hstuff i Hitting this construction by one step of expansion expands \exp_after:wN. we need to skip at each step over all the tokens in the result using \exp_after:wN. and trigger the construction \tex_romannumeral:D -‘0. This does not really work either: in order to expand what follows on the input stream. 333444.• firstly it means that for long expressions we would be reaching all the way to the end of the expression at every step of the calculation. we will obtain essentially \exp_after:wN \add:ww \__int_value:w 12345 . and that we want to parse the next number. \exp_after:wN \add:ww \__int_value:w 12345 \exp_after:wN . which f-expands \clean:w (see l3expan. Once \clean:w is done expanding. we need to go for some fine expansion control: the result is stored before the start. 523 . 1+2^3*4 would involve the following steps. then just end our job. • 2 is cleaned up. • The precedences of + and * are compared. the second operand of * should be cleaned. Since the latter is higher. let us assume that the operation which prompted \clean:w was a multiplication.28. Hence. • 4 is cleaned up. • Compute 2^3 = 8. • The precedences of + and ^ are compared. The true analog of our toy \clean:w macro must thus take care of that. Thus the true definition is slightly more elaborate. For definiteness. • We now have 1+8*4.2 Precedence A major point to keep in mind when parsing expressions is that different operators have different precedence. Since the latter is higher. itself smaller than * and /. the precedence of the following operation must be compared to that of the previous operation. • The precedences of ^ and * are compared. Since the former is higher. • Compute 8*4 = 32. the cleaning step stops. • 1 is cleaned up. and reach the end of the expression. and smaller than the precedence of + and -. However. The precedence of ( and ) are defined to be equal. If this is + or -. • 3 is cleaned up. if the operator we find is ^. the second operand of ^ should be cleaned. and the operation + is still looking for a second operand. then the multiplication should be calculated next. For instance. smaller. and the operation + is still looking for a second operand. • Compute 1+32 = 33. Then \clean:w (expand and) read digits until the number is ended by some operation. then this operation must be performed before returning control to the multiplication. Clean 8. finally. there is some (expensive) redundant work: the results of computations should not need to be cleaned again. and perform the calculation. and the end of the expression is reached. Clean 32. then the power operator ** (or ^). each time a number is cleaned. so \clean:w can simply decide that its job is done. • We now have 1+8*4. Here. 524 . The process of course has to happen recursively. This means that we need to \clean:w the number following ^. . \infix_? The dots are \__fp_parse_apply_binary:NwNwN *. Otherwise. 525 . and it expands (essentially) to \until hpreci \__fp_*_o:ww hfloating pointi hfloating point2 i \tex_romannumeral:D -‘0 \infix_? hpreci making TEX expand \__fp_*_o:ww before \until. which both take as their first argument the precedence (an integer) of the last operation. This is followed by a control sequence of the form \infix_?.3 Infix operators The implementation that was chosen is slightly wasteful: it causes more nesting than necessary. The f-expansion of \until hpreci \one hpreci hstuff i is the internal floating point obtained by “cleaning” numbers which follow in the input stream. The boolean tells \until that it is not done.28. \one hpreci reads one hfloating pointi number. This should be easier to see on an example. and performing computations until reaching an operation with a precedence less than or equal to hpreci. hfloating point2 i . otherwise it would have been performed already). it is simpler to implement and to explain than a slightly optimized variant. and converts it to an internal form. How is that expansion achieved? First. which is fed the hpreci. hfloating pointi \infix_? where ? is the operation following that number in the input stream (we thus know that this operation has at most the precedence hpreci. and hpreci.. for instance. To each infix operator. This triggers \tex_romannumeral:D. This function (one per infix operator) compares hpreci with the precedence of the operator we just read (here *). is associated the following data: • a test function. However. or if ? should be computed as well before \until hpreci ends. If hpreci is higher. our job is finished. This compares the precedence of the next operation. and \one leaves \__fp_parse_stop_until:N so that \until knows to stop. which is then checked by \until hpreci to know if the result of the multiplication is the end of the story. and leaves a boolean (and possibly more things). which fully expands \infix_? hpreci. namely. \infix_* triggers a new pair \until hprec(*)i \one hprec(*)i. *. \infix_*. \until and \one. then the following operation. which conditionally continues the calculation or waits to be hit again by expansion. ?. which produces the second operand hfloating point2 i for the multiplication: \until hpreci hfloating pointi . this operation expands what follows its result exactly once. The cornerstone of that method is a pair of functions. As implemented in l3fp-basics. is packed in the form \infix_*. say *. depending on the place). we add a trailing right parenthesis. when controlling expansion.9 ) \until( 11. 5. F + \until+ 8.9 ) \until( 11. which encodes the precedence of the operator. \infix_-+ 9 ) \until( 11. \infix_-* 9 ) \until( 11. In a first reading. \infix_*+ 5 .9 ) \until( 11.9 ) \until( 11. F ** 3. and in red. T \infix_. F + \until+ \one+ 2**3 * 5 . F + \until+ ** 2. \infix_* 5 .• a function * (notation for \__fp_*_o:ww) which performs the actual calculation. \infix_*+ 5 . F + \until+ 8.9 ) \until( 11. F + \until+ 2. F + \until+ 40. To end the computation cleanly.9 ) \until( 11. \infix_+( 2**3 * 5 . F * \until* 5 \one* .9 ) \until( 11. F + \until+ 2. F + \until+ 8. and give ( and ) the lowest precedence. It is only required to accomodate for multi-token infix operators such as **: indeed.9 ) \until( 11. F + \until+ 2. Tokens that have not yet been read (and could still be hidden in macros) are in gray.9 ) 526 . \infix_-+ 9 ) \until( 11. \until( \one( 11 + 2**3 * 5 . F + \until+ 2. F + \until+ 8.9 ) \until( 11. F * \until* \one* 5 . T \infix_* 5 . F + \until+ 8. F + \until+ 2. the disinction between the hprecedencei +. F * \until* 5.9 ) \until( 11 \one( + 2**3 * 5 .9 ) \until( 11. F ** \until** 3 \one** * 5 . F + \until+ 8. 3. the operation +.9 ) \until( 11. F + \until+ 2. F + 40. F * \until* 5.9 ) \until( 1 \one( 1 + 2**3 * 5 . and this only skips one token. *. The token that is currently being expanded is underlined.9 ) \until( 11. F + \until+ 2 \one+ **3 * 5 . Thus ** needs to be replaced by a single token (either its precedence or its calculating function.9 ) \until( 11.9 ) \until( 11.9 ) \until( 11. so that \until( \one( reads numbers and performs operations until meeting a right parenthesis.9 ) \until( 11. and the character token + should not matter. F ** \until** 3. \infix_. This is discussed more precisely in the next section. F ** \until** \one** 3 * 5 . F ** \until** 3. • an integer. \infix_**+ 3 * 5 . \infix_. F + \until+ 40. \infix_*** 5 . F * 5. F + \until+ * 8. we need to skip over those tokens using \exp_after:wN. T \infix_.9 ) \until( 11. the \prefix_? functions perform no test on their argument (which is once more the previous precedence).) as well. 28.. and possibly checking that nothing else remains. a dot. F . Then ( removes \infix_) and looks ahead for the next operation. 40. A left parenthesis is just a prefix operator which removes the closing parenthesis (with some extra checks). etc. then we have a number. which is expanded.. \infix_)( \until( 42. parentheses.\until. \infix_) \until( . Otherwise. T \infix_) 42. F . 9. it is put in a function. \infix_-( 9 ) \until( 51. comparing its precedence with the precedence * of the previous operation (in fact. with a left parenthesis we would have the following. F . for instance. Detecting prefix operators is done by \one. is very similar to grabbing the second operand of a binary infix operator.9.\until( + 11.\one.) \until( 51. If it is a digit. \one* ( 2 + 3 ) \prefix_(* 2 + 3 ) (* \until( \one( 2 + 3 ) . the \until–\one pair reads and compute until reaching an operator of precedence at most (. \infix_-( 9 ) \until( 51. T \infix_) \until( 51. See implementation for details. we may need to put more than one character in the \prefix_? construction. and must never stop there. F .\until.9 \one.9 ) \until( 51. Note that contrarily to \infix_? functions. \infix_) The only missing step is to clean the output by removing \infix_). exp. Once that argument is found.9.4 Prefix operators. it tests the first character.\until. F .\until. since we know that we need a number. or a register. and functions (sin. its sign can be flipped. \infix_) As usual.9. \infix_)( \until( 42. (* 5. this comparison is done by the relevant \infix_? built from the next operation). For instance. Finding the argument of the unary -. \infix_)\until( 51. and functions Prefix operators (typically the unary -) and parentheses are taken care of by the same mechanism. To support multi-character function (and constant) names.51. with a small subtelty on precedence explained below. Before looking for a number. 527 . \prefix_? (where ? is roughly that first character). Unfortunately.itself only matters when it follows a left parenthesis: (-2*4+3) should give ((-8)+3). In fact.is found. Once the argument of . F + \until+ 3. \infix_*( ( 2 + 3 ) . F * \until* \one* ( 2 + 3 ) .9 ) \until( 11.9 ) \until( 11.9 ) \until( 11. so that their argument is the first number that can possibly be built. just give . T \infix_) -9) \until( 11. \infix_) .9 ) \until( 1 \one( 1 * ( 2 + 3 ) . F + \until+ 3. An example with parentheses.Functions are implemented as prefix operators with infinitely high precedence. For instance.. equal to that of the infix + and -.9 ) \until( 11. and leaves it for the previous operation to use.9 ) 8 Taking into account the precedence of . F * \until* (* \until( 2 \one( + 3 ) . something like the following could happen in a computation \one* sqrt 4 + 3 ) \prefix_sqrt* 4 + 3 ) sqrt* \until∞ \one∞ 4 + 3 ) .9 ) \until( 11. this fails in subtle cases such as 3**-2*4. to be put somewhere: 2+sin 1 * 3 is 2 + (sin(1) × 3). F * \until* (* \until( 2. yielding 3−2×4 instead of the correct 3−2 × 4. F + \until+ \one+ 3)-9) \until( 11. Easy. . F * \until* \prefix_(* 2 + 3 ) . not (-(8+3)). and not (−3)2 = 9.9 ) \until( 11.hprec i \until? \one ? where ? is the maximum of hpreci and the precedence of -.gets its opposite. \infix_)+ -9) \until( 11. F + \until+ 3 \one+ )-9) \until( 11. \infix_+ 3 ) 2.a lower precedence. F * \until* (* \until( 2. F * \until* (* \until( 2. F + 3. a unary .8 Thus. \infix_+( 3 ) .. as well as -.should only perform operations whose precedence is greater than that of the last operation.9 ) \until( 11 \one( * ( 2 + 3 ) .sign: -3**2 should be −(32 ) = −9. F * \until* (* \until( 2. F * \until* (* \until( 2. \prefix_hpreci expands to something like . \infix_+* 3 ) Lonely example. A further complication arises in the case of the unary . F * \until* (* \until( 2. F * \until* (* \until( \one( 2 + 3 ) . \until( \one( 11 * ( 2 + 3 ) . 528 .9 ) \until( 11. sqrt* 4. \until.9 ) \until( 11. for including comments inside the computation itself?? 10 Keyword argument support may be added later.9 ) \until( * 11. \infix_) The end of this (sub)section was not revised yet • If it is a sign (.9. F * 5.55. then any following letter is grabbed.9 ) \until( 11.9. \infix_) \until( . F * \until* (* 5. \infix_)( . 9. for instance \prefix_(. F . only one token9 is grabbed.9 ) \until( 55.) \until( 55. 5. • If it is a letter. • round now has its first argument. \infix_-* 9 ) \until( 11. • Otherwise. F * \until* 5. but right now. possibly an unknown number10 . T \infix_) 47.or +).\until.\until. I don’t see a use for it.9.9 ) \until( 11. F . forming \prefix_+ or \prefix_-. F . Perhaps. for instance round(1. The comma is given the same precedence as parentheses. T \infix_. \infix_-( 9 ) \until( 55. calculating as necessary. F * \until* 5. T \infix_) . F * \until* (* \until( + 2.2).9 ) \until( 11. which tries to grab one number using \one.9 ) \until( 11. F . Functions may take several arguments. 9 Some support for multi-character prefix operator may be added in the future. forming for instance \prefix_sin or \prefix_sinh. \infix_)\until( 55. \infix_) . F . 529 .\one. • This builds \prefix_(. F * \until* (* \until( 5. \infix_)( \until( 47. or ).23456. F * \until* (* \until( 5. It can check whether the argument was closed by . \infix_)( . \infix_-( 9 ) \until( 55. and branch accordingly. and thus ends the calculation of the argument of round. \infix_. \infix_)( \until( 47.\until( 11. 3.9 \one. then any following sign will be combined with this initial sign. which uses \one to grab one number. • round is made into \prefix_round.\until. T \infix_) \until( 55. Every floating point operation calls those functions to normalize the input. Thus. Since floating point numbers are always accessed by the various operations using f-expansion. when used directly without an accessor function. Also. and \__fp_chk:w produces an error. build \__fp_<abc>:w when seeing some nonnumeric abc while still looking to complete a number (or other data). • The closing parenthesis (or another comma) is seen. floating points should produce an error. use it. then the first argument is skipped over. Here it is simply an integer. 3 quiet and signalling nan. 2 infinities: +inf and -inf. Internal floating point numbers will be used in expressions. The various possibilities will be distinguished by their hcasei. 11 Bruno: I need to implement subnormal numbers. easier to parse by building upon \etex_numexpr:D. and we provide here the tools to convert from a more user-friendly representation to internal floating point numbers. which is a single digit:11 0 zeros: +0 and -0. and for various other conversions. 29 Internal representation Internally. Or should the type be obtained after the semicolon which indicates the end of the thing? And placed there? Also to grab exponents correctly. a floating point number hX i is a token list containing \s__fp \__fp_chk:w hcasei hsigni hbodyi . The internal representation of floating point numbers is quite untypable. However. if \__fp_postfix_<type>_<abc>:w exists.• If it was a comma. 28. Let us explain each piece separately. through an expensive set of \exp_after:wN. and the control is given back to \prefix_round. They must leave a recognizable mark after f-expansion. The (decimal part of the) IEEE-754-2008 standard requires the format to be able to represent special floating point numbers besides the usual positive and negative cases. \s__fp is simply another name for \relax.5 Type detection The type of data should be detected by reading the first few tokens. Then. and in this context will be subject to f-expansion. and the second argument can be grabbed. 530 . 1 “normal” numbers (positive and negative). so they must be optimized. we can safely let them be protected: x-expansion will then leave them untouched. to prevent the floating point number from being re-parsed. quiet and signalling nan must be better distinguished. \s__fp will do nothing. before calling a type-specific function to parse it. . Normal floating point numbers (hcasei = 1) have the form \s__fp \__fp_chk:w 1 hsigni {hexponenti} {hX1 i} {hX2 i} {hX3 i} {hX4 i} .) \__fp_parse_operand:Nw If the following hoperationi has a precedence higher than hprecedencei. is a scan mark carrying information about how the number was formed (useful for debugging). . 30 \__fp_parse_until:Nw Internal parsing functions Reads the htokensi. Negative infinity. ...... \s__fp_. Signalling nan. the hexponenti is an integer. \s__fp_... expands to Otherwise expands to (End definition for \__fp_parse_infix_\metaoperation:N. Quiet nan.Table 1: Internal representation of floating point numbers. \s__fp_.. Negative zero. 0000 ≤ hXi i ≤ 9999.. which have hsigni = 1.. {hexponenti} {hX1 i} {hX2 i} {hX3 i} {hX4 i} .) \__fp_parse_infix_\meta{operation}:N If the hopi has a precedence higher than hprecedencei. .. where \s__fp_. The hsigni is 0 (positive) or 2 (negative). {hexponenti} {hX1 i} {hX2 i} {hX3 i} {hX4 i} . This implies 1000 ≤ hX1 i ≤ 9999. then expands to where the hopi is the first operation with a lower precedence. Representation Meaning 0 0 1 1 2 2 3 3 0 2 0 2 0 2 1 1 \s__fp_. at most \c__fp_max_exponent_int = 10000 in absolute value.. Positive infinity. The body consists in four blocks of exactly 4 digits.) 531 .. Negative floating point.. possibly end. . \s__fp_. except in the case of nan. Positive zero. .. This ensures that changing the hsigni digit to 2 − hsigni is exactly equivalent to changing the sign of the number. \s__fp_. Here. Positive floating point. expands to and otherwise expands to (End definition for \__fp_parse_operand:Nw. performing every computation with a precedence higher than hprecedencei. (End definition for \__fp_parse_until:Nw. Special floating point numbers have the form \s__fp \__fp_chk:w hcasei hsigni \s__fp_.. . such that 4 X hX i = (−1)hsigni 10−hexponenti hXi i10−4i i=1 and such that the hexponenti is minimal. ) \__fp_parse_return_semicolon:w This very odd function swaps its position with the following \fi: and removes \__fp_- parse_expand:w normally responsible for expansion. since a macro’s expansion could contain leading spaces which will stop the fexpansion before further macro calls are performed.30. this expansion is stopped by spaces. This can be problematic: for instance. forcing the expansion of protected macros. full-expansion should be performed as the expression is read. structure. \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} } \ExplSyntaxOff \test { 1 + \X } To avoid this problem. . floating point numbers will correctly be expanded to the underlying \s__fp . 10251 \cs_new:Npn \__fp_parse_expand:w #1 { -‘0 #1 } (End definition for \__fp_parse_expand:w. This requires in particular closing all conditionals properly before expanding. and ignoring spaces. The htokensi should be the part of the expression that we have not yet read. Floating point expressions should behave as much as possible like ε-TEX-based integer expressions and dimension expressions. spaces stop this f-expansion.1 Expansion control At each step in reading a floating point expression. Full expansion can be done with \tex_romannumeral:D -‘0. but may very easily come in document-level input. we wish to perform f-expansion. However. replace \c_nine by \c_ten. We can avoid being stopped by such explicit space characters (and by some braces) if we add \use:n after -‘0. . That turns out to be useful.) 532 . spaces will not appear in a code setting. then f-expand it. In particular. Of course. from which some expressions may come. #1 } (End definition for \__fp_parse_return_semicolon:w. the macro \X below will not be expanded if we simply do f-expansion. at every step. Thus using simply this will fail on \fp_eval:n { 1 + ~ \l_tmpa_fp } since the floating point variable will not be expanded. Normally. \__fp_parse_expand:w This function must always come within a \romannumeral expansion. we do essentially what \use:f would do: take an argument. The use of \token_to_str:N ensures that a digit with any catcode is detected. put it back in the input stream. Testing if a character token #1 is a digit can be done using \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: true code \else: false code \fi: To exclude 0. This is not a complete solution. token by token. 10252 10253 \cs_new:Npn \__fp_parse_return_semicolon:w #1 \fi: \__fp_parse_expand:w { \fi: . in practice it should be enough: in particular. Unfortunately. The first token which follows must be f-expanded prior to calling those functions. If the htokeni does not contain that string. The functions read tokens one by one.} { ‘\_ } \tl_to_lowercase:n { \group_end: \cs_new:Npn \__fp_type_from_scan:N #1 { \exp_after:wN \__fp_type_from_scan:w \token_to_str:N #1 \q_mark S--FP-? \q_mark \q_stop } \cs_new:Npn \__fp_type_from_scan:w #1 S--FP #2 \q_mark #3 \q_stop {#2} } (End definition for \__fp_type_from_scan:N and \__fp_type_from_scan:w.) 30.2 \__fp_type_from_scan:N \__fp_type_from_scan:w Fp object type Grabs the pieces of the stringified htokeni which lies after the first s__fp. hfilling 0 i . 7 } 533 . The full expansion is hdigitsi . or up to a number of digits equal to their index. the result is _?. and output digits into the input stream.3 \__fp_parse_digits_vii:N \__fp_parse_digits_vi:N \__fp_parse_digits_v:N \__fp_parse_digits_iv:N \__fp_parse_digits_iii:N \__fp_parse_digits_ii:N \__fp_parse_digits_i:N Reading digits These functions must be called within an \__int_value:w or \__int_eval:w construction. We are careful to pass the tested tokens through \token_to_str:N to normalize their category code. 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 \cs_set_protected:Npn \__fp_tmp:w #1 #2 #3 { \cs_new:cpn { __fp_parse_digits_ #1 :N } ##1 { \if_int_compare:w \c_nine < 1 \token_to_str:N ##1 \exp_stop_f: \token_to_str:N ##1 \exp_after:wN #2 \tex_romannumeral:D \else: \__fp_parse_return_semicolon:w #3 ##1 \fi: \__fp_parse_expand:w } } \__fp_tmp:w {vii} \__fp_parse_digits_vi:N { 0000000 . until we find a non-digit.30. 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 \group_begin: \char_set_catcode_other:N \S \char_set_catcode_other:N \F \char_set_catcode_other:N \P \char_set_lccode:nn { ‘\. until meeting a non-digit. and hlengthi is the number of zeros in the hfilling 0 i string. Each function puts a digit into the input stream and calls the next function. hlengthi where hfilling 0 i is a string of zeros such that hdigitsi hfilling 0 i has the length given by the index of the function. Characters such as * or / have a meaning as infix operators but are not valid when we are looking for an operand: for instance.10282 10283 10284 10285 10286 10287 10288 \__fp_tmp:w {vi} \__fp_parse_digits_v:N { 000000 . for instance. 1 } \cs_new_nopar:Npn \__fp_parse_digits_:N { . #1 is the previous hprecedencei. and they are further distinguished with a meaning test. \__fp_parse_operand:Nw Function called \one at other places. 2 } \__fp_tmp:w {i} \__fp_parse_digits_:N { 0 . and packs the symbol that follows in an \infix_ csname. which starts an identifier. It grabs one operand. 3 } \__fp_tmp:w {ii} \__fp_parse_digits_i:N { 00 . . This is subtely different from unpacking it. or a dot. etc. That can be an internal floating point. This can be an explicit floating point number. or just following a binary operation or a function call. All other characters are taken care of by building a csname from that character and using it to continue parsing.) 30. or !. A category code test separates the first two cases from the others. 10289 10290 10291 \cs_new:Npn \__fp_parse_operand:Nw #1 #2 { \if_catcode:w \tex_relax:D #2 534 . a TEX register. We then single out digits. or an unitialized register.4 Parsing one operand At the start of an expression. which makes us parse a subexpression until the matching ). and #2 the first character of the operand (already f-expanded). 4 } \__fp_tmp:w {iii} \__fp_parse_digits_ii:N { 000 . • +. 6 } \__fp_tmp:w {v} \__fp_parse_digits_iv:N { 00000 . 5 } \__fp_tmp:w {iv} \__fp_parse_digits_iii:N { 0000 . That marks the start of the significand for a floating point number. unary operators. • A letter (lower or upper-case). -. \c_minus_one**2 gives 1. • Other characters such as ’ or " may be given a meaning later. which resume looking for a floating point number before acting on it. while -1**2 gives −1. We distinguish the various cases by their first token after f-expansion: • \tex_relax:D in some form. a premature end. We interpret this as the significand of a floating point number. • (. • A digit. • A register. 3+*4 is not valid. a floating point variable. Letters are detected using their character code. Unknown characters lead to an error. either a constant or a function (possibly unknown). a function call such as sin(3). 0 } (End definition for \__fp_parse_digits_vii:N and others. a parenthesized expression. we are looking for an operand. ) \__fp_parse_operand_register:NN Find the exponent following the register #2. then combine the value of #2 (mapping 1pt \__fp_parse_operand_register_aux:www to 1) with the exponent to produce a floating point number.\if_meaning:w \tex_relax:D #2 \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_operand_relax:NN \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_operand_register:NN \fi: \else: \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_operand_digit:NN \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_operand_other:NN \fi: \fi: #1 #2 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 } (End definition for \__fp_parse_operand:Nw. There are three cases. \__fp_parse_exp_after_mark_f:nw \__fp_parse_exp_after_?_f:nw 535 . \__fp_parse_exp_after_f:nw dispatched using \__fp_type_from_scan:N. 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 \group_begin: \char_set_catcode_other:N \P \char_set_catcode_other:N \T \tl_to_lowercase:n { \group_end: \cs_new:Npn \__fp_parse_operand_register:NN #1#2 { \exp_after:wN \__fp_parse_infix_after_operand:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \exp_after:wN \__fp_parse_operand_register_aux:www \tex_the:D \exp_after:wN #2 \exp_after:wN P \exp_after:wN T \exp_after:wN \q_stop \__int_value:w \__fp_parse_exponent:N } \cs_new:Npn \__fp_parse_operand_register_aux:www #1 PT #2 \q_stop #3 .) \__fp_parse_operand_relax:NN The second argument is a control sequence equal to \tex_relax:D. { \__fp_parse:n { #1 e #3 } } } (End definition for \__fp_parse_operand_register:NN and \__fp_parse_operand_register_aux:www. 10355 10356 10357 10358 10359 10360 10361 \cs_new:Npn \__fp_parse_operand_other:NN #1 #2 { \if_int_compare:w \__int_eval:w \tex_uccode:D ‘#2 / 26 = \c_three \exp_after:wN \__fp_parse_operand_other_word_aux:Nw \exp_after:wN #1 \tex_romannumeral:D 536 . It separates letters from nonletters and builds the appropriate \prefix function. causing a bad-variable error. 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 \cs_new:Npn \__fp_parse_operand_relax:NN #1#2 { \cs:w __fp_parse_exp_after \__fp_type_from_scan:N #2 _f:nw \cs_end: { \exp_after:wN \__fp_parse_infix:NN \exp_after:wN #1 \tex_romannumeral:D \__fp_parse_expand:w } #2 } \cs_new_eq:NN \__fp_parse_exp_after_f:nw \__fp_exp_after_f:nw \cs_new:Npn \__fp_parse_exp_after_mark_f:nw #1 { \__msg_kernel_expandable_error:nn { kernel } { fp-early-end } \exp_after:wN \c_nan_fp \tex_romannumeral:D -‘0 #1 } \cs_new:cpn { __fp_parse_exp_after_?_f:nw } #1#2 { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2} \exp_after:wN \c_nan_fp \tex_romannumeral:D -‘0 #1 } (End definition for \__fp_parse_operand_relax:NN and others. which f-expands after the floating point. • \s__fp_mark is a premature end.• \s__fp starts a floating point number. • For a control sequence not containing \s__fp. we call \__fp_parse_exp_after_?_f:nw. as the unknown “prefix” can also be a (mistyped) constant such as Inf. If it is not defined (is \tex_relax:D). make it a signalling nan.) \__fp_parse_operand_other:NN The interesting bit is \__fp_parse_operand_other:NN. which triggers the appropriate error. we call \__fp_parse_exp_after_mark_f:nw. we make sure that the last argument of \__fp_parse_infix:NN is correctly expanded. We don’t look for an argument. and we call \__fp_parse_exp_after_f:nw. This scheme is extensible: additional types can be added by starting the variables with a scan mark of the form \s__fp_htypei and defining \__fp_parse_exp_after_htypei_f:nw. In all cases. \exp_after:wN \__fp_parse_letters:NN \exp_after:wN #2 \tex_romannumeral:D \else: \exp_after:wN \__fp_parse_operand_other_prefix_aux:NNN \exp_after:wN #1 \exp_after:wN #2 \cs:w __fp_parse_prefix_#2:Nw \exp_after:wN \cs_end: \tex_romannumeral:D \fi: \__fp_parse_expand:w 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 } 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 \cs_new:Npn \__fp_parse_letters:NN #1#2 { \exp_after:wN \c_zero \exp_after:wN #1 \tex_romannumeral:D \if_int_compare:w \if_catcode:w \tex_relax:D #2 \c_zero \else: \__int_eval:w \tex_uccode:D ‘#2 / 26 \fi: = \c_three \exp_after:wN \__fp_parse_letters:NN \exp_after:wN #2 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN \c_zero \exp_after:wN . { \cs_if_exist_use:cF { __fp_parse_word_#2:N } { \__msg_kernel_expandable_error:nnn { kernel } { unknown-fp-word } {#2} \exp_after:wN \c_nan_fp \tex_romannumeral:D -‘0 \__fp_parse_infix:NN } #1 } \cs_new_eq:NN \s__fp_unknown \tex_relax:D \cs_new:Npn \__fp_parse_operand_other_prefix_aux:NNN #1#2#3 { 537 . \exp_after:wN #2 \fi: } \cs_new:Npn \__fp_parse_operand_other_word_aux:Nw #1 #2. It stops at the first non-digit character. the hintegeri is a sequence of digits. 5. 6. • A number with no dot has zero decimal part. The hexponenti part has the form hexponent signi hexponent bodyi. 10. and hexponent bodyi is a string of digits. • An empty hintegeri part or decimal part is zero. The hdecimali part is formed by all digits from the dot (if it exists) until the first non-digit character. 538 . at the first non-digit. Any missing part will take the appropriate default value.\if_meaning:w \tex_relax:D #3 \exp_after:wN \__fp_parse_operand_other_prefix_unknown:NNN \exp_after:wN #2 \fi: #3 #1 10412 10413 10414 10415 10416 } \cs_new:Npn \__fp_parse_operand_other_prefix_unknown:NNN #1#2#3 { \cs_if_exist:cTF { __fp_parse_infix_#1:N } { \__msg_kernel_expandable_error:nnn { kernel } { fp-missing-number } {#1} \exp_after:wN \c_nan_fp \tex_romannumeral:D -‘0 \__fp_parse_infix:NN #3 #1 } { \__msg_kernel_expandable_error:nnn { kernel } { fp-unknown-symbol } {#1} \__fp_parse_operand:Nw #3 } } 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 (End definition for \__fp_parse_operand_other:NN.13 In the second form. hdecimali e hexponenti In both cases. 7. Border cases: 12 Bruno: except 1. 13. 2. 11. stopping. whose length is not limited by constraints TEX’s integer registers. 12. just 3. hsignsi is a (possibly empty) string of + and . 13 Bruno: test (and implement) non-other digits. where hexponent signi is any string of + or -. • A missing hexponenti is considered to be zero. 8. so really. 9).) The following forms are accepted: • • hfloating pointi • hintegeri . 4.(with any category code12 ). and those which cannot be tokens (0. as usual. e3 and . and we call \__fp_parse_zero: to take care of that case. go to the “special” branch. our number is exactly zero.• e1 is considered as invalid input. Only f-expansion at the start.4. Work-plan. It removes any leading zero. • Remove any leading sign and build the hsigni as we go.1 \__fp_parse_trim_zeros:N \__fp_parse_trim_end:w Trimming leading zeros This function expects an already expanded token.14 This will be important once parsing expressions is implemented. read the exponent hexp2 i. 539 . • Finally check that nothing is left. keeping track of how many were dropped after the dot.) 30. Bruno: expansion. then continue trimming zeros with \__fp_parse_strim_zeros:N. discussed later. since e-1 would be ambiguous otherwise. drop some more zeros.15 \__fp_parse_operand_digit:NN 10434 10435 10436 10437 10438 10439 10440 10441 \cs_new:Npn \__fp_parse_operand_digit:NN #1 { \exp_after:wN \__fp_parse_infix_after_operand:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \exp_after:wN \__fp_sanitize:wN \int_use:N \__int_eval:w \c_zero \__fp_parse_trim_zeros:N } (End definition for \__fp_parse_operand_digit:NN. Then read the decimal part with the \__fp_from_str_small functions. and unpacking of registers after signs. otherwise. not done yet. This is implemented through the more elaborate \__fp_from_str_large functions. • Continuing in the same line of expansion. hexp1 i = 0. Counting those gives hexp1 i < 0.. then distinguished three cases: if the first non-zero token is a digit. • Drop leading zeros. • Otherwise. 10442 10443 10444 10445 \cs_new:Npn \__fp_parse_trim_zeros:N #1 { \if:w 0 #1 \exp_after:wN \__fp_parse_trim_zeros:N 14 Bruno: 15 Bruno: now just gives an error. not yet. are zero. then the decimal part. If the next character is a letter. if it is . • . and gives qnan. then call \__fp_parse_large:N (the significand is ≥ 1). and first read the integer part. • If the next character is a dot. the number is an exact zero.) \__fp_parse_strim_zeros:N \__fp_parse_strim_end:w If we have removed all digits until a period (or if the body started with a period).\c_one \exp_after:wN \__fp_parse_strim_zeros:N \tex_romannumeral:D \else: \__fp_parse_strim_end:w #1 \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_strim_end:w #1 \fi: \__fp_parse_expand:w { \fi: \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: \exp_after:wN \__fp_parse_small:N \else: \exp_after:wN \__fp_parse_zero: \fi: #1 540 . 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 \cs_new:Npn \__fp_parse_strim_zeros:N #1 { \if:w 0 #1 . and otherwise.10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 \tex_romannumeral:D \else: \if:w . If the first non-zero token is a digit. then enter the “small_trim” loop which outputs −1 for each removed 0. call \__fp_parse_small:N (our significand is smaller than 1). #1 \exp_after:wN \__fp_parse_strim_zeros:N \tex_romannumeral:D \else: \__fp_parse_trim_end:w #1 \fi: \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_trim_end:w #1 \fi: \fi: \__fp_parse_expand:w { \fi: \fi: \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: \exp_after:wN \__fp_parse_large:N \else: \exp_after:wN \__fp_parse_zero: \fi: #1 } (End definition for \__fp_parse_trim_zeros:N and \__fp_parse_trim_end:w. Those −1 are added to an integer expression waiting for the exponent. If #4 is a digit. 10503 10504 10505 10506 10507 \cs_new:Npn \__fp_parse_small_leading:wwNN 1 #1 . #3 #4 { #1 #2 \exp_after:wN \__fp_parse_pack_trailing:NNNNNNww \exp_after:wN \c_zero 541 . 10494 10495 10496 10497 10498 10499 10500 10501 10502 \cs_new:Npn \__fp_parse_small:N #1 { \exp_after:wN \__fp_parse_pack_leading:NNNNNww \int_use:N \__int_eval:w 1 \token_to_str:N #1 \exp_after:wN \__fp_parse_small_leading:wwNN \__int_value:w 1 \exp_after:wN \__fp_parse_digits_vii:N \tex_romannumeral:D \__fp_parse_expand:w } (End definition for \__fp_parse_small:N. Since #1 is a digit. with an exponent shift of \c_zero (this shift is used in the case of a large significand).) \__fp_parse_small_leading:wwNN We leave hdigitsi hzerosi in the input stream: the functions used to grab digits are such that this constitutes digits 1 through 8 of the significand.) 30.4. leave it behind for the packing function. But we can’t do that all at once. then put a sign of 1 for \__fp_sanitize:wN. It is followed by a non-zero digit (with any catcode). #2. Hence we grab digits in two steps of 8 digits. Then the pack_leading auxiliary puts the various parts in the appropriate order for the processing further up. denoting an exact zero. Otherwise put 8 zeros in to complete the significand. Then prepare to pack 8 more digits.4.} 10488 (End definition for \__fp_parse_strim_zeros:N and \__fp_parse_strim_end:w. and grab some more. The goal is to read up to 16 digits. read seven more digits using \__fp_parse_digits_vii:N. \exp_after:wN 1 \__int_value:w \__fp_parse_exponent:N } (End definition for \__fp_parse_zero:.3 \__fp_parse_small:N Small significand This function is called after we have passed the decimal separator and removed all leading zeros from the significand. then look for an exponent.2 \__fp_parse_zero: Exact zero After reading a significand of 0.) 30. and read 6 more digits to reach a total of 15 digits: further digits are involved in the rounding. The small_leading auxiliary will leave those digits in the \__int_value:w. because \__int_value:w (which allows us to collect digits and continue expanding) can only go up to 9 digits. 10489 10490 10491 10492 10493 \cs_new:Npn \__fp_parse_zero: { \exp_after:wN . we need to remove any exponent. or stop if there are no more digits. . and look for an exponent. there is no 16-th digit.. #8 + #1 . syntax. { \if_meaning:w 2 #2 + \c_one \fi: . If the trailing digits cause a carry. {#3#4#5#6} {#7}. \__fp_parse_pack_leading:NNNNNww as well as the exponent.. to 1000. 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 \cs_new:Npn \__fp_parse_small_trailing:wwNN 1 #1 . The last argument is the exponent. which we add to the exponent found in the e. we keep it. The previous five arguments \__fp_parse_pack_carry:w are 8 digits which we pack in groups of 4. except in the rare case where rounding lead to a carry. Otherwise. we took care of the rounding. in which case the argument is 2. the integer expression for the leading digits is incremented (+ \c_one in the code below). If the hnext tokeni is a digit. the function \__fp_parse_pack_carry:w increments the exponent. and changes the significand from 0000. then the small_round auxiliary considers this digit and all further digits to perform the rounding: the function expands to nothing or to +1. } 542 . #3 #4 { #1 #2 \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: \token_to_str:N #4 \exp_after:wN \__fp_parse_small_round:NN \exp_after:wN #4 \tex_romannumeral:D \else: 0 \__fp_parse_exponent:Nw #4 \fi: \__fp_parse_expand:w } (End definition for \__fp_parse_small_trailing:wwNN.\int_use:N \__int_eval:w 1 \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: \token_to_str:N #4 \exp_after:wN \__fp_parse_small_trailing:wwNN \__int_value:w 1 \exp_after:wN \__fp_parse_digits_vi:N \tex_romannumeral:D \else: 0000 0000 \__fp_parse_exponent:Nw #4 \fi: \__fp_parse_expand:w 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 } (End definition for \__fp_parse_small_leading:wwNN.. it is the 16th digit.) \__fp_parse_small_trailing:wwNN Leave digits 10 to 15 (arguments #1 and #2) in the input stream. The trailing function has an exponent shift as its first argument. so we put a 0... 10533 10534 10535 10536 10537 \cs_new:Npn \__fp_parse_pack_trailing:NNNNNNww #1 #2 #3#4#5#6 #7.: this is simple because such a carry can only occur to give rise to a power of 10. and the argument before that is 1. #2. If the leading digits propagate this carry all the way up. #8 .) \__fp_parse_pack_trailing:NNNNNNww Those functions are expanded after all the digits are found. ) 30. insert the hzerosi to complete the 8 first digits. We also need to test for the presence of a dot each time we run out of digits. 0 {1000} } (End definition for \__fp_parse_pack_trailing:NNNNNNww . It is called within an integer expression for the exponent.4 Large significand Parsing a significand larger than 1 is a little bit more difficult than parsing small significands. 8.4. #4 543 . #7. \__fp_parse_pack_leading:NNNNNww . insert 8 more. branching to the small functions since the number of digit does not affect the exponent anymore. and \__fp_parse_pack_carry:w. 0 #1 { \fi: + \c_one . 10546 10547 10548 10549 10550 10551 10552 \cs_new:Npn \__fp_parse_large:N #1 { \exp_after:wN \__fp_parse_large_leading:wwNN \__int_value:w 1 \token_to_str:N #1 \exp_after:wN \__fp_parse_digits_vii:N \tex_romannumeral:D \__fp_parse_expand:w } (End definition for \__fp_parse_large:N. #2. Finally.#3 \exp_after:wN \__fp_parse_pack_leading:NNNNNww \int_use:N \__int_eval:w 1 #1 \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: \exp_after:wN \__fp_parse_large_trailing:wwNN \__int_value:w 1 \token_to_str:N #4 \exp_after:wN \__fp_parse_digits_vi:N \tex_romannumeral:D \else: \if:w . { + #7 \if_meaning:w 2 #1 \__fp_parse_pack_carry:w \fi: . and add that to the final exponent.) \__fp_parse_large_leading:wwNN We shift the exponent by the number of digits in #1. and branch to the appropriate parse_small function in those cases. if this is the end of the significand. Then prepare to pack the 8 first digits.10538 10539 10540 10541 10542 10543 10544 10545 \cs_new:Npn \__fp_parse_pack_leading:NNNNNww #1 #2#3#4#5 #6. If it is a period. Grab up to 7 more digits. namely the target number. read up to 6 more digits (digits 10 to 15). We need to count the number of digits before the decimal separator. If the hnext tokeni is a digit. \__fp_parse_large:N This function is followed by the first non-zero digit of a “large” significand (≥ 1). 0 {#2#3#4#5} {#6} } \cs_new:Npn \__fp_parse_pack_carry:w \fi: . and look for an exponent. try to grab the end of our 8 first digits. minus the hnumber of zerosi (number of digits missing). #3 #4 { + \c_eight . for a total of 8 digits. 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 \cs_new:Npn \__fp_parse_large_leading:wwNN 1 #1 . #3 #4 { \if_int_compare:w \c_nine < 1 \token_to_str:N #4 \exp_stop_f: \exp_after:wN \__fp_parse_pack_trailing:NNNNNNww \exp_after:wN \c_eight \int_use:N \__int_eval:w 1 #1 \token_to_str:N #4 \exp_after:wN \__fp_parse_large_round:NN \exp_after:wN #4 \tex_romannumeral:D \else: \exp_after:wN \__fp_parse_pack_trailing:NNNNNNww \int_use:N \__int_eval:w \c_seven . #4 \exp_after:wN \__fp_parse_small_trailing:wwNN \__int_value:w 1 \cs:w __fp_parse_digits_ \tex_romannumeral:D #3 :N \exp_after:wN 544 .#3 \exp_stop_f: \int_use:N \__int_eval:w 1 #1 \if:w . #2. then the exponent shift caused by this block of 8 digits is 8. This case happens in 123451234512345. 7 minus the hnumber of zerosi.) \__fp_parse_large_trailing:wwNN We have just read 15 digits. the exponent shift is the number of hdigitsi.67 with exactly 15 digits before the decimal separator. 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 \cs_new:Npn \__fp_parse_large_trailing:wwNN 1 #1 . We keep the hdigitsi and this 16-th digit. Finally. grabbing a few more digits to complement the digits we already grabbed. first argument to the pack_trailing function. and find how this should be rounded using \__fp_parse_large_round:NN. Then branch to the appropriate small auxiliary.\exp_after:wN \__fp_parse_small_leading:wwNN \__int_value:w 1 \cs:w __fp_parse_digits_ \tex_romannumeral:D #3 :N \exp_after:wN \cs_end: \tex_romannumeral:D \else: #2 \exp_after:wN \__fp_parse_pack_trailing:NNNNNNww \exp_after:wN \c_zero \__int_value:w 1 0000 0000 \__fp_parse_exponent:Nw #4 \fi: \fi: \__fp_parse_expand:w 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 } (End definition for \__fp_parse_large_leading:wwNN. Otherwise. If the hnext tokeni is a digit. and we test for a decimal point. look for an exponent after using the hzerosi and providing a 16-th digit of 0. if this is truly the end of the significand. leave an exponent of 0. If there is no e. \__int_value:w #2 \__fp_parse_exponent:N #1 } (End definition for \__fp_parse_exponent:Nw. and that function tries to produce an error. and \s__fp stops the expansion. However. We place those \fi: (argument #2) at a very odd place becase this allows us to insert \__int_eval:w . What can we do? Really. there if needed.5 Finding the exponent Expansion is a little bit tricky here. and terminates the expansion with a semicolon.) \__fp_parse_exponent:N \__fp_parse_exponent_aux:N This function should be called within an \__int_value:w expansion (or within an integer expression. in part because we accept input where multiplication is implicit. But taking care of the second case requires that we unpack registers after e. . Then we expand (and possibly unpack) the second token — and hopefully that is safe. Expanding two tokens ahead would then force the expansion of \__fp_chk:w (despite it being protected). \@@_parse:n { 3. considering in that case that we must be finding an exponent. Namely. Here. Indeed. since we would mistake the function erf for an exponent of “rf”.2 e\l_my_int } \@@_parse:n { 3.) 30. the only case where there may be an exponent is if the first token ahead is e. we should read ahead as little as possible. \c_pi_fp is expanded to \s__fp \__fp_chk:w 1 0 {-1} {3141} · · · . It leaves digits of the exponent behind it in the input stream. if the character code of #1 545 . expand the next token to run some tests on it.\cs_end: \tex_romannumeral:D \else: #2 0 \__fp_parse_exponent:Nw #4 \fi: \fi: \__fp_parse_expand:w 10603 10604 10605 10606 10607 10608 10609 } 10610 (End definition for \__fp_parse_large_trailing:wwNN.2. the reason why this last case breaks is that just as TEX does. blindly expanding the two tokens ahead completely would break the third example (unpacking is even worse).2 \c_pi_fp } The first case indicates that just looking one character ahead for an “e” is not enough.2 erf(0. If there is an e. An alternative would be to look two tokens ahead and check if what follows is a sign or a digit. in the course of reading 3.1) } \@@_parse:n { 3.4. 10611 10612 10613 10614 10615 \cs_new:Npn \__fp_parse_exponent:Nw #1 #2 \__fp_parse_expand:w { \exp_after:wN . \__fp_parse_exponent:Nw This auxiliary is convenient to smuggle some material through \fi: ending conditional processing. . ) \__fp_parse_exponent_body:N An exponent can be an explicit integer (most common case).is greater than that of 9 (largest code valid for an exponent. 10646 10647 10648 10649 10650 10651 10652 10653 10654 \cs_new:Npn \__fp_parse_exponent_body:N #1 { \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: \token_to_str:N #1 \exp_after:wN \__fp_parse_exponent_digits:N \tex_romannumeral:D \else: \__fp_parse_exponent_keep:NTF #1 { \__fp_parse_return_semicolon:w #1 } 546 .#1 + \fi: \token_to_str:N #1 \exp_after:wN \__fp_parse_exponent_sign:N \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN \__fp_parse_exponent_body:N \exp_after:wN #1 \fi: } (End definition for \__fp_parse_exponent_sign:N. there was in fact no exponent. 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 \cs_new:Npn \__fp_parse_exponent:N #1 { \if:w e #1 \exp_after:wN \__fp_parse_exponent_aux:N \tex_romannumeral:D \else: 0 \__fp_parse_return_semicolon:w #1 \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_exponent_aux:N #1 { \if_int_compare:w \if_catcode:w \tex_relax:D #1 \c_zero \else: ‘#1 \fi: > ‘9 \exp_stop_f: 0 \exp_after:wN . otherwise. 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 \cs_new:Npn \__fp_parse_exponent_sign:N #1 { \if:w + \if:w . or various other things (most of which are invalid).) \__fp_parse_exponent_sign:N Read signs one by one (if there is any). we search for the sign of the exponent. \exp_after:wN e \else: \exp_after:wN \__fp_parse_exponent_sign:N \fi: #1 } (End definition for \__fp_parse_exponent:N and \__fp_parse_exponent_aux:N. less than any code valid for an identifier). which should be a valid representation of 0.) \__fp_parse_exponent_digits:N Read digits one by one. It is mostly harmless. • another control sequence equal to \relax. Note that we don’t check for overflow of the exponent. • a register: in this case we make sure that it is an integer register. • a character other than +. 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 \cs_new:Npn \__fp_parse_exponent_digits:N #1 { \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: \token_to_str:N #1 \exp_after:wN \__fp_parse_exponent_digits:N \tex_romannumeral:D \else: \__fp_parse_return_semicolon:w #1 \fi: \__fp_parse_expand:w } (End definition for \__fp_parse_exponent_digits:N. stop.{ 10655 \exp_after:wN . but is not. probably a bad variable. The argument #1 is already fully expanded. .) \__fp_parse_exponent_keep:NTF This is the last building block for parsing exponents. and leave them behind in the input stream. and insert a semicolon. and neither + nor . hence there can be a TeX error. not a dimension. invalid here. an error. again. 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 \prg_new_conditional:Npnn \__fp_parse_exponent_keep:N #1 { TF } { \if_catcode:w \tex_relax:D #1 \if_meaning:w \tex_relax:D #1 \if_int_compare:w \pdftex_strcmp:D { \s__fp } { #1 } = \c_zero 0 \__msg_kernel_expandable_error:nnn { kernel } { fp-after-e } { floating~point~ } \prg_return_true: \else: 0 \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} 547 .nor a digit. except when parsing 0e9876543210. When finding a non-digit. It can be: • \s__fp. \tex_romannumeral:D 10656 10657 } \fi: \__fp_parse_expand:w 10658 10659 10660 10661 } (End definition for \__fp_parse_exponent_body:N. marking the start of an internal floating point.or digits. \prg_return_false: \fi: \else: \if_int_compare:w \pdftex_strcmp:D { \__int_value:w #1 } { \tex_the:D #1 } = \c_zero \__int_value:w #1 \else: 0 \__msg_kernel_expandable_error:nnn { kernel } { fp-after-e } { dimension~#1 } \fi: \prg_return_false: \fi: \else: 0 \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { exponent } \prg_return_true: \fi: 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 } 10706 (End definition for \__fp_parse_exponent_keep:NTF.) 30.6 \__fp_cfs_round_loop:N Beyond 16 digits: rounding Used both for \__fp_parse_small_round:NN and \__fp_parse_large_round:NN. Should appear after a \__int_eval:w 0. Reads digits one by one.\c_zero. 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 \cs_new:Npn \__fp_cfs_round_loop:N #1 { \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: + \c_one \if:w 0 #1 \exp_after:wN \__fp_cfs_round_loop:N \tex_romannumeral:D \else: \exp_after:wN \__fp_cfs_round_up:N \tex_romannumeral:D \fi: \else: \__fp_parse_return_semicolon:w \c_zero #1 \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_cfs_round_up:N #1 { \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f: 548 . ends the \__int_eval:w by . If all digits found are 0. otherwise by .4. Adds +1 for each digit. This is done by switching the loop to round_up at the first non-zero digit.\c_one. until reaching a non-digit. or e.+ 1 \exp_after:wN \__fp_cfs_round_up:N \tex_romannumeral:D \else: \__fp_parse_return_semicolon:w \c_one #1 \fi: \__fp_parse_expand:w 10726 10727 10728 10729 10730 10731 10732 10733 } (End definition for \__fp_cfs_round_loop:N. 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 \cs_new:Npn \__fp_parse_large_round:NN #1#2 { \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: + \exp_after:wN \__fp_round_s:NNNw \exp_after:wN 0 \exp_after:wN #1 \exp_after:wN #2 \int_use:N \__int_eval:w \exp_after:wN \__fp_parse_large_round_after:wNN \int_use:N \__int_eval:w \c_one \exp_after:wN \__fp_cfs_round_loop:N \else: %^^A could be dot. The goal is to get \c_zero or \c_one. #3 \exp_after:wN \__fp_parse_large_round_after_aux:wN \int_use:N \__int_eval:w #1 + \c_zero * \__int_eval:w \c_zero 549 . or other \exp_after:wN \__fp_parse_large_round_dot_test:NNw \exp_after:wN #1 \exp_after:wN #2 \fi: } \cs_new:Npn \__fp_parse_large_round_dot_test:NNw #1#2 { \if:w . and combine it to the number of digits before the decimal point (which we thus need to keep track of). check for an exponent afterwards. #2 #3 { \if:w .) \__fp_parse_large_round:NN hdigiti is the digit that we are currently rounding (we only care whether it is even or odd). #2 \exp_after:wN \__fp_parse_small_round:NN \exp_after:wN #1 \tex_romannumeral:D \else: \__fp_parse_exponent:Nw #2 \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_large_round_after:wNN #1 . 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 \exp_after:wN \__fp_cfs_round_loop:N \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: + #2 \exp_after:wN . \int_use:N \__int_eval:w #1 + \__fp_parse_exponent:N } (End definition for \__fp_parse_large_round:NN.) \__fp_parse_small_round:NN hdigiti is the digit that we are currently rounding (we only care whether it is even or odd).) 550 . #2 { + #2 \exp_after:wN . \int_use:N \__int_eval:w #1 + \exp_after:wN \__fp_parse_exponent:N \exp_after:wN #3 \fi: } \cs_new:Npn \__fp_parse_large_round_after_aux:wN #1 . #2 { + #2 \exp_after:wN . \__int_value:w \__fp_parse_exponent:N } (End definition for \__fp_parse_small_round:NN. The goal is to get \c_zero or \c_one 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 \cs_new:Npn \__fp_parse_small_round:NN #1#2 { \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f: + \exp_after:wN \__fp_round_s:NNNw \exp_after:wN 0 \exp_after:wN #1 \exp_after:wN #2 \int_use:N \__int_eval:w \exp_after:wN \__fp_parse_small_round_after:wN \int_use:N \__int_eval:w \c_zero \exp_after:wN \__fp_cfs_round_loop:N \tex_romannumeral:D \else: \__fp_parse_exponent:Nw #2 \fi: \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_small_round_after:wN #1. and perform hoperi on hfp1 i and hfp2 i: this triggers the expansion of \infix_? hpreci. and stop the initial expansion with \c_zero. This function should be used with much care.30. 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 \cs_new:Npn \__fp_parse_until:Nw #1 { -‘0 \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \exp_after:wN \__fp_parse_operand:Nw \exp_after:wN #1 \tex_romannumeral:D } \cs_new:Npn \__fp_parse_until_test:NwN #1 #2 @ #3 { #3 #1 #2 @ } \cs_new_eq:NN \__fp_parse_stop_until:N \use_none:n (End definition for \__fp_parse_until:Nw. then the input stream actually looks like \__fp_parse_until_test:NwN hpreci hfp1 i hfalsei hoperi hfp2 i \infix_? and we must feed hpreci to \infix_?. Note the trailing \tex_romannumeral:D.). and this expands to hfpi. then hfpi is the floating point number that we are looking for (it ends with . 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 \cs_new:Npn \__fp_parse:n #1 { \tex_romannumeral:D \exp_after:wN \__fp_parse_after:ww \tex_romannumeral:D \__fp_parse_until:Nw \c_minus_one \__fp_parse_expand:w #1 \s__fp_mark \s__fp_stop } \cs_new:Npn \__fp_parse_after:ww #1@ #2 \s__fp_stop { hasserti \assert_str_eq:nn { #2 } { \__fp_parse_infix_end:N \s__fp_mark } \c_zero #1 } (End definition for \__fp_parse:n.) \__fp_parse_until:Nw \__fp_parse_until_test:NwN The \__fp_parse_until This is just a shorthand which sets up both \__fp_parse_until_test and \__fp_parse_operand with the same precedence. the function \until yields 551 . Then check that there was indeed nothing left (this cannot happen). This function is documented on page ??. This function is documented on page ??. In that case.) \__fp_parse_until_test:NwN If hbooli is true. The \__fp_parse_until:Nw function will perform computations until reaching an operation with precedence \c_minus_one or less. continuing the computation (or stopping).5 \__fp_parse:n \__fp_parse_after:ww Main functions Start a \romannumeral expansion so that \__fp_parse:n expands in two steps. If hbooli is false. { \__fp_exp_after_f:nw { \__fp_parse_infix:NN #1 } #2.\__fp_parse_until_test:NwN hpreci hoperi hfp1 i hfp2 i \tex_romannumeral:D -‘0 \infix_? hpreci expanding hoperi next.) 30. } \group_begin: \char_set_catcode_letter:N \* \cs_new:Npn \__fp_parse_infix:NN #1 #2 { \if_catcode:w \tex_relax:D #2 \if_int_compare:w \pdftex_strcmp:D { \s__fp_mark } { #2 } = \c_zero \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_infix_end:N \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_infix_juxtapose:N \fi: \else: \if_int_compare:w \__int_eval:w \tex_uccode:D ‘#2 / 26 = \c_three \exp_after:wN \exp_after:wN \exp_after:wN \__fp_parse_infix_juxtapose:N \else: \exp_after:wN \__fp_parse_infix_check:NNN \cs:w __fp_parse_infix_#2:N \exp_after:wN \exp_after:wN \exp_after:wN \cs_end: \fi: \fi: #1 #2 } \cs_new:Npn \__fp_parse_infix_check:NNN #1#2#3 { \if_meaning:w \tex_relax:D #1 \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { * } 552 . (End definition for \__fp_parse_until_test:NwN.6 Main functions \__fp_parse_infix_after_operand:NwN 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 \cs_new:Npn \__fp_parse_infix_after_operand:NwN #1 #2. or we feed all items at once to the custom function.g. 553 . \__fp_sin_o:w. 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 \cs_new:Npn \__fp_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7 { \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \cs:w __fp \__fp_type_from_scan:N #2 _ #4 \__fp_type_from_scan:N #5 _o:ww \cs_end: #2#3 #5#6 \tex_romannumeral:D -‘0 #7 #1 } (End definition for \__fp_parse_apply_binary:NwNwN. so either we map through all its items.. and expands once after the calculation. #2 is e. 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 \cs_new:Npn \__fp_parse_apply_unary_array:NNwN #1#2#3@#4 { #2 #3 @ \tex_romannumeral:D -‘0 #4 #1 } \cs_new:Npn \__fp_parse_apply_unary:NNwN #1#2#3@#4 { #2 #3 \tex_romannumeral:D -‘0 #4 #1 } \cs_new:Npn \__fp_parse_unary_type:N #1 { \__fp_type_from_scan:N #1 _o:w \cs_end: #1 } (End definition for \__fp_parse_apply_unary_array:NNwN and \__fp_parse_apply_unary:NNwN.) 16 Bruno: explain. Builds the appropriate call to the hoperationi #4.16 The argument \__fp_parse_apply_unary:NNwN #3 may be an array.) \__fp_parse_apply_unary_array:NNwN Here.\exp_after:wN \__fp_parse_infix_*:N \exp_after:wN #2 \exp_after:wN #3 \else: \exp_after:wN #1 \exp_after:wN #2 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \fi: 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 } \group_end: (End definition for \__fp_parse_infix_after_operand:NwN.) \__fp_parse_apply_binary:NwNwN Receives hprecedencei hoperand1 i @ hoperationi hoperand2 i @ hinfix commandi. given the types of the two hoperandsi. } } \__fp_tmp:w {in} { {2} {7227} {0000} {0000} {0000} } \__fp_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} } \__fp_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} } \__fp_tmp:w {mm} { {1} {2845} {2755} {9055} {1181} } \__fp_tmp:w {dd} { {1} {1070} {0085} {6496} {0630} } \__fp_tmp:w {cc} { {2} {1284} {0102} {7795} {2756} } \__fp_tmp:w {nd} { {1} {1066} {9783} {4645} {6693} } \__fp_tmp:w {nc} { {2} {1280} {3740} {1574} {8031} } \__fp_tmp:w {bp} { {1} {1003} {7500} {0000} {0000} } \__fp_tmp:w {sp} { {-4} {1525} {8789} {0625} {0000} } \tl_map_inline:nn { {em} {ex} } { \cs_new_nopar:cpn { __fp_parse_word_#1:N } { \exp_after:wN \dim_to_fp:n \exp_after:wN { \dim_use:N \__dim_eval:w 1 #1 \exp_after:wN } \tex_romannumeral:D -‘0 \__fp_parse_infix:NN } } (End definition for \__fp_parse_word_inf:N and others.7. 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 \cs_set_protected:Npn \__fp_tmp:w #1 #2 { \cs_new_nopar:cpn { __fp_parse_word_#1:N } { \exp_after:wN #2 \tex_romannumeral:D -‘0 \__fp_parse_infix:NN } } \__fp_tmp:w { inf } \c_inf_fp \__fp_tmp:w { nan } \c_nan_fp \__fp_tmp:w { pi } \c_pi_fp \__fp_tmp:w { deg } \c_one_degree_fp \__fp_tmp:w { true } \c_one_fp \__fp_tmp:w { false } \c_zero_fp \__fp_tmp:w { pt } \c_one_fp \cs_set_protected:Npn \__fp_tmp:w #1 #2 { \cs_new_nopar:cpn { __fp_parse_word_#1:N } { \__fp_exp_after_f:nw { \__fp_parse_infix:NN } \s__fp \__fp_chk:w 10 #2 .7 30. 10951 10952 10953 \tl_map_inline:nn { {abs} {cos} {cot} {csc} {exp} {ln} {sec} {sin} {tan} } { 554 .30.) \__fp_parse_word_abs:N \__fp_parse_word_cos:N \__fp_parse_word_cot:N \__fp_parse_word_csc:N \__fp_parse_word_exp:N \__fp_parse_word_ln:N \__fp_parse_word_sec:N \__fp_parse_word_sin:N \__fp_parse_word_tan:N Unary functions.1 \__fp_parse_word_inf:N \__fp_parse_word_nan:N \__fp_parse_word_pi:N \__fp_parse_word_deg:N \__fp_parse_word_em:N \__fp_parse_word_ex:N \__fp_parse_word_in:N \__fp_parse_word_pt:N \__fp_parse_word_pc:N \__fp_parse_word_cm:N \__fp_parse_word_mm:N \__fp_parse_word_dd:N \__fp_parse_word_cc:N \__fp_parse_word_nd:N \__fp_parse_word_nc:N \__fp_parse_word_bp:N \__fp_parse_word_sp:N \__fp_parse_word_true:N \__fp_parse_word_false:N Prefix operators Identifiers A whole bunch of floating point numbers. which are applied to all of their arguments when receiving an array. 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 \cs_set_protected:Npn \__fp_tmp:w #1#2 { \cs_new:Npn #1 ##1 { \exp_after:wN \__fp_parse_apply_unary_array:NNwN \exp_after:wN ##1 \exp_after:wN #2 \tex_romannumeral:D \__fp_parse_until:Nw \c_sixteen \__fp_parse_expand:w } } \__fp_tmp:w \__fp_parse_word_max:N \__fp_max_o:w \__fp_tmp:w \__fp_parse_word_min:N \__fp_min_o:w (End definition for \__fp_parse_word_max:N and \__fp_parse_word_min:N.#2 \__fp_parse_round:Nw \__fp_round_to_ninf:NNN \fi: \fi: \fi: \exp_after:wN \__fp_parse_apply_round:NNwN \exp_after:wN #1 \exp_after:wN \__fp_round_to_nearest:NNN \tex_romannumeral:D \__fp_parse_until:Nw \c_sixteen \__fp_parse_expand:w #2 } \cs_new:Npn \__fp_parse_round:Nw 555 .) \__fp_parse_word_round:N This function expects one or two arguments. 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 \cs_new:Npn \__fp_parse_word_round:N #1#2 { \if_meaning:w + #2 \__fp_parse_round:Nw \__fp_round_to_pinf:NNN \else: \if_meaning:w 0 #2 \__fp_parse_round:Nw \__fp_round_to_zero:NNN \else: \if_meaning:w .\cs_new:cpn { __fp_parse_word_#1:N } ##1 { \exp_after:wN \__fp_parse_apply_unary:NNwN \exp_after:wN ##1 \cs:w __fp_ #1 \exp_after:wN \__fp_parse_unary_type:N \tex_romannumeral:D \__fp_parse_until:Nw \c_fifteen \__fp_parse_expand:w } 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 } (End definition for \__fp_parse_word_abs:N and others. but need to mix all of their arguments together.) \__fp_parse_word_max:N \__fp_parse_word_min:N Those functions are also unary. Boolean not. plus.) 30.) \__fp_parse_prefix_-:Nw \__fp_parse_prefix_!:Nw Unary .7.2 \__fp_parse_prefix_+:Nw Unary minus. 11011 \cs_new_eq:cN { __fp_parse_prefix_+:Nw } \__fp_parse_operand:Nw (End definition for \__fp_parse_prefix_+:Nw.{ .\c_one \__int_eval_end: \__fp_round:Nwn #2 #3 {0} \tex_romannumeral:D \or: \__fp_round:Nww #2 #3 \tex_romannumeral:D \else: \__msg_kernel_expandable_error:nnnnn { kernel } { fp-num-args } { round() } { 1 } { 2 } \exp_after:wN \c_nan_fp \tex_romannumeral:D \fi: -‘0 #4 #1 } (End definition for \__fp_parse_word_round:N. not A unary + does nothing.7.10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 #1 #2 \__fp_round_to_nearest:NNN #3 \__fp_parse_expand:w #4 { #2 #1 #3 \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_apply_round:NNwN #1#2#3@#4 { \if_case:w \__int_eval:w \__fp_array_count:n {#3} .3 Other prefixes \__fp_parse_prefix_(:Nw 11030 11031 11032 \group_begin: \char_set_catcode_letter:N \) \cs_new:cpn { __fp_parse_prefix_(:Nw } #1 556 . 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 \cs_set_protected:Npn \__fp_tmp:w #1#2 { \cs_new:cpn { __fp_parse_prefix_#1:Nw } ##1 { \exp_after:wN \__fp_parse_apply_unary:NNwN \exp_after:wN ##1 \cs:w __fp_ #2 \exp_after:wN \__fp_parse_unary_type:N \tex_romannumeral:D \if_int_compare:w \c_twelve < ##1 \__fp_parse_until:Nw ##1 \else: \__fp_parse_until:Nw \c_twelve \fi: \__fp_parse_expand:w } } \__fp_tmp:w .) 30.} \__fp_tmp:w ! { ! } (End definition for \__fp_parse_prefix_-:Nw and \__fp_parse_prefix_!:Nw.is harder. and precedence. given as arguments to \__fp_tmp:w.:Nw} #1 { \exp_after:wN \__fp_parse_infix_after_operand:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \exp_after:wN \__fp_sanitize:wN \int_use:N \__int_eval:w \c_zero \__fp_parse_strim_zeros:N } (End definition for \__fp_parse_prefix_.:Nw This function is called when a number starts with a dot.8 Infix operators As described in the “work plan”.) \__fp_parse_prefix_.{ 11033 \exp_after:wN \__fp_parse_lparen_after:NwN \exp_after:wN #1 \tex_romannumeral:D \if_int_compare:w #1 = \c_sixteen \__fp_parse_until:Nw \c_one \else: \__fp_parse_until:Nw \c_zero \fi: \__fp_parse_expand:w 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 } \cs_new:Npn \__fp_parse_lparen_after:NwN #1#2@#3 { \token_if_eq_meaning:NNTF #3 \__fp_parse_infix_):N { \__fp_exp_after_array_f:w #2 \s__fp_stop \exp_after:wN \__fp_parse_infix:NN \exp_after:wN #1 \tex_romannumeral:D \__fp_parse_expand:w } { \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { ) } #2 @ \__fp_parse_stop_until:N #3 } } \group_end: (End definition for \__fp_parse_prefix_(:Nw. The latter two are only needed when defining the \infix function.:Nw. each infix operator has an associated \infix function. 11067 11068 11069 11070 11071 \cs_set_protected:Npn \__fp_tmp:w #1#2#3#4 { \cs_new:Npn #1 ##1 { \if_int_compare:w ##1 < #3 557 .) 30. 11059 11060 11061 11062 11063 11064 11065 11066 \cs_new:cpn {__fp_parse_prefix_. a computing function. ) \__fp_parse_infix_*:N \__fp_parse_infix_^:N The power operation must be associative in the opposite order from all others.) \__fp_parse_infix_|:Nw \__fp_parse_infix_&:Nw 11110 \group_begin: 558 . 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 \group_begin: \char_set_catcode_letter:N ^ \__fp_tmp:w \__fp_parse_infix_^:N ^ \c_fifteen \c_fourteen \cs_new:cpn { __fp_parse_infix_*:N } #1#2 { \if:w * #2 \exp_after:wN \__fp_parse_infix_^:N \exp_after:wN #1 \else: \exp_after:wN \__fp_parse_infix_mul:N \exp_after:wN #1 \exp_after:wN #2 \fi: } \group_end: (End definition for \__fp_parse_infix_*:N.\c_nine \c_nine \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ + :N } + \c_nine \c_nine \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_and:N } & \c_five \c_five \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ or:N } | \c_four \c_four \group_end: (End definition for \__fp_parse_infix_+:N and others. For this.\exp_after:wN @ \exp_after:wN \__fp_parse_apply_binary:NwNwN \exp_after:wN #2 \tex_romannumeral:D \__fp_parse_until:Nw #4 \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN #1 \fi: 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 } 11083 11084 \__fp_parse_infix_+:N \__fp_parse_infix_-:N \__fp_parse_infix_/:N \__fp_parse_infix_mul:N \__fp_parse_infix_and:N \__fp_parse_infix_or:N } Using the general mechanism for arithmetic operations. we reverse the test. This function is documented on page ??.:N } . 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 \group_begin: \char_set_catcode_other:N \& \__fp_tmp:w \__fp_parse_infix_juxtapose:N * \c_thirty_two \c_thirty_two \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ / :N } / \c_ten \c_ten \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_mul:N } * \c_ten \c_ten \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ . hence treating a “previous precedence” of \c_fourteen as less binding than ^. ) \__fp_parse_infix_<:N \__fp_parse_infix_=:N \__fp_parse_infix_>:N \__fp_parse_infix_!:N \__fp_parse_infix_excl_aux:NN \__fp_parse_infix_excl_error: \__fp_infix_compare:N \__fp_parse_compare:NNNNNNw \__fp_parse_compare_expand:NNNNNw \__fp_parse_compare_end:NNNN \__fp_compare:wNNNNw 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 \cs_new:cpn { __fp_parse_infix_<:N } #1 { \__fp_infix_compare:N #1 \c_one_fp \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp < } \cs_new:cpn { __fp_parse_infix_=:N } #1 { \__fp_infix_compare:N #1 \c_one_fp \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp = } \cs_new:cpn { __fp_parse_infix_>:N } #1 { \__fp_infix_compare:N #1 \c_one_fp \c_zero_fp \c_zero_fp \c_zero_fp \c_zero_fp > } \cs_new:cpn { __fp_parse_infix_!:N } #1 { \exp_after:wN \__fp_parse_infix_excl_aux:NN \exp_after:wN #1 \tex_romannumeral:D \__fp_parse_expand:w } 559 .11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 \char_set_catcode_letter:N \| \char_set_catcode_letter:N \& \cs_new:Npn \__fp_parse_infix_|:N #1#2 { \if:w | #2 \exp_after:wN \__fp_parse_infix_|:N \exp_after:wN #1 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN \__fp_parse_infix_or:N \exp_after:wN #1 \exp_after:wN #2 \fi: } \cs_new:Npn \__fp_parse_infix_&:N #1#2 { \if:w & #2 \exp_after:wN \__fp_parse_infix_&:N \exp_after:wN #1 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN \__fp_parse_infix_and:N \exp_after:wN #1 \exp_after:wN #2 \fi: } \group_end: (End definition for \__fp_parse_infix_|:Nw. This function is documented on page ??. 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 \cs_new:Npn \__fp_parse_infix_excl_aux:NN #1#2 { \__fp_infix_compare:N #1 \c_zero_fp \c_one_fp \c_one_fp \c_one_fp \c_one_fp #2 } \cs_new:Npn \__fp_parse_infix_excl_error: { \__msg_kernel_expandable_error:nnnn { kernel } { fp-missing } { = } { ~after~!. } } \cs_new:Npn \__fp_infix_compare:N #1 { \if_int_compare:w #1 < \c_seven \exp_after:wN \__fp_parse_compare:NNNNNNw \exp_after:wN \__fp_parse_infix_excl_error: \else: \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN \__fp_infix_compare:N \fi: } \cs_new:Npn \__fp_parse_compare:NNNNNNw #1#2#3#4#5#6#7 { \if_case:w \if_catcode:w \tex_relax:D #7 \c_minus_one \else: \__int_eval:w ‘#7 .‘< \__int_eval_end: \fi: \__fp_parse_compare_expand:NNNNNw #2#2#4#5#6 \or: \__fp_parse_compare_expand:NNNNNw #2#3#2#5#6 \or: \__fp_parse_compare_expand:NNNNNw #2#3#4#2#6 \or: \__fp_parse_compare_expand:NNNNNw #2#3#4#5#2 \else: #1 \__fp_parse_compare_end:NNNN #3#4#5#6#7 \fi: } \cs_new:Npn \__fp_parse_compare_expand:NNNNNw #1#2#3#4#5 { \exp_after:wN \__fp_parse_compare:NNNNNNw \exp_after:wN \prg_do_nothing: \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN #4 \exp_after:wN #5 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w } \cs_new:Npn \__fp_parse_compare_end:NNNN #1#2#3#4#5 \fi: { \fi: 560 . ) \__fp_parse_infix_?:N \__fp_parse_infix_::N 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 \group_begin: \char_set_catcode_letter:N \? \cs_new:Npn \__fp_parse_infix_?:N #1 { \if_int_compare:w #1 < \c_three \exp_after:wN @ \exp_after:wN \__fp_ternary:NwwN \tex_romannumeral:D \__fp_parse_until:Nw \c_three \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN \__fp_parse_infix_?:N \fi: } \cs_new:Npn \__fp_parse_infix_::N #1 { \if_int_compare:w #1 < \c_three \__msg_kernel_expandable_error:nnnn { kernel } { fp-missing } { ? } { ~for~?: } \exp_after:wN @ 561 . These functions are documented on page ??.11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 \exp_after:wN @ \exp_after:wN \__fp_parse_apply_compare:NwNNNNwN \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN #4 \tex_romannumeral:D \__fp_parse_until:Nw \c_seven \__fp_parse_expand:w #5 } \cs_new:Npn \__fp_parse_apply_compare:NwNNNNwN #1 #2@ #3#4#5#6 #7@ #8 { \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN \if_case:w \__fp_compare_back:ww #7 #2 \exp_stop_f: #4 \or: #5 \or: #6 \else: #3 \fi: \tex_romannumeral:D -‘0 #8 #1 } (End definition for \__fp_parse_infix_<:N and others. ) \__fp_parse_infix_):N This one is a little bit odd: force every previous operator to end.11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 \exp_after:wN \__fp_ternary_auxii:NwwN \tex_romannumeral:D \__fp_parse_until:Nw \c_two \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN \__fp_parse_infix_::N \fi: } \group_end: (End definition for \__fp_parse_infix_?:N and \__fp_parse_infix_::N. This is very similar to \__fp_parse_infix_end:N.:N \else: \if_int_compare:w #1 = \c_one \exp_after:wN \__fp_parse_infix_comma:w \tex_romannumeral:D \else: 562 .) \__fp_parse_infix_ :N 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 \group_begin: \char_set_catcode_letter:N \. 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 \group_begin: \char_set_catcode_letter:N \) \cs_new:Npn \__fp_parse_infix_):N #1 { \if_int_compare:w #1 < \c_zero \__msg_kernel_expandable_error:nnn { kernel } { fp-extra } { ) } \exp_after:wN \__fp_parse_infix:NN \exp_after:wN #1 \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w \else: \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN \__fp_parse_infix_):N \fi: } \group_end: \cs_new:Npn \__fp_parse_infix_end:N #1 { @ \__fp_parse_stop_until:N \__fp_parse_infix_end:N } (End definition for \__fp_parse_infix_):N. \cs_new:Npn \__fp_parse_infix_.:N #1 { \if_int_compare:w #1 > \c_one \exp_after:wN @ \exp_after:wN \__fp_parse_stop_until:N \exp_after:wN \__fp_parse_infix_. regardless of the precedence. } \__msg_kernel_new:nnn { kernel } { fp-missing-number } { Missing~number~before~’#1’. • \__fp_max_o:w hfloating point arrayi 563 . } \__msg_kernel_new:nnn { kernel } { fp-after-e } { Cannot~use~#1 after~’e’. } \__msg_kernel_new:nnn { kernel } { fp-early-end } { Premature~end~in~fp~expression.) 31 Messages 11329 \__msg_kernel_new:nnn { kernel } { unknown-fp-word } { Unknown~fp~word~#1. } \__msg_kernel_new:nnn { kernel } { fp-num-args } { #1~expects~between~#2~and~#3~arguments. {hexpo2 i} hbody2 i . } \__msg_kernel_new:nnn { kernel } { fp-extra-comma } { Unexpected~comma:~extra~arguments~ignored. } \__msg_kernel_new:nnn { kernel } { fp-unknown-symbol } { Unknown~symbol~#1~ignored.1 Syntax of internal functions • \__fp_compare_npos:nwnw {hexpo1 i} hbody1 i . } 11330 h/initex | packagei 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 l3fp-logic Implementation 32 11331 h*initex | packagei 11332 h@@=fpi 32.\exp_after:wN \__fp_parse_infix_comma_gobble:w \tex_romannumeral:D \fi: \__fp_parse_until:Nw \c_one \exp_after:wN \__fp_parse_expand:w \fi: 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 } \cs_new:Npn \__fp_parse_infix_comma:w #1 @ { #1 @ \__fp_parse_stop_until:N } \cs_new:Npn \__fp_parse_infix_comma_gobble:w #1 @ { \__msg_kernel_expandable_error:nn { kernel } { fp-extra-comma } @ \__fp_parse_stop_until:N } \group_end: (End definition for \__fp_parse_infix_ and :N. } \__msg_kernel_new:nnn { kernel } { fp-missing } { Missing~#1~inserted #2. } \__msg_kernel_new:nnn { kernel } { fp-extra } { Extra~#1~ignored. so we evaluate #1. F . then compare with 0.3 \fp_compare_p:n \fp_compare:nTF \__fp_compare_return:w Existence test Comparison Within floating point expressions. T . TF } { \exp_after:wN \__fp_compare_return:w \tex_romannumeral:D -‘0 \__fp_parse:n {#1} } \cs_new:Npn \__fp_compare_return:w \s__fp \__fp_chk:w #1#2. F . 1 for > and 2 for ?. T .‘= \__int_eval_end: \prg_return_true: \else: \prg_return_false: 564 . 11333 11334 \prg_new_eq_conditional:NNn \fp_if_exist:N \cs_if_exist:N { TF . F . { \if_meaning:w 0 #1 \prg_return_false: \else: \prg_return_true: \fi: } (End definition for \fp_compare:n. These functions are documented on page ??. These functions are documented on page ??. p } \prg_new_eq_conditional:NNn \fp_if_exist:c \cs_if_exist:c { TF . Compare the result with ‘#2-‘=.) \fp_compare_p:nNn \fp_compare:nNnTF \__fp_compare_aux:wn Evaluate #1 and #3. defined below. using an auxiliary to expand both.2 \fp_if_exist_p:N \fp_if_exist_p:c \fp_if_exist:NTF \fp_if_exist:cTF Copies of the cs functions defined in l3basics. and feed the two floating point numbers swapped to \__fp_compare_back:ww. T . 11348 11349 11350 11351 11352 11353 11354 11355 11356 \prg_new_conditional:Npnn \fp_compare:nNn #1#2#3 { p . which is −1 for <. F . 32. T . TF } { \if_int_compare:w \exp_after:wN \__fp_compare_aux:wn \tex_romannumeral:D -‘0 \__fp_parse:n {#1} {#3} = \__int_eval:w ‘#2 . comparison operators are treated as operations.• \__fp_min_o:w hfloating point arrayi • \__fp_!_o:w hfloating pointi • \__fp_&_o:ww hfloating pointi hfloating pointi • \__fp_|_o:ww hfloating pointi hfloating pointi • \__fp_ternary:NwwN. 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 \prg_new_conditional:Npnn \fp_compare:n #1 { p . 0 for =.) 32. \__fp_ternary_auxii:NwwN have to be understood. \__fp_ternary_auxi:NwwN. p } (End definition for \fp_if_exist:N and \fp_if_exist:c. #2 { \exp_after:wN \__fp_compare_back:ww \tex_romannumeral:D -‘0 \__fp_parse:n {#2} #1. Expands (in the same way as \int_eval:n) to −1 if x < y. { \__int_value:w \if_meaning:w 3 #1 \exp_after:wN \__fp_compare_nan:w \fi: \if_meaning:w 3 #4 \exp_after:wN \__fp_compare_nan:w \fi: \if_meaning:w 2 #5 . but of a different type. \s__fp \__fp_chk:w #4 #5 #6. hxi .) \__fp_compare_back:ww \__fp_compare_nan:w \__fp_compare_back:ww hyi .\fi: 1 \fi: \else: \if_int_compare:w #1#4 = \c_zero 0 \else: 1 \fi: \fi: \exp_stop_f: } \cs_new:Npn \__fp_compare_nan:w #1 \exp_stop_f: { \c_two } (End definition for \__fp_compare_back:ww and \__fp_compare_nan:w. unless both are zero. the highest type is a larger number. we can henceforth assume that x ≥ 0. and they have the same type.11357 11358 11359 11360 11361 11362 11363 \fi: } \cs_new:Npn \__fp_compare_aux:wn #1. stop the comparison with \__fp_compare_nan:w returning 2. Finally.e. If either operand is nan. then x > y. 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 \cs_new:Npn \__fp_compare_back:ww \s__fp \__fp_chk:w #1 #2 #3. {hexpo2 i} hbody2 i . if y ≤ 0. 1 if x > y. If x is negative.) \__fp_compare_npos:nwnw \__fp_compare_significand:nnnnnnnn \__fp_compare_npos:nwnw {hexpo1 i} hbody1 i . or they are equal. 0 if x = y.. either they are normal and we compare them with \__fp_compare_npos:nwnw. #3. If y ≥ 0. These functions are documented on page 171. and 2 otherwise (denoted as x?y). If y ≥ 0. 565 . } (End definition for \fp_compare:nNn. swap the outputs 1 and −1 (i.\fi: \if_meaning:w #2 #5 \if_meaning:w #1 #4 \if_meaning:w 1 #1 \__fp_compare_npos:nwnw #6. > and <). \else: 0 \fi: \else: \if_int_compare:w #4 < #1 . \exp_stop_f: construction. If only the first 8 digits coincide. and 1 if the first is bigger. the numbers are equal.\fi: 1 \fi: } \cs_new:Npn \__fp_compare_significand:nnnnnnnn #1#2#3#4#5#6#7#8 { \if_int_compare:w #1#2 = #5#6 \exp_stop_f: \if_int_compare:w #3#4 = #7#8 \exp_stop_f: 0 \else: \if_int_compare:w #3#4 < #7#8 .4 \fp_do_until:nn \fp_do_while:nn \fp_until_do:nn \fp_while_do:nn Floating point expression loops These are quite easy given the above functions. If they are equal. The until_do and while_do do it the other way round. #3#4.) 32.Within an \__int_value:w . then test. This function is documented on page ??. { \if_int_compare:w #1 = #3 \exp_stop_f: \__fp_compare_significand:nnnnnnnn #2 #4 \else: \if_int_compare:w #1 < #3 . −1 if the first is smaller.\fi: 1 \fi: \else: \if_int_compare:w #1#2 < #5#6 . The do_until and do_while versions execute the body. this expands to 0 if the two numbers are equal. we must compare significands. . 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 \cs_new:Npn \__fp_compare_npos:nwnw #1#2. the next 8 decide. If both the first 8 digits and the next 8 digits coincide. . 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 \cs_new:Npn \fp_do_until:nn #1#2 { #2 \fp_compare:nF {#1} { \fp_do_until:nn {#1} {#2} } } \cs_new:Npn \fp_do_while:nn #1#2 { #2 \fp_compare:nT {#1} { \fp_do_while:nn {#1} {#2} } } \cs_new:Npn \fp_until_do:nn #1#2 { \fp_compare:nF {#1} { 566 . First compare the exponents: the larger one denotes the larger number. Otherwise.\fi: 1 \fi: } (End definition for \__fp_compare_npos:nwnw. the first 8 digits are compared. We start 567 .) 32.#2 \fp_until_do:nn {#1} {#2} 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 } } \cs_new:Npn \fp_while_do:nn #1#2 { \fp_compare:nT {#1} { #2 \fp_while_do:nn {#1} {#2} } } (End definition for \fp_do_until:nn and others.5 \__fp_max_o:w \__fp_min_o:w Extrema The maximum (minimum) of an array of floating point numbers is computed by reading them sequentially. These functions are documented on page 172.) \fp_do_until:nNnn \fp_do_while:nNnn \fp_until_do:nNnn \fp_while_do:nNnn As above but not using the nNn syntax. keeping track of the largest (smallest) number found so far. These functions are documented on page 172. 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 \cs_new:Npn \fp_do_until:nNnn #1#2#3#4 { #4 \fp_compare:nNnF {#1} #2 {#3} { \fp_do_until:nNnn {#1} #2 {#3} } \cs_new:Npn \fp_do_while:nNnn #1#2#3#4 { #4 \fp_compare:nNnT {#1} #2 {#3} { \fp_do_while:nNnn {#1} #2 {#3} } \cs_new:Npn \fp_until_do:nNnn #1#2#3#4 { \fp_compare:nNnF {#1} #2 {#3} { #4 \fp_until_do:nNnn {#1} #2 {#3} } } \cs_new:Npn \fp_while_do:nNnn #1#2#3#4 { \fp_compare:nNnT {#1} #2 {#3} { #4 \fp_while_do:nNnn {#1} #2 {#3} } } {#4} } {#4} } {#4} {#4} (End definition for \fp_do_until:nNnn and others. If the new number is nan.) \__fp_minmax_loop:Nww The first argument is −1 or 1 to denote the case where the currently largest (smallest) number found (first floating point argument) should be replaced by the new number (second floating point argument). 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 \cs_new:Npn \__fp_max_o:w #1 @ { \exp_after:wN \__fp_minmax_loop:Nww \exp_after:wN \c_minus_one \c_minus_inf_fp #1 \s__fp \__fp_chk:w { 3 \__fp_minmax_break_o:w } . If the new number is larger (in the case of max) or smaller (in the case of min). and we keep the second number as a new maximum. 568 . = #1 \__fp_minmax_auxii:ww \else: \__fp_minmax_auxi:ww \fi: \fi: \__fp_minmax_loop:Nww #1 \s__fp \__fp_chk:w #2#3. \s__fp \__fp_chk:w #4#5. 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 \cs_new:Npn \__fp_minmax_loop:Nww #1 \s__fp \__fp_chk:w #2#3. otherwise we keep the first number. the test yields true. Otherwise. } \cs_new:Npn \__fp_min_o:w #1 @ { \exp_after:wN \__fp_minmax_loop:Nww \exp_after:wN \c_one \c_inf_fp #1 \s__fp \__fp_chk:w { 3 \__fp_minmax_break_o:w } . Then loop. compare the two numbers. \s__fp \__fp_chk:w #2#3. unless that extremum is already a nan. { \if_meaning:w 3 #4 \if_meaning:w 3 #2 \__fp_minmax_auxi:ww \else: \__fp_minmax_auxii:ww \fi: \else: \if_int_compare:w \__fp_compare_back:ww \s__fp \__fp_chk:w #4#5.with −∞ (∞) since every number is larger (smaller) than that. keep that as the extremum. The weird fp-like trailing marker breaks the loop correctly: see the precise definition of \__fp_minmax_loop:Nww. } (End definition for \__fp_max_o:w and \__fp_min_o:w. \else:. close the current test with \fi:. \s__fp #4. Skip to the end of the tests. and one to please l3fp-parse. } \cs_new:Npn \__fp_minmax_auxii:ww #1 \fi: \fi: #2 \s__fp #3 . { \fi: \fi: #2 \s__fp #3 . { \if_meaning:w 0 #2 #1 \__fp_and_return:wNw \s__fp \__fp_chk:w #2#3. } (End definition for \__fp_minmax_break_o:w. and remove the other. clean up. Otherwise.) 32. 11514 11515 11516 11517 11518 11519 11520 11521 \cs_new:cpn { __fp_!_o:w } \s__fp \__fp_chk:w #1#2. In all cases. if the first number is zero. otherwise return the second number: we achieve that by hi-jacking \__fp_&_o:ww. one to exit the conditional. { \fi: \__fp_exp_after_o:w \s__fp #3. and return the appropriate number with one post-expansion. 11512 11513 \cs_new:Npn \__fp_minmax_break_o:w #1 \fi: \fi: #2 \s__fp #3. #4. expand after the floating point number. 11508 11509 11510 11511 \cs_new:Npn \__fp_minmax_auxi:ww #1 \fi: \fi: #2 \s__fp #3 .6 \__fp_!_o:w Boolean operations Return true or false. before \s__fp. with two expansions. the logic is reversed: if the first number is non-zero.) \__fp_minmax_auxi:ww \__fp_minmax_auxii:ww Keep the first/second number.) \__fp_minmax_break_o:w This function is called from within an \if_meaning:w test. { \if_meaning:w 0 #1 \exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp \else: \exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp \fi: } (End definition for \__fp_!_o:w. \fi: \__fp_exp_after_o:w } \cs_new_nopar:Npn \__fp_|_o:ww { \__fp_&_o:ww \else: } 569 . return it (with the same sign). 11506 } 11507 (End definition for \__fp_minmax_loop:Nww. inserting an extra argument.\s__fp \__fp_chk:w #4#5. For or. 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 \group_begin: \char_set_catcode_letter:N & \char_set_catcode_letter:N | \cs_new:Npn \__fp_&_o:ww #1 \s__fp \__fp_chk:w #2#3.) \__fp_&_o:ww \__fp_|_o:ww \__fp_and_return:wNw For and. return the second one. return it. { \fi: \fi: #2 } (End definition for \__fp_minmax_auxi:ww and \__fp_minmax_auxii:ww. 11533 11534 \group_end: \cs_new:Npn \__fp_and_return:wNw #1. unless the test branch is zero. { \if_int_compare:w #1 > \c_zero \exp_after:wN \__fp_ternary_map_break: \fi: \__fp_ternary_loop:Nw } \cs_new:Npn \__fp_ternary_map_break: #1 \__fp_ternary_break_point:n #2 {#2} 570 .7 \__fp_ternary:NwwN \__fp_ternary_auxi:NwwN \__fp_ternary_auxii:NwwN \__fp_ternary_loop_break:w \__fp_ternary_loop:Nw \__fp_ternary_map_break: \__fp_ternary_break_point:n Ternary operator The first function receives the test and the true branch of the ?: ternary operator. } (End definition for \__fp_&_o:ww. It returns the true branch. and the false branch. { \fi: #2 #1. In that case. This function is documented on page ??. The second function receives the output of the first function. \fi: #2#3.) 32. the function returns a very specific nan. It returns the previous input. unless that is the special nan. in which case we return the false branch. \__fp_ternary_break_point:n { \exp_after:wN \__fp_ternary_auxi:NwwN } \exp_after:wN #1 \tex_romannumeral:D -‘0 \__fp_exp_after_array_f:w #3 \s__fp_stop \exp_after:wN @ \tex_romannumeral:D \__fp_parse_until:Nw \c_two \__fp_parse_expand:w \else: \__msg_kernel_expandable_error:nnnn { kernel } { fp-missing } { : } { ~for~?: } \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \__fp_exp_after_array_f:w #3 \s__fp_stop \exp_after:wN #4 \exp_after:wN #1 \fi: } \cs_new:Npn \__fp_ternary_loop_break:w #1 \fi: #2 \__fp_ternary_break_point:n #3 { \c_zero = \c_zero \fi: \exp_after:wN \__fp_ternary_auxii:NwwN } \cs_new:Npn \__fp_ternary_loop:Nw \s__fp \__fp_chk:w #1#2. 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 \cs_new:Npn \__fp_ternary:NwwN #1 #2@ #3@ #4 { \if_meaning:w \__fp_parse_infix_::N #4 \__fp_ternary_loop:Nw #2 \s__fp \__fp_chk:w { \__fp_ternary_loop_break:w } . { \if_meaning:w 2 #1 + \c_one \fi: . All operations implemented in this module yield the outcome of rounding the infinitely precise result of the operation to the nearest floating point. multiplication. then round and pack digits in the final (braced) form. } 571 . subtraction. \__fp_basics_pack_high_carry:w is always followed by four times {0000}. These functions \__fp_basics_pack_high_carry:w take care of the packing.) 11589 h/initex | packagei l3fp-basics Implementation 33 11590 h*initex | packagei 11591 h@@=fpi The l3fp-basics module implements addition. Since rounding can only shift the final digit by 1. These functions are documented on page ??. and division of two floating points. a carry always produces an exact power of 10.yp. which can be found at http://cr. and \__fp_ternary_auxii:NwwN. by David Goldberg.1 Common to several operations \__fp_basics_pack_low:NNNNNw Addition and multiplication of significands are done in two steps: first compute a (more or \__fp_basics_pack_high:NNNNNw less) exact result.11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 \cs_new:Npn \__fp_ternary_auxi:NwwN #1#2@#3@#4 { \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \__fp_exp_after_array_f:w #2 \s__fp_stop #4 #1 } \cs_new:Npn \__fp_ternary_auxii:NwwN #1#2@#3@#4 { \exp_after:wN \__fp_parse_until_test:NwN \exp_after:wN #1 \tex_romannumeral:D -‘0 \__fp_exp_after_array_f:w #3 \s__fp_stop #4 #1 } (End definition for \__fp_ternary:NwwN . and the absolute value and sign-changing operations on one floating point.to/2005-590/goldberg. 33. 11592 11593 11594 11595 11596 11597 11598 \cs_new:Npn \__fp_basics_pack_low:NNNNNw #1 #2#3#4#5 #6. Some algorithms used below end up being quite similar to some described in “What Every Computer Scientist Should Know About Floating Point Arithmetic”. {#2#3#4#5} {#6} .pdf. with special attention given to the case where rounding has caused a carry. Thus. \__fp_ternary_auxi:NwwN . round. 572 . \__fp_-_o:ww and \__fp_+_o:ww. calling specialized auxiliaries. \__fp_basics_pack_high:NNNNNw . and pack using the \__fp_basics_pack_. • for normal floating point numbers. functions. and expand the tokens following the result once.. {#1#2#3#4} {#5#6#7#8} {#9} } (End definition for \__fp_basics_pack_weird_low:NNNNw and \__fp_basics_pack_weird_high:NNNNNNNNw. perform the addition or subtraction of significands.2 Addition and subtraction We define here two functions.) 33. we return one or the other operands depending on the signs. { \if_meaning:w 2 #1 \__fp_basics_pack_high_carry:w \fi: . The logic goes as follows: • \__fp_-_o:ww calls \__fp_+_o:ww to do the work. • in all cases except summing two normal floating point numbers. which perform the subtraction and addition of their two floating point operands. } \cs_new:Npn \__fp_basics_pack_weird_high:NNNNNNNNw 1 #1#2#3#4 #5#6#7#8 #9.. • to add two floating point numbers of the same sign or of opposite signs. {#5} . check for a carry. { \if_meaning:w 2 #1 + \c_one \fi: \__int_eval_end: #2#3#4. #1 { \fi: + \c_one . \__fp_add_big_i_o:wNww.11599 11600 11601 11602 11603 11604 11605 11606 11607 \cs_new:Npn \__fp_basics_pack_high:NNNNNw #1 #2#3#4#5 #6. with the sign of the second operand flipped. { . 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 \cs_new:Npn \__fp_basics_pack_weird_low:NNNNw #1 #2#3#4 #5. A more obscure function. used for additions and divisions. is used in l3fp-expo. • \__fp_+_o:ww dispatches depending on the type of floating point. or detect an invalid operation in the case of ∞ − ∞. compare the signs. Hence the \__fp_basics_pack_weird_high:NNNNNNNNw name. and \__fp_basics_pack_high_carry: \__fp_basics_pack_weird_low:NNNNw I don’t fully understand those functions. {#2#3#4#5} {#6} } \cs_new:Npn \__fp_basics_pack_high_carry:w \fi: . {1000} } (End definition for \__fp_basics_pack_low:NNNNNw . shift the significand of the smaller one to match the bigger one. Positioning the hook there means that \__fp_+_o:ww can still check that it was followed by \s__fp and not arbitrary junk. 2. If the htypesi #2 and #4 are the same. Now. or 3). those receive the tweaked hsign2 i (expansion of #1#5) as an argument. we can also use it when htype1 i is greater than htype2 i.1 \__fp_-_o:ww Sign. the result is simply the floating point number with the highest htypei. which is applied to the sign of the second operand. \s__fp \__fp_chk:w #4 #5 { \if_case:w \if_meaning:w #2 #4 #2 \exp_stop_f: \else: \if_int_compare:w #2 > #4 \exp_stop_f: \c_three \else: \c_minus_one \fi: \fi: \exp_after:wN \__fp_add_zeros_o:Nww \__int_value:w \or: \exp_after:wN \__fp_add_normal_o:Nww \__int_value:w \or: \exp_after:wN \__fp_add_inf_o:Nww \__int_value:w \or: \__fp_case_return_i_o:ww \else: \exp_after:wN \__fp_add_return_ii_o:Nww \__int_value:w \fi: #1 #5 573 . the \__fp_+_o:ww auxiliary has a hook: it takes one argument between the first \s__fp and \__fp_chk:w. Also note that we don’t need to worry about hsign2 i in that case since the second operand is discarded. and special numbers A previous version of this function grabbed its two operands. the operands were swapped in the process. or it is called by \__fp_-_o:ww with \__fp_neg_sign:N as #1 to compute a subtraction (equivalent to changing the hsign2 i of the second operand). changed the sign of the second. However. exponent.) \__fp_+_o:ww This function is either called directly with an empty #1 to compute an addition. dispatch to case #2 (0. 1. where we call specialized functions: thanks to \__int_value:w.2. 11618 11619 11620 11621 11622 \cs_new_nopar:cpx { __fp_-_o:ww } \s__fp { \exp_not:c { __fp_+_o:ww } \exp_not:n { \s__fp \__fp_neg_sign:N } } (End definition for \__fp_-_o:ww. If the htypesi are distinct.The trickiest part is to round correctly when adding or subtracting normal floating point numbers. for efficiency reasons. and called \__fp_+_o:ww. which means that error messages ended up wrong. 33. 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 \cs_new:cpn { __fp_+_o:ww } \s__fp #1 \__fp_chk:w #2 #3 . Since case 3 (used for two nan) also picks the first operand. 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 \cs_new:Npn \__fp_add_zeros_o:Nww #1 \s__fp \__fp_chk:w 0 #2 { \if_int_compare:w #2 #1 = 20 \exp_stop_f: \exp_after:wN \__fp_add_return_ii_o:Nww \else: \__fp_case_return_i_o:ww \fi: #1 \s__fp \__fp_chk:w 0 #2 } (End definition for \__fp_add_zeros_o:Nww. but using the sign #1 rather than #4. just return that infinity. As usual. otherwise.) \__fp_add_inf_o:Nww If both infinities have the same sign. \s__fp \__fp_chk:w #3 #4 { \__fp_exp_after_o:w \s__fp \__fp_chk:w #3 #1 } (End definition for \__fp_add_return_ii_o:Nww.\s__fp \__fp_chk:w #2 #3 . \s__fp \__fp_chk:w #4 #5 11643 11644 11645 } (End definition for \__fp_+_o:ww. We find out if that invalid operation is an addition or a subtraction by testing whether the tweaked hsign2 i (#1) and the hsign2 i (#4) are identical. expand after the floating point. \s__fp \__fp_chk:w 2 #4 } (End definition for \__fp_add_inf_o:Nww.) \__fp_add_return_ii_o:Nww Ignore the first operand. \s__fp \__fp_chk:w 2 #4 { \if_meaning:w #1 #2 \__fp_case_return_i_o:ww \else: \__fp_case_use:nw { \if_meaning:w #1 #4 \exp_after:wN \__fp_invalid_operation_o:Nww \exp_after:wN + \else: \exp_after:wN \__fp_invalid_operation_o:Nww \exp_after:wN \fi: } \fi: \s__fp \__fp_chk:w 2 #2 #3.) \__fp_add_zeros_o:Nww Adding two zeros yields \c_zero_fp.) 574 . except if both zeros were −0. and return the second. it is an invalid operation. 11646 11647 \cs_new:Npn \__fp_add_return_ii_o:Nww #1 #2 . 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 \cs_new:Npn \__fp_add_inf_o:Nww #1 \s__fp \__fp_chk:w 2 #2 #3. #2 . the final sign is hsign1 i.) \__fp_add_big_i_o:wNww \__fp_add_big_ii_o:wNww \__fp_add_big_i_o:wNww hshifti . #4. #2 #3. 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 \cs_new:Npn \__fp_add_npos_o:NnwNnw #1#2#3 . incremented if there is a carry. We now have two normal numbers to add. then add with \__fp_add_significand_o:NnnwnnnnN. 575 . 11678 11679 11680 11681 11682 11683 11684 11685 11686 \cs_new:Npn \__fp_add_normal_o:Nww #1 \s__fp \__fp_chk:w 1 #2 { \if_meaning:w #1#2 \exp_after:wN \__fp_add_npos_o:NnwNnw \else: \exp_after:wN \__fp_sub_npos_o:NnwNnw \fi: #2 } (End definition for \__fp_add_normal_o:Nww.2 Absolute addition In this subsection. hfinal signi hbody1 i .2. and the hfinal signi are then given to \__fp_sanitize:Nw which checks for overflow.\__fp_add_normal_o:Nww \__fp_add_normal_o:Nww hsign2 i \s__fp \__fp_chk:w 1 hsign1 i hexp1 i hbody1 i . Since we are doing an addition. \s__fp \__fp_chk:w 1 hinitial sign2 i hexp2 i hbody2 i . The exponent is computed as the largest exponent #2 or #5. and we have to check signs and exponents more carefully before performing the addition. } (End definition for \__fp_add_npos_o:NnwNnw. Start an \__int_eval:w. responsible for computing the exponent: the result. #1 #3. To add the significands. \s__fp \__fp_chk:w 1 #4 #5 { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN #1 \int_use:N \__int_eval:w \if_int_compare:w #2 > #5 \exp_stop_f: #2 \exp_after:wN \__fp_add_big_i_o:wNww \__int_value:w \else: #5 \exp_after:wN \__fp_add_big_ii_o:wNww \__int_value:w \fi: \__int_eval:w #5 . we decimate the smaller number by the difference between the exponents. We need to bring the final sign with us in the midst of the calculation to round properly at the end.) 33. Shift the significand of the small number. we perform the addition of two positive normal numbers. hbody2 i . \__fp_add_npos_o:NnwNnw \__fp_add_npos_o:NnwNnw hsign1 i hexp1 i hbody1 i . \s__fp \__fp_chk:w 1 hinitial sign2 i hexp2 i hbody2 i . This is done by \__fp_add_big_i:wNww or \__fp_add_big_ii:wNww. 11701 \cs_new:Npn \__fp_add_big_i_o:wNww #1. #2 #3 #4 #5 #6 #7 . {hX1 i} {hX2 i} {hX3 i} {hX4 i} hfinal signi To round properly. for which it is easy to correct the result at the end. #5#6#7#8 { \exp_after:wN \__fp_add_significand_test_o:N \int_use:N \__int_eval:w 1#5#6 + #2 \exp_after:wN \__fp_add_significand_pack:NNNNNNN \int_use:N \__int_eval:w 1#7#8 + #3 . { \__fp_decimate:nNnnnn {#1} \__fp_add_significand_o:NnnwnnnnN #3 #4 #2 } (End definition for \__fp_add_big_i_o:wNww. } \cs_new:Npn \__fp_add_significand_test_o:N #1 { \if_meaning:w 2 #1 \exp_after:wN \__fp_add_significand_carry_o:wwwNN \else: \exp_after:wN \__fp_add_significand_no_carry_o:wwwNN \fi: } (End definition for \__fp_add_significand_o:NnnwnnnnN.11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 { \__fp_decimate:nNnnnn {#1} \__fp_add_significand_o:NnnwnnnnN #4 #3 #2 } \cs_new:Npn \__fp_add_big_ii_o:wNww #1. #2 #3.99 · · · 95 → 1. #4. #1 } \cs_new:Npn \__fp_add_significand_pack:NNNNNNN #1 #2#3#4#5#6#7 { \if_meaning:w 2 #1 + \c_one \fi: . then go back and do the rounding. This function is documented on page ??.) \__fp_add_significand_o:NnnwnnnnN \__fp_add_significand_pack:NNNNNNN \__fp_add_significand_test_o:N \__fp_add_significand_o:NnnwnnnnN hrounding digiti {hY’1 i} {hY’2 i} hextra-digitsi .00 · · · 0. 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 \cs_new:Npn \__fp_add_significand_o:NnnwnnnnN #1 #2#3 #4. The rounding may cause a carry in very rare cases such as 0. but this situation always give an exact power of 10. Thus. we do the computation now and check for a carry. This requires to know whether the addition produces an overall carry or not. This function is documented on page ??. we must know at which digit the rounding should occur.) 576 . swap the numbers and call \__fp_sub_npos_i_o:Nnwnw with the opposite of hsign1 i. Thus. #5#6 { + \c_one \exp_after:wN \__fp_basics_pack_weird_high:NNNNNNNNw \int_use:N \__int_eval:w 1 1 #1 \exp_after:wN \__fp_basics_pack_weird_low:NNNNw \int_use:N \__int_eval:w 1 #2#3 + \exp_after:wN \__fp_round:NNN \exp_after:wN #6 \exp_after:wN #3 \__int_value:w \__fp_round_digit:Nw #4 #5 . h6di .) \__fp_add_significand_carry_o:wwwNN \__fp_add_significand_carry_o:wwwNN h8di . \s__fp \__fp_chk:w 1 #4#5#6. but we don’t care. 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 \cs_new:Npn \__fp_add_significand_no_carry_o:wwwNN #1. \exp_after:wN . h2di . } (End definition for \__fp_add_significand_carry_o:wwwNN. grab all the digits again and round.) 33. hrounding digiti hsigni The case where there is a carry is very similar. hrounding digiti hsigni If there’s no carry. #3#4 . If the numbers coincide. 11763 11764 11765 11766 \cs_new:Npn \__fp_sub_npos_o:NnwNnw #1#2#3. } (End definition for \__fp_add_significand_no_carry_o:wwwNN.3 \__fp_sub_npos_o:NnwNnw \__fp_sub_eq_o:Nnwnw \__fp_sub_npos_ii_o:Nnwnw Absolute subtraction \__fp_sub_npos_o:NnwNnw hsign1 i hexp1 i hbody1 i . \exp_stop_f: \exp_after:wN \__fp_sub_eq_o:Nnwnw 577 . #2. Rounding properly in some modes requires to know what the sign of the result will be. #5#6 { \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1 #1 \exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 1 #2 #3#4 + \__fp_round:NNN #6 #4 #5 \exp_after:wN . #2. #3#4. { \if_case:w \__fp_compare_npos:nwnw {#2} #3. Rounding can even raise the first digit from 1 to 2. {#5} #6. return zero.\__fp_add_significand_no_carry_o:wwwNN \__fp_add_significand_no_carry_o:wwwNN h8di . 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 \cs_new:Npn \__fp_add_significand_carry_o:wwwNN #1. If the second number is larger. h6di . \s__fp \__fp_chk:w 1 hinitial sign2 i hexp2 i hbody2 i . we start by comparing the exponents and significands. h2di . The packing function \__fp_basics_pack_high:NNNNNw takes care of the case where rounding brings a carry.2. The very large shifts of 109 and 1. This function is documented on page ??. If the two numbers have the same exponent. {#5} #6.11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 \or: \exp_after:wN \__fp_sub_npos_i_o:Nnwnw \else: \exp_after:wN \__fp_sub_npos_ii_o:Nnwnw \fi: #1 {#2} #3.1·109 are unnecessary here. { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN #1 \int_use:N \__int_eval:w #2 \if_int_compare:w #2 = #4 \exp_stop_f: \exp_after:wN \__fp_sub_back_near_o:nnnnnnnnN \else: \exp_after:wN \__fp_decimate:nNnnnn \exp_after:wN { \int_use:N \__int_eval:w #2 .#4 . If the resulting 16 digits start with a 0. the subtraction is exact. Otherwise. #2. Each integer expression produces a 10 digit result.). then call the far auxiliary to evaluate the difference between the two significands. \__fp_sanitize:Nw checks for overflow/underflow. 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 \cs_new:Npn \__fp_sub_npos_i_o:Nnwnw #1 #2#3. It expects the hfinal signi and the hexponenti (delimited by .#1 \__int_eval_end: #3. padding with trailing zeros. decimate y.\c_one \exp_after:wN } \exp_after:wN \__fp_sub_back_far_o:NnnwnnnnN \fi: #5 #3 #1 } (End definition for \__fp_sub_npos_i_o:Nnwnw. which starts with the exponent of the largest number. but allow the auxiliaries to be reused later. then we need to shift the group. { \exp_after:wN \c_zero_fp } \cs_new:Npn \__fp_sub_npos_ii_o:Nnwnw #1 #2. #4#5. so we discard the hfinal signi #9. } \cs_new:Npn \__fp_sub_eq_o:Nnwnw #1#2. and may be decreased if the two numbers are very close. Start an integer expression for the exponent.) \__fp_sub_back_near_o:nnnnnnnnN \__fp_sub_back_near_pack:NNNNNNw \__fp_sub_back_near_after:wNNNNw \__fp_sub_back_near_o:nnnnnnnnN {hY1 i} {hY2 i} {hY3 i} {hY4 i} {hX1 i} {hX2 i} {hX3 i} {hX4 i} hfinal signi In this case. Note that we decimate by 1 less than one could expect. } (End definition for \__fp_sub_npos_o:NnwNnw. call the near auxiliary. #3.) \__fp_sub_npos_i_o:Nnwnw After the computation is done. { \exp_after:wN \__fp_sub_npos_i_o:Nnwnw \int_use:N \__int_eval:w \c_two . 578 . #3. \__fp_sub_back_shift_iii:NNNNNNNNw #1 123456789. { \if_meaning:w 0 #1 \exp_after:wN \__fp_sub_back_shift:wnnnn \fi: . get four blocks of 4 digits and finally clean up. If the first two blocks are zero. This function is documented on page ??. yielding a result between 1 and 6. \__int_value:w #1 ~ #2#3 0 ~ 0000 0000 0000 000 . the space before #2#3 is ignored). { \if_meaning:w @ #1 @ . since non-zero blocks would then overflow \__fp_sub_back_shift_iv:nnnnw TEX’s integers).\c_eleven \exp_after:wN \__fp_sub_back_near_pack:NNNNNNw \int_use:N \__int_eval:w 11#7#8 . {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} . Otherwise we get the shift from #1 alone. 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833 11834 11835 \cs_new:Npn \__fp_sub_back_shift:wnnnn . Act with \number to trim leading zeros from \__fp_sub_back_shift_iii:NNNNNNNNw hZ1 i hZ2 i (we don’t do all four blocks at once. } \cs_new:Npn \__fp_sub_back_near_after:wNNNNw 10 #1#2#3#4 #5 . { + #1#2 . \fi: \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_sub_back_shift_iv:nnnnw \exp_after:wN . } \cs_new:Npn \__fp_sub_back_shift_ii:ww #1 0 . } 579 .\c_seven . Once the exponent is taken care of.) \__fp_sub_back_shift:wnnnn \__fp_sub_back_shift:wnnnn . \else: . \__fp_sub_back_shift_ii:ww This function is called with hZ1 i ≤ 999. {#3#4#5#6} {#7} . #1#2 { \exp_after:wN \__fp_sub_back_shift_ii:ww \__int_value:w #1 #2 0 . } \cs_new:Npn \__fp_sub_back_near_pack:NNNNNNw #1#2#3#4#5#6#7 .#1#2 . Trailing zeros are added so that digits can be grabbed safely. the auxiliary receives an empty #1 and trims #2#30 from leading zeros.\exp_after:wN \use_i:nnn \exp_after:wN \__fp_sub_back_shift_iii:NNNNNNNNw \__int_value:w #2#3 0 ~ 123456789. {#1#2#3#4} {#5} } (End definition for \__fp_sub_back_near_o:nnnnnnnnN.11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 \cs_new:Npn \__fp_sub_back_near_o:nnnnnnnnN #1#2#3#4 #5#6#7#8 #9 { \exp_after:wN \__fp_sub_back_near_after:wNNNNw \int_use:N \__int_eval:w 10#5#6 . trim leading zeros from #1#2#3 (when #1 is empty. yielding a total shift between 7 and 16 to the exponent.#3#4 \exp_after:wN . #2#3 . namely the first digit \__fp_sub_back_quite_far_ii:NN of x is 1. We use the odd combination of space and semi-colon delimiters to allow the not_far auxiliary to grab each piece individually. { . } (End definition for \__fp_sub_back_shift:wnnnn. If it is too close a call to know yet. we will get 1 whenever the hroundingi digit is less than or equal to 5 (remember that the hroundingi digit is only equal to 5 if there was no further non-zero digit). 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 \cs_new:Npn \__fp_sub_back_far_o:NnnwnnnnN #1 #2#3 #4. #5#6#7#8 { \if_case:w \if_int_compare:w 1 #2 = #5#6 \use_i:nnnn #7 \exp_stop_f: \if_int_compare:w #3 = \use_none:n #7#8 0 \exp_stop_f: \c_zero \else: \if_int_compare:w #3 > \use_none:n #7#8 0 . namely if 1hY’1 ihY’2 i = hX1 ihX2 ihX3 ihX4 i0. If the result is less than 10hexpox i . delimiter). Then the hroundingi #3 and the hfinal signi #4 control whether we get 1 or 0.) \__fp_sub_back_quite_far_o:wwNN The easiest case is when x − y is extremely close to a power of 10. 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 \cs_new:Npn \__fp_sub_back_quite_far_o:wwNN #1. then call the quite_far auxiliary. #2 . #1 } (End definition for \__fp_sub_back_far_o:NnnwnnnnN. {#8} \cs_new:Npn \__fp_sub_back_shift_iv:nnnnw #1 . {hX1 i} {hX2 i} {hX3 i} {hX4 i} hfinal signi If the difference is greater than 10hexpox i .9999999999999999.11836 11837 \cs_new:Npn \__fp_sub_back_shift_iii:NNNNNNNNw #1#2#3#4#5#6#7#8#9.) \__fp_sub_back_far_o:NnnwnnnnN \__fp_sub_back_far_o:NnnwnnnnN hroundingi {hY’1 i} {hY’2 i} hextra-digitsi . This function is documented on page ??. #5 #6 ~ #7 #8 . call the not_far auxiliary. and all others vanish when subtracting y. In the usual round-to-nearest mode. call the very_far auxiliary.\fi: \c_one \fi: \exp_after:wN \__fp_sub_back_quite_far_o:wwNN \or: \exp_after:wN \__fp_sub_back_very_far_o:wwwwNN \else: \exp_after:wN \__fp_sub_back_not_far_o:wwwwNN \fi: #2 ~ #3 . and the quite_far to ignore the significands easily (using the . #3#4 { \exp_after:wN \__fp_sub_back_quite_far_ii:NN \exp_after:wN #3 \exp_after:wN #4 } \cs_new:Npn \__fp_sub_back_quite_far_ii:NN #1#2 { \if_case:w \__fp_round_neg:NNN #2 0 #1 \exp_after:wN \use_i:nn \else: 580 . #1 .\fi: \c_one \fi: \else: \if_int_compare:w 1 #2 > #5#6 \use_i:nnnn #7 . #2. the very_far auxiliary to use \__fp_pack_eight:wNNNNNNNN. {1000} {0000} {0000} {0000} . #3 ~ #4.\exp_after:wN \__fp_round_neg:NNN \exp_after:wN #6 \use_none:nnnnnnn #2 #5 \exp_after:wN . Then proceed in a way similar to the near auxiliaries seen earlier.\c_one 581 . 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 \cs_new:Npn \__fp_sub_back_not_far_o:wwwwNN #1 ~ #2. Rounding is a bit more complicated: we have two hroundingi digits #3 and #6 (from the decimation. Shift the y significand by adding a leading 0. the last digit of 1100000000+#40-#2. Namely.\c_one \exp_after:wN \__fp_sub_back_near_after:wNNNNw \int_use:N \__int_eval:w 1#30 . we note that \__fp_round_neg:NNN only cares about its parity. and from the new shift) to take into account. The first \__int_value:w triggers the second one because the number is unfinished.\c_one . Then the logic is similar to the not_far functions above.) \__fp_sub_back_very_far_o:wwwwNN The case where x − y and x have the same exponent is a bit more tricky. #6#7 { \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1#4 . we can thus not use 0 in place of 2 there. } { . which is identical to that of the last digit of #2. we may have to decrease the result by one unit if \__fp_round_neg:NNN returns 1.#1 .\exp_after:wN \use_ii:nn \fi: { . 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 \cs_new:Npn \__fp_sub_back_very_far_o:wwwwNN #1#2#3#4#5#6#7 { \__fp_pack_eight:wNNNNNNNN \__fp_sub_back_very_far_ii_o:nnNwwNN { 0 #1#2#3 #4#5#6#7 } . } 11867 11868 11869 11870 11871 } (End definition for \__fp_sub_back_quite_far_o:wwNN. Decrement the exponent (with . mostly because \__fp_sub_back_very_far_ii_o:nnNwwNN it cannot reuse the same auxiliaries. and getting the parity of the main result requires a computation. This function is documented on page ??. } (End definition for \__fp_sub_back_not_far_o:wwwwNN. #4 ~ #5.\c_one). and with the added quirk that the hroundingi digit has to be taken into account. #3 . {9999} {9999} {9999} {9999} .) \__fp_sub_back_not_far_o:wwwwNN In the present case.\c_eleven \exp_after:wN \__fp_sub_back_near_pack:NNNNNNw \int_use:N \__int_eval:w 11 0000 0000 + #40 . and the hroundingi digit.#2 . but multiplying x by 10 (#30 and #40 below). This function expects the hfinal signi #6. #5#6 { . but y is large enough that x − y has a smaller exponent than x. x and y have different exponents.#1 . Instead of redoing the computation for the second argument. } \cs_new:Npn \__fp_sub_back_very_far_ii_o:nnNwwNN #1#2 . \exp_after:wN . in which the second operand is discarded. 11905 11906 11907 11908 11909 11910 11911 11912 \cs_new_nopar:cpn { __fp_*_o:ww } { \__fp_mul_cases_o:NnNnww * { . If the first operand is nan. If both numbers are normal. we do a computation which dispatches the products 0×0 = 0×1 = 1×0 = 0 to case 4 or 5 depending on the combined sign. used for the invalid operation exception. go to case 2. Otherwise. call \__fp_mul_npos_o:Nww to do the work. The second is inserted in a formula to dispatch cases slightly differently between multiplication and division. in which the first operand is discarded (note the weird interaction with the final test on signs).#2 .) \__fp_mul_cases_o:nNnnww Split into 10 cases (12 for division).\exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 2#5 . Then we separate the case where the first number is normal and the second is zero: this goes to cases 4 and 5 for multiplication. This function is documented on page ??. The third is the operation for normal floating points. Note that the code for these two cases (which return ±∞) is inserted as argument #4. and special numbers We go through an auxiliary.3 33.) 33. The first argument is the operation. and the products 1×∞ = ∞×1 = ∞×∞ = ∞ to cases 8 and 9. go to case 0 (same sign) or case 1 (opposite signs): in both cases. \s__fp \__fp_chk:w #8#9 { \if_case:w \__int_eval:w \if_int_compare:w #5 #8 = \c_eleven \c_one 582 . the products 0×∞ and ∞×0 to case 6 or 7 (invalid operation). The fourth is there for extra cases needed in \__fp_/_o:ww.\exp_after:wN \__fp_round_neg:NNN \exp_after:wN #7 \__int_value:w \if_int_odd:w \__int_eval:w #5 .3. because it differs in the case of divisions. go to case 3. which is common with \__fp_/_o:ww. 11913 11914 11915 11916 11917 11918 \cs_new:Npn \__fp_mul_cases_o:NnNnww #1#2#3#4 \s__fp \__fp_chk:w #5#6#7. 10 and 11 for division. 11895 11896 11897 11898 11899 11900 11901 11902 11903 } 11904 (End definition for \__fp_sub_back_very_far_o:wwwwNN.\c_two + } \__fp_mul_npos_o:Nww { } } (End definition for \__fp_*_o:ww.1 \__fp_*_o:ww Multiplication Signs. if the second operand is nan.#2 \__int_eval_end: 1 \else: 2 \fi: \__int_value:w \__fp_round_digit:Nw #3 #6 . triggered by \__fp_mul_significand_o:nnnnNnnnn.) 33.2 Absolute multiplication In this subsection. catching any shift coming from the computation in the significand. \s__fp \__fp_chk:w #6 #7 #8 #9 . \s__fp \__fp_chk:w #8 #9 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 } 11950 (End definition for \__fp_mul_cases_o:nNnnww.3. we perform the multiplication of two positive normal numbers. We setup the post-expansion here. As we did for addition. \__int_eval:w computes the exponent. After the computation. 11951 11952 11953 11954 \cs_new:Npn \__fp_mul_npos_o:Nww #1 \s__fp \__fp_chk:w #2 #3 #4 #5 .\c_one \fi: \__int_eval_end: \__fp_case_use:nw { #3 0 } \__fp_case_use:nw { #3 2 } \__fp_case_return_i_o:ww \__fp_case_return_ii_o:ww \__fp_case_return_o:Nww \c_zero_fp \__fp_case_return_o:Nww \c_minus_zero_fp \__fp_case_use:nw { \__fp_invalid_operation_o:Nww #1 } \__fp_case_use:nw { \__fp_invalid_operation_o:Nww #1 } \__fp_case_return_o:Nww \c_inf_fp \__fp_case_return_o:Nww \c_minus_inf_fp 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 \or: \or: \or: \or: \or: \or: \or: \or: \or: #4 \fi: \s__fp \__fp_chk:w #5 #6 #7. \s__fp \__fp_chk:w 1 hsign2 i {hexp2 i} hbody2 i . { \exp_after:wN \__fp_sanitize:Nw 583 .\else: \if_meaning:w 3 #8 \c_three \else: \if_meaning:w 3 #5 \c_two \else: \if_int_compare:w #5 #8 = \c_ten \c_nine #2 . \__fp_mul_npos_o:Nww \__fp_mul_npos_o:Nww hfinal signi \s__fp \__fp_chk:w 1 hsign1 i {hexp1 i} hbody1 i . The hfinal signi is needed to do the rounding properly in the significand computation.\c_two \else: (#5 #2 #8) / \c_two * \c_two + \c_seven \fi: \fi: \fi: \fi: \if_meaning:w #6 #9 . \__fp_sanitize:Nw checks for overflow or underflow. \exp_after:wN #1 \int_use:N \__int_eval:w #4 + #8 \__fp_mul_significand_o:nnnnNnnnn #5 #1 #9 11955 11956 11957 11958 11959 } (End definition for \__fp_mul_npos_o:Nww. \exp_after:wN . 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 \cs_new:Npn \__fp_mul_significand_o:nnnnNnnnn #1#2#3#4 #5 #6#7#8#9 { \exp_after:wN \__fp_mul_significand_test_f:NNN \exp_after:wN #5 \int_use:N \__int_eval:w 99990000 + #1*#6 + \exp_after:wN \__fp_mul_significand_keep:NNNNNw \int_use:N \__int_eval:w 99990000 + #1*#7 + #2*#6 + \exp_after:wN \__fp_mul_significand_keep:NNNNNw \int_use:N \__int_eval:w 99990000 + #1*#8 + #2*#7 + #3*#6 + \exp_after:wN \__fp_mul_significand_drop:NNNNNw \int_use:N \__int_eval:w 99990000 + #1*#9 + #2*#8 + #3*#7 + #4*#6 + \exp_after:wN \__fp_mul_significand_drop:NNNNNw \int_use:N \__int_eval:w 99990000 + #2*#9 + #3*#8 + #4*#7 + \exp_after:wN \__fp_mul_significand_drop:NNNNNw \int_use:N \__int_eval:w 99990000 + #3*#9 + #4*#8 + \exp_after:wN \__fp_mul_significand_drop:NNNNNw \int_use:N \__int_eval:w 100000000 + #4*#9 . { #1#2#3#4#5 . The approach is thus to compute the 5 first blocks of 4 digits (the first one is between 100 and 9999 inclusive). is used by \__fp_basics_pack_low:NNNNNw. one is for \__fp_round_digit:Nw later on. 584 . and one. preceeded by \exp_after:wN. which is correctly expanded (within an \__int_eval:w).) \__fp_mul_significand_o:nnnnNnnnn \__fp_mul_significand_drop:NNNNNw \__fp_mul_significand_keep:NNNNNw \__fp_mul_significand_o:nnnnNnnnn {hX1 i} {hX2 i} {hX3 i} {hX4 i} hsigni {hY1 i} {hY2 i} {hY3 i} {hY4 i} Note the three semicolons at the end of the definition. + #6 } \cs_new:Npn \__fp_mul_significand_keep:NNNNNw #1#2#3#4#5 #6. The place where we round depends on that number of digits. } (End definition for \__fp_mul_significand_o:nnnnNnnnn. } \cs_new:Npn \__fp_mul_significand_drop:NNNNNw #1#2#3#4#5 #6. the number of digits is known. Afterwards. and we can do the rounding within yet another set of \__int_eval:w. \exp_after:wN .) \__fp_mul_significand_test_f:NNN \__fp_mul_significand_test_f:NNN hsigni 1 hdigits 1–8 i . hdigits 13–16 i . and a compact version of the remaining 3 blocks. hdigits 9–12 i . One is for the last \__fp_mul_significand_drop:NNNNNw. but it is impossible to know which one before computing. { #1#2#3#4#5 . + hdigits 17–20 i + hdigits 21–24 i + hdigits 25–28 i + hdigits 29–32 i . #6 . The product of two 16 digit integers has 31 or 32 digits. . This function is documented on page ??. and may depend on all digits until the last in some rare cases. + { \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1#2 \exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 1#3#4#5#6#7 + \exp_after:wN \__fp_round:NNN \exp_after:wN #1 \exp_after:wN #7 \__int_value:w \__fp_round_digit:Nw } (End definition for \__fp_mul_significand_large_f:NwwNNNN. Our result will thus be hdigits 2–17 i.) 585 . after expansion of the small_pack auxiliary. to form a 9 digit number. by the next digit. plus some rounding which depends on the digits 17. plus some rounding which depends on the digits 16. #4#5#6#7. if hdigit 1 i is zero.\c_one \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1#3#4 \exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 1#5#6#7 + \exp_after:wN \__fp_round:NNN \exp_after:wN #1 \exp_after:wN #7 \__int_value:w \__fp_round_digit:Nw } (End definition for \__fp_mul_significand_small_f:NNwwwN.) \__fp_mul_significand_small_f:NNwwwN In this branch. The 8 digits 1#3 are followed. 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 \cs_new:Npn \__fp_mul_significand_small_f:NNwwwN #1 #2#3. + #7 { . #3. suitable for \__fp_round:NNN. Here. and replaces it by a hrounding digiti. 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 \cs_new:Npn \__fp_mul_significand_large_f:NwwNNNN #1 #2. 17.If the hdigit 1 i is non-zero. and whether further digits are zero. we care about digits 17 and 18. 11983 11984 11985 11986 11987 11988 11989 11990 11991 \cs_new:Npn \__fp_mul_significand_test_f:NNN #1 #2 #3 { \if_meaning:w 0 #3 \exp_after:wN \__fp_mul_significand_small_f:NNwwwN \else: \exp_after:wN \__fp_mul_significand_large_f:NwwNNNN \fi: #1 #3 } (End definition for \__fp_mul_significand_test_f:NNN. hdigit 1 i is zero.) \__fp_mul_significand_large_f:NwwNNNN In this branch. then for rounding we only care about the digits 16 and 17. On the other hand. 18. #6. #4#5. and whether all subsequent digits are zero or not. hdigit 1 i is non-zero. and whether all subsequent digits are zero or not. \__fp_round_digit:Nw takes digits 17 and further (as an integer expression). and whether further digits are zero or not (check for exact ties). The result is thus hdigits 1–16 i. \s__fp \__fp_chk:w 1 hsignZ i {hexp Z i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} .4 33.#6 \exp_after:wN \__fp_div_significand_i_o:wnnw \int_use:N \__int_eval:w #7 \use_i:nnnn #8 + \c_one .4. \__fp_/_o:ww Filtering special floating point is very similar to what we did for multiplications. a semi-colon. then the four {hAi i}. and the hfinal signi. { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN #1 \int_use:N \__int_eval:w #3 . As for multiplication. then the four {hZi i}.} \__fp_div_npos_o:Nww { \or: \__fp_case_use:nw { \__fp_division_by_zero_o:NNww \c_inf_fp / } \or: \__fp_case_use:nw { \__fp_division_by_zero_o:NNww \c_minus_inf_fp / } } } (End definition for \__fp_/_o:ww. used for rounding at the end.33. \__fp_sanitize:Nw checks for overflow or underflow. 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 \cs_new:Npn \__fp_div_npos_o:Nww #1 \s__fp \__fp_chk:w 1 #2 #3 #4 . we replace . and an integer expression in which we compute the exponent. \s__fp \__fp_chk:w 1 #5 #6 #7#8#9.\c_two + by -. we provide it with the hfinal signi. 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 \cs_new_nopar:cpn { __fp_/_o:ww } { \__fp_mul_cases_o:NnNnww / { . namely an integer hyi obtained by adding 1 to the first 5 digits of Z (explanation given soon below). We set up the arguments of \__fp_div_significand_i_o:wnnw. Invalid operation exceptions display / rather than *. There are two additionnal cases: if the first operand is normal and the second is a zero. In the formula for dispatch. with a few variations.1 Division Signs. #4 586 .) \__fp_div_npos_o:Nww \__fp_div_npos_o:Nww hfinal signi \s__fp \__fp_chk:w 1 hsignA i {hexp Ai} {hA1 i} {hA2 i} {hA3 i} {hA4 i} . The case of normal numbers is treated using \__fp_div_npos_o:Nww rather than \__fp_mul_npos_o:Nww. then the division by zero exception is raised: cases 10 and 11 of the \if_case:w construction in \__fp_mul_cases_o:NnNnww are provided as the fourth argument here. We want to compute A/Z. and special numbers Time is now ripe to tackle the hardest of the four elementary operations: division. in blocks of 4 digits. and we know that the first digits of A1 and of Z1 are non-zero. we want all intermediate steps to be positive. A = 0.A1 A2 A3 A4 and Z = 0. and E are all exact multiples of 10−16 . • Replace C by D = 104 C − QC Z. The result is then Q = 10−4 QA + 10−8 QB + 10−12 QC + 10−16 QD + rounding. we are now underestimating QA too much: it can be wrong by up to 100. Since the Qi are integers. since TEX can only handle integers less than roughly 2 · 109 . • Find an integer QC ' 104 C/Z. we explain how to avoid overflowing TEX’s integers when performing the division of two positive normal numbers. • Replace A by B = 104 A − QA Z. To compute A/Z. and a few steps down the line. #1 12040 12041 12042 } (End definition for \__fp_div_npos_o:Nww.) 33. • Consider E = 104 D − QD Z. However. A reasonable attempt would be to define QA as A1 A2 A \int_eval:n − 1 ≤ 104 Z1 + 1 Z Subtracting 1 at the end takes care of the fact that ε-TEX’s \__int_eval:w rounds divisions instead of truncating (really. and ensure correct rounding. for instance when Z = 0.{#7}{#8}#9 .Z1 Z2 Z3 Z4 . We are given two numbers.1 and A ' 1. In particular.4. since negative results would require extra calculations at the end. • Find an integer QD ' 104 D/Z. computing with 16 digits after the decimal separator yields exact results. we proceed as follows. we would run into arithmetic overflow. in other words. • Replace B by C = 104 B − QB Z. Unfortunately. D. • Find an integer QA ' 104 A/Z. Then B could take values up to 10 (maybe more). D. B. 1/2 would be sufficient. A better formula is to take 10 · A1 A2 QA = \int_eval:n −1 . C. This requires that QA ≤ 104 A/Z etc. • Find an integer QB ' 104 B/Z.2 Work plan In this subsection. and E may be greater than 1. The problem will be overflow: in general B. but we work with integers). things are not as easy as they seem. b10−3 · Z1 Z2 c + 1 587 . C. We add 1 to Z1 because Z1 ≤ 104 Z < Z1 + 1 and we need QA to be an underestimate. 6(y + 104 + 108 /y + 1012 /y 2 ). Also note that this formula does not cause an overflow as long as A < (231 − 1)/109 ' 2.This is always less than 109 A/(105 Z). 105 C < 1013 /y 2 + 1. y 2 Note that 104 < y ≤ 105 .Z2 Z3 Z4 ) 3 ≤ + y + 10 y 2 A1 A2 0 · 1 3 109 A ≤ + y + 10 ≤ + 1.6y. and the 8 first digits of A. and 999 ≤ QA ≤ 99989.6(y + 104 + 108 /y).6 · y. we take the 5 first digits of Z into account.A3 A4 − 10 · Z1 .147 · · · .Z2 Z3 Z4 + 10 < A1 A2 0 · 1 − 10 · y 2 A1 A2 0 · (y − 10 · Z1 . C. For convenience.147 · · · . taking into account the fact that ε-TEX rounds ties away from zero. y 2 y At the last step. we hide 10 into the second term for later convenience. 105 E < 109 D/y + 1. We shall prove that using this formula to define all the Qi avoids any overflow. since the numerator involves an integer slightly smaller than 109 A. so that. 105 C < 109 B/y + 1.6y. as we wanted. 105 E < 1021 /y 4 + 1.6y.Z2 Z3 Z4 · QA 3 Z1 . using 0 as a 9-th digit rather than the true digit for efficiency reasons. 105 D < 109 C/y + 1. let us denote y = 10−3 · Z1 Z2 + 1. A1 A2 0 1 QA = − y 2 A1 A2 0 3 > − . The goal is now to prove that none of B. D.6y. In words. Combining the various inequalities together with A < 1.Z2 Z3 Z4 + · 10 · Z1 .6(y + 104 ). Let us bound B: 105 B = A1 A2 0 + 10 · 0. and E can go beyond (231 − 1)/109 = 2. The same reasoning yields 105 B < 109 A/y + 1. 105 D < 1017 /y 3 + 1. we get 105 B < 109 /y + 1.6y. 588 . Thus. we need to find the integer part of 2E/Z. 10). The last step is to ensure correct rounding. Thus. hence will be rounded to a multiple of 10−16 or of 10−15 . 1. 1. and thus maximal at one of the end-points of the allowed range 104 < y ≤ 105 . Z1 Z2 which differs from 2E/Z by at most . so we only need to know the integer part of E/Z.7777 · 105 ). Furthermore.32 · 105 .16 · 105 . All of those bounds are less than 2. and a “rounding” digit encoding the rest. and we are thus within TEX’s bounds in all cases! We will later need to have a bound on the Qi . Equivalently. 105 E < max(1. Since 105 E 105 E 2E =2 5 ≤2 < 36.48 · 105 . 1. Their definitions imply that QA < 109 A/y − 1/2 < 105 A and similarly for the other Qi .All of those bounds are convex functions of y (since every power of y involved is convex.147 · 105 . we know that the result will be in [0. 105 B < max(1.1.7 · 105 ). all of them are less than 177770. 105 C < max(1. We have A/Z = 4 X 10−4i Qi + 10−16 E/Z i=1 exactly. 1. Z 10 Z 104 this integer part is between 0 and 35 inclusive. and the coefficients are positive). and determine whether it was an exact integer or not (this serves to detect ties). 105 D < max(1. We let ε-TEX round 2 · E1 E2 P = \int_eval:n .64 · 105 .77 · 105 ).777 · 105 ). . . . 8 . E . . . E 1 . + 2 . 10 E − E1 E2 . < 1. + 2 . . − −8 . . . P/2 . If it is negative. we know how to round to an integer. If it is zero. We will check the sign of 2E − P Z. then E/Z ∈ (P − 1)/2. Thus P is either the correct integer part. (P −1)/2 . or is off by 1. furthermore. depending on the parity of P . 2 Z 10 Z1 Z2 Z1 Z2 (1/2 comes from ε-TEX’s rounding) because each absolute value is less than 10−7 . 589 . and the rounding mode. In each case. P = 2E/Z. then E/Z ∈ P/2. if 2E/Z is an integer. then E/Z = P/2. If it is positive. which is 0 or 1. this is not possible because the macro has 9 parameters. 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 \cs_new:Npn \__fp_div_significand_i_o:wnnw #1 .) \__fp_div_significand_calc:wwnnnnnnn \__fp_div_significand_calc_i:wwnnnnnnn \__fp_div_significand_calc_ii:wwnnnnnnn \__fp_div_significand_calc:wwnnnnnnn h106 + QA i . and it turns out that we need post-expansion there. { \exp_after:wN \__fp_div_significand_test_o:w \int_use:N \__int_eval:w \exp_after:wN \__fp_div_significand_calc:wwnnnnnnn \int_use:N \__int_eval:w 999999 + #2 #3 0 / #1 . so the product of QA with each Zi is within TEX’s bounds. unbrace hA1 i and hA2 i. and call different auxiliaries for the two cases. {hB3 i} {hB4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} where B = 104 A − QA · Z. where hii stands for the 105 digit of QA . and is used in l3fp-expo. it is a little bit too large for our purposes: we would not be able to use the usual trick of adding a large power of 10 to ensure that the number of digits is fixed. and #1. Each of these calls will need hyi (#1). and prepare the hcontinuationi arguments for 4 consecutive calls to \__fp_div_significand_calc:wwnnnnnnn. However. #4 is six brace groups. etc. An earlier implementation did the tests within the computation. but since we added a hcontinuationi.33. {hA1 i} {hA2 i} {hA3 i} {hA4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} . #2#3 #4 .3 \__fp_div_significand_i_o:wnnw Implementing the significand division \__fp_div_significand_i_o:wnnw hyi .8 · 105 . followed by 0 or 1. implies that 106 + QA starts with the digit 1. hence the \__int_value:w. hB1 i hB2 i . The factors of 10 come from the fact that QA = 10 · 590 . hA1 i hA2 i . D. This function is also used to compute C.4. E (with the input shifted accordingly). The result we want is then (the overall power of 10 is arbitrary): 10−4 (#2 − #1 · #5 − 10 · hii · #5#6) + 10−8 (#3 − #1 · #6 − 10 · hii · #7) + 10−12 (#4 − #1 · #7 − 10 · hii · #8) + 10−16 (−#1 · #8). #4 { \exp_after:wN \__fp_div_significand_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_div_significand_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_div_significand_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_div_significand_iii:wwnnnnn \__int_value:w #1 } } (End definition for \__fp_div_significand_i_o:wnnw. We know that 0 < QA < 1. The bound on QA . #2 #3 . Here. {hA3 i} {hA4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} {hcontinuationi} expands to h106 + QA i hcontinuationi . which give the six first n-type arguments of the calc function. #2. are the parameters of either auxiliary. hsigni Compute 106 + QA (a 7 digit number thanks to the shift). We test. #3#4 #5#6#7#8 #9 { 1 1 #1 #9 \exp_after:wN .#1 * #7 .#70 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_middle_shift_int + #4 . #1 can go up to 99999. third. while the other negative term is very small < 106 (except in the first expression. leading to contributions of at worse −8 · 108 4. Indeed. which produces totals in the range [109 .#1 * #8 .1 · 109 ]. #2.#1 * #6 . Hence. 591 .#1 * #5 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_middle_shift_int + #3 .#1 * #8 .104 · hii + #1.#1 * #6 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_middle_shift_int + #4 . As usual. where we don’t care about the number of digits). a good choice is 2 · 109 . \int_use:N \__int_eval:w \c__fp_Bigg_leading_shift_int + #2 . {#5}{#6}{#7}{#8} } \cs_new:Npn \__fp_div_significand_calc_ii:wwnnnnnnn #1.#80 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_trailing_shift_int .#3#4 #5#6#7#8 #9 { 1 0 #1 #9 \exp_after:wN . for the auxiliary with hii = 0. We are flirting with TEX’s limits once more. to combine all the terms. #2. for the auxiliary with hii = 1.#1 * #5 . the positive contributions are at most 108 and the negative contributions can go up to 109 . #1 is at most 80000. Here.#5#60 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_middle_shift_int + #3 . \int_use:N \__int_eval:w \c__fp_Bigg_leading_shift_int + #2 . we need to choose some shifts which must ensure that the number of digits of the second. but there is no other negative term. 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 \cs_new:Npn \__fp_div_significand_calc:wwnnnnnnn 1#1 { \if_meaning:w 1 #1 \exp_after:wN \__fp_div_significand_calc_i:wwnnnnnnn \else: \exp_after:wN \__fp_div_significand_calc_ii:wwnnnnnnn \fi: } \cs_new:Npn \__fp_div_significand_calc_i:wwnnnnnnn #1.#1 * #7 \exp_after:wN \__fp_pack_Bigg:NNNNNNw \int_use:N \__int_eval:w \c__fp_Bigg_trailing_shift_int . 2. and fourth terms are each fixed. but both cannot happen simultaneously. 592 . and #6#7 up to 108 .{#5}{#6}{#7}{#8} 12096 12097 } (End definition for \__fp_div_significand_calc:wwnnnnnnn. with an extra hroundingi digit. This function is documented on page ??. which amounts to adding P/2 ' E/Z to QD . Otherwise it is in the appropriate range.P #2 . 12105 12106 12107 12108 12109 12110 12111 12112 \cs_new:Npn \__fp_div_significand_iii:wwnnnnn #1. since later expansions are triggered by this one). we need to be careful and show that the calculation #1 · #6#7 below does not cause an overflow: naively. which multiplies QD by 10: we will later add (roughly) 5 · P . i. This amounts to adding P/2 to QD . It seems an overkill to compute T exactly as I do here. #2. in other words if 1016 A/Z is an integer or half-integer.) \__fp_div_significand_iv:wwnnnnnnn \__fp_div_significand_v:NNw \__fp_div_significand_vi:Nw \__fp_div_significand_iv:wwnnnnnnn hPi . } (End definition for \__fp_div_significand_ii:wwn. 12098 12099 12100 12101 12102 12103 12104 \cs_new:Npn \__fp_div_significand_ii:wwn #1. Once more. % <. 4] or [6. This auxiliary is also used to compute QC and QD with the inputs C and D instead of B.) \__fp_div_significand_iii:wwnnnnn \__fp_div_significand_iii:wwnnnnn hyi . hB1 i . but I see no faster way right now.) \__fp_div_significand_ii:wwn \__fp_div_significand_ii:wwn hyi . #2. The result will be output to the left. {#3} {#4} {#5} {#6} {#7} } (End definition for \__fp_div_significand_iii:wwnnnnn. [1. in an \__int_eval:w which we start now. a packing auxiliary takes care of placing the digits of QB in an appropriate way for the final addition to obtain Q. 9]. hE1 i . if 0 = T = 2E − P Z.e.#3#4#5 #6#7 { 0 \exp_after:wN \__fp_div_significand_iv:wwnnnnnnn \int_use:N \__int_eval:w (\c_two * #2 #3) / #6 #7 .. To show that things are fine. we split in two (non-disjoint) cases. {hB2 i} {hB3 i} {hB4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} hcontinuationsi hsigni Compute QB by evaluating hB1 ihB2 i0/y − 1. This hroundingi digit is 0 or 5 if T does not contribute. the appropriate correction from a hypothetical QE . {hE2 i} {hE3 i} {hE4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} hsigni We compute P ' 2E/Z by rounding 2E1 E2 /Z1 Z2 . Once that is evaluated (and the other Qi also. {hE2 i} {hE3 i} {hE4 i} {hZ1 i} {hZ2 i} {hZ3 i} {hZ4 i} hsigni This adds to the current expression (107 + 10 · QD ) a contribution of 5 · P + sign(T ) with T = 2E − P Z. P can be up to 35.#3 { \exp_after:wN \__fp_div_significand_pack:NNN \int_use:N \__int_eval:w \exp_after:wN \__fp_div_significand_calc:wwnnnnnnn \int_use:N \__int_eval:w 999999 + #2 #3 0 / #1 . Note the first 0. hE1 i . This is precise enough for rounding purposes (in any mode). #2 #3 . • For P < 10. The packing function we define now does nothing special: it removes the 106 and carries two digits (for the 105 ’s and the 104 ’s). hence P ≤ 4E/Z. is also zero. The rest is standard.e. there was an exact agreement: T = 0. ε = sign(T ) is 0 in case 2E = P Z. Also.#1*#8 + \exp_after:wN \__fp_div_significand_v:NN \int_use:N \__int_eval:w 200000 + 2*#5 . we are in the following situation: TEX is in the process of expanding several integer expressions. \__fp_div_significand_test_o:w 106 + QA \__fp_div_significand_pack:NNN 106 + QB \__fp_div_significand_pack:NNN 106 + QC \__fp_div_significand_pack:NNN 107 + 10 · QD + 5 · P + ε . except that we use + as a separator (ending integer expressions explicitly). hsigni Here. #2.. a sum of several terms. and −1 if 2E < P Z. is less than a factor of 2. since the two factors are now independent. i.5 · 109 . It is also positive if the first character is 0 and second argument of \__fp_div_significand_vi:Nw. but not with an exact quotient.#3#4#5 #6#7#8#9 { + \c_five * #1 \exp_after:wN \__fp_div_significand_vi:Nw \int_use:N \__int_eval:w -20 + 2*#2#3 . { \if_meaning:w 0 #1 \if_int_compare:w \__int_eval:w #2 > \c_zero + \c_one \fi: \else: \if_meaning:w .#1 . T is negative if the first character is -. } \cs_new:Npn \__fp_div_significand_v:NN #1#2 { #1#2 \__int_eval_end: + } \cs_new:Npn \__fp_div_significand_vi:Nw #1#2. 12133 \cs_new:Npn \__fp_div_significand_pack:NNN 1 #1 #2 { + #1 #2 . Both inequalities could be made tighter if needed. it is positive if the first character is neither 0 nor -. which is at most 1. the product obeys P · #6#7 < 108 · P < 109 .#1*#6#7 + \exp_after:wN \__fp_div_significand_v:NN \int_use:N \__int_eval:w 199980 + 2*#4 . and \__fp_div_significand_vi: \__fp_div_significand_pack:NNN At this stage.\else: + \fi: \c_one \fi: . • For large P ≥ 3. } (End definition for \__fp_div_significand_iv:wwnnnnnnn . thus functions at the bottom expand before those above. P was an overestimate. #6#7 ≤ 108 · Z.) 593 . hence P · #6#7 ≤ 4E · 108 < 109 . \__fp_div_significand_v:NNw . which means that P was the correct value.#1*#9 . Otherwise. Thus we compute the two lower levels separately. 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 \cs_new:Npn \__fp_div_significand_iv:wwnnnnnnn #1. the rounding error on P . } (End definition for \__fp_div_significand_pack:NNN. Note however that P ·#8#9 may overflow. and the result may reach 3. 1 in case 2E > P Z. h5di .) \__fp_div_significand_large_o:wwwNNNNwN \__fp_div_significand_large_o:wwwNNNNwN h5di . 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 \cs_new:Npn \__fp_div_significand_small_o:wwwNNNNwN 0 #1. 12134 12135 12136 12137 12138 12139 12140 12141 12142 \cs_new:Npn \__fp_div_significand_test_o:w 10 #1 { \if_meaning:w 0 #1 \exp_after:wN \__fp_div_significand_small_o:wwwNNNNwN \else: \exp_after:wN \__fp_div_significand_large_o:wwwNNNNwN \fi: #1 } (End definition for \__fp_div_significand_test_o:w. #4#5#6#7#8. #9 { \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1 #1#2 \exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 1 #3#4#5#6#7 + \__fp_round:NNN #9 #7 #8 \exp_after:wN . h4di . h4di . #2. cannot reach 2 · 109 . It is now time to round. and 10 + QA = 10 · · · .1 (inclusive) and 10. h5di . h4di . h4di . together with contributions from the level below. 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 \cs_new:Npn \__fp_div_significand_large_o:wwwNNNNwN #1. hence 1#1#2. #3. #2. For rounding. h5di . This depends on how many digits the final result will have. We finally get to use the hfinal signi which has been sitting there for a while. #9 { + \c_one \exp_after:wN \__fp_basics_pack_weird_high:NNNNNNNNw \int_use:N \__int_eval:w 1 #1 #2 \exp_after:wN \__fp_basics_pack_weird_low:NNNNw \int_use:N \__int_eval:w 1 #3 #4 #5 #6 + \exp_after:wN \__fp_round:NNN \exp_after:wN #9 \exp_after:wN #6 594 . #3. h4di . hsigni We know that the final result cannot reach 10. h4di . hsigni The reason we know that the first two digits are 1 and 0 is that the final result is fA (the tilde denoting the contribution known to be between 0.\__fp_div_significand_test_o:w \__fp_div_significand_test_o:w 1 0 h5di .) \__fp_div_significand_small_o:wwwNNNNwN \__fp_div_significand_small_o:wwwNNNNwN 0 h4di . hence Q 6 f from the other Qi ) is at most 99999. we build the hrounding digiti from the last two of our 18 digits. } (End definition for \__fp_div_significand_small_o:wwwNNNNwN. hfinal signi Standard use of \__fp_basics_pack_low:NNNNNw and \__fp_basics_pack_high:NNNNNw. #4#5#6#7#8. exponential. and expands after itself in the input stream.5 \__fp_-_o:w Unary operations This function flips the sign of the hfloating pointi and expands after it in the input stream. 12164 12165 } 12166 (End definition for \__fp_div_significand_large_o:wwwNNNNwN.) 12183 h/initex | packagei l3fp-extended implementation 34 12184 h*initex | packagei 12185 h@@=fpi 34. just like \__fp_+_o:ww etc. 12167 12168 12169 12170 12171 12172 12173 12174 \cs_new:cpn { __fp_-_o:w } #1 \s__fp \__fp_chk:w #2 #3 { \exp_after:wN \__fp_exp_after_o:w \exp_after:wN \s__fp \exp_after:wN \__fp_chk:w \exp_after:wN #2 \int_use:N \__int_eval:w \c_two . some of the calculations are not performed with the full 24-digit precision. We add a hook used by l3fp-expo: anything before \s__fp is ignored. the last two blocks of each fixed point number may be wrong as long as the error is small enough to be rounded away when converting back to a floating point number. In other words. We must leave the sign of nan invariant. 12175 12176 12177 12178 12179 12180 12181 12182 \cs_new:Npn \__fp_abs_o:w \s__fp \__fp_chk:w #1 #2 { \exp_after:wN \__fp_exp_after_o:w \exp_after:wN \s__fp \exp_after:wN \__fp_chk:w \exp_after:wN #1 \__int_value:w \if_meaning:w 1 #2 1 \else: 0 \fi: \exp_stop_f: } (End definition for \__fp_abs_o:w. Since we eventually only care about the 16 first digits of the final result.) \__fp_abs_o:w This function sets the sign of the hfloating pointi to be positive. we work on (almost) fixed-point numbers with extended (24 digits) precision. and trigonometric functions.1 Description of extended fixed points In this module.) 33.#3 \__int_eval_end: } (End definition for \__fp_-_o:w. \exp_after:wN . The fixed point numbers are expressed as 595 . just like \__fp_-_o:w. This is used in the computation of Taylor series for the logarithm.\__int_value:w \__fp_round_digit:Nw #7 #8 . 12186 12187 \tl_const:Nn \c__fp_one_fixed_tl { {10000} {0000} {0000} {0000} {0000} {0000} } (End definition for \c__fp_one_fixed_tl. “nottoo-large” depends on the specific function (see the corresponding comments for details). This allows constructions such as \__fp_fixed_add:wwn hX1 i . except ha1 i. At the end of the calculation. Most functions we define here have the form They perform the hcalculationi on the two hoperandsi. 12188 \cs_new:Npn \__fp_fixed_continue:wn #1. #2 { #2 #1. where each hai i is exactly 4 digits (ranging from 0000 to 9999). This function has to change the exponent of the floating point number: it must be used after starting an integer expression for the overall exponent of the result.) \__fp_fixed_mul_after:wn The fixed point operations which involve multiplication end by calling this auxiliary. to compute (X1 + X2 ) · X3 + X4 .) \__fp_fixed_continue:wn This function does nothing. Of course. by changing a1 to 10000 + a1 . there is no bound on a1 (except TEX’s own 231 −1). This turns out to be very appropriate for computing continued fractions and Taylor series. hX2 i . used in l3fp-expo. This requires a1 ≤ 231 − 10001. 12189 12190 12191 12192 12193 \cs_new:Npn \__fp_fixed_add_one:wN #1#2. 6 point number a corresponding to the representation above is a = i=1 hai i · 10−4i . and places the hcontinuationi #2 in front. the result is turned back to a floating point number using \__fp_fixed_to_float:Nw. with or without trailing zeros. then feed the result (6 brace groups followed by a semicolon) to the hcontinuationi. Some functions only accept an N-type hcontinuationi. \__fp_fixed_add:wwn hX4 i . Checking for overflow is the responsibility of the code calling those The fixed Pfunctions. } (End definition for \__fp_fixed_continue:wn.{ha1 i} {ha2 i} {ha3 i} {ha4 i} {ha5 i} {ha6 i} . #3 { \exp_after:wN #3 \exp_after:wN { \int_use:N \__int_eval:w \c_ten_thousand + #1 } #2 . 34.) \__fp_fixed_add_one:wN This function adds 1 to the fixed point hai. \__fp_fixed_mul:wwn hX3 i . which may be any “not-too-large” non-negative integer. The hcontinuationi was brought up through the expansions by the packing functions.2 \c__fp_one_fixed_tl Helpers for extended fixed points The extended fixed-point number 1. #2 { #2 {#1} } (End definition for \__fp_fixed_mul_after:wn. then calls the hcontinuationi. It braces the last block of digits. responsible for the next step of the calculation.) 596 . 12194 \cs_new:Npn \__fp_fixed_mul_after:wn #1. Here. } (End definition for \__fp_fixed_add_one:wN. and the 4 other digits are braced. The auxiliary also computes ai −n·Qi .34. {#2} {#1} } 597 . } \cs_new:Npn \__fp_fixed_div_int:wnN #1. {#7} \__fp_fixed_div_int_auxi:wnn #4. {#7} \__fp_fixed_div_int_auxi:wnn #6. and ai as arguments. placing the result in front of the 4 digits of ai+1 . {#7} \__fp_fixed_div_int_auxi:wnn #2. Each pack auxiliary receives 5 digits followed by a semicolon. which places the hcontinuationi as appropriate. The first digit is added as a carry to the integer expression above. which ensures that the result of this expression will have 5 digits. There is no bound on a1 . 3: the ii or the iii auxiliary. It adds Qi to a surrounding integer expression. giving the integer closest to 10000 + a6 /n. {#7} \__fp_fixed_div_int_auxii:wnn .3 \__fp_fixed_div_int:wwN \__fp_fixed_div_int:wnN \__fp_fixed_div_int_auxi:wnn \__fp_fixed_div_int_auxii:wnn \__fp_fixed_div_int_pack:Nw \__fp_fixed_div_int_after:Nw Dividing a fixed point number by a small integer Divides the fixed point number hai by the (small) integer 0 < hni < 104 and feeds the result to the hcontinuationi. {#7} \__fp_fixed_div_int_auxi:wnn #3. The last brace group is produced by the after auxiliary. The resulting a0i+1 = 104 (ai − n · Qi ) + ai+1 serves as the first argument for a new call to the i auxiliary. Each call to the pack auxiliary thus produces one brace group. #8 { \exp_after:wN \__fp_fixed_div_int_after:Nw \exp_after:wN #8 \int_use:N \__int_eval:w \c_minus_one \__fp_fixed_div_int:wnN #1. 2: n.\c_one . The arguments of the i auxiliary are 1: one of the ai . When the iii auxiliary is called. {#7} \__fp_fixed_div_int_auxi:wnn #5. 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 \cs_new:Npn \__fp_fixed_div_int:wwN #1#2#3#4#5#6 . It computes a (somewhat tight) lower bound Qi for the ratio ai /n. The iii auxiliary adds Q6 + 2 ' a6 /n + 1 to the last 9999. n. The ii auxiliary receives Qi . the situation looks like this: \__fp_fixed_div_int_after:Nw hcontinuationi −1 + Q1 \__fp_fixed_div_int_pack:Nw 9999 + Q2 \__fp_fixed_div_int_pack:Nw 9999 + Q3 \__fp_fixed_div_int_pack:Nw 9999 + Q4 \__fp_fixed_div_int_pack:Nw 9999 + Q5 \__fp_fixed_div_int_pack:Nw 9999 \__fp_fixed_div_int_auxii:wnn Q6 . #7 . and starts a new one with the initial value 9999. #2 #3 { \exp_after:wN #3 \int_use:N \__int_eval:w #1 / #2 . {hni} {ha6 i} where expansion is happening from the last line up. and requires the result to be positive (this happens automatically for addition). #8 { #3 #4#5 \exp_after:wN \__fp_fixed_add_pack:NNNNNwn \int_use:N \__int_eval:w 2 0000 0000 #3 #6#7 + #1#2 .12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 \cs_new:Npn \__fp_fixed_div_int_auxi:wnn #1. b1 < 50000. #7 { + #1 . This function requires 0 ≤ a1 . . then #7) from the end of the argument list to its start. . { #1 {#2} } (End definition for \__fp_fixed_div_int:wwN. the rest of a.) 598 . After going down through the various level.} \cs_new:Npn \__fp_fixed_add:Nnnnnwnn #1 #2#3#4#5 #6. { + #1. the sign multiplying b. #7 { #7 {#1#2#3#4#5} {#6} } (End definition for \__fp_fixed_add:wwn and \__fp_fixed_sub:wwn. 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 \cs_new_nopar:Npn \__fp_fixed_add:wwn { \__fp_fixed_add:Nnnnnwnn + } \cs_new_nopar:Npn \__fp_fixed_sub:wwn { \__fp_fixed_add:Nnnnnwnn . It would be nice to grab the 12 brace groups in one go. #2 #3 { + #1 \exp_after:wN \__fp_fixed_div_int_pack:Nw \int_use:N \__int_eval:w 9999 \exp_after:wN \__fp_fixed_div_int:wnN \int_use:N \__int_eval:w #3 . and b1 and b2 . {#8} . } \cs_new:Npn \__fp_fixed_add_pack:NNNNNwn #1 #2#3#4#5 #6. These functions are documented on page ??. a4 . {#2} } \cs_new:Npn \__fp_fixed_div_int_after:Nw #1 #2. The two functions only differ a sign. . we go back up. The second auxiliary receives the rest of a. This function is documented on page ??. #7#8 { \exp_after:wN \__fp_fixed_add_after:NNNNNwn \int_use:N \__int_eval:w 9 9999 9998 + #2#3 #1 #7#8 \exp_after:wN \__fp_fixed_add_pack:NNNNNwn \int_use:N \__int_eval:w 1 9999 9998 + #4#5 \__fp_fixed_add:nnNnnnwn #6 #1 } \cs_new:Npn \__fp_fixed_add:nnNnnnwn #1#2 #3 #4#5 #6#7 . the rest of b. } \cs_new:Npn \__fp_fixed_div_int_pack:Nw #1 #2. a − b) and feeds the result to the hcontinuationi. .4 \__fp_fixed_add:wwn \__fp_fixed_sub:wwn \__fp_fixed_add:Nnnnnwnn \__fp_fixed_add:nnNnnnwn \__fp_fixed_add_pack:NNNNNwn \__fp_fixed_add_after:NNNNNwn Adding and subtracting fixed points Computes a + b (resp. hence use a common auxiliary. Start by grabbing the two signs. a1 .) 34. #2 #3 { + #1 + \c_two . {#7} {#2#3#4#5} {#6} } \cs_new:Npn \__fp_fixed_add_after:NNNNNwn 1 #1 #2#3#4#5 #6. packing digits and bringing the hcontinuationi (#8. and the hcontinuationi as arguments. only 9 parameters are allowed.#1*#2 \__int_eval_end: } \cs_new:Npn \__fp_fixed_div_int_auxii:wnn #1. as #7. a4 . a2 . a1 . b2 . . b1 < 10000. . including a left parenthesis for the fraction. a6 . . a6 . . . b1 . Once more. including the right parenthesis and the denominator of the fraction. b6 and finally the hcontinuationi as arguments. .5 \__fp_fixed_mul:wwn \__fp_fixed_mul:nnnnnnnwn Multiplying fixed points Computes a×b and feeds the result to hcontinuationi. . . and the corresponding parts of b. Note that we don’t need to obtain an exact rounding. Note how the first 15 terms only depend on a1 . Hence. . The i auxiliary receives a5 . so things could be harder. The packing auxiliaries bring the hcontinuationi up through the expansion chain. . a4 and b1 . . and b1 . 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 \cs_new:Npn \__fp_fixed_mul:wwn #1#2#3#4 #5. . the rest of a. contrarily to the * operator. while the last 6 terms only depend on a1 . It writes the end of the expression. This function requires 0 ≤ a1 . a5 . a2 . and it is finally placed in front of the 6 brace groups by \__fp_fixed_mul_after:wn. b5 . . #9 599 . we need to play around the limit of 9 arguments for TEX macros. b4 . . and writes the 15 first terms of the expression. We wish to perform carries in a × b =a1 · b1 · 10−8 + (a1 · b2 + a2 · b1 ) · 10−12 + (a1 · b3 + a2 · b2 + a3 · b1 ) · 10−16 + (a1 · b4 + a2 · b3 + a3 · b2 + a4 · b1 ) · 10−20 a3 · b4 + a4 · b3 + a1 · b6 + a2 · b5 + a5 · b2 + a6 · b1 + a1 · b5 + a5 · b1 + a2 · b4 + a3 · b3 + a4 · b2 + 104 where the O(10−24 ) stands for terms which are at most 5 · 10−24 .34. #6#7#8#9 { \exp_after:wN \__fp_fixed_mul_after:wn \int_use:N \__int_eval:w \c__fp_leading_shift_int \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int + #1*#6 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int + #1*#7 + #2*#6 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int + #1*#8 + #2*#7 + #3*#6 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int + #1*#9 + #2*#8 + #3*#7 + #4*#6 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_trailing_shift_int + #2*#9 + #3*#8 + #4*#7 + ( #3*#9 + #4*#8 + \__fp_fixed_mul:nnnnnnnwn #5 {#6}{#7} {#1}{#2} } \cs_new:Npn \__fp_fixed_mul:nnnnnnnwn #1#2 #3#4 #5#6 #7#8 . . . ignoring those leads to an error of at most 5 ulp. the first function grabs a1 . b4 . } \cs_new:Npn \__fp_fixed_mul_sub_back:wwwn #1. and · denotes multiplication. Since those functions are at the heart of \__fp_fixed_mul_one_minus_mul:wwn the computation of Taylor expansions. The task is obviously tough because we have 18 brace groups in front of us. c1 ≤ 10000. The hcontinuationi is placed correctly to be taken upstream by packing auxiliaries. For definiteness. c − a × b. and in particular we do not factor out the common parts of the three functions. + + #7 #8 . #9 { \exp_after:wN \__fp_fixed_mul_after:wn \int_use:N \__int_eval:w \c__fp_big_leading_shift_int \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int + #3 #4 \__fp_fixed_mul_add:Nwnnnwnnn - 600 . #2. corresponding to 10−4 . 12270 12271 12272 } 12273 (End definition for \__fp_fixed_mul:wwn.6 Combining product and sum of fixed points \__fp_fixed_mul_add:wwwn Compute a × b + c. #2. calls the i auxiliary with arguments described later. c5 c6 denote the 8-digit number obtained by juxtaposing the two blocks of digits of c. is empty). {#9} .{ 12269 #1*#4 + #2*#3 + #5*#8 + #6*#7 ) / \c_ten_thousand + #1*#3 + #5*#7 . 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 \cs_new:Npn \__fp_fixed_mul_add:wwwn #1. consider the task of computing a × b + c. \__fp_fixed_mul_sub_back:wwwn Those functions require 0 ≤ a1 . #3#4#5#6#7#8. with c1 c2 in the first level. We will perform carries in a × b + c =(a1 · b1 + c1 c2 ) · 10−8 + (a1 · b2 + a2 · b1 ) · 10−12 + (a1 · b3 + a2 · b2 + a3 · b1 + c3 c4 ) · 10−16 + (a1 · b4 + a2 · b3 + a3 · b2 + a4 · b1 ) · 10−20 a3 · b4 + a4 · b3 + a1 · b6 + a2 · b5 + a5 · b2 + a6 · b1 + a1 · b5 + a5 + a2 · b4 + a3 · b3 + a4 · b2 + 104 where c1 c2 . and 1 − a × b and feed the result to the hcontinuationi. #2 .. #2 . This function is documented on page ??. #9 { \exp_after:wN \__fp_fixed_mul_after:wn \int_use:N \__int_eval:w \c__fp_big_leading_shift_int \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int + #3 #4 \__fp_fixed_mul_add:Nwnnnwnnn + + #5 #6 . we over-optimize them a bit. {#9} . Each of the three function starts the first two levels (the first. which is omitted for \__fp_fixed_one_minus_mul:wwn. c3 c4 . {hcontinuationi} . The + c5 c6 piece. #1 .) 34. will be taken in the integer expression for the 10−24 level. and adds a trailing + c5 c6 . #3#4#5#6#7#8. b1 . #1 . We can build three levels: a1 · b1 for 10−8 . but not hbi. } (End definition for \__fp_fixed_mul_add:wwwn . Then we prepare level 10−24 . hb3 i. {#9} . Obviously. 12317 12318 \cs_new:Npn \__fp_fixed_mul_add:nnnnwnnnn #1#2#3#4#5. which was inserted by the i auxiliary. #4.) \__fp_fixed_mul_add:nnnnwnnnn Level 10−20 is (a1 · b4 + a2 · b3 + a3 · b2 + a4 · b1 ). #2 . #8. Note that #2 is empty for \__fp_fixed_one_minus_mul:wwn. a6 . To do all this. . we prepare the partial expressions b1 + a4 · b2 + a3 · b3 + a2 · b4 + a1 b2 + a4 · b3 + a3 · b4 + a2 . and \__fp_fixed_mul_one_minus_mul:wwn \__fp_fixed_mul_add:Nwnnnwnnn Here. and (a1 · b3 + a2 · b2 + a3 · b1 + c3 c4 ) for 10−16 . #2 . Arguments #3. ha2 i. We call the ii auxiliary for levels 10−20 and 10−24 . {#3} . 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 \cs_new:Npn \__fp_fixed_mul_add:Nwnnnwnnn #1 #2. #3 { \exp_after:wN \__fp_fixed_mul_after:wn \int_use:N \__int_eval:w \c__fp_big_leading_shift_int \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int + 1 0000 0000 \__fp_fixed_mul_add:Nwnnnwnnn . arguments #7. those expressions make no mathematical sense: we will complete them with a5 · and · b5 . we keep a1 . #2. hopi is either + or -. #1 . \__fp_fixed_mul_sub_back:wwwn . (a1 · b2 + a2 · b1 ) for 10−12 . #2 . } \cs_new:Npn \__fp_fixed_one_minus_mul:wwn #1. and of course with the trailing + c5 c6 . #9 are ha1 i. #5 are hb1 i. #7#8#9 { #1 #7*#3 \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int #1 #7*#4 #1 #8*#3 \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int #1 #7*#5 #1 #8*#4 #1 #9*#3 #2 \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_middle_shift_int #1 \__fp_fixed_mul_add:nnnnwnnnn {#7}{#8}{#9} } (End definition for \__fp_fixed_mul_add:Nwnnnwnnn. + #7 #8 . ha3 i. and with a6 · b1 + a5 · and · b5 + a1 · b6 .12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 + #5 #6 . The a–b products huse the sign #1. since there is another copy later in the input stream. #6#7#8#9 { 601 . #2 . multiplied by the sign. keeping the pieces of hai we’ve read. and the corresponding pieces of hbi. a5 . We don’t have access to all parts of hai and hbi needed to make all products. Instead. hb2 i. #3#4#5#6. Note that the total of level 10−24 is in the interval [−5 · 108 . #9 { #9 (#4* #1 *#7) #9 (#5*#6+#4* #2 *#7+#3*#8) / \c_ten_thousand } (End definition for \__fp_fixed_mul_add:nnnnwnnwN. The trailing + c5 c6 is taken into the expression for level 10−24 . 12328 12329 12330 12331 12332 \cs_new:Npn \__fp_fixed_mul_add:nnnnwnnwN #1#2 #3#4#5. The second one is divided by 10000: this is the carry from level 10−28 . {#6} 12319 12320 12321 12322 12323 12324 12325 12326 } 12327 (End definition for \__fp_fixed_mul_add:nnnnwnnnn. #6#7#8.( #1*#9 + #2*#8 + #3*#7 + #4*#6 ) \exp_after:wN \__fp_pack_big:NNNNNNwn \int_use:N \__int_eval:w \c__fp_big_trailing_shift_int \__fp_fixed_mul_add:nnnnwnnwN { #6 + #4*#7 + #3*#8 + #2*#9 + #1 } { #7 + #4*#8 + #3*#9 + #2 } {#1} #5. 6 · 108 (give or take a couple of 10000). ensuring that 1000 ≤ ha’1 i ≤ 9999. and we assume that it is less than 108 . 17 Bruno: I must double check this assumption.) 34. as expected by the packing auxiliaries. \exp_after:wN . { \__fp_fixed_to_float:wN #2. And the to_fixed version gives six brace groups instead of 4.) \__fp_fixed_mul_add:nnnnwnnwN Complete the hpartial1 i and hpartial2 i expressions as explained for the ii auxiliary. At this stage. we know that ha1 i is positive (otherwise. #1 } \cs_new:Npn \__fp_fixed_to_float:wN #1#2#3#4#5#6. See l3fp-aux for the definition of the shifts and packing auxiliaries.17 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 \cs_new:Npn \__fp_fixed_to_float:Nw #1#2. it is sign of an error before). #7 { + \c_four % for the 8-digit-at-the-start thing. {ha’1 i} {ha’2 i} {ha’3 i} {ha’4 i} . \exp_after:wN \exp_after:wN \exp_after:wN \__fp_fixed_to_loop:N \exp_after:wN \use_none:n \int_use:N \__int_eval:w 1 0000 0000 + #1 \exp_after:wN \__fp_use_none_stop_f:n \__int_value:w 1#2 \exp_after:wN \__fp_use_none_stop_f:n \__int_value:w 1#3#4 \exp_after:wN \__fp_use_none_stop_f:n \__int_value:w 1#5#6 \exp_after:wN . 602 . hence adding it to the shift gives a 10-digit number.7 \__fp_fixed_to_float:wN \__fp_fixed_to_float:Nw Converting from fixed point to floating point yields hexponent’i . we want to compute A/B. #1 \exp_after:wN \__fp_fixed_to_float_zero:w \else: \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_fixed_to_float_pack:ww \exp_after:wN . and express it as a floating point number.\c_two * \c__fp_max_exponent_int . { \exp_after:wN \__fp_basics_pack_high:NNNNNw \int_use:N \__int_eval:w 1 #1#2 \exp_after:wN \__fp_basics_pack_low:NNNNNw \int_use:N \__int_eval:w 1 #3#4 + \c_one . \fi: #1 #2 0000 0000 0000 0000 . B . { \if_int_compare:w #2 > \c_four \exp_after:wN \__fp_fixed_to_float_round_up:wnnnnw \fi: . { . } \cs_new:Npn \__fp_fixed_to_float_pack:ww #1 . } (End definition for \__fp_fixed_to_float:wN and \__fp_fixed_to_float:Nw. {0000} {0000} {0000} {0000} . #3 { 603 . #1#2#3#4 . #1 . } \cs_new:Npn \__fp_fixed_to_float_round_up:wnnnnw . 0000 0000 0000 0000 . { \if_meaning:w . #2#3 . .) \__fp_fixed_inv_to_float:wN \__fp_fixed_div_to_float:ww Starting from fixed_dtf A .\c_one \exp_after:wN \__fp_fixed_to_loop:N \else: \exp_after:wN \__fp_fixed_to_loop_end:w \exp_after:wN #1 \fi: } \cs_new:Npn \__fp_fixed_to_loop_end:w #1 #2 .12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 } \cs_new:Npn \__fp_fixed_to_loop:N #1 { \if_meaning:w 0 #1 . Normalize both numbers by removing leading brace groups of zeros and leaving the appropriate exponent shift in the input stream. 12389 12390 \cs_new:Npn \__fp_fixed_inv_to_float:wN #1#2. } \cs_new:Npn \__fp_fixed_to_float_zero:w . #3#4. } \cs_new:Npn \__fp_fixed_dtf_zeros:wNnnnnnn \fi: \__fp_fixed_dtf_no_zero:Nwn #1#2#3#4#5#6#7 { \fi: #1 \c_minus_one \exp_after:wN \use_i_ii:nnn \exp_after:wN \__fp_fixed_dtf_zeros:NN \exp_after:wN #1 \int_use:N \__int_eval:w 10 0000 + #2 \__int_eval_end: #3#4#5#6#7 . } \cs_new:Npn \__fp_fixed_div_to_float:ww #1#2. #4 \s__fp { \fi: \if_meaning:w . } \cs_new:Npn \__fp_fixed_dtf_zeros:NN #1#2 { \if_meaning:w 0 #2 #1 \c_one \else: \__fp_fixed_dtf_zeros_end:wNww #2 \fi: \__fp_fixed_dtf_zeros:NN #1 } \cs_new:Npn \__fp_fixed_dtf_zeros_end:wNww #1 \fi: \__fp_fixed_dtf_zeros:NN #2 #3. 1 . { \if_int_compare:w #1 < \c_one_thousand \__fp_fixed_dtf_zeros:wNnnnnnn \fi: \__fp_fixed_dtf_no_zero:Nwn .12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 + \__int_eval:w % ^^A todo: remove the +? \if_int_compare:w #1 < \c_one_thousand \__fp_fixed_dtf_zeros:wNnnnnnn \fi: \__fp_fixed_dtf_no_zero:Nwn + {#1} #2 \s__fp \__fp_fixed_dtf_approx:n {10000} {0000} {0000} {0000} {0000} {0000} .{#1} #2 \s__fp { \if_int_compare:w #3 < \c_one_thousand \__fp_fixed_dtf_zeros:wNnnnnnn \fi: \__fp_fixed_dtf_no_zero:Nwn + {#3} #4 \s__fp \__fp_fixed_dtf_approx:n } } \cs_new:Npn \__fp_fixed_dtf_no_zero:Nwn #1#2 \s__fp #3 { #3 #2. #1 #2 \c_two * \c__fp_max_exponent_int \use_i_ii:nnn 604 . 6 · 10−19 . Since we target a 16-digit value. 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 } \cs_new:Npn \__fp_fixed_dtf_zeros_auxi:ww { \__fp_pack_twice_four:wNNNNNNNN \__fp_pack_twice_four:wNNNNNNNN \__fp_pack_twice_four:wNNNNNNNN \__fp_fixed_dtf_zeros_auxii:ww . representing fixed point numbers in the range [0. We first find an estimate a for the inverse of B 0 by computing 109 α= x+1 9 10 β= x h y i a = 103 α + (β − α) · 103 − − 1750.255 · 10−5 < B0a < 1. 9999] and y ∈ [0. where hB’i and hA’i are each 6 brace groups. 9999] the first two groups of hB’i. 10 where •• denotes ε-TEX’s rounding division.\fi: \__fp_fixed_dtf_zeros_auxi:ww #1#3 0000 0000 0000 0000 0000 0000 . Let us prove the upper bound first. Denote by x ∈ [1000. #3 { #3 #1. hA’i . which is correct up to a relative error of 4 < 2. We will prove that 1 − 2. } \cs_new:Npn \__fp_fixed_dtf_zeros_auxii:ww #1. } We get \__fp_fixed_dtf_approx:n hB’i . The shift by 1750 helps to ensure that a is an underestimate of the correct value. 108 We can then compute the inverse B 0 a/108 using 1/(1 − ) ' (1 + )(1 + 2 ). 1). The idea is to interpolate between α and β with a parameter y/104 . h y i hyi h y i 3 7 0 3 + 103 − β+ α − 1750 (1) 10 B a < 10 x + 10 2 10 10 hyi 3 h y i 109 h y i 109 1 1 3 3 < 10 x + + 10 − + + + − 1750 10 2 10 x 2 10 x+1 2 (2) h y i 3 1012 h y i 109 < 103 x + + − − 1250 (3) 10 2 x 10 x(x + 1) 605 . this is small enough.1. #2. We have proven that the algorithm will give us a precise enough answer.We recognize a quadratic polynomial in [y/10] with a negative leading coefficient. the lower bound. and checking its sign. { hasserti \assert:n { #1 = 0000 } 606 . #7. \__fp_fixed_mul:wwn #8. the minimum is reached for one of the extreme values y = 0 or y = 9999. 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 \cs_new:Npn \__fp_fixed_dtf_approx:n #1 { \exp_after:wN \__fp_fixed_dtf_approx:wnn \int_use:N \__int_eval:w 10 0000 0000 / ( #1 + \c_one ) . the upper bound that we derived tells us that a < 108 /B ≤ 109 . we want to find the minimum of this quadratic polynomial. The same computation as (1) imply h y i 1 1012 h y i 109 − − 2250 − 107 B 0 a > 103 x + 10 2 x 10 x(x + 1) This time. {#2}{#3} } \cs_new:Npn \__fp_fixed_dtf_approx:NNNNNw 1#1#2#3#4#5#6. Hence. \__fp_fixed_dtf_epsilon:wN \__fp_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} . and we easily check the bound for those values. #7. #8. 107 B 0 a < 1015 x(x + 1) x+ 1 3 −3 + 10 − 6.5) 2 4 4 Now. \__fp_fixed_to_float:wN ? } \cs_new:Npn \__fp_fixed_dtf_epsilon:wN #1#2#3#4#5#6. Since the leading coefficient is still negative. \__fp_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} .5·10−3 )2 −10−3 x+1. which we do by simplifying the difference. { + \c_four % because of the line below "dtf_epsilon" here. 2 1 3 1 x(x+1)− x + + 10−3 − 6. and even add 109 to it to ease grabbing of all the digits.1750 + #1000 + (10 0000 0000/#2-#1) * (1000-#3/10) . #2#3 { hasserti \assert:n { \tl_count:n {#1} = 6 } \exp_after:wN \__fp_fixed_dtf_approx:NNNNNw \int_use:N \__int_eval:w 10 0000 0000 . Incidentally.25 · 10−10 x(x + 1) > − (1+1.25·10−9 x(x+1)(x+0. ([y/10] + a)(b − c[y/10]) ≤ (b + ca)2 /(4c). {#1} } \cs_new:Npn \__fp_fixed_dtf_approx:wnn #1.25 · 10−10 x(x + 1) 2 4 2 We want to prove that the squared expression is less than x(x + 1). hence we can compute a safely as a TEX integer. hence t= = (1 + )(1 + 2 )(1 + 4 ) .05 < ≤ 0. we find a small integer 5 ≤ c < 50 such that 0.045.) 12496 h/initex | packagei l3fp-expo implementation 35 12497 h*initex | packagei 12498 h@@=fpi 35. The last term is computed using the following Talor series of ln near 1: ac 1+t 1 1 1 1 2 2 2 2 ln = ln = 2t 1 + t +t +t +t + ··· 5 1−t 3 5 7 9 where t = 1 − 10/(ac + 5). 1− is not too difficult to compute.1. #7.91 ≤ ac/5 < 1. 607 .1 Logarithm 35. and use the relation ln(a · 10b ) = b · ln(10) − ln(c/5) + ln(ac/5). {0000} {#2#3#4#5} {#6} #7 .1. . 1). . Or is the code not in sync with the section? We are given a positive normal number. we filter out special cases in \__fp_ln_o:w. Then \__fp_ln_npos_o:w receives a positive normal number. } (End definition for \__fp_fixed_inv_to_float:wN and \__fp_fixed_div_to_float:ww. .#3#4 + \exp_after:wN \__fp_fixed_dtf_epsilon_pack:NNNNNw \int_use:N \__int_eval:w 2 0000 0000 .12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 hasserti \assert:n { #2 = 9999 } \exp_after:wN \__fp_fixed_dtf_epsilon:NNNNNww \int_use:N \__int_eval:w 1 9999 9998 . } \cs_new:Npn \__fp_fixed_dtf_epsilon_pack:NNNNNw #1#2#3#4#5#6.#5#6 . The logarithms ln(10) and ln(c/5) are looked up in a table. To compute its logarithm. \__fp_fixed_add_one:wN \__fp_fixed_mul:wwn {10000} {#2#3#4#5} {#6} #7 . of the form a · 10b with a ∈ [0. { #1 .1. { \__fp_fixed_mul:wwn %^^A todo: optimize to use \__fp_mul_significand.1. {#2#3#4#5} {#6} } \cs_new:Npn \__fp_fixed_dtf_epsilon:NNNNNww #1#2#3#4#5#6. We can now see one reason for the choice of ac ∼ 5: then ac + 5 = 10(1 − ) with −0. The rest of this section is actually not in sync with the code.1 Work plan As for many other functions. {0000} {#2#3#4#5} {#6} #7 . {0000} . which we write in the form a · 10b with a ∈ [0. 1). exponent. In all other cases. Positive normal numbers call \__fp_ln_npos_o:w.4 \__fp_ln_npos_o:w Absolute ln We catch the case of a significand very close to 0. The logarithm of +∞ or a nan is itself. It turns out that we don’t need the value of ln(5).5 · 10−20 is acceptable. 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 \cs_new:Npn \__fp_ln_o:w \s__fp \__fp_chk:w #1 #2 { \if_meaning:w 2 #2 \__fp_case_use:nw { \__fp_invalid_operation_o:nw { ln } } \fi: \if_case:w #1 \exp_stop_f: \__fp_case_use:nw { \__fp_division_by_zero_o:Nnw \c_minus_inf_fp { ln } } \or: \else: \__fp_case_return_same_o:w \fi: \__fp_ln_npos_o:w \s__fp \__fp_chk:w #1#2 } (End definition for \__fp_ln_o:w. raising a division by zero exception. Those are needed in the implementation.1.3 \__fp_ln_o:w Sign. and special numbers The logarithm of negative numbers (including −∞ and −0) raises the “invalid” exception. 12522 12523 12524 12525 12526 12527 12528 12529 12530 \cs_new:Npn \__fp_ln_npos_o:w \s__fp \__fp_chk:w 10#1#2#3. and then an error of 0. 12499 12500 12501 12502 12503 12504 12505 12506 12507 \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \tl_const:Nn \c__fp_ln_i_fixed_tl { {0000}{0000}{0000}{0000}{0000}{0000} \c__fp_ln_ii_fixed_tl { {6931}{4718}{0559}{9453}{0941}{7232} \c__fp_ln_iii_fixed_tl {{10986}{1228}{8668}{1096}{9139}{5245} \c__fp_ln_iv_fixed_tl {{13862}{9436}{1119}{8906}{1883}{4464} \c__fp_ln_vi_fixed_tl {{17917}{5946}{9228}{0550}{0081}{2477} \c__fp_ln_vii_fixed_tl {{19459}{1014}{9055}{3133}{0510}{5353} \c__fp_ln_viii_fixed_tl{{20794}{4154}{1679}{8359}{2825}{1696} \c__fp_ln_ix_fixed_tl {{21972}{2457}{7336}{2193}{8279}{0490} \c__fp_ln_x_fixed_tl {{23025}{8509}{2994}{0456}{8401}{7991} } } } } } } } } } (End definition for \c__fp_ln_i_fixed_tl and others.2 \c__fp_ln_i_fixed_tl \c__fp_ln_ii_fixed_tl \c__fp_ln_iii_fixed_tl \c__fp_ln_iv_fixed_tl \c__fp_ln_vi_fixed_tl \c__fp_ln_vii_fixed_tl \c__fp_ln_viii_fixed_tl \c__fp_ln_ix_fixed_tl \c__fp_ln_x_fixed_tl Some constants A few values of the logarithm as extended fixed point numbers.1 or to 1. not "underflow" \exp_after:wN \__fp_sanitize:Nw \__int_value:w % for the overall sign \if_int_compare:w #1 < \c_one 2 \else: 0 \fi: 608 .1. the final result is at least 10−4 .1.) 35. The logarithm of +0 is −∞. { %^^A todo: ln(1) should be "exact zero".) 35.35. It is chosen such that 0. 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 \cs_new:Npn \__fp_ln_x_ii:wnnnn #1. { #1 #2 #3 #4 } } (End definition for \__fp_ln_significand:NNNNnnnN. #2#3#4#5 { \exp_after:wN \__fp_ln_div_after:Nw \cs:w c__fp_ln_ \tex_romannumeral:D #1 _fixed_tl \exp_after:wN \cs_end: \__int_value:w \exp_after:wN \__fp_ln_x_iv:wnnnnnnnn \int_use:N \__int_eval:w \exp_after:wN \__fp_ln_x_iii_var:NNNNNw \int_use:N \__int_eval:w 9999 9999 + #1*#2#3 + \exp_after:wN \__fp_ln_x_iii:NNNNNw \int_use:N \__int_eval:w 1 0000 0000 + #1*#4#5 . {20000} {0000} {0000} {0000} 609 .4 in all cases. where Y = − ln(X) as an extended fixed point.\exp_after:wN \exp_stop_f: \int_use:N \__int_eval:w % for the exponent \__fp_ln_significand:NNNNnnnN #2#3 \__fp_ln_exponent:wn {#1} 12531 12532 12533 12534 12535 } (End definition for \__fp_ln_npos_o:w. Compute 1 + x = 1 + ac ∈ [1.7 ≤ ac < 1.#2 \else: 6 \fi: \or: 4 \or: 3 \or: 2 \or: 2 \or: 2 \else: 1 \fi: .) \__fp_ln_significand:NNNNnnnN hX1 i {hX2 i} {hX3 i} {hX4 i} hcontinuationi This function expands to \__fp_ln_significand:NNNNnnnN hcontinuationi {hY1 i} {hY2 i} {hY3 i} {hY4 i} {hY5 i} {hY6 i} . 2.4). 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 \cs_new:Npn \__fp_ln_significand:NNNNnnnN #1#2#3#4 { \exp_after:wN \__fp_ln_x_ii:wnnnn \__int_value:w \if_case:w #1 \exp_stop_f: \or: \if_int_compare:w #2 < \c_four \__int_eval:w \c_ten .) \__fp_ln_x_ii:wnnnn We have thus found c.7. 8 · 104 y C 104 D ≤ 108 + 1.6y ≤ 6. {#1#2#3#4#5} {#6} } The Taylor series will be expressed in terms of t = (x−1)/(x+1) = 1−2/(x+1). 2. y 2 (The 1/2 comes from how eTEX rounds. Q1 is an underestimate. Exactly as we did for division. we considered the case where both A and Z are arbitrary. C.12568 12569 12570 12571 12572 12573 12574 } %^^A todo: reoptimize (a generalization attempt failed).6y ≤ 6. Let us thus define y = 104 · Z + 1 ∈ (1. we want to compute A/Z with A = 2 and Z = x + 1. because our reason to work with higher powers has gone: we needed the integer y ' 105 · Z to be at least 104 . \cs_new:Npn \__fp_ln_x_iii:NNNNNw #1 #2#3#4#5 #6. to ensure that no overflow occured during the computation of the next quotient.7 · 104 ≤ y ≤ 2.4 · 104 . in the range [0.3 · 104 y D 104 E ≤ 108 + 1. { #1. We now compute the quotient with extended precision.4 · 104 ]. and convexity. i. reusing some code from \__fp_/_o:ww. and this limit was never far. and using 1. etc. Then 3 A 3 3 104 Z A1 A2 4 4 10 B ≤ A1 A2 . and $ % 108 · A 1 Q1 = − . The main source of risk was our choice to define the quotient as roughly 109 · A/105 · Z: then A was bound to be below 2.A3 A4 − − 10 Z ≤ A1 A2 1 − + 1 + y ≤ 108 + 1 + y y 2 y 2 y 2 In the same way. { #1#2#3#4#5 + \c_one .e. we set B = 104 A − Q1 Z. and we had to monitor the growth of the sequence of remainders A.6y ≤ 5. it is easy to see that Q1 ≤ 104 A/Z. and now.6y ≤ 4.5 · 104 y 4 8E 10 F ≤ 10 + 1. we can simply work with 108 · A and 104 · Z.147 · · · . B. {#2#3#4#5} {#6} } \cs_new:Npn \__fp_ln_x_iii_var:NNNNNw #1 #2#3#4#5 #6.6 · 104 y 610 .7 · 104 y B 104 C ≤ 108 + 1. 1). In l3fp-basics.7 · 104 . To reuse notations from l3fp-basics.1.6y ≤ 6.) As for division.. the definition y ' 104 · Z suffices. In our case. Note that 1 + x is known exactly. we get 104 A = 2 · 104 A 104 B ≤ 108 + 1. % Q2 #2 #3 . #2. hcontinuationi 18 Bruno: to be completed.#3#4#5 #6#7#8#9 %y. and thus corresponds to an error of 10−23 on the final result. add a mention that the error on Q6 is bounded by 10 (probably 6. Compute y by adding 1 to the five first digits. but just a faithful rounding). 19 Bruno: 611 .18 \__fp_ln_x_iv:wnnnnnnnn h1 or 2 i h8di . % Q6 } We now have essentially19 \__fp_ln_div_after:Nw hfixed tli \__fp_div_significand_pack:NNN 106 + Q1 \__fp_div_significand_pack:NNN 106 +Q2 \__fp_div_significand_pack:NNN 106 + Q3 \__fp_div_significand_pack:NNN 106 + Q4 \__fp_div_significand_pack:NNN 106 + Q5 \__fp_div_significand_pack:NNN 106 + Q6 .F2F3F4x1x2x3x4 { \exp_after:wN \__fp_div_significand_pack:NNN \int_use:N \__int_eval:w 1000000 + #2 #3 / #1 . B1. small enough in all cases. #6 #7 . the ending is much simpler.#3 % y. as we don’t need an exact rounding for transcendental functions.B2 <. #2. we need to know it with more accuracy (on the other hand.Note that we compute more steps than for division: since t is not the end result. 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 12586 12587 12588 12589 12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 \cs_new:Npn \__fp_ln_x_iv:wnnnnnnnn #1. } \cs_new:Npn \__fp_ln_div_vi:wwn #1. % Q1 } \cs_new:Npn \__fp_ln_div_ii:wwn #1. { \exp_after:wN \__fp_div_significand_calc:wwnnnnnnn \int_use:N \__int_eval:w 999999 + 2 0000 0000 / #1 . {#8} {#9} {#2} {#3} {#4} {#5} { \exp_after:wN \__fp_ln_div_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_ln_div_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_ln_div_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_ln_div_ii:wwn \__int_value:w #1 } { \exp_after:wN \__fp_ln_div_vi:wwn \__int_value:w #1 } } \cs_new:Npn \__fp_ln_div_i:w #1. hexponenti . {h4di} {h4di} hfixed-tli The number is x.F1. #2#3#4#5 #6#7#8#9 { \exp_after:wN \__fp_div_significand_pack:NNN \int_use:N \__int_eval:w \__fp_ln_div_i:w #1 .for k=1 { \exp_after:wN \__fp_div_significand_pack:NNN \int_use:N \__int_eval:w \exp_after:wN \__fp_div_significand_calc:wwnnnnnnn \int_use:N \__int_eval:w 999999 + #2 #3 / #1 .7). #2 \exp_after:wN .1765. We then compute 1 − 2/(x + 1). we know that the first two digits are 1 and 0 because of bounds on the final result of the division 2/(x + 1). ht6 i. ht3 i. #8. and hexponenti is the exponent. ht4 i. #3. #6. #4. Then \__fp_div_significand_pack:NNN puts things in the correct order to add the Qi together and put semicolons between each piece. However. 10]. \int_use:N \__int_eval:w 9999 . } \__fp_ln_t_large:NNw hsignihfixed tli ht1 i.#4 \exp_after:wN . \int_use:N \__int_eval:w 9999 . { \if_meaning:w 0 #2 \exp_after:wN \__fp_ln_t_small:Nw \else: \exp_after:wN \__fp_ln_t_large:NNw \exp_after:wN \fi: #1 } \cs_new:Npn \__fp_ln_t_small:Nw #1 #2. hexponenti . h4di .where hfixed tli holds the logarithm of a number in [1. hexponenti . 12628 12629 12630 12631 12632 12633 12634 12635 12636 \cs_new:Npn \__fp_ln_t_large:NNw #1 #2 #3. #5. so every piece has at most 4 digits. they can have less than 4 digits. h4di . hcontinuationi Compute the square t2 .#7 . since we were not careful in \__fp_ln_t_small:w. h4di . ht5 i .2. #7.#6 \exp_after:wN . after testing whether 2/(x + 1) is greater than or smaller than 1. Once those have been expanded.8 and 1. which is between roughly 0. #4.#5 \exp_after:wN . We know that t < 0.#3 \exp_after:wN . #7. \int_use:N \__int_eval:w 9999 . 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617 12618 12619 12620 12621 12622 12623 12624 12625 12626 12627 \cs_new:Npn \__fp_ln_div_after:Nw #1#2. { \exp_after:wN \__fp_ln_t_large:NNw \exp_after:wN + % <sign> \exp_after:wN #1 \int_use:N \__int_eval:w 9999 . Just as with division. the expansion is done backwards. \int_use:N \__int_eval:w 9999 . h4di . we get \__fp_ln_div_after:Nw hfixed-tli h1di . \int_use:N \__int_eval:w 1 0000 . #6. Also. h4di . h4di . ht2 i . { \exp_after:wN \__fp_ln_square_t_after:w \int_use:N \__int_eval:w 9999 0000 + #3*#3 \exp_after:wN \__fp_ln_square_t_pack:NNNNNw \int_use:N \__int_eval:w 9999 0000 + 2*#3*#4 \exp_after:wN \__fp_ln_square_t_pack:NNNNNw \int_use:N \__int_eval:w 9999 0000 + 2*#3*#5 + #4*#4 \exp_after:wN \__fp_ln_square_t_pack:NNNNNw 612 . and keep t at the end with its sign. #5. 2. { \__fp_ln_c:NwNn hsigni } hfixed tli hexponenti . 613 . C.} \loop 3. 1. { + #1 . A. 20 20 Bruno: add explanations. we get \__fp_ln_Taylor:wwNw {hT1 i} {hT2 i} {hT3 i} {hT4 i} {hT5 i} {hT6 i} . {#1} } \cs_new:Npn \__fp_ln_square_t_pack:NNNNNw #1 #2#3#4#5 #6.. \add A. . {\loop \eval 5-2. A. . {h(2t)1 i} {h(2t)2 i} {h(2t)3 i} {h(2t)4 i} {h(2t)5 i} {h(2t)6 i} .\int_use:N \__int_eval:w 9999 0000 + 2*#3*#6 + 2*#4*#5 \exp_after:wN \__fp_ln_square_t_pack:NNNNNw \int_use:N \__int_eval:w 1 0000 0000 + 2*#3*#7 + 2*#4*#6 + #5*#5 + (2*#3*#8 + 2*#4*#7 + 2*#5*#6) / 1 0000 % . . \mul T. { + #1#2#3#4#5 . {\loop 3.0. { .} \mul B.} \add 0. {#6} } \cs_new:Npn \__fp_ln_square_t_after:w 1 0 #1#2#3 #4. \mul T.) \__fp_ln_Taylor:wwNw Denoting T = t2 .. T. \div_int 5. \exp_after:wN \__fp_ln_twice_t_after:w \int_use:N \__int_eval:w -1 + 2*#3 \exp_after:wN \__fp_ln_twice_t_pack:Nw \int_use:N \__int_eval:w 9999 + 2*#4 \exp_after:wN \__fp_ln_twice_t_pack:Nw \int_use:N \__int_eval:w 9999 + 2*#5 \exp_after:wN \__fp_ln_twice_t_pack:Nw \int_use:N \__int_eval:w 9999 + 2*#6 \exp_after:wN \__fp_ln_twice_t_pack:Nw \int_use:N \__int_eval:w 9999 + 2*#7 \exp_after:wN \__fp_ln_twice_t_pack:Nw \int_use:N \__int_eval:w 10000 + 2*#8 . . { \__fp_ln_Taylor:wwNw {0#1#2#3} {#4} } (End definition for \__fp_ln_x_ii:wnnnn. hcontinuationi And we want to compute 1+t 1 1 1 1 ln +T +T +T + ··· = 2t 1 + T 1−t 3 5 7 9 The process looks as follows \loop 5. {#2} } \cs_new:Npn \__fp_ln_twice_t_after:w #1. {\loop \eval 5-2. { \__fp_ln_c:NwNw #1 } #2 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 } \cs_new:Npn \__fp_ln_twice_t_pack:Nw #1 #2. } (End definition for \__fp_ln_Taylor:wwNw. For now. then we get b ln(10) and add or subtract. 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684 \cs_new:Npn \__fp_ln_Taylor:wwNw { \__fp_ln_Taylor_loop:www 21 .21 12685 12686 12687 12688 12689 12690 12691 12692 12693 \cs_new:Npn \__fp_ln_c:NwNw #1 #2. {hexponenti} 21 Bruno: 22 Bruno: that was wrong at some point. { \if_int_compare:w #1 = \c_one \__fp_ln_Taylor_break:w \fi: \exp_after:wN \__fp_fixed_div_int:wwN \c__fp_one_fixed_tl . } #3. \__fp_fixed_add:wwn #2. #2 . \__fp_fixed_mul:wwn #3. } 22 (End definition for \__fp_ln_c:NwNw. since the final result will be at least ln(10/7) ' 0. I must check. this must be updated with correct values! 614 .35. hfixed tli hexponenti . {0000}{0000}{0000}{0000}{0000}{0000} .\c_two .) \__fp_ln_c:NwNw \__fp_ln_c:NwNw hsigni {hr1 i} {hr2 i} {hr3 i} {hr4 i} {hr5 i} {hr6 i} . { \fi: \exp_after:wN \__fp_fixed_mul:wwn \exp_after:wN { \int_use:N \__int_eval:w 10000 + #2 } #3. #3. } \cs_new:Npn \__fp_ln_Taylor_break:w \fi: #1 \__fp_fixed_add:wwn #2#3. ln(x) is given as ·100 . and adding it to the mixture. The first step is to get ln(c) − ln(x) = − ln(a). #2. Unless both the exponent is 1 and c = 1. #1.This uses the routine for dividing a number by a small integer ( < 104 ). #3 { \if_meaning:w + #1 \exp_after:wN \exp_after:wN \exp_after:wN \__fp_fixed_sub:wwn \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_fixed_add:wwn \fi: #3 . hcontinuationi We are now reduced to finding ln(c) and hexponenti ln(10) in a table. This function is documented on page ??.) \__fp_ln_exponent:wn \__fp_ln_exponent:wn {hs1 i} {hs2 i} {hs3 i} {hs4 i} {hs5 i} {hs6 i} . we shift to working in units of ·104 . } \cs_new:Npn \__fp_ln_Taylor_loop:www #1. #4 . { \exp_after:wN \__fp_ln_Taylor_loop:www \int_use:N \__int_eval:w #1 . This function is documented on page ??.. 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710 12711 12712 \cs_new:Npn \__fp_ln_exponent:wn #1. {#3}{0000}{0000}{0000}{0000}{0000} . 12713 12714 12715 12716 12717 12718 \cs_new:Npn \__fp_ln_exponent_one:ww 1. and set the exponent of the log to 4 (minus any shift coming from leading zeros in the conversion from fixed point to floating point). { \c_four \exp_after:wN \__fp_fixed_mul:wwn \c__fp_ln_x_fixed_tl . #1.Compute hexponenti times ln(10). \__fp_fixed_to_float:wN 0 } For small exponents. #4#5#6#7#8#9. \__fp_fixed_to_float:wN #1 23 Bruno: do rounding.3 in magnitude. except when computing ln(1). we already have addition and subtraction for 24 digits fixed point numbers. } Now we painfully write all the cases. we just drop one block of digits. Besides.23 No overflow nor underflow can happen. In the case of a very large (positive or negative) exponent. #1. 12719 12720 12721 12722 12723 12724 12725 12726 12727 \cs_new:Npn \__fp_ln_exponent_small:NNww #1#2#3. { \c_zero \exp_after:wN \__fp_fixed_sub:wwn \c__fp_ln_x_fixed_tl . but that would be slightly too tight for rounding to happen correctly. 615 . Apart from the cases where hexponenti is 0 or 1. the result will necessarily be at least ln(10) ' 2. since the result is of order 104 . one would think that in both cases we can drop 4 more digits than we do. #1. Naively. #2 {0000}{#4}{#5}{#6}{#7}{#8}. Note that here the exponent has been made positive. we can (and we need to) drop 4 additional digits. We can thus drop the least significant 4 digits. #2 { \if_case:w #2 \exp_stop_f: \c_zero \__fp_case_return:nw { \__fp_fixed_to_float:Nw 2 } \or: \exp_after:wN \__fp_ln_exponent_one:ww \__int_value:w \else: \if_int_compare:w #2 > \c_zero \exp_after:wN \__fp_ln_exponent_small:NNww \exp_after:wN 0 \exp_after:wN \__fp_fixed_sub:wwn \__int_value:w \else: \exp_after:wN \__fp_ln_exponent_small:NNww \exp_after:wN 2 \exp_after:wN \__fp_fixed_add:wwn \__int_value:w \fi: \fi: #2. } 12728 (End definition for \__fp_ln_exponent:wn.1 Exponential Sign.2 35.\__fp_fixed_inv_to_float:wN \fi: } \cs_new:Npn \__fp_exp_pos:NNwnw #1#2#3 \fi: #4#5.\c_eight \c_one \exp_after:wN \__fp_add_big_i_o:wNww \int_use:N \__int_eval:w \c_one .) 35. exponent.#4 . { \fi: \exp_after:wN \__fp_sanitize:Nw \exp_after:wN 0 \__int_value:w #1 \__int_eval:w \if_int_compare:w #4 < . and special numbers \__fp_exp_o:w 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 \cs_new:Npn \__fp_exp_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_case_return_o:Nw \c_one_fp \or: \exp_after:wN \__fp_exp_normal:w \or: \if_meaning:w 0 #2 \exp_after:wN \__fp_case_return_o:Nw \exp_after:wN \c_inf_fp \else: \exp_after:wN \__fp_case_return_o:Nw \exp_after:wN \c_zero_fp \fi: \or: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } (End definition for \__fp_exp_o:w.2. This function is documented on page ??. 0 {1000}{0000}{0000}{0000} . 616 . #5.) \__fp_exp_normal:w \__fp_exp_pos:Nnwnw 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765 12766 \cs_new:Npn \__fp_exp_normal:w \s__fp \__fp_chk:w 1#1 { \if_meaning:w 0 #1 \__fp_exp_pos:NNwnw + \__fp_fixed_to_float:wN \else: \__fp_exp_pos:NNwnw . #2.#4 } \__fp_exp_Taylor:Nnnwn } { \__fp_decimate:nNnnnn { \c_sixteen . delimited by a semicolon. form a fixed point number. The next three arguments. #2. #1 . 12797 12798 12799 12800 12801 12802 12803 12804 12805 12806 12807 12808 12809 \cs_new:Npn \__fp_exp_Taylor:Nnnwn #1#2#3 #4. #5 #6 { #6 \__fp_pack_twice_four:wNNNNNNNN \__fp_pack_twice_four:wNNNNNNNN \__fp_pack_twice_four:wNNNNNNNN \__fp_exp_Taylor_ii:ww .12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782 12783 12784 12785 12786 12787 12788 12789 12790 12791 12792 12793 12794 12795 12796 \tex_romannumeral:D \else: \if_int_compare:w #4 > \c_five % cf \c__fp_max_exponent_int \exp_after:wN \__fp_exp_overflow: \tex_romannumeral:D \else: \if_int_compare:w #4 < \c_zero \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { \c_zero \__fp_decimate:nNnnnn { . Our only task is to compute the Taylor series. { 617 . { \__fp_exp_Taylor_loop:www 10 . \s__stop } \cs_new:Npn \__fp_exp_Taylor_loop:www #1. 10−1 ). at least 16 digits. } \cs_new:Npn \__fp_exp_Taylor_ii:ww #1. #2#3#4 0000 0000 . so we pack it in blocks of 4 digits. } (End definition for \__fp_exp_normal:w and \__fp_exp_pos:Nnwnw. #1 . #3. The first argument is irrelevant (rounding digit used by some other functions).) \__fp_exp_Taylor:Nnnwn \__fp_exp_Taylor_loop:www \__fp_exp_Taylor_break:Nww This function is called for numbers in the range [10−9 .#4 } \__fp_exp_pos_large:NnnNwn } #5 {#4} #1 #2 0 \tex_romannumeral:D \fi: \fi: \exp_after:wN \c_zero } \cs_new:Npn \__fp_exp_overflow: { + \c_two * \c__fp_max_exponent_int . {1000} {0000} {0000} {0000} . and finally the exponent. The current total is expressed by leaving the exponent behind in the input stream (we are currently within an \__int_eval:w). and keeping track of a fixed point number. } (End definition for \__fp_exp_Taylor:Nnnwn.12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 \if_int_compare:w #1 = \c_one \exp_after:wN \__fp_exp_Taylor_break:Nww \fi: \__fp_fixed_div_int:wwN #3 . Remove leading zeros from the integer part: putting #4 in there too ensures that an integer part of 0 is also removed. and a brace group with 8 zeros). #3 \s__stop { \__fp_fixed_add_one:wN #2 . This function is documented on page ??. 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 \cs_new:Npn \__fp_exp_pos_large:NnnNwn #1#2#3 #4#5. #2 . The third argument is the integer part of our number. The loop is done by having the auxiliary for one exponent call the auxiliary for the next exponent. Our usage of \if_case:w is somewhat dirty for optimization: TEX jumps to the appropriate case. but we then close the \if_case:w “by hand”. 5]. and multiplying that to the current total.) \__fp_exp_pos_large:NnnNwn \__fp_exp_large_after:wwn \__fp_exp_large:w \__fp_exp_large_v:wN \__fp_exp_large_iv:wN \__fp_exp_large_iii:wN \__fp_exp_large_ii:wN \__fp_exp_large_i:wN \__fp_exp_large_:wN The first two arguments are irrelevant (a rounding digit. #6 { \exp_after:wN \exp_after:wN \cs:w __fp_exp_large_\tex_romannumeral:D #6:wN \exp_after:wN \cs_end: \exp_after:wN \c__fp_one_fixed_tl \exp_after:wN . #1 . } \cs_new:Npn \__fp_exp_large_v:wN #1. \__int_value:w #3 #4 \exp_stop_f: #5 00000 . then we have the decimal part delimited by a semicolon. #1 for the numbered auxiliaries. { \exp_after:wN \__fp_exp_Taylor_loop:www \int_use:N \__int_eval:w #1 . } } \cs_new:Npn \__fp_exp_Taylor_break:Nww #1 #2. using \or: and \fi: as delimiters. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn \or: + 4343 \__fp_exp_large:w {8806}{8182}{2566}{2921}{5872}{6150} \or: + 8686 \__fp_exp_large:w {7756}{0047}{2598}{6861}{0458}{3204} \or: + 13029 \__fp_exp_large:w {6830}{5723}{7791}{4884}{1932}{7351} \or: + 17372 \__fp_exp_large:w {6015}{5609}{3095}{3052}{3494}{7574} \or: + 21715 \__fp_exp_large:w {5297}{7951}{6443}{0315}{3251}{3576} \or: + 26058 \__fp_exp_large:w {4665}{6719}{0099}{3379}{5527}{2929} \or: + 30401 \__fp_exp_large:w {4108}{9724}{3326}{3186}{5271}{5665} \or: + 34744 \__fp_exp_large:w {3618}{6973}{3140}{0875}{3856}{4102} \or: 618 .1 . \__fp_fixed_add_one:wN \__fp_fixed_mul:wwn #2 . } \cs_new:Npn \__fp_exp_large:w #1 \or: #2 \fi: { \fi: \__fp_fixed_mul:wwn #1. Then read digits one by one. in the range [0. looking up exp(hdigiti·10hexponenti ) in a table. \__fp_exp_large_iv:wN } \cs_new:Npn \__fp_exp_large_iv:wN #1. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn \or: + 435 \__fp_exp_large:w {1970}{0711}{1401}{7046}{9938}{8888} \or: + 869 \__fp_exp_large:w {3881}{1801}{9428}{4368}{5764}{8232} \or: + 1303 \__fp_exp_large:w {7646}{2009}{8905}{4704}{8893}{1073} \or: + 1738 \__fp_exp_large:w {1506}{3559}{7005}{0524}{9009}{7592} \or: + 2172 \__fp_exp_large:w {2967}{6283}{8402}{3667}{0689}{6630} \or: + 2606 \__fp_exp_large:w {5846}{4389}{5650}{2114}{7278}{5046} \or: + 3041 \__fp_exp_large:w {1151}{7900}{5080}{6878}{2914}{4154} \or: + 3475 \__fp_exp_large:w {2269}{1083}{0850}{6857}{8724}{4002} \or: + 3909 \__fp_exp_large:w {4470}{3047}{3316}{5442}{6408}{6591} \or: \fi: #1. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn \or: + 5 \__fp_exp_large:w {2202}{6465}{7948}{0671}{6516}{9579} \or: + 9 \__fp_exp_large:w {4851}{6519}{5409}{7902}{7796}{9107} \or: + 14 \__fp_exp_large:w {1068}{6474}{5815}{2446}{2146}{9905} \or: + 18 \__fp_exp_large:w {2353}{8526}{6837}{0199}{8540}{7900} \or: + 22 \__fp_exp_large:w {5184}{7055}{2858}{7072}{4640}{8745} \or: + 27 \__fp_exp_large:w {1142}{0073}{8981}{5684}{2836}{6296} \or: + 31 \__fp_exp_large:w {2515}{4386}{7091}{9167}{0062}{6578} \or: + 35 \__fp_exp_large:w {5540}{6223}{8439}{3510}{0525}{7117} \or: + 40 \__fp_exp_large:w {1220}{4032}{9431}{7840}{8020}{0271} \or: \fi: 619 . \__fp_exp_large_ii:wN } \cs_new:Npn \__fp_exp_large_ii:wN #1.12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 + 39087 \__fp_exp_large:w {3186}{9209}{6113}{3900}{6705}{9685} \or: \fi: #1. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn \or: + 44 \__fp_exp_large:w {2688}{1171}{4181}{6135}{4484}{1263} \or: + 87 \__fp_exp_large:w {7225}{9737}{6812}{5749}{2581}{7748} \or: + 131 \__fp_exp_large:w {1942}{4263}{9524}{1255}{9365}{8421} \or: + 174 \__fp_exp_large:w {5221}{4696}{8976}{4143}{9505}{8876} \or: + 218 \__fp_exp_large:w {1403}{5922}{1785}{2837}{4107}{3977} \or: + 261 \__fp_exp_large:w {3773}{0203}{0092}{9939}{8234}{0143} \or: + 305 \__fp_exp_large:w {1014}{2320}{5473}{5004}{5094}{5533} \or: + 348 \__fp_exp_large:w {2726}{3745}{7211}{2566}{5673}{6478} \or: + 391 \__fp_exp_large:w {7328}{8142}{2230}{7421}{7051}{8866} \or: \fi: #1. \__fp_exp_large_iii:wN } \cs_new:Npn \__fp_exp_large_iii:wN #1. ) 35. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn + 1 \__fp_exp_large:w {1105}{1709}{1807}{5647}{6248}{1171} + 1 \__fp_exp_large:w {1221}{4027}{5816}{0169}{8339}{2107} + 1 \__fp_exp_large:w {1349}{8588}{0757}{6003}{1039}{8374} + 1 \__fp_exp_large:w {1491}{8246}{9764}{1270}{3178}{2485} + 1 \__fp_exp_large:w {1648}{7212}{7070}{0128}{1468}{4865} + 1 \__fp_exp_large:w {1822}{1188}{0039}{0508}{9748}{7537} + 1 \__fp_exp_large:w {2013}{7527}{0747}{0476}{5216}{2455} + 1 \__fp_exp_large:w {2225}{5409}{2849}{2467}{6045}{7954} + 1 \__fp_exp_large:w {2459}{6031}{1115}{6949}{6638}{0013} \fi: #1. \__fp_exp_large_after:wwn } \cs_new:Npn \__fp_exp_large_after:wwn #1. \__fp_exp_large_i:wN 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 } \cs_new:Npn \__fp_exp_large_i:wN #1. #2. #2 { \if_case:w #2 ~ \exp_after:wN \__fp_fixed_continue:wn + 1 \__fp_exp_large:w {2718}{2818}{2845}{9045}{2353}{6029} + 1 \__fp_exp_large:w {7389}{0560}{9893}{0650}{2272}{3043} + 2 \__fp_exp_large:w {2008}{5536}{9231}{8766}{7740}{9285} + 2 \__fp_exp_large:w {5459}{8150}{0331}{4423}{9078}{1103} + 3 \__fp_exp_large:w {1484}{1315}{9102}{5766}{0342}{1116} + 3 \__fp_exp_large:w {4034}{2879}{3492}{7351}{2260}{8387} + 4 \__fp_exp_large:w {1096}{6331}{5842}{8458}{5992}{6372} + 4 \__fp_exp_large:w {2980}{9579}{8704}{1728}{2747}{4359} + 4 \__fp_exp_large:w {8103}{0839}{2757}{5384}{0077}{1000} \fi: #1. } (End definition for \__fp_exp_pos_large:NnnNwn and others. 620 \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: \or: .3 Power Raising a number a to a power b leads to many distinct situations.#1. {} #3 \__fp_fixed_mul:wwn #1. \__fp_exp_large_:wN } \cs_new:Npn \__fp_exp_large_:wN #1. #3 { \__fp_exp_Taylor:Nnnwn ? { } { } 0 #2. For a = +0 or + inf. • If it is positive. to return either +0 or +∞ as appropriate. • Finally. \__fp_^_o:ww We cram a most of the tests into a single function to save csnames. call \__fp_pow_zero_or_inf:ww instead. Then do some tests to find the final sign of the result if it exists. then skip to the next semicolon (which happens to be conveniently the end of b) and return nan. { \if_meaning:w 0 #4 \__fp_case_return_o:Nw \c_one_fp \fi: \if_case:w #2 \exp_stop_f: \exp_after:wN \use_i:nn \or: \__fp_case_return_o:Nw \c_nan_fp \else: \exp_after:wN \__fp_pow_neg:www \tex_romannumeral:D -‘0 \exp_after:wN \use:nn \fi: { \if_meaning:w 1 #1 \exp_after:wN \__fp_pow_normal:ww \else: 621 . and keep an extra copy of a and b (the second brace group.ab +∞ 1<x +1 0<x<1 +0 −0 −1 < −x < 0 −1 −x < −1 −∞ nan −∞ +0 +0 +1 +∞ +∞ nan nan nan +0 +0 nan −y +0 +x−y +1 +x−y +∞ nan nan nan nan +0 nan −n +0 +x−n +1 +x−n +∞ ±∞ ±x−n ±1 ±x−n ±0 nan ±0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +n +∞ +xn +1 +xn +0 ±0 ±xn ±1 ±xn ±∞ nan +y +∞ +xy +1 +xy +0 +0 nan nan nan nan nan +∞ +∞ +∞ +1 +0 +0 +0 +0 nan nan nan nan nan nan nan +1 nan nan nan nan nan nan nan nan One peculiarity of this operation is that nan0 = 1nan = 1. is inserted between a and b). even ±∞. call \__fp_pow_normal:ww followed by the two fp a and b. • If a is a nan. Then test the sign of a. First treat the case b = 0: a0 = 1 for any a. containing { b a }. 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 \cs_new:cpn { __fp_ \iow_char:N \^ _o:ww } \s__fp \__fp_chk:w #1#2#3. because this relation is obeyed for any number. \s__fp \__fp_chk:w #4#5#6. if a is negative. even nan. compute ab (\__fp_pow_normal:ww which ignores the sign of its first operand). and a is a normal number. 0 and 2. Indeed. } \s__fp \__fp_chk:w #4#5#6. either a = ±0 with b < 0 and we have a division by zero. since those conveniently take the same possible values. or a = ±∞ and b > 0 and the result is also +∞. 12954 12955 12956 } { \s__fp \__fp_chk:w #4#5#6. Thus. 622 .) \__fp_pow_normal:ww We have in front of us a. the result is 0. if the type of a and the sign of b coincide. the result is +0 if 0 is raised to a positive power or ∞ to a negative power. If |a| = 6 1. and b 6= 0. Otherwise. and +∞ otherwise. we already filtered b = ±0. \s__fp \__fp_chk:w #1#2#3. test the type of b: 0 Impossible.) \__fp_pow_zero_or_inf:ww Raising −0 or −∞ to nan yields nan. 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 \cs_new:Npn \__fp_pow_zero_or_inf:ww \s__fp \__fp_chk:w #1#2. but without any exception. \s__fp \__fp_chk:w #3#4 { \if_meaning:w 1 #4 \__fp_case_return_same_o:w \fi: \if_meaning:w #1 #4 \__fp_case_return_o:Nw \c_zero_fp \fi: \if_meaning:w 0 #1 \__fp_case_use:nw { \__fp_division_by_zero_o:NNww \c_inf_fp ^ \s__fp \__fp_chk:w #1 #2 . we return 1. 12957 12958 12959 12960 } (End definition for \__fp_^_o:ww. } \else: \__fp_case_return_o:Nw \c_inf_fp \fi: \s__fp \__fp_chk:w #3#4 } (End definition for \__fp_pow_zero_or_inf:ww.\exp_after:wN \__fp_pow_zero_or_inf:ww \fi: \s__fp \__fp_chk:w #1#2#3. 3 Return b. and we wish to compute |a|b . 2 Return +∞ or +0 depending on the sign of b and whether the exponent of a is positive or not. returning 1 at this point would wrongly raise “invalid” when the sign is considered. unless a = −1 and b is nan. we know that a is a normal number. 1 Call \__fp_pow_npos:ww. If |a| = 1. For other powers. we only need at most 21 digits.) \__fp_pow_npos:Nww We now know that a 6= ±1 is a normal number. \s__fp \__fp_chk:w #4 #5 } (End definition for \__fp_pow_normal:ww. If z is negative. negate that decimal exponent. we need to know the digits of z up to the 16-th position. 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 \cs_new:Npn \__fp_pow_npos:Nww #1 \s__fp \__fp_chk:w 1#2#3 { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN 0 \__int_value:w \if:w #1 \if_int_compare:w #3 > \c_zero 0 \else: 2 \fi: \exp_after:wN \__fp_pow_npos_aux:NNnww \exp_after:wN + \exp_after:wN \__fp_fixed_to_float:wN \else: \exp_after:wN \__fp_pow_npos_aux:NNnww \exp_after:wN - 623 . \s__fp \__fp_chk:w #4#5 { \if_int_compare:w \pdftex_strcmp:D { #2 #3 } { 1 {1000} {0000} {0000} {0000} } = \c_zero \if_int_compare:w #4 #1 = 32 \exp_stop_f: \exp_after:wN \__fp_case_return_ii_o:ww \fi: \__fp_case_return_o:Nww \c_one_fp \fi: \if_case:w #4 \exp_stop_f: \or: \exp_after:wN \__fp_pow_npos:Nww \exp_after:wN #5 \or: \if_meaning:w 2 #5 \exp_after:wN \reverse_if:N \fi: \if_int_compare:w #2 > \c_zero \exp_after:wN \__fp_case_return_o:Nww \exp_after:wN \c_inf_fp \else: \exp_after:wN \__fp_case_return_o:Nww \exp_after:wN \c_zero_fp \fi: \or: \__fp_case_return_ii_o:ww \fi: \s__fp \__fp_chk:w 1 #1 {#2} #3 . To compute the exponential accurately. and b is a normal number too. hence the fixed point result of \__fp_ln_o:w is precise enough for our needs. Start an integer expression for the decimal exponent of e|z| .12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 \cs_new:Npn \__fp_pow_normal:ww \s__fp \__fp_chk:w 1 #1#2#3. We want p to compute |a|b = (|x| · 10n )y·10 = exp((ln|x| + n ln(10)) · y · 10p ) = exp(z). and prepare to take the inverse when converting from the fixed point to the floating point result. Since the exponential of 105 is infinite. \exp_after:wN \__fp_fixed_mul_after:wn \int_use:N \__int_eval:w \c__fp_leading_shift_int \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int #1#2*23025 . 13024 13025 13026 13027 13028 13029 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 13042 13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 \cs_new:Npn \__fp_pow_npos_aux:NNnww #1#2#3#4#5. {#9} . \s__fp \__fp_chk:w 1#6#7#8.#8 ) / 1 0000 . Then comes an exponent and the 4 brace groups of x. #2 { \if_int_compare:w #2 > \c_zero \exp_after:wN \__fp_pow_exponent:Nwnnnnnwn % n\ln(10) .#1 #5 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int #1 #2*0456 . #1 #2 0 % fixed_to_float:wN } \cs_new:Npn \__fp_pow_exponent:wnN #1.) \__fp_pow_npos_aux:NNnww The first argument is the conversion function from fixed point to float.#1 #7 #1 ( #2*7991 .#1 #4 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int #1 #2*2994 . 624 . \__fp_pow_B:wwN #7. #3#4#5#6#7#8.#1 #6 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_trailing_shift_int #1 #2*8401 . } \cs_new:Npn \__fp_pow_exponent:Nwnnnnnwn #1#2. #9 { %^^A todo: use that in ln. #1. { #1 \__int_eval:w \__fp_ln_significand:NNNNnnnN #4#5 \__fp_pow_exponent:wnN {#3} \__fp_fixed_mul:wwn #8 {0000}{0000} . followed by b. Compute − ln(x).(-\ln(x)) \exp_after:wN + \else: \exp_after:wN \__fp_pow_exponent:Nwnnnnnwn % -( |n|\ln(10) + (-\ln(x)) ) \exp_after:wN \fi: #2.#1 #3 \exp_after:wN \__fp_pack:NNNNNwn \int_use:N \__int_eval:w \c__fp_middle_shift_int #1 #2*8509 .\exp_after:wN \__fp_fixed_inv_to_float:wN \fi: {#3} 13020 13021 13022 13023 } (End definition for \__fp_pow_npos:Nww. #2 { \if_meaning:w 0 #1 \exp_after:wN \__fp_pow_C_pack:w \exp_after:wN #2 \else: \if_meaning:w 0 #2 \exp_after:wN \__fp_pow_C_pos_loop:wN \__int_value:w \else: \exp_after:wN \__fp_pow_C_overflow:w \__int_value:w \fi: \__int_eval:w #1 . This is invalid. unless ab turns 625 .13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 } \cs_new:Npn \__fp_pow_B:wwN #1#2#3#4#5#6.\c_one \exp_after:wN . Otherwise. If b is an even integer (case −1).) \__fp_pow_neg:www This function is followed by three floating point numbers: ab . If b is an odd integer (case 0). ab = −ab . { \if_int_compare:w #7 < \c_zero \exp_after:wN \__fp_pow_C_neg:w \__int_value:w \else: \if_int_compare:w #7 < 22 \exp_stop_f: \exp_after:wN \__fp_pow_C_pos:w \__int_value:w \else: \exp_after:wN \__fp_pow_C_overflow:w \__int_value:w \fi: \fi: #7 \exp_after:wN . a ∈ [−∞. %^^A todo: how many 0? } \cs_new:Npn \__fp_pow_C_overflow:w #1. the sign is undefined. \fi: } \cs_new:Npn \__fp_pow_C_pack:w { \exp_after:wN \__fp_exp_large_v:wN \c__fp_one_fixed_tl . #7. #2. \int_use:N \__int_eval:w 10 0000 + #1 \__int_eval_end: #2#3#4#5#6 0000 0000 0000 0000 0000 0000 . } (End definition for \__fp_pow_npos_aux:NNnww. } \cs_new:Npn \__fp_pow_C_pos_loop:wN #1. and b. #3 { + \c_two * \c__fp_max_exponent_int \exp_after:wN \__fp_fixed_continue:wn \c__fp_one_fixed_tl . ab = ab . } \cs_new:Npn \__fp_pow_C_neg:w #1 . 1 { \__fp_pow_C_pos_loop:wN #1. 1 { \exp_after:wN \exp_after:wN \exp_after:wN \__fp_pow_C_pack:w \prg_replicate:nn {#1} {0} } \cs_new:Npn \__fp_pow_C_pos:w #1. −0]. obtained by a call to \__fp_-_o:w. \cs:w __fp_-_o:w \exp_after:wN \cs_end: \or: \if_int_compare:w \__int_eval:w #1 / \c_two = \c_one \__fp_invalid_operation_o:Nww ^ #3. } (End definition for \__fp_pow_neg:www. { \if_case:w #1 \exp_stop_f: \c_minus_one \or: \__fp_pow_neg_case_aux:nnnnn #3 \else: \c_one \fi: } \cs_new:Npn \__fp_pow_neg_case_aux:nnnnn #1#2#3#4#5 { \if_int_compare:w #1 > \c_eight \if_int_compare:w #1 > \c_sixteen \c_minus_one \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_pow_neg_case_aux:NNNNNNNNw \prg_replicate:nn { \c_sixteen .#1 } { 0 } #4#5 . 0 \__fp_pow_neg_case_aux:nnnnn if it is an odd integer.1)**(12345. the number is not an integer. 16]. #4. 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 \cs_new:Npn \__fp_pow_neg_case:w \s__fp \__fp_chk:w #1#2#3. In the former case. ±∞ and nan are non\__fp_pow_neg_case_aux:NNNNNNNNw integers.6) will give +0 rather than complaining that the sign is not defined. { \if_case:w \__fp_pow_neg_case:w #4 . and 1 if it is not an integer. which would be the digits surrounding the decimal period. We also separate the ranges of exponent [1. then the number is even. check that the last 8 digits are zero (otherwise we don’t have an integer). since the underflow detection occurs before \__fp_pow_neg:www is called. If the exponent is greater than sixteen. and “returns” −1 if it is an even integer.out to be +0 or nan. #4. \fi: 626 . consider the appropriate 8 digits. In particular. (-0. either #4#5 or #2#3.) \__fp_pow_neg_case:w This function expects a floating point number. check the parity of the hdigiti and return \c_zero or \c_minus_one. in which case we return that as ab . In both cases. #3. If the exponent is non-positive. Zeros are even. If the hdigitsi are non-zero. Otherwise. 8] and [9. The sign of normal numbers is irrelevant to parity. the number cannot be an integer. \tex_romannumeral:D -‘0 \exp_after:wN \exp_after:wN \exp_after:wN \__fp_use_none_until_s:w \fi: \fi: \__fp_exp_after_o:w \s__fp \__fp_chk:w #1#2. 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 \cs_new:Npn \__fp_pow_neg:www \s__fp \__fp_chk:w #1#2. remove the first few: we are then left with hdigiti hdigitsi . \__fp_pow_neg_case_aux:nnnnn .) 13168 h/initex | packagei 36 Implementation 13169 h*initex | packagei 13170 h@@=fpi 36. Very small numbers take a slightly different route. cotangent. ± inf and nan). shift the significand to convert them to fixed point numbers. • Keep the sign for later. (This is called argument reduction. • For numbers ≥ 1. cosecant. cosine. π/2]. tangent.) 627 .1 Direct trigonometric functions The approach for all trigonometric functions (sine.#1 } { 0 } #2#3 . and secant) is the same. { \if_int_compare:w 0 #9 = \c_zero \if_int_odd:w #8 \exp_stop_f: \c_zero \else: \c_minus_one \fi: \else: \c_one \fi: } (End definition for \__fp_pow_neg_case:w . \else: \c_one \fi: \else: \c_one \fi: \fi: 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 } \cs_new:Npn \__fp_pow_neg_case_aux:NNNNNNNNw #1#2#3#4#5#6#7#8#9. and \__fp_pow_neg_case_aux:NNNNNNNNw. • Filter out special cases (±0.\else: \if_int_compare:w #1 > \c_zero \if_int_compare:w #4#5 = \c_zero \exp_after:wN \exp_after:wN \exp_after:wN \__fp_pow_neg_case_aux:NNNNNNNNw \prg_replicate:nn { \c_eight . • For numbers less than 1. subtract a multiple of π/2 to bring them to the range to [0. and work with the absolute value x of the argument. For larger inputs.• Reduce further to [0. In this second case. 13186 13187 13188 13189 13190 13191 13192 13193 13194 13195 13196 13197 13198 \cs_new:Npn \__fp_cos_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_case_return_o:Nw \c_one_fp \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_one_o:w \__fp_sin_series:NNwww \__fp_fixed_to_float:wN 0 \c_two } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { cos } } \else: \__fp_case_return_same_o:w \fi: 628 . but using a positive sign 0 and with an initial octant of 2.) \__fp_cos_o:w The cosine of ±0 is 1. use \__fp_trig_epsilon_one_o:w which returns cos = 1. an initial octant of 0. we will use a sign #2. the sign. since sin(x) = #2 sin|x|. π/4] using sin x = cos(π/2 − x). The cosine of ±∞ raises an invalid operation exception. use the series \__fp_sin_series:NNwww after argument reduction. x c mod 8. 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 13183 13184 13185 \cs_new:Npn \__fp_sin_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_case_return_same_o:w \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_o:w \__fp_sin_series:NNwww \__fp_fixed_to_float:wN #2 \c_zero } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { sin } } \else: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } (End definition for \__fp_sin_o:w. \__fp_trig_exponent:NNNNNwn checks the exponent: if the number is tiny. use \__fp_trig_epsilon_o:w which returns sin = . Otherwise. use the same series as for sine. \__fp_trig_exponent:NNNNNwn checks the exponent: if the number is tiny. because cos(x) = + sin(π/2 + |x|). For larger inputs.1 \__fp_sin_o:w Sign and special numbers The sine of ±0 or nan is the same floating point number. • Use the appropriate power series depending on the octant b π/4 and the function to compute. and convert the result of the series to a floating point directly. 36. Otherwise.1. The sine of ±∞ raises an invalid operation exception. The cosine of nan is itself. For larger inputs. because csc(x) = #2 sin|x| . use the same series as for sine. use \__fp_trig_epsilon_inv_o:w which returns csc = 1/. and inverting during the conversion from the fixed point sine to −1 the floating point result. using the sign #2. and inverting upon conversion. For larger inputs. 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 \cs_new:Npn \__fp_sec_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_case_return_o:Nw \c_one_fp \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_one_o:w \__fp_sin_series:NNwww \__fp_fixed_inv_to_float:wN 0 \c_two } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { sec } } \else: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } 629 . a starting octant of 0. The secant of nan is itself.) \__fp_sec_o:w The secant of ±0 is 1. Otherwise. use \__fp_trig_epsilon_one_o:w which returns sec = 1. The cosecant of ±∞ raises an invalid operation exception. The secant of ±∞ raises an invalid operation exception. using a positive sign 0. Otherwise. with a division by zero exception (see \__fp_cot_zero_o:Nnw defined below). a starting octant of 2.) \__fp_csc_o:w The cosecant of ±0 is ±∞ with the same sign. \__fp_trig_exponent:NNNNNwn checks the exponent: if the number is tiny. The cosecant of nan is itself.\s__fp \__fp_chk:w #1#2 13199 13200 } (End definition for \__fp_cos_o:w. because sec(x) = +1/ sin(π/2 + |x|). \__fp_trig_exponent:NNNNNwn checks the exponent: if the number is tiny. use the same series as for sine. 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 \cs_new:Npn \__fp_csc_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_cot_zero_o:Nnw #2 { csc } \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_inv_o:w \__fp_sin_series:NNwww \__fp_fixed_inv_to_float:wN #2 \c_zero } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { csc } } \else: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } (End definition for \__fp_csc_o:w. use \__fp_tan_series_o:NNwww for the calculation after argument reduction. We use cot x = − tan(π/2 + x). with a sign #2 and an initial octant of 1 (this shift is somewhat arbitrary). so the octant here starts at 3. and the initial octant for the tangent was chosen to be 1. Those signs are eventually combined. 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 \cs_new:Npn \__fp_tan_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_case_return_same_o:w \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_o:w \__fp_tan_series_o:NNwww 0 #2 \c_one } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { tan } } \else: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } (End definition for \__fp_tan_o:w. The tangent of ±∞ raises an invalid operation exception. Otherwise. \__fp_trig_exponent:NNNNNwn checks the exponent: if the number is tiny. See \__fp_cot_o:w for an explanation of the 0 argument. with a division by zero exception (see \__fp_cot_zero_o:Nnw. The cotangent of ±∞ raises an invalid operation exception. 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 \cs_new:Npn \__fp_cot_o:w \s__fp \__fp_chk:w #1#2 { \if_case:w #1 \exp_stop_f: \__fp_cot_zero_o:Nnw #2 { cot } \or: \__fp_case_use:nw { \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_inv_o:w \__fp_tan_series_o:NNwww 2 #2 \c_three } \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { cot } } \else: \__fp_case_return_same_o:w \fi: \s__fp \__fp_chk:w #1#2 } \cs_new:Npn \__fp_cot_zero_o:Nnw #1 #2 #3 \fi: 630 .) \__fp_tan_o:w The tangent of ±0 or nan is the same floating point number. For larger inputs. The cotangent of nan is itself.) \__fp_cot_o:w \__fp_cot_zero_o:Nnw The cotangent of ±0 is ±∞ with the same sign.(End definition for \__fp_sec_o:w. use \__fp_trig_epsilon_o:w which returns tan = . The change in sign is obtained by feeding \__fp_tan_series_o:NNwww two signs rather than just the sign of the argument: the first of those indicates whether we compute tangent or cotangent. which is appropriate.1. } (End definition for \__fp_trig_exponent:NNNNNwn. #2 .) 36. 631 . Argument reduction leaves a shift into the integer expression for the octant. 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 13282 13283 13284 13285 13286 13287 13288 \cs_new:Npn \__fp_trig_exponent:NNNNNwn #1#2#3#4#5 \s__fp \__fp_chk:w 1#6#7 { \if_int_compare:w #7 > . Cosine and secant simply give 1. #4. computed in an integer expression starting with #5 and stopped by a period. This is actually slightly wrong because further terms in the power series could affect the rounding for cotangent. and a fixed point number obtained from the floating point number by argument reduction. then call the _epsilon auxiliary #1.\c_eight \exp_after:wN #2 \exp_after:wN #3 \exp_after:wN #4 \int_use:N \__int_eval:w #5 \if_int_compare:w #7 > \c_zero \exp_after:wN \__fp_trig_large:ww \__int_value:w \else: \exp_after:wN \__fp_trig_small:ww \__int_value:w \fi: \else: \exp_after:wN #1 \exp_after:wN #6 \fi: #7 . 13289 13290 13291 \cs_new:Npn \__fp_trig_epsilon_o:w #1 #2 . Numbers less than 1 are converted using \__fp_trig_small:w which simply shifts the significand. Cotangent and cosecant compute 1/. This function is documented on page ??. call the function #2. with arguments #3. { \__fp_exp_after_o:w \s__fp \__fp_chk:w 1 #1 {#2} } \cs_new:Npn \__fp_trig_epsilon_one_o:w #1 .2 \__fp_trig_exponent:NNNNNwn Small and tiny arguments The first five arguments control what trigonometric function we compute. If the floating point is smaller than 10−8 .) \__fp_trig_epsilon_o:w \__fp_trig_epsilon_one_o:w \__fp_trig_epsilon_inv_o:w Sine and tangent of tiny numbers give the number itself: the relative error is less than 5 · 10−17 .{ 13262 \fi: \if_meaning:w 0 #1 \exp_after:wN \__fp_division_by_zero_o:Nnw \exp_after:wN \c_inf_fp \else: \exp_after:wN \__fp_division_by_zero_o:Nnw \exp_after:wN \c_minus_inf_fp \fi: {#2} 13263 13264 13265 13266 13267 13268 13269 } 13270 (End definition for \__fp_cot_o:w. the octant. Otherwise. then follows a normal floating point number. while large numbers need argument reduction. we are done subtracting 2π. #3. 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 \cs_new:Npn \__fp_trig_small:ww #1. We use a value of 2π rounded up. \exp_after:wN . #2. and we call \__fp_trig_octant_loop:nnnnnw to do the reduction by π/2.13292 13293 13294 13295 13296 13297 13298 13299 13300 13301 { \exp_after:wN \c_one_fp } \group_begin: \char_set_catcode_letter:N / \cs_new:Npn \__fp_trig_epsilon_inv_o:w #1 #2 .) 36. Since we have already filtered out numbers less than 10−8 . The arguments of \__fp_trig_large:www are a leading block of up to 5 digits. we need to perform argument reduction. { \if_meaning:w 0 #3 \__fp_trig_large_break:w \fi: \exp_after:wN \__fp_trig_large_o:wnnnn 632 . The multiple of 2π to subtract is estimated as b#1/6283c (the formula chosen always gives a non-negative integer).3 Reduction of large arguments In the case of a floating point argument greater or equal to 1. #2#3. we add at most 7 zeroes. three brace groups of 4 digits each. hence no digit is lost in converting to a fixed point number. #3 . and \__fp_trig_epsilon_inv_o:w. #1.) \__fp_trig_small:ww Floating point numbers less than 1 are converted to fixed point numbers by prepending a number of zeroes to the significand. \__fp_trig_large:ww \__fp_trig_large:www \__fp_trig_large_o:wnnnn \__fp_trig_large_break:w We shift the significand by one digit at a time. \__fp_trig_epsilon_one_o:w . but has the nice property that sin(180deg) = 0 exactly. The subtraction has a form similar to our usual multiplications (see l3fp-basics or l3fp-extended). \tex_romannumeral:D -‘0 \prg_replicate:nn { .1.#1 } { 0 } #2#3#4#5 0000 0000 . and the exponent. { \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN \exp_after:wN . { \exp_after:wN \__fp_/_o:ww \c_one_fp \s__fp \__fp_chk:w 1 #1 {#2} } \group_end: (End definition for \__fp_trig_epsilon_o:w . { \__fp_trig_large:www #2. 13312 13313 13314 13315 13316 13317 \cs_new:Npn \__fp_trig_large:ww #1. Once the exponent reaches 0. decremented at each step. subtracting a multiple of 2π at each step. This is not quite correct from an accuracy perspective. } \cs_new:Npn \__fp_trig_large:www #1. #2#3#4#5. consistent with the choice of \c_pi_fp. } (End definition for \__fp_trig_small:ww. } \cs_new:Npn \__fp_trig_large_break:w \fi: #1. Once the argument becomes smaller.#1*7179 \exp_after:wN \__fp_pack:NNNNNw \int_use:N \__int_eval:w \c__fp_trailing_shift_int + #50 .7854 (overestimate of π/4). 0. appropriate for the series expansions.3141 ) / 6283 . #2. The result is in all cases in the range [0. \__fp_trig_octant_loop:nnnnnw } \cs_new:Npn \__fp_trig_octant_break:w #1 \fi: + #2#3 #4#5. then compute π/2 − x and increment the octant. { \fi: \__fp_trig_octant_loop:nnnnnw #2 {0000} {0000} . { \fi: \if_int_compare:w #4 < 7854 \exp_stop_f: \exp_after:wN \__fp_use_i_until_s:nw \exp_after:wN . break the initial loop. #7. namely 1. #2#3#4#5 { \exp_after:wN \__fp_trig_large:www \int_use:N \__int_eval:w \c__fp_leading_shift_int + #20 . {#1} #2 \exp_after:wN .#1*5880 \exp_after:wN .7854]. \int_use:N \__int_eval:w \c_minus_one + #3. } (End definition for \__fp_trig_large:ww and others.5707963267948970. { \if_int_compare:w #1#2 < 157079633 \exp_stop_f: \if_int_compare:w #1#2 = 157079632 \exp_stop_f: \if_int_compare:w #3#4 > 67948969 \exp_stop_f: \use_i_ii:nnn \fi: \fi: \__fp_trig_octant_break:w \fi: + \c_two \__fp_fixed_sub:wwn {#1} {#2} {#3} {#4} {0000} {0000} . subtract that fixed-point approximation of π/2.) \__fp_trig_octant_loop:nnnnnw We receive a fixed point number as argument. 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346 13347 13348 13349 13350 13351 13352 13353 13354 13355 13356 13357 13358 \cs_new:Npn \__fp_trig_octant_loop:nnnnnw #1#2#3#4#5#6. 633 . } \cs_new:Npn \__fp_trig_large_o:wnnnn #1. {15707} {9632} {6794} {8970} {0000} {0000} . If the number is greater than 0. #6.#1*8530 \exp_after:wN \__fp_pack:NNNNNw \int_use:N \__int_eval:w \c__fp_middle_shift_int + #40 . As long as it is greater than half of \c_\__fp_trig_octant_break:w pi_fp. and leave + \c_two in the integer expression for the octant.#1*62831 \exp_after:wN \__fp_pack:NNNNNw \int_use:N \__int_eval:w \c__fp_middle_shift_int + #30 .13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 \int_use:N \__int_eval:w ( #1 . which depends on the octant #3 and the original sign #2. . The auxiliary receives: • The final sign.2 \__fp_sin_series:NNwww \__fp_sin_series_aux:NNnww Computing the power series Here we receive a conversion function \__fp_fixed_to_float:wN or \__fp_fixed_inv_to_float:wN. and \__fp_sanitize:Nw checks for overflow and underflow. computed with \__fp_fixed_mul:wwn. 2! 4! Otherwise. . { \__fp_fixed_mul:wwn #4. the series 1 1 sin(x) = x 1 − x2 − x2 − x2 · · · 3! 5! is used. #4. . we are near an extremum of the function and we use the series 2 1 2 1 2 cos(x) = 1 − x −x − x ··· . • The number itself. { \exp_after:wN \__fp_sin_series_aux:NNnww \exp_after:wN #1 \__int_value:w \if_int_odd:w \__int_eval:w ( #3 + \c_two ) / \c_four \__int_eval_end: #2 \else: \if_meaning:w #2 0 2 \else: 0 \fi: \fi: {#3} } #4 . #5. a (non-negative) hoctanti delimited by a dot. the fixed point number is converted to a floating point number with the given sign.\fi: + \c_one \__fp_fixed_sub:wwn #6 . and junk delimited by a semicolon. • The square #4 * #4 of the argument. 13359 13360 13361 } 13362 (End definition for \__fp_trig_octant_loop:nnnnnw and \__fp_trig_octant_break:w. 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 \cs_new:Npn \__fp_sin_series:NNwww #1#2#3 . a hfixed pointi number. . 2. If the octant is in {1. } \cs_new:Npn \__fp_sin_series_aux:NNnww #1#2#3 #4. 6. • The octant #3. }. #4. which will control the series we use. . Finally. a hsigni (0 or 2). #5.) 36. { 634 . 5. {#4} #5 . and 2 for cotangent. and 2 otherwise. which means that it is 1 or 2 for |x| ∈ [0. } { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN #2 \int_use:N \__int_eval:w #1 } #2 13381 13382 13383 13384 13385 13386 13387 13388 13389 13390 13391 13392 13393 13394 13395 13396 13397 13398 13399 13400 13401 13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412 13413 13414 13415 13416 } (End definition for \__fp_sin_series:NNwww and \__fp_sin_series_aux:NNnww. {0000}{0000}{0000}{7647}{1637}{3182}. \__fp_fixed_mul_sub_back:wwwn #4. \__fp_fixed_mul_sub_back:wwwn #4. {0013}{8888}{8888}{8888}{8888}{8889}. \__fp_fixed_mul_sub_back:wwwn #4. and 635 . \__fp_fixed_mul:wwn #5. \__fp_fixed_mul_sub_back:wwwn #4. {5000}{0000}{0000}{0000}{0000}{0000}. \__fp_fixed_mul_sub_back:wwwn #4. The octant #3 starts at 1. \__fp_fixed_mul_sub_back:wwwn #4. #4. The auxiliary receives the sign. #4. \__fp_fixed_mul_sub_back:wwwn #4. {0000}{0027}{5573}{1922}{3985}{8907}.{10000}{0000}{0000}{0000}{0000}{0000}. \__fp_fixed_mul_sub_back:wwwn #4.) \__fp_tan_series_o:NNwww \__fp_tan_series_aux_o:Nnww Contrarily to \__fp_sin_series:NNwww which received the conversion auxiliary as #1. {0001}{9841}{2698}{4126}{9841}{2698}. } { % 1/17! \__fp_fixed_mul_sub_back:wwwn {0000}{0000}{0000}{0028}{1145}{7254}. {0000}{0000}{0000}{0477}{9477}{3324}. π]. {0000}{0000}{2087}{6756}{9878}{6810}.{10000}{0000}{0000}{0000}{0000}{0000}. it is straightforward to check that the first \__int_value:w expansion produces 0 for a positive final result. \__fp_fixed_mul_sub_back:wwwn #4. {0000}{0002}{5052}{1083}{8544}{1719}. \__fp_fixed_mul_sub_back:wwwn #4. \__fp_fixed_mul_sub_back:wwwn #4. {0000}{2480}{1587}{3015}{8730}{1587}. and so on: the intervals on which tan|x| ≥ 0 coincide with those for which b(#3 + 1)/2c is odd. it is 3 or 4 for |x| ∈ [π/2. π/2]. {0000}{0000}{0160}{5904}{3836}{8216}. \__fp_fixed_mul_sub_back:wwwn #4. We also have to take into account the original sign of x to get the sign of the final result. \__fp_fixed_mul_sub_back:wwwn #4. {0000}{0275}{5731}{9223}{9858}{9065}. here #1 is 0 for tangent. Consider first the case of the tangent. \__fp_fixed_mul_sub_back:wwwn #4. the octant. {0000}{0000}{0011}{4707}{4559}{7730}. {0083}{3333}{3333}{3333}{3333}{3333}. A similar story holds for cot(x). the square of the (reduced) input. {1666}{6666}{6666}{6666}{6666}{6667}.\if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end: \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { % 1/18! \__fp_fixed_mul_sub_back:wwwn {0000}{0000}{0000}{0001}{5619}{2070}. {0416}{6666}{6666}{6666}{6666}{6667}. \__fp_fixed_mul_sub_back:wwwn #4. \__fp_fixed_mul_sub_back:wwwn #3. \__fp_fixed_mul:wwn #4. {0536}{6357}{0691}{4344}{6852}{4252}. \__fp_fixed_mul_sub_back:wwwn #3. { \__fp_fixed_mul_sub_back:wwwn {0000}{0007}{0258}{0681}{9408}{4706}. {5263}{1578}{9473}{6842}{1052}{6315}. { \exp_after:wN \__fp_tan_series_aux_o:Nnww \__int_value:w \if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end: \exp_after:wN \reverse_if:N \fi: \if_meaning:w #1#2 2 \else: 0 \fi: {#3} } #4 . {0019}{2638}{4588}{9232}{8861}{3691}.{10000}{0000}{0000}{0000}{0000}{0000}. #3. #4. 1 − x2 (b1 − x2 (b2 − x2 (b3 − x2 (b4 − x2 b5 )))) The ratio itself is computed by \__fp_fixed_div_to_float:ww. #3.the (reduced) input as arguments. {1929}{8245}{6140}{3508}{7719}{2982}. \__fp_fixed_mul_sub_back:wwwn #3. {0115}{5830}{7533}{5397}{3168}{2147}. { \exp_after:wN \__fp_sanitize:Nw \exp_after:wN #1 \int_use:N \__int_eval:w \reverse_if:N \if_int_odd:w \__int_eval:w (#2 . {0000}{0159}{6080}{0274}{5257}{6472}. #5. { \__fp_fixed_mul_sub_back:wwwn {0000}{0000}{1527}{3493}{0856}{7059}. #4. #4. \__fp_fixed_mul_sub_back:wwwn #3. \__fp_fixed_mul_sub_back:wwwn #3. It then computes the numerator and denominator of tan(x) ' x(1 − x2 (a1 − x2 (a2 − x2 (a3 − x2 (a4 − x2 a5 ))))) .{10000}{0000}{0000}{0000}{0000}{0000}. 13417 13418 13419 13420 13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441 13442 13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455 \cs_new:Npn \__fp_tan_series_o:NNwww #1#2#3. {0002}{4571}{2320}{0157}{2558}{8481}. \__fp_fixed_mul_sub_back:wwwn #3. Note that this \if_int_odd:w test relies on the fact that the octant is at least 1. For octants #2 (really. {0000}{2343}{7175}{1399}{6151}{7670}. } \cs_new:Npn \__fp_tan_series_aux_o:Nnww #1 #2 #3. { \__fp_fixed_mul:wwn #4. quadrants) next to a pole of the functions.\c_one) / \c_two \__int_eval_end: \exp_after:wN \__fp_reverse_args:Nww \fi: \__fp_fixed_div_to_float:ww 636 . the fixed point numerator and denominator are exchanged before computing the ratio. \__fp_fixed_mul_sub_back:wwwn #3. \__fp_fixed_mul_sub_back:wwwn #3. which converts it directly to a floating point number to avoid rounding issues. and the second argument is the same loop auxiliary. #2 \s__stop { #1 } (End definition for \__fp_trim_zeros:w. Once the last trailing zero is reached. Then filter the special cases: ±0 are represented as 0. the second argument will be the dot auxiliary. \__fp_trim_zeros_loop:w 0. We then clean-up with the end auxiliary. First cater for the sign: negative numbers \__fp_to_scientific_normal:wNw (#2 = 2) start with -. and the format is very well defined. #2 { #2 #1 . which removes a trailing dot if any. the loop auxiliary takes that zero as an end-delimiter for its first argument. This function is documented on page ??. infinities are converted to a number slightly larger than the largest after an “invalid_operation” exception.) 13459 h/initex | packagei 37 l3fp-convert implementation 13460 h*initex | packagei 13461 h@@=fpi 37. #2 } \cs_new:Npn \__fp_trim_zeros_dot:w #1 .1 \__fp_trim_zeros:w \__fp_trim_zeros_loop:w \__fp_trim_zeros_dot:w \__fp_trim_zeros_end:w Trimming trailing zeros If #1 ends with a 0. we then only need to care about positive numbers and nan.2 \fp_to_scientific:N \fp_to_scientific:c \fp_to_scientific:n Scientific notation The three public functions evaluate their argument.) 37. \s__stop } \cs_new:Npn \__fp_trim_zeros_loop:w #1 0. 13462 13463 13464 13465 13466 13467 13468 13469 \cs_new:Npn \__fp_trim_zeros:w #1 . functions are documented on page ??.) These \__fp_to_scientific_dispatch:w Expressing an internal floating point number in scientific notation is quite easy: no \__fp_to_scientific_normal:wnnnnn rounding..} 13456 } 13457 } 13458 (End definition for \__fp_tan_series_o:NNwww and \__fp_tan_series_aux_o:Nnww. { \__fp_trim_zeros_loop:w #1 . then pass it to \__fp_to_scientific_dispatch:w. 13470 13471 13472 13473 13474 13475 13476 13477 \cs_new:Npn \fp_to_scientific:N #1 { \exp_after:wN \__fp_to_scientific_dispatch:w #1 } \cs_generate_variant:Nn \fp_to_scientific:N { c } \cs_new_nopar:Npn \fp_to_scientific:n { \exp_after:wN \__fp_to_scientific_dispatch:w \tex_romannumeral:D -‘0 \__fp_parse:n } (End definition for \fp_to_scientific:N . nan is represented 637 .. } \cs_new:Npn \__fp_trim_zeros_end:w #1 . and \fp_to_scientific:n. \__fp_trim_zeros_dot:w . keeping only the number. \fp_to_scientific:c . { \__fp_trim_zeros_end:w #1 . responsible for creating e with category “other”. } 638 . then in a second step grab the first digit (previously hidden in braces) to order the various parts correctly. In the normal case. 13478 13479 13480 13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494 13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 \group_begin: \char_set_catcode_other:N E \tl_to_lowercase:n { \group_end: \cs_new:Npn \__fp_to_scientific_dispatch:w \s__fp \__fp_chk:w #1#2 { \if_meaning:w 2 #2 \exp_after:wN .\c_one \fi: .\tex_romannumeral:D -‘0 \fi: \if_case:w #1 \exp_stop_f: \__fp_case_return:nw { 0 } \or: \exp_after:wN \__fp_to_scientific_normal:wnnnnn \or: \__fp_case_use:nw { \__fp_invalid_operation:nnw { \exp_after:wN 1 \exp_after:wN E \int_use:N \c__fp_max_exponent_int } { fp_to_scientific } } \or: \__fp_case_use:nw { \__fp_invalid_operation:nnw { 0 } { fp_to_scientific } } \fi: \s__fp \__fp_chk:w #1 #2 } \cs_new:Npn \__fp_to_scientific_normal:wnnnnn \s__fp \__fp_chk:w 1 #1 #2 #3#4#5#6 .as 0 after an “invalid_operation” exception. { \if_int_compare:w #2 = \c_one \exp_after:wN \__fp_to_scientific_normal:wNw \else: \exp_after:wN \__fp_to_scientific_normal:wNw \exp_after:wN E \int_use:N \__int_eval:w #2 . Finally trim zeros. The whole construction is within a call to \tl_to_lowercase:n. #3 #4 #5 #6 . decrement the exponent and unbrace the 4 brace groups. which we don’t expand now since it most likely won’t be needed. { \__fp_trim_zeros:w #2. 15] have that number of digits before the decimal separator: “decimate” them. When the exponent is non-positive. \fp_to_decimal:c . #1 } (End definition for \__fp_to_scientific_dispatch:w . ±∞ and nan yield an “invalid operation” exception. Zero gives 0.#3 .) \__fp_to_decimal_dispatch:w \__fp_to_decimal_normal:wnnnnn \__fp_to_decimal_large:Nnnw \__fp_to_decimal_huge:wnnnn The structure is similar to \__fp_to_scientific_dispatch:w. and \__fp_to_scientific_nor 37.13522 13523 13524 } \cs_new:Npn \__fp_to_scientific_normal:wNw #1 . and remove leading zeros with \__int_value:w. we only need to add trailing zeros. \__fp_to_scientific_normal:wnnnnn . 13525 13526 13527 13528 13529 13530 13531 13532 \cs_new:Npn \fp_to_decimal:N #1 { \exp_after:wN \__fp_to_decimal_dispatch:w #1 } \cs_generate_variant:Nn \fp_to_decimal:N { c } \cs_new_nopar:Npn \fp_to_decimal:n { \exp_after:wN \__fp_to_decimal_dispatch:w \tex_romannumeral:D -‘0 \__fp_parse:n } (End definition for \fp_to_decimal:N . 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 \cs_new:Npn \__fp_to_decimal_dispatch:w \s__fp \__fp_chk:w #1#2 { \if_meaning:w 2 #2 \exp_after:wN . then trim trailing zeros and dot. Normal numbers with an exponent 16 or larger have no decimal separator.for negative numbers. and \fp_to_decimal:n. trimmed.3 \fp_to_decimal:N \fp_to_decimal:c \fp_to_decimal:n Decimal representation All three public variants are based on the same \__fp_to_decimal_dispatch:w after evaluating their argument to an internal floating point. Insert . Normal numbers with an exponent in the range [1.hzerosihdigitsi. #2#3. These functions are documented on page ??.\tex_romannumeral:D -‘0 \fi: \if_case:w #1 \exp_stop_f: \__fp_case_return:nw { 0 } \or: \exp_after:wN \__fp_to_decimal_normal:wnnnnn \or: \__fp_case_use:nw { \__fp_invalid_operation:nnw { \exp_after:wN \exp_after:wN \exp_after:wN 1 \prg_replicate:nn \c__fp_max_exponent_int 0 } { fp_to_decimal } } \or: \__fp_case_use:nw { \__fp_invalid_operation:nnw 639 . note that ±∞ produces a very large output. the result should be 0. } \cs_new:Npn \__fp_to_decimal_huge:wnnnn #1. #2#3#4#5 { #2#3#4#5 #1 } (End definition for \__fp_to_decimal_dispatch:w and others.#2 } { 0 } #3#4#5#6 .{ 0 } { fp_to_decimal } 13553 13554 } \fi: \s__fp \__fp_chk:w #1 #2 13555 13556 13557 13558 13559 13560 13561 13562 13563 13564 13565 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575 13576 13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 } \cs_new:Npn \__fp_to_decimal_normal:wnnnnn \s__fp \__fp_chk:w 1 #1 #2 #3#4#5#6 . } } \cs_new:Npn \__fp_to_decimal_large:Nnnw #1#2#3#4.) 37.4 \fp_to_tl:N \fp_to_tl:c \fp_to_tl:n Token list representation These three public functions evaluate their argument. 13594 13595 \cs_new:Npn \fp_to_tl:N #1 { \exp_after:wN \__fp_to_tl_dispatch:w #1 } \cs_generate_variant:Nn \fp_to_tl:N { c } 640 .\c_sixteen } { 0 } . \tex_romannumeral:D -‘0 \prg_replicate:nn { . { \int_compare:nNnTF {#2} > \c_zero { \int_compare:nNnTF {#2} < \c_sixteen { \__fp_decimate:nNnnnn { \c_sixteen .#4 . then pass it to \__fp_to_tl_dispatch:w.#2 } \__fp_to_decimal_large:Nnnw } { \exp_after:wN \exp_after:wN \exp_after:wN \__fp_to_decimal_huge:wnnnn \prg_replicate:nn { #2 . } {#3} {#4} {#5} {#6} } { \exp_after:wN \__fp_trim_zeros:w \exp_after:wN 0 \exp_after:wN . { \exp_after:wN \__fp_trim_zeros:w \__int_value:w \if_int_compare:w #2 > \c_zero #2 \fi: \exp_stop_f: #3. and otherwise use scientific notation. 37.13596 13597 13598 13599 13600 \cs_new_nopar:Npn \fp_to_tl:n { \exp_after:wN \__fp_to_tl_dispatch:w \tex_romannumeral:D -‘0 \__fp_parse:n } (End definition for \fp_to_tl:N .\tex_romannumeral:D -‘0 \fi: \if_case:w #1 \exp_stop_f: \__fp_case_return:nw { 0 } \or: \exp_after:wN \__fp_to_tl_normal:nnnnn \or: \__fp_case_return:nw { \tl_to_str:n {inf} } \else: \__fp_case_return:nw { \tl_to_str:n {nan} } \fi: } \cs_new:Npn \__fp_to_tl_normal:nnnnn #1 { \if_int_compare:w #1 > \c_sixteen \exp_after:wN \__fp_to_scientific_normal:wnnnnn \else: \if_int_compare:w #1 < .5 Formatting This is not implemented yet. but without the “invalid operation” exception.) 37. 16]. for this kind of structured conversion from a floating point (or other types of variables) to a string.\c_two \exp_after:wN \exp_after:wN \exp_after:wN \__fp_to_scientific_normal:wnnnnn \else: \exp_after:wN \exp_after:wN \exp_after:wN \__fp_to_decimal_normal:wnnnnn \fi: \fi: \s__fp \__fp_chk:w 1 0 {#1} } (End definition for \__fp_to_tl_dispatch:w and \__fp_to_tl_normal:nnnnn. 641 . \fp_to_tl:c .) \__fp_to_tl_dispatch:w \__fp_to_tl_normal:nnnnn A structure similar to \__fp_to_scientific_dispatch:w and \__fp_to_decimal_dispatch:w. We express normal numbers in decimal notation if the exponent is in the range [−2. We make sure to produce pt with category other. First filter special cases.6 \fp_to_dim:N \fp_to_dim:c \fp_to_dim:n Convert to dimension or integer These three public functions rely on \fp_to_decimal:n internally. These functions are documented on page ??. 13601 13602 13603 13604 13605 13606 13607 13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619 13620 13621 13622 13623 13624 13625 \cs_new:Npn \__fp_to_tl_dispatch:w \s__fp \__fp_chk:w #1#2 { \if_meaning:w 2 #2 \exp_after:wN . as it is not yet clear what a correct interface would be. and \fp_to_tl:n. Ideas welcome. } \cs_new:Npn \__fp_from_dim_test:N #1 { \if_meaning:w 0 #1 \__fp_case_return:nw \c_zero_fp \else: \if_meaning:w . .) 37. These functions are documented on page ??. then multiplied by 2−16 = 0. converted to a number (i.#1 642 . { \exp_after:wN \__fp_to_decimal_dispatch:w \tex_romannumeral:D -‘0 \__fp_round:Nwn \__fp_round_to_nearest:NNN #1. and \fp_to_int:n.e. expressed in scaled points). and \fp_to_dim:n.) as arguments. \fp_to_dim:c . first round to 0 places (to the nearest integer).0000152587890625 to give a value expressed in points. { 0 } } (End definition for \__fp_to_int_dispatch:w. 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653 \cs_new:Npn \dim_to_fp:n #1 { \exp_after:wN \__fp_from_dim_test:N \__int_value:w \etex_glueexpr:D #1 . .) \__fp_to_int_dispatch:w To convert to an integer. These functions are documented on page ??. 13638 13639 13640 13641 13642 \cs_new:Npn \__fp_to_int_dispatch:w #1..7 \dim_to_fp:n \__fp_from_dim_test:N \__fp_from_dim:Nw \__fp_from_dim:wNNnnnnnn \__fp_from_dim:wnnnnwN Convert from a dimension The dimension expression (which can in fact be a glue expression) is evaluated. then pass it to \fp_to_int_dispatch:w. The auxiliary \__fp_mul_npos_o:Nww expects the desired hfinal signi and two floating point operands (of the form \s__fp . 13631 13632 13633 13634 13635 13636 13637 \cs_new:Npn \fp_to_int:N #1 { \exp_after:wN \__fp_to_int_dispatch:w #1 } \cs_generate_variant:Nn \fp_to_int:N { c } \cs_new_nopar:Npn \fp_to_int:n { \exp_after:wN \__fp_to_int_dispatch:w \tex_romannumeral:D -‘0 \__fp_parse:n } (End definition for \fp_to_int:N . .) \fp_to_int:N \fp_to_int:c \fp_to_int:n These three public functions evaluate their argument. \fp_to_int:c .13626 13627 13628 13629 13630 \cs_new:Npx \fp_to_dim:N #1 { \exp_not:N \fp_to_decimal:N #1 \tl_to_str:n {pt} } \cs_generate_variant:Nn \fp_to_dim:N { c } \cs_new:Npx \fp_to_dim:n #1 { \exp_not:N \fp_to_decimal:n {#1} \tl_to_str:n {pt} } (End definition for \fp_to_dim:N . then express the result as a decimal number: the definition of \__fp_to_decimal_dispatch:w is such that there will be no trailing dot nor zero. This function is documented on page 180. \s__fp \__fp_chk:w 1 0 {-4} {1525} {8789} {0625} {0000} . { \__fp_pack_twice_four:wNNNNNNNN \__fp_from_dim:wNNnnnnnn .) 643 . \fp_use:c . 13682 13683 13684 13685 \cs_new:Npn \fp_max:nn { \fp_to_decimal:n { \cs_new:Npn \fp_min:nn { \fp_to_decimal:n { #1#2 max ( \__fp_parse:n {#1} . #2#3#4#5#6. } (End definition for \dim_to_fp:n. These functions are documented on page 180. and \fp_eval:n.) \fp_abs:n Trivial but useful. for consistency with \int_max:nn. etc. #7 { \__fp_mul_npos_o:Nww #7 \s__fp \__fp_chk:w 1 #7 {#5} #1 . This function is documented on page 180. 13680 13681 \cs_new:Npn \fp_abs:n #1 { \fp_to_decimal:n { abs \__fp_parse:n {#1} } } (End definition for \fp_abs:n. \__fp_parse:n {#2} ) } } #1#2 min ( \__fp_parse:n {#1} .) 37. These functions are documented on page 169. #2 000 0000 00 {10}987654321. } \cs_new:Npn \__fp_from_dim:wnnnnwN #1. \__fp_parse:n {#2} ) } } (End definition for \fp_max:nn and \fp_min:nn. for better error reporting.\exp_after:wN \__fp_from_dim:Nw \exp_after:wN 2 \__int_value:w \else: \exp_after:wN \__fp_from_dim:Nw \exp_after:wN 0 \__int_value:w #1 \fi: \fi: 13654 13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 } \cs_new:Npn \__fp_from_dim:Nw #1 #2. namely. #1 } \cs_new:Npn \__fp_from_dim:wNNnnnnnn #1. See the implementation of \fp_add:Nn for an explanation of why to use \__fp_parse:n. #2#3#4#5#6#7#8#9 { \__fp_from_dim:wnnnnwN #1 {#2#300} {0000} . 13677 13678 13679 \cs_new_eq:NN \fp_use:N \fp_to_decimal:N \cs_generate_variant:Nn \fp_use:N { c } \cs_new_eq:NN \fp_eval:n \fp_to_decimal:n (End definition for \fp_use:N .8 \fp_use:N \fp_use:c \fp_eval:n Use and eval Those public functions are simple copies of the decimal conversions.) \fp_max:nn \fp_min:nn Similar to \fp_abs:n. 644 . ~ } \fp_to_tl:n { #1 #2 . { \use_none:n #1 { . } \exp_not:N \__fp_array_to_clist_loop:Nw } (End definition for \__fp_array_to_clist:n. } \__fp_array_to_clist_loop:Nw } The \use_ii:nn function is expanded after \__fp_expand:n is done.~ from the start of the representation. and it removes . \exp_not:N \exp_after:wN \c_space_tl \exp_not:N \tex_romannumeral:D -‘0 \exp_not:N \__fp_to_tl_dispatch:w #1 #2 . \__prg_break_point: } } } \cs_new:Npx \__fp_array_to_clist_loop:Nw #1#2. This function is documented on page ??. 13686 13687 13688 13689 13690 13691 13692 13693 13694 13695 13696 13697 13698 13699 13700 13701 13702 13703 13704 13705 13706 13707 13708 13709 \cs_new:Npn \__fp_array_to_clist:n #1 { \tl_if_empty:nF {#1} { \__fp_expand:n { { \use_ii:nn } \__fp_array_to_clist_loop:Nw #1 { ? \__prg_break: } . { \exp_not:N \use_none:n #1 \exp_not:N \exp_after:wN { \exp_not:N \exp_after:wN . we can simplify the code for the auxiliary to become \cs_new:Npn \__fp_array_to_clist_loop:Nw #1#2. If speed here ends up irrelevant.9 \__fp_array_to_clist:n \__fp_array_to_clist_loop:Nw Convert an array of floating points to a comma list Converts an array of floating point numbers to a comma-list.37.) 13710 h/initex | packagei l3fp-assign implementation 38 13711 h*initex | packagei 13712 h@@=fpi 38.1 \fp_new:N Assigning values Floating point variables are initialized to be +0. 13713 13714 13715 \cs_new_protected:Npn \fp_new:N #1 { \cs_new_eq:NN #1 \c_zero_fp } \cs_generate_variant:Nn \fp_new:N {c} (End definition for \fp_new:N.) \fp_set_eq:NN \fp_set_eq:cN \fp_set_eq:Nc \fp_set_eq:cc \fp_gset_eq:NN \fp_gset_eq:cN \fp_gset_eq:Nc \fp_zero:N \fp_gset_eq:cc \fp_zero:c \fp_gzero:N \fp_gzero:c Copying a floating point is the same as copying the underlying token list. 13725 13726 13727 13728 \cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN \cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN \cs_generate_variant:Nn \fp_set_eq:NN { c . Nc . cc } \cs_generate_variant:Nn \fp_gset_eq:NN { c . 13716 13717 13718 13719 13720 13721 13722 13723 13724 \cs_new_protected:Npn \fp_set:Nn #1#2 { \tl_set:Nx #1 { \__fp_parse:n {#2} } } \cs_new_protected:Npn \fp_gset:Nn #1#2 { \tl_gset:Nx #1 { \__fp_parse:n {#2} } } \cs_new_protected:Npn \fp_const:Nn #1#2 { \tl_const:Nx #1 { \__fp_parse:n {#2} } } \cs_generate_variant:Nn \fp_set:Nn {c} \cs_generate_variant:Nn \fp_gset:Nn {c} \cs_generate_variant:Nn \fp_const:Nn {c} (End definition for \fp_set:Nn and others.) \fp_set:Nn \fp_set:cn \fp_gset:Nn \fp_gset:cn \fp_const:Nn \fp_const:cn Simply use \__fp_parse:n within various x-expanding assignments.) \fp_zero_new:N \fp_zero_new:c \fp_gzero_new:N \fp_gzero_new:c Set the floating point to zero. cc } (End definition for \fp_set_eq:NN and others.) Setting a floating point to zero: copy \c_zero_fp. 13729 13730 13731 13732 \cs_new_protected:Npn \fp_zero:N #1 { \fp_set_eq:NN #1 \c_zero_fp } \cs_new_protected:Npn \fp_gzero:N #1 { \fp_gset_eq:NN #1 \c_zero_fp } \cs_generate_variant:Nn \fp_zero:N { c } \cs_generate_variant:Nn \fp_gzero:N { c } (End definition for \fp_zero:N and others.) 38. This function is documented on page 168.2 Updating values These match the equivalent functions in l3int and l3skip. These functions are documented on page ??. These functions are documented on page ??. 645 . These functions are documented on page ??. These functions are documented on page ??. Nc . 13733 13734 13735 13736 13737 13738 \cs_new_protected:Npn \fp_zero_new:N #1 { \fp_if_exist:NTF #1 { \fp_zero:N #1 } { \fp_new:N #1 } } \cs_new_protected:Npn \fp_gzero_new:N #1 { \fp_if_exist:NTF #1 { \fp_gzero:N #1 } { \fp_new:N #1 } } \cs_generate_variant:Nn \fp_zero_new:N { c } \cs_generate_variant:Nn \fp_gzero_new:N { c } (End definition for \fp_zero_new:N and others. or define it if needed. The \__msg_show_variable:n auxiliary expects its input in a slightly odd form. but instead round it up to the next nearest multiple.4 \c_one_fp \c_e_fp Some useful constants and scratch variables Some constants.\fp_add:Nn \fp_add:cn \fp_gadd:Nn \fp_gadd:cn \fp_sub:Nn \fp_sub:cn \fp_gsub:Nn \fp_gsub:cn \__fp_add:NNNn For the sake of error recovery we should not simply set #1 to #1 ± (#2): for instance.3 \fp_show:N \fp_show:c \fp_show:n Showing values This shows the result of computing its argument. These variables are documented on page 173. Thus we evaluate #2 instead of just putting parentheses.) 38.) \c_pi_fp \c_one_degree_fp We do not round π to the closest multiple of 10−15 .) 38. which would convert the result away from the internal representation and back.718 2818 2845 9045 } { 1 } (End definition for \c_one_fp and \c_e_fp. 13739 13740 13741 13742 13743 13744 13745 13746 13747 13748 \cs_new_protected_nopar:Npn \fp_add:Nn { \__fp_add:NNNn \cs_new_protected_nopar:Npn \fp_gadd:Nn { \__fp_add:NNNn \cs_new_protected_nopar:Npn \fp_sub:Nn { \__fp_add:NNNn \cs_new_protected_nopar:Npn \fp_gsub:Nn { \__fp_add:NNNn \cs_new_protected:Npn \__fp_add:NNNn #1#2#3#4 { #1 #3 { #3 #2 \__fp_parse:n {#4} } } \cs_generate_variant:Nn \fp_add:Nn { c } \cs_generate_variant:Nn \fp_gadd:Nn { c } \cs_generate_variant:Nn \fp_sub:Nn { c } \cs_generate_variant:Nn \fp_gsub:Nn { c } \fp_set:Nn \fp_gset:Nn \fp_set:Nn \fp_gset:Nn + + - } } } } (End definition for \fp_add:Nn and others. and displays the rest. These functions are documented on page ??. This particular choice of rounding has very nice 646 . starting with >~. if #2 is 0)+2. which is an overestimate by roughly 7. 13761 13762 \fp_const:Nn \c_e_fp \fp_const:Nn \c_one_fp { 2. \fp_show:c . which would underestimate it by roughly 2.7 · 10−16 . As an optimization we use \__fp_parse:n rather than \fp_eval:n.4 · 10−16 . These functions are documented on page ??. the parsing error would be raised at the last closing parenthesis rather than at the closing parenthesis in the user argument. and \fp_show:n. 13749 13750 13751 13752 13753 13754 13755 13756 13757 13758 13759 13760 \cs_new_protected:Npn \fp_show:N #1 { \fp_if_exist:NTF #1 { \__msg_show_variable:n { > ~ \fp_to_tl:N #1 } } { \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } \cs_new_protected:Npn \fp_show:n #1 { \__msg_show_variable:n { > ~ \fp_to_tl:n {#1} } } \cs_generate_variant:Nn \fp_show:N { c } (End definition for \fp_show:N . . hence ensuring that sin(180deg) = sin(π) = 0 exactly. TF } { \exp_after:wN \__fp_if_undefined:w #1 } \cs_new:Npn \__fp_if_undefined:w \s__fp \__fp_chk:w #1#2. These functions are documented on page ??. 13763 13764 \fp_const:Nn \c_pi_fp { 3.) \fp_if_undefined_p:N \fp_if_undefined:NTF An old floating point is undefined if it is inf or nan. i. TF } { \exp_after:wN \__fp_if_zero:w #1 } \cs_new:Npn \__fp_if_zero:w \s__fp \__fp_chk:w #1#2. These functions are documented on page ??. 13772 \fp_const:Nn \c_undefined_fp { nan } (End definition for \c_undefined_fp.) \fp_if_zero_p:N \fp_if_zero:NTF An old floating point is zero if it is ±0. if its type is 2 or 3.) \l_tmpa_fp \l_tmpb_fp \g_tmpa_fp \g_tmpb_fp Scratch variables are simply initialized there.1 \c_undefined_fp Compatibility The old floating point number \c_undefined_fp is now implemented as a nan. These variables are documented on page 173. { \if_int_compare:w #1 > \c_one \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \fp_if_undefined:N. { \if_meaning:w #1 0 \prg_return_true: \else: \prg_return_false: \fi: } (End definition for \fp_if_zero:N.) 647 . T . i.. F .properties: it is exactly divisible by 4 and by 180 as a 16-digit precision floating point number.) 13769 h/initex | packagei l3fp-old implementation 39 13770 h*initex | packagei 13771 h@@=fpi 39. T . 13773 13774 13775 13776 13777 13778 13779 \prg_new_conditional:Npnn \fp_if_undefined:N #1 { p . with no rounding artifact.e. This variable is documented on page ??.141 5926 5358 9794 } \fp_const:Nn \c_one_degree_fp { 0. F . its type is 0. 13765 13766 13767 13768 \fp_new:N \fp_new:N \fp_new:N \fp_new:N \l_tmpa_fp \l_tmpb_fp \g_tmpa_fp \g_tmpb_fp (End definition for \l_tmpa_fp and others.e. These variables are documented on page 173.0 1745 3292 5199 4330 } (End definition for \c_pi_fp and \c_one_degree_fp. 13780 13781 13782 13783 \prg_new_conditional:Npnn \fp_if_zero:N #1 { p . an added twist is that each value computed by these expensive unary operations is stored as a constant floating point number. The \prg_do_nothing: is not necessary. These functions are documented on page ??.) \fp_exp:Nn \fp_exp:cn \fp_gexp:Nn \fp_gexp:cn \fp_ln:Nn \fp_ln:cn \fp_gln:Nn \fp_gln:cn \fp_sin:Nn \fp_sin:cn \fp_gsin:Nn \fp_gsin:cn \fp_cos:Nn \fp_cos:cn \fp_gcos:Nn Here. 13818 13819 13820 13821 \cs_set_protected:Npn \__fp_tmp:w #1#2#3#4#5 { \cs_new_protected_nopar:Npn #1 { #5 {#4} \tl_set_eq:NN #3 } \cs_new_protected_nopar:Npn #2 { #5 {#4} \tl_gset_eq:NN #3 } 648 .) \fp_mul:Nn \fp_mul:cn \fp_gmul:Nn \fp_gmul:cn \fp_div:Nn \fp_div:cn \fp_gdiv:Nn \fp_gdiv:cn \fp_pow:Nn \fp_pow:cn \fp_gpow:Nn \fp_gpow:cn \__fp_mul:NNNn See \fp_add:Nn for details.\fp_abs:N \fp_abs:c \fp_gabs:N \fp_gabs:c \fp_neg:N \fp_neg:c \fp_gneg:N \fp_gneg:c \__fp_abs:NNN Simply expand the floating point variable to feed it to \__fp_abs_o:w or \__fp_-_o:w. expanded within an expanding token list assignment. 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 \cs_new_protected_nopar:Npn \fp_mul:Nn { \__fp_mul:NNNn \cs_new_protected_nopar:Npn \fp_gmul:Nn { \__fp_mul:NNNn \cs_new_protected_nopar:Npn \fp_div:Nn { \__fp_mul:NNNn \cs_new_protected_nopar:Npn \fp_gdiv:Nn { \__fp_mul:NNNn \cs_new_protected_nopar:Npn \fp_pow:Nn { \__fp_mul:NNNn \cs_new_protected_nopar:Npn \fp_gpow:Nn { \__fp_mul:NNNn \cs_new_protected:Npn \__fp_mul:NNNn #1#2#3#4 { #1 #3 { #3 #2 \__fp_parse:n {#4} } } \cs_generate_variant:Nn \fp_mul:Nn { c } \cs_generate_variant:Nn \fp_gmul:Nn { c } \cs_generate_variant:Nn \fp_div:Nn { c } \cs_generate_variant:Nn \fp_gdiv:Nn { c } \cs_generate_variant:Nn \fp_pow:Nn { c } \cs_generate_variant:Nn \fp_gpow:Nn { c } \fp_set:Nn \fp_gset:Nn \fp_set:Nn \fp_gset:Nn \fp_set:Nn \fp_gset:Nn * * / / ^ ^ } } } } } } (End definition for \fp_mul:Nn and others. but it reminds us more clearly that \__fp_abs_o:w and \__fp_-_o:w expand after their result. 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 \cs_new_protected_nopar:Npn \fp_abs:N { \__fp_abs:NNN \tl_set:Nx \__fp_abs_o:w } \cs_new_protected_nopar:Npn \fp_gabs:N { \__fp_abs:NNN \tl_gset:Nx \__fp_abs_o:w } \cs_new_protected_nopar:Npx \fp_neg:N { \exp_not:N \__fp_abs:NNN \exp_not:N \tl_set:Nx \exp_not:c { __fp_-_o:w } } \cs_new_protected_nopar:Npx \fp_gneg:N { \exp_not:N \__fp_abs:NNN \exp_not:N \tl_gset:Nx \exp_not:c { __fp_-_o:w } } \cs_new_protected:Npn \__fp_abs:NNN #1#2#3 { #1 #3 { \exp_after:wN #2 #3 \prg_do_nothing: } } \cs_generate_variant:Nn \fp_abs:N { c } \cs_generate_variant:Nn \fp_gabs:N { c } \cs_generate_variant:Nn \fp_neg:N { c } \cs_generate_variant:Nn \fp_gneg:N { c } (End definition for \fp_abs:N and others. These functions are documented on page ??. ) \fp_compare:NNNTF Comparisons used to be easier between floating points stored in variables. 13847 13848 13849 \cs_new_protected_nopar:Npn \fp_compare:NNNTF { \fp_compare:nNnTF } \cs_new_protected_nopar:Npn \fp_compare:NNNT { \fp_compare:nNnT } \cs_new_protected_nopar:Npn \fp_compare:NNNF { \fp_compare:nNnF } (End definition for \fp_compare:NNNTF. No more. These functions are documented on page ??. } } #3 #5 #1 } (End definition for \fp_exp:Nn and others. 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 \cs_new_protected_nopar:Npn \fp_round_places:Nn { \__fp_round_places:NNn \tl_set:Nx } \cs_new_protected_nopar:Npn \fp_ground_places:Nn { \__fp_round_places:NNn \tl_gset:Nx } \cs_new_protected:Npn \__fp_round_places:NNn #1#2#3 { #1 #2 { \exp_after:wN \exp_after:wN \exp_after:wN \__fp_round:Nwn \exp_after:wN \exp_after:wN \exp_after:wN \__fp_round_to_nearest:NNN \exp_after:wN #2 \exp_after:wN { \int_use:N \__int_eval:w #3 } 649 .) \fp_round_places:Nn \fp_ground_places:Nn \__fp_round_places:NNn Rounding to a given number of places is easy. #4 { \exp_args:Nc \__fp_assign_to_ii:NnNNN { c__fp_ #4 [ #1 # 2 \if_meaning:w 1 #1 #3 \fi: ] _fp } { #1#2#3 } } \cs_new_protected:Npn \__fp_assign_to_ii:NnNNN #1#2#3#4#5 { \cs_if_exist:NF #1 { \tl_const:Nx #1 { #4 \s__fp \__fp_chk:w #2. This function is documented on page ??. since it is provided by the l3fp-round module.13822 13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842 13843 13844 13845 13846 \cs_generate_variant:Nn #1 { c } \cs_generate_variant:Nn #2 { c } } \__fp_tmp:w \fp_exp:Nn \fp_gexp:Nn \__fp_exp_o:w {exp} \__fp_assign_to:nNNNn \__fp_tmp:w \fp_ln:Nn \fp_gln:Nn \__fp_ln_o:w {ln } \__fp_assign_to:nNNNn \__fp_tmp:w \fp_sin:Nn \fp_gsin:Nn \__fp_sin_o:w {sin} \__fp_assign_to:nNNNn \__fp_tmp:w \fp_cos:Nn \fp_gcos:Nn \__fp_cos_o:w {cos} \__fp_assign_to:nNNNn \__fp_tmp:w \fp_tan:Nn \fp_gtan:Nn \__fp_tan_o:w {tan} \__fp_assign_to:nNNNn \cs_new_protected:Npn \__fp_assign_to:nNNNn #1#2#3#4#5 { \exp_after:wN \__fp_assign_to_i:wNNNn \tex_romannumeral:D -‘0 \__fp_parse:n {#5} {#1} #2#3#4 } \cs_new_protected:Npn \__fp_assign_to_i:wNNNn \s__fp \__fp_chk:w #1#2#3. \exp_after:wN \__fp_exponent:w #1 } } \cs_new_protected:Npn \fp_ground_figures:Nn #1#2 { \__fp_round_places:NNn \tl_gset:Nx #1 { #2 . These functions are documented on page ??. 13882 13883 13884 13885 13886 \lua_now_x:n \lua_now_x:x \lua_now:n \lua_now:x \lua_shipout_x:n \lua_shipout_x:x \lua_shipout:n \lua_shipout:x h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei When LuaTEX is in use. after shifting by the exponent of the argument.) \fp_round_figures:Nn \fp_ground_figures:Nn Rounding to a given number of figures is the same as rounding to a number of places.13864 13865 13866 13867 } } \cs_generate_variant:Nn \fp_round_places:Nn { c } \cs_generate_variant:Nn \fp_ground_places:Nn { c } (End definition for \fp_round_places:Nn and \fp_ground_places:Nn. for pdfTEX and XETEX the argument should be removed from the input stream before issuing an error. These functions are documented on page ??. This is expandable. On the other hand. 13868 13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879 \cs_new_protected:Npn \fp_round_figures:Nn #1#2 { \__fp_round_places:NNn \tl_set:Nx #1 { #2 .) 13880 40 13881 h/initex | packagei l3luatex implementation h*initex | packagei Announce and ensure that the required packages are loaded. this is all a question of primitives with new names.\exp_after:wN \__fp_exponent:w #1 } } \cs_generate_variant:Nn \fp_round_figures:Nn { c } \cs_generate_variant:Nn \fp_ground_figures:Nn { c } (End definition for \fp_round_figures:Nn and \fp_ground_figures:Nn. 13887 13888 13889 13890 13891 13892 13893 13894 13895 \luatex_if_engine:TF { \cs_new_eq:NN \lua_now_x:n \luatex_directlua:D \cs_new_eq:NN \lua_shipout_x:n \luatex_latelua:D } { \cs_new:Npn \lua_now_x:n #1 { \__msg_kernel_expandable_error:nnn 650 . using \__msg_kernel_expandable_error:nnn as done for V-type expansion in l3expan. To satisfy both of these requirements. These functions are documented on page ??. Here. 13913 13914 13915 13916 \int_new:N \g__cctab_allocate_int \int_set:Nn \g__cctab_allocate_int { \c_minus_one } \int_new:N \g__cctab_stack_int \seq_new:N \g__cctab_stack_seq (End definition for \g__cctab_allocate_int. Lownumbered tables are more efficiently-stored than high-numbered ones. therefore. This function is documented on page ??. both the read-only and stack tables need to be followed.1 13912 \g__cctab_allocate_int \g__cctab_stack_int \g__cctab_stack_seq Category code tables h@@=cctabi To allocate category code tables.) 40. There is also a need to have a stack of flexible tables as well as the set of read-only ones. the odd numbers are allocated.) \cctab_new:N Creating a new category code table is done slightly differently from other registers.{ kernel } { bad-engine } { \lua_now_x:n } } \cs_new_protected:Npn \lua_shipout_x:n #1 { \__msg_kernel_expandable_error:nnn { kernel } { bad-engine } { \lua_shipout_x:n } } 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 } \cs_generate_variant:Nn \lua_now_x:n { x \cs_new:Npn \lua_now:n #1 { \lua_now_x:n { \exp_not:n {#1} } } \cs_generate_variant:Nn \lua_now:n { x } \cs_generate_variant:Nn \lua_shipout_x:n \cs_new_protected:Npn \lua_shipout:n #1 { \lua_shipout_x:n { \exp_not:n {#1} } \cs_generate_variant:Nn \lua_shipout:n { } { x } } x } (End definition for \lua_now_x:n and \lua_now_x:x. There is also a sequence stack for the dynamic tables themselves. 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 \cs_new_protected:Npn \cctab_new:N #1 { \__chk_if_free_cs:N #1 \int_gadd:Nn \g__cctab_allocate_int { \c_two } \int_compare:nNnTF \g__cctab_allocate_int < { \c_max_register_int + \c_one } { \tex_global:D \tex_chardef:D #1 \g__cctab_allocate_int \luatex_initcatcodetable:D #1 } { \__msg_kernel_fatal:nnx { kernel } { out-of-registers } { cctab } } } \luatex_if_engine:F { 651 . odd numbered tables are used for read-only tables. and even ones for the stack. This function is documented on page 185. and actually having them as “in use” copies. This is done by using a stack of tables which are not read only. 13948 13949 13950 13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971 13972 13973 13974 13975 \cs_new_protected:Npn \cctab_begin:N #1 { \seq_gpush:Nx \g__cctab_stack_seq { \tex_the:D \luatex_catcodetable:D } \luatex_catcodetable:D #1 \int_gadd:Nn \g__cctab_stack_int { \c_two } \int_compare:nNnT \g__cctab_stack_int > \c_max_register_int { \__msg_kernel_fatal:nn { kernel } { cctab-stack-full } } \luatex_savecatcodetable:D \g__cctab_stack_int \luatex_catcodetable:D \g__cctab_stack_int } \cs_new_protected_nopar:Npn \cctab_end: { \int_gsub:Nn \g__cctab_stack_int { \c_two } \seq_if_empty:NTF \g__cctab_stack_seq { \tl_set:Nn \l__cctab_internal_tl { 0 } } { \seq_gpop:NN \g__cctab_stack_seq \l__cctab_internal_tl } \luatex_catcodetable:D \l__cctab_internal_tl \scan_stop: } \luatex_if_engine:F { \cs_set_protected:Npn \cctab_begin:N #1 { \__msg_kernel_error:nnxx { kernel } { bad-engine } { \exp_not:N \cctab_begin:N } {#1} } \cs_set_protected_nopar:Npn \cctab_end: { \__msg_kernel_error:nnx { kernel } { bad-engine } 652 .) \cctab_begin:N \cctab_end: \l__cctab_internal_tl The aim here is to ensure that the saved tables are read-only.13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 \cs_set_protected:Npn \cctab_new:N #1 { \__msg_kernel_error:nnx { kernel } { bad-engine } { \exp_not:N \cctab_new:N } } } h*packagei \luatex_if_engine:T { \cs_set_protected:Npn \cctab_new:N #1 { \__chk_if_free_cs:N #1 \newcatcodetable #1 \luatex_initcatcodetable:D #1 } } h/packagei (End definition for \cctab_new:N. This function is documented on page 185. 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011 14012 14013 \luatex_if_engine:T { \cctab_new:N \c_code_cctab \cctab_gset:Nn \c_code_cctab { } } h*packagei \luatex_if_engine:T { \cs_new_eq:NN \c_document_cctab \CatcodeTableLaTeX \cs_new_eq:NN \c_initex_cctab \CatcodeTableIniTeX \cs_new_eq:NN \c_other_cctab \CatcodeTableOther \cs_new_eq:NN \c_str_cctab \CatcodeTableString 653 .) \c_code_cctab \c_document_cctab \c_initex_cctab \c_other_cctab \c_str_cctab Creating category code tables is easy using the function above. This function is documented on page ??.) \cctab_gset:Nn Category code tables are always global. whereas when in package mode the rest can be copied from the existing LATEX 2ε package luatex. 13987 13988 13989 13990 13991 13992 13993 13994 13995 13996 13997 13998 13999 14000 14001 \cs_new_protected:Npn \cctab_gset:Nn #1#2 { \group_begin: #2 \luatex_savecatcodetable:D #1 \group_end: } \luatex_if_engine:F { \cs_set_protected:Npn \cctab_gset:Nn #1#2 { \__msg_kernel_error:nnxx { kernel } { bad-engine } { \exp_not:N \cctab_gset:Nn } { #1 {#2} } } } (End definition for \cctab_gset:Nn. so only one version is needed. The table for expl3 category codes is always needed.{ \exp_not:N \cctab_end: } 13976 13977 13978 13979 13980 13981 13982 13983 13984 13985 13986 } } h*packagei \luatex_if_engine:T { \cs_set_protected:Npn \cctab_begin:N #1 { \BeginCatcodeRegime #1 } \cs_set_protected_nopar:Npn \cctab_end: { \EndCatcodeRegime } } h/packagei \tl_new:N \l__cctab_internal_tl (End definition for \cctab_begin:N. The other and string ones are done by completely ignoring the existing codes as this makes life a lot less complex. and means that at the point of use there is no need to worry about escaping category codes. The set up here is simple. This function is documented on page 186. } { The~feature~you~are~using~is~only~available~ with~the~LuaTeX~engine. } { LaTeX~has~been~asked~to~switch~to~a~new~category~code~table. 654 . for removal by 2012-03-31.~ but~there~is~no~more~space~to~do~this! } 40. } \__msg_kernel_new:nnnn { kernel } { cctab-stack-full } { The~category~code~table~stack~is~exhausted.14014 14015 14016 14017 14018 14019 14020 14021 14022 14023 14024 14025 14026 14027 14028 14029 14030 14031 14032 14033 14034 14035 14036 14037 14038 14039 14040 14041 14042 } h/packagei h*initexi \luatex_if_engine:T { \cctab_new:N \c_document_cctab \cctab_new:N \c_other_cctab \cctab_new:N \c_str_cctab \cctab_gset:Nn \c_document_cctab { \char_set_catcode_space:n { 9 } \char_set_catcode_space:n { 32 } \char_set_catcode_other:n { 58 } \char_set_catcode_math_subscript:n { 95 } \char_set_catcode_active:n { 126 } } \cctab_gset:Nn \c_other_cctab { \int_step_inline:nnnn { 0 } { 1 } { 127 } { \char_set_catcode_other:n {#1} } } \cctab_gset:Nn \c_str_cctab { \int_step_inline:nnnn { 0 } { 1 } { 127 } { \char_set_catcode_other:n {#1} } \char_set_catcode_space:n { 32 } } } h/initexi (End definition for \c_code_cctab.2 14043 14044 14045 14046 14047 14048 14049 14050 14051 14052 14053 14054 Messages \__msg_kernel_new:nnnn { kernel } { bad-engine } { LuaTeX~engine~not~in~use!~Ignoring~#1.3 Deprecated functions Deprecated 2011-12-21.~LaTeX3~ignored~‘#1#2’.) 40. These variables are documented on page ??. the angle itself may be needed by the engine-dependent code. 14067 14068 \fp_new:N \l__box_cos_fp \fp_new:N \l__box_sin_fp (End definition for \l__box_cos_fp and \l__box_sin_fp. These variables are documented on page ??. 14066 \fp_new:N \l__box_angle_fp (End definition for \l__box_angle_fp. 14073 14074 14075 14076 \dim_new:N \dim_new:N \dim_new:N \dim_new:N \l__box_top_new_dim \l__box_bottom_new_dim \l__box_left_new_dim \l__box_right_new_dim (End definition for \l__box_top_new_dim and others. 14077 \box_new:N \l__box_internal_box 655 . 14069 14070 14071 14072 \dim_new:N \dim_new:N \dim_new:N \dim_new:N \l__box_top_dim \l__box_bottom_dim \l__box_left_dim \l__box_right_dim (End definition for \l__box_top_dim and others.) \l__box_top_new_dim \l__box_bottom_new_dim \l__box_left_new_dim \l__box_right_new_dim These are the positions of the four edges of a box after manipulation. This variable is documented on page ??.2 \l__box_angle_fp Additions to l3box Affine transformations When rotating boxes.\c_string_cctab 14055 14056 14057 h*deprecatedi \cs_new_eq:NN \c_string_cctab \c_str_cctab h/deprecatedi (End definition for \c_string_cctab.) \l__box_internal_box Scratch space. but also needed by some parts of the driver.) 14058 h/initex | packagei l3candidates Implementation 41 14059 14060 14061 14062 14063 14064 h*initex | packagei h*packagei \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \__expl_package_check: h/packagei 41.1 14065 h@@=boxi 41. This is done using the fp module so that the value is tidied up properly. These variables are documented on page 189.) \l__box_top_dim \l__box_bottom_dim \l__box_left_dim \l__box_right_dim These are the positions of the four edges of a box before manipulation.) \l__box_cos_fp \l__box_sin_fp These are used to hold the calculated sine and cosine values while carrying out a rotation. This variable is documented on page 189. ) \box_rotate:Nn Rotation of a box starts with working out the relevant sine and cosine. for a point P and 656 . D and E is illustrated (Figure 1). The vertex O is the reference point on the baseline. 14090 14091 14092 14093 14094 14095 \cs_new_protected:Npn \__box_rotate:N #1 { \dim_set:Nn \l__box_top_dim { \box_ht:N #1 } \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l__box_right_dim { \box_wd:N #1 } \dim_zero:N \l__box_left_dim The next step is to work out the x and y coordinates of vertices of the rotated box in relation to its original coordinates. and in this implementation is also the centre of rotation. The actual \__box_rotate:N rotation is in an auxiliary to keep the flow slightly clearer \__box_rotate_x:nnN 14078 \cs_new_protected:Npn \box_rotate:Nn #1#2 \__box_rotate_y:nnN 14079 { 14080 \hbox_set:Nn #1 \__box_rotate_quadrant_one: 14081 { \__box_rotate_quadrant_two: \group_begin: \__box_rotate_quadrant_three: 14082 14083 \fp_set:Nn \l__box_angle_fp {#2} \__box_rotate_quadrant_four: 14084 \fp_set:Nn \l__box_sin_fp { sin ( \l__box_angle_fp * deg ) } 14085 \fp_set:Nn \l__box_cos_fp { cos ( \l__box_angle_fp * deg ) } 14086 \__box_rotate:N #1 14087 \group_end: 14088 } 14089 } The edges of the box are then recorded: the left edge will always be at zero. C. This variable is documented on page 189. Rotation of the four edges then takes place: this is most efficiently done on a quadrant by quadrant basis. The formulae are.C B O A D E Figure 1: Co-ordinates of a box prior to rotation. (End definition for \l__box_internal_box. The box can be visualized with vertices B. Each function gives only one component 657 . #2) and rotate its location about the origin.) \fp_compare:nNnTF \l__box_sin_fp > \c_zero_fp { \fp_compare:nNnTF \l__box_cos_fp > \c_zero_fp { \__box_rotate_quadrant_one: } { \__box_rotate_quadrant_two: } } { \fp_compare:nNnTF \l__box_cos_fp < \c_zero_fp { \__box_rotate_quadrant_three: } { \__box_rotate_quadrant_four: } } 14096 14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 The position of the box edges are now known. The result can then be used to reset the original box. this part of the calculation is omitted here. but the box at this stage be misplaced relative to the current TEX reference point. This is desirable as TEX boxes must have the reference point at the left edge of the box. So the content of the box is moved such that the reference point of the rotated box will be in the same place as the original.angle α: Px0 = Px − Ox Py0 = Py − Oy Px00 = (Px0 cos(α)) − (Py0 sin(α)) Py00 = (Px0 sin(α)) + (Py0 cos(α)) Px000 = Px00 + Ox + Lx Py000 = Py00 + Oy The “extra” horizontal translation Lx at the end is calculated so that the leftmost point of the resulting box has x-coordinate 0. (As O is always (0.\l__box_left_new_dim } \box_use:N \l__box_internal_box 14118 14119 14120 14121 14122 14123 } These functions take a general point (#1. using the previously-set sine and cosine values. 0). \box_set_ht:Nn \l__box_internal_box { \l__box_top_new_dim } \box_set_dp:Nn \l__box_internal_box { -\l__box_bottom_new_dim } \box_set_wd:Nn \l__box_internal_box { \l__box_right_new_dim . \hbox_set:Nn \l__box_internal_box { \box_use:N #1 } \hbox_set:Nn \l__box_internal_box { \tex_kern:D -\l__box_left_new_dim \hbox:n { \__driver_box_rotate_begin: \box_use:N \l__box_internal_box \__driver_box_rotate_end: } } 14107 14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 Tidy up the size of the box so that the material is actually inside the bounding box. the top and bottom edges only need the resulting y-values. 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 \cs_new_protected:Npn \__box_rotate_quadrant_one: { \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim \l__box_top_new_dim \__box_rotate_y:nnN \l__box_left_dim \l__box_bottom_dim \l__box_bottom_new_dim \__box_rotate_x:nnN \l__box_left_dim \l__box_top_dim \l__box_left_new_dim \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim \l__box_right_new_dim } \cs_new_protected:Npn \__box_rotate_quadrant_two: { \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim \l__box_top_new_dim \__box_rotate_y:nnN \l__box_left_dim \l__box_top_dim \l__box_bottom_new_dim 658 . Each case is a question of picking out which corner ends up at with the maximum top. left and right value. This is because for rotation of a box each step needs only one value.( \l__box_sin_fp * \dim_to_fp:n {#2} ) } } } \cs_new_protected:Npn \__box_rotate_y:nnN #1#2#3 { \dim_set:Nn #3 { \fp_to_dim:n { \l__box_sin_fp * \dim_to_fp:n {#1} + \l__box_cos_fp * \dim_to_fp:n {#2} } } } Rotation of the edges is done using a different formula for each quadrant.of the location of the updated point. Contrast this with the equivalent function in the l3coffins module. and so performance is gained by avoiding working out both x0 and y 0 at the same time. 14124 14125 14126 14127 14128 14129 14130 14131 14132 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 \cs_new_protected:Npn \__box_rotate_x:nnN #1#2#3 { \dim_set:Nn #3 { \fp_to_dim:n { \l__box_cos_fp * \dim_to_fp:n {#1} . where both parts are needed. Doing this by hand means a lot less calculating and avoids lots of comparisons. whereas the left and right edges need the x-values. bottom. In every case. 14192 14193 14194 14195 14196 14197 14198 14199 14200 \cs_new_protected:Npn { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \dim_set:Nn \dim_set:Nn \dim_zero:N \box_resize:Nnn #1#2#3 \l__box_top_dim { \box_ht:N #1 } \l__box_bottom_dim { -\box_dp:N #1 } \l__box_right_dim { \box_wd:N #1 } \l__box_left_dim The x-scaling and resulting box size is easy enough to work out: the dimension is that given as #2. These variables are documented on page 189. 14201 14202 \fp_set:Nn \l__box_scale_x_fp { \dim_to_fp:n {#2} / ( \dim_to_fp:n \l__box_right_dim ) } 659 .) \box_resize:Nnn \box_resize:cnn \__box_resize:Nnn Resizing a box starts by working out the various dimensions of the existing box. 14190 14191 \fp_new:N \l__box_scale_x_fp \fp_new:N \l__box_scale_y_fp (End definition for \l__box_scale_x_fp and \l__box_scale_y_fp.) \l__box_scale_x_fp \l__box_scale_y_fp Scaling is potentially-different in the two axes.14163 14164 14165 14166 14167 14168 14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189 \__box_rotate_x:nnN \l__box_right_dim \l__box_left_new_dim \__box_rotate_x:nnN \l__box_left_dim \l__box_right_new_dim \l__box_top_dim \l__box_bottom_dim } \cs_new_protected:Npn \__box_rotate_quadrant_three: { \__box_rotate_y:nnN \l__box_left_dim \l__box_bottom_dim \l__box_top_new_dim \__box_rotate_y:nnN \l__box_right_dim \l__box_top_dim \l__box_bottom_new_dim \__box_rotate_x:nnN \l__box_right_dim \l__box_bottom_dim \l__box_left_new_dim \__box_rotate_x:nnN \l__box_left_dim \l__box_top_dim \l__box_right_new_dim } \cs_new_protected:Npn \__box_rotate_quadrant_four: { \__box_rotate_y:nnN \l__box_left_dim \l__box_top_dim \l__box_top_new_dim \__box_rotate_y:nnN \l__box_right_dim \l__box_bottom_dim \l__box_bottom_new_dim \__box_rotate_x:nnN \l__box_left_dim \l__box_bottom_dim \l__box_left_new_dim \__box_rotate_x:nnN \l__box_right_dim \l__box_top_dim \l__box_right_new_dim } (End definition for \box_rotate:Nn. This function is documented on page 188. and the scale is simply the new width divided by the old one. In the x direction this is relatively easy: just scale the right edge. 14213 14214 14215 14216 14217 14218 14219 14220 14221 \cs_new_protected:Npn \__box_resize:Nnn #1#2#3 { \dim_set:Nn \l__box_right_new_dim { \dim_abs:n {#2} } \dim_set:Nn \l__box_bottom_new_dim { \fp_abs:n { \l__box_scale_y_fp } \l__box_bottom_dim } \dim_set:Nn \l__box_top_new_dim { \fp_abs:n { \l__box_scale_y_fp } \l__box_top_dim } \__box_resize_common:N #1 } (End definition for \box_resize:Nnn and \box_resize:cnn. 14208 14209 14210 14211 14212 \__box_resize:Nnn #1 {#2} {#3} \group_end: } } \cs_generate_variant:Nn \box_resize:Nnn { c } With at least one real scaling to do. and this again needs the absolute scale value.) \box_resize_to_ht_plus_dp:Nn \box_resize_to_ht_plus_dp:cn \box_resize_to_wd:Nn \box_resize_to_wd:cn Scaling to a total height or to a width is a simplified version of the main resizing operation.The y-scaling needs both the height and the depth of the current box. the next phase is to find the new edge co-ordinates. as the sign for both parts is needed (as this allows the same internal code to be used as for the general case). The internal auxiliary is called using the scaling value twice. These functions are documented on page ??.\l__box_bottom_dim } ) } 660 . 14222 14223 14224 14225 14226 14227 14228 14229 14230 14231 14232 14233 14234 14235 \cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2 { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \l__box_top_dim { \box_ht:N #1 } \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l__box_right_dim { \box_wd:N #1 } \dim_zero:N \l__box_left_dim \fp_set:Nn \l__box_scale_y_fp { \dim_to_fp:n {#2} / ( \dim_to_fp:n { \l__box_top_dim . In the y direction.\l__box_bottom_dim } ) } Hand off to the auxiliary which does the work. 14203 14204 14205 14206 14207 \fp_set:Nn \l__box_scale_y_fp { \dim_to_fp:n {#3} / ( \dim_to_fp:n { \l__box_top_dim . both dimensions have to be scaled. Once that is all done. with the scale simply copied between the two parts. the common resize/rescale code can be employed. This is done using the absolute value of the scale so that the new edge is in the correct place. 14236 14237 14238 14239 14240 14241 14242 14243 14244 14245 14246 14247 14248 14249 14250 14251 14252 14253 14254 14255 14256 14257 14258 \fp_set_eq:NN \l__box_scale_x_fp \l__box_scale_y_fp \__box_resize:Nnn #1 {#2} {#2} \group_end: } } \cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c } \cs_new_protected:Npn \box_resize_to_wd:Nn #1#2 { \hbox_set:Nn #1 { \group_begin: \dim_set:Nn \l__box_top_dim { \box_ht:N #1 } \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l__box_right_dim { \box_wd:N #1 } \dim_zero:N \l__box_left_dim \fp_set:Nn \l__box_scale_x_fp { \dim_to_fp:n {#2} / ( \dim_to_fp:n \l__box_right_dim ) } \fp_set_eq:NN \l__box_scale_y_fp \l__box_scale_x_fp \__box_resize:Nnn #1 {#2} {#2} \group_end: } } \cs_generate_variant:Nn \box_resize_to_wd:Nn { c } (End definition for \box_resize_to_ht_plus_dp:Nn and \box_resize_to_ht_plus_dp:cn.) \box_scale:Nnn \box_scale:cnn When scaling a box. 14259 14260 14261 14262 14263 14264 14265 14266 14267 14268 14269 14270 14271 14272 14273 14274 14275 14276 \cs_new_protected:Npn \box_scale:Nnn #1#2#3 { \hbox_set:Nn #1 { \group_begin: \fp_set:Nn \l__box_scale_x_fp {#2} \fp_set:Nn \l__box_scale_y_fp {#3} \dim_set:Nn \l__box_top_dim { \box_ht:N #1 } \dim_set:Nn \l__box_bottom_dim { -\box_dp:N #1 } \dim_set:Nn \l__box_right_dim { \box_wd:N #1 } \dim_zero:N \l__box_left_dim \dim_set:Nn \l__box_top_new_dim { \fp_abs:n { \l__box_scale_y_fp } \l__box_top_dim } \dim_set:Nn \l__box_bottom_new_dim { \fp_abs:n { \l__box_scale_y_fp } \l__box_bottom_dim } \dim_set:Nn \l__box_right_new_dim { \fp_abs:n { \l__box_scale_x_fp } \l__box_right_dim } \__box_resize_common:N #1 661 . Once that is done then after a check for the trivial scaling a hand-off can be made to the common code. The new dimensions are also relatively easy to find. allowing only for the need to keep them positive in all cases. These functions are documented on page ??. setting the scaling itself is easy enough. The dimension scaling operations are carried out using the TEX mechanism as it avoids needing to use too many fp operations. ) \__box_resize_common:N The main resize function places in input into a box which will start of with zero width. However. for case of a negative scaling the material must be shifted such that the reference point ends up in the right place. as the reference point needs to remain unchanged.\group_end: 14277 } 14278 14279 14280 } \cs_generate_variant:Nn \box_scale:Nnn { c } (End definition for \box_scale:Nnn and \box_scale:cnn. \fp_compare:nNnTF \l__box_scale_x_fp < \c_zero_fp { \hbox_to_wd:nn { \l__box_right_new_dim } { \tex_kern:D \l__box_right_new_dim \box_use:N \l__box_internal_box \tex_hss:D } } { \box_set_wd:Nn \l__box_internal_box { \l__box_right_new_dim } \hbox:n { \tex_kern:D \c_zero_dim \box_use:N \l__box_internal_box \tex_hss:D } } 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300 14301 14302 14303 14304 14305 14306 14307 14308 14309 } (End definition for \__box_resize_common:N.) 662 . 14281 14282 14283 14284 14285 14286 14287 14288 \cs_new_protected:Npn \__box_resize_common:N #1 { \hbox_set:Nn \l__box_internal_box { \__driver_box_scale_begin: \hbox_overlap_right:n { \box_use:N #1 } \__driver_box_scale_end: } The new height and depth can be applied directly. and includes the handles for engine rescaling. These functions are documented on page ??. \box_set_ht:Nn \l__box_internal_box { \l__box_top_new_dim } \box_set_dp:Nn \l__box_internal_box { \l__box_bottom_new_dim } 14289 14290 Things are not quite as obvious for the width. For positive scaling factors resizing the box is all that is needed. 41. 14338 14339 14340 14341 14342 14343 \dim_compare:nNnTF { \box_ht:N \l__box_internal_box } > {#5} { \hbox_set:Nn \l__box_internal_box { \box_move_up:nn \c_zero_dim { \box_use:N \l__box_internal_box } } \box_set_ht:Nn \l__box_internal_box { \box_ht:N \l__box_internal_box .(#5) } 663 . These functions are documented on page ??. Material always has to stay on the correct side. The internal box is used here as it allows safe use of \box_set_dp:Nn. or if not move down so the result is zero depth.(#3) } } { \hbox_set:Nn \l__box_internal_box { \box_move_down:nn { #3 . 14321 14322 14323 14324 14325 14326 14327 14328 14329 14330 14331 14332 14333 14334 14335 14336 14337 \dim_compare:nNnTF { \box_dp:N #1 } > {#3} { \hbox_set:Nn \l__box_internal_box { \box_move_down:nn \c_zero_dim { \box_use:N \l__box_internal_box } } \box_set_dp:Nn \l__box_internal_box { \box_dp:N #1 . so trimming has to check that there is enough material to trim. simply set the depth.) \box_trim:Nnnnn \box_trim:cnnnn Trimming from the left.and right-hand edges of the box is easy: kern the appropriate parts off each side. 14310 14311 14312 \cs_new_protected:Npn \box_clip:N #1 { \hbox_set:Nn #1 { \__driver_box_use_clip:N #1 } } \cs_generate_variant:Nn \box_clip:N { c } (End definition for \box_clip:N and \box_clip:c. this time from the top of the box.\box_dp:N #1 } { \box_use:N \l__box_internal_box } } \box_set_dp:Nn \l__box_internal_box \c_zero_dim } Same thing.3 \box_clip:N \box_clip:c Viewing part of a box A wrapper around the driver-dependent code. there is a need to watch the baseline is respected. 14313 14314 14315 14316 14317 14318 14319 14320 \cs_new_protected:Npn \box_trim:Nnnnn #1#2#3#4#5 { \hbox_set:Nn \l__box_internal_box { \tex_kern:D -\__dim_eval:w #2 \__dim_eval_end: \box_use:N #1 \tex_kern:D -\__dim_eval:w #4 \__dim_eval_end: } For the height and depth. First. If there is enough depth. the bottom edge. \box_move_down:nn is used in both cases so the resulting box always contains a \lower primitive. ) \box_viewport:Nnnnn \box_viewport:cnnnn The same general logic as for the trim operation. 14356 14357 14358 14359 14360 14361 14362 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372 14373 14374 14375 14376 14377 14378 14379 14380 14381 14382 14383 14384 14385 14386 14387 14388 \cs_new_protected:Npn \box_viewport:Nnnnn #1#2#3#4#5 { \hbox_set:Nn \l__box_internal_box { \tex_kern:D -\__dim_eval:w #2 \__dim_eval_end: \box_use:N #1 \tex_kern:D \__dim_eval:w #4 . but with absolute dimensions. These functions are documented on page ??. As a result.\box_wd:N #1 \__dim_eval_end: } \dim_compare:nNnTF {#3} < \c_zero_dim { \hbox_set:Nn \l__box_internal_box { \box_move_down:nn \c_zero_dim { \box_use:N \l__box_internal_box } } \box_set_dp:Nn \l__box_internal_box { -\dim_eval:n {#3} } } { \hbox_set:Nn \l__box_internal_box { \box_move_down:nn {#3} { \box_use:N \l__box_internal_box } } \box_set_dp:Nn \l__box_internal_box \c_zero_dim } \dim_compare:nNnTF {#5} > \c_zero_dim { \hbox_set:Nn \l__box_internal_box { \box_move_up:nn \c_zero_dim { \box_use:N \l__box_internal_box } } \box_set_ht:Nn \l__box_internal_box { #5 \dim_compare:nNnT {#3} > \c_zero_dim { .14344 14345 14346 14347 14348 14349 14350 14351 14352 14353 14354 14355 } { \hbox_set:Nn \l__box_internal_box { \box_move_up:nn { #5 . there are some things to watch out for in the vertical direction.\box_ht:N \l__box_internal_box } { \box_use:N \l__box_internal_box } } \box_set_ht:Nn \l__box_internal_box \c_zero_dim } \box_set_eq:NN #1 \l__box_internal_box } \cs_generate_variant:Nn \box_trim:Nnnnn { c } (End definition for \box_trim:Nnnnn and \box_trim:cnnnn.(#3) } } } 664 . otherwise. { \int_compare:nNnTF {#1} = \c_zero 665 . The loop itself is very simple. 14401 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 14417 14418 14419 14420 14421 14422 14423 14424 14425 14426 \cs_new:Npn \clist_item:Nn #1#2 { \exp_args:Nfo \__clist_item:nnNn { \clist_count:N #1 } #1 \__clist_item_N_loop:nw {#2} } \cs_new:Npn \__clist_item:nnNn #1#2#3#4 { \int_compare:nNnTF {#4} < \c_zero { \int_compare:nNnTF {#4} < { .#1 } { \use_none_delimit_by_q_stop:w } { \exp_args:Nf #3 { \int_eval:n { #4 + \c_one + #1 } } } } { \int_compare:nNnTF {#4} > {#1} { \use_none_delimit_by_q_stop:w } { #3 {#4} } } { } . These functions are documented on page ??. #2 . but not less than −hlengthi. \q_stop } \cs_new:Npn \__clist_item_N_loop:nw #1 #2. decrease the counter and repeat.) 41. or more than hlengthi.{ 14389 \hbox_set:Nn \l__box_internal_box { \box_move_up:nn { -\dim_eval:n {#5} } { \box_use:N \l__box_internal_box } } \box_set_ht:Nn \l__box_internal_box \c_zero_dim 14390 14391 14392 14393 14394 14395 } \box_set_eq:NN #1 \l__box_internal_box 14396 14397 14398 14399 } \cs_generate_variant:Nn \box_viewport:Nnnnn { c } (End definition for \box_viewport:Nnnnn and \box_viewport:cnnnn. If it is negative.4 14400 \clist_item:Nn \clist_item:cn \__clist_item:nnNn \__clist_item_N_loop:nw Additions to l3clist h@@=clisti To avoid needing to test the end of the list at each step. we first compute the hlengthi of the list. the result is empty. return the item if the counter reached 1. less than −hlengthi. If the item number is 0. add hlengthi + 1 to the item number before performing the loop. } \cs_new:Npn \__clist_item_n_strip:w #1 . { \exp_args:No \tl_if_blank:nTF {#2} { \__clist_item_n_loop:nw {#1} \prg_do_nothing: } { \int_compare:nNnTF {#1} = \c_zero { \exp_args:No \__clist_item_n_end:n {#2} } { \exp_args:Nf \__clist_item_n_loop:nw { \int_eval:n { #1 .) \clist_item:nn \__clist_item_n:nw \__clist_item_n_loop:nw \__clist_item_n_end:n \__clist_item_n_strip:w This starts in the same way as \clist_item:Nn by counting the items of the comma list.14427 14428 14429 14430 { \use_i_delimit_by_q_stop:nw { \exp_not:n {#2} } } { \exp_args:Nf \__clist_item_N_loop:nw { \int_eval:n { #1 . and a comma. The first comma must be removed. except in the case of an empty comma-list. 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442 14443 14444 14445 14446 14447 14448 14449 14450 14451 14452 14453 14454 14455 14456 14457 14458 14459 14460 \cs_new:Npn \clist_item:nn #1#2 { \exp_args:Nf \__clist_item:nnNn { \clist_count:n {#1} } {#1} \__clist_item_n:nw {#2} } \cs_new:Npn \__clist_item_n:nw #1 { \__clist_item_n_loop:nw {#1} \prg_do_nothing: } \cs_new:Npn \__clist_item_n_loop:nw #1 #2.1 } } } } \cs_generate_variant:Nn \clist_item:Nn { c } (End definition for \clist_item:Nn and \clist_item:cn. Blank items are ignored. These functions are documented on page ??. 14461 14462 14463 14464 \cs_new_protected:Npn \clist_set_from_seq:NN { \__clist_set_from_seq:NNNN \clist_clear:N \tl_set:Nx } \cs_new_protected:Npn \clist_gset_from_seq:NN { \__clist_set_from_seq:NNNN \clist_gclear:N \tl_gset:Nx } 666 . hence we insert a couple of odd-looking \prg_do_nothing: to avoid losing braces. { \exp_not:n {#1} } (End definition for \clist_item:nn. This function is documented on page ??. We wrap most items with \exp_not:n. The final item should be space-trimmed before being brace-stripped. Items which contain a comma or a space are surrounded by an extra set of braces.) \clist_set_from_seq:NN \clist_set_from_seq:cN \clist_set_from_seq:Nc \clist_set_from_seq:cc \clist_gset_from_seq:NN \clist_gset_from_seq:cN \clist_gset_from_seq:Nc \clist_gset_from_seq:cc \__clist_set_from_seq:NNNN \__clist_wrap_item:n \__clist_set_from_seq:w Setting a comma list from a comma-separated list is done using a simple mapping.1 } } \prg_do_nothing: } } } \cs_new:Npn \__clist_item_n_end:n #1 #2 \q_stop { \__tl_trim_spaces:nn { \q_mark #1 } { \exp_last_unbraced:No \__clist_item_n_strip:w } . grab the next one. These functions are documented on page ??. this particular variant of the emptyness test is optimized).) \clist_if_empty_p:n \clist_if_empty:nTF \__clist_if_empty_n:w \__clist_if_empty_n:wNw As usual. If the item of the comma list is blank.) \clist_const:Nn \clist_const:cn \clist_const:Nx \clist_const:cx Creating and initializing a constant comma list is done in a way similar to \clist_set:Nn and \clist_gset:Nn. cc } \cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } \cs_generate_variant:Nn \clist_gset_from_seq:NN { c . we insert a token (here ?) before grabbing any argument: this avoids losing braces. #1 ~ } { \exp_not:n {#1} } { \exp_not:n { {#1} } } } \cs_new:Npn \__clist_set_from_seq:w #1 . being careful to strip spaces. unless every item in the comma list was blank and the loop actually got broken by the trailing \q_mark \prg_return_false: item. \q_mark \prg_return_true: \q_stop } \cs_new:Npn \__clist_if_empty_n:w #1 . As soon as one item is non-blank. cc } (End definition for \clist_set_from_seq:NN and others.14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475 14476 14477 14478 14479 14480 14481 14482 14483 14484 14485 14486 14487 14488 \cs_new_protected:Npn \__clist_set_from_seq:NNNN #1#2#3#4 { \seq_if_empty:NTF #4 { #1 #3 } { #2 #3 { \exp_last_unbraced:Nf \use_none:n { \seq_map_function:NN #4 \__clist_wrap_item:n } } } } \cs_new:Npn \__clist_wrap_item:n #1 { . \q_mark \prg_return_false: . \tl_if_empty:oTF { \__clist_set_from_seq:w #1 ~ . The argument of \tl_if_empty:oTF is empty if #1 is ? followed by blank spaces (besides. #2 ~ { } \cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } \cs_generate_variant:Nn \clist_set_from_seq:NN { c . F . cx } (End definition for \clist_const:Nn and others. T . Nx . These functions are documented on page ??. TF } { \__clist_if_empty_n:w ? #1 . { 667 . 14489 14490 14491 \cs_new_protected:Npn \clist_const:Nn #1#2 { \tl_const:Nx #1 { \__clist_trim_spaces:n {#2} } } \cs_generate_variant:Nn \clist_const:Nn { c . 14492 14493 14494 14495 14496 14497 14498 14499 14500 \prg_new_conditional:Npnn \clist_if_empty:n #1 { p . exit: the second auxiliary will grab \prg_return_false: as #2. the three items really belong to the comma list. Otherwise. If it has one item. the first \q_mark is taken as a delimiter to the use_ii function. \q_mark is taken as a third item. 2. { \__clist_use:nwwwwnwn {#3} } \q_mark . When we reach the last two items of the original token list. and the continuation is use_ii itself. #4 . If it has none. and 8: the temporary result. #3 { \exp_not:n { #1 #3 #2 } } \cs_new:Npn \__clist_use:nwwwwnwn #1#2 . #2 . use_iii. 6: a hcontinuationi function (use_ii or use_iii with its hseparatori argument). which is built in a brace group following \q_stop. output nothing. \__clist_use:nwwwwnwn takes the following arguments. place the hseparator between twoi in the middle. and now the seconf \q_mark serves as a delimiter to use_ii. 14506 14507 14508 14509 14510 14511 14512 14513 14514 14515 14516 14517 14518 14519 14520 14521 14522 14523 14524 14525 14526 14527 14528 14529 14530 14531 \cs_new:Npn \clist_use:Nnnn #1#2#3#4 { \clist_if_exist:NTF #1 { \int_case:nnn { \clist_count:N #1 } { { 0 } { } { 1 } { \exp_after:wN \__clist_use:wwn #1 . If it has two. { } } { 2 } { \exp_after:wN \__clist_use:wwn #1 . switching to the other hcontinuationi.14501 14502 14503 14504 14505 \tl_if_empty:oTF { \use_none:nn #1 ? } { \__clist_if_empty_n:w ? } { \__clist_if_empty_n:wNw } } \cs_new:Npn \__clist_if_empty_n:wNw #1 \q_mark #2#3 \q_stop {#2} (End definition for \clist_if_empty:n. #3 . output that item. which uses the hseparator between final twoi. { \__clist_use:nwwn {#4} } \q_stop { } } } { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } } \cs_new:Npn \__clist_use:wwn #1 . then we use the hcontinuationi. 4: three items from the comma list (or quarks). The hseparatori and the first of the three items are placed in the result. 5: the rest of the comma list. 7: junk. {#4} . #5 \q_mark . Then count the items in the comma list. {#6} #7 \q_stop { #8 #1 #2 } } \cs_new:Npn \__clist_use:nwwn #1#2 . 3. These functions are documented on page 190. .) \clist_use:Nnnn \__clist_use:wwn \__clist_use:nwwwwnwn \__clist_use:nwwn First check that the variable exists. \q_mark . #6#7 \q_stop #8 { #6 {#3} . #3 \q_stop #4 { \exp_not:n { #4 #1 #2 } } 668 . {#2} } } { \exp_after:wN \__clist_use:nwwwwnwn \exp_after:wN { \exp_after:wN } #1 . placing the remaining two items after it. #5 \q_mark . 1: a hseparatori. brace stripped (note that space-trimming has already been done when the comma list was assigned). When we begin this loop. which are carried through unchanged for the rest of the procedure. 14537 14538 14539 14540 \dim_new:N \dim_new:N \dim_new:N \dim_new:N \l__coffin_left_corner_dim \l__coffin_right_corner_dim \l__coffin_bottom_corner_dim \l__coffin_top_corner_dim (End definition for \l__coffin_left_corner_dim. This variable is documented on page ??. 14535 \prop_new:N \l__coffin_bounding_prop (End definition for \l__coffin_bounding_prop. 14541 14542 14543 14544 \cs_new_protected:Npn \coffin_rotate:Nn #1#2 { \fp_set:Nn \l__coffin_sin_fp { sin ( ( #2 ) * deg ) } \fp_set:Nn \l__coffin_cos_fp { cos ( ( #2 ) * deg ) } The corners and poles of the coffin can now be rotated around the origin.) \l__coffin_bounding_prop A property list for the bounding box of a coffin. 14533 14534 \fp_new:N \l__coffin_sin_fp \fp_new:N \l__coffin_cos_fp (End definition for \l__coffin_sin_fp.) 41. This function is documented on page 191. so there is just the one. This function is documented on page ??.(End definition for \clist_use:Nnnn. This function is documented on page ??.5 14532 h@@=coffini 41. The first step is to convert the angle given in degrees to one in radians. This is best achieved using mapping functions. 14536 \dim_new:N \l__coffin_bounding_shift_dim (End definition for \l__coffin_bounding_shift_dim. This variable is documented on page ??. This is then used to set \l__coffin_sin_fp and \l__coffin_cos_fp.) \coffin_rotate:Nn \coffin_rotate:cn Rotating a coffin requires several steps which can be conveniently run together.) \l__coffin_bounding_shift_dim The shift of the bounding box of a coffin from the real content.6 \l__coffin_sin_fp \l__coffin_cos_fp Additions to l3coffins Rotating coffins Used for rotations to get the sine and cosine values. 14545 14546 14547 14548 \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_rotate_corner:Nnnn #1 {##1} ##2 } \prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop } { \__coffin_rotate_pole:Nnnnnn #1 {##1} ##2 } 669 . This is only needed during the rotation.) \l__coffin_left_corner_dim \l__coffin_right_corner_dim \l__coffin_bottom_corner_dim \l__coffin_top_corner_dim These are used to hold maxima for the various corner values: these thus define the minimum size of the bounding box after rotation. \l__coffin_bottom_corner_dim } \box_set_dp:Nn \l__coffin_internal_box { 0 pt } \box_set_wd:Nn \l__coffin_internal_box { \l__coffin_right_corner_dim .\l__coffin_left_corner_dim \__dim_eval_end: \box_move_down:nn { \l__coffin_bottom_corner_dim } { \box_use:N #1 } } If there have been any previous rotations then the size of the bounding box will be bigger than the contents. 14564 14565 14566 14567 14568 14569 \box_set_ht:Nn \l__coffin_internal_box { \l__coffin_top_corner_dim . The x-direction is handled by moving the content by the difference in the positions of the bounding box and the content left edge. 14552 14553 14554 \__coffin_find_corner_maxima:N #1 \__coffin_find_bounding_shift: \box_rotate:Nn #1 {#2} The correction of the box position itself takes place here. The y-direction is dealt with by moving the box down by any depth it has acquired. the safe way to do this is to use the internal box and to reset the result into the target box. The internal box is used here to allow for the next step. and to do this the corners have to be found first. As this operation requires setting box dimensions and these transcend grouping. 14555 14556 14557 14558 14559 14560 14561 14562 14563 \hbox_set:Nn \l__coffin_internal_box { \tex_kern:D \__dim_eval:w \l__coffin_bounding_shift_dim . This can be corrected easily by setting the size of the box to the height and width of the content. 14570 14571 14572 14573 14574 14575 \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_shift_corner:Nnnn #1 {##1} ##2 } \prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop } { \__coffin_shift_pole:Nnnnnn #1 {##1} ##2 } } \cs_generate_variant:Nn \coffin_rotate:Nn { c } 670 . there needs to be a calculation to find where the corners of the content and the box itself will end up. 14549 14550 14551 \__coffin_set_bounding:N #1 \prop_map_inline:Nn \l__coffin_bounding_prop { \__coffin_rotate_bounding:nnn {##1} ##2 } At this stage.\l__coffin_left_corner_dim } \hbox_set:Nn #1 { \box_use:N \l__coffin_internal_box } The final task is to move the poles and corners such that they are back in alignment with the box reference point. and has the reference point at the bottom-left. They are then rotated in the same way as the corners of the coffin material itself.The bounding box of the coffin needs to be rotated. The idea is that the bounding box for a coffin is tight up to the content. ) \__coffin_rotate_pole:Nnnnnn Rotating a single pole simply means shifting the co-ordinate of the pole and its direction.\box_dp:N #1 } \prop_put:Nnx \l__coffin_bounding_prop { bl } { { 0 pt } { \dim_use:N \l__coffin_internal_dim } } \prop_put:Nnx \l__coffin_bounding_prop { br } { { \dim_use:N \box_wd:N #1 } { \dim_use:N \l__coffin_internal_dim } } } (End definition for \__coffin_set_bounding:N. The same treatment is used for the corners of the material itself and the bounding box. These functions are documented on page ??. This function is documented on page ??.) \__coffin_rotate_bounding:nnn Rotating the position of the corner of the coffin is just a case of treating this as a vector \__coffin_rotate_corner:Nnnn from the reference point.) \__coffin_set_bounding:N The bounding box corners for a coffin are easy enough to find: this is the same code as for the corners of the material itself.(End definition for \coffin_rotate:Nn and \coffin_rotate:cn. 14600 14601 14602 14603 14604 14605 14606 14607 14608 14609 14610 14611 \cs_new_protected:Npn \__coffin_rotate_pole:Nnnnnn #1#2#3#4#5#6 { \__coffin_rotate_vector:nnNN {#3} {#4} \l__coffin_x_dim \l__coffin_y_dim \__coffin_rotate_vector:nnNN {#5} {#6} \l__coffin_x_prime_dim \l__coffin_y_prime_dim \__coffin_set_pole:Nnx #1 {#2} { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } { \dim_use:N \l__coffin_x_prime_dim } { \dim_use:N \l__coffin_y_prime_dim } } } 671 . 14576 14577 14578 14579 14580 14581 14582 14583 14584 14585 14586 14587 \cs_new_protected:Npn \__coffin_set_bounding:N #1 { \prop_put:Nnx \l__coffin_bounding_prop { tl } { { 0 pt } { \dim_use:N \box_ht:N #1 } } \prop_put:Nnx \l__coffin_bounding_prop { tr } { { \dim_use:N \box_wd:N #1 } { \dim_use:N \box_ht:N #1 } } \dim_set:Nn \l__coffin_internal_dim { . but using a dedicated property list. The rotation here is about the bottom-left corner of the coffin. 14588 14589 14590 14591 14592 14593 14594 14595 14596 14597 14598 14599 \cs_new_protected:Npn \__coffin_rotate_bounding:nnn #1#2#3 { \__coffin_rotate_vector:nnNN {#2} {#3} \l__coffin_x_dim \l__coffin_y_dim \prop_put:Nnx \l__coffin_bounding_prop {#1} { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } } } \cs_new_protected:Npn \__coffin_rotate_corner:Nnnn #1#2#3#4 { \__coffin_rotate_vector:nnNN {#3} {#4} \l__coffin_x_dim \l__coffin_y_dim \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } {#2} { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } } } (End definition for \__coffin_rotate_bounding:nnn. This function is documented on page ??. This function is documented on page ??. This function is documented on page ??. The values start at the maximum dimensions so that the case where all are positive or all are negative works out correctly. The values \l__coffin_cos_fp and \l__coffin_sin_fp should previously have been set up correctly.) \__coffin_rotate_vector:nnNN A rotation function. after all. which needs only an input vector (as dimensions) and an output space.( \dim_to_fp:n {#2} * \l__coffin_sin_fp ) } } \dim_set:Nn #4 { \fp_to_dim:n { \dim_to_fp:n {#1} * \l__coffin_sin_fp + ( \dim_to_fp:n {#2} * \l__coffin_cos_fp ) } } } (End definition for \__coffin_rotate_vector:nnNN.) \__coffin_find_corner_maxima:N The idea here is to find the extremities of the content of the coffin. 14631 14632 14633 14634 14635 14636 14637 14638 14639 14640 14641 14642 14643 14644 14645 14646 14647 14648 \cs_new_protected:Npn \__coffin_find_corner_maxima:N #1 { \dim_set:Nn \l__coffin_top_corner_dim { -\c_max_dim } \dim_set:Nn \l__coffin_right_corner_dim { -\c_max_dim } \dim_set:Nn \l__coffin_bottom_corner_dim { \c_max_dim } \dim_set:Nn \l__coffin_left_corner_dim { \c_max_dim } \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_find_corner_maxima_aux:nn ##2 } } \cs_new_protected:Npn \__coffin_find_corner_maxima_aux:nn #1#2 { \dim_set:Nn \l__coffin_left_corner_dim { \dim_min:nn { \l__coffin_left_corner_dim } {#1} } \dim_set:Nn \l__coffin_right_corner_dim { \dim_max:nn { \l__coffin_right_corner_dim } {#1} } \dim_set:Nn \l__coffin_bottom_corner_dim { \dim_min:nn { \l__coffin_bottom_corner_dim } {#2} } \dim_set:Nn \l__coffin_top_corner_dim 672 . This is done by \__coffin_find_corner_maxima_aux:nn looking for the smallest values for the bottom and left corners.(End definition for \__coffin_rotate_pole:Nnnnnn. 14612 14613 14614 14615 14616 14617 14618 14619 14620 14621 14622 14623 14624 14625 14626 14627 14628 14629 14630 \cs_new_protected:Npn \__coffin_rotate_vector:nnNN #1#2#3#4 { \dim_set:Nn #3 { \fp_to_dim:n { \dim_to_fp:n {#1} * \l__coffin_cos_fp . Working this way means that the floating point work is kept to a minimum: for any given rotation the sin and cosine values do no change. and the largest values for the top and right corners. ) \__coffin_shift_corner:Nnnn \__coffin_shift_pole:Nnnnnn Shifting the corners and poles of a coffin means subtracting the appropriate values from the x.\l__coffin_left_corner_dim } } { \dim_eval:n { #4 .) 41. For the poles. 14662 14663 14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 14677 14678 \cs_new_protected:Npn \__coffin_shift_corner:Nnnn #1#2#3#4 { \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _ prop } {#2} { { \dim_eval:n { #3 .) 673 .\l__coffin_bottom_corner_dim } } } } \cs_new_protected:Npn \__coffin_shift_pole:Nnnnnn #1#2#3#4#5#6 { \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _ prop } {#2} { { \dim_eval:n { #3 . 14679 14680 \fp_new:N \l__coffin_scale_x_fp \fp_new:N \l__coffin_scale_y_fp (End definition for \l__coffin_scale_x_fp.{ \dim_max:nn { \l__coffin_top_corner_dim } {#2} } 14649 } 14650 (End definition for \__coffin_find_corner_maxima:N.\l__coffin_bottom_corner_dim } } {#5} {#6} } } (End definition for \__coffin_shift_corner:Nnnn.) \__coffin_find_bounding_shift: The approach to finding the shift for the bounding box is similar to that for the corners. This function is documented on page ??. so things are a bit clearer. This function is documented on page ??. 14651 14652 14653 14654 14655 14656 14657 14658 14659 14660 14661 \cs_new_protected_nopar:Npn \__coffin_find_bounding_shift: { \dim_set:Nn \l__coffin_bounding_shift_dim { \c_max_dim } \prop_map_inline:Nn \l__coffin_bounding_prop { \__coffin_find_bounding_shift_aux:nn ##2 } } \cs_new_protected:Npn \__coffin_find_bounding_shift_aux:nn #1#2 { \dim_set:Nn \l__coffin_bounding_shift_dim { \dim_min:nn { \l__coffin_bounding_shift_dim } {#1} } } (End definition for \__coffin_find_bounding_shift:.7 \l__coffin_scale_x_fp \l__coffin_scale_y_fp Resizing coffins Storage for the scaling factors in x and y. This function is documented on page ??. respectively. \__coffin_find_bounding_shift_aux:nn However. This function is documented on page ??. there is only one value needed here and a fixed input property list.and y-components. this means that the direction vector is unchanged.\l__coffin_left_corner_dim } } { \dim_eval:n { #4 . ) \coffin_resize:Nnn \coffin_resize:cnn Resizing a coffin begins by setting up the user-friendly names for the dimensions of the coffin box. These functions are documented on page ??. 674 . This is the same operation as takes place for the underlying box. but that operation is grouped and so the same calculation is done here. Only the total height is needed. 14695 14696 14697 14698 14699 14700 \cs_new_protected:Npn \__coffin_resize_common:Nnn #1#2#3 { \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_scale_corner:Nnnn #1 {##1} ##2 } \prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop } { \__coffin_scale_pole:Nnnnnn #1 {##1} ##2 } Negative x-scaling values will place the poles in the wrong location: this is corrected here. as this is the shift required for corners and poles.) \coffin_scale:Nnn \coffin_scale:cnn For scaling. the values given have to be turned into absolute values. 14683 14684 14685 14686 14687 14688 14689 14690 14691 14692 14693 14694 \cs_new_protected:Npn \coffin_resize:Nnn #1#2#3 { \fp_set:Nn \l__coffin_scale_x_fp { \dim_to_fp:n {#2} / \dim_to_fp:n { \coffin_wd:N #1 } } \fp_set:Nn \l__coffin_scale_y_fp { \dim_to_fp:n {#3} / \dim_to_fp:n { \coffin_ht:N #1 + \coffin_dp:N #1 } } \box_resize:Nnn #1 {#2} {#3} \__coffin_resize_common:Nnn #1 {#2} {#3} } \cs_generate_variant:Nn \coffin_resize:Nnn { c } (End definition for \coffin_resize:Nnn and \coffin_resize:cnn.) \__coffin_resize_common:Nnn The poles and corners of the coffin are scaled to the appropriate places before actually resizing the underlying box. The scaling is done the TEX way as this works properly with floating point values without needing to use the fp module.\l__coffin_scaled_total_height_dim When scaling. This function is documented on page ??. \fp_compare:nNnT \l__coffin_scale_x_fp < \c_zero_fp { \prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop } { \__coffin_x_shift_corner:Nnnn #1 {##1} ##2 } \prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop } { \__coffin_x_shift_pole:Nnnnnn #1 {##1} ##2 } } 14701 14702 14703 14704 14705 14706 14707 14708 } (End definition for \__coffin_resize_common:Nnn. \l__coffin_scaled_width_dim 14681 \dim_new:N \l__coffin_scaled_total_height_dim 14682 \dim_new:N \l__coffin_scaled_width_dim (End definition for \l__coffin_scaled_total_height_dim. The new sizes are then turned into scale factor. the opposite calculation is done to find the new dimensions for the coffin. This function is documented on page ??. 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718 14719 14720 14721 14722 14723 \cs_new_protected:Npn \coffin_scale:Nnn #1#2#3 { \fp_set:Nn \l__coffin_scale_x_fp {#2} \fp_set:Nn \l__coffin_scale_y_fp {#3} \box_scale:Nnn #1 { \l__coffin_scale_x_fp } { \l__coffin_scale_y_fp } \dim_set:Nn \l__coffin_internal_dim { \coffin_ht:N #1 + \coffin_dp:N #1 } \dim_set:Nn \l__coffin_scaled_total_height_dim { \fp_abs:n { \l__coffin_scale_y_fp } \l__coffin_internal_dim } \dim_set:Nn \l__coffin_scaled_width_dim { -\fp_abs:n { \l__coffin_scale_x_fp } \coffin_wd:N #1 } \__coffin_resize_common:Nnn #1 { \l__coffin_scaled_width_dim } { \l__coffin_scaled_total_height_dim } } \cs_generate_variant:Nn \coffin_scale:Nnn { c } (End definition for \coffin_scale:Nnn and \coffin_scale:cnn.) \__coffin_scale_vector:nnNN This functions scales a vector from the origin using the pre-set scale factors in x and y. and as a result the code is a lot clearer. These functions are documented on page ??. This function is documented on page ??. 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741 14742 14743 14744 14745 \cs_new_protected:Npn \__coffin_scale_corner:Nnnn #1#2#3#4 { \__coffin_scale_vector:nnNN {#3} {#4} \l__coffin_x_dim \l__coffin_y_dim \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } {#2} { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } } } \cs_new_protected:Npn \__coffin_scale_pole:Nnnnnn #1#2#3#4#5#6 { \__coffin_scale_vector:nnNN {#3} {#4} \l__coffin_x_dim \l__coffin_y_dim \__coffin_set_pole:Nnx #1 {#2} { { \dim_use:N \l__coffin_x_dim } { \dim_use:N \l__coffin_y_dim } {#5} {#6} } } (End definition for \__coffin_scale_corner:Nnnn. This is a much less complex operation than rotation.) 675 .) \__coffin_scale_corner:Nnnn \__coffin_scale_pole:Nnnnnn Scaling both corners and poles is a simple calculation using the preceding vector scaling. 14724 14725 14726 14727 14728 14729 14730 \cs_new_protected:Npn \__coffin_scale_vector:nnNN #1#2#3#4 { \dim_set:Nn #3 { \fp_to_dim:n { \dim_to_fp:n {#1} * \l__coffin_scale_x_fp } } \dim_set:Nn #4 { \fp_to_dim:n { \dim_to_fp:n {#2} * \l__coffin_scale_y_fp } } } (End definition for \__coffin_scale_vector:nnNN. This function is documented on page ??. These functions are documented on page 193. This function is documented on page ??. Those are not yet in l3kernel proper since the mapping below is the first of its kind. 14746 14747 14748 14749 14750 14751 14752 14753 14754 14755 14756 14757 14758 14759 14760 \cs_new_protected:Npn \__coffin_x_shift_corner:Nnnn #1#2#3#4 { \prop_put:cnx { l__coffin_corners_ \__int_value:w #1 _prop } {#2} { { \dim_eval:n { #3 + \box_wd:N #1 } } {#4} } } \cs_new_protected:Npn \__coffin_x_shift_pole:Nnnnnn #1#2#3#4#5#6 { \prop_put:cnx { l__coffin_poles_ \__int_value:w #1 _prop } {#2} { { \dim_eval:n #3 + \box_wd:N #1 } {#4} {#5} {#6} } } (End definition for \__coffin_x_shift_corner:Nnnn. hence the set up.) 41. This mapping cannot be nested as the stream has only one “current line”. 14766 14767 14768 14769 14770 14771 14772 14773 14774 14775 14776 14777 14778 \cs_new_protected_nopar:Npn \ior_map_inline:Nn { \__ior_map_inline:NNn \ior_get:NN } \cs_new_protected_nopar:Npn \ior_str_map_inline:Nn { \__ior_map_inline:NNn \ior_get_str:NN } \cs_new_protected_nopar:Npn \__ior_map_inline:NNn { \int_gincr:N \g__prg_map_int \exp_args:Nc \__ior_map_inline:NNNn { __prg_map_ \int_use:N \g__prg_map_int :n } } \cs_new_protected:Npn \__ior_map_inline:NNNn #1#2#3#4 { \cs_set:Npn #1 ##1 {#4} 676 . hence the two applications of \ior_if_eof:N.\__coffin_x_shift_corner:Nnnn These functions correct for the x displacement that takes place with a negative horizontal \__coffin_x_shift_pole:Nnnnnn scaling. there is a check to avoid reading past the end of a file. Within that. 14762 14763 14764 14765 \cs_new_nopar:Npn \ior_map_break: { \__prg_map_break:Nn \ior_map_break: { } } \cs_new_nopar:Npn \ior_map_break:n { \__prg_map_break:Nn \ior_map_break: } (End definition for \ior_map_break: and \ior_map_break:n.8 14761 \ior_map_break: \ior_map_break:n Additions to l3file h@@=iori Usual map breaking functions.) \ior_map_inline:Nn \ior_str_map_inline:Nn \__ior_map_inline:NNn \__ior_map_inline:NNNn \__ior_map_inline_loop:NNN \l__ior_internal_tl Mapping to an input stream can be done on either a token or a string basis. 10 14800 \prop_map_tokens:Nn \prop_map_tokens:cn \__prop_map_tokens:nwn Additions to l3prop h@@=propi The mapping grabs one key–value pair at a time.) 41. The odd construction \use:n {#1} allows #1 to contain any token. These functions are documented on page ??. 14794 14795 14796 14797 14798 14799 \cs_new_protected:Npn \fp_set_from_dim:Nn #1#2 { \tl_set:Nx #1 { \dim_to_fp:n {#2} } } \cs_new_protected:Npn \fp_gset_from_dim:Nn #1#2 { \tl_gset:Nx #1 { \dim_to_fp:n {#2} } } \cs_generate_variant:Nn \fp_set_from_dim:Nn { c } \cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } (End definition for \fp_set_from_dim:Nn and others. and stops when reaching the marker key \q_recursion_tail.\ior_if_eof:NF #3 { \__ior_map_inline_loop:NNN #1#2#3 } \__prg_break_point:Nn \ior_map_break: { \int_gdecr:N \g__prg_map_int } 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 } \cs_new_protected:Npn \__ior_map_inline_loop:NNN #1#2#3 { #2 #3 \l__ior_internal_tl \ior_if_eof:NF #3 { \exp_args:No #1 \l__ior_internal_tl \__ior_map_inline_loop:NNN #1#2#3 } } \tl_new:N \l__ior_internal_tl (End definition for \ior_map_inline:Nn and \ior_str_map_inline:Nn. which cannot appear in normal keys since those are strings.) 41. These functions are documented on page ??.9 14793 \fp_set_from_dim:Nn \fp_set_from_dim:cn \fp_gset_from_dim:Nn \fp_gset_from_dim:cn Additions to l3fp h@@=fpi Use the appropriate function from l3fp-convert. 14801 14802 14803 14804 14805 14806 14807 14808 14809 14810 14811 14812 14813 \cs_new:Npn \prop_map_tokens:Nn #1#2 { \exp_last_unbraced:Nno \__prop_map_tokens:nwn {#2} #1 \s__prop \q_recursion_tail \s__prop { } \__prg_break_point:Nn \prop_map_break: { } } \cs_new:Npn \__prop_map_tokens:nwn #1 \s__prop #2 \s__prop #3 { \if_meaning:w \q_recursion_tail #2 \exp_after:wN \prop_map_break: \fi: \use:n {#1} {#2} {#3} \__prop_map_tokens:nwn {#1} 677 . then the stop code { ? \__prg_break: } { } will be used by the auxiliary. the current hkeyi and the current hvaluei. the hvaluei is returned. terminating the loop and returning nothing at all. If the hkeysi match. These functions are documented on page ??.14814 14815 } \cs_generate_variant:Nn \prop_map_tokens:Nn { c } (End definition for \prop_map_tokens:Nn and \prop_map_tokens:cn. These functions are documented on page ??. 14816 14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827 14828 14829 14830 14831 \cs_new:Npn \prop_get:Nn #1#2 { \__prop_get:No #1 { \tl_to_str:n {#2} } } \cs_new:Npn \__prop_get:Nn #1#2 { \exp_last_unbraced:Nno \__prop_get_Nn:nwn {#2} #1 \s__prop #2 \s__prop { } \__prg_break_point: } \cs_generate_variant:Nn \__prop_get:Nn { No } \cs_new:Npn \__prop_get_Nn:nwn #1 \s__prop #2 \s__prop #3 { \str_if_eq_x:nnTF {#1} {#2} { \__prg_break:n { \exp_not:n {#3} } } { \__prop_get_Nn:nwn {#1} } } \cs_generate_variant:Nn \prop_get:Nn { c } (End definition for \prop_get:Nn and \prop_get:cn. If the resulting offset is too large.11 14832 \seq_item:Nn \seq_item:cn \__seq_item:nnn Additions to l3seq h@@=seqi The idea here is to find the offset of the item from the left. this expands to nothing.) 41. 14833 14834 14835 14836 14837 14838 14839 14840 14841 14842 14843 14844 14845 \cs_new:Npn \seq_item:Nn #1#2 { \exp_last_unbraced:Nfo \__seq_item:nnn { \int_eval:n { \int_compare:nNnT {#2} < \c_zero { \seq_count:N #1 + \c_one + } #2 } } #1 { ? \__prg_break: } 678 .) \prop_get:Nn \prop_get:cn \__prop_get:Nn \__prop_get:No \__prop_get_Nn:nwn Getting the value corresponding to a key in a property list in an expandable fashion is a simple instance of mapping some tokens. then use a loop to grab the correct item. Map the function \prop_get:nnn which takes as its three arguments the hkeyi that we are looking for. If none of the keys match. This is most conveniently done in two steps using an auxiliary function. or worrying about which is longer.1 } } } } \cs_generate_variant:Nn \seq_item:Nn { c } (End definition for \seq_item:Nn and \seq_item:cn.) 679 .14846 14847 14848 14849 14850 14851 14852 14853 14854 14855 14856 { } \__prg_break_point: } \cs_new:Npn \__seq_item:nnn #1#2#3 { \use_none:n #2 \int_compare:nNnTF {#1} = \c_one { \__prg_break:n { \exp_not:n {#3} } } { \exp_args:Nf \__seq_item:nnn { \int_eval:n { #1 . When the code hits the end of one of the sequences. The function to be mapped will then be applied to the two entries. the break material will stop the entire loop and tidy up. cc } (End definition for \seq_mapthread_function:NNN and others.) \seq_mapthread_function:NNN \seq_mapthread_function:NcN \seq_mapthread_function:cNN \seq_mapthread_function:ccN \__seq_mapthread_function:NN \__seq_mapthread_function:Nnnwnn The idea here is to first expand both of the sequences. The mapping then throws away the first token of #2 and #5. which for items in the sequences will both be \__seq_item:n. 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873 14874 14875 14876 14877 14878 14879 14880 14881 14882 \cs_new:Npn \seq_mapthread_function:NNN #1#2#3 { \exp_after:wN \__seq_mapthread_function:NN \exp_after:wN #3 \exp_after:wN #1 #2 { ? \__prg_break: } { } \__prg_break_point: } \cs_new:Npn \__seq_mapthread_function:NN #1#2 { \exp_after:wN \__seq_mapthread_function:Nnnwnn \exp_after:wN #1 #2 { ? \__prg_break: } { } \q_stop } \cs_new:Npn \__seq_mapthread_function:Nnnwnn #1#2#3#4 \q_stop #5#6 { \use_none:n #2 \use_none:n #5 #1 {#3} {#6} \__seq_mapthread_function:Nnnwnn #1 #4 \q_stop } \cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } \cs_generate_variant:Nn \seq_mapthread_function:NNN { c . These functions are documented on page ??. These functions are documented on page ??. adding the usual { ? \__prg_break: } { } to the end of each one. This avoids needing to find the count of the two sequences. \cs_new_protected:Npn \seq_reverse:N #1 { \cs_set_eq:NN \@@_item:n \@@_reverse_item:nw \tl_set:Nf #2 { #2 \exp_stop_f: } } \cs_new:Npn \@@_reverse_item:nw #1 #2 \exp_stop_f: { #2 \exp_stop_f: \@@_item:n {#1} } At first. and never reads the \@@_item:n {#1} left by the previous call. \seq_reverse:N was coded by collecting the items in reverse order after an \exp_stop_f: marker.\seq_set_from_clist:NN \seq_set_from_clist:cN \seq_set_from_clist:Nc \seq_set_from_clist:cc \seq_set_from_clist:Nn \seq_set_from_clist:cn \seq_gset_from_clist:NN \seq_gset_from_clist:cN \seq_gset_from_clist:Nc \seq_gset_from_clist:cc \seq_gset_from_clist:Nn \seq_gset_from_clist:cn Setting a sequence from a comma-separated list is done using a simple mapping. TEX cannot remove that previous call from the stack. cc \cs_generate_variant:Nn \seq_set_from_clist:Nn { c \cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc \cs_generate_variant:Nn \seq_gset_from_clist:NN { c . and in particular must retain the various macro parameters in memory. cc \cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } } } } } } (End definition for \seq_set_from_clist:NN and others.) \seq_reverse:N \seq_reverse:c \seq_greverse:N \seq_greverse:c \__seq_tmp:w \__seq_reverse:NN \__seq_reverse_item:nwn Previously. TEX’s usual tail recursion does not take place in this case: since the following \__seq_reverse_item:nw only reads tokens until \exp_stop_f:. since we can forget about each item as soon as it is placed after \exp_stop_f:. These functions are documented on page ??. until the end of the replacement text is reached. 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 \cs_new_protected:Npn \seq_set_from_clist:NN #1#2 { \tl_set:Nx #1 { \clist_map_function:NN #2 \__seq_wrap_item:n } } \cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 { \tl_set:Nx #1 { \clist_map_function:nN {#2} \__seq_wrap_item:n } } \cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 { \tl_gset:Nx #1 { \clist_map_function:NN #2 \__seq_wrap_item:n } } \cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 { \tl_gset:Nx #1 { \clist_map_function:nN {#2} \__seq_wrap_item:n } } \cs_generate_variant:Nn \seq_set_from_clist:NN { Nc \cs_generate_variant:Nn \seq_set_from_clist:NN { c . this seems optimal. The stack is thus 680 . Unfortunately. ) \seq_set_map:NNn \seq_gset_map:NNn \__seq_set_map:NNNn Very similar to \seq_set_filter:NNn. hence in the x-expanding assignment. and skipping out of that would break horribly. without a \__prg_break_point: because the user’s code is performed within the evaluation of a boolean expression. Keeping track of the arguments of all those calls uses up a memory quadratic in the length of the sequence. The \__seq_wrap_item:n function inserts the relevant \__seq_item:n without expansion in the input stream. Instead. We could actually merge the two within a single function. TEX can then not cope with more than a few thousand items. we collect the items in the argument of \exp_not:n. 14938 14939 14940 \cs_new_protected_nopar:Npn \seq_set_map:NNn { \__seq_set_map:NNNn \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_map:NNn 681 .only flushed after all the \__seq_reverse_item:nw are expanded. These functions are documented on page 195. and the memory consumption becomes linear. These functions are documented on page ??.) \seq_set_filter:NNn \seq_gset_filter:NNn \__seq_set_filter:NNNn Similar to \seq_map_inline:Nn. The previous calls are cleanly removed from the stack. but it would have weird semantics. 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 \cs_new_protected_nopar:Npn \seq_set_filter:NNn { \__seq_set_filter:NNNn \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_filter:NNn { \__seq_set_filter:NNNn \tl_gset:Nx } \cs_new_protected:Npn \__seq_set_filter:NNNn #1#2#3#4 { \__seq_push_item_def:n { \bool_if:nT {#4} { \__seq_wrap_item:n {##1} } } #1 #2 { #3 } \__seq_pop_item_def: } (End definition for \seq_set_filter:NNn and \seq_gset_filter:NNn. 14909 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 14920 14921 14922 14923 14924 14925 14926 14927 \cs_new_protected_nopar:Npn \__seq_tmp:w { } \cs_new_protected_nopar:Npn \seq_reverse:N { \__seq_reverse:NN \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_greverse:N { \__seq_reverse:NN \tl_gset:Nx } \cs_new_protected:Npn \__seq_reverse:NN #1 #2 { \cs_set_eq:NN \__seq_tmp:w \__seq_item:n \cs_set_eq:NN \__seq_item:n \__seq_reverse_item:nwn #1 #2 { #2 \exp_not:n { } } \cs_set_eq:NN \__seq_item:n \__seq_tmp:w } \cs_new:Npn \__seq_reverse_item:nwn #1 #2 \exp_not:n #3 { #2 \exp_not:n { \__seq_item:n {#1} #3 } } \cs_generate_variant:Nn \seq_reverse:N { c } \cs_generate_variant:Nn \seq_greverse:N { c } (End definition for \seq_reverse:N and others. The main difference is that we use \__seq_item:n as a delimiter rather than commas.) 41. These functions are documented on page 195. This function is documented on page 195.12 14979 Additions to l3skip h@@=skipi 682 .14941 14942 14943 14944 14945 14946 14947 { \__seq_set_map:NNNn \tl_gset:Nx } \cs_new_protected:Npn \__seq_set_map:NNNn #1#2#3#4 { \__seq_push_item_def:n { \exp_not:N \__seq_item:n {#4} } #1 #2 { #3 } \__seq_pop_item_def: } (End definition for \seq_set_map:NNn and \seq_gset_map:NNn.) \seq_use:Nnnn \__seq_use:NnNnn \__seq_use:nwwwwnwn \__seq_use:nwwn See \clist_use:Nnnn for a general explanation. We also need to add \__seq_item:n at various places. 14948 14949 14950 14951 14952 14953 14954 14955 14956 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 \cs_new:Npn \seq_use:Nnnn #1#2#3#4 { \seq_if_exist:NTF #1 { \int_case:nnn { \seq_count:N #1 } { { 0 } { } { 1 } { \exp_after:wN \__seq_use:NnNnn #1 \__seq_item:n { } { } } { 2 } { \exp_after:wN \__seq_use:NnNnn #1 {#2} } } { \exp_after:wN \__seq_use:nwwwwnwn \exp_after:wN { \exp_after:wN } #1 \__seq_item:n \q_mark { \__seq_use:nwwwwnwn {#3} } \q_mark { \__seq_use:nwwn {#4} } \q_stop { } } } { \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#1} } } \cs_new:Npn \__seq_use:NnNnn \__seq_item:n #1 \__seq_item:n #2#3 { \exp_not:n { #1 #3 #2 } } \cs_new:Npn \__seq_use:nwwwwnwn #1 \__seq_item:n #2 \__seq_item:n #3 \__seq_item:n #4#5 \q_mark #6#7 \q_stop #8 { #6 \__seq_item:n {#3} \__seq_item:n {#4} #5 \q_mark {#6} #7 \q_stop { #8 #1 #2 } } \cs_new:Npn \__seq_use:nwwn #1 \__seq_item:n #2 #3 \q_stop #4 { \exp_not:n { #4 #1 #2 } } (End definition for \seq_use:Nnnn. 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009 15010 15011 15012 \cs_new:Npn \tl_reverse_tokens:n #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \__tl_act:NNNnn \__tl_reverse_normal:nN \__tl_reverse_group:nn \__tl_reverse_space:n { } {#1} } } 683 . F . Otherwise. If it holds infinite glue set #3 and #4 to zero and issue the special action #2 which is probably an error message. These functions are documented on page 196. token list starting with a normal token. resp. 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 14990 14991 14992 \cs_new:Npn \skip_split_finite_else_action:nnNN #1#2#3#4 { \skip_if_finite:nTF {#1} { #3 = \etex_gluestretch:D #1 \scan_stop: #4 = \etex_glueshrink:D #1 \scan_stop: } { #3 = \c_zero_skip #4 = \c_zero_skip #2 } } (End definition for \skip_split_finite_else_action:nnNN. compare with a single space. 14994 14995 14996 14997 14998 14999 \prg_new_conditional:Npnn \tl_if_single_token:n #1 { p .13 14993 \tl_if_single_token_p:n \tl_if_single_token:nTF Additions to l3tl h@@=tli There are four cases: empty token list. If the hskipi register holds finite glue it sets #3 and #4 to the stretch and shrink component. T .\skip_split_finite_else_action:nnNN This macro is useful when performing error checking in certain circumstances.) \tl_reverse_tokens:n \__tl_reverse_group:nn The same as \tl_reverse:n but with recursion within brace groups.) 41. This function is documented on page 196. TF } { \tl_if_head_is_N_type:nTF {#1} { \__str_if_eq_x_return:nn { \exp_not:o { \use_none:n #1 } } { } } { \__str_if_eq_x_return:nn { \exp_not:n {#1} } { ~ } } } (End definition for \tl_if_single_token:n. or with a space token. If the token list starts with a normal token. with a brace group. remove it and check for emptyness. Assignments are local. only case where we have a single token. 15019 15020 15021 15022 15023 \cs_new:Npn \__tl_act_group_recurse:Nnn #1#2#3 { \exp_args:Nf #1 { \exp_after:wN \exp_after:wN \exp_after:wN { #2 {#3} } } } (End definition for \tl_reverse_tokens:n.) \c__tl_act_uppercase_tl \c__tl_act_lowercase_tl These constants contain the correspondance between lowercase and uppercase letters. respectively. In this code. which should expand in two steps.. #1 is the output function. Somewhat a hack..) \tl_count_tokens:n \__tl_act_count_normal:nN \__tl_act_count_group:nn \__tl_act_count_space:n The token coung is computed through an \int_eval:n construction. we need to recursively apply some transformation within brace groups. and AaBbCc.. Each 1+ is output to the left. and the sum is ended by the \c_zero inserted by \__tl_act_end:wn. This function is documented on page 196. 15024 15025 15026 15027 15028 15029 15030 15031 15032 15033 15034 15035 15036 15037 15038 15039 \cs_new:Npn \tl_count_tokens:n #1 { \int_eval:n { \__tl_act:NNNnn \__tl_act_count_normal:nN \__tl_act_count_group:nn \__tl_act_count_space:n { } {#1} } } \cs_new:Npn \__tl_act_count_normal:nN #1 #2 { 1 + } \cs_new:Npn \__tl_act_count_space:n #1 { 1 + } \cs_new:Npn \__tl_act_count_group:nn #1 #2 { 2 + \tl_count_tokens:n {#2} + } (End definition for \tl_count_tokens:n. in the form aAbBcC. This function is documented on page 196. 15040 15041 15042 15043 15044 15045 15046 15047 15048 \tl_const:Nn { aA bB cC nN oO pP } \tl_const:Nn { Aa Bb Cc Nn Oo Pp \c__tl_act_uppercase_tl dD eE fF gG hH iI jJ kK lL mM qQ rR sS tT uU vV wW xX yY zZ \c__tl_act_lowercase_tl Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz 684 .. #2 is the transformation. into the integer expression.15013 15014 15015 15016 15017 15018 \__tl_act_group_recurse:Nnn \cs_new:Npn \__tl_reverse_group:nn #1 { \__tl_act_group_recurse:Nnn \__tl_act_reverse_output:n { \tl_reverse_tokens:n } } In many applications of \__tl_act:NNNnn. and #3 is the group. then output. before being output. we must perform the conversion within the group (the \exp_after:wN trigger \romannumeral. we use the hparametersi argument to carry which case-changing we are applying. As for other token list actions. These variables are documented on page ??.15049 } (End definition for \c__tl_act_uppercase_tl and \c__tl_act_lowercase_tl.) \tl_expandable_uppercase:n \tl_expandable_lowercase:n \__tl_act_case_normal:nN \__tl_act_case_group:nn \__tl_act_case_space:n The only difference between uppercasing and lowercasing is the table of correspondance that is used. For a group. then output. and this time. which expands fully to give the converted group). A space is simply output. and converted if necessary to upper/lowercase. 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 15078 15079 15080 15081 15082 15083 15084 15085 15086 \cs_new:Npn \tl_expandable_uppercase:n #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \__tl_act_case_aux:nn { \c__tl_act_uppercase_tl } {#1} } } \cs_new:Npn \tl_expandable_lowercase:n #1 { \etex_unexpanded:D \exp_after:wN { \tex_romannumeral:D \__tl_act_case_aux:nn { \c__tl_act_lowercase_tl } {#1} } } \cs_new:Npn \__tl_act_case_aux:nn { \__tl_act:NNNnn \__tl_act_case_normal:nN \__tl_act_case_group:nn \__tl_act_case_space:n } \cs_new:Npn \__tl_act_case_space:n #1 { \__tl_act_output:n {~} } \cs_new:Npn \__tl_act_case_normal:nN #1 #2 { \exp_args:Nf \__tl_act_output:n { \exp_args:NNo \str_case:nnn #2 {#1} { \exp_stop_f: #2 } } } \cs_new:Npn \__tl_act_case_group:nn #1 #2 { \exp_after:wN \__tl_act_output:n \exp_after:wN { \exp_after:wN { \tex_romannumeral:D \__tl_act_case_aux:nn {#1} {#2} } } } 685 . A normal token is compared to each letter in the alphabet using \str_if_eq:nn tests. we feed \__tl_act:NNNnn three functions. then use a loop to grab the correct item.14 15111 \char_set_active:Npn \char_set_active:Npx \char_gset_active:Npn \char_gset_active:Npx \char_set_active_eq:NN \char_gset_active_eq:NN 15112 15113 15114 15115 15116 15117 15118 15119 15120 15121 15122 15123 Additions to l3tokens h@@=chari \group_begin: \char_set_catcode_active:N \^^@ \cs_set:Npn \char_tmp:NN #1#2 { \cs_new:Npn #1 ##1 { \char_set_catcode_active:n { ‘##1 } \group_begin: \char_set_lccode:nn { ‘\^^@ } { ‘##1 } \tl_to_lowercase:n { \group_end: #2 ^^@ } } } 686 . 15087 15088 15089 15090 15091 15092 15093 15094 15095 15096 15097 15098 15099 15100 15101 15102 15103 15104 15105 15106 15107 15108 15109 15110 \cs_new:Npn \tl_item:nn #1#2 { \exp_args:Nf \__tl_item:nn { \int_eval:n { \int_compare:nNnT {#2} < \c_zero { \tl_count:n {#1} + \c_one + } #2 } } #1 \q_recursion_tail \__prg_break_point: } \cs_new:Npn \__tl_item:nn #1#2 { \__quark_if_recursion_tail_break:nN {#2} \__prg_break: \int_compare:nNnTF {#1} = \c_one { \__prg_break:n { \exp_not:n {#2} } } { \exp_args:Nf \__tl_item:nn { \int_eval:n { #1 .) \tl_item:nn \tl_item:Nn \tl_item:cn \__tl_item:nn The idea here is to find the offset of the item from the left. and \tl_item:cn. then \quark_if_recursion_tail_stop:n terminates the loop. If the resulting offset is too large. These functions are documented on page ??.) 41. These functions are documented on page 197.(End definition for \tl_expandable_uppercase:n and \tl_expandable_lowercase:n. \tl_item:Nn . and returns nothing at all.1 } } } } \cs_new_nopar:Npn \tl_item:Nn { \exp_args:No \tl_item:nn } \cs_generate_variant:Nn \tl_item:Nn { c } (End definition for \tl_item:nn . the meaning of \outer has nothing after outer. 15132 15133 15134 15135 15136 15137 15138 15139 15140 15141 15142 15143 15144 15145 15146 15147 15148 15149 15150 15151 15152 15153 \group_begin: \char_set_catcode_other:N \O \char_set_catcode_other:N \U \char_set_catcode_other:N \T \char_set_catcode_other:N \E \char_set_catcode_other:N \R \tl_to_lowercase:n { \cs_new_protected_nopar:Npn \__peek_execute_branches_N_type: { \if_int_odd:w \if_catcode:w \exp_not:N \l_peek_token { \c_two \fi: \if_catcode:w \exp_not:N \l_peek_token } \c_two \fi: \if_meaning:w \l_peek_token \c_space_token \c_two \fi: \c_one \exp_after:wN \__peek_N_type:w \token_to_meaning:N \l_peek_token \q_mark \__peek_N_type_aux:nnw OUTER \q_mark \use_none_delimit_by_q_stop:w \q_stop \exp_after:wN \__peek_true:w \else: 687 . Otherwise. Here. except in four cases: begin-group tokens. without impacting performance too much for non-outer tokens. end-group tokens. we must detect outer tokens. Macros and marks would have ma in the part before the first occurrence of outer. In the true branch. If that is absent. These functions are documented on page 198. Since \l_peek_token might be outer. there is no hsearch tokeni. or it can be an outer token. and that covers all cases. and must resort to the old trick of using \ifodd to expand a set of tests. contrarily to outer macros.) 15131 \peek_N_type:TF \__peek_execute_branches_N_type: \__peek_N_type:w \__peek_N_type_aux:nnw h@@=peeki All tokens are N-type tokens. so we feed a dummy \scan_stop: to the \__peek_token_generic:NNTF function.15124 15125 15126 15127 15128 15129 15130 \char_tmp:NN \char_tmp:NN \char_tmp:NN \char_tmp:NN \char_tmp:NN \char_tmp:NN \group_end: \char_set_active:Npn \char_set_active:Npx \char_gset_active:Npn \char_gset_active:Npx \char_set_active_eq:NN \char_gset_active_eq:NN \cs_set:Npn \cs_set:Npx \cs_gset:Npn \cs_gset:Npx \cs_set_eq:NN \cs_gset_eq:NN (End definition for \char_set_active:Npn and \char_set_active:Npx. the token can be a non-outer macro or a primitive mark whose parameter or replacement text contains outer. calling \__peek_true:w or \__peek_false:w as appropriate. we cannot use the convenient \bool_if:nTF function. it can be the primitive \outer. The false branch of this test is taken if the token is one of the first three kinds of non-N-type tokens (explicit or implicit). \use_none_delimit_by_q_stop:w cleans up. thus we call \__peek_false:w. space tokens with character code 32. and we call \__peek_true:w. and outer tokens. The first filter is to search for outer in the \meaning of \l_peek_token. ) 15174 h/initex | packagei 688 .15154 15155 15156 15157 15158 15159 15160 15161 15162 15163 15164 15165 15166 15167 15168 15169 15170 15171 15172 15173 \exp_after:wN \__peek_false:w \fi: } \cs_new_protected:Npn \__peek_N_type:w #1 OUTER #2 \q_mark #3 { #3 {#1} {#2} } } \group_end: \cs_new_protected:Npn \__peek_N_type_aux:nnw #1 #2 #3 \fi: { \fi: \tl_if_in:noTF {#1} { \tl_to_str:n {ma} } { \__peek_true:w } { \tl_if_empty:nTF {#2} { \__peek_true:w } { \__peek_false:w } } } \cs_new_protected_nopar:Npn \peek_N_type:TF { \__peek_token_generic:NNTF \__peek_execute_branches_N_type: \scan_stop: } \cs_new_protected_nopar:Npn \peek_N_type:T { \__peek_token_generic:NNT \__peek_execute_branches_N_type: \scan_stop: } \cs_new_protected_nopar:Npn \peek_N_type:F { \__peek_token_generic:NNF \__peek_execute_branches_N_type: \scan_stop: } (End definition for \peek_N_type:. This function is documented on page 198. . . . . . . . . . 8809 \. . . . . 8821 \. . . . . . . . . . 8813 \. . . . . 1860. . . 1799. . . . . . . . . . . 7698 \" . . . . . . . 8743 \.value_required: . . . . 8821 \. . . . 1793. .tl_set:N . . . . . 2821. . . . . . . . . . . . . . . . . . . 1794. 1864 \::N . . . 8747 \. . 1795. . . . . . . . . . . 1633. . . . . . . 2730. . . 1783. 1782. .int_gset:N . 1804. . . . . . . . . . . . . . 6. . . . . . . . . . . . . . . . . . . . . . 8837 \/ . . . . .code:x . . . . . . . 1787. . . . 2744. . . . . . . . . 8390.int_set:c . . . 8805 \. . . . . . . . . . . . . . . . . . . . . . . . 1640. . . . . . . 8771 \. . 1823. 8771 \. . . 1787.clist_set:c . . . . . .tl_set_x:c . . . . . . . . . 8783 \. . . . . . . . . . . . . . 1634. . . . 8813 \. 1634. . . . . . 1813. . . . . . .generate_choices:n . . . . . . . . . . 8763 \. . . . . . . 11285 \. . .skip_set:c . . . . . . . . . . . . . . . . . . . . . . . . 1792. . . . . 8821 \. . . . . . . . . 1777. . . . .skip_set:N . . 1635. . . . . 7699. . 1786. . . . . . .tl_gset_x:c . . 8775 \. . 8388. . .. 1640. . . . . . . 1862 \::f_unbraced . 1796. . . . . . . . 8763 \. . . 1791. . 8783 \. 1786. . . . . . . . . . . . . . . . . . 1802. 8837 \. . .fp_gset:N . . . . . . . . . . . . . . . . . . . . . . . . . 1803. . . . . . . 1781. . . . . . . 1652. . . . . 1788. . . . . . 8797 \. . . . . . . . . 34. . . . . 8759 \. . . . . . 10841 \. . . . . . . 2744 \% . . 1779. . . . . . . . . . .dim_set:c . 8821 \. . .multichoice: . .bool_gset_inverse:N . . . . . . . . 8797 \. . . .tl_gset_x:N . . 1861.bool_set_inverse:N . . . . . . . . . . . . . . 1860. . . . . . . . . . . . . .tl_gset:N . . . . . . 1798. . .fp_set:c . . . . . . . . . 1781. . . . .bool_gset:N . . . . . 1803 \::f . . 1658. . . . . . . . . . . . . . . . . 1647. 1783. . 8743 \. . 2731. . . 8805 \. .dim_gset:c . . . . . 1077. . . . . 1801. . . . . . . . . . . 318 ?: . . . . . . . . . .clist_set:N . . . . . . 1789. . . . . . . . . .tl_set:c . . . 1632. . . . . 8809 \. . . . . . . . .default:n . . . 8797 \. . . . 8821 \. . . . . 1793. . . . 1631. . .value_forbidden: . . . 1785. .choice: . . . . . . . . . . . . . . . . . . 1652. . 9439 \$ . . . . . . . . . . . 8793 \. 8763 \. . . . . . 8753 \. . . . . . . .fp_gset:c . 1779. . . . . . . . . . . . .default:V . . . . . . . . . . . . . 1790. . . . . . . . 11086. . . . . . 1863 . . . . . . . . 1789. . 8813 \. 10258 \. . . . . . . . . . . . . 1794. . . . . numbers underlined point to the definition. . . . . . . . . . . . . 1778. . . . . . . . .choices:nn . . . . 2744. 177 \ . . . 1795. . . . . .dim_set:N . . .tl_gset:c . . . .clist_gset:c . . . . 319. 9406. . . .tl_set_x:N . . . . . . . . . . . . . . . . . . 8747 \. . . . . . 9441 . . . all others indicate the places where it is used. 2744 \# . . . . . . . . 11031. . . . . . . 8821 \. 7698. . 1818. . . . . . . . . .meta:x . . . .dim_gset:N . . . 1800. . . . . . . 1811. . . . . . 34. . . . . . . . 8775 \. 3020 \::: . . 1783 \::V_unbraced . . . .int_set:N . 1784. . . . . . . . . . . . . . . . . . . . . . 1803. . . . . .multichoices:nn . . . .skip_gset:c . . . . . . . . . . . . . . . . . . . . . . .choice_code:x . . . . . . . 8813 \. . . 1793. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8755 \. . 1632. . . . . . 1782. . . . . 8797 \. . . 11112 \) . . . . . . . . 1778. 1633. . . . 1798. . . . . . 1863. 1796. 1636. . 1800. . . . . . 1785. 34. . 1788. . . . . . . . . . . . 34. . . . . . . . . . . .choice_code:n . 8821 \. . . . . . 1640. . . . . . . . . . . . . .clist_gset:N . . . 34. . . . . . . . . . . . . 1806 \::n . . . 177 \: . . . . . . . . . . . 1798. . . . . . 1780. .meta:n . . . . . 8763 \. . 11267 ** . 1638. . . 8783 \. .initial:V . .int_gset:c . . . . . . . . . 8759 \. . . . . . . . . . . . . . . . . 8751 \. . . . . . . . . . 2744. . . . . 1636. . . . 9407. 8755 \. . . . . . 1813 \::c . . . . . . .fp_set:N . . . . . . 1795. . . . . . . . . . . . . . 1805. . . . . . . . . . 1781. . . . . 8821 \. . . 8775 \. . 1630. . . 1634. . . 2711. .skip_gset:N . . . . 34. . . . . . . . . . . . . . . 1802. . . . 1863 \::V . . . . . . . . . . . . . . . . 1805. 1636. . . . . . . . 2722. . . .bool_set:N . . . 1652. . . . . . 1806. . . . . 178 \* 2709. 1778. . . . 2715. 8793 \. .initial:n . . 1799. . . . . .code:n . 1633. . . . . . . 2729. . . . . . . . . . . 8783 \.Index 689 Index The italic numbers denote the pages where the corresponding entry is described. . . . . . . 8791 \. . . 1801. . . . . . . 1862. 1780. . . . . . . . . . . . Symbols \! . . 8775 \. . . . . . . 1797. . . . . . . . 2210 \__bool_S_1:w . . . . 2173 \__bool_if_or:wwwn 2162. 10056. . . . . 14090 \__box_rotate_quadrant_four: . . . . . . . . . . . . . . 1801. . . . . . . . 1823. . . . . . . . 188. 3019. . . 2225 \__bool_eval_skip_to_end_auxiii:Nw . . . . . . . 12936. . 9795 \\__fp_decimate_auxiii:Nnnnn . . 14276. . 7749. 2175 \__bool_p:Nw . . . . 2172. . . . . 14146 \__box_rotate_quadrant_three: . . . . . . . . 10044. . . 7531. 1790. . 2167. . . . 9795 \\__fp_decimate_auxvi:Nnnnn . 2194 \__bool_)_0:w . . . . . 2229. 1801. . . 14157 \__box_rotate_x:nnN . . . . . . . . . . 9795 \\__fp_decimate_auxiv:Nnnnn . . . 2744. . . 14208. . . 8298. . . 7530. . . . . . . . . . . 8339. . . . . . . 7674. . . . . . 9438 \} . . . . . . . 9054 \@filelist . . . . 7838. . . 2176. . . . . 8298. . . 2199 \__box_resize:Nnn . 1647. . . . . . 8074. . . . 1800. . 14078. . 9795 \\__fp_decimate_auxxiii:Nnnnn . . . . . 14154. . 11234 \@ . 2221. . . . . . . . . . 9595. . . . 742 \@@hyph . 1861. . . . 1777. 14152. . 2193. . . . 223 \@namedef . 4729. . 14124. 55. . . . 14099. . . 9204 \@ifpackageloaded . . . . . . . . . 65 \\ . . . . . 2162. . . . . . . . . 14168 \__box_rotate_quadrant_two: . . . . . . 1652. . . . . . . 747 \@@underline . . 15113. . . . . . . . . . . 1861 \::o_unbraced . . 2201 \__bool_eval_skip_to_end_auxi:Nw . 14100. . . . . . . . . . . 1788. . 8994. 14213. . . 8055. 8299. . . . . 2182. . . . . 8387. . . 14163. 1638. . . . . . . . 7658. . . . . 34. . . . . . . . . . . . . . . . . . 1792. . . . . . . . . . . . . . . . . . . . . . 9795 \\__fp_decimate_auxxvi:Nnnnn . 11284 \. 10059. . . . 9413. . 4. . . 205 \@nil . . . . 14078. . . 1474. . 9160. . . . . . . . . 9795 \\__fp_decimate_auxx:Nnnnn . 8062. . . 2216. . 1638. . . . . . 1791. . . . . 7532. 2162. . . 1789. . 748 \@addtofilelist . . . 10047. . 2169. . . . 9795 \\__fp_decimate_auxxv:Nnnnn . . 9189. 8993. . . . . . . . . . . 14104. 7633. . . . . . . 5. . . . . . 2744. . . . . . . . . . . 90. . . . . . . . 7653. . . . . . . . . . . . . . 9444. . . 9161 \@currname . . . 190 \@pushfilename . . . 2182. . . . . . . 186 \@tempa . . . 2178. 1799. 2210 \__bool_:Nw . . . . . . . . . 1787. 1782. . . . . . . 1804. 1805. 9588. . . 1658 \::v_unbraced . . . 8294. 7. . . . 2214. 2215 \__bool_if_left_parentheses:wwwn . . 9020. 1797. . 2216. . 9795 \\__fp_decimate_auxix:Nnnnn . . . 9795 \\__fp_decimate_auxv:Nnnnn . . . 9795 690 \\__fp_decimate_auxxii:Nnnnn . 1784. . . . . . . 9795 \\__fp_decimate_auxxi:Nnnnn . . . . . . . . . . . . 1779. . 1635 \::v . 10049. . . . 4730 \@@end . . . 3020 \= . . . . . 1793. . . 200. . . 14078. . 14165. . . . . 14187 . 15120 \_ . . . 1794. . . . . 14254 \__box_resize_common:N . 14237. . . . 9795 \\__fp_decimate_auxxiv:Nnnnn . . . 1864 \:N . . . 142. . 2732. . 1798. . . . . 2210 \__bool_)_1:w . . 170. . . . . . . 9440 \^ . . 2210 \__bool_choose:NNN 2196. . . . 2177 \__bool_if_parse:NNNww . . . . 8978. 2200. . . . . . . . . . . . 1786. . 14078. .Index \::o . . . . . 7696. . . . . 1862. 1860. . . . 2216 \__bool__1:w . . . . . . . . . . . . 14174. 1077. . 1811. . . . 1805. . . 2168. . 1790. . 14105. . 170. . . . . . . . . . . . . 14176. . . . . . . . . . 8091. . . . . 7846. . . 2744. . 2219. . 208 \@popfilename . . . . 1078. . 171. 34. . . . . . 1647. . . . . . . . . . . . . . . . . 1802. . . . . . . . 9795 \\__fp_decimate_auxii:Nnnnn . . . . . . . 1863 \::p . . 2216. . 9007. 14179 \__box_rotate_quadrant_one: . 2165. . . . . . . . . . . 34. . 2197. . . . . . 9000. 8303. . 2217. . . . 9026. . . . 2216. . . 2744. . 8298. . . 7673. 14192. 2214 \__bool_(:Nw . . 1791. . 10. . . 2233 \__bool_eval_skip_to_end_auxii:Nw . 8299. . . . . . . . . . . . . 14185. . . 8205. . . 10048. . 9795 \\__fp_decimate_auxviii:Nnnnn . . . . . 14281. 8389 \? . . . . . 7677. . . . . 8090. . . . 2821. . . . . . . . . . . . . 1804 \::x_unbraced . . . . . 8294. . . . . . . . 34. . . . . . . . . 57. 7533. . 14078. . . . . . . 1796. 7697. . . . . 2174. . . 8075. . . . . 1799. 14220. . . . . . . 9187. . . . . 10060 \\__fp_decimate_auxi:Nnnnn . . . . . . . . 2192 \__bool_S_0:w . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7651. . . . . . . . 2733. . . . . 1635. 1803. . . . . . . . . . . 745 \@@input . . . . . . . 2178 \__bool_if_right_parentheses:wwwn . . . . . . . . . . . . 10258 \__bool__0:w . 1805. . . . 14281 \__box_rotate:N . . . . . . . . . . 14086. 1785. . . . . . . . . . . . . 7678. 9795 \{ . . . . 746 \@@italiccorr . . . . . 2180. 7659. . 2744. . . . 8294. . . 1818 \::x . 9795 \\__fp_decimate_auxvii:Nnnnn . 2231 \__bool_get_next:NN . . . . 2201. . . 14078. 9581. . . . . . 14441. . . . . . 5873. . . . . 6083 \__clist_use:nwwn . . . . . . . . 5926. 6073. 14455 \__clist_item_n_loop:nw . . 7184. 7459. . . 1193. . . . . 5852. . 5888. . . . . . . . . 6127 \__clist_pop:NNN . . . . 14526 \__clist_wrap_item:n 14461. 14519. 7186. 6043. . . . . . . . . . . . . . . 7064. . 1216. 14640 . . . . 14514. 6134. . 14403. 5826 \__clist_count:n . . 5910. . . 6602. . . . . . . . . . 14150. . . . . . 14135. 6134. . 25. . . . . 6041 \__clist_item:nnNn . 14461. .Index \__box_rotate_y:nnN . . . 1193. 5950. . 7387. . 5869. . . . 6034. 14513. . 14631 \__coffin_find_corner_maxima_aux:nn . . 14503. 5940 \__clist_if_empty_n:w . . 14440. . . 14433 \__clist_item_N_loop:nw . 14078. . 14502 \__clist_if_empty_n:wNw . . . . . . . 6000. 1225. . . . . . . . . . . 5862. . . . . . . . . 14494. . . . . . . . 7176. 7071. . . 4187. . . . 5803. . . 14161. . . 14170. . . . . . . . . . . . . 14520. . . . 14631. . 6122. 6039. . . . . . . . . . 7584. . 4603. 7426. 1193. . 14436. . 5951 \__clist_put_left:NNNn . . 7028. 1224 \__chk_if_free_cs:N . . . . . . 7106 \__coffin_display_attach:Nnnnn . 5889 691 \__clist_remove_all: 5999. . . 6148. . . . 14401. . . . . . 6032. . 14492. . . . . 6061. . 5909. 5885. . . . . . . . . . . 14458. . . . . 5863 \__clist_trim_spaces_generic:nn . . 14431. . . 6079. . . . . . . . 6075. 5847. . . 5875. . . . . . . . 5912. . 7465 \__coffin_display_handles_aux:nnnnnn . . 14431. 14651. . 1214 \__chk_if_free_msg:nn . . 7421 \__coffin_calculate_intersection_aux:nnnnnN . 14473. . . . 14553. . 5909. 14444. . . 7158. . . . . . . . . 5999. . . . . 14480. . . . 3476. . . . . . . . . . . . . . . 7189. 4597. . . . . 5932 \__clist_pop:wwNNN 5909. . . . . . 7013. 1278. . 7594. . 1057. 6152 \__clist_count:w . . 7607 \__clist_concat:NNNN 5822. . . . . 14462. 5956 \__clist_pop_TF:NNN 5935. 5898. . . 5983. 6082. 7467. . . . 14409. . . . . . . . . 14449 \__clist_item_n_strip:w . 6083 \__clist_map_unbrace:Nw 6073. . . . 7584. . . . . . . . . . . . . . 14424. . 5839. . 6025 \__clist_remove_all:NNn . 6045 \__clist_trim_spaces:n . 14148. . . . 7473 \__coffin_display_handles_aux:nnnn . . . . . . . . 7013. . . . . . . . . . . . 14401. . . . . . 1047. 24. . 6086 \__clist_map_variable:Nnw . . . . 14490 \__clist_trim_spaces:nn . . . . . . 5948. . . 6003 \__clist_remove_all:w . . 5825. . . . . 1886 \__chk_if_exist_cs:c . . . 5839. . . . 4501. 6026. . . . . 1620. 5987 \__clist_set_from_seq:NNNN . 6106. 5858. . . . . 14447. . . . 6498. . 14172. 7387. 6066. . . 14505 \__clist_if_in_return:nn . 5848. . . . . . 14439 \__clist_item_n_end:n 14431. . . . 14484 \__clist_tmp:w . 13942 \__chk_if_free_cs:c . . . . 14552. . 14406. . . . . . . . . . 14492. . . . 14651 \__coffin_find_bounding_shift_aux:nn . 6026. . . . . . . . . . . . . . . 14428 \__clist_item_n:nw . . 14651. . . . . 7454. 5842. . . . 6157 \__clist_get:wN . . . . . . 14506. . . . . 6057. . 6609 \__chk_if_exist_cs:N . 14183 \__box_show:NNnn . . . . 5906. . 6013. 7097. 1216. . . . 1215. . . . . 7055. 5918. . 14638. 5903. 14506. . . 6075. . 5999. . . . . . . 7121. . . . . . . 14461. 5876 \__clist_put_right:NNNn . . . . . . . . . . . . 7019. 4411. . 7275 \__coffin_calculate_intersection:Nnn . . . . 6111. 5845. . 1216. . . . 6027 \__clist_remove_duplicates:NN . . . . 5844 \__clist_trim_spaces_generic:nw 5839. 5886. . . 14655. 5986. . 6609. . . . . . . 5921. . . . . . . . . . . . . . . . 7448. 6002. . . . . . 7475 \__coffin_calculate_intersection:nnnnnnnn . . . . . 5823. . . . 14517. 6139. 5845. . . . 14499. 6070. . . . . 7184. 4608. . . . . . . . . . . 1230. 14464. . . . . 7416 \__coffin_find_bounding_shift: . . . . 6009. . 14477 \__coffin_align:NnnNnnnnN . . . . . . 5867. 1203. . . 6005. . . . . . 14181. . . . 7013. 14465 \__clist_set_from_seq:w . . . . . . 14431. . . . . . . . . . . 13919. . . . 6592. . 1062. . . . . . . . . . . . . . 14527 \__clist_use:wwn 14506. . 7412. 14159. 5872. . . . 14631. . . 7040. . . . . 5803. . . 5913 \__clist_pop:wN . . . 6153. . 6093 \__clist_map_function_n:Nn . . . . 7387. . 5984. . . . . . . 3461. 5857. . . . 5845. . . . 1052. . 7013. . . 14657 \__coffin_find_corner_maxima:N . 14460 \__clist_map_function:Nw . . . . . . . . . . . . . . . 14530 \__clist_use:nwwwwnwn . . . . . . . . 14596. . 6849. . . . . . . . . 6891. . 1363 \__cs_generate_internal_variant:n . . . . . . . 14700. . . . . . . . . . . . 6979. . . . 2071 \__cs_generate_variant:N 1887. 1982 \__cs_generate_variant_loop_same:w . . 7203. . . . . 14670 692 \__coffin_update_B:nnnnnnnnN . 14576 \__coffin_set_eq_structure:NN . 6943. . . . . . . 1930. . . . 1940. 7227 \__coffin_offset_corners:Nnn . . 7499 \__coffin_mark_handle_aux:nnnnNnn . . . . 7167 \__coffin_update_vertical_poles:NNN . . . . . . . 14662 \__coffin_shift_pole:Nnnnnn . . . . . . . . . . 14724. 7405 \__coffin_gset_eq_structure:NN . . . . . . . 6920. . . . . . . . . 6894. . . . . . . . 14605. . . . . . . . . . 6825. . . 7240. . 6793. . . . . . . . . . . . . . 6954. . . . 1955. . . . . 6802. . . . . . 7222. . 6941. 6810. . . . . . 7244. 1325. . . . . . . . . 1959. 14731. . 7241. . . . . . . . . . . . . 7252. . 1952. . . . . . 1932. . . . . . 7245. . . . . . 1890. . 14612 \__coffin_scale_corner:Nnnn . 6848. . . . . . . . 2050. . 6871. . 14573. . . . . . . . . . . . . . . . . . . . . . . . 6910. 1354. . . . 7248 \__coffin_update_corners:N . . . . . 1942. . . 1995 \__cs_generate_variant_loop_long:wNNnn . . . . 2022 \__cs_generate_variant:wwNw . 6803. . . . . 14746. . . . 1916. . . . . . . . 6827. . . . . . . . . . . . . . 7163 \__coffin_resize_common:Nnn . . 7375. . . . . . . . . . . 2029. . 14600 \__coffin_rotate_vector:nnNN 14590. 1932. . 14695. . . . 7148. . . . . . . . . . . 6968. . . . . . . . . . 7237. . . . . . . 1952. . . . . 14594 \__coffin_rotate_pole:Nnnnnn . . 6941. . . . . 7243. . 6945. . 7264. . . . .Index \__coffin_get_pole:NnN . . 1952. . . . . 1907. . 14731. . . 14753 \__cs_count_signature:N . 14602. . . . . 7149. 7168. . . 6762. 14720 \__coffin_rotate_bounding:nnn . . . . . . . 2042. . . . 6927 \__coffin_set_pole:Nnn . . . . 14576. . 7015. . . . . . . . . . . . . . . . . . . 6979. 1325. . 1360. . . 7256. . . . . . . . . . . . . . . . . . 6762. . 7237. . . 1923 \__cs_generate_variant:ww 1894. . . . . . . . 7169. . . 14740 \__coffin_shift_corner:Nnnn . . 1894. . . 14588 \__coffin_rotate_corner:Nnnn . . . . . . . . . . 14731 \__coffin_scale_pole:Nnnnnn . 7016. . . . . . . 14724. . 14588. . 14662. . 1358 \__cs_generate_from_signature:nnNNNn . . . . . . . 2042. 1952. . . . . 14746. . . . . . . . . 1325. . . 14546. 14603. . 1917 \__cs_generate_variant_loop:nNwN . . . . . . . . . . . . . . . . . . . 1335 \__cs_count_signature:nnN 1325. 14549. . . . . 14706. . . . . . . . 14551. . . . . 6804. . . . 7225. . 14698. . 7142. . . . 7222. . . 7268. . . . . 6857. . . . . . . . . 7401. . . . . . 7133. . . . 6870. . 7260 \__coffin_update_T:nnnnnnnnN . 6956. 25. . . . . . . . 6840. . . . . . 7141. . . 1966 \__cs_generate_variant_loop_end:nwwwNNnn . . . . . . 2059. 7146. . . . . . . . . . 14739 \__coffin_set_bounding:N . 14695. . . . . 1894. . . 1327 \__cs_generate_from_signature:NNn . . . 7171. . 14704. . 2022. . . . 7239. . . . . . 1952. . . . . . . 6927. . . . . 2068. 7215. . . . 1973 \__cs_generate_variant_loop_invalid:NNwNNnn . . . 14588. . . . . 1915 \__cs_generate_variant:wwNN . . . 7203 \__coffin_reset_structure:N . . . . . 6968 \__coffin_update_poles:N . 7208 \__coffin_offset_poles:Nnn 7139. . . . . . . . . . . 6927. . 6823. . . . 7222 \__coffin_offset_pole:Nnnnnnn . 14737 \__coffin_scale_vector:nnNN . . . . 6963. . . 1923. . . . . . . . . . 1939. 6934 \__coffin_if_exist:NT . . . 7203. . . 7136. . . 7145. . . . . 14746 \__coffin_x_shift_pole:Nnnnnn . . . . 1336 \__cs_count_signature:c . 1902 \__cs_generate_variant:Nnnw . . . . . 7379 \__coffin_offset_corner:Nnnnn . . . . 14612. . . 7237. . . . 1968 . . . 7140. . . . . . . 7152. 6776. . . . . . . 7332. 1950 \__cs_generate_variant:nnNN . . 6967 \__coffin_set_pole:Nnx . 6920. 7206. . . 6910. . . . 14733. . . . . . . 6824. . 14571. . . . . . . 1326. 7370. . . 1952. . . . 14600. 6874. . . . . . 6872. . . . . 6847. . . . 2048 \__cs_generate_internal_variant:wwnNwnn . . . . . . . . . . 2042 \__cs_generate_internal_variant_loop:n . . . . . 7402. . . . 14548. . . . . . 2061 \__cs_generate_internal_variant:wwnw . . . . . . . . . . . . . . . . . 7237 \__coffin_x_shift_corner:Nnnn . . . . . . . . . . . . . . . 6773. . . 14692. . . 14662. 1945. . 341. 1805. . 1386. . 1423. . 9043. . . 1655. 4593. . . 1090 \__cs_split_function_auxii:w . . 336. 89. . . . . 323. . . 345. . 4305 \__dim_eval:w . . 6536. 25. . . . 348. . 6649. . . . 1754. . 4314. . . . . . . 1226. 4475 \__cs_to_str:N . 344. 2010 \__cs_get_function_name:N 25. 1261. . 362. 1430. . . . . 4580 \__dim_strip_bp:n . . 1865. . 330. . 1264. 4265. . 1422. . 1675. 4248. . . 1414. . 322. 4318 \__dim_case_end:nw . 6705. . . . 4317. . . . 4312 \__dim_case_aux:nw 4307. 4250. 4279. . . 1076. . 920. . . 1245. 6705. . . 1295. 364. 1920. . 326. 1418. 4233. . 337. . 14285 \__driver_box_scale_end: . . 4231. 335. . 320. 355. . . 6213. 1416. . 693 6538. 1829. 7. 4378. . . . . 1388. . . . 14319. 4282. . . . . . . 1007. 25. . . . 1412. . . 1413. . 2030. . 6549. . . . . . . . . . . . 324. 1847. . 4274. 4244. 4378. . 1841. 1375. 14287 \__driver_box_use_clip:N . 4307. 4575. 2087. 4211. 1415. . 329. . . 4248. . 353. . . 4294 \__dim_compare_:w . . 356. . . 4234. . . . . 4268. 4234. . 1095. . 1628. . . . 4300. 363. 1630. . . . . 4240. . 4380. 4388 \__driver_box_rotate_begin: . 14063 \__expl_primitive:NN 310. . . . 6662. 1067. . . . 1867 \__expl_package_check: . . 219. . . 4384. 1387. . . . 1390. . . . . . . 14360. 4384. 6551. 1630. 907. 1856. . 89. 1410. . 4242. . . 4379. . 1631. 1677 \__exp_eval_register:N . . 1705. 1263. 351. . . 1258. . 1250. . . 1073. . 331. 1234. 14560 \__dim_maxmin:wwN 4231. 340. . 1661. 4295. . . . 6551. 6649. . . 1091. 925. . 13885. 1881 \__exp_last_two_unbraced:noN . 14319. . . . . 1637 \__exp_arg_next:nnn . . 5799. . . 14360. . . . . 1805. . . . . . 1239. 1639. 1424. . 4569. 346. 89. . . 4227. . . . . 6629. . . . . . . 1419. 4271 \__dim_compare_<:w . 317. . 10947. 1820 \__exp_arg_next:Nnn . . . . . 1244. .Index \__cs_generate_variant_same:N . 1008. 4222. . 1085. 1076. 1971. . . . 1408. 4380. 4307. 1242. . . 1237. 1247. . . 4265. . . . . . 1235. . . . 7560 \__exp_arg_last_unbraced:nn . . 1380. . . . . 4577. . . 2609. 4313. 6549. 1381. . 338. 1642. . 1650. 4227. . . . 2010. . 1350. 4381 \__dim_strip_pt:w . . 6677. 318. 1265. . 1888 \__cs_split_function_auxi:w . . 1297. 1816. . . . . 7557. . . . . . . 1654. . . . . 1379. . 6555. . . 4271 \__dim_compare_>:w . 1664. 1267. . . . 4273. 7574. 1096. 4380. . . . 4568. 1876 \__exp_eval_register:c . . 367. 4211. 1260. . . . 2052. . 352. . . 1249. 1831. . 1076. . . . . . 1262. 1253. 1660 \__exp_eval_error_msg:w 1664. . . 6629. 325. 1429. 14115 \__driver_box_scale_begin: . 4465. 1389. 4236 \__dim_case_aux:nnn . 4271. . . . . 4310. . . . 310. 6493. 359. 1428. 1248. . 4573. 1339 \__cs_parm_from_arg_count_test:nnF . . . 4384. . . 1407. . . . 1728. 1393. . 1098. 1074 \__cs_to_str:w . . . . . 1630. . 1095. . . 1398. . . . 1394. 366. 1459. . . 4254 \__dim_ratio:n . 6540. 4249. 361. . 6536. 1399. 4579. . . 319. 4268. . 328. 357. . 347. 4271 \__dim_compare_end:w . . . 1382. . 1470. . . 1256. . . 365. 14113 \__driver_box_rotate_end: . . 1259. 343. 4183. 1252. . 332. . 4222. 4182. . 6553. . . 89. . . . . . 6555. 1074 \__dim_abs:N . . . 1067. . . . 4381. . . . . . . . 6553. 4181. 1092 \__cs_tmp:w . 1815. . . 4276 \__dim_compare:wNN 4271. . . . 4241. 1241. 333. . 1710. 4252. . 1095 \__cs_get_function_signature:N . 4263. . 1238. . . 1747. 1664. 1266. . . . . 14311 \__driver_color_ensure_current: . 3381. . 1474 \__cs_split_function:NN . 1664. 1254. 1425. . 1427. 1082. 1384. 1326. . . . 4401. . 7541. 350. . 321. 1676. 4264 \__dim_set_max:NNNn . . 349. 1866. 4379 \__dim_strip_pt:n . 1257. 1411. 1316 \__cs_show:www . . 4320 \__dim_compare:w . 5393. . . 6538. . 4181. 339. . . 1071. 1905. 1808. . 8378. 4240. 1812. . 1376. 1396. 1397. . . 1295. . . . . 7551. . . . 1420. . 1421. . 6540. 4262. 1378. . 1391. 4279. . . . . . . . . 1240. 1668. . . . . 1246. 1722. . 14362. . . . . . 1385. 1070. . . 4381. 1417. 1426. 1236. 1360. . 764. 4179. . . 1409. . 1377. 9629. 6677. . 1255. . 327. . . 1097 \__cs_parm_from_arg_count:nnF . 1821. 1392. . . 1295. . 342. 6662. 360. . 2485. 334. 1251. 354. 14558 \__dim_eval_end: . . 25. 6715. . 1746. 14362. 1383. . 14317. 1395. 14317. . 4571. . 358. . 580. 679. 11739 \__fp_add_significand_o:NnnwnnnnN . . 12175. . 714. 429. . 638. 483. 469. . 379. 736. . . . 560. 371. 11704. . . 716. 663. 512. . 9145 \__file_input:n . . 471. 697. . 430. 382. . 13739. . . 499. . . 9094. . . 649. 13794. . . . 707. 9095. . . . . . 659. 473. . . . 692. . 553. 633. . 733. 418. 539. . . 9151 \__file_name_sanitize:nn . . . . 13743 \__fp_add_big_i_o:wNww . 536. . . . . 577. 602. . 640. . 425. . . 375. 9233. 11712. 436. . 721. 706. . . . 565. . . . . 557. 723. . 394. 11739. . 472. 625. . 670. 431. . 9172. 387. 466. 626. 534. 713. 569. . . . . . . . 13784. . 621. . 11681. 392. 465. . 11717. . 9171. . 537. . 397. . 710. . 11701. . 444. 507. 490. . 488. . . . 424. . 717. . . . . 11749 \__fp_add_significand_no_carry_o:wwwNN . 617. . . 370. . 11514 \__fp_abs:NNN . 644. 592. 372. 618. 11658 \__fp_add_normal_o:Nww 11637. . . 568. 695. . 9180. 412. 11734. . 497. 373. 605. . . 381. . 576. . . 502. . 578. . . . 400. . . . 443. 516. . 645. 11638. 426. 561. 386. . . 555. 540. . 669. 627. 619. 529. . 399. 11646. 378. 481. . . 724. . 460. 383. 404. . 681. 11724 \__fp_add_significand_test_o:N . 527. 729. 13741. . 643. . 728. 574. 639. 13742. . 652. . 563. . 11736. . 612. . . 726. 439. 632. 672. 685. . 566. 480. 476. . 657. 727. 459. . 637. . 662. 414. . 505. . 591. 464. . . 11717. 9173 \__fp_ . . . . 11709 \__fp_add_inf_o:Nww . 415. . . . 391. . 522. 635. 596. 523. 712. . . 166. . . 494. 12015 \__fp_^_o:ww . . . . . . 547. 9100. 622. 454. 9074. 585. 684. . . 722. 9150. . 542. . 416. 398. . 434. . 451. . 470. . 518. . 377. . 12167 \__fp_-_o:ww . 587. 457. . . 493. 674. 709. . . 442. . . . 401. . . 549. . . 647. . . 664. 558. 623. 427. . 468. . 590. . 606. 384. 607. 458. . . . 735. . 449. . . 651. 581. 675. . 691. . 369. . 11719. . . 535. . . 419. 699. . 600. 641. 467. . . 614. . 533. . 9170 \__file_input_aux:o . 526. 452. 725. . 447. 485. 13740. . 703. . 636. . . 628. 500. 611. . . 420. 680. . . . 678. 599. 646. 682. . 715. 588. 630. 450. 514. . 456. 732. 453. 570. 498. 506. . . 719. 446. 603. 9172. . 417. . 508. 613. . . 405. 608. 711. . . 428. 545. 13297 \__fp__o:ww . 486. . . . 406. 701. 11640. 708. . 552. 579. . 610. 519. 683. . . 582. 11532. 13785 \__fp_add:NNNn . 551. . 624. . 575. . . 11717. . . . . 513. 629. 9094. . 445. 677. . . 11749. . . . 393. 720. . . 207 \__file_add_path:nN . 13798 \__fp_abs_o:w . 461. 586. 403. 474. 13784. . 668. . 479. 388. . . 11658. . . . . 673. 572. 598. . . . 9137. 567. 739 \__expl_status_pop:w . 511. . . . 9153 \__file_input:n\__file_input:V . 11905 \__fp_+_o:ww . . . . 589. . 698. 517. . 648. . 689. .Index 694 368. 11525. 525. 688. 593. 435. 12936 \__fp__o:w . 616. 532. . . . . 11678. 658. 478. . . . 423. 554. 484. . 408. 700. 731. 504. 562. . 694. . 376. 433. 653. 11731 . . 11721. . 550. 11701. . . 548. 9104 \__file_input:V . 11694. 411. . 422. 655. . . 730. . . . 544. . . 390. . 665. 615. . . . . . . 693. 396. 686. . . 634. . 666. 437. . . . 530. 11701. 559. . 696. . 737. 510. . 601. 538. 9095. 477. . . . . 374. 690. . . . . 491. . 9096 \__file_add_path_search:nN . . . 564. . 556. . . . . . . . . 11646. . . . 410. 9154. . 687. . . 9142. 9137 \__file_input_aux:n 9137. 734. 631. . 524. 380. . 11678 \__fp_add_npos_o:NnwNnw . . 11687 \__fp_add_return_ii_o:Nww . . 597. 9223. 421. . . . . . 705. 395. 9338 \__file_path_include:n . 9074. 660. . . . . . . . . 440. 620. . . . . . . . . . . 441. . 389. . . . . 509. 11717 \__fp_add_significand_pack:NNNNNNN . . 496. . 609. . 604. 462. 13788. 13784. 667. . . 482. 407. 546. . . 409. 11522 \__fp_*_o:ww . 515. . 702. 503. . 718. . 573. . 704. 448. . 385. 402. . . . . 595. . 463. 531. 13739. 487. . . . . 571. 455. 495. . . 489. 661. 650. 584. . 594. . 543. 521. 12764 \__fp_add_big_ii_o:wNww . 13785. . . 12175. . . . . 413. 11687. 583. 11651 \__fp_add_significand_carry_o:wwwNN . 642. 11623 \__fp_-_o:w . . 676. 432. . . . . . 541. . 501. . . . 9147. 654. . 738. 475. 492. 520. . 438. . . 11697. . 671. . . . . 656. 528. . 11618 \__fp_/_o:ww . 11948. 11366. 13835 \__fp_assign_to_ii:NnNNN . 11994. . . . 13226. 12999 \__fp_case_return_same_o:w . 12980. 13201 \__fp_decimate:nNnnnn . . . 11608. 13008. . 11505. 9653. 11659. 9871. . . . . . 9835. 13006. 13651 \__fp_case_return_i_o:ww . . 12167. . . . . 13176. . . 12978. . 12976. . 11138 \__fp_compare_aux:wn 11348. . . . 12518. . 9827. 9826. 9779. . . . . . . . . . . 11937. 13186. . 13818. . . 9825. 13005. 10769. . 13181. . 11653. 11608. 13124. 11952. . 13174. . . . . 13201. 11644. 11687. . . 9802. 12508. . . . . . 9657. 11351. . 9833. 12956. 12384 \__fp_basics_pack_high_carry:w . . 11392. 11608. . 11678. . 11392. . 10727 \__fp_chk:w . . . 9833. . . . . . . . 9749. . . . . . . . 11528. . 9829. 13825. . 13241. . . . . 10929. 10018. . 12958. . 13508. . 13251. 13557. 11370. 11534 \__fp_array_count:n . . 13212. . . 13829. . . 9707. 9791. . 12780. 12967. . . . 12744. 11592. . 13698. . . . . . . 13206. . . 11943. 13490. 12996. . . . 9831. 11711. 12511. 13109. 11744. . 13844 \__fp_compare:wNNNNw . . 11375. 11940. . 10707. 11485. 13827. . 13182. . 11599. 9833. . . 10745. . 12175. 12697. . . . 9693. . . 11648. . . . . . 11592. 12031. 13246. 9717. . 13246. . 11945. . . 13487. . 11914. . 13607. . 13608. 11938 \__fp_case_return_ii_o:ww . 9874. 13511. . . 13199. 12157 \__fp_basics_pack_weird_low:NNNNw . 9644. . . . 12026. . . 13246 \__fp_cot_zero_o:Nnw . . 12748. 13214. 9825. 11225. . . 13550 695 \__fp_cfs_round_loop:N . . 9655. 13171. 13624. 11949. . 9654. . . 11497. 10176. . . 11656. 11482. . 11565. . . 11001 \__fp_array_count_loop:Nw . 10707. . 11506. . 13540. 10233. 13533. 12737. 11676. 12732. . . 13257 \__fp_case_use:nw . . 11753. 11765 \__fp_compare_return:w 11335. . . . 11606 \__fp_basics_pack_low:NNNNNw . . 13191. . 13221. . 13686 \__fp_array_to_clist_loop:Nw . 11624. 11337. 11648 \__fp_and_return:wNw 11522. 9659. . . . . 13186. 11340. 9822. 11616. . 11893. . 9871. 9791 \__fp_decimate_pack:nnnnnnnnnnw . . 12973. 11996. 12522. . . . 11592. . 11400 \__fp_cos_o:w . . . . 13122. 11361. . . . 13246. . . . . 9669. . 11639. 10723. . . . . . 13675. 10797 \__fp_cfs_round_up:N 10715. 13204. 12940. . . 11675. . 11647. . . . . 11340 \__fp_compare_significand:nnnnnnnn . . . . 11392. . 9793 . . . . . 13782. 13244. . 13605. 9821 \__fp_decimate_pack:nnnnnnw . . 9730. 13835. . 10187. . . . 13560. . . 9663. . . . . . 13271. 13818. . . 10189. . . . 12985. . 12937. 13537. . . 10013. . . . . . 13242. . . 12784. . 11648. 13693. 9779. 13216. . 11602. . . . 11395. . 11662. 13775. . 13818. . . . 9840. . 11364. . 13261 \__fp_csc_o:w . 9823 \__fp_decimate_tiny:Nnnnn . . 11790. . . 9826. 13837. . 13826. 9871. 11742. . . . . 11936. . . 13259. . . 11643. . . . 13219 \__fp_case_return_o:Nww . 9821. 13249. . . . 9791. . 9697. . 13501. 11514. . . 12023. 12386 \__fp_basics_pack_weird_high:NNNNNNNNw . 9829. 11528. . . . 12008. . 12159 \__fp_case_return:nw . . . 13832. . 9640. 12970. . . 9673. 9827. . 13211. . . . 12148. 12514. 9879 \__fp_array_to_clist:n 10173. . 13201. . . 11592. . . 11365. . . 13686. 13828 \__fp_cot_o:w . . . . . . . . . . . . . 11540. 13227. 9842. . . . 13229. . . . 11939. . 9696. 11942. . . . 12945. 9660. 13003 \__fp_case_return_o:Nw . 11391 \__fp_compare_npos:nwnw . . . . 9831. 12146. . . 9878. 13299. 13236. . . 11369. . 9837. . . . . 13841 \__fp_basics_pack_high:NNNNNw . 13290. 12729. . . . 10185. 11496. 11646. . 11525. 10712. . 12740.Index \__fp_add_zeros_o:Nww 11636. . 13708 \__fp_assign_to:nNNNn . . . 13828. . 13674. . 13566 \__fp_decimate_:Nnnnn . 11941. . 11944. 9656. . . 13256. . . 12006. . 11364. 11763. 13483. . . . 11364. 11359 \__fp_compare_back:ww . . 12987. 13186. . . . 13601. . 13830 \__fp_assign_to_i:wNNNn . . . 11755. 11495 \__fp_compare_nan:w . . 12179. . . . . . . 13686. 13196. . . . . . . 13234. 12746. . . 12964. . . 11664. 12961. . 9853. . . 9641. . . 11895. . . . . 13189. 11474. . 13184. . . 13231. . 12520. 13197. 12959. 13024. 12171. . 11703. . . . . . . . . . . . . . . 12577. 12770. . . 11555. . . . . 12877. . . 12177. . . . . . . . 12876. . . 12118. . 12708 \__fp_fixed_add_after:NNNNNwn . . . . . . . 9747 696 \__fp_exp_after_normal:nNNw . . 12690. . 12236 \__fp_fixed_add:wwn . . . . . . . 12108. 12230. . 12902. . . 12843. . . 12056. . . . . . . 12913. . 13876 \__fp_fixed_add:Nnnnnwnn . 12043. . 12098. 11647. 9884. . 12890. 13267 \__fp_error:nffn 9954. 13121. 9977. 9697. 11048. . . . . . . 12751. 12113 \__fp_div_significand_large_o:wwwNNNNwN . . . 10029. . . 12227. 12781. . . 9756 \__fp_exp_large:w . 9988. . 12924. 12891. . . . . 12797. 12748 \__fp_exp_o:w . . . . . 12824 \__fp_expand:n . 12894. 12671. . . 12857. 12153 \__fp_div_significand_pack:NNN 12100. . 12053. 11530. 12931 \__fp_exp_large_i:wN 12824. . . . . . . . 9712. 12839. 12806 \__fp_exp_Taylor_loop:www . . . 12919. 10928 \__fp_exp_after_normal:Nwwwww 9739. . . 12862. 12059. . . . . . . . 12861. . . . 12838. . 12226. . 12795 \__fp_exp_pos:NNwnw . . . . 12910. 12875. 12870. . 12909. . . . . 12597 \__fp_div_significand_calc_i:wwnnnnnnn . 12748 \__fp_exp_pos_large:NnnNwn . . . . . 12908. . . . . 10025. 12871. . . . . . . 12859. 12860. 13690 \__fp_expand_loop:nwnN . . 12889. . 12822 \__fp_exp_Taylor_ii:ww . 12134 \__fp_div_significand_v:NN . 12886. 12785. . . . . 10038. 12858. 12030 \__fp_div_significand_calc:wwnnnnnnn . . 12515. 9673. . . . 12226. . . . . 12105. 12244 . . . . . . 12817 \__fp_exp_after_array_f:w . 9836. . . . 12051. . 10245. 10341. 12921.Index \__fp_div_npos_o:Nww 12020. . . . . 12226. . . 9722. . 11513. . . . . . . . . . . 12105 \__fp_div_significand_iv:wwnnnnnnn . . . . . 12137. . . . 10837. . . . . . . . 9963. . . . . . . . . . . 12139. . . . . 12748. . 12897. . . . . . . 12054. . . 9880. 12030. 10227. 9750. 12922. . . 10183. 13265. 12883 \__fp_exp_large_iii:wN 12824. . . . 12133. . 12807. . . . 12120. . . . 12824. . . . . 12226. . . . . . . . . . . 9834. . . . 12590. . 9697. . 12143 \__fp_div_significand_test_o:w . 13825 \__fp_exp_overflow: . . . . 9697. . . . 12226. 12865. . . . 9750. 12797. . . 12906. . . 9946. . . 12797. . . 9750. . . 11578. . . . . . . 13290 \__fp_exp_after_special:nNNw . 10038 \__fp_error:nnfn . . . 9697. . 12811. . 12846. . . . . 9710. . . . . 12824. 12844. . 12098 \__fp_div_significand_iii:wwnnnnn . 12052. . . 12047. . . 12756 \__fp_exp_pos:Nnwnw . . 12797. 12907. 12888. . . 12133. . . 9880. . . 9702. . 9707 \__fp_exp_after_o:w . . . . 12753. . . . 10016. . . . . . 12899 \__fp_exp_large_ii:wN 12824. 9727 \__fp_exp_after_stop_f:nw . 12835. . 12925. . 12081 \__fp_div_significand_i_o:wnnw . . . . 12027. . . . . . 12833. . . 12143. . . . . . . 13871. . . . . 10028. . . . 12603 \__fp_div_significand_small_o:wwwNNNNwN . . . 12734. . . 12729. 12856. 12056. . . 12134. . . . . . . . . . . 9753. . 9737 \__fp_exp_after_o:nw . . . . 12849. 12887. . 12842. . . 12045. 12228 \__fp_fixed_add:nnNnnnwn . . . . 12972 \__fp_division_by_zero_o:Nnw . 12124 \__fp_division_by_zero_o:NNww 9985. 12113. 9720. . 12918. . . 12043 \__fp_div_significand_ii:wwn . . 12881. . . . 12153. . 12226. . . . 9717. . . 10040 \__fp_exp_Taylor:Nnnwn . 12595. . . . . . . . . . . 11544. . . . . 12893. . 9880. 12905. . . . . 12116. . . . 12915 \__fp_exp_large_after:wwn . . . 12878. . . . . . 9737. 12679. . 12867 \__fp_exp_large_iv:wN 12824. . 12056. . 12854. 12874. . . . . . . . . . . 10038 \__fp_error:nnnn . . . 12873. 11586 \__fp_exp_after_f:nw . 12729. 12872. 12926 \__fp_exp_large_:wN . . 12803. . . . . . . 12923. 9700. . . . . . . 9727. . 9980. . . . . 12824. . . . . . . 12840. . 12841. . 13108 \__fp_exp_normal:w . 12851 \__fp_exp_large_v:wN 12824. . 12169. 12845. . . . 12929. . . . . . . . . 12113 \__fp_div_significand_vi:Nw . . . . 9882. 12892. . . . . . 9830. . . 12113. 12903. . 10038. . . . . . . . . 12037. . . 12904. . . . . 12056. . . 12824. . . 12920. . . 12123 \__fp_div_significand_v:NNw . . 10025. . 12102. . 12064 \__fp_div_significand_calc_ii:wwnnnnnnn . 12024. 12061. . 12808. . 12234. 12855. . 12933 \__fp_exp_Taylor_break:Nww . . 9887 \__fp_exponent:w 9673. . . . . . . . . . 12432. . 13443. . . . 12246. 12328 \__fp_fixed_mul_add:wwwn . . 13194 \__fp_fixed_to_float_pack:ww 12365. . . . . . . 12348. . . . 12853. . 12407. 12682. . . 13401. . 13209. 12294 \__fp_fixed_sub:wwn . 13393. 13387. . . . . . . . 12670. . . . 12420. . 12382 \__fp_fixed_to_float_zero:w 12361. 13664 \__fp_from_dim:wNNnnnnnn . 10025. . . 12934. 12823 \__fp_fixed_add_pack:NNNNNwn . 12286. 12415 \__fp_fixed_dtf_zeros:NN . . . . 12413. . . . . . . . . . . 12354. . . . . . 12246. . . . . . 12389. . . . . . . . . 12280. 12477 \__fp_fixed_dtf_epsilon_pack:NNNNNw . 13394. . . 9943. . 13782 \__fp_inf_fp:N . . . . . . . . . . . . . . . . . . . . 12290. 12304. . . . 13016. . . . . 12215 \__fp_fixed_div_int_auxii:wnn . . 11145. . . . . . . . . 13392. . . . . 12333. . . . 12195. 12195. . 12232. . . 13552 . . 12188. 12389. . 10025. . . 12218. . . . . . 13047 \__fp_fixed_mul_one_minus_mul:wwn 12274 \__fp_fixed_mul_sub_back:wwwn . 11138. . . . . 13666. . 12195. . . 12225 \__fp_fixed_div_int_auxi:wnn . 13455 \__fp_fixed_dtf_approx:NNNNNw . 12268 \__fp_fixed_mul:wwn . . . . . . 13648 \__fp_if_undefined:w . 13405. . 12450. 13658. 12242 \__fp_fixed_continue:wn . . 12716. . 12460 \__fp_fixed_dtf_epsilon:NNNNNww . . . . 13645. . . . . . . . . . . 12375 \__fp_fixed_to_float_round_up:wnnnnw . . . . . 12409. . 12223 \__fp_fixed_div_int_pack:Nw . . . . 13179. 13436. 12751. . . 12917. . 12317. . . . . . 12869. . . . . 12481. 12226. . . 13441. . . . . 12454 \__fp_fixed_dtf_approx:wnn 12456. . 12813 \__fp_fixed_div_int_after:Nw . 12300. . . . . . 12410. . 697 12473. . . 13444. 12488 \__fp_fixed_dtf_epsilon:wN 12472. . . . . . . 12315. . . 12195. 13669 \__fp_from_dim:wnnnnwN 13643. . . . 12205. . 13643. . . . 13671 \__fp_from_dim_test:N 13643. 13402. . . . . . 12463. . . . . 12434 \__fp_fixed_inv_to_float:wN . 12248. . . . . . . 12201. . 12333. . . . . 12226. 11176 \__fp_invalid_operation:nnw . . 12246. 13781. . 12834. 12194. 12197. . . . 12389. . . . 12202. . 12195. 12414 \__fp_fixed_dtf_zeros_auxi:ww . . 12276. . 12239. 12722. . 12204. . . . 12672. . . 12815. . . 12378.Index \__fp_fixed_add_one:wN . . . . . . . 13365. 13407. 12208. . . . . . 13670. . . 12203. . . . . 12445 \__fp_fixed_dtf_zeros_auxii:ww . . . 13542. . 12328. . 12468 \__fp_fixed_dtf_approx:n . . . . 12322. 11140. . . . 13399. . . . . 12435 \__fp_fixed_dtf_zeros:wNnnnnnn . 12837. . . . 12317 \__fp_fixed_mul_add:nnnnwnnwN . . . . . . . . . . . . 12814. . . . . . 12402. . . . . . . . . . . . 12885. . . 13396. . . . . . . . 13404. . . 12471. 12494. . . . . 11168. . . . . . . . 13503. . . . . . . . . . . . 13419. . 12901. . 12200. . . . . . 12486 \__fp_fixed_dtf_no_zero:Nwn . . 12697 \__fp_fixed_to_float:wN . . . . . . 12227. . . . 13437. . . . 12493. . . . . 13446 \__fp_fixed_one_minus_mul:wwn . 13775 \__fp_if_zero:w . . . . 12188. . 12688. . 13020. . 13391. . . . . . 13403. 13439 \__fp_fixed_mul_add:Nwnnnwnnn . 12399. . . 12333. . . . 13030. . 12396. . . . 11150. . 13774. 12296. 10001 \__fp_infix_compare:N . . . . 12195. 12370 \__fp_fixed_to_loop:N 12338. . . . . . . . . 9660. . . . . 13084 \__fp_fixed_div_int:wnN . 12442. . . . . . . . . 12717. . 12352 \__fp_fixed_to_loop_end:w . . 13435. . 12284. . 13361 \__fp_fixed_to_float:Nw . . 12395. . . . 12453 \__fp_fixed_dtf_zeros_end:wNww . 12753. . 12274 \__fp_fixed_mul_after:wn 12194. . 13224 \__fp_fixed_mul:nnnnnnnwn . . . 12220 \__fp_fixed_div_int:wwN . 13492. 12727. . . . 13654. . . . . . . . . . . . . . . . 12304 \__fp_fixed_mul_add:nnnnwnnnn . . . . . . . . . . . . . 13348. . 12474. 13643. 12704. . . . . . . . . . . . . . 13438. . . . . . . . . . . . . . 13408. 12393. 12189. . . 12404. . . 12333. . . 12274. . . 12358 \__fp_from_dim:Nw . . . 13406. 13445. . 12334. . . . . . . . . . . . . 12430. . . . 12266. . . . . . . . . . . 12425. 13389. . . . . 13433. . . . . . . . . . 12195. . . . . . . 10037. 9659. . . . 12189. . 11160. . . . . . . 12224 \__fp_fixed_div_to_float:ww . . . . . . . . . . 12274. 12490. . . . . . 13395. . . . . . . . . 12206. 12475. . . . . 13390. . . . . 12483. . . . 12699. . 13327. . . . . . . . . . 11468 \__fp_min_fp:N . 13808. . 12628 \__fp_ln_t_small:Nw . . 9661. . . . . . . . . 12694 \__fp_ln_exponent_one:ww . 12663. . 12658 \__fp_ln_twice_t_pack:Nw . . . 12250. 11508. . . . 12579. . . . 9760. 10025. 11958. . . . . . . 12588 \__fp_ln_div_ii:wwn . . 11960. . . . 12644. . . . . 13211. . . . . . 11476 \__fp_minmax_auxi:ww . . . . . . . . 12278. . . . . . . . . . . . 13049. . . 13331 \__fp_pack:NNNNNwn . . . 11489. . . . . . 9761. 12636. . . . 12307. . . . . . . 13226. . . 12802. . 12801. . 13804. 12288. 10220. . 12665. . . . . . . . 13531. . . . . 12003. 12298. . 11621 \__fp_overflow:w . . 9960. . . . . 12575 \__fp_max_fp:N . . . . . . 11468. . . . 13810 \__fp_mul_cases_o:NnNnww . . . . . . . . .Index \__fp_invalid_operation_o:Nww . . . . . . 10030 \__fp_pack:NNNNNw . . . 11352. . . . . . . 11960. . . 12536. 10251. . 12601 \__fp_ln_exponent:wn 12534. . . . . . . . . . . . . . . 9763. 12070. . . 12449. . . . . 12583. . 11491. 11986. 12659 \__fp_ln_t_large:NNw 12611. 11478. . . . . . . . . . . . 13681. . . . . . . 12661 \__fp_ln_square_t_pack:NNNNNw . . . 11499. . 12556. 12646. 12618. . . 9775. . 11965. . . . . 12616 \__fp_ln_twice_t_after:w . . . 11508 \__fp_minmax_auxii:ww . 11362. 10172 \__fp_ln_Taylor:wwNw 12662. . . . . . . . . 11512 \__fp_minmax_loop:Nww . . . 13476. 12648. . . . 12363. . . . 9770. . 13256 \__fp_invalid_operation_tl_o:nf . . . . 11910. 11913. . . 13304. . . . . . . 11979 \__fp_mul_significand_keep:NNNNNw . . . 12679 \__fp_ln_Taylor_loop:www . . 12702. 12533. 13807. . . . 12606 \__fp_ln_div_i:w . . 12447. . . 10330. . . . . . . 12652. 13306. . 11960. . 12642. . . . . 11983 \__fp_neg_sign:N . 12262. . . 12259. . 12570 \__fp_ln_x_iv:wnnnnnnnn . . . 12654. 9661. . 9777. 12508. 10885. . . 10975. . . . 12508. 12003 \__fp_mul_significand_test_f:NNN . . 13055. . . . . . 12256. . . . . . . . 12558. 12522. . 13685. . 11470. . . . 13115 \__fp_invalid_operation_o:nw . . . 13636. . . . 13683. 12664. . . . . . . . 12536. . . . . . 11468. . . . 9682. . . . . . 12556 \__fp_ln_x_iii:NNNNNw . 11951. . 13717. 9757. . . 11886 \__fp_pack_twice_four:wNNNNNNNN . 13058. . 12685. . . . . . . . 9777. . 13181. . . 13833 \__fp_parse_after:ww 10809. . . 12076. 12609. . 11484. . 9757. 13804. 12800. . 13666 \__fp_parse:n . 13028 \__fp_ln_square_t_after:w . 11962. . 12448. . . 9768. 10812. . . 11981 \__fp_mul_significand_large_f:NwwNNNN . . . . . 12719 \__fp_ln_npos_o:w . 11338. . . . 11073 . . . . . . . . . 9661 \__fp_min_o:w . 11942. . . . . 11951. 9766 \__fp_pack_big:NNNNNNwn . 12563. . . . . . 12585. 10809. 12674 \__fp_ln_c:NwNw . 12706. . . . 11512. . 10818 \__fp_parse_apply_binary:NwNwN . . . . . 10026. . . 12561. . . . . . . 11973. . 12073. . . . . 13599. 13826 \__fp_ln_significand:NNNNnnnN . . . . . . . . . . . . 12650. . 10025. . . 12630. 12582. . . . 11983. 12668. . . . 12565. 12320 \__fp_pack_eight:wNNNNNNNN . 10027. . . . . . . . 9773. . . 11501. . 12538. . . . . . 9951. . . 9689. . 12093 \__fp_pack_big:NNNNNNw . 11971. 10221. 12638. . . . 10036. . . 12522 \__fp_ln_o:w . . . . . . . . 9667 \__fp_max_o:w . . . . . . 10036. . . . 11830. . . 11504 698 \__fp_mul:NNNn . 11943. . . . 13744. 12310. . . . . 12584. . 13061 \__fp_pack_Bigg:NNNNNNw . 11907. . 13719. . 13809. . . 12593 \__fp_ln_div_vi:wwn . . 10976. . . . . . 9682. . . . . 11969. . 12586. . 12090. . . 11474. . . . 9775. . 11670. . 13241. . 11960 \__fp_mul_significand_small_f:NNwwwN . 12520. 13196. 13673 \__fp_mul_significand . . 12632. . . . 13305. . 12569 \__fp_ln_x_iii_var:NNNNNw . . . . . . 11829. . . . . 12490 \__fp_mul_significand_drop:NNNNNw . . . 12713 \__fp_ln_exponent_small:NNww . . 9763. 12657 \__fp_ln_x_ii:wnnnn . . . . . . . 11975. . . . . . . 11510 \__fp_minmax_break_o:w . . 11484. . 13329. 12017 \__fp_mul_cases_o:nNnnww . . . 12663 \__fp_ln_Taylor_break:w . . . . . . 12087. . 11667. . . . . . 13721. . . . 10809. . . 12511. . . . . 12253. . 11988. 11992. . 11508. 12694. . . . . 12313. 12634. . 13805. . 11967. 11913 \__fp_mul_npos_o:Nww . . . 13811. 11992 \__fp_mul_significand_o:nnnnNnnnn . . . 10025. . . 12364. 10885. . 13052. . 13806. . 11482. . . . . 12685 \__fp_ln_div_after:Nw . . . . . 11085 \__fp_parse_infix_-:N . . 10759. . 11196 \__fp_parse_compare_end:NNNN . . . 10859. . 11130. . 11205 \__fp_parse_compare_expand:NNNNNw . . . . . 10501. . 11138. . 10948. . . . . . . . 10269. . . . 11085 \__fp_parse_infix_::N . . 10251. . . . . . . 10807 \__fp_parse_exponent:Nw . . . . . . . . 11301. . 10802. . 10529. 11097. 11258. . . . . 10251. . . 10551. . . . . . . 10998. . . 10666 \__fp_parse_exponent_keep:N . 10875. . 10616. . . . 10852. 10761. . . . . . . 10732. . . . . . . . 11179. . . 11025. 11537 \__fp_parse_infix_:N . 10548. . . . 11077. . 10284 \__fp_parse_digits_iv:N . . . . 10283 \__fp_parse_digits_v:N . . . 10650. . . . . . . . . . . . . . . . . 11095 \__fp_parse_infix_+:N . . . 10553. . . 10611. 10516. . . . 10800 \__fp_parse_exponent_aux:N . . 10835. 11085. . . . 10609. . . . 10550 \__fp_parse_exp_after_?_f:nw . . . 11061 \__fp_parse_infix_and:N . . . . . . 11274. . . . . 10336. 11163. 10327. 11209. . . 11172 \__fp_parse_infix_juxtapose:N . . 10646 699 \__fp_parse_exponent_digits:N . . . . . . . . . . . . . . . 10660. 10518. . . . . 10606. 10500. . . . . . . . . . . . . . 10770. 10928. . . . . 11087 \__fp_parse_infix_mul:N . . 11085. . . 10639 \__fp_parse_infix:NN . 10900. . . . 11132 \__fp_parse_infix_check:NNN 10861. . 10784. 10626 \__fp_parse_exponent_body:N . . . 10561 \__fp_parse_digits_vii:N . . . 10341 \__fp_parse_exp_after_mark_f:nw . . 10546 \__fp_parse_large_leading:wwNN . . . . . . . 11046. 10492. . . . . . . 11203. . . . 11138. . . . . . . . . . . . 11190. . . 10961. 11110 \__fp_parse_infix_):N . 11104 \__fp_parse_infix_or:N . . 11118. 11191. . . . . . . . . . . . . . . . . . . 10581. 11095 \__fp_parse_infix_after_operand:NwN . 10646. . 10372. . 10999 \__fp_parse_apply_unary:NNwN . . . 10286 \__fp_parse_digits_ii:N . . . . . 10881. . . . . . . . . 11291 \__fp_parse_infix_:Nw . 11049. . . 11548 \__fp_parse_exponent:N . . . 10546. . . . 11233 \__fp_parse_infix_\meta{operation}:N . . . 11306 \__fp_parse_infix_end:N . 10619. . 10968 \__fp_parse_compare:NNNNNNw . . . . . . . 10842. . . . . . . 10611. . . . 10849. . . 11304 \__fp_parse_infix_comma_gobble:w . . . 11156. 10457. . 10436. . . . . 10405. 11138. . . . . . . . . 10616. . . . . . . . . 11187. . . . . . . . 10642. . . 10281. . . 11262. . . . 11294. . . . . . . . . . . . . . . . . 11016 \__fp_parse_apply_unary_array:NNwN . . . 11189.Index \__fp_parse_apply_compare:NwNNNNwN . . . . . . . 11101. . . 10673 \__fp_parse_exponent_keep:NTF . . 10332 \__fp_parse_exp_after_f:nw 10332. 10269. 10251 \__fp_parse_infix_^:N . 10455. 11297. . 10636. 10477. . . . . . . . . . . . 10531. . . 10837. . . . . 11138. . . . . . . . . . . . . . . . . 10775. . . 11085. . . . 11246. . 10332. 11138 \__fp_parse_infix_>:N . . 10815. . 10721. . . . 10997. . . 10278. . . . . . . 10513. . . 10616. . . . . . . 10632. 10662. . . . . 11283 \__fp_parse_infix_excl_aux:NN . 11278. . . . . . . 10640. . . . . . . . . . . . 11051. . . . . 11128. . . 11233. . . . . 10426. . . 10553 . 11138. . . . 11266 \__fp_parse_infix_*:N . . . . . 10269. . . . . . . 10624. 11120 \__fp_parse_large:N . . . . . . . . . . 11217 \__fp_parse_apply_round:NNwN 10990. . . . 11188. . . . . . . . . 10972. 10905. . . 10269. . . . 11138 \__fp_parse_infix_?:N . . . . . . . . . . 11158 \__fp_parse_infix_excl_error: . . 10673 \__fp_parse_exponent_sign:N . . . . . 10269. . . . . . . . . 11125. . 11284. 10462. . . . . . . . . . . . . . 10285 \__fp_parse_digits_iii:N . . . . . . . 10269. . . 10835. . . . 10287. . 11215. 11155. . 11268. . 10614. 11235. . 10900. 10342 \__fp_parse_expand:w . 10956. . . 11242. 10871 \__fp_parse_infix_comma:w . . 11171. . . . 10318. . . . . 10820. . . . . . . 10671. 10915. 11286. 10282 \__fp_parse_digits_vi:N . . 10479. 10636. . . . . . . . 11138 \__fp_parse_infix_<:N . . . . . 10288 \__fp_parse_digits_i:N . . . . . . . . . . . . . 10662. . . 10900. . . . . 10578. . . . 11116. . . 11042. . . 11194 \__fp_parse_digits_:N . . . . . 11272 \__fp_parse_infix_ . 11113. 10653. 10994. . . 10269. . . 10253. . . . 10390. . . . . . 11282. . . . . . . . . . . 10337. 11249. . 11085 \__fp_parse_infix_/:N . . . . . . . . 10611. . . 11219. . . . . . 10912 \__fp_parse_prefix_. . . . 10297. . 10375. . . 10593 \__fp_parse_word_exp:N . . . . . . . . . . . 10494. 10397 10887. . . . . . 10976 \__fp_parse_return_semicolon:w . . 10912 \__fp_parse_small:N . . . . . . . . . . . . . . . . . . 10496. . . 10332 \__fp_parse_word_cos:N . . . 10835. . . 10958. . . 11044 \__fp_parse_strim_zeros:N . . 10418 \__fp_parse_until_test:NwN . . 10483. . 10912 \__fp_parse_word_em:N . . . . . . . . 11012 \__fp_parse_word_max:N . . . . 10520. . . . . . . 10779 \__fp_parse_stop_until:N . . . . 10252. . . . . . . . . . . 10410 11021. . . 10912 \__fp_parse_word_pi:N . . . . . . . . . . . 10355.:Nw . . 10442. . . \__fp_parse_operand_other_word_aux:Nw . 10503. \__fp_parse_operand_digit:NN . . . . . . . . . . . . . . 10834. . . . . . . . 10468. . . 10533. . 11241. . . . . . . 10538. . 10912 . . . 10449. 10440. . . 10541. . . . . . . . . . 10321. . . . . . . . . . . . . . 10475. . . . . . . . 10972. . . . . . . 10669. . . . . 10829. 10912 \__fp_parse_small_leading:wwNN . . . 10434. . . . 10431. . 10544 \__fp_parse_word_csc:N . . . . . . . 10912 . . . . . 10912 \__fp_parse_round:Nw . 10359. 11023. 11283. . 10316 \__fp_parse_word_abs:N . \__fp_parse_operand_other:NN . . . 10951 \__fp_parse_word_cot:N . . 10996 \__fp_parse_word_nd:N . . . 10983. . 10366. . . . . . . . . . . 11309 \__fp_parse_large_trailing:wwNN . . . . . \__fp_parse_large_round_after_aux:wN . 10912 \__fp_parse_word_nc:N . . 10310. . . . . . 11080. 10472. . . . . . . .Index 700 \__fp_parse_large_round:NN . . . . 10912 . . . . 10525. . . . 10912 \__fp_parse_prefix_-:Nw . . 10520. . 10445 . . . . . . . 11040. 10975 \__fp_parse_word_min:N . . . . . . . . 11011 \__fp_parse_word_in:N . . . \__fp_parse_operand_other_prefix_unknown:NNN 11215. . 10964. . . . . . . . . 10575. . . . . . . . . . . 10533. . . . . . . . . . . . . . . 10823. . 10951 \__fp_parse_pack_carry:w . . 11011 \__fp_parse_trim_end:w 10442. . . . . . . 10654. 10980. . . . . . . . 10586. . . . . . . 11030 \__fp_parse_word_false:N . 11076. 11300. . . . . . . . . . . . . 10565 \__fp_parse_word_pt:N . . . . 10479 \__fp_parse_letters:NN 10362. 10468. . . . . 11012 \__fp_parse_word_inf:N . . . . . \__fp_parse_word_mm:N . 10823. . . . . . . . . . . . . . . . . 10912 \__fp_parse_prefix_+:Nw . . . 10622. . . 10355 \__fp_parse_operand_other_prefix_aux:NNN \__fp_parse_until:Nw . . . . . . . . . . . . . 10826. . . . . . . . . . . 10755. . . . . . 10503. . . 10332. . . . 11547 . . 10912 \__fp_parse_word_cm:N . 10960. . . . . . . . . . . . 10951 \__fp_parse_word_bp:N . . . . . . 10786 \__fp_parse_small_round_after:wN . . \__fp_parse_large_round_after:wNN . . . 10786. 11575. . . . . . . 10387 \__fp_parse_lparen_after:NwN 11034. . . 10452. 10329 \__fp_parse_word_cc:N . 11290. . . . . . . . . . 10310. . . 10910. . . . . . . . . . . . 10719. 10752 11277. . . 10743. . . 10763 \__fp_parse_small_trailing:wwNN . 10589. . 10556 \__fp_parse_word_deg:N . . . . . . 10498. . 10494 \__fp_parse_word_pc:N . . 10533. 10583 \__fp_parse_strim_end:w . . . . . . . . . . 10747. . . . . . . . . . . . . 10302. 10276. . . . . . . . . . . . \__fp_parse_word_ex:N . . . 11552. . 10294. . . . . . . . . 10994. . 10442. . . . . . 10951 \__fp_parse_prefix_:Nw . . . . . 10912 \__fp_parse_operand_relax:NN . . . . . . . . . . . . . . . . . . . . . . . 11018 . . 10795. . . . 10766. . 11038. 11065 \__fp_parse_operand:Nw . . . . . . . . 11583 \__fp_parse_operand_register:NN . . . . . . . . . 10511. . . . 10833. . . . . 10734 . . . . . . . . . . 10823. . . . . . . . . . . . . . . . . . . . \__fp_parse_small_round:NN . . . . . . . . . . 10730 \__fp_parse_word_nan:N . . 10912 \__fp_parse_operand_register_aux:www . 11257. 10951 \__fp_parse_word_dd:N . . . 10559. . 10468. 10814. . . . 10434 \__fp_parse_unary_type:N . . 11245. . . . . 11261. . . . . . . 10413. 10533. . 10912 \__fp_parse_pack_leading:NNNNNww . . . . . . . . 10951 \__fp_parse_prefix_(:Nw . . 10912 \__fp_parse_pack_trailing:NNNNNNww . . . . . . 10305. 11059 \__fp_parse_word_ln:N . . . . . . . . . . . . . . . . 10734. . 10252. 11305. . . . . . . . . . . . 10506. 10251. . . . . 10986. . 10289. . . . . . 10804 . . . 10457 \__fp_parse_trim_zeros:N . . . . . . . . . 10583. . . 10597 . . . . . . . . . 10289. . . . . . . . . . . \__fp_parse_large_round_dot_test:NNw 11055. . . 10251. 11175. . . . 10964. . . . . . . 10079. . . 9837. . . . . . . 10150 \__fp_sanitize:Nw . . 13124. . . . . 12961. . 13216. . . 10464. . . . 13224. . . . . . . 10130. . . . 13096. 9837. 11879. . . 13081. . 10951 \__fp_parse_word_true:N . 9684. 11783. . . . . . 10085. . . . . . . . . 13008 \__fp_pow_npos_aux:NNnww . 10246. . 10168. . . . . 10090. . . . . 10145. . . 10236. . 13854. 12947. 12524. 13124 \__fp_pow_neg_case_aux:NNNNNNNNw . . 10114. . . . . . . . . 12164 \__fp_round_neg:NNN . . 10079. . . 13139. . . . . 10222. 10168. . 9696 \__fp_sec_o:w . . . . . . . . . 13859 \__fp_round:Nww . . . . 10095. . . . . 11760. . . . . . . . . . 13102 \__fp_pow_C_pack:w . . . . . . . . . 12961 \__fp_reverse_args:Nww 9639. . . . . . . . . . 13018. . 13367. . . 10489 \__fp_pow_B:wwN . . . . . . . . . . 11002. 10166. . . . . . . . . . . 9837. . 9865 \__fp_sub_back_far_o:NnnwnnnnN . . 10168. . . . . . . . . . . . . . . . 11800. . . . . . . . 13453 \__fp_round:NNN . . . . . . . . . . . . . . . . . 10100. . 11792. . . 10439. . . . 13092. . . . . . 10977. 10951 \__fp_parse_word_sp:N . . . . . . . . . . . 10228. . . . . . . 11875 . 13045 \__fp_pow_exponent:wnN . . . . . 13146. 10141. . . . . . . . 9691. . . . . . . . . . . . . . . . . . 11746. . . . 13093. . . . . . . . 13363. 11064 \__fp_sanitize_zero:w . . . . . . 13107 \__fp_pow_C_pos:w . . . . . 10214 \__fp_round_normal:NnnwNNnn . . . . . . . 13109. . 13171. . 13069. . . . . 13109 \__fp_pow_neg_case:w 13111. . . . . 10153. . . . . . . . 13008. 13850. 13875 \__fp_round_return_one: . . . . . 12010. . 11864. 13010. . . 11954. 13024. . 12161 \__fp_round:Nwn . . . . . . . . . . . . . . 13091 \__fp_pow_C_pos_loop:wN . 12952. . . . 13363. . . . . . . . 9841. . 10116. . . . . 10198. . . . . 9639. . . 10113. . . . 11838. . . 10103. 13037. . 13034 \__fp_pow_neg:www . 12033. . 9837. . . . . . . . . 11838 \__fp_sub_back_near_after:wNNNNw . . . 12954. . . . . . . . . . 13029. . . . . . . . . 10485. 13132 \__fp_pow_normal:ww . . 10225 701 \__fp_round_pack:Nw . . . . . . . . . 13194. 10997. 10168. . 10176. . . 10912 \__fp_parse_zero: . . . 13379 \__fp_small_int:wTF . 11003 \__fp_round_digit:Nw . . . . . . . 12150. . . . . . 13411. . . . . . . 10167 \__fp_round_to_ninf:NNN . . . . . 9854. . . . 10986 \__fp_round_to_ninf_neg:NNN 10141. . . . . 10141 \__fp_round_to_pinf:NNN . . . 11757. . 10168. . . . .Index \__fp_parse_word_round:N . . . 10091. 10079. . . . . . . . 10489. 11807. 9862 \__fp_small_int_true:wTF . . . 10243 \__fp_round_to_nearest:NNN . . . . 13851. . . . . . 12980 \__fp_pow_npos:Nww . . . . . . 11902. . . . 9695. . 9695. 10212 \__fp_round_places:NNn . . 10951 \__fp_parse_word_sin:N . . . . . . 13100 \__fp_pow_exponent:Nwnnnnnwn . . . . . . . . . . 13179. . . . . . . . . . 10079. . . . . 9845. 10980 \__fp_round_to_pinf_neg:NNN 10141. . . 13014. 10113. . . . . . . . . 13827 \__fp_sin_series:NNwww . 10192 \__fp_round_normal:NwNNnw . . 10217. 11689. . . . . 12759. . . . . . 10166. . . 13086 \__fp_pow_C_overflow:w 13074. . . . . . . . . . . . . . . 13124. . . . . . 10170 \__fp_small_int_normal:NnwTF . . . 13861 \__fp_round_to_nearest_neg:NNN . . . . 9840. . . . 13066 \__fp_pow_C_neg:w . . 13641. . 12980. . . . . . 9837. . . . . 10168. 10168. . . 10190. . 10194. . . . 13216 \__fp_sin_o:w . . . . . 11897 \__fp_round_normal:NNwNnn . . 12991. . . . . . . . . 10114. . . . . 10161 \__fp_round_s:NNNw . . . . 9801. 13641. . . . 10141. 13209. . . 12013. . . . 10912 \__fp_parse_word_tan:N . . . . . 13024 \__fp_pow_zero_or_inf:ww . . 13363 \__fp_sin_series_aux:NNnww . . . . . 10187 \__fp_round_normal_end:wwNnn . 13448 \__fp_sanitize:wN 9684. 10081. . . . . . . . . . . . . . . . 10130. 13156 \__fp_pow_neg_case_aux:nnnnn . . . . . 9684. . . . . . . 10079. 12001. . . . 13088. . 10977 \__fp_parse_word_sec:N . . . 10983 \__fp_round_to_zero_neg:NNN 10141. . . 10157 \__fp_round_to_zero:NNN . . . 10790 \__fp_round_special:NwwNnn . . . . . . . . 10230 \__fp_round_special_aux:Nw . . . 10179. . . . 10107. . . . . . . . . 9821. . . . . . 11798. . . . . . . . . . . . . . . . . . 10738. . 10992. 9846 \__fp_small_int_test:NnnwNTF . 13040. . . 13128. 10170. . . . . 13870. 13072. . . . . . . . 11998. 10167. 9684. . . . . . 10168. . 10168. . 10079. . . . 13171. . . . . . 13853. 13031. 10168. . . 13124. . . . . . . . 13638. . . . . 10976. . . . . 9810. 9809. . . 13614. . . . . . . 9937. . . . . . 9813. 11851. . . . . 10286. 11535. 11563. . . . . . 9994. 11887. . 11565. 11850. . 9994. 13254. . . . . . . . . . 9973. . 10001. 9816. . . . . 11088. 13571. . . . . . 9997. . 11872. . . . . . . . . . . 11540. . . 13829 \__fp_to_decimal_dispatch:w . 9811. . 10924. . . 10921. . . . . . . . . . . 10964. . . . . . . . . 10938. . 13567. . . . . . . . . . . . 13471. 11028. . . . . . . . 9935. . 13593 \__fp_to_decimal_large:Nnnw . . . . . . . . . . . . . . . 9934. . . . 9818. 11891 \__fp_sub_back_very_far_o:wwwwNN . . 11798. . . . . . . . . 13421. 13631. . 10919. 10922. . . . . . . 10283. . . . 11239. 13231. . 10000 \__fp_trap_overflow_set:NnNn . . . . 13533. . 10975. . . . . 11572 \__fp_tmp:w . . . 13584 \__fp_to_decimal_normal:wnnnnn . . 9999. . . . . . 11097. . 13483 \__fp_to_scientific_normal:wNw . . . . . . . . . . . . . . . . . . . . 13611 \__fp_trap_division_by_zero_set:N . . . . . 11856 \__fp_sub_back_shift:wnnnn . 13533. . . . . 9805. 9938 \__fp_trap_overflow_set:N . . . 11535 \__fp_ternary_auxi:NwwN . . 11090. 9807. . 11763. . 11798 \__fp_sub_back_near_pack:NNNNNNw . . . . . . 11836 \__fp_sub_back_shift_iv:nnnnw . . . . 13478. . . 11877 \__fp_sub_back_not_far_o:wwwwNN . . 11255. . . . 11568. . . . . . 11535. 11538. . . . . . . . . . . . . . 13825. . . . 13523 \__fp_to_scientific_normal:wnnnnn . . . . . . . 11581 \__fp_ternary_break_point:n . . 10935. 11766. . . 13706 \__fp_to_tl_normal:nnnnn . . . . . . . 11093. . . . . 11802. . 11560. . . . 13514. 11884. . 11774 \__fp_sub_npos_i_o:Nnwnw . . 9806. . 11770. . . . . . . 9971. . . . . . 13818. 11535. 13231. . . . . . . . . . . . . . . . . . . 13635. 11858. . 10940. 13606. . . . 10269. . 13559. . 13417. 11852. . . . . . 10010 . . . . . 13598. 13621 \__fp_to_int_dispatch:w . . . 11541. . . . . . . . . 11837 \__fp_sub_back_very_far_ii_o:nnNwwNN . . . 11872 \__fp_sub_back_quite_far_ii:NN . 13417. . . . . 11781 \__fp_sub_npos_ii_o:Nnwnw . 13640 \__fp_to_decimal_huge:wnnnn . . . 11535. . . . 11805. . . . . . . 10284. . . . . . . . 13601. . . . . 11570 \__fp_ternary_loop_break:w . 11827. . 13827. . . . . . . 13478. . 9934. . . . . . . . . . . . . . . 13601. . . . . . . . . 10912. . . . 13538. . . . . 10918. . . 9940 \__fp_trap_invalid_operation_set_error: . . . . . . . . . . 9934 \__fp_trap_invalid_operation_set_flag: . . . . . 10934. . . . . 10917. . . . . 11763 \__fp_tan_o:w . . 11535. 10920. . . . .Index \__fp_sub_back_near_o:nnnnnnnnN . 11798. . 10285. . . . . . . . . . . . . . . . . . . . 13431 \__fp_tan_series_o:NNwww . 9814. . 10282. . . . 11816. 11535. 10923. . . . . . . . . . . 13526. . 13533. . . 9812. . . 9968. . . 10932. . . . . . . . . . 13488. . . . . . . . . 9995. 11768. 11541. . . . 13530. . . 11814. . 13533. 11012. . . . . . 13533. . . . . . 9808. . 13417 \__fp_ternary:NwwN . . . . . . . . 9968. . . . 13516. . . . . . . . 10287. 11884. . . . . 9974 \__fp_trap_division_by_zero_set_error: . . . . . . . 11819 \__fp_sub_back_shift_iii:NNNNNNNNw . . 9969. . 9970 \__fp_trap_division_by_zero_set_none: . . 9820. . . 11814. . 11810. . . 13239. 11763. . . 11775 \__fp_sub_npos_o:NnwNnw . 11831. . . . . 11856. 11573 \__fp_ternary_auxii:NwwN . . 10009. . . . . 11067. . . 11781. 11814 \__fp_sub_back_shift_ii:ww . 11856. . . . . . . . . . . . . . . . 11788. . . . . . . . . . 10937. . . . . . . . . 10933. 11824. 13478. . . . . . . . . . . 13601. . 11683. . . . . . . . . 11029. . . . . . 11092. . . . . . . . 11535. . . . 9968 \__fp_trap_division_by_zero_set_flag: . . . . 9795. . . 13828. . . . . . . . . . 11089. 9968. . 702 9819. 9968. . . . . . . . . . . 13510. . . . . . 9815. 11814. . . . 13638 \__fp_to_scientific_dispatch:w . 11814. . . . . . . . . . . . . . 11087. 9934. 11777. . 11560 \__fp_ternary_map_break: . . 11572 \__fp_ternary_loop:Nw . 9939. . 10941. 13594. 11091. . . . . . . . . 13826. . . . . . . . . . 9817. . 10939. 11862 \__fp_sub_back_quite_far_o:wwNN . 11884 \__fp_sub_eq_o:Nnwnw 11763. . . . . 9934. 9972 \__fp_trap_invalid_operation_set:N . . . . . . . 13829 \__fp_tan_series_aux_o:Nnww . . . . 9936 \__fp_trap_invalid_operation_set_none: . . . . . 13475. 13618 \__fp_to_tl_dispatch:w . . 10936. . . . 10281. . . . . 10031 \__fp_use_i_until_s:nw . 11699. . 11691. . 12251. . . . 13462. . 9994. 12311. . 3431. . . . . 10440. . . . . . 3607 \__int_compare:w . 3560. 10003. 12391. 3610. . . . . . 13313. 13289 \__fp_trig_epsilon_one_o:w . 10794. . . 9633. 3396. . 11964. . 11900. 13271 \__fp_trig_large:ww . . . . 13271. . 10006 \__fp_trig_epsilon_inv_o:w . 3632. 13291 \__fp_trig_exponent:NNNNNwn . 13467 \__fp_type_from_scan:N . . . . . . . . . 13323 \__fp_trig_octant_break:w . . . 3605. . . . . 12192. . 12211. . . . . . 12173. . 12109. . . . 9994. 3619. . . 13253. . 2684. . 10007. 12121. . 9998 \__fp_trap_underflow_set:N . . . 3428. . . . . 10742. . . . 13289. . 3392. 3601. . 11801. 11001. 3563. 12160. 13357 \__fp_use_ii_until_s:nnw 9636. . . . . . . 11896. . . . 12007. . . . . 10238. . . . . 3587. 9558. 11785. 12221. 12068. 11185. . . 12342. 4167. 9634 703 \__fp_use_s:nn . 9633. . 12422. 12071. 3406. . . . . 10508. . 10009. 2688. . . . . . . . . 3560 \__int_constdef:Nw 3466. 1300. . . . . 3397. 2698. . 12091. . 3413. 12260. . 3434. 13468. 3622. . . 9752. . . . . . . 10199. 11916. . . . . . . 3539. . 2704. . 11956. 13462. . . . . 12482. 13312. . . 3616. . . 13238. . . 12219. . . . . 13577. 10892. 12299. 12387. . . . 10594. 12257. . 12457. 10384. . 12103. . . . . . 13289. 3616. . 3627 \__int_case_end:nw . 9659. 13353 \__fp_trig_octant_loop:nnnnnw . 12231. 12297. . . . 12543. . 10136. . 3592. 12127. 13118 \__fp_use_s:n . 3616. . . . 3560. 2692. . . 2694. . . . 12240. . . . 9678. . 3394. 2700. 12158. 13178. 3560 \__int_compare_=:NNw . 2612. 13208. 12117. 10334. . . . . . . . . 12088. . . . 12340. 3515. . 4048. . 12077. 3572. 11720. . 13316. . . 10894. 10588. . 2614. 12279. . . 12321. . . . 11778. 13345. 9994. . 10123. . 10744. . . . . . 12038. . 11876. . 3592 \__int_compare:nnN . 10774. . . 11966. 10768. 11976. 10497. 12277. 12341. 75. . . . 13469 \__fp_trim_zeros_loop:w . . . 3565 \__int_compare_<:NNw . 13312. . 11065. . . . . 3452. . 13337. . . . . . . 12009. . 11974. . 12532. 11878. 3414. 10005. 13312. 13193. 13524. . . . . . . . . . 10595. . 10254. . 11894. . 12035. . 12046. 9996 \__fp_trap_overflow_set_none: 9994. 3457 \__int_eval:w . 12085. . . . . 9676 \__fp_use_none_stop_f:n . . 3493 \__int_div_truncate:NwNw . . 9994. . . . 12385. . . 2682. 3517. . 3478. 9634. . . . 13312 \__fp_trig_large:www . 3489. . 10135. . . . 3640. 3430. . . 4092. . 11968. . 3893. . 12263. . . . 12314. . 11353. 3570. . . . 13462. 12484. 3400 \__int_case:nnn . . 13178. 13351 \__fp_trig_small:ww . 2285. . . . 10262. 9786. . . 2696. . 13302 \__fp_trim_zeros:w . 12101. . . . . . . . 13193. 12343 \__fp_use_none_until_s:w 9636. . 9638. . 10008 \__fp_trap_underflow_set_error: . . 3562. . . 11803. 10911 \__fp_type_from_scan:w 10254. . . . . 13314. 13337. . . . . . . 10856. 10025. . . . 11743. 10264. . 11972. . 3623. 12048. . . . . . . 12289. . . . . . 10767. . . . . 12149. . . 13337. . . 12308. . 12254. . 3453. 9637. 13468 \__fp_trim_zeros_end:w 13462. . . . . 13312. . . . 11754. . . 9994 \__fp_trap_overflow_set_flag: 9994. . 12464. 3383. 13335 \__fp_trig_large_o:wnnnn . . . . . . 10267 \__fp_underflow:w . 2616. . 13464. . 11970. . . 3576 \__int_compare:Nw 3560. 12147. 12094. 13295 \__fp_trig_epsilon_o:w . . . . 2702. . . . . . 9635 \__fp_zero_fp:N . 13223. 12233. 10195. 12287. . 3621 \__int_case:nw . 13317. . . . 11995. . . . . . 12249. . . . . . 11791. 9634. . 3405. 3568. 10234 \__int_abs:N . 3866. . 10796. 9994. . 13325 \__fp_trig_large_break:w . 3597. . 3599. 9636. . . 3384. . 3429. . . . . . 13586 \__fp_trim_zeros_dot:w 13462. . . . . . 11997. . . 9690. . . 10358. . . . . 13465. 3389. 11745. 13336. . 3448. . . . 13289. . . . . 13465. . . . 9659. . 3629 \__int_compare:NNw . 3595. . 12119. . 9783. 10119. . . . 10002 \__fp_trap_underflow_set_flag: . 11722. 3560. 13302. . . . . . . 13281. . . 9885. 2686. . 12199. . . . 9683. . . 3626. 3477. . . 10004 \__fp_trap_underflow_set_none: . . . 9636. 12074. 3560 \__int_compare_>:NNw . 3451. 13279. 13238. 13223. . . 3603. 11756. . 13208.Index \__fp_trap_overflow_set_error: . . . . 13253. 3426. 10557. . . 10783. 2690. . 9873. 3932 \__int_to_base:nn . 3404. 3396. . . 2682. . . . 4043. 3914. . 2688. . 2614. . 6787. 14697. 4168. 13074. 3404. . . 6785. 4002 \__int_from_base:nnN 3993. 12637. 4049. 3933 704 \__int_to_Roman_m:w . 3977. . . . 14545. . . 12621. 3843. 10209. 6998. . 13050. 6991. 12622. . 13318. . 3991 \__int_from_alph:n . 3905. . 4009 \__int_from_roman:NN . 13518. . 2700. . 13027. 13413. . 2702. . . 12342. 4043. . 13048. 12578. 3716. 3954. . . 2696. . . . . 12586. 794. 2704. . . . 6937. . . . 11353. 3902. 14547. 12653. 4088 \__int_from_roman_end:w 4043. 12344. 12704. . 3936 \__int_to_Roman_v:w . . 9742. 3972. 6976. 10549. . 4052. . . 11825. 3902. 13422. . 12635. 11694. . . 4069. 11613. 12818. 10499. 3902. 2684. 12583. 9800. 4003. 11697. . 13062. . 3702. . 4047. 11368. 75. 11900. . . 13450. . 14755 . 13863 \__int_eval_end: . . 10690. 13281. . . 2285. . 1069. 3632. . . . . . 11817. . 3454. . . 14705. 7005. 12598. . 6922. . . 7400. . 9561. 3456 \__int_step:NNnnnn 3725. . . 7205. . 3917. 3389. 6930. . 13370. 12181. 3902. 13072. . 14637. . . 3964 \__int_maxmin:wwN 3394. 894. . 3840. . 9744. . 3383. . 13078. . 3902. . 2686. 2698. . . 13369. 1075. 3765 \__int_value:w . 12221. 12624. 3902. 10512. 6931. 3924 \__int_to_symbols:nnnn . . . 11833. 12830. 10598. . . 896. 12052. . 6938. 2197. . 3902. . 12123. 12683. . 3383. 6913. . . 14570. . 3751. 3857 \__int_to_base:nnnN . . 10202. 14734. . 4060. 2690. 6924. . . 1300. 13069. 3934 \__int_to_Roman_d:w . . 3977. 3988. 6936. 3849. 3943.Index 12562. 4067. . . 3517. . . . . . 3863 \__int_to_roman:N . . 14748. 3938. 12053. 3755. . 12591. 793. 12564. . . 13332. . 12651. . . . . . 3848. 3728. . 12566. . 10492. . . . . 3928 \__int_to_roman_v:w . 3835. 3412. 4010. 2285. 3926 \__int_to_roman_d:w . . . 2616. . 3389. . 12631. 12604. . 3915 \__int_to_roman_Q:w . . 2283. 13102. 12054. . 3835. . . . . 3902. 3836. 12584. 7165. 7224. 7166. 3910 \__int_to_roman:w . 13012. 3432. 11185. 3426. . 3902. 3385. . . 12582. 12645. 3993. . 13586. 3539. 3981. 13646. 3451. . 3418 \__int_mod:ww . 9558. 10577. 3997 \__int_get_sign_and_digits:nNNN . . . . 3640. . 3841. . 10614. . . 12001. . . 13381. . 2694. . 9683. . . 3855 \__int_to_letter:n 3835. . . . . 13056. 3902. 10327. . 3383. . 9743. . . . 11899. 6939. . 14699. 3448. 13381. 3837 \__int_to_base:nnN . 11636. 3998. . 9741. 7135. 12560. 13321. . . 11001. 6932. . 7230. 14572. 3453. 3893. . . 3927 \__int_to_roman_i:w . . 74. 4077. . 13423. 3929 \__int_to_roman_c:w . . . . . . . 12625. 2692. 3902. . . 12649. 3902. 13328. . . 3923 \__int_to_roman_x:w . . 14597. 3980 \__int_from_alph:nN 3972. . . . . 11640. 13452. 13104. . 13326. . 3931 \__int_to_Roman_x:w . . . 6964. . 12596. 4086 \__int_get_digits:n 3938. . 12761. . . . . . . 3902. 3448. . . 10213. . . . 4014 \__int_from_base:nn . . 3712. . 3935 \__int_to_Roman_i:w . 12422. . . . 12675. . 12539. 75. . . . 3866. . . . . . . 10566. 3976. 10560. 3920 \__int_to_Roman_c:w . 6783. 3515. 14703. 3744 \__int_step:NnnnN . 3893. 4048. 3904. . 3721 \__int_to_Roman_Q:w . 3982. . 3902. . . . 14672. . 10181. . 3452. 3397. . . 11935. 11637. . 3948. 13452 \__int_from_alph:N . . 3938. 12164. 3573. 3958. 12633. . 13053. . . 3451. 3705. 3902. 12643. . 3735. . . 3938. . 9866. 11638. . 12051. 3902. 3925 \__int_to_roman_m:w . 2612. . . 13660. . 3567. 6784. 3940. . . 9745. 3592. . . . . 12623. 13100. . 3930 \__int_to_Roman_l:w . 3392. . . . 12761. . 6986. 13277. . 2200. . . 11760. . 3945. 3392. 13656. 12708. 4265. 13330. 13279. . . 3993. . 4004. 4171. 13114. . . . . . . 3987 \__int_from_base:N . 9876. 3902. 12173. 3610. 3835. . 4081 \__int_from_roman_clean_up:w . 6974. 3972. 12765. 6972. 12585. . . . 12647. 6752. 12343. 3922 \__int_to_roman_l:w . . 12525. 3478. . . . 13423. . 3937 \__int_to_Roman_aux:N . 14664. . 10197. 3971 \__int_get_sign_and_digits:oNNN . . 12639. . . 11778. 3412. . 10807. . . 13370. . 3846. 13078. 12013. 7504. 11902. 12626. . 6970. 3902. 3907. 12699. 3383. 3999 \__int_get_sign:n 3938. . 13059. . . . . . 6929. . . 6981. 10692. . . . . . 8523 \__keys_define_key:n . . 8565 \__keys_execute: . . . . 9490. . . . . . 9542 \__iow_wrap_unindent:w . . . . . . . . . 9526 \__iow_wrap_newline: . . 8696. 8668. . . 9509 \__kernel_register_show:N . . . 8699. . . 8609. . . 166. 4488. 9521 \__iow_wrap_indent: . . 9521 \__iow_wrap_special:w . . . . . . . . . 8533. . . . 9344. 8580. . . . 8512 \__keys_define:onn . . . . . . . 8623. 8935 \__keys_execute_unknown_std: . . . . 14776 \__ior_map_inline:NNn . . . . 9233 \__ior_open:No . . . 8573. . . . . . . . . . . 8744. 8518 \__keys_define_elt_aux:nn . 8678. . 14783. . . . . . . . . 8944. . . 8934 \__keys_execute_unknown_alt: . . 8628. . . 8663. 8713. . . 8926. . . . . . . 8859. . . . . . 8703. . 9476. . . . 9476. . . 8686. . . . . 9377 \__iow_open:Nn . . 8600. 8681. . . . . . . 9098. . . . 8955. . . 8754 \__keys_cmd_set:Vo . . 8546 \__keys_set:nnn . . 8746 \__keys_bool_set_inverse:NN . . . . . . . . 8607. . . . . . . 9118. . 9223. . 9352. . . 9521 \__iow_wrap_loop:w . . . . . . . . . . . . . . . 9282. . . . . . . . . . . 9483. . . . . . . . . . . 8582. . . . . . 14766. . 8925. . . . 14767. . . . 1448. . . . . . 8699. . 9264 \__iow_indent:n . . . 8567. 8760 \__keys_choice_code_store:x . 8680. . 8660. . . . 8513. . . . . 8661. . . . . . 4550 \__kernel_register_show:c 1448. . . . . 9446 \__iow_list_streams:Nn . 1457. 8504. 8928. 9263 \__ior_open:NnTF . 8509. 14770 \__ior_map_inline_loop:NNN . . . . . . . . . 8691 \__keys_cmd_set:n 8661. 8699. . 4398. . 9521. . . . . . . . . . . . . . . . . . . 9283. . . 8718. . . 8736. 8917 \__keys_if_value_p:n . . . . . . 8842 \__keys_set_elt:n 8846. . 8858. . . . . . . . . . . . . . . . . . . . . 14773. . . . . . . . . 8537. . . 8806 \__keys_meta_make:x . . . . . . 8582. . . . . . . 8550. . 8575. . 8953. 8924. 8859. . 9480. . 4090 \__keys_bool_set:NN 8567. 8882. 8758 \__keys_default_set:V . . . . 8756 \__keys_cmd_set:nx . . . . . . . . . 9521. . 8700. . . . . . . . . . 8924. 8892. . . . . . . . . . 9247. 8925. . . 8506. . . 14769. . . . . . . . 8750 \__keys_choice_code_store:n . 8701. . 8684. 9225 \__ior_open_aux:NnTF . . . 8681. 8704 \__keys_multichoice_make: . 8571. . 8956 \__keys_execute_unknown: . 8857. 8924. . . 8865. . . . 8850 \__keys_set:onn . . . . . 8513. 9247. . . . . . . . . . . . . . 8808 \__keys_multichoice_find:n . 9525 \__iow_wrap_unindent: . . 9251. 8794 \__keys_initialise:wn . . . 9376. 8774 \__keys_default_set:n . . . 8841. . . 8590. . . . . 8570. . . 8681. . . . . . . . . . 8649. 8924. . . 8637 \__keys_choices_make:nn 8607. . . 8601. . 8899. 9491. 25. . . . . . . . . . . . . 8504. 8513. . . . . . . . 8672 \__keys_cmd_set:nn . 14789 \__ior_open:Nn . . . . . 8550. . . . . . 8649. 8924. . 9548 \__iow_wrap_end:w . . . 8623. . . . 8533 \__keys_property_find:w . . . . . . . . . . . . 8689. . 8595. . . . . 9428. . 8614. . 8711. . 8843. . . 8640. . 9483. . . 9427. . . . . . . . . . . . . . . 8752 \__keys_choices_generate:n . . 8705. . . . . . .Index \__ior_list_streams:Nn . 8857. . 9247 \__ior_open_aux:Nn . . . . . . . 8678. . 8810 \__keys_multichoices_make:nn . . 8586. . . . 9467. 8841. . 8550 \__keys_define_key:w . 8588. . . . 8748. . . . . . . . . . 9481. . . . 8527. . . . . . 8687 \__keys_meta_make:n . . . 9340. . . 8585. . . 8689. 8533. . 1448. . . . 8599. . . 9377 \__ior_map_inline:NNNn 14766. . . . . . . . 9375. . . . 9528 \__iow_wrap_newline:w . 8865 . . . 8597. . . . 9337. . . . 9247. . . 8661. 8917 \__keys_initialise:V . . 8630. . . . . . . . . . . . 8792 705 \__keys_choices_generate_aux:n . 9521 \__iow_wrap_word: . . . . . . 8953 \__keys_choice_make: . . . . . . . 9232. . . . . 8796 \__keys_initialise:n 8681. 8649. . . . 9243. . . . . . . . . . 9222. . 8934 \__keys_if_value:n . . . . 9357 \__iow_wrap_end: . 8671. . . . 9338. . . 9259. 9489. . . . 8689. 9536 \__iow_wrap_indent:w . 4089. 8772 \__keys_define:nnn . . . . . . . . . . . . 8661. . . . 8554. . . . 8678. . . 8540. . 9284. . . . . 8509. . . . . . 8661. . . . . . 8505 \__keys_define_elt:n . 8694. . 9493 \__iow_wrap_word_newline: 9483. . . . . . . . . . . . 8924 \__keys_execute:nn . . . . . . . . . 14779. . . 8513 \__keys_define_elt:nn . . . . . . . . . . . . . . . 8521. . . 8762 \__keys_choice_find:n . . . . . 9230. . . . . 1458. 9483 \__iow_wrap_word_fits: . . 8516. . . . . . . 8666. . . . . 8623. 9237 \__ior_open_stream:Nn . 8597. . . . . 9337. . . 8812 \__keys_property_find:n 8525. . 8699. 9356 \__iow_open_stream:Nn . 14766. . . . . . . . . . 8824. 8039 \__msg_expandable_error:n . 7681. . 7850. . . 10679. . 8227. . 8834 \__keys_variable_set:cnN . . 979. . . . . . 8035. 8035. . 8742. 8538. 1188. . . . . 8040 \__msg_kernel_info:nnn . . 8038. 7598. . 7023. 13975 \__msg_kernel_error:nnxx . . . 8804. 8229 \__msg_expandable_error:w 8204. . . . . . 10684. . 8039. . . . 1341. 5397. . 8832. . 8818. . 8040 \__msg_kernel_info:nnnnn . . . . . 7842. . . . . 8786. . . . 10429. . . 8035 \__msg_kernel_fatal:nnxxx . 10422. . 8040 \__msg_kernel_info:nnnn . . 8865. 8035 \__msg_kernel_fatal:nnx . . . . . . . . 8227. . . . . 8733. 7683. . . 11252. . . . . . . 8035 \__msg_kernel_fatal:nnnnnn . . . 7588. . . . 8241. . 9143. 8040 \__msg_kernel_info:nnxx . 7791. . . 8040 \__msg_kernel_info:nnnnnn . . . . . . . . 8446 \__keyval_split_value_aux:w . 10702. . . . . . . . . . 8788. 8325. . . . . . . . . . . . . 1175. . . . . . . . . . . . 8041 \__msg_kernel_class_new_aux:nN . . . . 2589. . 11308 \__msg_kernel_expandable_error:nnn . 6915. . . . . . 8227. . . . 1189. . . 5302. . . 1926. . 8035. . 7856 \__msg_error:cnnnnn . . . . 8733. . . . 13954 \__msg_kernel_fatal:nnn . . 8768. 13754. . . . 8438. . . . 8246. . . . 8865. 6618. . 10695. 8402. . . . 7681 \__msg_kernel_bug:x . . . 10344. 8218. 1175. 8418. . . . . . . . . . 8035 \__msg_kernel_error:nnnnn . . 958. . . 8444 \__keyval_split_key_value:w . 1036. 8870 \__keys_set_elt_aux:nn . . . 8035 \__msg_kernel_error:nnxxxx . 1207. . 11550 \__msg_kernel_expandable_error:nnnnn . 147. 8764. . 7886. . 8386. . . 8879. 8036. 8822. 9253. . 13927 \__msg_kernel_fatal:nnxx . . . . . . . . . 14966 \__msg_kernel_expandable_error:nnnn . 8802. 8776. . . . . 8040 \__msg_kernel_info:nnx . . . 8433 \__msg_kernel_error:nnn . . 8798. . 7754. . . . . . 8035 \__msg_kernel_fatal:nnxxxx . . 7872. 13970. 8438. . 8577. 8707. . . 10350.Index \__keys_set_elt:nn 8846. . 9229. . . . . . . 7953 \__msg_class_new:nn . . 2137. . . . 8875 \__keys_set_known:nnnN . 7813. 7703 \__msg_interrupt_wrap:nn . . 8418 \__keyval_split_key_value:wTF . . 8411. 8790. . . 8784. 8529. 1197. 6767. . . . . . . 8224 \__msg_fatal_code:nnnnnn . . . 8814. 8035 \__msg_interrupt_more_text:n . . . . . . 7673. . 8408. 8467 \__msg_class_chk_exist:nT . . 11165. . . 8727. . 4996. . . . . . 147. 8830. 8035 \__msg_kernel_error:nnx 938. 7858. 3709. . . . 8408. . . . . . 8633. . . . 8236. . . . 8853. . . . . . 8035 \__msg_kernel_fatal:nnnnn . . . . . . . . 8035 \__msg_kernel_error:nnnn . . . . 7999. 8243. . 8000 706 \__msg_kernel_error:nn . . . 8415 \__keyval_split_key:n . 148. . 9084. 9346. 1987. . . . . . 1681. . . . . . . . 8227. 11054. . . . 1190. 8836 \__keyval_parse:n . 8739. . 1371. . 7686 \__msg_interrupt_text:n 7684. . 7861. 7753. 4792. . . 8864 \__keys_set_known:onnN . 929. . . 8037. . . . . . 8035 \__msg_kernel_error:nnnnnn . . 8431. . . 14524. . . . . 8326 \__msg_kernel_class_new:nN . . . 8464. . 1175. 8603. . . . 8896. 8035. . 7813. . 8858. . . . . . . . . . 8035 \__msg_kernel_fatal:nnnn . . 8740. 1187. 7997. 8035. 7834. . . . . . . 2313. 8902. 8902 \__keys_value_requirement:n . . . . 7938. 7815. . . 7681. . . . 8438 \__keyval_split_key:w . 13895. 8727. 9643. . 8766. . 8826 \__keys_variable_set:NnNN . 8204. 8394. 13900. 8253 \__msg_kernel_fatal:nn . . . 8227. . . . . . . . . . 8930. 8840 \__keys_variable_set:NnN . . 8733. 7827 \__msg_error_code:nnnnnn . . . 11271. . . . 8251. 13998 \__msg_kernel_error:nnxxx . . . . 8248. . 8040 \__msg_kernel_info:nnxxx . . 8418. . . . 7997. . . 8820. . . . . 8277. . . 8442. . 7695. 8733. . . . . . . . . 8592. . 1022. 13933. 8414. . 9931. . 8800. 8558. 8035. . 8436 \__keyval_split_value:w 8432. . . . . 8480 \__keyval_parse_elt:w . 8782. . . . 7858. 8886. . . 8420. . . . . 8852 \__keys_value_or_default:n . . . . 8741. 7677. . 9928. 11005 \__msg_kernel_expandable_error:nnnnnn 147. 10874. . . 8035 \__msg_kernel_expandable_error:nn . . . . . . . . 8446. . 8838. . . . . 8851. 7802. . . . 1453. . . . . . 8780. . 8868. . . . 8212. 1220. . . 8851. . . 8040 . . . 10401. . 8035 \__msg_kernel_info:nn . 7948. 3556. . 8873. . 8770. . . . 8040. 1175. . 8238. . . . 10039. . . . . 1017. 8227. . 147. 8778. 8828 \__keys_variable_set:cnNN 8733. 8816. . 2002. 7998. . 11 \__my_map_dbl_fn:nn . . 7888. . . 8269. . 8988. . . 3245. . 3081. . 8292. . . 8256. . 7946 \__msg_redirect_loop_chk:nnn . . 7983 \__msg_redirect_loop_list:n . . . 15169. . . . . 11314. 3215 \__peek_execute_branches_catcode_aux: . . 3146 \__peek_execute_branches_catcode_auxii:N . . 10041. 3083. . . . . . . . . 5769. 8256. . . 148. . . . . 11322. 3247 \__peek_false:w . . . 7989. . . 3209. . 3175. . 8202. . . . 13752. . . . . . 7993 \__msg_kernel_warning:nn . . . . 8287. . 8281. 3095. 3144. . 8077. . . 15173 \__peek_execute_branches_catcode: . . . 7868. . 3172. 8256. . 8269. . . . . 7833 \__msg_redirect:nnn 7942. . 9592. . . . . . . . . . . . 15149. 3142. . . . . 8066. . . . . . . 3246 \__peek_def:nnnnn . . 3139. . 9893. . . 3222. . . 7868. . . . . . 7518. . . 10072. . 3239. . . 3093 \__peek_token_generic:NNF . 14049 \__msg_kernel_set:nnn . 1467. . . 3166 \__peek_execute_branches_charcode: . . 8266. 14043. . . . . . . . 8981. . 8264. 3207. 8168. . . . 7963. 3259. 10068. . 8292 \__msg_show_item:nn . 8040 \__msg_kernel_warning:nnnn . 11328 \__msg_kernel_new:nnnn . 8193. . 8160. . 7899. . 3112. . 7942. . . . . . . . . . . 15140. . . 148. . 8186. . . 8292. 3142. . . 11318. 3229. . . 6443. . 7917. . . 8200. 15161 \__peek_def:nnnn . . . 10074. 8972. 7528. . . 7987 \__msg_redirect_loop_chk:onn . . 11312. . . 3202. . 8170. 7979. . 9023. 8268 \__msg_use:nnnnnnn 7762. 7989. . . 7989. . 8291 \__msg_term:nn . . . . . . . . . . 3210. . . . . 7991. . 8483. 8131. . . . 3238. 3153. . . . . 15154. . . . . . 3214. 3197 \__peek_execute_branches_N_type: . . . . . . . 8975. . . 7989. 3162. 3134. 8174. . . 3241. 7902 \__msg_use_redirect_module:n . . . . . . . . . . 7521. 8085. 10070. 9003. . . . 3084. . . 11326. . . . . . . 3179. 9017. 8256 \__msg_term:nnnnnn . 3142. 3231 \__peek_execute_branches_meaning: . . . . . . . . . . 6161. . . 9290 \__msg_show_variable:Nnn . 8283 \__msg_show_variable_aux:w . . . . .Index \__msg_kernel_info:nnxxxx . 3186. . 3277 \__peek_ignore_spaces_execute_branches: . 3113. . 3115. 3095. 15147. 8040 \__msg_kernel_warning:nnxxx . . 7868. 8059. . . . . 8176. . . 147. 8263 707 \__msg_term:nnnnnV . . . 3251. . . 7875. . 8301. 7868. 8292. . . . . 3142. . . . . 8269. 8172. . . . . . . 7989. 3189. 3206. . . . 3230. . . 3205. . 11324. . . . 3114. 15171. . . . 15173 \__peek_token_generic:NNT . 7829. . . . . . . . . . 3217. . 3221. 3252. 3156 \__peek_execute_branches_catcode_auxiii: . . 15132. 7928 \__msg_use_hierarchy:nwwN . 8262. . . 8274. 8040 \__msg_kernel_warning:nnx . 3104. 8256. 10064. . . . 7883. . 7945. . 8094. . 3190. . . . . . 7868. . . . . 9578. . . . 3237. 146. . 8108. . . 8051. . . . . . 3233. . . . 15132. . . . . . 7868. . . 7510. . . . . . . 3218. . . . . 8040 \__msg_kernel_warning:nnxx . . . . . . . 3234. 3132 \__peek_token_remove_generic:NNT . . . 7988 \__msg_show_item:n . . . . . 3134. . . 8178. 3142. 6442. . . . . 8296 \__msg_show_item_unbraced:nn . 10053. . . . 3122. . . . . . . . 7892. . 8269 \__msg_show_variable:n . 2144. 146. . . . . . . 8124. 3081. . . 7942. 15169 \__peek_token_remove_generic:NNF . 8997. . . 6162. . 3223. . . 15166 \__peek_get_prefix_arg_replacement:wN . . 8145. 3145. . 8040 \__msg_kernel_warning:nnn . 8282. 7958. . 3130 . 8101. . . . 11316. . . 148. 148. 8273. 8256. . . . 7896. . . 8267 \__msg_term:nnn . 10 \__peek_N_type:w . . 8362 \__msg_use_code: . 15171 \__peek_token_generic:NNTF . 3188. 9585. 11320. 3185. . . 9286 \__msg_term:nnnnn . 3185. . . . . . . . . . 8265. . . 8152. . . 9572. . . . 8269. 8040 \__msg_kernel_warning:nnxxxx 7973. . . 3. . . 7895. . 7501. . 3226. 3242. . . 3268. . . . . 15157 \__peek_N_type_aux:nnw 15132. 7907. . . . . 4. . . . . 9010. . . . . . 7920 \__msg_use_redirect_name:n . . . 5308. . . . . . . 7889 \__my_map_dbl:nn . 8040 \__msg_kernel_new:nnn . . 8138. . 13759 \__msg_show_variable_aux:n . . . . 3142. . 7505. . 9289. . . . . . 8043. . . 8040 \__msg_no_more_text:nnnn 7813. . . . 7995 \__msg_kernel_set:nnnn . . . . . . 3213. . 6. . . . . . . . . . 10066. 2145. 7943. . . . . 3182. . 3175. 3249 \__peek_tmp:w . 3143. 8115. . 148. . . . . 8040 \__msg_kernel_warning:nnnnnn . 3225. . . . 8040 \__msg_kernel_warning:nnnnn . 3150. . 5770. 3192 \__peek_execute_branches: . 2339. 4948. . . . . . . . . 1014 \__prg_set_eq_conditional_p_form:wNnnnn . . . . . . 917. 15104 \__prg_break:n . . . . . . . . 2292 \__prg_replicate_0:n . . . 950. . . . . . 43. . . . . 3545 \__prg_compare_error:Nw . 6114. . 926. 3081. . . . . . . 3120 \__prg_break: . . 1567. . 2281 \__prg_replicate_first_8:n . 14829 \__prop_if_in:N . . . . . . 6439. . . . . . . . . . . . . . . . 3545. 915. . 14817 \__prop_get_Nn:nwn . . 3549. . 1043 \__prg_set_eq_conditional_p_form:nnn . 6363. . . . 1060 \__prg_set_eq_conditional_TF_form:nnn . . 3748. . 2373. . 2288. . 25. . . . . . . . . 3551. . 2289. . . . . . . 14864. 1002 \__prg_set_eq_conditional:nnNnnNNw . . . . . . . 983 \__prg_generate_conditional:nnNnnnnn . . . 15106 \__prg_break_point: . . . . . . . . . . . . . . .Index \__peek_token_remove_generic:NNTF . . . . . 43. . 898. . 1566. . . 2281 \__prg_set_eq_conditional:NNNn . . 2281 \__prg_replicate_2:n . . 2281 \__prg_replicate_first_6:n . 3089. . . . . . . . . 2281 \__prg_replicate_1:n . . . . . 1026. . . . 2373. . . . . 2339. . . 6063. . . . . 14822. . . . . . . . . . . . 4276 \__prg_compare_error:NNw . . 2290 \__prg_replicate_first_-:n . 3580 \__prg_generate_F_form:wnnnnnn 967. . . . 2339. 5668. . . . 14820. . 2281 708 \__prg_replicate_7:n . . . 935. 5675. . . 4320. . . . 5710. . . . 2281 \__prg_replicate_first_4:n . . 6384. . 3089. . . . . 913. . . . 75. . 6077. 3629. . . 1565. . . . . . 15165. . . . . . . . . . . 1566. 2281. . 1556. . . . . . 15166 \__peek_true_aux:w 3081. . 923 \__prg_generate_conditional_parm:nnNpnn . . 1565. 2351 \__prg_variable_get_type:N 42. . . . 1565. . . . . 902. . . . . . . . . . . . . . . . . 988 \__prg_generate_TF_form:wnnnnnn 967. . 6374. . . 2281 \__prg_replicate_first_1:n . . . . . . 6371. . . . 2281 \__prg_replicate_first_0:n . 14816. . . . . 4965. . . 900. 1050 \__prg_set_eq_conditional_T_form:nnn . . . . . . . . 1014 \__prg_set_eq_conditional_TF_form:wNnnnn . . . . . 9874. . . . 2339. 6437. . . 1555. . . 5721. . 907. . . . . . . . . . . 5670. 2281 \__prg_replicate_4:n . . . . . . 14853. . . . . . 920. . . 6369. . 42. 904. 1567. . . 14828. . . . 1556. . . . . 3082. 3120. 1014 \__prg_set_eq_conditional_T_form:wNnnnn . . . . . . . . 2281 \__prg_replicate_first_3:n . . . . . . 1557. . 1557. . . . . . . . . . . . 2365. . . . . . . . 918 \__prg_generate_conditional_count:nnNnnnn . 14765 \__prg_replicate:N 2281. 4274. . 14825. . 14816. . . . . . . . . 1554. . . 15100 \__prg_break_point:Nn . 910. . 1014 \__prg_set_eq_conditional_F_form:nnn . . . . . . . . . . . . . . 9875. . . 3099. . . . . 1055 \__prg_set_eq_conditional_loop:nnnnNw . . . . . 4987. . . 2281 \__prg_replicate_5:n . . 14780. . . . 965 \__prg_generate_conditional_count:nnNnn . . . . . . 2373. . . . 14845. . . . 3563. . . . . . 6096. 2360 \__prg_variable_get_type:w . . . . . . . 1014. . 14816. . . 3160. 2281 \__prg_replicate_9:n . . . . . . . 1532. . . 13693. 910. . . . . . . . . . . 6131. 4943 \__prg_compare_error: . . . . . . . . . . . . . 3170. . . . . 4974. 999. . 998. . . . 944. . . . . . . . . . 14824 \__prop_get:No . . . . 3092. . . . . . 1045 \__prg_variable_get_scope:N . . . . . 43. . . . 2281 \__prg_replicate_first:N 2281. 14818. 3133 \__peek_true:w 3081. . . 2369 \__prop_get:Nn . . . . . 1001. . 3116. . . 3116. 3131. . . . . . 14847. . 14763. . 5540. . . . . 911. 2362. . . . . . 2284. . . . . 6365. 2281 \__prg_replicate_first_7:n . 2281 \__prg_replicate_8:n . . . 6433. . 6133. . . 2281 \__prg_replicate_first_2:n . . 14805 \__prg_case_end:nw . . . . . . 2373. . . . . . . . 3121 \__peek_true_remove:w . 2281 \__prg_replicate_3:n . . . 1014. . . . . . . . . . . 1565. . . . . . . . 14871. . . . . . 14863. . . 935. . 2373. . . 2281 \__prg_replicate_first_5:n . 1006. 3545. . 2345 \__prg_variable_get_scope:w . . . . 2281 \__prg_replicate_6:n . 13694. . . . 967 \__prg_map_break:Nn . . . . . . . . . 1014 \__prg_set_eq_conditional_F_form:wNnnnn . . . . . . 5543. . . 2348. 6375 . . . . . . . 6377 \__prop_if_in:nwn 6363. . 1556. 43. . . . . 935 \__prg_generate_conditional:nnnnnnw . . . . . . 1563. . . . . . . 905 \__prg_generate_p_form:wnnnnnn 967. . . . . . 4989. . . . . . . . . . . 1028. 15152. . . . . . . . . . . . . . 3137. 2291 \__prg_replicate_ . . . . . 993 \__prg_generate_T_form:wnnnnnn 967. . . 6413. . 2281 \__prg_replicate_first_9:n . . . . . . 3565. 897. . . . . . . . 5603. 15104 \__scan_new:N . 9563. 14913. . . . . 5182 \__str_if_eq_x_return:nn . 5650 \__seq_pop_left:NnwNNN . . . . . . . 5579. . . . 5452. . . . 5687. 14857. . . . 5439. . . . . . . . . 6253. . 14917. . . 5550. . . . . . . 6240. . 5730. 5579. 14997. . . . . . 5422. . 5438. 5482. . . . . 5615. . 5616. . 5517. . . . 1532. 5580. . . . . 6250 \__quark_if_recursion_tail_break:NN . . . . . 5525. . 5395. . . . . . 5534. 14934. 6068. . . . . . 5580. 5479. 14921 \__seq_set_filter:NNNn . . 5677. . . . . 6269. . . . 5652. . . 14936. . 48. . 14919 \__seq_use:NnNnn 14948. 9640. . . . . 5477. . . . 5498. . . . . . . 9554. . 5542 \__seq_item:n . . 5421. . 14879 \__seq_pop:NNNN . . . 1535. . 5684. . . . 5425 \__seq_set_split_auxi:w . 6244. . . . . 5449. . . . . 6240. 5648. . . . . . . 4981 \__quark_if_recursion_tail_break:nN . . . . 6327 \__prop_put_if_new:NNnn . . 5692. . . 6344. . . 2974. 9651. 5447. . . 9569 \__str_head:w . . . . . . 5648. . . . 9486. . . . 5630. . . . . . 14998 \__str_tail:w . . . . . . . 14859. 14946 \__seq_pop_left:NNN . . . . 5462. 9556 \__str_count_loop:NNNNNNNNN . . 5681 \__seq_mapthread_function:NN . . . . . . 5558. 5470. . . 14901. . 14868. . 2918. . 14916. . 5628. 5654 \__seq_pop_item_def: . 6409. . . . 14962. . 14807. 1552 \__str_count_ignore_spaces:N . 14909. . . . 9555. . . . 5633 \__seq_push_item_def: . 2896. 5609. . . . 1551. . . 5434. 14916. . 1524. 14942 \__seq_set_split:NNnn . . 14931. . 5584. . . . 6215. . 14959. . 5686. . . 14886. . . 5689. . . . . . . 5266. . . 6240. . 5700. . 6326. . . 5702. 1524. . 14849. . . . . 5374. . 5583. . . . . . . . . . . 5421. 4473 \__str_case:nw . . . . . . . . . . . . . . . . . . 6309. 14929. 14955. . . 5513. 2526. 5585. 14938. . . . 5691. . . . . 5428. . . . 4954. . . . . . . . . . . 5451 \__seq_set_split_end: . . . 14924. 5585 \__seq_pop_right_aux:NNN . . . . . 1555 \__str_case_x:nw . . 14968 \__seq_use:nwwn . 14928. . . . . . 6429 \__prop_map_tokens:nwn . 5725. 5176. . . . 5684. . . . . . . 14948. . 5609. 6259. . . 5582. . . . 14891. . . . . 5576. 2602. 5395. 5573. . . . . . . . 14801. . 14874. 9554 \__str_count_ignore_spaces:n . . . 5464. . . . . . 5176. . 2585. . . . 14934 \__skip_if_finite:wwNw . 9554. 5495. 9652 \__seq_count:n . . 6247. . 14854 \__seq_map_function:NNn . 5652. . . . . 6396 \__prop_split_aux:NnTF . . . 5576 \__seq_get_left:NnwN . . . 14970 \__seq_wrap_item:n . . . . . . . 5708. . . 5483 \__seq_reverse:NN . 6346. 2956. . . . 4930. . 14911. . . . . . 5190 . . . . . . . 6324. . . . . . 48. . 5568 \__seq_get_right_loop:nn . . . . . 5572. . . . . . 14944 \__seq_push_item_def:x . . . . . 2532. 1540. . 14939. . . . 126. . 9648. . . . . . . . . . . 6343. . . 5178. . 5477. 14948. . 5694 \__seq_push_item_def:n . . . . . 6286. 14932 \__seq_set_map:NNNn . . 5496. . . 5186. . . . 5550. . . 6347 \__prop_split:NnTF . . . 14919. . 5445 \__seq_set_split_auxii:w 5421. . 5671.Index \__prop_map_function:Nwn . 26. 2987. 5638. . . . . 111. . 9650. 1546. . . . . 5592. 5650. . . . . . . . . . . . 2597. . 6081. . 5715 \__seq_remove_all_aux:NNn . . . . . . . 4469. . 5472. . . 6242 \__prop_split_aux:w 6240. . . 14968. 14961. . 14955. . . . . 14974. . . . . . . . 2880. . . 6277. 5550. . 5501. 5654 709 \__seq_pop_right_loop:nn . . 14977 \__seq_item:nnn 14833. 5612 \__seq_pop_TF:NNNN . . 2938. . . 14917. . . 6241. . . . 9646. . 14941. 6421. 5594. 5445. . . . . . . . . . . . . 14835. 2585. . . 5610. . . 112. . 2998. 1537. . . . . . 2871. . . . 14914 \__seq_reverse_item:nwn . . . . 14956. 6331. 5477. 14977 \__seq_use:nwwwwnwn . 14866 \__seq_mapthread_function:Nnnwnn . 6351. . 5721. . . . . . 6299. . . . . 2600. . . . . 14813 \__prop_put:NNNnn 6323. . 5613. . 5421. . 14896. . 1548. . 6411. . 6415. 2526. . . . 5480. . . . 5424. . . . . . . . . . . . . . 5499 \__seq_remove_duplicates:NN . . 1541 \__str_case_end:nw 1532. 14960. . 9559. . . . . . . . . 14971. 14909. . . . 9649. . 5733 \__seq_get_left:Nnw . . . . . . . . . . . . 5530. . . 5610. . . . 5606 \__seq_if_in: . . . . . . . . . 5640. 9554. . 14944. . . . 5620. . . . . . . . . . 5612. 2526. . . . . . . 3008. 4465. . . . . . . 5684. 5684. . 14803. 14909. . . . . . . . . . . . . . . . . . . . 5684. 14857. . 5698. . 14909. 9647. . 5710. 5432. . . . 5451 \__seq_tmp:w . . 1532. . . . . 111. . . 5582. 5673. . 4776. 5074. . . 15102. 15029. 5081. . . . . . 15107 \__tl_map_function:Nn . . . . . . 5014. . . . . . . . . . . . 5162 \__tl_head_auxii:nw . . 5009 \__tl_head_auxi:nw 5146. 15013 \__tl_reverse_group_preserve:nn . . . . . . . 3034 \__token_if_primitive:Nw 3017. . . . . . . . 4934. 15073. . 2858. . 5019. 5103 \__tl_act_group_recurse:Nnn . . . 15085 \__tl_act_case_group:nn . . 5047. 4939. . . . 3015 \__token_if_macro_p:w . . 15016 \__tl_act_space:wwnNNN . . . . . . . . . . 5026 \__tl_reverse_normal:nN . 5002. . . . . . 3050. 2858. . . . . . . . . . . . 5151. 5036. . . 2829. . 4779. . . 5127. 4776. . 5106. . . . 15089. . . . . . . 5116. 4918. . . 5128. . . 4882 \__tl_if_head_eq_meaning_normal:nN . . 5053. . . . . . . . 2947 \__token_if_primitive:NNw 3017. . 2940. . . . 5232. . . . . . . . . 2929 \__token_if_long_macro:w . . . . . . . . . . . . . . . 5137. . . . . . 3017. . . . . . . 5036 \__tl_trim_spaces_auxiii:w . . . . . . . . . . . . . . 4777. . . . . 5022 \__tl_reverse_items:wn . . . . . 4739. . . . . . . 5233. . . . . 15074 \__tl_act_case_space:n 15050. . 4931. . . . . . . . . . . . 4824 \__tl_rescan:w . . . . . . . . . . . 15024. . 5012. 5045. . . . . . . . . . . . . . . . . . . . . . . . 15063. . 4983 \__tl_replace:NNNnn . . . . 4783. 5087.Index \__tl_act:NNNnn . . . . 4822. . . . . . . . . . . 3041 . . . . . . 3017. . . 5135. . . 15006 \__tl_reverse_space:n . . 5070 \__token_if_chardef:w . . . 3037. . 4738. . . . 15038 \__tl_act_count_normal:nN . . . . . . . 5125. . . 14457 \__tl_trim_spaces_auxi:w . . 5149. . . . . . . . . . . . . . . . 3036. . . . . . . . 4819 \__tl_replace_once_end:w 4776. . . . . . . 3010. . . . . . 4970. 4940 \__tl_case_end:nw . . 2858. . . . . 4764 \__tl_reverse_group:nn 15000. . . . 15019. . . 15028. . . . . . . . 5110 \__tl_case:Nw . 5079. . 2920. 2887 \__token_if_dim_register:w . 15005. . . . 5012. . 4776. . 4978. 15084 \__tl_act_result:n . . . . 5044. 5136 \__tl_reverse_items:nwNwn . . . 4838 \__tl_if_empty_return:o . . . . . . . . . . . . 4781. 4741. 2858. 5113 \__tl_act_normal:NwnNNN 5074. . . . 15068 \__tl_act_case_aux:nn . . . . . 5084. . 5074 \__tl_act_end:wn . . . 3030. . . 5117. . . . 3000. 15037 \__tl_act_end:w . . . . . . . . 5058 \__tl_trim_spaces_auxii:w\__tl_trim_spaces_auxiii:w . . . . . 4999. . . . . . . 15082 \__tl_act_case_normal:nN . . . . . . . 5036. 3042 \__token_if_primitive_space:w . 4962 \__tl_map_variable:Nnn . 2905 \__token_if_int_register:w . . . . . . . . . . . . . 15024. . 5007. . 15031. . . . 4779. 4822. . 2873. . 15076. . 5118. . . . . . . . 5074. . . . . . 2818. . . 103. 5077. . . . . . . . . . . . 15050. . 3038. 3056 \__token_if_primitive_nullfont:N . . . . . 5120. 5059 \__tl_trim_spaces_auxii:w . . . . . . . . . . . . . . 5126. . . . 3017. . . . . . 4817 \__tl_replace_once: 4776. 5119 \__tl_act_reverse_output:n . . . . 15055. . . . . . 15069. . . . . . 4946. . . . . . . . . . . . . . . . 5245 \__tl_if_head_is_space:w 5285. . 5092 \__tl_act_output:n . . . . . . 5064. . . . . . . 2858. . 15030. . . 15024. 15070. . . 4756. . . . 15073 \__tl_act_count_group:nn . . . . . 5074. . 4943 \__tl_count:n . . . 15087. . 5016. . 2898. . . 5098. . . . . . . . . . . 5036. . . . 4839. 5120. 5139. . . . 5050. . . . . . . . . . . . . . . . . . . . . 5116. . . . . . . . . . . . . . 4783. . 4777. . . . 5023. . . . . 15066. . . 5290 \__tl_item:nn . . . . . 4814. . . . . . . . . . 3059 \__token_if_primitive_loop:N . 5288. . . . . 5101. . 5134. . . . . . . . . 5074. . . . . . . 5061. . . . . . . . . . . . 5236 \__tl_if_head_eq_meaning_special:nN . 5029. . . . . . . . . . . 2832 \__token_if_muskip_register:w . 15007. . . 3053. . . 15015. . 4952. 5073 \__tl_trim_spaces:nn . . . . 5040. 5068 \__tl_trim_spaces_auxiv:w 5036. . 4743. . 15071. 5074. 5841. . . . . . 4744 \__tl_tmp:w . . . . . . . . . . . . 2882. . . . . . . 5101 \__tl_act_group:nwnNNN . 4813. . 4788 710 \__tl_replace:w . . . . . . . . . . . . 4821 \__tl_replace_all: . . . . . . . 4936. . 5138. 5074. . . . . . . . . . . . . . . . 4738. . 15036 \__tl_act_count_space:n . . . . . . 4944. . . 5074. . 5038. . . . 15008 \__tl_set_rescan:NNnn . . . 4797. 4872. . 5118. . . 15019 \__tl_act_loop:w . . . . 4816. . . 5120. . . . . 4919. . . . . . . . . . 5088. . . . . . . 15050. 4955. . . . . . . . . . . 5146. . . . . . . . . . . 5152. . . 4972. . . . 4781. . . . . . . . . . . 5153 \__tl_if_blank_p:NNw . . 4931. . . . 5095. . . . . . . . 4872. . . . . 4817. 5015. . . . . . . . . . 2598. . . . . . 8905 \bool_if:nT . . . . . 8304. . . 2129. . 2119 \bool_gset_eq:cc . . . . . 409 . . . 2248 \bool_do_until:Nn 40. . . . . . . . 454 \binoppenalty . . 9202 \atop . . 9442 Numbers \8 . . . . . . . . . . . . . 2092 . . . . 9445 A \A . . . . . . . . . . . . . . . . . . . . . . . 2114. 3966. . . . . . 2120 \bool_if:N . . . . . . . . . . . . . . . . . . . . . 347 \beginL . . . . 2598 \| . . . . . . . . . . . 438 \abovedisplayshortskip . . . . . . . 2105 . . 2162. . . 37. . . . . . . . . . . 701 \beginR . . . . . 48. . . . 4729. . 2262. 2248 \bool_do_while:Nn 40. . . . 1896. 2983 \__use_none_delimit_by_s__stop:w . . . 2979. . . . . . . . . . . . . . . . . . 10820 \AtBeginDocument . . . . . 8880. . . . . . 2901. . . . . . . . 2128 \bool_if_p:n . 2120. . . . 38. . . . . . . . . . . . 2744. . 2858. . . . . . . . . . . 2252 \bool_do_while:nn . . . . . . . . . . . . . . 344 false . . . . . . 2961. . . 8552. 8206. . . . . . 3017. . . . 2243. . . 8299. 8294. . . . . . . . . . . . . . . . . 2265. . . . . . . . 2278 \bool_do_while:cn . . . 12462. . . . . 477 \bodydir . 2249. . . . . . . . . . . . . . . 38. . . . . . 3952. . 2965 \__token_if_toks_register:w . . . . . 452 \abovewithdelims . . 7696. . . . . 9495 \bool_if:nTF . . . . . . . 179 tan . . 38. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2249. . 8389 8390 317. 489 \adjdemerits . 2106. . . . . . . . . . 2162. . . . . . . . . . . . . 2154 \bool_if:NF . . . 2976. . . . . . . . . . . . 2238 \bool_new:c . . . . . . . . . . . . . . . . . . 9407. . 526 \advance . . . . . . . . . 3967. 12480 \assert_str_eq:nn . . 2251. 2152 \bool_if_p:c . . 2131. . . . . . . . . . 8047. 2153 \bool_if_exist:cTF . . . 453 \belowdisplayskip . . 4731 \above . . . . . . . . . . . . . . . . . . . . . . . . 8303. . . . 4732 . . . . . . \9 . . . . . . . . . . . . . . . 2269. . . . . . . . . 2994 \__token_if_skip_register:w . . . . . . . . . . . . . . . 38. . . . . . . . . . 72. . . . .bool_gset:N . . . . . . . . . 2094. . . 13. 180 nan . . . . . . . . 3003. . 3966. . . . . . . . . . . . . . . 2820. . . . . . . . . 150 \bool_gset:Nn . 2989. . 38. 40. . . . . 2098. . 151 \bool_gset_true:c . . 68. . 2251. . . . . . 2094 \bool_gset_true:N . . . . \BeginCatcodeRegime . . . . . 4730. . . . . 2134. . . . . . . . . . . . . . . . . . . . . . 2248. . . . 441 max . . . .bool_gset_inverse:N . 440 \atopwithdelims . . . . 2254. 2858. . . . . . . . 3062. . . . . . . 7422. . . . . . . . . . . . 8584 \bool_if_exist:NTF . . . . . . . 2143. 8890 \bool_if_exist:c . . . . . . . . . . . . 2120 \bool_if:n . 309. . . . . . . . . . . 2152 \bool_if_exist_p:N . . 2110 \bool_gset_false:c . . . . . . 2116. . . . . . 2943. . . . . . . . . 2256. . . . 40. . . 2106. . . . . . 2094 \bool_gset_false:N . . . 2154. . . . . . 1070. . . 2120 \bool_if_p:N . . . . 703 \belowdisplayshortskip . . 2250. . . . . 2858. . . . . . . . . . . 2265 \bool_gset:cn . . 2248. . . 2094. . . . . . 8298. . . . . . 8940 \bool_if:nF . . 2106. . . . . . . . . . . . . 2152 \bool_if_exist_p:c . . . . . . 178 B \B . . . . . . . . . . . 516 . . . . . . . . . 7555. . . . . . . . 39. . . . . . . 12479. . . . . . . . . . . . . . . 439 \accent . . . . . . . . . . . . . . . . . . . . . . . 2156. . 333 \afterassignment . . 11111 \~ . 2253 \bool_do_until:nn . . . . 3068 \__token_if_protected_macro:w . . 4138. . . . . 2113 \bool_gset_eq:cN . . . . . . . . . . . . . . . . 179 \assert:n . . . . . . 343 \aftergroup . . . . . . . . . . . . . 2923. . . . . . . . . . . . . . 2992. . . . . . . 451 \abovedisplayskip . . . . . . . . 2104 \bool_if:cTF . . . . . . . . . . . 2100. . . . . .Index 711 \__token_if_primitive_undefined:N . . \badness . . . . . . 14934 \bool_if:NTF . . 2734. . . . 2112 \bool_gset_eq:Nc . . . . . . . . . . . . . \batchmode . . . . . . 3013. . . . 38. . 2154. . . . 39. . 2111 \bool_gset_eq:NN . . . . . . . . . . . . . 2130. . . . . . . . . . . . . . . . . . . . . . . . . . . . 62. 8111. . . . . 2254. . . . . \␣ . . . 8092. . . . . 7021. . . . . . . . . . . . . . . . 13982 \begingroup . . . . . 735 \bool_do_until:cn . . . 588 . . . . . . . . . . . . 2120. . . . . . . . . 2117. . 38. . . . 2248. . . . . 2958. . . . . . . . . . 2115. . . . . . . 2278 \bool_if:NT . . . . . . . . . . . . . . . . 1365. . 8569. 2152 \bool_if_exist:N . . . . 2275. . . . \baselineskip . . . . . . . . . . . . . . . . . . . . . 2744. . . . . . . . . . 2114 . . . . . . . . . . . . . . 2152 \bool_if_exist:NF . . . . . . . 2106. 2235. . 249. . . . . . . . . . . . 7697. . . . . . . . . 2245. . . . . . . 6509 \box_gclear_new:N . . 6571 \box_if_empty:NF . 2096. . . . 6512 \box_gclear_new:c . 6878. . . . 128. . 7490. . . . . . 6594 \box_log:N . . . . . . . 6567 \box_log:c . . . . . 6505. 6594. . 6994. . . . 6775. . . . . . . . . 6907 \box_ht:N . 14368. . 2272 \bool_while_do:cn . . 2106. . . 2092. 2254. . . 2244. . . . 7179. . . 6538. 6515 712 \box_gset_eq:cN . 6904. . . . . . . . . . . . . 6503. 9404 \bool_not_p:n . 6559. 6571 \box_if_empty:N . 6559 \box_if_horizontal:NF . . . . 7420. . . . . . . . . 7531. . . 2102. . . . . . 6577. 37. . 2106. . . . . 127. . 14310. . . . . . 6527 \box_if_horizontal:cTF . . . . 14248. . . . . . . 2094. 6548 . . . . . . . 2149. . . . . 6971. . 2093. . . 7081. . . . . 2107 \bool_set_eq:NN . . 2259 \bool_xor_p:nn . 7001. . . . . 6526 \box_gset_to_last:c . . . 6529. . . . . . . 6509. . . . 6559 \box_if_vertical_p:N . 14312 \box_dp:c . . . . . . . . . 8515. . . 6566 \box_if_horizontal_p:c . . 2242 \bool_until_do:Nn 40. . . . 14310 \box_clip:N . . . 6595. .bool_set_inverse:N . . . 40. 6830. 6515 \box_gset_eq:Nc . 6520 \box_gset_eq_clear:cc . . . 41. . 6577 \box_gset_to_last:N 130. 6528 \box_if_exist:cTF . . . . . . 2114. . 6559 \box_if_horizontal:N . 6575 \box_if_empty:NT . 8569. . 8872. . . . . . . . . . 264. 632 \box_clear:c . . . 2150. . . . . . . . . . . . . . . . . 14581 \box_if_empty:cTF . . 8584. 7008. . 14267. . . 14266. . 6594 \box_log:cnn . . . 6512. 14093. . . . . . . . . 6569 \box_if_vertical:NT . . . . . 2094. . 6533. . . . 6594. . . . 7532. . 2242. . 2132. 38. 6517. . . . . . . . 6509 \box_clear_new:N . . . . 6563 \box_if_vertical:cTF . . . 6529. . . 6906. . . . . . 6511. . 6608 \box_move_down:nn . 14247. . . 2109 \bool_set_eq:cN . . . . . . 6508. 38. . . . . . 6977. 6527. . . . . . . . . . . 6514 \box_gset_eq:cc . . . . 2108 \bool_set_eq:Nc . . 188. 6905 \box_dp:N . . . . . . . . . 128. . . . . . . . . 6503 \box_gclear:N . . 7178. . 6975. . . .Index \bool_new:N . . . . . . . . 129. . . . . . . . . 6571. . . . . . . . . . . 6521 \box_gset_eq_clear:NN 127. . 2247 \bool_until_do:nn . . 6883 \box_clear_new:c . . . . . . . . 2243. . . . . . 38. 129. . 2148. . . . . . . . . 2094. . . . . 6503. . . . . . 14333. . 151 \bool_set_true:c . . . . 128. . 6530. . . . 128. .bool_set:N . . . . 6834. . . . . . . . . . . . . . . . . . . 129. 7050. . . . . . . . 2245. . 2242. . 14227. . . . . . . . . . 7160. . . 41. . . 6527 \box_if_exist:N . . 9497 . . . . . . . . 6559. . . . 6527 \box_if_exist_p:N . 128. 6503 \box_clear:N . . . . . 6568 \box_if_vertical:NTF . . 2254. . . . . . . . . . . . 2103. . . . 6548. . . . . . . . . . . . . . . . 127. . . . . 2118 \bool_set_eq:cc . . 6509. 6521 \box_gset_eq_clear:cN . . 2242 \bool_while_do:Nn 40. 14348. . . . . . . . 2106. 2235 \bool_set:cn . . . 6548. . . . 6615 \box_if_exist_p:c . . . . . . . 6573 \box_if_exist:c . . . . . . . . . . . 127. . 129. . . . 6571 \box_if_empty_p:N . . . . 7161. . . . . . 14321. . . . 6570 \box_if_vertical_p:c . . . 7035. . . . 14375. . . . . . 6529. 2236. 6559 \box_if_horizontal_p:N . . . . . . 127. 6576 \box_if_empty_p:c . . . . . . . . . . . . 2267. . . . . . 130. 6565 \box_if_horizontal:NT . . . . 6739. . . . . 6523. . 14579. 6510. . . . 6994. . . . . . 14343. . . 6559. 6597. . 129. 6973. . . . . 38. . . . . 14582 \box_gclear:c . 6594. . . . . 6510. . . . . . . 6536. . . 2114. 6561 \box_if_vertical:NF . . . 278. . . . . . . . 14310. . . . 6571. . . 6532. . . . . . . . . . . . . . . 6509. . 424 \botmarks . 2141 \bool_until_do:cn . . . . 2242. . 2147 \bool_show:n . . . . . . . . . . . . . 6506. 6513 \box_clip:c . 8499. . . 6529. . 6582 \box_ht:c . . 2151. 2236 \botmark . 2132. . . . . . . 6507. . . 2246 \bool_while_do:nn . . . . . 2135. . 14333. 2094 \bool_set_false:N 37. . 14092. . 6559. . . 129. . . . 6579. . . . . . . . . . . . . . . . . . . . 2132. . . . . . . 6564 \box_if_horizontal:NTF . . . . . . 14228. . . . 2114 . . 6574 \box_if_empty:NTF . . . . . 14198. . 9534 \bool_show:c . . . 6527 \box_if_exist:NTF . 9463. . . . . 6554. . . . . 2106 \bool_set_false:c . . . 14197. . 131. . . 38. . . . . . . 2092. . . . . . . . . . . . 14325. 7017. . . 8867. . . 650 \box . . 150 \bool_set:Nn . . . . . 6521. . . . . . 6515. . . . . . . . . . . . . . 6503. . . . . . . 14561 \box_move_left:nn . . . . . . . . . . . . . . . . 40. . 129. . . . . . . . . 2132 \bool_show:N . . . . . . . . . 7492. . . 2235. . . . . . . 14338. 8520. 6521 \box_gset_eq_clear:Nc . . . . 2254. . . . . . . . . 6559 \box_if_vertical:N . . . . . . . . 2094 \bool_set_true:N . . . . 6515 \box_gset_eq:NN 127. . . . . . . . . . 6529. 6596 \box_log:Nnn . . 2106. . . . . 14328. . . . . . . . . . . 14356 \box_viewport:Nnnnn . . . 14397 \box_set_eq_clear:cc . . 14581. . . 14296. . 14259. . . . . 9770. . . . . . . 14393. 9765. . . . 6588 \box_show:cnn . . . 7162. . . . . . 14376. . 14241 \box_resize_to_wd:cn . 14355 \box_use:c . . . . 129. . . . . . 128. . . . 6525 \box_set_ht:cn . . . 12068. . . . 14395. . . . . . 6541. . . . . . . 6588. 13326 \c__fp_ln_i_fixed_tl . . . 14341. . 14199. . . . 6515 \box_set_eq:NN . 14362. . 14222. 6720. . . 6577 \box_set_to_last:N . 14289. . . 6535. 7196. 6722. . 12074. 6734. . . . . . . 12308. . . . . . 14375. . 14259. . . 189. . 9757. . 6588. . . . . . 12077. . . 14554 \box_scale:cnn . 9770. . 12091 \c__fp_Bigg_trailing_shift_int . 7495. 6548. . . . . . . 12071. . . . . 6495 \box_new:N . . . . . 7180. 7181. . . . . . 14229. . . . . . . . . . 9764. . . . . 14353. 6544. . . . . 6735. . . 6728. . . . . . . . 12499. 6534. . 7160. 188. . . . 551 abs . 12297 \c__fp_big_middle_shift_int . . 6535. . . . . . . . 6577. 130. . . . . . . . 6519. . . . . . . 7197. . . 12277. . . . . 6521 \box_set_eq_clear:NN . 6518. . . 6909 \box_wd:N . . . . 6544. . . . . . 6581 \box_set_wd:cn . . 6580. . . . . 14349. . . . . 14119. . . 14369. . . . . 9772. . . . 180 pc . . 14328. . . . 6545. . 188. . . . . 14286. . 9771. 6736. . . . . 130. . . . . . . . . . 6723. . . 14318. . . . . 14348. . . . 14114. 6973. . . 6542. . 6515 \box_set_eq:Nc . 14259 \box_scale:Nnn . . . . . . 14757 \boxmaxdepth . . . . . . . 130. 12287. 14336. 14567 \box_show:c . . . . . . . 127. . 129. 6590 \box_show:Nnn . . . . . . 7485. . . . . . . . . 14268. . 6729. . 14305. . . 6502. 6786. . . . . 6529. 14351. 14222 \box_resize_to_ht_plus_dp:Nn . . . 7487. . 7494. . . . 9770. . . . 6893. 12279. . 180 \c__coffin_corners_prop . . . . . . 6521 \box_set_eq_clear:cN . . . . . . 6720. . . . 6717. . . . . . . . . . . . . . 12299. 14334. . . 14342. . . . . . 7161. 7484. . 14691 \box_resize_to_ht_plus_dp:cn . . 9763. 12499. . 6515 \box_set_eq:cN . . . . . . . . 129. 13048. . . . 6535 \box_set_dp:Nn . . 14564 \box_set_to_last:c . . . 12085 \c__fp_Bigg_middle_shift_int . . . 14586. . . 6908. 14212. . 6788. 6727. . 14258 \box_rotate:Nn . . 14313. . . 6591. 14222. . . . . . . . . . . . . . . . . . 7199. . . 7533. 594 \brokenpenalty . 6583. . . . . . 6584. . . . . . 14361. . . . 6504. . 6535 \box_set_wd:Nn . . . 6721. . . . . . . 12499. . 9763. . . . . . . . . . . . . . . 6731. . . . . . . . 6529. . . . . . 7493. . . . . . . . 14562. 14301. . . . . . . . . 12249. . . . 188. . 14566 \box_set_eq:cc . . . . . 7199. . . . . . . . 7414. . . . . . . . . . . . . 189. . . . . 14392 \box_new:c . 14381. . . 7178. 6593 \box_trim:cnnnn . 14313. . . 14356. . 7179. . 6977. 6577. . . . . . 6521. . 127. . . . . . 6531.Index \box_move_right:nn . 6732. 6589. . . 6983. 14356. . 6535. . . 6544 \box_use:N . . 9770. . . . . . . 6537. 6585. . . . . 7277. 6512. . . . . . . . . . . . . . . . . . . . 128. . 6515. . . . . 188. . . . . 7129. . . . . . 12321 \c__fp_Bigg_leading_shift_int . . 12499 \c__fp_ln_ii_fixed_tl . . . . 128. 14242. . 14290. . . . . . 6925 \c__fp_big_leading_shift_int . . . . 14750. . 14118. . . . . . . . 14192. . . . . . . . . 14077 \box_resize:cnn . 6782. 6524. . . . 14107. . 14713 \box_set_dp:cn . . 12500 \c__fp_ln_iii_fixed_tl . 6587. . . . . . 6544. . . 6510. . 12094 \c__fp_leading_shift_int . . . . . . . 14382. . 12088. . . . . . . . . . . 6521. . 14094. . . . . . . 12501 . . . . 6586. . . 6539. . . 14222 \box_resize_to_wd:Nn . . 7489. . . . . . . 6535. . . . . . . 6540. . 187. . 6515. . . . 6588. 6521 \box_set_eq_clear:Nc . . . 6588 \box_show:N . . . 9763. 6543. . . 7491. . 14313 713 \box_trim:Nnnnn . . 14399 \box_wd:c . . 14326. . 14192. 14569 \box_use_clear:c . . . . . . . . . . . . . . . 12289. . . . . 128. 14078. . . . 14341. . . 127. 6550 \box_move_up:nn . . . 6495. 6988. . . . . . 6548. . . . . 6733. . . . . . . . . . . 129. 6547. . 14249. . 6552. 7487. . . . 9757. . . . . . 180 nc . . . . . . 14222. . . . . . 14122. 7162. . . 6724. . . . . . 6923 \c__coffin_poles_prop . 14078. 14381. . . . . . 14371. . . 6725. . 7180. . 12311. 6496. . . . . 6544 \box_use_clear:N . . . . . . . . . . . . . . 14280. . . . . 6535 \box_set_ht:Nn . . . . . . 9763. 14120. . 6546 \box_viewport:cnnnn . . . . 14192 \box_resize:Nnn . . 6725. 178 C cc . 12314 \c__fp_big_trailing_shift_int . . . . . . . . . 9432 \c__keys_code_root_tl . 6504. 2762. . 9445 \c_catcode_other_token . . . . 14022 \c_e_fp . 14010. 4765 \c_active_char_token . . 4029 \c__int_from_roman_I_int . . . . . 13062. 12506 \c__fp_ln_vi_fixed_tl . 14002. . . . . 173. 8960. . . . . 9405. . . 8657. . 8563. 15040. . . . . . 12439. . . 8912. . 4029 \c__int_from_roman_c_int . . 8831. 7577. 8730. . . 13134. . . 9687. . . . 7625. 3310. . . . . . . 8773. . . 8749. . 12499. 8829. . 3311 \c_catcode_active_tl . 12257. . . . . . . 8652. 2706. 8328. 9412. 8743. . . . . . . . . 2800. 53. 7816 \c__msg_text_prefix_tl . . 8920 \c__max_constdef_int 3466. . 2795. . . . . . . . . . 12828. . 12499. 15063 \c__tl_act_uppercase_tl . 8789. . . . . . . 8232. . 9410. . . 9035 \c__keys_props_root_tl . . . 12499. . . . . 7614. . 8807. . 2706. 9469 \c__iow_wrap_indent_marker_tl 9410. . . . 12505 \c__fp_ln_x_fixed_tl . . . . . . . . . . . . 9524 \c__iow_wrap_newline_marker_tl . 8335 \c__msg_more_text_prefix_tl . . 8839 \c__keys_value_forbidden_tl . . . . 9759. . 4728. . 8751. 8909. . . . 9658. 2666. . . . 165. 13083. 5937. . . . . 8799. . 4029 \c__int_from_roman_V_int . . . 8769. . . 8767. 8783. . . . . . . . . . . 8675. . . . 3494 \c__msg_kernel_bug_more_text_tl . . 12263. . 8771. . . . 15055 \c__tl_rescan_marker_tl . . . . 8333. 13545 \c__fp_middle_shift_int . . 8757. 185. 12251. 8775. 9421. . . . . 8813. 13108 \c__fp_trailing_shift_int . 14005 \c_document_cctab . 9664. . 12504 \c__fp_ln_viii_fixed_tl . . 9410. 8492. . . . . . . 7577. 2719. . . . . 8765. . . 8491. . . . 9430 \c__iow_wrap_marker_tl . . . 6583. . . . 714 8805. . 2721. . . . . 5900. . 6583. . . . . 9479. . 4029 \c__int_from_roman_L_int . 8763. . . . 8679. . . . . 5915. . 53. 8759. . . . . . . . . 9422. . . . . . . 4029 \c__int_from_roman_M_int . 4029 \c__int_from_roman_d_int . . . 9670. . . 4029 \c__int_from_roman_v_int . 2634. 8801. 4093. . . . . . . 8833. . . . 2706. 8809. . . 8761. . . . . . 73. . 8745. 9658. . . 8490. 13147. . 7623. . . . . . . . . . . 8492. . 4098. 8966. . . . . . . . 13332 \c__int_from_roman_C_int . . 8325. 8971. 3313 \c_catcode_other_space_tl . . . . . . . . . . . . . . . . . . . . . . 12796. . 14004. 3470. . . . . . . 13059. . 8946. . . . . 13328. 3316. 53. . . . . . . . 2790. . . . 12372. 10587. 6506. . . . . . . . 8823. 8777. . 4736. . 8556. . . 7616. . . . 8793. 4029 \c__int_from_roman_i_int . 8626. 11801. . . . . .Index \c__fp_ln_iv_fixed_tl . 7274 \c_empty_clist . 7581. . . . . . . . . . . . 2640. . . 14002. . 8494 \c__keys_vars_root_tl . 8490. . . . . . . . . . 13761. . . 15040. 2712. . . . . . 7577. . . . . . . 7853. . . 13273 \c_eleven . . 7847. . . . . . . . . . 5953 . 12499. 9420. . . . . . 7796. . . 3317 \c_catcode_letter_token . 12186. 8779. 15040. 8835. 12507. 186. . . 3490. . . . 8493 \c__keys_value_required_tl . . . . . . . 7807. . . . . . . . . . . . . 9410. . 8259 \c__tl_act_lowercase_tl . . 8827. . . . . . . 8785. 4029 \c__int_from_roman_x_int . . . . . . . . . . . . . 3317 \c_alignment_tab_token . . 12670. . 8753. . 9849. . . . . 8669. . . 12503 \c__fp_ln_vii_fixed_tl . . . 7822. . 9444 \c__iow_wrap_unindent_marker_tl . . . . . . 4029 \c__iow_wrap_end_marker_tl . . 8817. 13761 \c_eight . . . . . . . 8815. 2672. . . . . 8803. . . . . . . 8791. . . . . . 10555. . . . . . . 8819. . . 8325. 73. 4747. . . . 9408. . . 9757. . 12186. . 2723. . . 9424. . . 12499. 13330 \c__fp_one_fixed_tl . . . . . . . . . . 3311 \c_alignment_token . . . . . . . 11876. . . . . . . . . 53. 12499. . 8674. . 8948. . . . 8490. . 8655. 4029 \c__int_from_roman_m_int . . . 8676. . . 12769. 8755. . . . 12716. 3314 \c_code_cctab . . . . 9758. . 9410. 5801. . . . 8781. . 11917 \c_empty_box . . . . . 9686. . 13056. . 13496. 8337 \c__msg_kernel_bug_text_tl . . 8821. . . . . 7578. . . 8747. . . . . 8787. . . . . . . 14019. 8825. 8493. . . 5801. . . . . . . . 130. . . . . . . . 15045. 12762. . 8493. . . . . . . 8664. 8526. . . 4029 \c__int_from_roman_l_int . . 8795. . 8907. 7839. . . . . . . 12723 \c__fp_max_exponent_int . 4029 \c__int_from_roman_X_int . . . . . . . . 9757. . 12260. 8837. 13050. 4028. . . . . . . . 13053. 2718. 12254. . . 8646. 120. . 8797. . . . . . 13084. . . 4101. 4093. . . . 12502 \c__fp_ln_ix_fixed_tl . . . . 8811. 4029 \c__int_from_roman_D_int . . 11611. 13127. . 11845. . 4554. 2775 \c_math_toggle_token . . 3468. 11145. . . 5402. . 186. . 9458. 9013 \c_msg_continue_text_tl 7630. . 13762 \c_one_hundred . 4093. 1498. . . 6899. . 4111. . 12199. . . 6635. . 73. 2628. 14840. 10133. 11934. . 4616. . 8054. 10648. . 7630. 7630. . 11791. . 10300. 12810. . . 7630. 9653. 9387. . 6640. . 1487. 13298. 8155. . . 10814. 4108. 13162. 9538. 3527. . . . . . . 9035 \c_letter_token . . . . . . . 812. . 7630. 2706. 13321. . 2660. . . 73. . 13777. 53. 12542. 14002. 12997.Index \c_empty_coffin 138. 82. 2212. . 4555 \c_max_register_int . 8057. 6589. 6217. . 53. . . . 11001. 73. . . 7656 \c_nan_fp . 9322. . . 10736. 14633. 11472. . . 4850. 7810 \c_msg_fatal_text_tl . . . . . . . . 11941 \c_msg_coding_error_text_tl . . . 172. . . . . 13267 \c_minus_one . 976. . 13513. . . 3442. 2706. . . . 1332. . 7674 \c_msg_critical_text_tl 7630. 12987. . . . . . 7275 \c_empty_prop . 5552. 14415. 12024. 11293. . 8080. 11517. . . . 4641. 11091. . . 2706. 10744. . . . . 4598. 8118. . . 2648. . 10917. . 817. 7630. . 12769 \c_four . 88. 13136. 12572. 85. 12976. 10709. 11607. 11090. . 8341 \c_msg_trouble_text_tl . 4093. . . . . 3529. . 10080. . 13292. 2101. 14011 \c_job_name_tl . 73. . 11945. 11752. 2716. . . 2752. . . 5733. 13152. 4402. . . 9272. . 4748. 53. 816. 10545. . 10102. . 12392. 7643. . . . 8088. . 5221. . 4108 \c_one_thousand . 13452. 7637. 7641. . 12401. 8991. 6683 \c_group_end_token . 1489. . . 11870. 7678 \c_msg_no_info_text_tl . 11288. . 8141. 9654. . . . . . . . 4096. 7646. 13761. 2757. . 1172. 11894. . 2678. . 7630. 4109. . 937. . 1087. 13518. 6898. 73. 1311. . 10461. 5801. 12765. . 10664. . 11300. 12336. . . . . 12377. . 11727. . . . . . . . 12005. . 11150. . . 13149. . 10136. . . . . . . . . . 1318. 10424. 4659 \c_keys_code_root_tl . 7649. . 8104. 13953 \c_max_skip . 12738. 12428. . 6217 \c_empty_seq . 4097. 73. 6152. . 11471. 1065. 10558. 5402. . 4093. . . . 2707. 9653. 2216. 13114. . 12457. 2780 \c_math_superscript_token . . 9322. . . . . 10788. . . 10585. 2646. . 9411. . . 8049. . . 12156. . 12945 \c_nine . . 10923. 73. 11093. . . . 9388 \c_luatex_is_engine_bool . 11633. 12418. 8163. . . . . 6595 \c_max_muskip . 2092. . 73. 10730. 9544. 12515. . 12027. . . . 4093. 13165. 13764 \c_one_fp . . . 4103. . . . 3941. 8148. . . 10918. 14852. 4655. 15105. . . . 10710. . 11038. . 2626. . . . . . 5560 \c_empty_tl 102. 12721. 9686. 827. 9365. . . . 12129. . . . 9653. . 10273. 9957. . . . 126. 2714. . . . 6691 \c_inf_fp . 11097 \c_five . . . . 12972. 11848. . . . 12940. . 111. 7648. . 11874. . 7639. . . 10238. 3310. . . . . 7635. 9655. 1510. 3312 \c_math_subscript_token . 2097. . . 1599. 10213. . 1066. 13922. . 73. 7673 \c_msg_on_line_text_tl . . 11918. 11944. . 10345. . 8111. . 5009. 2620. 824. 3312 \c_max_dim . . 11183. 1016. . . . . . 7974. 9657. . 165. 2680. 12526. 4403. 10352. 4641. . . 10921. 53. 12470. . 173. . 9965. 1021. . 4099. 13360. . . . . . . 4093. 13922. 2706. 12667. 2210. . 4614. 1600 \c_math_shift_token . . . 813. . . 6641. . 173. 4642. . 11595. 8064. . 11092. 4093. 11097 \c_group_begin_token . . 14634. . 4493 \c_minus_inf_fp . . 4093. 53. 3310. . . 2710. 15094. . 7665 \c_msg_return_text_tl . . 10037. . 10509. 9653. . 8984. 13265 \c_initex_cctab . 10403. . . 11140. 13914 \c_minus_zero_fp . 12351. 14653 \c_max_int . 13370 \c_fourteen 73. 9879. 6592. . 9437. 7799 \c_msg_help_text_tl . . 12038. 2706. 6156. 12127. 9006. 3955 \c_fifteen . . 4104. 7513. . 6898. 2239. 7980. 13219. . 3841. . . 10523. . . 12211. 11479. 13104. 10482. 2658. . . . 7630. 21. . . . 6217 \c_false_bool . 4093. . 7740. 10535. . 11480. . 2636. 10960. . 9322. . . 825. 2706. 5256. . 8127. 9656. . . 12406 . . 1925. . 13189. 4111. . 12387. . . . 172. . 7630. 14635. 12763. . 10471. . 13239. 715 9315. . 13129. 15146 \c_one_degree_fp 173. 14636. . 10132. 13763. . 12732. . . 8134. 8097. . . . 3313 \c_log_iow . 2652. 4108. 3946. . 11007. 11161. . . . . . . 2668. . 10725. . 11927 \c_one 73. . . . 10920. . . . . 4749. . 4492. . 2747. 102. . 7524. . . 12115. 4493. . 8046. 5402. . . . 812. 12223. 13278. . . . 14988. . 133. . . . 1174. 118. . 113. 13036. 1521. 2240. . . . 11547. 2654. . 13013. 129. 12796. 242. 4492. 73. 10440. . . 11929 \c_six . . 4492. 13613 \c_space_tl . 6157. . . . . 14426. 127. . . . . . . . 812. . . 11927. . 2535. . . . 11562. 7037. . . 21. . 13144. 3555. 11241. 10148. . 13140. 10821. 10201. . . 4093. 4110. . 1682. 2664. . . . . . . . . . 10088. 1599. 82. 4093. 10919. 10386. 14325. 2769 \c_pdftex_is_engine_bool . 11141. . 12372. 85. . 4392. 132. . 7666. 14368. . . 131. 11567. 10155. . . . 3707. . . 9848. 12543 \c_ten_thousand . 14304. . . 7. . 9619. 5. . . . . 10160. 88. . 102. . . 13566. 14096. . 9220. . 11170. 12109. 10090. 10094. 2785. . . . 11087 \c_three . . 13572. 53. . 4095. . 13763. . 73. . 821. . 10719. 3547. 15145 \c_two_hundred_fifty_five 73. 2317. 4093. . 12741. . 4093. 14701 \c_zero_muskip . . . . 13179. . 2834. . 13135. 240. 976. 10084. 2656. 9209. 7137. 13651. 2324. . 13083. 4100. 73. . 4093. . . 2670. . . 1554. 13960. 14002. 14021. 812. 9335. . 14013 . . 2319. . 2122. 4661. . . 9683. . 2624. 11391. 9297. 2632. . . . 10164. . 173. 11257. . . 13143. 4102 \c_thirty_two . 13114. . 4093 \c_sixteen . 10507. 5293. 4105. . . . 10691. 10994. . 73. 14056 \c_string_cctab . 12983. 12715. . . . 10922. . 13714. 128. . 636 \catcodetable . 9688. 13452. 12697. . . 3310. . . . . 13194. . 10358. 11215. 3017. . . . 4108. . 9371 \c_term_iow 165. 3839. . . 823. . . 14010 \CatcodeTableOther . . . 11023 \c_two . 10377. . 14098. 9209. . 13347. 116. 2316. 2571. . . 11151. . . . 7975. 10135. . 14341. . . 73. 1599. 819. . 7125. 12675. 11146. 12192. . . 10196. . 10123. 4402. 2644. 4093. 12995. 3442. 14351. . 12773. 13423. 13616. 1075. 3866. 4198. 812. 2356. . 9873. 7031. . 10576. 119. 10847. . 2713. 11926. 12439. 4026. . . 4094. . . 53. 13704 \c_space_token . . . 6148. . . 13381. 14839. 2674. . 13772. 120. . . . . 4105. 10134. 14012 \CatcodeTableString . 2717. 9470. 11020. . 4106. 12779. . 3946. . . 10144. . . 2865. . 14103. . 13763 \c_seven 73. . . 11631. 10189. 239. 4422. . . . 186. 2334. 13587. 2323. . 7068. 9456. . . . 3497. . . 14020. 10796. . . 4093. . 2766. 4402. 238. . . 2638. 73. . . 3959 \c_twelve . 10972. 3941. . . 9166. 12784. 3177. . . 2662. 15145 \c_str_cctab . 13370. 172. . . . . 7052. 12173. . . 1516. 14364. 9323. 9322. . . 73. . . 4513. . . 2322. 11929. . . . 130. 14395 \c_zero_fp . . 1073. 10857. . . 10594. 1601 \c_pi_fp . . . . 1065. 13158. 2341. 5222. 11383. 9272. 2518. 10677. 14012. 9783. 2511. . 11924. 9687. . 2211. 2217. 14381. . 14056 \c_ten . 13564. . 2706. 7130. . 9688. . . 11251. . 13254 \c_token_A_int . . . 9540. . 2622. 14291. . . 186. . 2099. 4554 \c_zero_skip . 14446. . . . 4107 \c_undefined_fp . . 5257. . . . 2630. . 13160. 112. . 11270. 117. 9278. . 2320. . . 15093 \c_zero_dim . 9323. 11160. . . 4661. 7034. . 7046. . . . 11940. . 812. 11037. . . . 73. . . 10. . 1509. 996. 14035. . 4106 716 \c_two_hundred_fifty_six . 2562. 2315. 12270. 5102. . . 8220. . 14002. 73. 6601. 5294. 2318. 10392. . 2706. 986. . . . 14989 \catcode 4. 2676. 11778. . 13730. 12793. . 2213. . . . 14378. . . 13562. . . . . 6. . 10629. 729 \CatcodeTableIniTeX . 12701. . 13729. . . 1673. 12331 \c_term_ior 165. . 11774. 3704. 3314 \c_parameter_token . 2650. 236. . 9653. 1065. . 14013. 13952. 11088. 4492. 115. 9696. 2336. 243. 11519.Index \c_other_cctab . . 7049. 2312. 14030 \c_other_char_token . 13920. . 9389. . 10098. 6602. . 3496. . 73. 4106. 13224. 13068. . 4459. . . 10382. . 9653. 10111. . 976. 2642. 11921. 11040. 2618. . . 237. . 11843. . . 15143. . 11089. 9209. 14336. . 3052 \c_true_bool . 7061. 12967. 1488. 822. . . . 1086. 11822. 2321. . 10152. 13209. . 5110. 14385. 1329. . . 241. . . 6650. 1602 \c_zero . 11237. . 14411. 820. 126. 13772 \c_xetex_is_engine_bool . . . 6664. 9365. 11909. 1499. . . 14055. 4554. 10768. 9853. 1526. . . . 14011 \CatcodeTableLaTeX . . 13000. 2095. 11065. 12127. 15144. . 9617. 4093. . 14376. 3437. 9390 \c_thirteen . 991. . 4024. . . . 114. . . 73. . . . 3319. . 2611. . . 197. 2621. 3344 \char_make_space:N . . . 50. 13982 \cctab_end: . . . . . . . . . 14004. . . . 2650. . 3319. . . . 14021 \char . 3353. . 2640. 256. 3319. 3339 \char_set_catcode_group_end:N . . 3326 717 \char_make_parameter:n . . . . . . . . 3325 \char_make_end_line:n . . . . . 50. . . . . 2730. . . . . . . . 14020. 3349 \char_set_catcode_invalid:N . . 3351 \char_make_math_shift:N . . . . . 3336 \char_make_comment:n . . . . . . . . . . . . 50. . . . 3340 \char_set_catcode_ignore:N . 2651. . . . 3319. . . . . . . . . 7699. . . 13999. 185. . 2722. . . . . . 2638. . . . 3343 \char_set_catcode_escape:N . 3319 \char_make_alignment_tab:N . . . . . . . . . . . . 15128 \char_set_catcode:nn . . . . 3319 \char_make_other:N . . 3342 \char_make_begin_group:N . . . . 13996. . 3319. 2635. . . . . . 3323 \char_make_math_shift:n . . 50. 3338 \char_make_group_begin:N . . . . 3329 \char_make_math_subscript:n . 257. . 3337 \char_make_invalid:n . . . 3350 \char_set_active:Npn . 50. . 13917. . . 3319. 3337 . . . . . . . 50. . 13931. 2678. . . 15112. . . . . 3332 \char_make_space:n . . . . . 3339 \char_make_comment:N . . 2619. . . . . . 13971. . . . 2731. . 50. . 3320 \char_make_escape:n . . . . . . . . . . 3353 \char_make_alignment:N . . . . . . 3343 \char_make_escape:N . 2649. . . . . 3319. 253. . . . . . 3319 \char_make_math_toggle:n . . . . . . . 2624. . 3354 \char_set_catcode_end_line:N . . . . . . 3319 \char_make_ignore:N . . 50. . . . . 14022. 2652. . . . 2660. . . . . . 13940. . . . 3283. . . . . 2653. 3319. . . . 15125 \char_set_active_eq:NN 197. 15112. . . 2644. . . 13934. . . 3331 \char_set_catcode_ignore:n . . 3322 \char_make_end_group:n . . . . 2643. . . 3349 \char_make_invalid:N . 8387. 185. . 2666. . . . . . . 2649. . . 3335 \char_make_active:n . 13987. . 261. . . . 3354 \char_make_end_group:N . . . . 2676. . . . . . . . . . . . . . 2617. 3319. . 51. . . 260. 2645. 3342 \char_set_catcode_comment:N . . . . . . . 3319. . . 258. . . . . 8388. . . 2626. . 3320 \char_set_catcode_escape:n . 3319. . 15118 \char_set_catcode_alignment:N . . . . . . . . . . . . 14019. . 3340 \char_make_end_line:N . 13917. 3319 \char_make_group_begin:n . . 2617. . . . . . . . 50. . . . . . . 3324 \char_set_catcode_alignment:n . . . 3319 \char_make_group_end:n . . . . 3319. . 13983 \cctab_gset:Nn 185. . 3319. 2634. . 2617. 3319 \char_make_alignment:n . . . . 2622. 3325 \char_set_catcode_end_line:n . . . . . . . . 14005. 2711. . 2657. . 3331 \char_make_ignore:n . . . . . . . . 14035 \cctab_new:N . . . . . . . 3321 \char_set_catcode_group_begin:n . 13948. . . 2617. . 2674. 268. 2662. 2667. . . . 254. . 15112. . . . . 2654. 15112. 2734. . 3319. . . 2636. 3352 \char_make_parameter:N . 2618. . . 3341 \char_make_math_subscript:N . . . . . . . . 2649. 14028. . 15129 \char_make_active:N . . . . . . . . . 3333 \char_make_letter:n . . . . . . . 3322 \char_set_catcode_group_end:n . . . . . . . 3319. . . . . 14030. . . 2649. . 13973. . . . . . . . . . . . 50. 2675. . . 2656. . . 2668. . 2876 \char_gset_active:Npn . . . 3347 \char_make_math_superscript:N 3319. 2620. . . . . 3336 \char_set_catcode_comment:n . 2617. 13968. 2617. . . . . 490. . . . . . . 2732. . . . 13987. . . . . . 2617. 2647. 3321 \char_make_begin_group:n . 15127 \char_gset_active_eq:NN 198. 2625. . 15113 \char_set_catcode_active:n . . 3334 \char_make_other:n . 2630. . 185. 197. 50. . 50. . . . . . . . . . . 3327 \char_make_math_superscript:n 3319. . . . . . 2865 \char_set_catcode:w 3282. . 15124 \char_set_active:Npx . 50. . . . 269. 2648. . . . 2628. 2617. . . . . . 2649. . . . . 2729. . . . 2649. . . . . 3292 \char_set_catcode_active:N . 2649. . . . 15112. . . . . . 3338 \char_set_catcode_group_begin:N . . . 2658. . 2659. . . . . . . . . .Index \cctab_begin:N . . . . . . . . . 13976. 3319. 3319 \char_make_group_end:N . . . . . . . 13958. . . . . . . . . . 3319. 2632. 3290. . . . 3319. . 15112. . 2611. . . . 50. . . 2649. . . . . . 13948. . 3335. 3319. 3319. . 271. . 2617. 2677. 2670. . . . . 255. 2642. . . . . . . . . . . . . . . . . . . . 50. . 50. 2617. 2649. 2733. . . 2646. . 50. . . 2672. 3345 \char_make_math_toggle:N . . . . . . . . . . . . . . . 3319. . . . . . 2664. . 3324 \char_make_alignment_tab:n . . . . . 3355 \char_make_letter:N . . . . . . . . 15126 \char_gset_active:Npx . . . . . . 2680. . . 2627. . . 13948. . 3319. 259. . . . . 14489. . 3293 \char_value_sfcode:n . . . . . . . . 15127. 1620 . . . . . . 2649. 52. . . 3326 \char_set_catcode_parameter:n . . 14024. 3302. . . . 5810. . 3332 \char_set_catcode_space:n . 2617. . . 113. . . . 5989. . . . . . . 3304 \char_set_uccode:nn . 2693 \char_set_uccode:w 3282. . . 52. 6134. 7696. . . 6182. . . 5810 \clist_concat:ccc . 50. . 3289. . 11031. . . 2681. 255. 14489 \clist_const:cx . 11096. . . 50. . 2649. . . 5822. . 14027 \char_set_catcode_math_superscript:N . 113. . . . . . 6200 \clist_count:N . 11267. . . 2681. 2617. . 3289. . . 6142. . . . . 3285. . . 6134. . 8206. . 8390. 2661. 5807 \clist_clear:N . . . . . 2681. . . . . . . 14038 \char_set_catcode_parameter:N . . . . 2611. . 3295 \char_set_sfcode:nn . . 257. 2715. . 2649. . 3290 \char_value_lccode:n . 5809 \clist_gclear:N . 5873. . 5806. 2859. . . . . 5886 \clist_const:cn . 151 . . 14039 \char_set_lccode:nn . 5808. 6201. . . 10256. . . 3350. . . . 118. 258. 2681. 13294 \char_set_catcode_letter:n . 138. 15129 \char_value_catcode:n 51. . . . . . 2673. 15133. . . . . . . . . . . 5822. . 52. 6183 \clist_gclear:c . 3333. 14462 \clist_clear_new:c . . . . . . . 15126. . . 3296 \char_value_mathcode:n . . . 3298 \char_set_mathcode:nn . . . . . . . 3323 \char_set_catcode_math_toggle:n . . . . . . 14464 \clist_gclear_new:c . 52. 2823. . 3289. . . 7697. 8209. . 6182. . . . . 190. . . 2649. . . . 3300 \char_tmp:NN . 3352. 50. . . 2701 \char_value_sfcode:w . . 3299. 3289. . . 3289. . . . 3287. 50. . . 3289. . . . . . . . . . . 3330 \char_set_catcode_math_subscript:n . 15134. . . . 15135. .choices:nn . 5810. . . 2681.choice_code:x . . 9406. . 3293. . . . 3020. . . . . 2819. . 2687. . . . 2681. 3301 \char_show_value_catcode:n 51. . . . . 3303 \char_show_value_uccode:n 52. . 3351 \char_set_catcode_math_subscript:N . . . . . . . . . 3341 \char_set_catcode_other:N . 15128. 5806. . . 8389. 11285. . . . . 2860. . 151 . 3348. . . . . . . . . . . . 3284. . 276. . . . . . . . 2683 \char_value_mathcode:w . 14025. . . 253. 14033. 6199. . 3346 \char_set_catcode_math_toggle:N . . . . . . . . . . . . . . . 11524. . 11234. . . 2861. 14026. . . . . 2655. . . 2862. . . 3022. . 2681. . . . 14404. . . . 11523. . . . . 2641. . . . . . . . . . . 2681. 3289. 6134. . . . 270. 7698. 2649. . . 2689 \char_value_lccode:w . . 2649. 50. . 8205 \char_set_catcode_math_superscript:n . . . . . . . 2681. . . 50. . . . . . . . . 273. 3289. 3302 \char_value_uccode:n . 3355 \char_set_catcode_letter:N . 256. . 52. . 2665. . 10312. 10255. . 2863. . 114. 11086. 2623. . . 272. . . . . . . . . . . 2679. 275. . . . . 15114. . 2617. . 2631. 151 \cleaders . . 274. 6134. 50. . . . 325 \chk_if_free_cs:N . . . . 51. 15124. 15136. . . . . . . . . . . 261. . 6184 \clist_display:N . . . . 2617. 5810. 3019. . . . . 2649. 11111. . . . . . 10311. . 2681 \char_set_mathcode:w 3282. . 3289. . 3328. . 14489 \clist_const:Nn . . . 5835. . . . . . . . . . 113. . 113. . . . . . . . . 5806. . 2681. 15125. . . . 2697 \char_show_value_uccode:w . . . . . . . 2669. 2649. . . 254. . 5822 \clist_concat:NNN . 2671. 14489. 2822. . . 2663. . . 3286. 151 . . . 50. . . 10841. . . . 8856. .choice: . 5812 . 50. . 2611. . . . . . . .choice_code:n . 5810. . . 2703 \char_show_value_sfcode:w . 2637. . 2821. . . . . 2820. . . 3021. . . . . . . 14491 \clist_const:Nx . 2691 718 \char_show_value_lccode:w . . 2617. 2709. . . 2615 \char_show_value_catcode:w . 5813 \clist_gclear_new:N . . . . . 260. . 14434 \clist_display:c . . . 122. 50. . . 8208. . . 2681. . . 50. . 52. . . . 52. . . . . 508 \clist_clear:c . 6143. . . . 3289. . . . . 3296. . . 259. . . . 2681. . . 11112. . . . . 8207. . . 9407. 10257. . 3294 \char_show_value_sfcode:n 53. . . . . . . . 14510 \clist_count:n . . . . . . . 50. . . . . . . 10258. . 5811 \clist_clear_new:N . 3291 \char_show_value_lccode:n 51. . 13479. . 3297 \char_show_value_mathcode:n . 2639. . . . 2699 \char_set_sfcode:w 3282. . . . 3334. . 51. . 5806. . . . . . . . . . . 135. . . . . 3299 \chardef . . 2617. . . . . . . . . 50. . . . . 3344 \char_set_catcode_space:N . . . . . . 15137 \char_set_catcode_other:n 50. . 283. . 2695 \char_value_uccode:w . 2613 \char_value_catcode:w . . 14489 \clist_count:c . 2633. . . . . . . 15120 \char_set_lccode:w 3282. 2617.Index \char_set_catcode_invalid:n . 50. 1619. . . . 2685 \char_show_value_mathcode:w . . . . 2629. . . . 5806. . . . . . . . . . . . . 5966. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5975 \clist_gput_left:Nx . . 5820 \clist_gset_eq:Nc . . 5935 \clist_gpop:NN 119. . . . . . . . 5979 \clist_gput_left:cx . . . . 114. . . . . . 5837 \clist_if_exist_p:N . . . . . . 5946 \clist_gpop:cN . . . . . . . . . . . . 5897 \clist_gput_right:No . . . 5909. . . . . . . . 6194 \clist_if_eq:NcTF . . . . . . . . . . 5985. . . . . . . . . . . . . . . . 5966. . . 5887. 5935 \clist_get:NN . 118. . . . . . . 115. . . . 6029. . . . . . . 14492 \clist_if_empty_p:c . . 6016. . . . . . . . . . 5866 \clist_gset:co . . . 5981 \clist_gpush:Nn . . 5866 \clist_gset_eq:cc . . 5819 \clist_gset_eq:NN . . . . . . . . . . . . . . 5896. . . . . . . 5945 \clist_get:NNT . 6192 \clist_if_eq_p:cc . . 5885. . . . . . . 5966. . . . . . . . . . . . . . . . . . . 6178. . . . . . . . . 6180 \clist_gremove_duplicates:c . . . . . . . 190. . . . . . . . . 5885 \clist_gput_right:NV . . . . . . . . . . . . . . . . . . . . . . . . . . . 6186 \clist_gtrim_spaces:N . 5837 \clist_if_exist:NT . .clist_gset:c . . . . . . . . . . . . . . 118. . . . . 5866 \clist_gset:cx . 6175 \clist_get:NNF . . 5934. . . . . . . . . . 5871 \clist_gset:No . 5979 \clist_gpush:cx . . . . . . . . . . 14492 \clist_if_eq:cc . . . . . . . . . . . . . . . . . . . . . . . . 5898. . . . 114. . . 5814. . 5963 \clist_gpop:NNTF . 6192 \clist_if_eq_p:NN . . . . . . . . . . . . 5872. . . . 115. . 6186. . . . . 5831. . . 115. . 5824. . . . 5983. 5976 \clist_gpush:NV . . . 5898. . . . . . 190. . . . . . . . . . . . . 5974 \clist_gpush:No . . . . . . . . . . . . 5964 \clist_gpop:NNT . . . . . . 5935. . . . . . . . . . . . . . . . . . 151 \clist_gset:Nn . . . . 5885 \clist_gput_right:Nn . . . . . 14461 \clist_gset_from_seq:cN . . . . . . . . . . . . 5977 \clist_gput_left:cn . 5966. . . 5998 \clist_gremove_element:Nn . 5944 \clist_get:NNTF . 5999. . . . . . . . . . . . 5966. . . . . 14461 \clist_gset_from_seq:NN . . . . . . . . . . . 5935. . 5872. . 14492 \clist_if_empty:NF . . . 5966. . . 5872. 6108 \clist_if_empty:NTF . . . . 6059.Index \clist_gconcat:ccc . . . 6001. . . . . . . . . . . . . . . . . . . . . . . . 8182 \clist_if_empty:nTF . . . . . . . . . . . . . . . . . . . 5888 \clist_get:cN . . . 5866 \clist_gset:Nx . . . . . . . . . . . . 6192 \clist_if_eq:cN . . . . . . . . . . . . . . . 6192 \clist_if_exist:c . . . . . . . . . 6192 \clist_if_eq:NN . . 14463. . . 114. . . . . . . 5885 \clist_gput_right:cx . . . . . . . . . . . 6192 \clist_if_eq:Nc . . 6030 \clist_if_empty:N . . . . . . . . . . 14461 \clist_gset_from_seq:Nc . . . . . . 5898. . . . . . . . . . . . . . . . . . 5966. . . . 5911. . 6180 . . . . . . . . . . . . . 5875. . . . . 5884. 119. . . . 5949 \clist_gpop:NNF . . . . . 5978 \clist_gput_left:co . . . . . . . . . . 5872. . . . . . . . . . . . 6030 \clist_if_empty_p:n . . . . . . . . . . . . 115. 6030 \clist_if_empty:n . . . . . . . 114. . . . . 6193 \clist_if_eq:NNTF . 5986 \clist_gset_from_seq:cc . . . . . . 5978 \clist_gpush:co . . . . . . . . 5814. . . . . . . 5999 \clist_gremove_all:Nn . . 14487. . . . . . . . . . . . . . 114. . . 9187 \clist_if_exist:NTF 114. . . . . . . . . 5838 \clist_if_exist:cTF . . . . . . . 5868. . . . . . . . 14488 \clist_gtrim_spaces:c . . . . . . . 14508 \clist_if_exist_p:c . . . . 6190 \clist_if_empty:c . . . . . . . . . . . . 5965 \clist_gpush:cn . 9160. . . . . . . . . . . . 6195 \clist_if_eq:cNTF . 5885 \clist_gput_right:Nx . 5866. . 5977 \clist_gput_right:cn . . . 5822 \clist_gconcat:NNN . . . . . . . . . . . . . . . 5908. 5866 \clist_gset:cV . . . . . 114. . . 5837. . . 5872. . 5814. . . 6188 \clist_gset:NV . . . . . . 5975 \clist_gpush:Nx . . . . . . 5974 \clist_gput_left:No . . . . . . . . 5837 \clist_if_exist:N . . . . . . . . . . . . . . . 5874. . . . . 6089. . 5872. . . 5818. . . . . . . 5980 \clist_gpush:cV . . . 5814. 6192 \clist_if_eq_p:Nc . . 190. .clist_gset:N . 6030. . . . . . . . . . . . . . . . . . . . . . . . . 5885 \clist_gremove_all:cn . . . 6176 \clist_get:cNTF . . . . 5883. 5966. 6192 \clist_if_eq_p:cN . 5872. . 5836. . . . . 5822. . . . . . . . . . . . . . . . . . . . 6031 \clist_if_empty:cTF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14461. . . . . . . . 6030 \clist_if_empty_p:N . 119. . . . . . . . 151 719 \clist_gset:cn . . . . . . 5935. . . . . . 5885 \clist_gput_right:co . 5980 \clist_gput_left:cV . . . . . . . 5866 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5872. . . . . . . . . . . 6196 \clist_if_eq:ccTF . . . 5821 \clist_gset_eq:cN . . . . . . . . . . . . . . . . . . 5981 \clist_gput_left:Nn . 5909 \clist_gpop:cNTF . . . 6188. . 5837 . . . 5866. . . 5976 \clist_gput_left:NV . . . . . 5983 \clist_gremove_duplicates:N . . . . . . . . . . . 5885 \clist_gput_right:cV . . . . . 5885 \clist_put_right:Nx . . . . 5885 \clist_put_right:co . . . . . . . . . . . . . . 113. 6049 \clist_if_in:nnT . . 5966 \clist_put_left:No . . . . 6032 \clist_if_in:coTF . . . 6055 \clist_if_in:NnT . . . . . . 5909 \clist_pop:cNTF . . . . . . 5866 \clist_set:Nx . 114. . . . . . . . 117. . . . . . . 6032. . . . . . . . . . . . . . . . . . . . 6106. 6087. . . 6032 \clist_item:cn . . . . . . . . . 5970 \clist_push:co . . . . . . . . . . . . 5804. 5872. . . . . . . . 5895. . . 5997 \clist_remove_element:Nn . . . . . 9204 \clist_map_inline:nn 6087. . 6036 \clist_if_in:NnF . 5966. . . 5983. . . . . . . . . . . . . . . . 5968 \clist_put_left:NV . . 6173 \clist_pop:cN . . . 6032. . . . . . . . . . 6131. . . . 14886. . . . . 5947 \clist_pop:NNF . . . 8630. . . . . . . . 6100. . . . . . . . . . 5973 \clist_put_left:Nn . . 115. . . . 5804. . . . . . 5968 \clist_push:NV . . . . . . . . . . . . . . . 14430 \clist_item:nn . . . 6032 \clist_if_in:nVTF . . . . . . . . . . . . 6032 \clist_if_in:cVTF . 6117 \clist_new:c . 6199 \clist_length:n . . . . . . . . . . . . 5866 . . . . 5814. 116. 14461 \clist_set_from_seq:Nc . . 119. 6081. 6198. . . . . . . . . . . . . . . . . 5966. . 6068. 14401 \clist_item:Nn . 5933.clist_set:c . . . 118. . . . . . . . 116. . . . . . 5815 \clist_set_eq:NN 114. . 6179 . . . . . 119. . . . . . . . . . . 5972 \clist_push:cV . . . . . . 114. . . . . . 5967 \clist_push:Nx . . . 8937 \clist_remove_all:cn . . . . 5885 \clist_put_right:NV . . . 5999. . . . . . . . 5969 \clist_put_right:cn . 6130. . . . . . . 5935 \clist_pop:NN . . . . 5872. . . . 5872. . . . . 6053 \clist_if_in:nnTF . . . . . . . . 5870. 119. . . . . . . . . . . . . . 5817 \clist_set_eq:cN . 5804. 114. . . . . . . 5882. . . 6063. . . 5805 \clist_new:N . . . . . . . . 6032 \clist_if_in:noTF . . 5888. . . . 151 \clist_set:cn . . . . . 5872. . . . . . . . . . 6133 \clist_map_break:n . . . . . . . . . . . . 5894. . . . . . 6087 \clist_map_inline:Nn . . . . . 5881. . . . 5814. . 14431. . 5966. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5816 \clist_set_eq:Nc . . . . . . . . . 5873. . . . . . . . . . . 6087. . . . . 6170. . 5866 \clist_set:cx . . . 8861 \clist_set_from_seq:cc . . . . . . . . . 6162. 5866. . . . . . . 5866 \clist_set:co . . . . . . . 5982. . . . 6057. . 6038. . . 6119. . . . . . . . . . 5983. . 6048. . . . . . . 6032 \clist_if_in:Nn . . . 6130. . . . 5814. . . . . 5966. . 6120. . . . 5966. . . . . . 6172. . 151 \clist_set:Nn . . 5966. . . . . . . . . . 5866. 5960 \clist_pop:NNTF . . 6171. . . 5984. . . . . . . . . . . . . . 14891. . . . . . 6072. . . . . . 6103. . . . . . . 5966. . 6051 \clist_if_in:nnF . . . 5961 \clist_pop:NNT . . . 5962 \clist_push:cn . 14901 \clist_map_inline:cn . . . . . . . . 6032 \clist_if_in:NVTF . 6073. . . 5909. 6200 \clist_map_break: . . 8715 \clist_map_variable:cNn . 5872. . 5814. . . . 5872. . . . . . 5999. . 5885. 6198. 5909. . . . . . 5967 \clist_put_left:Nx . . . . . . . . . . . . . . 5885. . . . . . . . . . . 5969 \clist_put_left:cn . . . . . 9924 \clist_if_in:NoTF . . . . . . . . . . . . . . . . . . . 6028. . . . . . . 5990. . 5885. . . . 6073. . . . . . . 6056. . . . . . . . . . . . . . . . 14431 \clist_length:c . . . 14461 \clist_set_from_seq:cN . 6032 \clist_if_in:nn . . . . . . . . . . . . . 6106 \clist_map_variable:NNn . . . . . . . 5971 720 \clist_push:cx . 5993 \clist_put_right:No . . . . . . 5872. 6132 \clist_map_function:cN . . . . . 14401. . 5814. . . . . . . . . . . 5866 \clist_set:cV . 6166 \clist_set:No . 6106. . . . . . . . . . . . . . . . . . . . 116. . . . 6077. . . . . . . . . . . . 6201 \clist_length:N . . . . . . . . . . . 8700. . . 14461 . . . . . . . . . . . . . 6114. . . . . . 9189. . . . . . . . . . . . . 6178. . . . 5875. . . 5935. 6139. . . . . . . 5885 \clist_put_right:Nn . . . . . . . . . . . . . 6198. . 5966 \clist_push:No . . . 5970 \clist_put_left:co . . 6050. . . 115. . . . . . . . 6129 \clist_map_variable:nNn . 6096. . 5973 \clist_push:Nn . . . . . 5971 \clist_put_left:cx . . . . . . . 6187 \clist_set:NV . . . 5885 \clist_put_right:cx . . . . . 117. . . . 6102. . . . . 190. . . . . . . .Index \clist_if_in:cnTF . . . . 5966. 6105. 5885 \clist_put_right:cV . . . . . . . . 14401.clist_set:N . . . 6052. . 6130. . . . . . . . 5972 \clist_put_left:cV . . . 5983 \clist_remove_duplicates:N . . . . . 6054 \clist_if_in:NnTF . . 6057. . . . 5872. . . . . 5872. . . . . . . . . 6057 \clist_map_function:NN . . . . . . . 6179 \clist_remove_duplicates:c . . . . . . . . . 5866. . . . . 5866 \clist_set_eq:cc . . . . . . 5992. 6106. . . . . . . . 5886. . . . . . 8611. . . 14896 \clist_map_function:nN . . . . . . . . 5999 \clist_remove_all:Nn . 6798. . 6159. . 7272. . . . 6903. . . . . . 1355. . . 6748 \coffin_if_exist:N . . . . . . . . . 6167. . 1759. 6761. 14575 \coffin_scale:cnn . . 1766. . . 14715 \coffin_if_exist:cTF . . . . . . . . 6748 \coffin_if_exist_p:N . 6889 \coffin_set_eq:cN . . . . . 1774. 6889 \coffin_set_eq:NN . 6760 \coffin_if_exist:NT . . . . . . . 7201. . . 799. 7544 \columnwidth . . . . 7365. . . 14689. . . . 6941. . . . . . . . . 6169. 7564 \color_group_begin: . . . 6759 \coffin_if_exist:NTF 135. . . . 7472 \coffin_dp:c . 7549. 1404. . . . . . . . . 6906. 6203. . 6865. . . 1113. . 119. . . . . . 3544. . . 1773. . . . . . . 7387 \coffin_display_handles:Nn . . 1733. . . . . . . 352 \cs:w .code:n . 11018. . . . . . 7381 \coffin_clear:c . . . . . . . . . . 14683 \coffin_resize:Nnn 191. . . . . . 1696. . . . . . . . . . . . . . . 6889. . . 14461. 858. . . . . . . . . 138. . 7332 \coffin_mark_handle:Nnnn . . . . . 6909 \coffin_wd:N 138. 139. 6965 \coffin_set_vertical_pole:cnn . 6868. . . . . . . . 1288. . . 351 \crcr . . . . . . . . . . . . . 7172. . . 119. 858. . . . . . 6966 \coffin_show_structure:c . . . . 797. . . 7279 \coffin_wd:c .Index \clist_set_from_seq:NN . 7497. . . . . . . . . . . 9781. 384 \closeout . . . . . . . . . . . . 14686. . . . . . . . . . . . . . . . . 692 \clubpenalty . . . 6758 \coffin_join:cnncnnnn . 9752. . . . . . 6904. 1870. . . 14709. . . 7550. . . . . . . . 1697. 7272 \coffin_typeset:Nnnnn 137. . . 6842. . . 6780. . . . . 1147. . . . 6771. 7543. . . . . . . 1739. 7156. . 7280. 10369. . . 14709. 14719 \color . . . . 6203. . 6771. . . . . . . . . . . . . 627 \countdef . . 783. 6941 \coffin_set_vertical_pole:Nnn . . . . . . . . 6189 \clist_use:c . 7386 \coffin_new:c . 6889 \coffin_set_eq:Nc . 7156 \coffin_attach:cnnNnnnn . . . . . . . . . . . . . 14506 \closein . . 138. . . 7332. . . . . . 17. . . . . . . 2070. . . 1836. . . . . . 139. . . . . . . . . . 135. . . . . 7156 \coffin_attach:Nnncnnnn . . 1119. . . . . . . . . . . 7497. . . . . . . . . . 7332. . . . . 6183 \clist_show:n . . 14506. . . 6904. . . . . . . . . . . 10567. . . . . . . . . . . . 6941. . . . 6797. . . . . . . . 7340. . . 7183 \coffin_attach_mark:NnnNnnnn . . . 14541. . . . . . . . . 7408 \coffin_set_horizontal_pole:cnn . . . . . 7543 \color_group_end: . . 7554. . . . . . . . . 6764 \coffin_if_exist_p:c . . 137. . . . . . . . . . . . 10958. . . . . 14541. . . . . 7497 \coffin_show_structure:N . . . . 14683. . . . 10862. . . . 7352. . . . . . . . . . . . . . 7119. . . . . . . 14709 \coffin_scale:Nnn 191. 6174. . 12559. . . . . . . . . . . . . . . . . . . . . . 6863 \copy . 7156. . . . . . . . . . 6889. 136. 7119 \coffin_join:NnnNnnnn 137. . . . . . . . . . 799. . 1840. 7156. . . . . . . . 1692. 6904. . . . 6186 \clist_trim_spaces:N . 6780. . . . . . 6904. 6205 \clist_use:N . . . . 1119. . 797. . . . 14689. . 6187. . . . . . . . . . . . 7156 \coffin_attach:NnnNnnnn . 1141. . . . . . . . . . 14486 \clist_show:c . . . . . . . . 10599. . . . 782. . 6821. . . . . . . . . . . 6902. . . . . . . 6865. . . . . . . . 151 \coffin_attach:cnncnnnn . . . . 326 \cr . . 2289. 6907 \coffin_ht:N 138. . . . . . 7119 \coffin_join:Nnncnnnn . . . 190. 1676. 6186. . . 6184 \clist_show:N . . . . . . . . . . . . . . . . . . . . . . 14694 \coffin_rotate:cn . . . . . . . . . . . . . . . . . . . . . . . 6817. 14715 \coffin_ht:c . . . . 138. . 135. . . . . . . . . . 6204 \clist_use:Nnnn . 7272. . 6164 \clist_top:cN . . . . . . 191. . . . . 1690. . 6898. . 6952. . . . . . . 7435 \color_ensure_current: 139. . 14683. . 6159. . . . . . . . 6904. . . . 151 . . . 14541 \coffin_rotate:Nn 191. . . . . . . . . 519 . . 7119. 1147. 12827. . . 7153. 6901. 2291. 7281. . . . . . . . 7543. . . . 6159. . . . . . . . . . 7387. . . 1637. . . . 6800. . 6941. . 6904. . 6175 \clist_trim_spaces:c . . 10334. 7344. . . 6905 \coffin_dp:N 137. 576 \count . . . . . . . . . . . . . . . 135. . . 780. 780. . 1761. 6176 \clist_top:NN . .code:x . . . . . . 6842. . 6845. . . . 5326. . 6904. . . . . . . 6941 \coffin_set_horizontal_pole:Nnn . 7155 \coffin_mark_handle:cnnn . . . . . . 7174. 7387. . . . . . . 14485. . 1355. . . 7509 \coffin_typeset:cnnnn . . . 1698. . 14723 \coffin_set_eq:cc . . . . 6748 \coffin_if_exist:NF . 6159. 6900. . 6790. . . . . . . 6819. . . . 6779 \coffin_display_handles:cn . . . 136. . 6771 \coffin_clear:N . 135. . 13112 \cs_end: 17. . . . . . . . 14461. 379 \clubpenalties . . . . . . 7559. 7395. . 10890. . . . . . . . . 6908. . . 6174. . 6897. . . . . . . . . . . . 6748. 6748. . . . . . . . 7119 \coffin_join:cnnNnnnn . . . . . . . 803. . . . . 6780 721 \coffin_new:N . . . 7282 \coffin_resize:cnn . . . . . . . . 6403. 13800. 5644. 3504. 5544. 5660. 5896. 2077. 4583. 4207. 6356. 1690. 4870. 6322. 5519. 6658. 6967. 6320. 5547. 4582. 4486. 10911. 4892. 2118. 2293. 6526. 4724. 13802. 4699. 5791. 4618. . . 13728. 13823. 6574. 5666. 6807. 4214. 4440. 6052. 4425. 4624. 6543. 6626. 6564. 12559. 2075. 6534. 6055. . 1637. 4522. 4924. . 13472. 4216. 5946. 4449. 4702. 4998. 5897. 6341. 2301. 1836. 4611. 5933. 6520. 9380. 5884. . 6105. 5467. 13724. 13867. 4516. 9374. 5945. . . 4768. 9386. . 3541. 13911. 15. 6293. 5663. 4197. 5963. 4424. 8686. 6657. 5494. 6759. 5174. 5545. 4487. 1692. 5476. 5320. 5641. 5635. 5326. 6633. 5724. 6404. 2093. 1870. 1348 \cs_generate_from_arg_count:NNnn . 7386. 13904. 5465. 2524. 1840. 6854. 6632. 2303. 3525. 6464. 9224. 4397. 6049. 6466. 4677. 5636. 1774. 6387. 6570. 4545. 9153. . 4224. 5306. 6576. 4489. 6388. 6547. 4532. 4201. 6627. 6541. 6608. . 6965. 4437. 4770. 3522. 3535. 7183. 2246. 4842. 10603. 4678. 13112 \cs_generate_from_arg_count:cNnn . 9789. 4549. 4515. 5659. 1337. 5883. 4841. 6675. 2105. 4830. 6568. 13748. 5208. 6457. 1759. 6573. 5965. 1697. 4540. 6054. 6897. 4219. . 2102. 1696. 4529. 8660. 5608. 5964. 4787. 6790. 5454. 4421. 6056. . 4617. 13760. 4531. 4859. 6265. 5836. . 5319. 6028. 4985. 6295. 1739. 4727. 5662. 4891. 5646. 4217. 1676. . 5657. 4225. 3511. 4843. 4893. . . 2080. 10369. 4430. . . 5011. 5661. . 9170. 5870. . 5665.Index 1404. 5772. 6680. 4784. 4696. 4623. 4454. 6575. 6405. 13879. 13715. 8863. 2297. 2252. 8742. 1761. 8741. 6837. 5133. 10896. 2081. 13817. 4544. 6669. 4698. 28. 2129. . 4837. 4721. 2131. 6686. 10571. 9383. 13731. 3524. 13801. 6273. 2556. 6393. 2309. 4723. 9339. 1337. 1349. 6546. 14241. 2078. 6317. . 6758. 3971. 5934. 6051. 9281. 5871. 5961. 5207. 1698. 13907. 7155. 4831. 5642. 13866. 6392. 13745. 3507. 4479. 6424. 5034. 6687. 7279. 6507. 4230. 4703. 6888. 3544. 2147. 12827. 5944. 5643. 1347. 7987. 3498. 6566. 3523. 2307. 6406. 4206. 6335. 4441. 5895. 1367 \cs_generate_variant:Nn . 4229. 4857. 4448. . 6638. 6407. 8349. 4992. 4612. . 4969. 5590. 2555. 14212. 6142. 13908. 4720. 6502. 4600. 8671. 6169. 6596. 4846. 6569. 6703. 5520. . 13595. 6408. 1884. 3499. 6266. 1346 \cs_generate_from_arg_count:Ncnn . 2292. 5908. 4957. 4913. 6050. 8864. 5164. 2247. 4840. 1337. 9336. 13813. 2253. 4675. 13812. 5881. 5035. 4528. 6263. 2074. 4871. 4444. 3486. 13727. . 4534. 6779. 7509. 13816. 6072. 4786. 4674. 13747. 13815. 4725. 8262. 6321. 5734. 2294. . 5835. 9234. 6563. 13732. 2580. 4845. 2305. . . 6542. 6264. 13878. 2073. 6508. 1733. 4700. 6029. 4399. 4769. 3534. 5473. 4539. . 5723. 8351. 5683. . 4697. 4722. 6391. 6445. 6513. . 14258. 4551. 5468. 4415. 10865. 3465. 6053. 13723. 6390. 2578. 5359. 6386. 9221. . 4856. 4676. 6274. 13628. 4942. 2130. 4213. . 6668. 4200. 5655. 2079. 6702. 13803. 4521. 6389. 10334. 1766. 4914. . 5144. 4836. 13738. . . 6567. 6639. 6533. 4584. 3542. 6190. 4785. 5882. 4220. 3536. . 6355. 6514. 5209. 5591. 4915. 9752. 6760. 6129. 2295. 2070. 4847. 4535. 4505. 4894. . 5548. 5997. 13814. 6319. . 5010. . 4868. 6435. 5466. 1337. 8512. 5894. . 4679. 13822. 3505. 6582. 9910. 1884. 6565. 4844. 2557. 9263. 5712. 5658. 13737. 4637. 5145. 4638. 4922. 5475. 8849. 3508. 5474. 6581. 4923. 8680. 5656. 4771. 3510. 7472. 2577. 6590. . . 5664. 5998. 6532. . 4726. 8850. . . . 4511. 8350. 5206. 6458. 13527. 2119. 6519. 4191. 13678. 5546. 6339. 6674. 2104. 9236. 5578. 4443. 6966. 6761. . 5645. 10040. . 3537. 9235. 722 5453. 6465. 6423. . . 6681. 2579. 2525. 2076. 4453. . 13632. 5960. 6337. 5493. 5549. 2299. 6294. . 6189. . 6048. 5962. 2286. 6296. 4869. 2103. 6525. 6318. 4858. 2128. 4701. 1773. 4431. . 9356. 6593. 13722. 4438. . 2558. 6469. 4585. 13746. . 849. . . . . 4524. . . 1399 \cs_gset_nopar:cpn . . . . . 5460. 1446 \cs_if_eq:ccTF . 1503. . . . . . . . . . . . 4689. . . 1350 \cs_gset_nopar:Npn . 1399 \cs_gset_protected:Nn . . . . . . . . 843. . . 1350 \cs_gset_protected_nopar:cn . . . . . . . 1444 \cs_if_exist:c . 851. . . . 1350 \cs_gundefine:c . 9371. . . 843. . . . . 1431. . . . . 14487. 14903. 1264 \cs_gset_protected:cpx . 5702 \cs_gset_eq:NN . . . 12. . . . . 5697. . . 1246. . . . 1274. . . . . . . . . . 14694. . . . . . 1445 \cs_if_eq:cNF . . . 1247. . . . . . . 1240. . . . . 1350 \cs_gset_eq:cc . . . . . . . . . . . . 1259 \cs_gset_protected_nopar:cx . 847. . . . . . . . . 852. . . 1262. . . 1443 \cs_if_eq:NcT . . . 4598. . . . . . . 7663 \cs_gset_nopar:Npx . . . . . . . . . . 1274. 1505. . . . . . . 1436 \cs_if_eq_p:Nc . . . 1235. . 15110 \cs_gnew:cpn . . . . 5838. 4632 \cs_gset_eq:cN . 2110. 1247 723 \cs_gset_nopar:cx . . . 14907. 1590 \cs_gnew_eq:cN . . . . . . . . . . 1431. 14926. . . . . . . . . . 1436. . . . . . . . . 1573 \cs_gnew_protected:cpn . . . . . 856. . . . . 1252. . . . . . 5692. . . . . . . 1399 \cs_gset_protected_nopar:Nn . 1574 \cs_gnew_eq:cc . . . . . . . . . 1252. . . . . . . . . . . . . . 1446 \cs_if_eq:NNTF . . . 6428. . . 843. . . . . . . . 4631. . . . . . . 14831. 14. . 1583 \cs_gnew_protected_nopar:Npn . . . . . . 21. 15129 \cs_gset_nopar:cn . 1497. 14798. . . . . . . 8478 \cs_gset_eq:Nc 1268. . 1273. . . . . . . . . . . 1293. . . . . 1509. . 1447 \cs_if_eq:ccT . . 2101. . . . 1578 \cs_gnew:cpx . . . 1576 \cs_gnew_protected_nopar:cpn . . 15126 \cs_gset:Npx . . 1234. . 1258 \cs_gset_protected_nopar:Npx . . . . 1265 \cs_gset_protected:Nx . . . . . 1438. . . . 2112. . . . . . 1437. . . . . . . . . . . . 1581 \cs_gnew_nopar:Npn . 1498. 7623. . . . . . . . . 1242. . . 1439. . . . 1268. . . 1437. . 1431. . . 1431. . 848. . 1577 \cs_gnew_nopar:cpx . . 4669. 6528. . . . . . . . . . . . . 4629. 1493. 1496. 4609. . . . . . . . . . . . . . . . . . . 4671. . . 1253 \cs_gset:cx . . . . . . . . . . 843. . . . . . 1285. 4715. 1242. . . . . . . 4209. . . 6092. . . . . 1273. . 1258 \cs_gset_protected_nopar:cpx 1256. . . 4691. . 1438 \cs_if_eq:cNTF . . . . . . . . . 4695. . 846. . . 1262. . . . . . . . 14908. 855. . . . . . 850. . 1399 \cs_gset_nopar:Nn . 14399. . . . . . . . . 1495. . . . . . . . . . . . . 1399 \cs_gset_protected:cpn . . 1399 \cs_gset:Nn . . . . 4630. 14491. . . . . . . 7625 \cs_gset:cpx . . 1399 \cs_gset:cpn . . . . 1264. . . 1441 \cs_if_eq:NN . . . 1442. . 844. . . . . 1399 \cs_gset_protected_nopar:cpn 1256. . . . . . . . . . 853. . . 6358. . . . . . . . . . . . . . . 4433. 1241. . 843. . . . . 1569 \cs_gnew_nopar:Npx . 4640. . . . . 1431. . 1588 \cs_gnew_eq:Nc . 14881. . 1350 \cs_gset:Npn . . . . 1275. . . 1239. . . 1508. . . 7829 \cs_if_eq:NcF . 845. . 1594 \cs_gundefine:N . . . 1253. . . . 1111. . . . . 1444 \cs_if_eq_p:cN . . 9278. . 1259 \cs_gset_protected_nopar:Nx . . 15. . 1431 \cs_if_eq:NNF . 3736. 1570 \cs_gnew:Npx . . . 2153. . . . . . . . . . . . . . . . . . . . . . . . . 1236. . . . . . . . 1593 \cs_if_eq:ccF . . . . . . . 1504. . . . . 1575 \cs_gset:cn . . . . . . . . . . . . 1589 \cs_gnew_eq:NN . . . . . . . 14723.Index 14280. . 1440 \cs_if_eq_p:NN . . . . . 1572 \cs_gnew_protected:Npx . . . . . . . . . . 14856. . . . . 8476. . . . . . . 4713. . . . 4961. . 3729. . . 2111. . . 14824. 1506. . . 1350 \cs_gset_protected:Npn . 1246 \cs_gset_nopar:cpx . . . . . . . . 1442 \cs_if_eq:NcTF . . 7594 \cs_gset_protected:Npx 843. . 1431. 4693. 14815. . 1268. . . . 14882. . . . . . 1445 \cs_if_eq_p:cc . 1275. . . . 1265 \cs_gset_protected:cx . . . . . 2099. 14799. . . . . . . . . 1238. 5687. . . . . . . . . 1268. . . 11334 . . . 14905. . . . . . . 14. . 4604. . . . . . . . . . 1507. . . . . . . . . . . . . . . . 4717. . . 1582 \cs_gnew:Npn . 14486. . . . . 1584 \cs_gnew_protected:Npn . . . . . 1431. . . . . 1571 \cs_gnew_protected_nopar:Npx . 843. . . . 1579 \cs_gnew_protected_nopar:cpx . . . . . 12. . 1494. . . . . . . . . 4673. . . . 14906. . . . 1492. 14927. . . . . . . 1440. 1250. . 1587 \cs_gnew_nopar:cpn . . 1237. . . . . 14904. 1350 \cs_gset_protected:cn . . . 1439 \cs_if_eq:cNT . . 1447 \cs_if_eq:NNT . . . . . . . 854. . 14312. . 15127 \cs_gset:Nx . . 14430. 1499. . . . 12. . . . . 14355. . . . . . . 1250. . 15. . . . . 16. . . . 1580 \cs_gnew_protected:cpx . . . 843. . . . 14485. 21. 3513. . 1443. . . . . 14575. . 1441. . . . . 14488. . . . . 13. . . 1350 \cs_gset_protected_nopar:Npn . . . . . . . . . . . 4719 \cs_gset_nopar:Nx . . . 1431. 1272. . 843. 2113. 1510. . . . . . . . . . . 1871. 13. 3565. 3400. . . 4314. 2526. . . 2994. 2244. 2242. . . 3598. . 3716. . . 2248. . . 5118. 1982. 2365. 11153. 11098. . 787. 4952. 5120. . . . 4027. 3551. 3646. . . 1254. . 3449. 2601. . . 4303. 4025. . . 5839. 5146. 10348. . . 1828. . . 4639. . . 5477. . 3042. 3392. . . 1205 \cs_if_free:NTF 22. . 4944. . . 4312. 1952. 1756. 2290. . 1742. 4476. . 2351. 1851. . . 2288. . 1155 \cs_if_free:c . . 1250. 3863. . 6079. . . 3512. . 1749. 1532. 3682. . 3835. 1168. 3606. . 8909 \cs_if_exist:cTF . .Index \cs_if_exist:cF . 3765. . 1160. . 1770. 1158. 2319. 4236. . 5176. . . 10954. . 1631. . 5358. 11014. 9611. . . . 1099. . 4305. . 2182. 4928. 4276. . . 11514. 1633. 2306. 5576. 7557. . . 6. 8651 \cs_if_exist:cT . 3696. 1658. . . 1849. . . . 5385. 2323. 2068. . 3837. . 5116. . . 1099. 1170. . . 4546. . 12936 \cs_new:cpx . . 9108. 3600. . . 22. . . . . 1675. 8960. 8526. 3604. 5677. . . 4379. 1161 \cs_if_exist_use:NF . 9797. . . . 5395. 11148. . . 4023. . 3912. 2515. 2194. 5844. 3041. 1805. 4381. 2310. 12167. . 1835. . 3668. . 4481. . 9613 \cs_if_free_p:c . . 1687. 7581. 1567. . 3447. . 2887. 1578. . 1139 \cs_if_free:cT . 5459. . . 3902. . . . . . . . 3943. 3674. . . . 3596. 1156. 2294. . . . 1685. . 11. 1582 \cs_new:cx . . . 3264. 5837. . 3050. . 3623. . . 1226. 1250. . 5845. . 4231. 1524. . 2262. . 2300. 1724. 11143. 1693. 1691. . . 4824. . 1811. 6025. 1867. 5103. . 2254. 17. 5038. 1843. 17. . . 1707. . 4307. 1167 \cs_if_exist_use:cTF . 1554. 5074. . 2683. 2317. 5167. 5236. 5932. 2345. . . . 1155. . . . . 3426. . 3855. 1813. 1806. 2613. . 5009. 4484. . 2929. 2947. . 2318. . 1450. 5101. 5058. 1995. . 8966. 5004. . . 2231. 2360. 2174. 1159 \cs_if_exist_use:NTF . . 21. . . . . 6027. . 9295 \cs_if_exist_p:c . 1255. . . 2695. . 3702. . 1968. . . 4931. . . 8625. . . . 2315. . 2178. . . 2599. . . . . 2508. . 2701. . . . . . 1543. . . . 4088. 5245. . 4262. 4927. . . 3690. 4208. 811 \cs_meaning:N . 1537. . . 11032. 3938. 5451. 6752. 3587. . . 2065 \cs_if_free:cTF . . . 1638. 1155. 1155. 2296. . 1127 \cs_if_free_p:N . . . . . . 2689. . 3771. 1548. 3907. . 1677. 2321. . . . . 1099 \cs_if_exist_p:N . 5445. . . . 1700. . 2201. 3896. 4813. 4301. . 2316. 1973. 4014. 3156. 7563. 3843. . 3456. 3418. . 4925. . . . 16. 4872. 1878. 6527. 3751. . 2026. . 1635. . . 5151. 1865. . 1566. 724 1474. 5165. . 1165. 4002. . . . . 2192. . . . 13843 \cs_if_exist:NT 1490. 2281. . . 3602. 3576. 5290. . 5852. 1164. 2500. 4086. . 10399 \cs_if_exist_use:cT . 5134. 4764. 2832. 1325. 2250. 3993. 4004. . . 4999. . 6086. . 3084. 4052. 1157 \cs_if_exist_use:NT . . . . 9126 \cs_if_exist:NTF . . 1837. 4991. 1155. 1399 \cs_new:cpn . 1169 \cs_if_exist_use:cF . 5028. . . 1127. 1. . . 4144. . 3273. 11138. . 3252. 21. 2532. 5671. . . . . . . 1718. 3594. 3255. . 1664. . 1163 \cs_if_exist_use:N . . . 2236. . . . . 2302. . 5138. . 1833. 2292. 2293. . . . . 5110. . . 3750. . 5092. . . . . 4432. 3654. . 10420 \cs_if_exist:N . 3898. 4299. 5184. . . 1127 \cs_if_free:NF . 2308. . . . 1870. 4993. . 6073. 1470 \cs_new:cn . 2324. 11333 \cs_if_exist:NF . . . . . . 3803. 1763. . 5070. . . 5190. 1327. . . 1873. 3621. . . 3982. 1652. 1570. . . . . . 2267. 2320. . . 3972. 1830. 2598. 2494. 1127 \cs_meaning:c . 3980. . . . . 4297. . . 1702. . 1636. . . . 2235. . . 1634. 4936. 5153. 10271. 3059. 801. 2965. 6057. . . 1730. . 5012. . . 8271. 1099. . . . 3948. 1630. 5136. . 4926. 5026. . 1736. 1640. . . 808. 2275. . 3937. 4377. 4282. 5019. 5064. 789. 1127. 2298. 4043. 4473. . 5182. . . 2010. . 3034. 187. 2176. . . 9922. . . 4388. . . 1218. 8946. 1689. . . 2225. 3068. . . 1162. 2199. . 3582. . . . 2162. 1099 \cs_if_exist_use:c . 5050. 1712. 1557. 6066. 3544. 1350 \cs_new:Npn . . 2322. 11059. 5630. . 3662. 8356. 6134. 1501. . 3616. 4523. 1399 \cs_new:Nn . . 1869. 1166. . 5733. . . . . 2152. 5725. . 3917. 6152. 3991. . . 1832. 1254. 5790. 4264. . 7860 \cs_if_free:N . 2295. 3394. . 4254. . 3900. 1858. 2905. . . 2304. 2983. . . 6357. 2219. 3570. 11623. 6750. 1236. . . . 5360. 1632. 3434. . 4129. 2172. . 800. . . . . . . 1684. 1195. . 3015. . 5081. . 1818. 14460. 11391. 12284. 1276. 1350 \cs_new_eq:cc . 13462. 10397. 10626. 9768. 12413. 8301. 12460. 1268. 12123. 12124. 10479. 12043. 9795. 11724. 12244. 14530. 10038. . 15038. 13024. 13186. 11113. 6143. 11807. 13337. 11678. . 12454. . 13594. 15074. 12616. 12486. 9837. 12665. 13533. 9727. 10091. 12756. 9637. 1589 \cs_new_eq:NN . 9880. 12228. . . 11194. 11731. 11235. 10457. 12659. 10214. 10251. 11798. 8212. 15050. 12134. 12188. 13611. 9634. 14874. 11484. 12328. 11510. 13034. 10027. 9747. . 12748. . 15066. 1268. 15024. 13467. 13353. 1283. 9835. . 10262. 14816. 13905. 13629. 10833. 13593. 12414. 14825. 11306. . 11960. 12661. 10871. 11158. 7744. 9697. 9833. 12980. 10707. 13124. 10442. 13671. 13246. 11460. 14484. 14801. 12628. 12153. 11440. . 10329. 7742. 11658. 10468. 8953. 1268. 12003. 10910. 9660. 11205. 12434. 14455. 12795. 10342. 12208. 10823. 11446. 10966. 12194. 13893. 13468. 12797. 9878. 11819. 7833. 6377. 11217. 11775. 8292. 10494.Index 725 6250. 14818. 8291. 13107. 12536. 11565. 12317. 14505. 9737. 13216. 8251. 12719. 10809. 9829. 11701. 15. 14866. 9766. 11992. 10225. 9846. 13669. 11286. 13648. 11606. 14948. 9793. 10176. 11648. 9775. 10090. 11951. 9827. 12246. 13684. 8436. 10636. 15000. 13201. 12575. 14921. . 7858. 13086. 15058. 12453. 9777. 1281. 9684. 11525. 9428. 8236. 7743. 11011 \cs_new_eq:Nc . 13631. 12833. 12064. 11508. . 9779. 13523. 13698 \cs_new:Nx . 10434. 8227. 12508. 13081. 12242. 12399. 10546. 11763. . 13680. 12822. 11592. 12658. 1268. 8246. 11979. 11400. 10031. 13261. 14970. 12851. 9761. 10418. 12113. 12223. 11340. 13682. 13312. 10900. 12098. 10141. 11125. 13643. 9661. 14506. 10752. 12274. 11268. . 10410. . 11572. 12488. 7745. 12477. 11476. 11749. 15102. 13289. 13314. . 13470. . 13559. 8224. 9823. . 14441. . 12569. 10212. 15037. 11359. 11983. 11179. 12334. 9773. 11774. 12601. 1283. 12224. . 7988. 1001. 13091. 9682. 12105. 12133. 11069. 10030. . 11913. 10187. 10533. 10662. 10252. 12225. 11687. 11709. 13271. . 11836. . 10289. 13584. 11646. . 11249. 10538. 9667. 9638. 10977. 11418. 9659. 10114. 10646. 12657. 11616. 9845. 10081. . 12915. 11862. 9906. 11392. 12389. 9821. 12358. 11573. 10267. . 12835. 12215. 1574. 9825. 15087. 1255. 9633. 10243. 12081. 12570. 10503. 8699. 12899. . . 11364. 12867. 14526. 9791. 9639. 11717. 12824. 14431. 14527. 13664. 10489. 11560. . 11163. 13323. 13295. 9871. . 11891. 12189. 13156. 10583. 11814. 6415. 10028. 13469. 11168. . 13109. 8241. 10100. . . 10168. 10025. 8582. 11512. 12606. 1590 \cs_new_eq:cN . 14977. 13066. 11468. 14857. 12663. 14980. 14968. . 11981. 14849. 13302. 13417. 6153. 13363. 15019. 8970. 12729. 10026. 13638. 11535. 9831. 8687. 1282. 12143. 13093. 10885. 14424. 13686. 9760. . 8944. 9563. 12685. 11432. 14409. 10818. 14833. 10192. . 9673. 11412. 9707. 13379. . 9696. 10544. . 9717. 12030. 6409. 10230. 13335. 10520. 12268. . 9887. 14807. 10842. 11856. 14499. 1588. 11282. 11452. 12175. 12522. 11872. . 1281. . 13626. 10786. 11304. 12593. 11608. 9862. 10611. 10157. 12236. 12883. 11534. 15116 \cs_new:Npx 1226. 12382. 13291. 9750. . 12445. 12931. 10553. 10029. 10150. 12304. 13525. 12375. 9636. 11781. 12588. 13045. 15013. 14477. 10999. 1282. 10723. 13510. 12468. 11739. 10996. 12294. 7746. . 12348. 13171. . 10375. 11599. 13008. 10316. 10779. . 13775. 13431. 6371. 15073. 1237. 12806. 12713. 10079. 12694. . 10616. 12808. 13601. 10905. 12333. 9826. 10355. 12961. 13782. 1478. 14401. 11884. 8296. 15082. 14439. 12056. 12679. 12425. 11424. 15036. 10835. . 11838. 7747. 13483. . 10332. 11805. 10763. 11044. 12370. 9635. 10734. 12556. 8567. 13132. 9695. 10804. 13231. 12195. 11581. 10130. 9556. 11837. . 9605. 4167. 1445. . 3340. 3320. 2213. 3146. 13889. 1570. 1779. 5345. 3302. 6640. 13726. 5782. 5749. . 3349. 10166. 3354. 6529. . 14056 \cs_new_nopar:cn . . 9916. 3314. 3321. 5330. 3313. 1446. . . 1234. 5370. 1580. 5756. 2705. 1582. . 5981. 4632. . 3077. 3362. 6557. 3290. 3296. 6483. 3311. 5331. 4569. 2212. 13633. 2107. 5746. 3134. 5368. 1597. 5458. 5409. 4943. . 3543. 9554. 10834. 1439. 3359. 4119. 3335. 3083. 5415. 4090. 3081. 2472. 1782. 3333. 14012. . 4161. 6478. 5735. 4480. 3331. 5403. 5413. 1573. 14010. 9917. 9322. 10944. . 1226. . 6482. 5801. 3347. 1587. 5760. 5350. 5340. 5418. 9622. 5747. 6222. 8345. 5810. 2468. 2477. . 1444. . 3926. 5408. 4168. 4181. 3326. . 6701. 3385. . 1350 \cs_new_nopar:Npn . 10113. 3372. 12226. 6436. 1583. 5808. 1556. 4118. . 3166. 6906. . 6641. 6707. . 3934. 5332. 1861. 8926. . 2217. 5809. 2056. . 5175. 3343. 13. 9292. 3361. 6230. 8924. 2092. 13596. 5968. 1569. 3923. 6904. 6647. 5812. 1576. 4630. 1602. . 9220. 8310. 1437. 2707. 5805. 3082. 5806. . 1443. 3300. . 3342. 2111. 6183. 1248. 6184. 1593. . 5351. . 5335. 3312. 6695. 1796. 3369. 6228. 1335. 6697. . . 5669. 3924. 5402. . 10288. . 10914. 5813. 5750. 6642. 2473. 1248. 4483. 6698. 12015 \cs_new_nopar:cpx . 5754. 3287. 1617. 1601. . 6558. 9031. 3930. 5977. 6224. . 1242. 9603. . 6545. 5353. 6204. 5542. 1565. 13725. 2335. 5811. 6531. 7543. 4550. . 3336. 15109 \cs_new_nopar:Npx . 6438. 2211. 3364.Index 726 1479. 3493. 5333. 5976. . 4568. 5336. . 1226. 3373. 4565. 4626. 5743. 5975. 5972. 5817. 9392. 6908. 3936. 1794. 3307. 2470. 1249. 1600. 5742. 5979. 11. 2210. 6231. . 5820. 1436. 3144. 3489. 9032. 5814. . 1489. . 1581. 3308. . . 1579. . 5366. 1785. . 5807. 9035. 1438. 1911 . 1588. 5416. 5329. 3339. . 6693. 2110. 1781. 10409. . 6907. 8311. 3384. 1441. . . 1482. 4988. 2469. . 5419. 5357. 8934. 3323. 5783. 5966. 3368. 5971. 6175. 6643. 5341. 3285. 6645. 1571. 11618 \cs_new_nopar:cx . 1793. . 6646. 6205. 3925. 6132. 1589. 5166. 14011. 5334. 6694. 5753. 1797. 6201. . 3350. 1590. . 5406. . . 2112. 12227. 5816. 6485. 3284. 6199. 5748. 3322. 6225. 6644. 1795. 5978. 8312. 2216. 11905. . 5967. 2594. 3387. 5758. 3351. 4628. 1784. 4089. 5740. 1569. 5412. 3299. 6556. 3355. 1249. 6130. 5349. 4950. 5343. 3142. 1440. 1487. 10167. 5821. . . . 4398. . 3079. . 5778. 1620. 1512. 5787. 1860. 10036. 5737. . 5974. 6905. 1573. 5417. 2106. 6655. 6226. 3358. 3383. 1480. 5970. . 1399 \cs_new_nopar:Nn . 5356. 3303. 3352. . 5818. . 5346. 4986. 1572. 1483. 5420. 3386. 8346. 3325. 3291. 3371. 3932. 3367. . . . 5738. . 6221. 10341. 6232. 5751. 9377. 9391. 5741. 2108. 13679. 6696. 2476. . 3344. . 2113. . 6223. 3338. 6227. 4320. 14762. 1235. 3293. . 5804. 5339. . 3341. 6200. 1584. 1614. 3370. 5757. 5736. 6909. . 1486. 6179. 3360. 4990. . 3931. 14764. 6530. . 13528. 9756. 5410. 1484. 4396. 3345. 4171. . 13677. 3078. 2215. 5759. 6218. 6480. 5819. 5404. 6235. 5411. 9918. 1786. 9209. 6233. 9623. . 6234. 13714. 13890. . 6176. 3327. 6700. 1778. 5973. 4631. 4629. 4117. 2706. 6481. . . 2333. . . 2214. 1442. . 5457. 5344. 5745. 1594. 4488. 9323. 6461. 5752. 4478. 5367. . 3332. 5815. 2471. 3294. 8314. 4814. 9030. 6219. . 2478. . . 1616. 1555. 8935. 1577. 3353. 5667. 8313. 10926. 1783. . . . 5369. 8307. 9335. 5407. 1242. 5414. 6479. 3363. . 3283. 4122. 5980. 4182. 9919. 6180. 3337. 1862. 5456. . 3317. 9607. 6484. 1575. 1578. 6220. 5744. 3929. 11532. 3927. . 1488. 4625. 1581. 4627. 7662. 1780. 1485. 4183. 3629. 2109. 5755. 4548. 3329. . . 6447. . 3928. 1399 \cs_new_nopar:cpn . 6229. 1646. 5969. 3935. 5779. 5455. 1577. . 5352. 5342. 14013. 1863. . 5405. 3297. 3922. 3365. 6656. 5739. . 3324. 1574. 4819. 5786. 13473. 6699. 6448. 6544. 3334. 6217. . 1615. 5363. 3286. . 3933. 1481. 1447. 3366. 3502. 2649. 4621. 8002. 7203. 8678. 9612. 8797. 5876. 8032 \cs_new_protected:cx . 4595. 8773. 8550. 8759. 1358. 2699. 8753. 2100. 8825. 9270. 9616. 8354. 13716. 2465. 2681. . . 8265. 6496. 9340. 9974. 7272. 6588. 8827. 2116. 8807. 4615. 4192. 5826. 7260. 8902. 6920. 5803. 1284. 8661. 8870. 5463. 4426. . 5469. 2677. 4434. . 7767. 8805. . 6672. 7669. 6511. 2703. 4212. 7248. 2635. 6503. 4514. 8821. 1399 \cs_new_protected:cpn . 5889. 4199. 1262. 3744. 9222. 6327. 2661. 8473. 8781. 4422. 7989. 3528. 6659. 1268. . 6682. . 4538. . . 2633. 8418. 4633. 6117. 2675. . 6623. 5694. 7465. 7775. 2665. 2487. 4527. 4704. 7773. 6100. 2094. 4452. 4662. 13730. . 6347. 6275. 1267. 4619. 8394. 8775. 7788. 6003. 6624. 2132. 8533. 6636. 6554. 5706. . 8013. 8269. 8835 \cs_new_protected:cpx . 6968. 2114. 5713. . 4718. 7784. 8811. 9220. 8540. . 4221. 5767. 6661. 2705. 5592. 8771. 1465. 4708. 6653. 3500. 4400. 8755. 8623. 3506. 6704. 7889. 9521. 6159. 4716. 2623. 2619. . 2659. 7963. 5550. 9363. 2657. 8030. 5999. 9335. 6552. 2625. 1276. 3496. 4223. . 6187. 4530. 9284. 5425. 8256. 2631. 4680. 9427. 8793. 8283. 7621. 6625. 6855. 9618. 5868. 2585. 8739. 1584. 6523. 7612. . 2679. 6650. 7991. 6515. . 2621. . 4672. 4215. 4423. 6257. 7769. 2611. 1448. 5987. 1399 \cs_new_protected:Nn . . 9940. 8321. 2653. 8817. . 7208. 4226. 8649. 7584. 13713. 7907. 11. 4682. 9173. 4635. 9096. 4541. 2693. 2048. 1572. 2096. 7387. 9074. 5866. 5499. 7028. . 8015. 8281. 6577. 9641. 6087. 7610. 6762. 8727. 7119. 6660. 1286. 8851. 5479. 6665. 8803. 1350 \cs_new_protected:Npn . 7995. . 6934. 8323. . 5030. 8523. 9904. 5906.Index \cs_new_nopar:Nx . 3466. 4536. 5461. 6663. 7703. 8694. 6505. 9610. 8017. 8444. 6517. 2639. 2374. 8829. 5983. 6963. 727 4828. 7227. 7628. 1580. 13733. 6780. . 8757. 9104. . 6550. 13. 4439. 9154. 9309. 4533. 4684. . 2647. 8791. 1917. . 3514. 5585. 4552. 9337. 5495. . 8446. 5689. 8358. . 10000. 2464. 7332. 4686. . . 4788. 3132. 4670. 4826. 8319. 2643. 3516. 8011. 1266. 8789. 4606. 1350 \cs_new_protected:cn . 9311. 4958. 9247. 4774. 8865. 3116. 8408. 6838. . 2061. 9476. . 5483. 4710. 5297. 7686. 7222. . 8833. 10010. 7727. 8843. . . 5583. 8317. 7605. 5140. 7237. 5142. 8747. 7184. . 8763. . 4512. 6041. 6667. 6537. 2669. 8733. 7174. 6164. 4580. 7757. 7944. 8783. . 2022. 4688. 8815. 4506. 7416. 6597. 8637. 5985. 8666. . 9599. 2141. 6452. 4690. 1240. 9264. 5684. 6579. 8711. 5613. 4185. 6634. 9225. 3459. 6535. 6941. 4601. 8518. 6910. 6242. 6240. 7473. 4218. 9381. 3497. 6808. . 6521. 2098. 1902. . . 8853. 8813. 6284. . 7733. 4744. 4442. 3732. 4714. 4706. 6106. 7933. . 6927. 6425. 6676. 6188. 8028. 10008. 4204. 4409. 2667. 2687. 8765. 1823. 5558. 4519. 2655. . 4436. 4970. 6688. 1262. 7497. 7156. 4499. 3509. 4450. 8318. 2671. 4978. 4834. . 4668. 3095. 8513. . 9378. 3526. 8672. 8801. 2617. 7868. 9171. 7013. 4613. 2629. 8267. 9137. 8743. 1363. 6979. 6594. . 6678. 4517. 4694. 6889. 6122. 8504. 8795. 6630. 8749. 4490. 4228. 9357. 8787. 1337. . 5898. 2673. 8779. 5951. 9178. 9920. 6609. 6539. 9147. 8322. 2615. 3130. . 6267. 8320. 8819. 6670. . 5921. 1884. 8565. . 2697. 4091. 9384. 6628. . 3538. 4967. 6001. 7379. 4202. 4772. 2092. 4664. 3089. 7827. 9094. . 8761. . 5032. . 3114. 6648. 6791. . 8769. 8831. . 4666. 5913. 2637. 8506. 8785. 5497. 6440. 2641. . . . 8438. 8777. 8019. 4416. 2645. 2685. 7619. 2663. 8681. 6251. 4428. 8799. 13720. 7902. 8263. 2651. 4447. 6651. 7771. 4525. . 5325. 1266. 8823. . 1226. 8467. 6509. . 1923. 8745. 1932. 8607. 5471. . 6684. 4210. 7758. 4445. 4832. 7993. 5307. . 4198. . 1647. 5568. 8875. . 2691. 6548. 8767. 5603. 5481. 9237. 8841. 4712. . 7786. 13729. 5314. 8689. . 1915. . 9434. 2627. . 3112. 4543. 13718. 6771. 7106. 6952. 4692. . 7681. 7946. . . . 5824. 15157. 893. 1864. 2383. 13868. 857. 2052. . . . 13786. 13742. 15161 \cs_new_protected:Npx . . 11. 1159. 891. 14213. 1226. . 1082. 7544. 1272. 3175. 14768. 14794. 1250. . 7614. 5615. 5609. 3120. . 3389. 832. 14222. . 9390. 895. 1350. 1399 \cs_new_protected_nopar:Nn . . 885. . . 14. 14778. 876. . 14259. 1801. . . 6325. 4572. . 1576 \cs_new_protected:Nx . 4343. 858. 13739. 3118. 13830. 3540. 2445. 1399 \cs_set_nopar:cpn . . . 13850. . . . . 3085. 2108. . 1250. . 3530. . 14917. . 1050. . 1239. 4238. 1165. . . . 13784. 3520. 9509. 14709. 1242. . 868. 4740. . . . . 1790. 15114. 14942. 1575. 1268. . 3186. 5887. 1269. 14766. 13948. . . 9994. 13798. . 8664. 1283. 13810. . 4349. . 1352. . 14192. 1399 \cs_set_nopar:Nn . 1261. 14124. . . . . 999. 1097. . . 15128 \cs_set_eq:NwN . . 1268. 1399 \cs_set:cpn . . . 1074. . . 13807. . . 2411. . 889. 883. 4321. 12. 1270. . 1268. . . . 1243. . 1350 \cs_set_nopar:Npn . 1800. 9960. 14465. . 13898. 14909. 2107. 1606. 878. 5323. 3194 \cs_new_protected_nopar:cx . . 2109. 4627 \cs_set_eq:NN . . . 5885. 874. 4246. . 2053. 2437. 872. 13743. . 14463. . 6345. . 833. 13987. 14938. 1251. 8597. . 14893. 13873. . 4912. 14356. . . 836. 13835. 13809. . . . . 829. 1268. . . 14313. 4628 \cs_set_eq:cN 1268. 1060. . 840. . 13. 14753. . 2431. . 9375. . 829. . 7616. . .Index 13735. . . 1476. 1250. 1350 \cs_new_protected_nopar:cn . 14912. 5581. 14242. 14600. 831. 1792. 4782. . . 1092. 10013 \cs_set:cpx . 14461. 1571. 870. . 8751. 1256. . 4797. 1799. . . 9483. . 1399 \cs_new_protected_nopar:cpn . . 6005. 5909. . . 14631. . 14776. . 886. 14640. . 8809. 4625. . 14724. . . . 4976. 14914. . . 1281. 9951. 8837. . 865. 1270. 2461. 9446. 8839 \cs_new_protected_nopar:cpx . 1242. . . 7888. . 1803. 14168. 1798. 4911. . . 1244 . 6887. . 13808. 1350 \cs_set_eq:cc . 4574. 9998. . . . . 887. 14594. 728 14910. 13909. . 2402. . . 14657. . . 1789. 1804. 1250. . 14683. 1905. 1157. . 1260. . 14770. 1346. . 7942. 9977. . 14883. . 14670. . . . 14940. 1269. 2460. 3518. . . 2441. 2387. . 9943. . 4918. 1788. 1073. 13804. . 1191. . 13805. . 1163. . . . 14146. 6343. 884. . 1161. . . . 2443. 13758. . . . . . 14731. 4365. . 1251. 13792 \cs_new_protected_nopar:Nx . . 2435. . 3097. 3. 7554. 10004. 14930. . . 15168. 866. . 4329. 1909. 3545. 4778. . 1350 \cs_new_protected_nopar:Npn . . 5423. . . . 2337. 14090. . 6244. 879. . 890. . 14541. . . 9536. . 1271. 10002. 1271. . 1610. 2106. 3197. . 16. 4742. . 15124 \cs_set:Npx . 1802. 5579. . 5036. 3192. . 5616. . 9905 \cs_set_eq:Nc . . 2052. . 4738. . 1272. 1605. 864. 1607. 829. 1350 \cs_set:cn . . . 3087. 13852. 9444. . 9528. 5628. . 2433. 15140. 1090. . 5421. 4910. . . 1401. 14737. 13740. 4337. . . 14612. . 1787. 15172 \cs_new_protected_nopar:Npx . . . . 9183. 1169. 871. 9608. 5822. . 7550. . . . . 835. 13917. 1583. . 4357. 9970. 9985. 837. . . 1226. 14281. 14783. 9493. . 4371. . . . 13847. 13854. . 1226. 14746. . 9936. 1245 \cs_set_nopar:cx . . 15170. . 1399 \cs_set:Nn . . . 1350 \cs_set:Npn . 9606. 11. 2766. . 1055. . 9938. . 1270. 2393. 881. . 14695. . . 1155. 888. . . 2379. 8859. 1269. . 882. 14932. 13848. 1777. 1226. . . . . . 1279. 9972. . . 1260. 13820. 833. . . 13806. . . 13841. 14916. 3093. 1242. 14898. . 13749. 13958. . 2097. 1045. 14888. 14. . . 6853. . 14588. 1273. 9282. 14157. 1241. 1579. . 2375. 14078. 5874. 4626. 4578. . 1267. . . . . 9996. . 1271. 1791. 4776. 1920. 13821. 4576. 5700. . . 1905. 2449. . 14135. 877. 9968. 1067. 1244 \cs_set_nopar:cpx . 14489. 1095. 9388. 2095. . 9548. . . 13741. . . . 15125 \cs_set:Nx . 9445. 5911. 5611. 829. 873. . 14796. . . 6043. 880. . 1256. 14651. 4780. 3410. 14576. . 9542. 3725. 6323. 2439. 10006. 14310. . 892. 3402. 1261. . 8701. 1282. 13849. . . 831. 1608. 1457. 5872. 3532. . 1238. 1611 \cs_set_nopar:cn . 9934. . 875. . . . . 1399. 1167. . 14179. 1274. . . 867. 14662. 14928. . 8857. 8669 \cs_set:cx . . . . 869. 14919. . 1348. 13785. . . 2420. . 6591. 1275. . 829. . 414 \currentgrouplevel . . . . . . . 298. 855. . . . . 912. . 1649. . . . . . 14385 \dim_compare:nNnTF . . 1228. . . . 4221. . . . . . . . . 8036. 14. 9441. . . . . 4351. 14321. . . . . 4340 \dim_compare:nTF . . 13940. . 8367. . 13968. . 13818. . 4224 \dim_case:nnn . . . . . 834. . 8326. 4687.. 1256. . . . . . . . . 4266. . 4231. . . . . 159. 4681.default:n . . 79. . 8319. 1284. . . . . . . 33. 1825. . . 7262. . 4134. . . . . 1086. 177. . 8363. 4316. . . 36. . 1245. . . . . . . 4375 . . . 152 . . 8000. . 5530. 6866. 298. . . . . . 4135. . . 221. . 431 \delimiterfactor . . 208. . . 845. . 33. . . 78. . 2465. 841. . 36. . 9439. 196. . 910. . . 1173. . . . . 69. . . . 265. . 667 663 662 664 D dd . . 7061. . . . . . . . . . . 4465. . . 1263. 4705. . . . . 1014. 9389. . . . 3121. . . . . . 7130. . . . . . . 208. . . . . . 8318. . . 10269. . . . . 13996 \cs_set_protected:Npx . . . . . . 8369 \cs_set_protected:cx . 289. 55. . . . . . . 73. . . 16. . 296.. . 916. . . . . . . . . . . . . . . 192. . . . . 138. . . 3099. 1459. . . . 7250. 140. . 10964. .. . . 7068. . . . . . . . . 4271 \dim_compare:nF . . . 1477. . . . . 4. . 1316. . . 291. 205. . . 152. . 197. . . . . 1350 \cs_set_protected_nopar:cn . 899. 7564. . . . . . . . . 4374 \dim_compare:nNnT . . . 211. . . . 935. . 1187. 8323 \detokenize . . . . . . . . . 1257. . . . . . . 14. . 829. . 8971 \cs_show:N . . . . . . 607 \delcode . . . 4565 \dim_compare:n . . 1399 \cs_set_protected:cpn . . . . . . . . . . 950. 3122. . . 135. 479 \deprecated . . . . . . . . . . . 9392 \cs_undefine:c . . . 12. . . . . 1399 \cs_set_protected_nopar:Nn . . . . . . . . . . 839. . . 296. . 7713. 1028. 4192. . 1171. . . 918. . . . . 4707. . 9078. 321 . . . . . . . . . . 4321. . . . . 4266 \dim_const:cn . . 1262. . . . . . 7875 \cs_set_protected_nopar:Nx . . . . 183. . . . . . 901. . 1286. . . 291. . 4667. . . . . . . . . . . . 220. . . . 80. . 830. . 841. . . 993. 8037. 8321. 7034. . . . . 8361 \cs_set_protected_nopar:cpx . . . 4192. . 13982. . 842. . 79. . 1203. . . . . . 905. . . . . . . 7037. . . . . . 4346 \dim_compare:nNn . . . . 77. 8317. . . . . 4665. . . . 4709. . . . . 77. . 310. .. . 7137. . 480 \delimitershortfall . . 1263 \cs_set_protected:Nx . . . . . . 1257 \cs_set_protected_nopar:cx . . . . . 8357 \cs_set_protected:cpx . 1350 \cs_set_protected:cn . . . 10912. 923. . . . . . . . . .. . . . 247. . . . 221. 3104. 1216. . 861. . . . 1067. . . 164.default:V . . . . . . . 4359. . 4403 \dim_do_until:nn . 4402. . . . . . . 8320. . . . . . . . . 9440. . . . . . 666 729 \currentgrouptype \currentifbranch \currentiflevel . 4140 \day . . . 829. . 13931. . . . 1465. . 211. . . 983. . . \currentiftype . . . 4197. . . . . . . . . . 4231. 829. . 1295. . . 138. . . 13973. . . . . . 11067. .. . . . 1189. . . . . . . . . 1594 \cs_undefine:N . . . 897. . . . 4271 \dim_compare_p:n . 1399 \cs_set_protected_nopar:cpn . 1459.. . .. . 4271 \dim_compare_p:nNn . . . 14378 \dim_compare:nT . . . 556 \def . 1350 \cs_set_protected:Npn . . . . 152 \defaulthyphenchar . . . . . . . 859. . . . . . . . . . . . . 1476. 16. 4581. . . 191. . . . . . . 1002. 4307.Index \cs_set_nopar:Npx . 4347 \dim_do_until:nNnn . 7125. . . . . . 14364. . . . . . 847. . . 1000. . . . . . . . . . . . . . . 122. 9442 \cs_set_nopar:Nx . . 8365. . . . 622 \ddagger . . . . . . . 4368. 177. 998. . . 4711. 4349.. 4221. 7998. . . . . 81. . . . 4192 \dim_const:Nn . . 8038 \csname 14. . . . . 210. . . . . . 914. . . . . . 78. 174. . . . . . . 251. . . 853. 4307. . 4371. 4323. . . . . 1350 \cs_set_protected_nopar:Npn 12. . . . 1262. 4663. . 57. 9438. 4266 \dim_compare:nNnF . . . . . . 2464. . . . . 1224. 606 \defaultskewchar . . 4685. . . . 1262. . . . . 4343. 838. . . . . . . 1284. 14215 \dim_add:cn . 654 \dim_abs:n . . 280. 1214. 11012. . 174. 198. 1256. . 988. . . 637 \delimiter . . . 1399 \cs_set_protected:Nn . . . . . . . . . 9387. . . . 1256. . 4221 \dim_add:Nn . . 8322. . . . . . . . 7754. 14338. . . . . . . 63. . . . . . . 1284. 1593. 6843. . 1175. . 5300 \cs_to_str:N . 1350 \cs_show:c . . . .. 7052. . . 903. . . . . . . . 135. 967. 849. . 835. 2349. . 180 \dagger . . 18. . . 4223. . 7046. . . . . . . . 7559. . . . 839. 1256. 122. 183. . . . . 1067. . 4331. . 1262. . . . . 289. 829. . . 1193. 13983 \cs_set_protected_nopar:Npx . . . . . . . .. . 199. . . 76. 4141 \deadcycles . . . . 4683. 837. 7031. 851. 10924. 180 nd . 7049. . . . . . . . . . 80. . . 4207 \dim_if_exist:c . . . . . . 4198 \dim_gzero:N . 4203. 4210. . . 14614. . . . . . . . . . . 77. 7114. . 4241. . .dim_gset:N . 14267. . . 4208 \dim_if_exist:N . 7322. . . 4349. 4378. . . 4399 \dim_show:n . 4567. . . . . 14718. . . 14645. 77. . . . . . . 4321. . 14274. . . . . . . . 14130. . 4574. . . 13643. . . 14633. 10947. . 6747. . 14094. . . 14205. 7210. . . 14728 \dim_set_eq:cc . 4321. 14392. . 4329. . . . . . 14072. . . 7090. . . . . . . . . . 4234. . . . 14618. 14607. 4362 \dim_use:c . 14069. 76. . . . . 4202. . . . 14199. . . . 77. . . . 14247. . . 4208 \dim_if_exist_p:N . . . . . 4341 \dim_do_while:nNnn . . . . 4210. . 4262. 6971. . 7233. 4184 \dim_new:N . . 14735. . . 6977. . . . 81. . 14137. . . 14197. . . 4396. . . . . . . . 4208 \dim_if_exist:NTF . 4357. 14141. . . . . . 7053. . 14729. . 14234. 4398 \dim_show:N . . . . 152 \dim_set:cn . . 14644. . 7033. 7070. . . 6977. . . 4577. 152 \dim_set:Nn . 6988. . 152 \dim_gset:cn . . 4571 \dim_set_max:Nn . . . 6860. 4231. . . 4404. .dim_gset:c . . 14540. 4398. 14227. . 4205. 4226. . . . 14714. 7234. 4198 .dim_set:c . . 4349. . . .dim_set:N . . . . 7128. . . . 4213. . 7320. . 14726. 4205 \dim_gzero_new:c . 14272. . . 4217. 4215 \dim_set_eq:NN . 4384. . . . . . . . 4584 \dim_show:c . . 82. 14215. . . 6744. . 6740. . . . . 4310. . 14608. . . . . 4228. 14131. . . . . 6947. . . 4221. . . . . . . . . . . . . . 4295. 14622. 14584. . . 7211. . . 77. . . . . . . . 14653. . . . . . 14592. . . . 14682 \dim_ratio:nn . . . 4242. 152 \dim_gset:Nn . . 4225 . . . . . . . . . 4571 \dim_set_min:Nn . . 4203. 14659. . . . 7478. 4407. 4185. . 14642. . . . 4400. . . . . . . 77. . . . 4365. 4571. 14634. . . 81. 7008. 4571 \dim_gset_min:Nn . 6973. . 14073. 14689. 4569 \dim_gadd:cn . . . . 78. 14598. . . . . . . . 14648. . . . . 4571. 4208 \dim_if_exist_p:c . . . . . . . 4571. . 4401. . . . . . . 4238. . 4337. 14636. 6878. . . . 4240. 4248. 4377. . 14076. . 4215 \dim_gset_eq:NN 77. . . 4575. . . . . . . . . 7477. 14586. 7083. 7078. . . . . . . . . 4262 . . 4321. . . . . 14233. . 4572. . 14252. 14681. . 4579 \dim_gset_eq:cc . . . . . . . . . . . . 14538. 4274. 4567. 14536. 14093. . 4215 \dim_gset_eq:Nc . . . . . . 14716. . 4406. . 6816. . . . . 4212. 7089. . . 4191. . . . 4210 730 . . . . . 6958. . 7321. . . . . 14229. 6718. 4583 \dim_gset_min:cn . . . 4218. . 4221 \dim_gadd:Nn . 14216. . . . 14142. . . . 14579. . . . . 4573. . . 6863 \dim_set_max:cn . 14674. . . . . 4195. . . 14266. 4230 \dim_gzero:c . 4215. . . 6746. . . . . 4184. . 76. . . 7188. . . . 14675. . . . 80. . 7076. 4228. . . . . . . 6975. 14686. . . . . . . . . . . 7531. . . . . . 76. . . . . . . . 4578. . 4208 \dim_max:nn . . . . . . . . 4221 \dim_sub:Nn . 4214. . 14075. . . . . . . 14660 \dim_new:c . . . . . 4246. 4216. . 4400 \dim_sub:cn . . 6983. . . . . . . 14071. 77. . 77. 6817. 180. . . . . . 14666. . . . . . . . 4369 \dim_eval:n . 4215. . . . . . . 77. . . . 4209 \dim_if_exist:cTF . 14074. . . . 14218. 4219. . . 7088. . . . 4321. . . . 4576. . . 4223. 14646. . 4250. . 14198. . . . . . 7190. 14757 \dim_eval:w . . . . 4221. 10946. . . 4202 \dim_gzero_new:N . . . . 14667. . . 4349. 4249. 7476. 4405. 7038. . . . . . . 14609. 4571. . . . 14635. . . 81. . . . . . . 14371. . . . . . . . 14626. 14750. . 14619. . . . . . . . . . . . . 6741. . 14647. . . 4377. . 4571 \dim_gset_max:Nn . 4199. . . 7533. 14228. . 7218. 7108. 7091. . 76. 6830. . . . . 14270. 7001. . . . . . . . 14537. . 82. 7192. . . . 76. . . 6745. 6994. . . . . 14742 \dim_while_do:nn . 4396. . 4326 \dim_while_do:nNnn . . . 4210 . 14248. . . 4568 \dim_eval_end: . . . . 7112. . 4221. . 6862. 4194. 4334 \dim_until_do:nNnn . 7532. 14126. 7424. 7063. . . . 82. . . . . 14070. . . 7187. . . 14202. . . . . . . .Index \dim_do_while:nn . . 4215 \dim_set_eq:Nc . . 14092. . . 4354 \dim_zero:c . 14797 \dim_until_do:nn . . 4215. . . . . . . . 14582. 81. 14649 \dim_min:nn . 80. . . . . . 14581. 4215 \dim_gset_eq:cN . . 7480. . . . 14268. . . . 81. . 14249. . . . . . 4212. . . 14727. . 4231. . 14643. . . . . 4198. 4221 \dim_gsub:Nn . . . 7113. . 4582 \dim_set_min:cn . . . . . 6814. 4220 \dim_gset_max:cn . . 4396 \dim_use:N . . . 14795. . . . 7323. . 13643. . . . . 4215 \dim_set_eq:cN . . . 4205. . . . . . 14206. . . . . . . 7115. 14539. 4204. 4398. . . . . 4585 \dim_gsub:cn . . 4397. . 4349. . 4210. . 7425. 7048. 14627. . . . 4229 \dim_to_fp:n . 4201. . . 395 \errmessage . 10878. . 1434. 9842. . . . . . . . . . . . . . 13983 \endcsname 14. 2326. 11922. 11173. 1143. . . 3893. . . 11131. . . 10981. 183. 10474. 5917. 3063. 2914. . . . . . 2551. . . 1958. . . 2973. . 1670. 13266. . . . 110. . 5249. 3612. . . . . . . . . . . . 618 E \E . 4199. 194. 13227. 10239. 2892. . 12768. 289. . 13017. . . . . 2017. . 298. . . . 13164. 13657. . 628 \dimendef . . . . . . 4887. . 9567. . . . 10746. 11844. . . . 6572. . . . . . 429 \endR . 1320. . 13013. . . . 731 9857. 5902. . . . 2504. . 3585. . . 14250. . . 11695. . . 3161. 1517. . 6560. . . . . . . . 2952. . . . 121. . 3152. 10668. . . . 13098. . . . . 5939. 91. . . . 4258. 10133. . . 635 \dump . . . 2955. 12775. 11296. 105. . . . 138. 296. . . . . . . 1121. . 13197. 9687. 10528. 221. . . . 1311. . 13426. . . 13778. . 13129. . . . 2917. 13283. 10700. 11500. . . . . 444 \displaywidowpenalties . . . 10447. 10235. 4306. . . . . . 12128. 2124. 173. 174. 11518. 12739. . 2158. 4461. . . . . . . . . . 171. . . . 13151. . 5241. 12975. . . 13137. . 12362. . 11275. 2520. 11376. . . 10299. . 2791. 3642. . 2758. 1956. . . 1528. . . 415 \endgroup . 704 \eqno . . . . . . . . . 10850. 11229. . . . . . 2850. . 11640. 11866. . 188. 13161. . . . 10984. . . . . . 5281. . . . 12953. 7025. 2748. . . 13783. . . 63. 122. 4202 \dim_zero_new:N . . 214. . 13073. . . . . . . . . . . . . . 106. . . . . . . . 1149. 76. 124. 5225. 10295. . . 15153 \emergencystretch . . 2934. 11259. . . . . . 10383. 87. 4903. 3138. 1290. 375 \else: . . . . 702 \endlinechar . . . . . 9688. . . . . . . 10729. 457 \divide . . . 13652. . 10799. . . 10771. . . . . . 135. 12752. . . 11919. 197. . 10182. . . 1106. 1957. 4852. . . . 4200. . 10104. 76. 410 . 62. . 244. . . . 1115. . 3171. . 1131. . . 4202. . 9302. . 73. . . . 2460. . 12689. 12772. 68. . . 5202. . . . . . 11769. . 524 \dp . . 2763. 2816. . . . 11379. . . 13039. . . 11078. . . . 1103. . 192. . . . 10631. . . . . . . 64. . . . 2753. 11925. . . 4198. . . 11682. . 9677. . 10714. . . . . 4203. 14230. 466 \displaystyle . . 389 \ERROR . 10563. 11852. . . 11735. . . 7024. . .Index \dim_zero:N . 12552. 13619. . . 2187. 10200. 10303. . 11847. . . . 10629. 286. . 4279. . . . . 10688. 12610. . 9852. . . . 177. . 13070. . 11532. . . . . . . . . 10391. . . . 10515. . . . . . . . 208. 4237. . 10451. . . . . 456 \displaylimits . 134. 12700. 2564. . 10605. . 2937. 10573. . 10854. 11243. 396 \errorstopmode . . 10463. . . 5259. . . 199. . . . . . . . . 10365. . 9867. 3072. 2895. 9721. 15136 sec . 4864. 2461 \errorcontextlines . . . 5554. . . . . . . . 13182. . . . . . . 12353. 11385. . . . . . . 11669. . . 13. 11396. 11826. . . . 13257. . 4269. . 6381. 769. . 293. . . . . 9785. . 1906. . . . 971. . 11355. . . . . . 13515. . . . 413 \EndCatcodeRegime . . . . 179 \else . . . . . 10484. . . . . . . . 681 \directlua . 14095. 179 \edef . . . 10682. 4877. . 12060. . . 2543. 10860. . 2811. . 10718. 348 \endinput . . 5563. 179. 11184. . . . 2332. 3634. . . 3046. 11490. . . . 12181. 2014. 1331. . 11119. 694 \displaywidowpenalty . 13101. . . 2970. 2776. 34. . 12528. . . . . . 72. . . 13615. 11004. 2328. 10621. . 12517. . 9711. . . . . . 1522. 12129. . . . . . . 13608. 11901. . 2801. 3438. . 6562. . . 1134. . . . 2806. . . 334 \doublehyphendemerits . . . . . . 9912. . . 3181. . . . . . . 11549. 11789. . 12429. . . . 9686. . 13142. . 10758. 24. . 449 \errhelp . . . . . 4206 \dimen . 3055. 10693. . 5158. . . . . . . . . 11103. . 322 deg . . 12544. . . 9701. . . . . . 11191. . . . . 291. 211. . . . 387 \endL . 2770. 9299. 10652. 11987. 13373. 10275. . 455 \displaywidth . . . . . 33. . . . . 3401. 10132. . 12705. 14200. 11652. . 730 \discretionary . . 14269 \dim_zero_new:c . . 2786. . . . 11629. . . 11405. 69. 3422. . . 539 \end . . . . 2836. . . . . . 327 \dimexpr . . . . . 13242. 11382. . 2844. . . . 11292. . 2573. . . . . . 2330. . . . 13372. . . . . 4198. . 12998. . 15. 5955. . . 13148. . . . 16. . . . . . . . 2206. 12138. . . . . 10592. . 11663. . . 491 \displayindent . 12946. . . . . . . . 2796. . 766. . 11493. 13280. 805. . . 4202. . . . . . . 11022. 11344. . 11632. . . . . 36. . 11039. 3441. 11408. 13212. . . . . . 1606. . 2781. 10641. 208. 11928. 2853. . 13383. . 797. . . . . . . . . . . . . . 842. . . . . 692 \etex_currentgrouplevel:D . . . . . . . 697 \etex_scantokens:D . . . . . . . 804. . . . 686 \etex_gluetomu:D . . . . . . . . . 1880. . 9316 \etex_savinghyphcodes:D . . . 6601. . . . 684. . . . . . . . . . . . . . . 3384 \etex_pagediscards:D . . . . . . . 4482. . . . . 1744. . . . . . . 4758 \etex_showgroups:D . . . 428 \etex_beginL:D . . . . . . . . . 652 \etex_splitdiscards:D . . 696 \etex_savingvdiscards:D . . . . . . . . 5122. 1745. . . . . . . . . . . . . . . . . . . . . 6604. . . . . . . . . . . . . . . . . 545 \everyvbox . . . 658 \etex_tracinggroups:D . . . . . . . . . . . 649 \etex_fontchardp:D . . . . . . . . . . 1740. 1695. . . . 1722. . . . . 5148. . . . . . . . . . . 4491. . . . . . . . . . . 1676. 679 \etex_parshapeindent:D . 651 \etex_TeXXeTstate:D . . . . . . 666 \etex_currentgrouptype:D . . . . . . . . . . . 4477. . . . . . . . . . . . . . . . . . . . . . . 6605 \etex_interlinepenalties:D . . 646 \eTeXversion . . . . 701 \etex_beginR:D . . . . . . . . . . . 1709. . . 1727. . . . . . 669 \etex_showtokens:D . . 667 \etex_currentifbranch:D . . . . . 833. 598 \exhyphenpenalty . . . . . . . . . . . . . . . . . . . . . . 1746. . . . . 4485. . . . . . . . . . . . . . . . . . . . . . . 946. . . . 1071. . . . 4990. . . 835. 1031. . 690 \etex_lastnodetype:D . 4553. . . 940. . . 707. . . . . . 856 \etex_readline:D . . 695 \etex_muexpr:D . . . . 1738. . . . . . . . . . . . . . . . . . . . . 972. . . . . . . . . . . 4182 \etex_displaywidowpenalties:D . . 14984 \etex_gluestretchorder:D . . . . . . 799. 1075. . 4537. . . . . . . . . 1686. . . . . . . 1289. . 771 \etex_widowpenalties:D . . . . . . . . 1655. . . . 663 \etex_currentiflevel:D . . . 650 \etex_clubpenalties:D . . . . . . . . . . . 705 732 \etex_protected:D . . 702 \etex_endR:D . . . . 521 \exp_after:wN 32. 681. . . . . . . 644. . . . . . . . . . . . . . . . . 676 \etex_fontcharwd:D . . 661 \etex_tracingnesting:D . 1630. . . . . . . . . . . 1470. . . . . . . . . . . 704 \etex_eTeXrevision:D . . 673 \etex_fontcharic:D . . 1733. . . . 1872. 1721. . 1355. . 1701. . . . . . . . . . . 32. 1869. . . . 656. . . 4092. . . . . . 1642. 645 \etex_everyeof:D . . . 4526. . 1720. . . . . . . . 4470. . 687 \etex_gluestretch:D . . . . . . . . 4491. . . . . . . . . . . . . . . . . 1671. . . . 824 \etex_iffontchar:D . . . . . . . 655. . 1643. 806. . . . . . . . . 648 \etex_tracingassigns:D . 1732. . . . . 854. . . . . . 643. . . . . . 1714. . . . . . . . . 689 \etex_numexpr:D . . . . 894. 1716. 1637. . . . . . 706 \everyhbox . . . . . . . . . . . . . 657. 4446. 1404. . . . . 706. . . 4547. . . . . . . 1875. . . . . . . . . . 15052. . . . . . 1704. . 675 \etex_glueexpr:D 682. 838. . . . . 672 \etex_interactionmode:D . 4542. . 1114. . 678 \etex_predisplaydirection:D . . 1747. . . . . . . . . . 647 \etex_middle:D . 4401. . . . 677 \etex_parshapelength:D . . 831. 1321. . . . . . . 953. 646 \etex_eTeXversion:D . 482 \everypar . 693 \eTeXrevision . 837. . . . . . . . . . . . . 840. . . 1661. . . 836. . . . . . 1561. . . 1673. 1654. . . . . . . . . . . 8288 \etex_splitbotmarks:D . . . . . . . . . . . . . . . . . . . . . . . . . . 685. . 691 \etex_lastlinefit:D . . . 784. . . . . . . . . . . . 668 \etex_showifs:D . . . . . . . . . . . . 1690. 4435. 1650. 1739. . . 1119. . . . . . . 1684. . . . 14985 \etex_glueshrinkorder:D . . 4451. . . . . . . 1010. . . . 654. .Index \escapechar . . . . 1715. 784. . . . 15002. . . . 4747 \etex_firstmarks:D . . . . . . . 1319. . 664 \etex_detokenize:D . . . . . . 1084. 665 \etex_tracingifs:D . . . . . . . . . . . . 1728. 674 \etex_fontcharht:D . 1299. . . . . . . 786. . . . . . . . . . . . 1696. . . . . . 15060 \etex_unless:D . . 781 \etex_ifdefined:D . 694 \etex_endL:D . . . 688 \etex_ifcsname:D . . . . . . . . . 703 \etex_botmarks:D . . 699 \etex_splitfirstmarks:D . 896. . . . . . . . 660 \etex_tracingscantokens:D . . . . . . 1688. . . . . 1024. . . 1291. . . . . . 597 \everyjob . . . . 1085. . . . . 653. . . . . . . 970. . . 1639. 780. . . . . . 357 \everydisplay . . . . . . 1144. 683. . . . . . . . . . . . . . 642. 626 \everymath . . . . 852. . 1116. . 13646 \etex_glueshrink:D . . . . . . . . . . 3578. . . . . . . . . . . . . . . 645 \everycr . . 1692. . . . . . . . 5169. . . . . . 670. . . . . . . . . . . . . 659 \etex_unexpanded:D . . . . . . . . . . . . 1892. . . . . . . . 850. . . . . . . . 700 \etex_topmarks:D . 662 \etex_currentiftype:D . . 1697. . . . . . 458 \everyeof . . . . . . . 1726. . . 4991 \etex_dimexpr:D . . . 1142. . . . . . . 680. . . . 1734. . . . 1147. . . . . . . . . . . . 671 \etex_marks:D . 1666. . . . . . . 1660. 1019. . 4553 \etex_mutoglue:D . . . 698 \etex_parshapedimen:D . . . . . . 1821. 10321. 11584. 11211. 3150. 5595. 4240. 5572. 10849. 4652. 11542. 9742. 11638. 11064. 11637. 1812. 2898. 11222. 1935. 11246. 10437. 10360. 11212. 2362. 10550. 9841. 6026. 11049. 5122. 11199. 3151. 11689. 5172. 10337. 1760. 3137. 3430. 1774. 11102. 5584. 11470. 11219. 11018. 8219. 1820. 11519. 11242. 11369. 10881. 11291. 3053. 1870. 11223. 11050. 11478. 2196. 11155. 10388. 1840. 10755. 5156. 11117. 10793. 11361. 11575. 10302. 11198. 11683. 10773. 11255. 4875. 10513. 11260. 10274. 10575. 1836. 1869. 10782. 1752. 9868. 3405. 2829. 10589. 11651. 11370. 10369. 10792. 5178. 11671. 11134. 10852. 1753. 1907. 3000. 5294. 1773. 10462. 5159. 10946. 9691. 2284. 11274. 1889. 11583. 5940. 4645. 3160. 10319. 10829. 3865. 1890. 3182. 10548. 10296. 4241. 2976. 10770. 9739. 9690. 10352. 2503. 9700. 10345. 2512. 11132. 11017. 10769. 3277. 3054. 10797. 10378. 5248. 8217. 10180. 9679. 10990. 3159. 10387. 11121. 10205. 3413. 11156. 1888. 10888. 10498. 1767. 1759. 10650. 11670. 10880. 4491. 3178. 9712. 10586. 10956. 3172. 10367. 10632. 10738. 11081. 11077. 11201. 1880. 11035. 8218. 11116. 5238. 10887. 10445. 10859. 3429. 3567. 11556. 3268. 1775. 8684. 4383. 10640. 3572. 3914. 10439. 1855. 9720. 10368. 10749. 10118. 10968. 11262. 10851. 10359. 1891. 5620. 11016. 10597. 2505. 4756. 10324. 3010. 11224. 9059. 11172. 11681. 11636. 9850. 10485. 11105. 5534. 8402. 5152. 2347. 10362. 10464. 10565. 4249. 9733. 3065. 4092. 10525. 11301. 5918. 10858. 10559. 9982. 3401. 10642. 8231. 3396. 11238. 1831. 11196. 11294. 9744. 1768. 1904. 5275. 2529. 11208. 10506. 1846. 11101. 10848. 10117. 3404. 10526. 9865. 10643. 11034. 9832. 10363. 9745. 2536. 11209. 1875. 1832. 8554. 10206. 10775. 10877. 6247. 11697. 11197. 10304. 10630. 4808. 10236. 10293. 3451. 3056. 10666. 8404. 4273. 3259. 11244. 3030. 11133. 5903. 10183. 10812. 10745. 11062. 10712. 5295. 11563. 10756. 11129. 1853. 11122. 11640. 10237. 10826.Index 733 1751. 1845. 10827. 8288. 1816. 10875. 7722. 10969. 9730. 11276. 9957. 9702. 9801. 3062. 10795. 10747. 11272. 9732. 1839. 10619. 9743. 1758. 10390. 10366. 11557. 1809. 4291. 9731. 10602. 11517. 3149. 11213. 3412. 11289. 2940. 1872. 2920. 10301. 5293. 1928. 2348. 10590. 2848. 2193. 10403. 9559. 9734. 8289. 1765. 9729. 10436. 11553. 10992. 3170. 10080. 10297. 11273. 1754. 11176. 5621. 9722. 10305. 8220. 1854. 9678. 2200. 10776. 10496. 10227. 11545. 9566. 10507. 10413. 11278. 4237. 4991. 8692. 10790. 11337. 10336. 9710. 3590. 11239. 11174. 9851. 10861. 2521. 11719. 11290. 10613. 4553. 10587. 11668. 4401. 11552. 10264. 11576. 11694. 11541. 11007. 9965. 3452. 11106. 6013. 10639. 9741. 10116. 4278. 10472. 3893. 10245. 10957. 10991. 5251. 6021. 3169. 11074. 11258. 11568. 3153. 10748. 11261. 11690. 10394. 5673. 10234. 10947. 11202. 2519. 10576. 11245. 1815. 11203. 5594. 10739. 10958. 10970. 2989. 4294. 10392. 10325. 11073. 3592. 10500. 4469. 10179. 10483. 10218. 9828. 5157. 9569. 10791. 1829. 10743. 11171. 11079. 10323. 11220. 10198. 11277. 5619. 10449. 5095. 10830. 10294. 10511. 10876. 10326. 6418. 5155. 10727. 4248. 3904. 10318. 4816. 3139. 11254. 9889. 10561. 3179. 11104. 11120. 11061. 11479. 4874. 9047. 10217. 11080. 4862. 11351. 11667. 10593. 10194. 4757. 1772. 10766. 11118. 11297. 11175. 10556. 5273. 1955. 5186. 9676. 1859. 3562. 10570. 9991. 10414. 2882. 11471. 2873. 10915. . 11210. 11130. 10424. 3162. 1868. 1808. 1850. 9799. 4233. 11072. 10715. 10741. 4047. 11128. 10037. 10864. 5956. 2958. 10393. 2497. 2070. 5216. 5274. 1834. 9858. 10879. 10806. 10491. 10656. 10377. 5197. 9689. 1766. 9740. 1866. 10740. 4821. 11200. . 15085. 15084. 13703. 1756 \exp_args:NcNo . 12483. 11882. 985. . 11736. 13304. . 13358. 13517. 13097. 11880. 1689. 12827. 11092. . 12084. . 11770. 12774. 13781. 13579. 12741. 11734. 12170. 14810. . . 800. 12169. 13325. 12320. . 13267. 1763 \exp_args:Ncnx . 11768. 11766. 1437. . . 29. 1445. . 12364. 12853. 13621. . . 13104. . . 1793. . . 12218. . . 12456. 11965. 12531. 13014. 15002. 13055. . 796. 12146. 12811. 13876. . 14868. 13862. . 12034. 11088. 12999. 11969. 12076. 12770. 13571. 13145. . . . 12722. . 11879. 12708. 1749. 12420. 12054. 13284. 13047. 11755. 1802 \exp_args:Ncf . 13074. . . 14960. 12595. 12253. . 12632. . 12087. 13860. 13367. 12634. . 11788. 796. 13357. . 11783. 13016. 13011. 11998. . . . 11865. 13305. 13297. . . . 12061. 13863. . 12584. 13015. 11897. 12151. 12829. . 12577. 1712. 12707. 15152. 13448. 13327. 14518. 13018. . 13538. 1336. 12259. 12948. 12093. 1439. 13488. 12630. 12051. 13368. 12619. . 12108. 13411. . 13088. 12481. 12622. 808. . 12646. 1458. . 12740. 12139. 13000. 14773 \exp_args:Ncc . . 13586. . 12826. 13701. 12947. 12342. 12682. 14861. 13832. . 12638. 12256. 11994. 13010. 11859. 13606. . 13449. . 11747. 1271. . 11867. 13774. 1269. 13577. 13570. 12885. 13654. 12307. 14513. 13308. 12996. 12992. 13618. 13578. 11791. 13084. 12759. . . 13041. 12090. . 12052. 13281. . 13072. 12901. 13535. 12232. 11999. 13614. 12419. 11971. 12346. 11753. 12650. 4962. 1689 \exp_args:Nc . 13495. 12337. 13077. . 13112. 1444. 12198. 12565. 1730 . 11774. 12010. 13617. . . 14860. 12991. 13645. 12648. 8948. . 12609. 12793. . 13139. 12162. 12943. 12674. 13598. 13640. 12590. 13594. 11831. 11875. 12997. 990. . 13799. . 11996. 13117. 11898. 14956. 12421. 12008. 13285. . 12586. 11903. 13331. 11858. . 1803 \exp_args:Nco . 12157. 12220. 11977. . 13096. 11761. 14869. 13146. 13058. . 12952. 12644. 12363. . 12262. 11757. 12366. . 13704. 12776. . 12230. 13858. 12178. 11973. 12148. 13544. 15147. 12171. 12339. . 12994. 12563. . 1347. . 11962. 13292. . 13320. . 11823. 11829. . 11895. . 12361. 13494. 13871. . 1736 \exp_args:NcNc . 1689. . 12163. 12000. 12352. 13275. 13658. . 12179. . 11832. 13514. 13384. . 12837. 11986. 12059. 12365. 12298. 1693 \exp_args:Ncco . 14955. 798. 12067. 12670. 11824. 1403. 1712. 11955. 13306. . 12524. 13020. 11744. 12642. . 15060. . . 13424. 12612. 1438. 12917. 12033. 12100. 11810. 1274. 12623. 12652. 13659. 13526. . 14514. 12582. 11089. 12620. . 12120. 13317. 12210.Index 734 11721. . . 13049. 12384. 11988. . 12611. 12102. 12011. 995. 13108. . 15154 \exp_args:cc . 11803. 13485. 13421. 11091. 11860. 14959. . 15022. 12191. . . 14859. 12583. 1243. 12006. 12621. . 12286. . 1689. 12603. 12053. 12558. . 1275. 13620. 1215. 12165. 12161. . 12734. 13052. 12985. . 13040. 13859. 11816. 12118. . 11784. 12559. 1749. . . 1447. . . 12738. 1446. 13279. 13307. 12624. 11851. 11758. 796. . . 12764. 13412. 12636. 12625. 1281. 12047. 13603. 11090. 13118. 13276. 11967. 11852. . 12172. 13655. . 12313. . 13329. 12683. 12037. 13382. 11954. 13837. 12817. 13635. 12386. . 12012. . 12538. . 12197. 12704. 12288. 12378. 12716. 12828. 12702. 1283. 13453. . 1225. 13861. 12597. . 12737. 12463. 12248. 13265. 11963. 11790. . 1770 \exp_args:Nccx . 12159. . 11093. 12276. 1793. 12760. 12354. . . 12341. 12296. 12278. 13037. 12310. 975. 1436. 12250. 13019. 13333. . . 12177. . 13102. 11893. . 12703. 12688. 11975. 12116. 13061. 12585. 13069. 12180. 12690. 13475. 12343. 12706. 12137. 13038. 12618. 11800. 12869. . 11802. 13530. 11759. 11792. 13516. 1749. 11830. 13274. 12070. 11777. 12355. 13100. 12699. 12338. . 15052. 11877. 11742. . 12045. 13138. 12345. 9907. 12954. 1691 \exp_args:Nccc . 12073. 13631. 12239. 13471. 12561. 11850. 14517. . . . . 2398. . . . . . 15107 \exp_args:Nff . . . 8425. . . 2511. . . . . 1712. . 1849. 33. 1793 \exp_args:Nnno . . 13796 \exp_not:f . . . 2518. . 1828. . . 1666. 2434. 1778. . 1793. . . . 1948. . . . . . 5033. . . 2562. 2403. . . . . 1796 \exp_args:NNNV . . . . . 2412. . . . 8018. . . . . 1793. . . . 1871 \exp_not:N . . . 1804 \exp_args:Nox . . . . . 3998. . 14854. . 4926. . . . . 1793. 1828. . . . . 785. . 3836. 5031. 2843. 4927. . . . . 2432. 3159. 5141. . . . 3755. . 1828. . . . . . 8222. . . . . 2780. . . . . . 1354. . . 1742 \exp_args:Nx . . . . . . 1684. . 1865. 14472 \exp_last_unbraced:Nfo 1828. 1828. . . 1789 \exp_args:No . 1778. 4389. . . . . 14449. . . . . 1749 \exp_args:NNnx . 1792 \exp_last_two_unbraced:Noo . . 1828. . . 2442. 8031. . . 1724 \exp_args:NNv . . 2030. 8014. . . 30. 1862. . 2810. . 1778. . 1006. . 1979. 4968. 4800. 2424. . . 2421. . . . . . 8016. 3705. . . 3977. 7780. . . 5448. . . . . 2406. . 1778. 1832. . 1702 \exp_args:NVV . . . . 8587. . . . . 1869. . . . . . 2762. 3857. .Index \exp_args:Ncx . . 2752. 1700. 1684. . . . . . . . . 9555. . . 1477. 2452. . 4754. . 2436. . . 9959. . . 1799 \exp_args:Nnox . 1700. 1707 \exp_args:Nv . 2535. 30. . 14803. . . . 2415. 3987. 3251. . . 1795 \exp_args:NNNo . . 7215 \exp_last_unbraced:Nno . . . 6110. . . 1861. 2407. . . . . . 1828. 2389. . 29. . 1828. . 7787. 2394. . . . . . . 1863 \exp_last_unbraced:NNNV . . 2775. 1782. . 1777. . 3755. 13790. . 3148. 1403. 1786 \exp_args:Nof . . 2795. 6155. 2451. . . . 1009. . . 1689. 32. 14447. 1851 \exp_last_unbraced:NNo . 30. . . . . 6020. . . 5216. 2790. 4388. 8029. 1793. . . 1788 \exp_args:Nf . 8370. . 1687 \exp_args:NNno . . . 6365 \exp_last_unbraced:NV . 1778. . 2397. . . . 5254. 1793. . . 1778. 1980. 7453. . . . . . . 4910. . 9473. . . 1273. 30. 2376. . 7774. . . 3740. 9976. 4911. 1778 \exp_args:NNf 1712. 1939. 7785. . 2444. . . 7375. . . . 3124. 7789. . . . . . . . . . . 5175. . 1869. 5109. . . 6061. . 32. . . . 1870. 2438. 3101. . 1349. 4912. 8589. . . 14415. . 3950. . 8229. . 5213. . . 8024. . . 1828. . . 2446. . . 8364. 2757. . . . . 11620. . . . . . 4009. 14835 \exp_last_unbraced:NNNo . 8574. 1784 \exp_args:Nooo . . 4764. . 31. 1977. . . . 1442. 4977. . . . . . . 1749. 3168. . . 1778. 31. 2769. . . 2440. 7018. . . 6034. 2747. . . 15076. . . 1778. . 14788. 1441. . . . 1793. . . 2421. 1828. . . . . . . 1297. . . 1712. . . 15078 \exp_args:Nno . . . . 14433. . . . . . 4925. 1978. . . . 1793. . 1712. . . . 6411. . 1828. . 1270. 4747. . 7768. . . 2384. . . 3728. . . 784. 1630. . 1904. . 1779. . . . . . . . . 15089. 1787 \exp_args:Nnx . 2412. . . 2800. 1355. 1404. 1700. . 4310. 2723. . . 1864 \exp_not:c . . 1835. 2815. . . . . 1828. . . 14403 \exp_args:NNc . . 2380. . . . 31. . 6241. 1793. . . 8366. 1860. 1828 \exp_last_unbraced:Nv . 1778. . 4951. 14428. . 1778. . 1800 \exp_args:NNo . 30. . 2423. . 1684. 1828. . 8948. . 2403. 7772. 1798 \exp_args:Nnnx . 14458 \exp_last_unbraced:Noo . . . . 4392. . . . . . . . 3712. . . 1778. . . 3151. . 10012 \exp_args:NNoo . . . 1440. . . 6093. . . 2070. 2385. . 4475. 5197. . 7688 735 \exp_args:Nxo . 1777. . . 3767. . . 6039. . . . 944. 3735. 1718 \exp_args:NnV . 1785 \exp_args:Noo . . . . . . . . . 4928. 33. 1833. . 5447. . 1685. 7245 \exp_last_unbraced:Nco . 1689. 7459. . . 1684. . 1790 \exp_args:NV . . . 3619. 8033. 3169. 33. 7370. 14820 \exp_last_unbraced:NNV . . 1781 \exp_args:Nnnc . . . 1712. . 3721 \exp_args:Nnf . . . 5842. . . . . . . . 1791 \exp_args:Nxx . . 1801 \exp_args:NNV . 1443. 3198. . 31. . . 5247. 1828. . 8450. . 6429 \exp_last_unbraced:NcV . 2571. . . . . . 1830 \exp_last_unbraced:Nx . . 3963. . . . . . . . . . . 4281. 1837 \exp_last_unbraced:Nf . 5143. . . . 1778. . . . . . . . 1700. 2030. . 3846. 2848. . . . . . . 1778. 2405. . 1843 \exp_last_unbraced:No . 9950. . 2381. 4801. . . 1858 \exp_last_unbraced:NnNo . . 3848. 30. . . . . 4747. . . 1793. . 32. . 15109 \exp_args:Noc . 1865. . 5166. . . . . . . . . 1828. 9984. . 3106. . 2394. . 1793. 2450. 15021. . 3158. . . . 7241. 1870. . . 1797 \exp_args:Noox . . . . . . 7770. 2388. 3840. 14443. . 1783 \exp_args:NNx . . . . . . . . . 9942. 8572. 2785. 5194. 4766. . . . 8368. 1778. 8231 \exp_args:Nnc . . 8737. 1794 \exp_args:NNox . . . . 1780 \exp_args:Nfo . . 8012. . 2414. . . . 2396. 2416. . 1778. . 1282. . . . 2425. . . . . . . . 11630. . 6020. 265. 14062 \ExplFileName . . . 11391. . . 13356. . 4592. 2844. 941. 4. 1137. 66. 6492. . 13. 1960. . . 12513. 3591. . 286 \ExplSyntaxOff . 124. . 191. . 2811. 763. 4178. . 1075. . . . 14526. 4. 2484. 1869. 1999. . 3102. 15079 \expandafter . . 4687. 8006. 3066. 2763. 2758. 14531. . 4683. 72. . . . . 7573. 2530. . . . 10256 . . . . 1672. 3154. 9042. 2924. 1606. 155. 201. . . 6212. 8737. 13704. . 8589. 1646. 2086. 11841. . 4711. 1976. 1292. 1669. . . 10122. 10509. . 11403. 1996. 4592. 6492. 3547. 337 . 8720. . 376 . 220. . 10523. 3057. 786. 6492. 8377. 8941. 5861. . 8023. 2608. 954. . 4930. 9471. 3614. 1605. . 2332. 2963. 13604. 9633. 345 \ExplFileDate . 3074. 2484. 2160. 2801. . 185. 3555. . 3380. 12942. 63. 8231. 4705. 24. 1679. 3444. 10594. 14460. . 4715 \exp_not:v . 3121. 1136. 305. 13906. 4825. 5477. 13789. 162. 8214. 9042. 32. 6212. 13884. 247 \F . 7779. . 2498. . 6149. . 947. 2187. 10709. 1299. 6602. . 10585. 8643. 13788. . 2608. 8471. 2944. 9091. 13884. 11692. 8222. 2806. . 4178. 4604. 13999. 7540. 215. 3183. 1878. . 1936. 13188. 14921. . 13159. 2776. . 3107. 290. . 8455. 1869. 1312. 3401. 9382. . 33. 5392. 13910. 2330. 1873. . . . 2562. 12984. 9628. 5717. 109. 2506. . 807. . 3644. 8377. 10106. 2086. . 246. 2566. 2484. 2571. 8427. 3199. . 3380. . 11650. . 10558. 4813. 2823. 208. . 181. . . 1117. 1108. 3585. . 195. . 5798. 5027. . 2748. . . 14481. 14997 \exp_not:V . 8023. 1680. 13339. . 5798. 295. . 13071. 2575. . . 2980. 5509. . . 10725. . 13126. . 13706. 285. . . 4592. 3398. 4634. 14062 \ExplSyntaxNamesOff . 8441. 2816. 8723. 14969. . 14944. 176. 10482. . 213. 3380. 4665. 5268. 13700. 13934. 973. 14062 \ExplFileDescription . 108. 4689. 285. 7540. . 1032. . 280 \ExplSyntaxOn . 13341. 13630. . 10461. 2535. 2328. 1962. . . 10664. 1515. 2855. 766. 4178. 2511. . 945. 3048. 3894. 106. 288. 5798. 2962. 6145. 1109. 6330. 1333. 2537. . 2377. 1984. 2608. . . 1607. 3173. 4691. 4592. 7540. . . . 6027. 33. . 3424. 1530. 10273. . 6492. . 190.Index 5449. 1020. 3579. . 2786. . 13701. . 2608. 65. F . . . 4671. 15143. 13976. 1123. 2522. . 6156. 4683. 1322. 1627. 14918. 11621. 2206. 2781. 9316. . 7877. 4715. 770. . 1434. 12540. 1945. 216. 6. 6332. 138. 215. 14978. 9042. 4695. 2019. 1145. 12531. 13705. . 4685. 13627. . 4717. 12989. 13486. . 13703. 1522. . 7779. 8452. 196. 8377. 1825. . 6155. 2791. . 11765. 5927. 2796. 4691. . 736 73. 13971. 12830. 193. 2856. 1517. 2020. 12696. . . . 5718. 297. 4709. . . 305. . . 13173. 1627. 198. 4802. . 13218. . 2945. . . 1869. 6714. 3125. . 213. 68. 15144 \exp_not:n . . . . 14924. 6157. 4681. 13203. . 3163. 11787. . 1869. 10648. 10736. 6. . . . 2925. 62. 4669. 6714. 14853. 69. 5029. 6350. 12181. 763. 3584. 8697. . 13248. 1640. 1025. 11842. 1627. 4693. 8721. 305. 4689. 4636. 3416. . 210. 2753. 2126. 1630. 784. . 9628. 50. . 4766. . 11628. 7540. 4707. 13884. 1913. 8574. 45. 9539. 8616. . 2513. . 33. 4705. 3441. 1608. 4713. . 13536. 12731. 3589. 10300. . 5267. 8688. 2334. 182. 1627. 6212. 13795. . 13884. 5392. 4289. 2770. 3380. 13590. . . . . 2981. 9839. 50. 4681. 15106 \exp_not:o . 6212. 14482. 4707. 6714. 2326. 2545. . 3442. . 4719. 1929. 71. . 33. 167. . . . 8642. 11394. 3197. 33. 8939. 1562. 13340. 9466. 8572. 14. . 7762. 11402. 1998. 1011. . 763. . . 87. . . 2484. . 8462. 1151. 8587. 7573. 1212. 6714. 251. 2086. . 9042. 763. 8377. 8617. . 7573. 4663. 5392. 36. 5392. 7573. 2518. 13233. 3636. 1961. 110. 11389. 14998. . 14427. . . 5577. 1070. 2349. . . . 2553. 14062 \ExplFileVersion . 9385. 5798. 2086. 13708. . 9617. 173. 4178. . 3408. 246. 10788. 10629. 13794. 5830. . 2903. 5632. 2838. . . 2336. 2902. 3140. 293 \ExplSyntaxNamesOn . 9628. 9628. 11225. 8619. 4713. 186. 5832. . 109. 3022. 14828. 305. 6148. \fam \fi \fi: . . 3741. 8645 \exp_stop_f: . 10371. . 9703. 4288. 11370. . 11811. . 10687. . 12379. 12988. . 5149. . 10109. 13150. . . . 13454. . 9239 \file_if_exist:n . 5227. 11381. . 12709. 13622. 13849 . . . 10213. . 11407. 13680. . . . 11569. . 13385. 11335 \fp_compare:nF . 11263. 13213. 11932. . 13198. . 12941. . 13783. . 11558. . . . 13343. . . 13353. 10705. 13603. 4866. 160. . . . . . 11041. 10204. . 336 \fontchardp . 9227. . . . . 13228. . . 10517. . 11989. 13784. 14719 \fp_add:cn . 10750. . 10476. . 13849 \fp_compare:nNnF . . 12367. 12792. . 10108. 11207. 5508. 11082. 649 \floatingpenalty . 10866. . 9826. . . . 9713. . 13141. 5243. 570 \font . 13166. . . 11607. . . . 13519. . . . 11247. . . . . . 12679. 10277. . 12863. 13589. . . . 13075. . 15144. . . . 12949. 11397. 11828. . . 12758. 12994. . 5535. 10580. 11380. . 11560. . 13800 \fp_abs:n . . . 10110. . . . . . 13154. . 11901. . . . 11302. . . . 11369. 5556. . 13739. . . 9828. . 10638. 11492. 10545. 9094. 5162. 13163. 5919. 13130. . 11346. 10395. . 12669. . . . . . 12833. . .Index 737 4237. 10240. . . . . . . 12431. . 10465. 4269. 5942. . . . . . 10544. 10644. 10486. . . . . 10454. 10163. . . 12062. . 14717. . 10203. 5096. 11641. 13103. 12812. . . . 11008. 9171 \file_path_remove:n . 10453. . . . . 9132. . . . . . 12895. 11186. 12977. . . . 12834. . . . . . 11848. . . 12435. 9827. 13838. 4889. . 11443. . 5624. . 5505. . 5190. . 5160. . . . 15161. 13258. . 10154. 12955. . . 13485. 11378. 6572. 13268. 10760. 6562. 6560. 12742. 10087. . 5618. . 9834. . 11853. . 13661. 5152. . 4260. 13374. . 674 \fontcharht . 11371. 525 \firstmark . . . 12403. . 12754. . 5252. . 9832. 11454. . . . 12408. 11868. 11634. 5204. . 13282. 11931. . . 9171. . . . 9830. 9304. . 10853. 11123. . 160. 161. . 11512. . 11511. 12613. . 9787. 10120. . 12441. . . 10460. . 13784 \fp_abs:N . 13001. . . . . 12181. . . 9856. 9183. . . 9836. . 13739. 13344. . . . 9692. . . 13623. . . . 12512. 603 \fontname . 11513. . . 15155. 11387. 10535. . 10699. 10670. . 13042. 9833. 12129. 12847. . . 9137 \file_list: . 10608. 10882. . . 13286. 11603. . 6419. . 10184. 10306. . . . 10633. . . . 9688. . 10777. . 13426. 10134. 12927. . 4292. . . . 11502. . . 14271. . . . . . 10017. . 9137. . . . . 11684. . 9914. 10607. . 5566. 10121. . . . . 12691. 13355. . 11415. 11793. 13507. 14275. . 12356. . 11398. 11674. 5283. . . . 9843. 12710. 10629. 13261. 13105. 9829. 10415. 11930. 10479. 11205. 12394. . 11672. . 5261. . 11279. 10731. . 10096. . . 15145. . . 11299. 11534. . . 13784. 13359. 13739 \fp_add:Nn . 11508. 13243. . . . 12879. 12553. 13680. 11230. 13336. 12130. . . . 180. . . 10239. . 12965. . 11698. . 13425. . 11606. . 9178 \finalhyphendemerits . 10989. 12140. 9139. 13076. 9825. 13778. 13535. 6383. . 9723. . 10138. . 11934. . 11135. . 9831. 13745 \fp_compare:n . 4306. . . 13013. . . 10307. . . . . 9869. . . 13662. . . 5958. 10125. 4906. 12417. 11024. 11845. . 12127. 160. . 9680. 10659. . . 14219. 9094. 5904. . 13263. . 11520. . . 5295. . 12437. . 673 \fontcharic . . . 14273. . . 675 \fontdimen . 10987. 12415. 11409. 10385. 9305. 11933. 11388. 12968. . . 12546. . . . 11107. 15163 \file_add_path:nN . 10717. . 12745. 11612. 12911. . 13004. . . . . . . 10623. 10137. 4463. . . 7603. 10086. . 11192. . 676 \fontcharwd . . . . 10219. 11406. . . 13346. . . 15143. 13120. . 14811. 12756. . . . 10298. 14217. 161. 10459. . 9859. . . 9130 \file_if_exist:nTF . 10867. . . . 12519. . 9570. 10147. 11562. 11529. . 10457. . 9130 \file_input:n . 10541. . 12986. 10988. 11737. 11177. 10720. . . . 4854. . . 10697. 11510. 10162. . . 9866. 427 \fp_abs:c . 13335. 13373. 13316. . . . . . 9171. 13153. . 9835. . . 11654. 13021. . . . 10481. 10146. 11509. 12681. 11849. 5287. . . . 4879. . . . 13119. . 12777. 12530. . . 11426 \fp_compare:nNn . . . 11410. 10253. . 10530. . 11348 \fp_compare:NNNF . 11357. 9183 \file_path_include:n . . . 11728. 11596. . 13556. 11635. 161. . . 10801. . 11947. . 10097. 11846. 12791. 10126. 169. . 13183. . 13609. . 11503. . . . 423 \firstmarks . . . 11771. . 10579. . . . . . . . . 9904. . . . . . . . . 13739. . . . . . . . . . . . . 13723. . . . . . . . 13734. . . . 14534. . . . . . . . . 13826 \fp_gmul:cn . . . . . 13818 \fp_gln:Nn . . . . . 13847. 13828 \fp_div:cn . . . . . . . 11333 \fp_if_exist_p:N . . . . . . . . . . . . . . 14794. . . . . . 13879 \fp_ground_places:Nn 13850. . . . . . . . . . . 13728. 13729. . . 13780 \fp_if_zero:NTF . . . . . . . . . 13812 \fp_neg:c . . . . . . . 13803 \fp_gpow:cn . . . . . . . . . . . 13768. . . . . 13784 \fp_gabs:N . . 13716. 169. . 13809 \fp_gset_eq:cc . . 9904 \fp_flag_on:n . . . . . . . . . . . . . . 13766. . . . . . . . 13725 \fp_gset_eq:Nc . . 11450 \fp_eval:n . . . . 13736. . . . 13739 \fp_gadd:Nn . . . . . 9990. 168. . . . . . . . . . . . . . . . . 13677. . . 14096. 13784. . . . 14190. . . 11440. . . . . . 13818 \fp_ln:Nn . . . 13713. . . 174. . . . . . . . . 13772 \fp_cos:cn . . . . 13784 \fp_gneg:N . 13739 \fp_gsub:Nn . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168. 13733. . . . . . . 13804 \fp_gdiv:Nn . . . . . . . . . . . 10021 \fp_gabs:c . . . . . . . . . . . . . . 11440. . . . . . 14679. 14701 \fp_compare:NNNTF . . . . . . . 169. . . . . . . . 13730. . . . . . . . . . . . . . 171. . . . . . . . . 13818. . . . . . . 9908 \fp_if_flag_on:nTF . . . . . . . . . . . . . . . . . 13773 \fp_if_undefined:NTF . . . . 11444 \fp_do_while:nn . . . . . . . . . . . 11412. . . . . . 13684 \fp_mul:cn . . . . . . . . 174. . . . . . 13735. . 13825 \fp_gln:cn . . . . . 13804 \fp_gmul:Nn . . . . 180. . . . . 14191. . . . . . 11440. 13733 \fp_gzero_new:N . . . 13739. . . . . 14068. 11462. . . . . . . . 9981. . . . . . . 13807. . . . . . . . 11416 \fp_do_until:nNnn 171. . . . 13804 \fp_gpow:Nn . . . . . . 13761. . . . . . . . . . . . . . . . . . . . . . . 13852. . . . . . . . . . . . . 13818. . . . . . . . . . . . . . . . . . 9964. . 13726. . . 13720. . . . 13679 \fp_exp:cn . . 152 \fp_gset:cn . . . 13773 \fp_if_zero:N . . . . . . . . 13847 \fp_compare:nNnTF . . . . . 11348 \fp_const:cn . . . . . . 14066. . . . . . . . . . . . . . 14103. . . . . . . . . 13773 \fp_if_undefined_p:N . . . . . 13765. . . . . . . . . . . 14794 \fp_gset_from_dim:Nn . . 13848 \fp_compare:nNnT 11449. . . . . . . . . . . 13815 \fp_gexp:cn . . . . . . . . . . . . . . . . . 13804. 13740. 11434 \fp_compare:nTF . . . . . . . . . . 13804 . . 13809. . . . . . . . 13716. . . . . . . . . . . . 13784. . . 152 738 \fp_gset:Nn . . 13682. . . . . . . . . 6738. . . . . . . . . . . . . . . 13715. . . . . . . . . . . . . 13780 \fp_ln:cn . . . . 9956. 13828 \fp_gdiv:cn . . . . . . . . . 13730 \fp_gset_from_dim:cn . . . . . 13762. . . . . . . . 13829 \fp_gzero:c . 7079. . . 174. . . . . 13826 \fp_max:nn . . . . . . . . . . . 13807. 13804 \fp_div:Nn . . . . . 14799 \fp_gsin:cn . . . . . . . . . . . . . . . . . . . 13763. . 169. . 13738 \fp_if_exist:c . . . . 13804. . . . . . 13792. . 11334 \fp_if_exist:cTF . . . . . . . . . . . . 13806. 13682 \fp_min:nn . . . . 13767. . . . . . . 13804. . . . . . . . . . . . . 13746 \fp_gcos:cn . 13716 \fp_const:Nn 168. . . . 13818 \fp_gexp:Nn . . . . . . 13818. . . . . . . . 13780 \fp_if_zero_p:N . . . . . 13801 \fp_gadd:cn . 11446. . . . . . . . . . . . 13804 \fp_mul:Nn . . . . 13818 \fp_gtan:Nn . . . . . . . 14533. 169. . . . 13713. . 13751 \fp_if_exist_p:c . . . 13725 \fp_gset_eq:NN . . . 9947. . . . . . . . . 171. . 13804. . . . . . . . . . . . . . . . . . 9906. . . . . . . . . . . . . . . . . 13764. 13784. . .fp_gset:c . . . . 13718. . . . . 11412. . . 13847. 11333. . . 13742. . . . . . . 13740. . . . . . . . 14796. . 13825 \fp_flag_off:n . . . . . . 9906. . . . . . . . . . . 13814 \fp_do_until:nn . 13818 \fp_gcos:Nn . . . . . . . . . . . . . . .fp_gset:N . . . . . . 13813 \fp_gneg:c . . . . 13818. 170. . . 13748 \fp_gtan:cn . . . . . 13732. 193. 13804. . . . . . . . . . 172. 13734. . . . . . . . . 11333 \fp_if_flag_on:n . 13725. . 11412. . . 13818. . . . . . 13786. 11335 \fp_compare_p:n . . 13818 \fp_gsin:Nn . . 13848. 11421. . . . . 13873. . . . . 11333 \fp_if_exist:NTF . . 13804. . . . . 13729 \fp_gzero:N 168. . . . . 13736 \fp_gzero_new:c . . . . . . . 13817 \fp_ground_figures:Nn 13868. . . . . 11418. . . . . 13818 \fp_exp:Nn . . 13724. . 14291 \fp_compare:nT . 13802 \fp_new:N . . . 14098. . . . . 13818 \fp_cos:Nn . 14067. 13818. . . . . . . . . . . . . . . . 11422 \fp_do_while:nNnn 171. 13682. .Index \fp_compare:NNNT . . . . 14680 \fp_pow:cn . . . . 13818. . 13784 \fp_neg:N . . . . . 9908 \fp_if_undefined:N . . . . . . 13805. . . . 174. 13867 . . . . . . 13818. . . 13827 \fp_gsub:cn . . 172. . . . . . 170. 180. . . . . . . . . . . . . . . . . 6737. . . . . 13742. . . . 11335 \fp_compare_p:nNn . 13725 \fp_gset_eq:cN . . . 13736. . 11333 \fp_if_exist:N . . . . . . . 11348. . . . . 13785. . 9908 \fp_if_flag_on_p:n . . . . . . 13805. . . 13716 . . . 168. . . 172. . . . . . . . . . 13913. . . . 6586 . . . . . . . . . . . . . . . . 13806. . . . . . \fp_until_do:nn . . . . 170. 9920. 5704. . 13596. . . . 9320 \g__file_record_seq . . 2587. . . . . 14084. 13963 \g__file_internal_ior . . . . . . . . . .fp_set:N . . . . 4963. . . . 5703. . . . . 9118. . . 13472 \fp_to_scientific:n . 13749. 9333. 14712 \fp_set_eq:cc . 7110. . 3730. . . . 3078. 14727. . . . . 170. 13749. . . . . 14139. . . 11457 . . 152 \fp_set:Nn . 9168 \g_peek_token . 13818 \fp_sin:Nn . . . . . 10032. . 13681. . . 9955. 14083. . . . 13525. . . . 9369. 13747 \fp_tan:cn . 9332. 13920. 11452. . . 10033. . 9164. . 9329. 169. 4965. . 2148. . . . 13741. 9343. . 14772. 169. . . . . . . 13739. . . . . . . . . 13725 \fp_set_eq:Nc . 13850. . 13729. . . . . . 13473 \fp_to_tl:c . . . . . . . 9275. 13878 \fp_round_places:Nn . 9205 \g__file_stack_seq 9056. . . . . 4960. . 13632 \fp_to_int:n . . . . 13804. . 13470. . . 743 . . . . . . . . . . . . . 13677. 13868. . . 13716. 14794 \fp_set_from_dim:Nn . . 9062. . 11437 11440. . . . . . . . . 13594. . . . 169. . . . 13525. . . . . 13685 \fp_to_dim:c . 14687. 13679. . . . . 2593 \g_file_current_name_tl . . 9898. 3727. . . . . . 14203. . 9119. 13760 \fp_show:n . . . 13716 . . . 168. . . . . 13727. . . 13829 \fp_to_decimal:c . . 13734 . . . \fp_until_do:nNnn 171. . . . . . 9644. . . . 13913. . 13677 \fp_to_decimal:n . 13631. . . 58. . 13731. . . . 9324. . 9324. . . . . . 13633 \fp_to_scientific:c . . . . . 13631 \fp_to_int:N . . 43. . 9102. 169. . . 9167 \g__ior_streams_prop . 11424. . . . . . . . . . 13961. . . . . 14781 \g__scan_marks_tl 2584. . . . . . . 14711. . . . . . . 14085. . . 172. . . 9164. 13960 \g__cctab_stack_seq . 170. 13594. 160. . . . . . . . . 9050. . . . 9283 \g__ior_streams_seq . 8381. 9062. . . . 14624. 13525. 9360. 152 \fp_set:cn . . 9980. 14798 \fp_show:c . . 9056. . 13594. . \frozen@everydisplay . . . . . 13952. 2372. . . . . . . . 13595. . . . . . . . . . . . . 174. . . . . . . . . . . 8426. . . . . . . . . . . . . . 13739. . 13913. . . . . . . . 6433. . . . . 13752 \fp_to_tl:n . . . . . . . . . . . . 14774. . . . 9210. . . . . . . \fp_use:N . . . . . . . . . \frozen@everymath . . 13528. 13922. . . . 3077. 3088 \g_tmpa_bool . . 13804. . . 9162. . . . . . . . . . . 11460. . . . . . . . . 9216. . 13955. . . . . . . . \fp_zero:c . . 13741. 8479. 13913. . . . . . 13924 \g__cctab_stack_int . . . 13737 . 7077. 13725 \fp_set_eq:NN . 13915. . . . . . . 9098. . . . . 14265. . . . . 13722. . . . 13527. 11432. . 14251. . 6092. . . . . 9376 \g__iow_streams_seq . . 14616. 13827 \fp_sub:cn . 9218. . . 13470 \fp_to_scientific:N . 2584. . . . 9329. . . 14264. . 9276. . . 6091. . 14543. . 14231. . 13626. . . . . . 9045. . . . . 13733. . . . 10034. 13758 \fp_sin:cn . . . . 13627. . . 9057. 9370 \g__keyval_level_int . . 193. . 13631. 13749 \fp_show:N . 13678 11412. . . . \futurelet . . . 744 . . 13729 13729. 11465 . . . . . . 13629. . . . . . . . . . . . . 9045. 13950. . 6094. . . 13953.Index \fp_pow:Nn . . 13677 13677. . 13729. . . 8477. . 9057. 13818 \fp_tan:Nn . . 13866 . 9185. . 13628 \fp_to_dim:n .fp_set:c . . 14236. . . 6584. . 13808. . 3734. 168. . \fp_while_do:nn . . 13470. 14794. . 2150 \g_tmpa_box . . . \fp_zero_new:N . . . . 13470. . . . . 14685. 9157. . . . 13626. 13725. . . 13749. . . . . . . 13759 739 \fp_trap:nn . 6097. . 13818. 10035 11412. . . 13956. . . . . . . . . . . 9165. 6427. . . 9989. . . . . . \fp_use:c . . 13525 \fp_to_decimal:N . . 9368. . 13683. 9277. 9216. 9212. . . 7085. . 13808. . . . 9320. 9326 \g__iow_streams_prop . . \fp_zero_new:c . 13914. . 13739 \fp_sub:Nn . 13818. . . . . 9331. 14128. . . 332 G \g__cctab_allocate_int . 4961. . . . . 3748. . . 13816 \fp_round_figures:Nn 13868. 3737. . . . . . . . . . . . 14729 \fp_to_int:c . . . . . . . . . . . . 13626 \fp_to_dim:N . . . . . 13850. 8475. . . . . . 8481 \g__prg_map_int . . 9099. . . . . . . 6428. 13626. . . . 174. \fp_zero:N 168. . 13630. . . . . . 7075. . 9250. . 9946. . . . . . . . . . . . 10018. . \fp_while_do:nNnn 172. 13733 13733. . . . 14794. . 13725. 14201. . . . . 13716. 13725 \fp_set_eq:cN . . 6430. . 5696. . 9267. . . . 9920. 13594 \fp_to_tl:N 170. . 8381. . 11429 11440. . . . . . . . 5697. 9054. . . . . . 9897. . . . . . 38. 9326. . . . . . . . . . 13631. . . . . 13916. . . 130. . . 9210. 8451. . . 14253 \fp_set_from_dim:cn . . 2372. . . . . 14544. . . 6642 \hbox_set_inline_end: . . . 685 \glueshrinkorder . . . 2333. . . 740 3024. . . 14277. . . 4497 \g_tmpb_tl . . . . 13992. . . . . . 9. . . 5773. . . . . . 3250. 5776 \g_tmpb_skip . 14246. 9. 6239 \g_tmpb_seq . . . . . . . . 7712. . . . 686 \gluetomu . . . 790. 14358. . 4112. . . . . 82. . . 2354. . 6624. . . . . 14374. . 1459. 2151 \g_tmpb_box . 11266. 4735. . . . 73. . . 8042. . . 6624 \hbox_set:cw . . . 795. . . . . 3109. . . . 15112. . . . . 14311. 6846 \hbox_set_inline_begin:c . 6172 \g_tmpa_dim . . 11533. . . . 152 \GetIdInfo . . 9405. . 10261. 684 \gluestretchorder . . . . . 14082. . 14108. . 9. . . . . . . 6. . . 6645 \hbox_gset_end: . . . . . . . . . . . . . 7695. 791. 9090. . . . 6642. 6646 \hbox_gset_inline_begin:N . . 527 \hangindent . 6645 \hbox_gset_inline_end: . . . . . . . . . . 8226. 6625. . 2344. . . . . . . . . . 1477. . . 126. . . . 6899. 6628 \hbox_gset_to_wd:Nnn 131. 11311. . . . . . . . . . 11095. 6632 \hbox_to_wd:nn . . . . . . . . 4753. . . . . . . . 2213. . 8204. . . . . 8386. . . . . . 6842 \hbox_set_end: 132. . . . 82. . . . . . . . 14390. . . . 11030. . . . 15132 \group_end: . . 6646 \hbox_gset:Nn . . . 88. . . . 9410. . . . 3124. 2047. . . . 1597 H \halign . 4558 \g_tmpa_prop . . 11284. . 15119. 2339. 6625. . . . . . 3185. . . . . . 6648. 2212. . . . . . 7723. . 2818. 792. . . . . . 2720. . . 6644 \hbox_set_to_wd:cnn . 3127. 1901. . 131. 11137. . . 6584. . . 6627 \hbox_gset:Nw . . 111. . . 132. . . . . 9076. . . . 6651. . 85. 4404. . . . . . . . . . 131. 131. . 2333. . 8396. . . . 2868. . 2858. . . 6636. 14569 \hbox_set:Nw . . . . 11281. 682 \glueshrink . . . 2737. . . . . . . . . . . . . . . . . 14255. . 173. 6587 \g_tmpb_clist . . . . . . . 111. . . . . 6623. 13765. . . . . . 7547. . 2333. . . . . . . 13478. . 6642. . . . . . 2031. 3106. 8404. . . . . 7337. 6624.generate_choices:n . . 1076. . . 14302 \hbox_gset:cn . . . . . 15130. . . . . 4897. . . . 14283. 15121. . . 4494. 14261. . . . . . . 6628. 2708. . . . . 14238. . 6642. . . . . . . . 2826. . . . 4115 \g_tmpb_muskip . . 4406 \g_tmpa_fp . 7857. . . 5543. . 102. . . 14323. 4114 \g_tmpa_muskip . . . . 14331. 9473. 1464. . . . 6170. 342 \glueexpr . . . . . 338 \globaldefs . . . 795. . 131. 2728. . . 42. 307. . . 73. 9409. . 13989. 14107. . . 3101. 3091. . . 323 . . . . . 6634. 173. 2765. . . . . 2148. 11094. . . . . 4746. 6634. 13765. . . . 14366. . 11233. . . 5309. 5309. . . . . . . . . . 131. 2721. . . . 6641. . 14380. . . . 4407 \g_tmpb_fp . . . . . 5310 \gdef . . 5102 \group_begin: . . . . . 2772. . . . . 5076 \group_align_safe_end: . . . 11058. . 120. . 6173 \g_tmpb_dim . . 6621. 2724. . 6628. 7543. . . . . . . . . . 14209. . . . . . . 5528. . . . . . . . 14263. . . . . 6634. . . . . . . . . 6634. . . 5773. . . . 4496 \g_tmpa_tl . . . . 131. . . . . . 6642. 13767 \g_tmpa_int . 5309 \g_tmpb_bool . . 10840. . . . 10884. 584 \hbox:n . . 5538. 14196. 11110. 9414. . 120. . . . . . 6631. . . . 14226. . . . . 13301. . 102. . . 4494. . 14286 \hbox_set:cn . . . . . . . . 4901. . . . . 6647 \hbox_gset_inline_begin:c . . . . . . 6642. . . 7997. . . 14111. . . . 6634. . . . . 6626. . . 790. 6647 \hbox_gset_to_wd:cnn . . . 4112. . . . . 6653. 2164. . 7753. 11109. 6795. . . . 14194. . 10310. . . . 4728. . . . 11522. 1894. 6634. . . . 7482. . . . 4556. . . . . . 688 \group_align_safe_begin: . . . . 6611. 126. . 132. . 4404. 7392. 6638. 6637. . . . . . . 6651 \hbox_overlap_right:n . . . 14340. 6236. . . . . 6643 \hbox_set:Nn 131. . . 349 \hangafter . 9436. 6643 \hbox_set_inline_begin:N . . 8393. . . . . . . . . . . 14080. 14244. . . . . . . . . . . . 589 \hbox . 10254. . . . . . . 528 \hbadness . . . 7702. . 10315. . . 6648. . . 13768 \g_tmpb_int . 139 \global . . . . 11085. 6628. . . . . . . . 6644. . . . . . . . . . . . 7194. 4805. . 14346. 4556. . 14224. 14555. . . . 88. . 85. . . . 5775 \g_tmpa_skip . . . 1597 \group_insert_after:N . 3018. . . . . 6640. 11265. . . . . 2028. . 6628 \hbox_set_to_wd:Nnn . . . . . . 13482. . 6623. . . . 14293 . 4796. . . . . . . . . . 14087. . . . . 6651. . . 4559 \g_tmpb_prop . . . . . 6624. . 2335. . . . . . . . 6630. 1081. . . . 13293. 14315. . . 2359. . . 15160 \group_execute_after:N . . . 6639. . . 38. 132. 2042. . . . 7123. 6634. . . 1477. . 6633 \hbox_overlap_left:n . . . . . 6642. . 42. . . 4904. . . . 687 \gluestretch . . . . . 6642. 6238 \g_tmpa_seq . . . 6236. . . 6170. . 130.Index \g_tmpa_clist . . 6624 \hbox_gset:cw . . . . 7334. . 2780. . . . 24. . 3632. . 9686. . . . 3383. . . 191. 10596. 5618. . 11380. 773. . . . 9686. 6655. . . . 24. . . . . 793. 3387. . . 13248. . 12762. . . . . 2950. 12513. . . . . . 10765. 10381. 2015. . . . 12540. . . . 767. . . . . 10380. . 11288. . 775. . . . 13486. . . . . . . . . . . . 11848. . . 11350. . . . . 10509. . 493 \hfuzz . . . . 6648. . . 10132. 10677. . . 780. 1515. . 11001. . 13218. 5187. . . 11383. . 11037. . 2805. . . . . 12769. . 766. . 9565. . . . . . . . . 9910 \if_dim:w 88. . . 4256. 2968. 2517. . . 2334. . 11626. 10628. . . 3547. . . 10160. 6652. . . 13203. 1104. . . . . . . . . 13451. . 6843. . . . 741 5272. 2810. . . .Index \hbox_to_zero:n 131. 6650. 11225. . 2334. 780. . . . 1934. . . . . . 24. . 13587. . . . . 1526. 13370. . . . . 2785. . . 12942. 3420. . . . . 12377. 2089 \if_box_empty:N . 165. . . . . . . . . . . 530 \hskip . 12810. . 9292. 2496. . 2122. . 2795. 11567. . . . 6560 \if_int_compare:w . . 2935. . . . 3599. 9297. . . 11182. . . . . . . . . . 3386. . . . 5212. 2561. . 12401. . . 6558. 358 \if:w . . 6838 \hcoffin_set:Nn . . . . . 10094. . . . . 10788. . . . 2762. . . . 12773. . . 11403. . 12989. 2851. 766. 24. . . 13068. . 1129. 10461. . . . . . 24. 3383. 3610. 13381. . 6556. 3603. . . 2912. . 569 \hrule . 12901. . . 2502. . 5162. 13158. 10291. 134. . . . . . . . . . . 11494. 522 I pi . . 11237. 1318. 11115. . 11864. 2757. 2953. 9300 \if_false: . . . . . . 10725. . . 2775. 1147. . . 11170. 4161. . . . 5505. 13604 \if_catcode:w . . . . . 505 \hsize . . . 10754. 12995. 11840. 1021. 6656. 3607. 11650. 6655 \hbox_unpack_clear:N 132. 1925. 2843. 5624 \if_hbox:N . . 6791. . . 3866. 10711. . . 1070. . 11916. 7346. . . . . 10558. . . 10736. 11787. 4181. . . . . . 1957. 1958. . 10144. . . 11251. 42. . . . . 3143. . . 12837. . . . 2187. 13188. . . . 952. 135. 1016. . 15142 \if_meaning:w . . . . 13143. . . . . . 5152. 2800. . 10357. 772. 12542. . 5193. 781. 11293. 13356. . . 3052. 2089. 3605. 2541. . . 11127. 604 \hyphenpenalty . 7389. 10638. . . . 10102. . 5508. . . . 2890. . . 1300. . . . . 12731. . 766. . . 134. . 13278. . . . . 2206. . . . 13114. 496 \ht . 13613. . 6854 \hcoffin_set_end: . 2932. 9687. 6791. 1141. . 12392. 3148. . 10470. . . 5295. 5247 \if_cs_exist:N . . . . . . 11394. 6807. . 10845. . . . 132. . . . . 11270. . . . . 3070 \if_cs_exist:w . 793. . . 10196. . 9783. . 2528. . . . . 3383. . . . . 4293 \if_eof:w . . 6556. . . . 780. 9848. . . 2790. . 10564. . . . . 10106. . 591 \hoffset . . . . . 6791 \hcoffin_set:cw . . . . 13013 \if_bool:N . . . . . . . 11845. . 11841. 74. 11100. 766. 6838. . 2012. 10855. . . 10648. . . . . . . . 6654 \hbox_unpack:c . 10123. . . 136. 9292. . 2336. . 10482. . 4181. . 12127. . 1101. 2570. . 10135. . . . . 12853. . 3601. . 2893. . . . . . . . 10585. 13135. 9839. . . . . . 6853 \hfil . . 1132. 13423. 2534. . 969. . . . . 11020. 12869. . . . . 13340. 11406. 10300. . 11181. . 10675. 1954. . 12406. 1521. . 6838. 3061. 11692. 492 \hfill . . 5254. . . . 13111. 10444. 136. 2815. . . 6838. . . . . 495 \hss . . . . 13071. . 179 \if . . 10844. 13173. . . 3595. 10618. 3145. 1667. 1119. . . 3640. 11071. 13777 \if_int_odd:w 74. . 13513. . 13616. . . . 494 \hfilneg . . 1433. . . . . . . 5287. . . 13159. 24. 774. . . . 12701. 6655 \hbox_unpack:N . . . . . 13134. . 10664. 1560. 11765. . 803. . 15143. . . . . . . 12667. . . 10523. 10152. 11926. 10120. 6657. . 620 \hyphenchar . 1288. 74. 10689. 2915. . 13273. 1904. 2752. . 3597. . . 766. 6655. . . 10628. . . . . 566 \holdinginserts . . . . . . . . 3567. . 4278. 13339. . . . . 634 \hyphenation . . . 10448. . . 1030. 2769. 12982. . . 13126. . 7127. 1329. 13341. . . . . . 12696. 11409. . . . . . . 11402. 11900. . 6658 \hcoffin_set:cn . . . 2510. . 12984. . . . 6572 \if_case:w . . 15144 \if_charcode:w . 11397. . . . . . . . . . 1666. . . 937. . . . 4457. 13013. . . 12885. . . . 10201. . . 6556. 6655. . . 2834. 7274 \hbox_unpack_clear:c . 1113. 11630. 12917. . 2549. 10709. . 11917. 2848. 9849. 12526. . . 10084. 7429 \hcoffin_set:Nw . 13144. . . 2747. 11842. 13233. 13036. . . 10273. . . . 5149. . 4268. 13536. . . . . 13603. . . 3718 \int_compare:nNnT . 365 \ifhmode . . 2332 \if_mode_vertical: . . . 11680. . 3671 \int_compare:nNn . 179 \indent . . . . . . . . . . . . . . . . . . 4117 \int_convert_to_base_ten:nn . . . . . . . 5238. 13564. 11726. . 3608 \int_const:cn . . . . 731 . . 4160. 386 \input@path . . 3845. 12969. . . 12966. . . . . . . . . 9771. 5533. . . 9765. . . . 2089. . . 4040. . . 10982. . . 9500. . . 13783. . 13921. . . 3992. . . . . 5560. . 766. . . . . . . . . . . . . . . . . . 24. 4042 \int_const:Nn . . . . 10159. . . . 3707. . . . . . . . 4110. . 3441. . 24. . 3426. . . . 10676. . 11923. . . . . . 5900. 4033. 11661. . 10535. 5155. 11372. 10213. . . . . . . . . . 66. . 5953. . . . . 9675. . 4020. . . . 12736. . 11537. 4096. . 3676. . 3608. 10232. . . . . . . . . . 9688. . . . 3763. . . . . . . . . . 3684. 176. . . . 11920. 12510. . . . . 14418. . . 10093. 3466. . . . . 3514. . 69. . . . . 4041. . . . . 388 \insert . . . . . . . . . . . . . . . 12126. . . . . . . . . . . . . 2090. . . 370 \ifvbox . 766 \if_vbox:N . . . 3136. . . . . . . . . . . . . . 359 \ifcat . . . 4031. . . . . 5552. 13562. 10017. . 4862. 368 742 \ignorespaces . 372 \ifnum . . . . . . . . . . . . 11934. . . . 11527. . . . 3526 \int_decr:N . 10178. . 10083. 369 \iffontchar . . . . 4116. . . . . 66. 5915. . . . . . 13650. . . 4093. . . . 3616. 12608. 10873. . . . . . . . . . . . 3394. 4111. 3704. 4102. . 11809. . . . . . . 4107. . . . . . . 3466. 366 \ifvmode . . . . . . . . 63. . . 4118 \int_decr:c . . . . . . 9538 \int_case:nnn . . 10121. . . . . . 14510. 3699. . . . . 642 \ifdim . . . . . 4094. . . . . . . . . . . . . . . . . 4119 \int_convert_to_symbols:nnn . . . . 776. . . 779. 9719. . . 42. . 4286. . . . 10412. 11374. . . 13535. . 9272. . . . . . 4098. 9108. 65. . . 4099. . . . . . . . 367 \ifx . . . . . 643 \ifdefined . 371 \ifinner . . . . 12687. . . . 9658. . . . . . 11488. . . 4105. . . . . . 4095. . . . . . . 6417. . . 9365 \int_compare:nTF . 64. . 10133. . . . . 4030. 12951. . . . . . . . . . 67. . . . . . 4103. . . . . . . 374 \ifmmode . . 12438. 11610. . . . . . . . . . . . 3608 \int_compare:nNnF . 3616. 62. 778. . . . . . . . . . . . . 13099. . . . . . . . 12058. . . 24. . 2238. . . 512 \initcatcodetable . 361 \ifodd . . . 9866. . . 12360. . . . . . . . 9763. . . . . 3522. . . . . . . . . . 9764. 12427. . . . 4032. . . . . . . . . . . . . . . . . 3839. 776. 3665. 15145 \if_mode_horizontal: . . . . . . . . 5094. . . . . . . 11487. 62. 3656. . . . . . 3447 . . . 776. 11985. . . 14413. . . 24. . 63. . . . . 4037. 9770. . . . . 3526. 4108. 11594. . . . . . 12129. . . 152 . . . . 12994. 3442. . . 14. . . . 776. . . . . . . 11516. . . . 2328 \if_mode_inner: . . . . . . . . . . 2330 \if_mode_math: . . . . . . . . . 134. . . 4100. . . . . . . . . . . 10292. 9699. . . . 11342. . . . 3533. . . 4039. 11666. 4106. 3519. . 568 \insertpenalties . . . . 378 min . . 3625. 14852. 3514 \int_add:Nn . . 360 \ifcsname . 9126 \inputlineno . . . . . . . . . . 9709. . . . . . 15093 \int_compare:nNnTF 65. 4016. . 3486. . . . . . . . . 4034. 15105 \int_compare:nT . . . 10541. 13373. . 6556. . . . . 364 \iffalse .Index 2971. . . 14952 \int_compare:n . . . . . . . 363 \ifeof . . 4097. 4885. 11627. 3579. 12350. 4070. . . 10105. . 12963. 14446. . . . . 13264. . . 2468. 3693. 13426. . . . 11369. . . 3535 \int_div_round:nn . 672 \ifhbox . . . . 13485. 3044. 13953. . . 9488. . . 13095. . 14809. . . . . 3394 \int_add:cn . . . . 777. . 13653. . . . . . . . 212. . . 13838. 3757. 6557. 11733. . . . . . 2156 \if_true: . . . . . 2326 \if_num:w . 4116. 12136. . . . 3468. . . . 3560 \int_compare:nF . . . . . 10979. . 4237. . 4029. . . . . . . 3560 \int_compare_p:nNn . . 9864. 9759. . 4038. 11371. . 11370. . . . . . . . . . . . 9772 \int_convert_from_base_ten:nn 4116. . 373 \ifvoid . . . . 10216. 3648. . . 3560 \int_compare_p:n . 14839. . 10132. . . . . . . . 178 sin . . . 152 \input . . 416 \immediate . 3514. . . 362 \iftrue . 14411. . . . . . . 6562 \ifcase . . . . . . . . 4900. 3753. . . . . . 4109. . . 64. . . 10143. . . . 73. . . . . 4850. . 11601. . 12750. . . . . . . . 5937. 3470. . . . 6379. 3466. . 12181. . 3177. . . . 13316. . . . 4036. . . . . 9487. . .initial:n . . 4392. . . 24. 776. . 3528. . . 4161 \if_predicate:w . . . . . . . . . .initial:V . . 10239. . . . 4874. 10120. 10985. . . . . . . . . . . . . . . . . . . . . . . 4104. . . . . . . 4101. . . . . . 11821. . . . 12939. . . . . . . 9111. . 14426. . 3401. . . . . . . . . . . . . . . 571 \int_abs:n . . 4035. . . . . 9758. . 3436. . 11373. 9757. . . . . . 3646. 4023 \int_from_hexadecimal:n . 3526. . . . 13960 \int_gzero:c . . 3392. . . . 64. 3905. 3516. 8613. . 3499. . . 4089. . 6613. . . . . . 4960. . . . 3506 \int_gset_eq:NN . . . 3988. . . 4089 \int_show:n . 3534. . . 3542 \int_gset_eq:cc . . 3389. . 67.int_gset:c . . . 5696. 14450. . . . 4027 \int_from_roman:n . . . . . 3507. . . . . . . 3696. . 3750. 3501. . 71. .Index \int_div_truncate:nn . . . . . . . . . 4059. . . . . . . 5001. . 4066. . 3901. 4024. . . . . 3538. . . . . . 3898 . . . . . . . . 14837. . . . . . 4091 \int_step_function:nnnN . . 3747 \int_step_inline:nnnn . . . 3771. . . 3896. 3750 \int_to_base:nn . 3725. . . . . 4117 \int_to_binary:n . 3514 \int_sub:Nn 64. . . . . . . . . . . 5704. . 2476. . 2477. . 64. . 3993. 72. . . . 9443. . . . . . 14415. 72. . 3532. . . . . 3503. 9396. . 3538. 71. . 4010. . . . . . 4089. . . 2372. . . . 4168 \int_from_alph:n . . 3520. . . . . . 3473. . . 3530. . 3619. . . . 4043. . . 3526 \int_gdecr:N 64. . . . 3662. . 6433. . . . . . . . . . 15107 \int_eval:w . . . 3458 \int_new:N 63. . . . 3501. . . . 3849 \int_new:c . . 4166. . 3426. 9317. 69. 3394. . 3536. . . . . . 71. . . . . . . . . 3541. . . 4164. . 3502. . . 4114. 63. . . . . . 4043 \int_gadd:cn . . . . . . . . . . 13952 \int_gdecr:c . . 3510. . . . . . 4028. . . . . 3402 \int_min:nn . . . . . . 3993. 8475. . . 3465. . 3525. 3526. . . . 9393. 3915. . . . . 3483. . . . 6427. . . . . . 9397. 4119 \int_from_binary:n . . . 14428. 4112. . . 70. . 8495. . . 3513 \int_if_exist:cF . . . . . . 3449. . 1326. . . . . 3630 743 \int_if_exist:c . . . 3524. . . . 9485. . 6091. 3750. 9544 \int_to_Alph:n . . . 8481. . 3858 \int_do_until:nn . . . 6603. . 3514. 3521. . . 3506 \int_set_eq:NN . . . . 3512 \int_if_exist:N . . . 71. . 3537. . . . . . 13920. . 4167 \int_eval_end: . 3630 \int_if_even_p:n . . 8639. . . 68. . . . . 3725. . . . . 3836. . . . . . . . . . . . . . . . . 3506 \int_gset_eq:Nc . . 68. . 3500 \int_gzero_new:N . . 14032. . . . . . 70. 9258. 69. 3506. 3668. . . . . . . 3540. . . . . 3803 \int_to_alph:n . . . . . . . . 63. . . . 3514. . . . 14854. . . . . 72. 3526 \int_incr:N . . . . . . . 4068 \int_if_exist:cTF . . . . 6612. . . . . . . . 63. . . . . . 3672 \int_do_until:nNnn . . 3995. . . . 6145. . . . . 4090 \int_show:N . . . . 4025 \int_from_octal:n . . . . . . . . 3630 \int_if_odd_p:n . 4023. . . . . . . . . . 8617. . . . . 63. . 67. . 3509. . . . . . . 3974. . . . . . . . . . . . 4965. . . . . . 3518. 3458. 3500. . . . . . . 3638 \int_if_even:nTF . . . 3835. . . . 3538. . . . 3512 \int_if_exist_p:N . . . 3388. 4166. . . . 63. 3666 \int_do_while:nNnn . . . . . . 13914 \int_set_eq:cc . 3732 \int_sub:cn . 3540. . . 69. . . 3512 \int_if_odd:n . . . 3472. . 4019. . . 4023. . . . 9506 \int_max:nn . . . . . . . . . . . . . . . . . . . . . 3497. . 9437 \int_show:c . . . . 3734. . . . . 6136. . . . . 152 \int_gset:cn . 3511. . . . . . . . . . 3531. . . . . . . . . . 64. . . 3506 \int_set_eq:cN . . . . . 3526. 63. 3514 \int_gadd:Nn . . . . . . . . . 9395. . . . . . . . 3410 \int_mod:nn . . . 71. . . . . . . . . . . . . 3702. . . . . . . . . 4023. 3714. 3426. . . . . . . . . . . . . . . . 8643. . 64. . . . . 9315. . . . . . . . . 3505 \int_if_even:n . . 9394. . . . . . . 3725. . . . . . . . 4091. 69. 9351. . 3538 . . . . . . . 3690. . . . . . . 4115. . . . . . . . 72. . . 3646. . 3526. . . . . 14772 . 3506 \int_set_eq:Nc . 13915 . . . 4026. 3748. 3972. 3523. 2478. . . . 70. 3508. . 3394. 67. . . 72. 3514 \int_gsub:Nn . . 63. . . .int_set:c . 152 \int_gset:Nn 64. . 152 \int_set:Nn 64. 3503. . . 152 \int_set:cn . . . . 3506. . . . . 3758. . . . 67. . . . . 9664. . 3702. . 63. . . . . . 3526 \int_gincr:N . . . 5727. . . . 3496 \int_gzero:N . . . . . . . . 9457. . 1342. 9513. 3674. . . . . . . . . . . . 14781 \int_gincr:c . . . . . .int_gset:N . 14037 \int_step_variable:nnnNn . . 3896 \int_to_hexadecimal:n . 9411. . . . . . . . . 3897. .int_set:N . . . . . . . 3630 \int_incr:c . . . 8721. . . . . . . . . 3835. 3700 \int_do_while:nn . . 8717. . . . . . . 13913. . . 15026. . . . . . 3992. 3459. . . . . . 67. . 9398. . . . 5006. . . . . . . . . . . . 3896. 6614. . . . . . . . . 64. . 3512 \int_if_exist:NTF . . 3630 \int_if_odd:nTF . 3503 \int_gzero_new:c . . 4113. 3506 \int_gset_eq:cN . . . . 3899. . . . . . . . . . . . . . . . 3496. . . 3722. . . . 62. . 3768. . 15091. . . . 3694 \int_eval:n . . 3674. . 3771 \int_to_arabic:n . 3514. . . . . . . . . . 3482. . . 64. 3506. . . . 3771. 3538 . . 3972 \int_from_base:nn . . . 67. 8381. . . . . . . . . 7740 \int_gsub:cn . . 3512 \int_if_exist_p:c . . . . . . . . . . . . 3426. . . . . 6097. . . . . . . 3727. . . . . . . . . . . . 9607. 11995. . 3413. . 162. . 9335. 162. . . 9606 \ior_if_eof:N . 11785. . . 3773. . 4170. . 68. . . . 3896. . . 10508. . . . . 12645. 3431. 12038. . . . 12007. 9605. 12387. 12643. 3496. . 9607. 12048. . . . 12649. . . . 4171 \int_while_do:nn . . 9873. 12936 \iow_close:c . 12074. . . . . 12260. . . 12101. 9427. . 9374 \iow_indent:n . . . 3646. . . . . . 9270. . 4122 \int_to_symbol_math:n . . 11722. 11964. 68. 12158. . . . 11778. . . . . 14766 \ior_new:c . 3659 \int_until_do:nNnn . 162. . 11691. . . . . . . . 6092. . . . . 9605. 12311. 12624. . . . . . 71. . 11065. 670 \interlinepenalties . . . . 3500. . . . . 3679 \int_zero:c . . . 12071. . . 12633. 9392. . . 10238. . 9375. 10796. 12308. . . 13318. . 11791. . . 691 \interlinepenalty . 4126. 12651. . 2034. 3767. 11745. . . 12464. . 13326. . 12277. . 10794. 9199. . 192. 14762. 13450. 10557. 9249. 10119. . . 161. . . 13053. . . 9622 \ior_map_break: . 13863. 8629. 13048. . 6094. . . 9459. . . 12637. . 3651 744 \int_while_do:nNnn . . . . 9387. 11966. . 162. 1171. 12240. 4146 \int_until_do:nn . . . . . 9363 \iow_close:N . . 9336 . 10057 \iow_list_streams: . . 9282. 9622 \ior_str_gto:NN . . . 11756. . . . 4127. 8451. . . 10497. . 4129 \int_to_symbol_text:n . . 11894. 12249. . . . 8644. 9235 \ior_open:NnT . . . 9102. . 3900 \int_to_Roman:n . . 13413. . . 14763. . . 12211. 3730. . . 12623. 9335. 4144 \int_to_symbols:nnn . 12251. . 12683. 3414. 164. 10595. . 9270 \ior_close:N . 11956. . 3563. 9236 \ior_open_streams: . . . . . 3405. . . 14766. 8479. . . . 7729. 9427. . . . 8618. 12598. . 11997. 3543. . . . . . . . 4121. 12103. . 4131. 3751. . . 11720. 7854. . 11976. . 12314. . 12562. . 3654. . . . . . . . . . 12532. . . . . . . . 192. . 9119. . 12596. 12199. . 14762. . 9621. 10767. . 162. . . 13277. . 12289. 163. . 9222. 63. . 5703. 9099. 3430. . 161. . 3682. . . . 3646. . 9317. . 12254. . . . . 3498. 3902. 12088. 8610. 11876. . . 12604. 9608 \ior_str_map_inline:Nn 192. . 10588. . . . . . 9234 \ior_open:NnTF . . . 12068. . 4118. 3805. 14774 \int_value:w . . . 10774. 12591. 10195. 9221. . . . 4961. . 9220. 7662. 12263. . 9232 \ior_open:NnF . 10594. 12279. 10742. . 10440. 3902 \int_to_symbol:n . . 8075. . 9320 \ior_open:cn . . . . 12219. . . 12635. . 8714. . 12622. . 12321. 12233. 6428. 70. . . 12385. 3496 \int_zero:N 63. . 163. 13056. . . . . . . . 8426. . 10783. . 12035. . . . . 9387 \iow_new:c . . . 12091. . . . . . . 3543. . 9282. . . 9220. 9342. 14780 \ior_map_break:n . . . . . . . . 9198. 12631. . . . 9605. 9293 \ior_if_eof:NF . 9461. . . . . 11974. . . 5697. . . . . 14764 \ior_map_inline:Nn . . 9375. . . . . . . . . 12639. . . . . 3501. . 9606 \iow_char:N . 12077. . . 9222 \ior_open:cnTF . 11801. 3544 \int_use:N . . 14786 \ior_if_eof:NTF . 9311. 14762. . . . 12085. . 68. 11878. . 9222. . 14779. . . . 7730. 9605. 13496. . . 3543. . . . . 12094. 9224. . . . . 4963. 12192. 9605. 3544. . . 12626. . . . . . . . . 9311. . 14765. . . 161. . 3428. . . 12647. . . 65. 11968. . . 12484. . . 9293 \ior_if_eof_p:N . 12119. 11743. 9392. . . 3687 \int_use:c . . . 12675. 4092. 161. . . . . . 8477. 12160. . 12221. . . 12121. 12818. . . . . . 9309. 3500 \int_zero_new:N . . 9232. 12457. . . . . 4121. 12299. 9532 \int_zero_new:c . 10744. . . 12653. 12297. 4121. . . 3500. . . 12231. . 13062. 12009. . 9670. . 12147. . 3912 \int_to_roman:n . 3737. . 13330. . 13321. . . . 7731. 9608 \ior_to:NN . 13078. 3646. 11803. . 3674. 12149. 11754. . 11896. . 193. . . . . . . . . . 3902. . . 12765. . . 9309. . 9446. . 9270. . . . 12625. 3397. . 3504 \interactionmode . . . . 12173. . 550 \ior_close:c . 9335 \iow_new:N . . 10199. 12287. . 13332. 9388 \iow_log:x . . 9220 \ior_new:N . . . 6430. 12564. . . 68. 12621. . 3496. . 14769 \ior_gto:NN . . . 8722. . . . 12578. . 9293 \ior_list_streams: . 12109. . 12422. . 12046. . . 9363. . . . 13050. . . 9363. . . 7601. 163. . 1171. 9605. . . 71. . . 14766. 3406. . . 163. . . 3674. 12257. . 9281 \ior_get:NN . . 1210. 71. . . . 14767 \ior_get_str:NN 162. 9387. 12482. . . 13328. 3674. . . 9623 \iow_log:n . . . . 13059. . 9232 \ior_open:Nn . 12340. 9197. 3751. . . . 12566. . . .Index \int_to_octal:n . 12117. . 11970. 14768 \ior_str_to:NN . 8111. 11972. . . . . 10045. . 13518. . . . 8504. . . 14326. . . . . 7705. 9337. 9610 \iow_now_when_avail:Nx . . 156. . . . . . 14305. 14107. 14375. . . 9030. . . . . . . 9384. 14066. . 9612 \iow_open:cn . 189. 14268. . . 9613 \iow_now_buffer_safe:Nn . . . . . \keys_show:nn . . 9609. . 14283. 14190. . . . 9383 \iow_shipout:Nx . . 14150. 9384. . 8851 \keys_set_known:nvN . 9029. 9599. 14073. 14301. 7684. . . . 7683. . 9378. . 9384. 9615. . . . 163. . 8851. . . . 14114. . 9390. . 9029. . . 189. 8688. 8692. . 14074. . . 9390 \iow_term:x . . . . 8992 \keys_if_choice_exist:nnn . . . 14267. . . . . 14069. 14077. . . 14155. . . . . . . . . 9434. . . . 14067. . . 14249. . . . 8964 14185. K 14374. 14165. . . . \kern . 8863 14121. . . 7691. . 9389 \iow_wrap:nnnN . 7707. . . . 14183. . . . 14069. . 14159. 14119. 14073. 9381. 9600 \iow_wrap:xnnnN . 9380 \iow_shipout_x:Nx . . . 14076. 14148. . 14275. 7736. . . . . 9619 \iow_now:Nx . . 14397 \keys_define:nn . 14077. . . . 14289. . . 14085. . . . . . . 14084. . . . . 9029. . 503 14382. . . . . 8282. . . . . . 8841. . . . 14301 \keys_set_known:nVN . . 14273 . 14108. . . 14198. 14130. . . 9378 \iow_term:n . \keys_set:no . 9617. 14166. 9454 \iow_now:Nn . . 14066. 7730. . . . . . . 14159. . 8958 \l__box_left_new_dim . . 7709. 14187. . . . . . . . 14228. . . . . 14170. . 14216. 14188. 14273 \l__box_bottom_new_dim . . . 14072. 14272. \jobname . . . . 14219.Index \iow_newline: . 14120. . . . . 8858. 14253. . 14265. . 9391. . . . \keys_set_known:nnN 157. . 9388. . . 14252. . . . . . . . . . 14275 \keys_set:nv . . 14172. . . . . 9434. 14070. . . . . . 14346. 14071. . . . 14296. 14173. 14230. 1171. . . . \keys_if_choice_exist:nnnTF . . . 150. . . . . . 8964 \l__box_left_dim . 9617. . . . . . . . . . . . 14203. . . 14165. . . . . . 8841 14229. 14366. 14291 \keyval_parse:NNn . 8697. . 14151. . 14395. . . . 14217. 14381. . . . 14250. . 9616 \iow_now_buffer_safe:Nx . 164. . . . . . . . . 14380. . . 14181. . . 14217. . . . 14269 \keys_if_exist:nn . . 14154. . . 14190. . 14340. 9387. . 8958 \keys_if_exist:nnTF . 14274. . . 9391. . . . 14185. . . 9389. 7736. 8851 14215. . . . 14295. . 9611. . 9378. . 14248. 14190. . . . . 14231. . . . . . . . 14236. . . . . . . 14290. 8841 14174. . . 9621. . . . . 163. . . . . 14153. . . . 14358. 7735. \KV_process_no_space_removal_no_sanitize:NNn 14191. 8849 \l__box_right_dim 14069. 14073. . . . . . 14315. 14290 \l__box_cos_fp . 8258. . . . 14142 \l__box_internal_box . . . 8260. 1202. 8504. . . . 14177. 14338. . . 14093. . . . 14163. 14328. . 14234. . J 14336. 14293. 9337. . . . 163. 9387. . . . 189. . . . 7852. . \keys_set:nV . 14085 \l__box_bottom_dim . . 8841. . 14174. . 9339 \iow_open_streams: . . 7593 \l__box_angle_fp . 14393. . . 8851 \l__box_scale_x_fp . . . . . . 9619 745 \KV_process_space_removal_no_sanitize:NNn . 157. 14176. . 14170. . \keys_if_choice_exist_p:nnn . 159. . . . . . . 14323. . . . . . 8509. . . 14184. . 189. \keys_if_exist_p:nn . . . . . . . 8473. . 14119. 14351. . . . . 9381. . . . . . . . . . . . . . . 14098. . 8841 \l__box_right_new_dim . . . . 189. . . . . 14067. \keys_set_known:noN . . 8970. . . . 9386. . . . . . . . . . . . 157. . . 14095. . . 14075. 14164. . . 14200. . . 9618 \iow_now_when_avail:Nn . . 9598. 157. 1173. . . 14083. . . 9031. . . 8473. . . . 14162. . . . 8964 14161. 14201. . 625 14343. 9609. . . . . . . . 8958 14121. . . . . 9623 \iow_shipout:Nn . . . 14331. 14152. . . 14341. 162. 14094. 157. 8851. 9032 14236. 14271. . 14154. 14353. . . 9337 \iow_open:Nn . 14186 \keys_set:nn . 14183. . 164. . 14371. 14150. 9030 L \l@expl@log@functions@bool . 157. . 14122. 8970 14251. 9615. . 14118. . . 9032 \l__box_scale_y_fp . . . . . . . . . 14390. . . . . . . . . 14348. . . . . . . . . . . 14253. 14349. 14206. . 14342. . . . 14103. 163. . 14175. . . . 9031 \KV_process_space_removal_sanitize:NNn . . 7737. . . 14369. . . 14264. . . 14376. 9381 \iow_shipout_x:Nn . 9387. . . . . . 14334. 14202. . . . . 14199. . . . . . . 8846. 14110. . . 7384. 7126. . 7240. . . 7330. 6719. . 6883. . 5891. . . 14701. 7290. . . . 5992. . 7362. 6741. . 14092. . . . . 7407. 14566. . 14713. 5989. 13948. 7167. . . 7282. 7135. 7318. 7277. . 7286. 7485. 14537. . . . . 14565. . 7363. 7020. 14721 . . . 7137. . . 6717. . . 6730. . 7316. . 14181. 7190. . 14160. . 13962. 7492. . . 7354. . . 7493. 7081. . 7429. 14717. 14627 \l__coffin_display_coffin . . 14564. . 6717. . 7449. . 7304. . . 14176. . . 6740. . 7469. 7194. . 7324. . 7136. 14270. . 14582. 7192. . 14713. . 7130. 14171. . 7177. . 7425. . 14666. 14073. 14583. . . . 14642. . . 7242. 7128. 7403. . 14559. 7441. 7125. . . 14118. . . 7170. . 7346. . 14069. . 7122. 14568. 7383. 7442. . . . 6739. 7314. 6830. 7280. . . . 7322. . . 6734. 7489. 7382. . 14567. . 14711. . . . 14149. 7414. 14559. . . . . . . 14643. . . 7216. . . . 6103. . . . 14218. 14568. . . . . . . . . . 7345. . . . . 7420. . . . . . . 7050. 14172. . . 7153. 6826. 6873. 7322. . . 7021. 14679. 7172. . . . 7406 \l__coffin_pole_b_tl . . 14687. . . 7359. 6120. 14266. . . 7015. . 7170. . 7161. 5892. 7487 \l__coffin_pole_a_tl . 7294. . . . . . . 14585. 6717. 7371. . 6038. . 14645 \l__coffin_scale_x_fp . . 6736. 14197. 7276. 7490. . 6718. . . . 7288. 5879. . 7446. 7495 \l__coffin_display_coord_coffin . . 7411. . 7408. 14717 \l__coffin_internal_tl . 7244. . . 14634. . 14206. 14675 \l__coffin_bounding_prop . . 6743. 14580. . . 14714. . 7312. 14131. 14681. 7401. . . 7280. 7361. . . 6727. 7159. 7405. . 14161. . . . 7214. 14654 \l__coffin_bounding_shift_dim 14536. 14148. . . 7171. . . . 14535. 7484. 14727 \l__coffin_scale_y_fp . 14550. 14660 \l__coffin_cos_fp . 7482. 14234. . . . . . . 14068. . . 6742. . . . 5995 \l__coffin_aligned_coffin . . 14555. . . . 7424. 7399. 14271 \l__box_top_new_dim . 7422 \l__coffin_internal_box . 7418 \l__coffin_display_x_dim . . . . . . . 14646. . . 14182. . 7357. 7141. 6742. 7150. . 7321. . . . 5878. . . . 7427 \l__coffin_display_poles_prop . 7017. 7139. . 14716. . 7281. 6732. 7404. . 6039. 7213. . 7323. . . 14536. . 7284. 14679. . . . . . . . 6901. 7486 \l__coffin_offset_y_dim . . . . 7437 \l__coffin_display_handles_prop . 7230. 6119. . . . . 7239. . . 14535. 7389. . . . . 14584. . . . 14187. 7152. 14289 \l__cctab_internal_tl . 7016. . . . 14644. . 14561. . . 14534. 6729. . 14227. . . . 14618. . . 7322. . 14635. . 7402. . . . . . 7491. . . . . 14586. . . . . . 7327. . 7280. 6167. . . . . . 7147. 14685. 7131. 6900. . . . 7280. 14569 \l__coffin_internal_dim . . . . . 13963. . 14681. . 7198. . 7468 \l__coffin_display_font_tl . 14219. 14659. 7320. . 7035. . . 14636. 7306. . 7181. . . . 5802. . . 7133. . . 14537. . 7358. . . 7298. 14647. 7246. . 7480. 7163. . 7129. 7140. . . . . . . . . . 7150. . 7296. . 5982. 7376. . . 7292. . 7334. . . . . . . . . . 8181 \l__clist_internal_remove_clist . . 14067. 189. . . 7020. . . 7494. . 5982. 14538. 7470 \l__coffin_display_pole_coffin . 6740. 7180. . . 7409. 6898. . 7178. 14084. 7479 \l__coffin_display_y_dim . . . 14537. . 7444 746 \l__coffin_display_offset_dim 7320. 7325. 14674 \l__coffin_offset_x_dim . 7242. . . 14141 \l__box_top_dim . . . . 14680. 7162. 14163. . 7481 \l__coffin_error_bool 6739. 6731. . . 13964. 7283. 7165. . 14247. . . 7324. . . 7300. 14096. 7160. 6878. . 14069. . . 14591. . . . . . 7179. . . . 7440. . 7406 \l__coffin_right_corner_dim . 7199. . . . 7445. 6735. 7201 \l__coffin_bottom_corner_dim . 7310. . 14653. 14544. . 6728. .Index \l__box_sin_fp . 6166. 6740. . 14729 \l__coffin_scaled_total_height_dim . 7147. . . . 7308. 6834. 7127. 14667. . 14539. 7283. 14537. 14719. . 7142. . . . 14533. 7460 \l__coffin_left_corner_dim . 7478. 5993. . 6733. 14578. . . . 7366. . . . 6102. . 5802. . 13986 \l__clist_internal_clist . 14073. . 7246. . 7123. 7325. 14152. . . 6717. 7302. . . . . 6726. . 14679. . 6898. . . 7495 \l__coffin_aligned_internal_coffin . . 7243. 6742. . . 7455. 7215. . 7403. 14712. . . . . 9185. 165 \l__file_internal_name_tl . 9113. 9215. . 7048. . 14721 \l__coffin_sin_fp . . . 9459. 861. 14590. 14565. 14682. 7053. . 9266 \l__iow_current_indentation_int . 9328. . 9531. . . . . 7867. 8505. . . 9512. . 9449. . . 6746. . . . . 264. . 14742 \l__coffin_x_prime_dim . . . 7867. 9191. . . 14633. . 8905. . . . . . . . . 7218. 8423. . 9498. . . 9919 \l__ior_internal_tl . . . . . . . . . . . 7025. . . . . . . 7975. 9132. . . 8445. . . . 8470 \l__keyval_sanitise_tl . 8454. . 8397. . . . . 8847. 9488 \l__iow_wrap_tl 9402. . . 9396. 7187. 9133. . . 7978. 8508. . . . 9068. 6745. . 8548. . . 7056. 7980 . . 9396. . . 1826 \l__expl_status_stack_tl . 7089. . 14602. 7479. . . 7188. 8502. . 14681. . . . . 9505. .Index \l__coffin_scaled_width_dim . 1649. . . . 8845. . 9539. 14540. . . . 9403. 14607. . 8931 \l__keys_no_value_bool . 9501. . 14619. . . . . . 9478. 9079. . 14609 \l__exp_internal_tl . . . 8400. . . . 9167. . . . . . 7. 8535. 1650. 7075. . . . 9485. . . . 7477. . . . . . 9168 \l__file_saved_search_path_seq . . 14766. . 9463. 9506. 9486. . 14733. . . . 9080. . . . . 9328. . 8403 \l__keyval_value_tl . 9215. . . 9462. . . . . 9454. . . 14543. 9550 \l__kernel_expl_bool . . 9110. . . 8461. . . 6744. . 14648. 9111. . . . 9519 \l__iow_line_start_bool . . . . 283 \l__keys_module_tl . . . . . . . 9916 \l__fp_overflow_flag_token . 7424. . . . . 7099. . 9230. . . 9399. 14533. 9916. . . . . . . . . 9530. . 7094 \l__coffin_top_corner_dim . . 8893. 9402. . . . 9461. . . . 7094 \l__coffin_slope_y_fp . 9069. . . . . 7210. 8861. 7080. . 7088. 9538. 9239. . 9067. . 9127 \l__file_search_path_seq . . 862. 14533. . . 9916. . 14739. . . 7041. . . . 138. . 8501. . . . . 14735. 14649 \l__coffin_x_dim . . 9495. 9396. 8856. . . 8872. 9395. 8441. 9500. 8530. 9399. 9917 \l__fp_invalid_operation_flag_token . 9343. . . . . 7193. . 9534 \l__iow_newline_tl . . 8382. . . . 9398. 8860. 9243 \l__file_internal_seq . . 8384. . . 6744. 9457. . . . 6738. 8515. . 9532 \l__iow_current_line_tl . 7211. . . . . . . . . 8526. . 9250. 9066. . 9511. 14592. 9091. 9067. 278. 9452. . . . 14788. 7065. 7477. 9110. 7481. . . 9404. 8855. 14537. . . . . . . 9499. . 8384. . . . 6737. . . . . 14604. 14739. . . 8940 \l__keys_property_tl 8501. . . . . 14598. 8427. 8563 \l__keys_unknown_clist . 8697. . . . 9918 \l__fp_underflow_flag_token . . 8456. . . . 9479. 7187. . 9474. . 7083. . . . 8520. . . 282. 7077. . 9401. . 8928. 7476. . 9227. . . 7063. . . 14596. . . . 9546 \l__iow_current_indentation_tl 9399. 8498. . . . 14792 747 \l__ior_stream_tl . . 857. 9487. . 9140. . 204 \l__file_internal_name_ior . 7218. 7476. . . 7098. 9086. 8552. . 9460. . . . 14608 \l__coffin_y_dim . . . . . . 9181 \l__fp_division_by_zero_flag_token . 8448. . 8452 \l__keyval_parse_tl . 7191. . . 8383. 9456. . . 1630. 7191. 9085. . 9518. . . . . . 8382. . . . . 9504. . . . . 9916. . . 9455. 9175. . . 9228. 857. . 7193. . . . . . . 9468. 6737. 8502. 14742 \l__coffin_y_prime_dim . . 9497. 7038. . 6744. . . 8498. 9066. . . 6747. . 14735. 14604. 9176. . 9400. . 9531 \l__iow_stream_tl . 6744. . 6744. 9113. . 7425. 8405. 8459. . . . . . . . . . . . . . 8401. . . 9544. . 8469. 9071. 9499. 8399. 7070. . . 14607. 8499. . . . . 9466. 9258. 14592. 9196. . 9072. . 7080. . . . . 7024. . 7965. . . . . 8384. . . . . . . 9198 \l__file_internal_tl 9065. . 14590. 165. . . 7957. 9516. . . 14598. . 9139. 8867. . 9512. . . . . . 9487. . . 9545 \l__iow_current_line_int . . . 9533. 1825. . . 9145. . . . 9081. 9551 \l__iow_current_word_int . . 8692. . 9519. . . . 8852. 8510. . 6737. 7033. 9403. . 9116. . . 8499. 9396. . . 14718. 14602. . . . 9359 \l__iow_target_count_int . . . . . 8385. . . . 14785. . . . . . 8457. 8398. . 8382. . . 9458. 7072. 8556. 9916. 9351. . . . . 34. . . 7188. 8883. 9395. 9082. 249. 14733. . . 14596. 9065. 9515 \l__iow_current_word_tl . 8842. . 9127. . . 14626 \l__coffin_slope_x_fp . 7974. 9513. 9404. 8878. . . . . . . 9112. . . 9397. . . . . . . 8937 \l__keyval_key_tl . . . . . 9488. . 8471 \l__msg_class_loop_seq . 8555. 8559. . 9399. . 9240. . . 7891. . 3118. . . . . 7916. . . . . . . . 616 \lastskip . . . 2148. . . . . . . . . 5436. . 8593. . . . . . 58. . . . . 53. . . . . . . . . 8629. . 3136. . . . . 111. 3080. . . 5489. . . . . . 8720 \l_keys_key_tl . . . 8642. . . . 2738. . . . 7911. 5529. . . . . . . 7970 \l__msg_hierarchy_seq . . 8877. . 8878. 8286. . . . . . . 6903 \l_tmpb_dim . . 8897. . 8640. . 3097. 5311. 6584. . . . 7966. . . . . . . 467 \linepenalty . . . . . . 507 \left . 8912. . . 5773. . . . . . 13765. 8730. 8573. . 7970. . 6707 \l_peek_token . 85. . . . . . . . . 4494. . . . . . 320 \limits . . . 173. . . . . . . . . 3098. . . . . . . 533 \leqno . 7894. . 6349. 2148 \l_tmpa_box . . . . . . . . . 3159. . 4556 \l_tmpa_prop . . 6584. . . . . . . 3077. 8684. . . . . 2742. . . . . . 5533 \l__seq_internal_b_tl . 70. . . 102. . 8634. . . . 8586. . . . . . . . . . . 120. 8545. . 6170 \l_tmpa_coffin . . . . . 157. 8503. . 6353. . . 5400. . . 157. . . . . 8289 \l__msg_redirect_prop . . 6170. . . 2725. . . . . 4163. . . . 3080. . . . . . 8722 \l_keys_choice_tl . . . 8941. . . . . . . 7939 \l__peek_search_tl . . . . . . 7983 \l__msg_current_class_tl . 3136 \l__prop_internal_tl . . 4404 \l_tmpa_fp . . . . 8911. . . 82. . 420 \lastbox . 138. . 8500. . 671 \lastpenalty . . 4909 \l_char_active_seq . 8907. 7576. . . 4112. . 4494. 9603 \l_keys_choice_int . . . . . . 8657. . 8646. 4404. 6236. . . . 73. 7866. 8610. 450 \let . . . 475 \lefthyphenmin . . . . . . . 8939 \l_keys_path_tl . . . . . . . . . . . 15145. . . . . . 88. 7866. . . . . . . 6171 \l_tmpb_coffin . . . . . . . . . . . 5515. 4556. . . . . . . 9458. . . . . . . . . . 73. . . 6902. . . . 3079. . . . 6329. . . . . . . 85. . . . 8575. . 7864. . . . . . . . . 8679. . . . . 5506. . . 13765. . . . . . . . 5773 \l_tmpa_skip . 5532. 5430. . . . . . . . 4404. 5533 \l__seq_remove_seq . . 8956 748 \l_keys_value_tl . 8931. . . 2148. 6902 \l_tmpa_dim . . 8652. . . . . . . 8616. 6170. . . . . 8691. . . . . . . . . . . . 8655. . . . . . 130. . 8708. . . 8614. . . . 5401. 8721. . . . 8618. . . 2149 \l_tmpb_box . . . 8878. . . 82. . 2725. . . . . 8530. . . 126. . . . . . . . . . . 518 . . . . . . . . . . . 2743 \l_iow_line_count_int . . 3168. . . . . . . . . . . . . 639 \leaders . 7891. 5478. . . 4164 \language . . 510 \lastlinefit . . . 4113 \l_tmpb_muskip . 8588. . . . . 8495. . 9393. . . 8590. 7912. 8578. . . . . . . . . . . . . . . . . . . . 9603 \l_iow_line_length_int . . . . 732 \lccode . . . . . . 111. . . . . . . . . . 6585 \l_tmpb_clist . 5485. 8601. . 7865. . . . . 5510. . . . . 8644. . 130. . . . . . 6236. . . 13766 \l_tmpb_int . . . 7956. . . . 3119. . . . . . . . . . . . . . 165. . . . . . . . . . 7865. . . . . . . . . . . . . . 7919. . . 9077 \l_char_special_seq . . . . . . . . 8909. 88. . . . . 3079. . 8756. . . . . 8617. . . . . 15148 \l_tmpa_bool . . 517 \lineskiplimit . . . . . . 15143. . 8560. . . . . . . 155. . . 6216. . 138. . . . . . . . . . . . . . . . . . . . . . . . 8949 \l_last_box . . . 157. . . 5774 \l_tmpb_skip . . 5442. . 5311 \l_tmpb_bool . 8925. . . . . . . . . . 7909 \l__msg_internal_tl . 7863. . . . . 511 \latelua . . . . . . . . 690 \lastnodetype . 6451. . . . . . . 173. . 6216. . . . 7879. 8887. . 15144. . . . . . . . . . . . . . 8696. . 307. . . . . 38. . 3169 \l__peek_search_token . 8604. 6455 \l__seq_internal_a_tl . 8495. . . . . . . . . . . . . 7936. 5488. . 8736. . . 8497. 6333. . . . 7927. . . . . . . 8542. . . 8496. 4557 \l_tmpb_prop . . . . . . . . . . . . . . . . 38. . . . . 8717. . . . 53. . . . . . . 4405 \l_tmpb_fp . 8718. . . . . . 5400. . . . . . . . . 8535. . 3077. . 4899. . . 9602. 8497. . . . . . . . 7904. . . . 4556. . . . 5. . . . . . . . 6332. 126. . . 8495. . . 8643. . . . . . . . . . . . 2725. . . . . . . . 8920. . . . . . . . 6237 \l_tmpb_seq . . 8571. . 3177. . 7576. . . . . 8897. . 7874. . . . . . 6706. . . 7863. 7968. . . 4908 \l__tl_internal_b_tl 4895. . 120. 8613. . 7863. . . . 155. . . . . . . 4898. 6454. . . . . 3086. . 8503. 4112. . 5773. . . . . 102. 9394. . 6902. 5510. 5311. . . . . . . . . .Index \l__msg_class_tl . . . . . . . 5441. . . . . . . . . . . . . . . . 9393. . . . 6584 \l_tmpa_clist . 8758. . . 13765 \l_tmpa_int . 8955. 308. . . 5478. . . . . . 60. . 4112 \l_tmpa_muskip . 8705. 8287. 7927. . . . . . . 4495 \l_tmpb_tl . 8703. . . . . . . . . . 8626. 3148. . 8639. . . . . . . . . . . . . 4900. . . . . 531 \leftskip . . . . . . . . . . . . . 4494 \l_tmpa_tl . . . . 5400. 8714. . 8500. . . . . . . 126. . . 5491 \l__tl_internal_a_tl 4895. . . 523 \lineskip . . . . 6236 \l_tmpa_seq . 4900. . 7916. 5312 \l_tmpc_int . . . . . 8599. . . 577 \lastkern . . . . 7919. . 8904. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824 \luatex_mathdir:D . . . . . . . . . . . 755 \luatexpardir . . 41. 184. . . . . 6862 \ln . . . . . 13925. . . . . . . 4643. . . 1503. . . . . . . . . . . . . . . . . . . . . 77. . 23. . 554 \meaning . . . . . . . . . . . . . . . 433. . . . . . 13887. . . . . . . . 736. . . . . . . . . . . . . . . . . . . . 757 \luatexbodydir . . . . 13887 \lua_now_x:n . . . . . . . . . . . . . . . . . . . . . . . . 752 \luatextextdir . . . . . . 13904. . . . . . . . 2331. . . 13887. . . . . 84. . . . . 13929. . . . . . . . . . . . . . . . . . . . . . . 733 749 M \M . . . . . . . . . . . 1600 \luatex_initcatcodetable:D . . . . . . . . . . . . . . . . . . . . . . . . 2325 \mode_if_vertical_p: . . . . . . . . 2331 \mode_if_math:TF . 2325 \mode_if_vertical:TF . 469 \mathord . . . . . . . . . . . 14017 \luatex_if_engine:TF . . . . . . . . . . . . . . . 13887 \luatex_if_engine_p: . . . . . . . . . . . 2329 \mode_if_math: . . . . . 13887 \lua_shipout_x:n . . . . . 185. . . . . 735. . . . . . . . . . . . . . . . . . . . . . . 184. . . . . . . . . . . . . . . . 535 \lower . . . . . . . . . . . . . . . . 13887 \lua_shipout:n . . . . . 13889 \luatex_if_engine:F . . . . . . 2885 \mathchardef . . . . 2325 \month . . . . . . 4137 \mathpunct . . . . . . . . . . . . . . . . . . . . . 1504. 1478. . . . . . 1505. . 483 \maxdeadcycles . . . . . . . . 13040 \long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2329 \mode_if_inner:TF . . . . . . . . . . . . . . . 463 \mathcode . . . . 757 \luatexversion . . . . . . . . . . . . . . . . . . . . . . . 1509. . . . . . . . . . . . . . . . . . . . . . . . . . . 464 \mathop . . . . . . . . . . 470 \mathparagraph . . . 330 \mathchoice . . . . . . 2329 \mode_if_inner_p: . . . . 484 \message . . . . . . . . . . . . . . . . . . . . . . . . . 13909. . . . . . . . 13887 \luaescapestring . . 1480. . . . . . . 2331 \mode_if_vertical: . . . 13889. . . . . . 553 \maxdepth . . . . . . 749. . 751 \luatexmathdir . . . 180 mm . . . . . 78. . . . . 184. . . . . . . 13964 \luatex_directlua:D . . 82. . . . . . . . . . 1479. . . . . . 13911 \lua_shipout:x . . . 733. . . . . . . . . . 752. . . . . 472 \mathsection . . . . . . . . . . . . . . . . . . . . . 4125 \mode_if_math_p: . . 755 \luatex_pardir:D . . . . . . . . . . . . . . . . . . . . . 1487. . . . . . 430 \mathclose . . . . . . . . 13910 \lua_shipout_x:x . . . . . . . .meta:x . . . . 751. . . . . 390 \MessageBreak . . . . . . . . . . . . . . . . . . . . . . . 41. . . 13944 \luatex_latelua:D . . . . 13907 \lua_now:x . . 41. . . . 13896. 79. . . . . . . . 13994 \luatex_if_engine:T . . . . . . . . . . 14002. . . 738. . . 41. . . 2327 \mode_if_inner: . . . . . . . . . . . . . . . . . . . . . . . 437 \mode_if_horizontal: . 613 \medmuskip . . . . . 1895. . 462 \mathchar . . . . . . . . . . . . . . . . . . 13938. . . . . . . . . . . 572 \lowercase . 13966. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13951. . . . . . . .Index \linewidth . . . . . . . . . . 229 . . . . . . . . . . . . . . . 1478. . . . . . . . . 611 \lua_now:n . . 13950. . . . . . . . . . 432 \mathbin . . . . . 756 \luatex_savecatcodetable:D . . . . . . . . . . . . . . . . . 13887. . . . 13893. . . . . . . . . . . . . . . . . . . . . . . 41. . . . 41 \luatex_bodydir:D . . . . . . . . . 13980. . . . . . . . . . 13898. . . . . . 153 . . . . . . 81. . . . . . . . . . . . 753 \luatexcatcodetable . 1501. . . 2327 \mode_if_horizontal:TF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13908. . . . . . . . . . 419 \mark . . . . . . . . 13890 \luatex_luatexversion:D . . . 148. . . . . . . . . . . . . . . . . . . 13991 \luatex_textdir:D . . . . . . 180 em . . . . . . . . . 695 \mkern . . . . . . . . 647 \mathaccent . . . . . 13890. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 731. . 4648. . . . . . . . . . 41. 734. . . . . . . . 153 \middle . . . . . . . . . 749 \luatexinitcatcodetable . . . 180 \m@ne . . . . 732. . . . . . . . . . . . . . . . . . 813 \mag . . . . 13956. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13887. . . . . . . . . . . . 4136 \mathsurround . . . . . . . . . . 34. . . . . . . . . . . 13905. . 736 \mathinner . . . . . . . . 739. . . . . . . 471 \mathrel . . . . .meta:n . . . . . . . . . . 83. . 729. . . . . . . . . 750 \luatexlatelua . . . . 41. . . . . . . 40. . . . . . 623 . . . . . 6816. . 13906 \lua_now_x:x . . 641 \mathdir . . . 750. . . . 14008. . . 13901. . . . . . . . . . . . . 465 \mathopen . . . . . 2327 \mode_if_horizontal_p: . . . . 754 \luatexpagedir . . . . . 310. 737. . . . . . . . . 13037. . . . . . . 756 \luatexsavecatcodetable . . . 753 \luatex_catcodetable:D . . . 339 \looseness . . . . . . . . . . 80. . . . . . . . . . . . . . 754 \luatex_pagedir:D . . . . . . . . . . 41. . 13955. . . . . . . . . 421 \marks . . 2819 cm . . . . . . . . . . . 23. . . . . . . 730. . . . . . . . . . . . . . . . 1478. . . . . . . . . . . . . \msg_generic_new:nn . 7747. . . . . . . . . . . . . . \msg_critical:nnnnn . . . . . . . . . . . . . . . . . . . . . \msg_class_set:nn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7605. . 8314 \msg_trace:nnx . . 7990 \msg_newline: . . . . . . . . . . . . . . 7608. . 8351 \msg_interrupt:xxx . . 7842 \msg_info:nnx . . . . . . . . . . . . . . . . . . 141. . . . . . . 143. . 7742. . . 7662. . . . . . 7942. . \msg_fatal:nnn . . . 7850 \msg_log:nnnnnn . 1210. . . . 7663 \msg_line_number: . . . . 1191. 8309. . \msg_generic_set:nnn . . . . . . 8484 \msg_log:n . . . . . \msg_error:nnx . 7744. . . . . . . . . 7733. 7605. 143. . . . . . . . . . . . . . . . . . . . . . . . . . 7621. . . . . . . . \msg_error:nnn . . . . . . . . \msg_critical:nnxx . . . . . . . . . 8316. 8331 \msg_set:nnn . . . . . 7742. . 7842. . . . . . . . . . . . . . . . . . . . \msg_error:nnxxx . . 7605. . . . . . . . . . 7856 \msg_none:nnx . . . . . . . . 7605. . . . . . . 7742. . . . . . . . \msg_fatal:nn . . . 8309. . . . . . . . . . . 7856 \msg_none:nnnn . .Index \moveleft . \msg_fatal:nnxx . 750 573 574 8307 8354 7802 7802 7802 7802 7802 7802 7802 7802 7802 7805 8321 8322 8323 7813 7813 7813 7813 7813 7813 7813 7813 7813 7820 7791 7791 7791 7791 7791 7791 7791 7791 7791 7794 8318 8317 8320 8319 7628 7629 7579 7596 7870 7579 7842 7842 7842 \msg_info:nnnnn . . . . . . 143. . . 8348 \msg_trace:nn . . . 8314 \msg_log:nnn . . . . . . . 8309. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . \msg_generic_new:nnn . 8353. . . . . . . . . . . . . \msg_if_exist:nnTF . . . . 145. . . 7994 \msg_term:n . . . . 7842 \msg_info:nnxxxx . . . . \msg_gset:nnn . . . . 145. . 7850. . 7933. . . . . . . . . . . . . . . . . . . . . . . . . . . 7611. . . 7856 \msg_redirect_class:nn . . . 7669. . . . . 7856 \msg_none:nnxx . . . . . . . . . . . . . . . . 7605. \msg_critical:nnnnnn . 146. . . . . . . . . . . . . . 7850. . \msg_error:nnnnnn . . . 7856 \msg_none:nnxxx . . . . . \msg_info:nn . . . . . . . . 7942 \msg_redirect_module:nnn 145. . . . . . \msg_fatal:nnnnnn . 7797. . . . . 141. . . . . 7579. . . . . . . . . . . . . . . . 7586. . . 8311 \msg_log:nnxxxx . . 7620. 7747. . . . . . 140. 7742. . . . . . . . 7662. . . . . 7667. \msg_direct_log:xx . . . . . . . . . . . . . \msg_fatal:nnnn . . . . . 7669. . . \msg_error:nnxxxx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7619. . . . . 7610. . . . . . \msg_if_exist_p:nn . . . . . . 8316. . . 8350 \msg_term:x . . . . . . 7743. . . . . . 7727. . . . . . . . . . . . . . . . . . . . 8313 \msg_trace:nnxx . . . . . . . 7804. . \msg_direct_term:xx . . . . . . . . 141. . . . . 7996 \msg_set:nnnn . . . . . . 7842 \msg_info:nnxx . . \msg_critical:nnxxx . . . . 7844. . . . . . 8316. . . . . . . . \msg_error:nnxx . . . \msg_if_exist:nn . . . . \msg_direct_interrupt:xxxxx . . . . \msg_if_exist:nnT . . . . . . . . . . . . . 8348 \msg_line_context: . . . \msg_critical_text:n 141. . 8316. 7944 \msg_redirect_name:nnn . . . \msg_fatal:nnxxx . . 1191. . . . . . . . . . . . . . . . . . . . . . . \msg_critical:nnn . \msg_class_new:nn . . 141. 7842 \msg_info:nnxxx . . . . . . . . 7746. . . . . . . . . . . 7850. . . 7605. . . . . . . . . . 142. . . . . . . . . 8328. . 8312 \msg_trace:nnxxx . 7662. . . . . 8312 \msg_log:nnxxx . . . . . . . 144. . . . . . . . . . . . . 141. . . . . . . . . . . . . . 8041 \msg_info_text:n . . . 8306. . 7856 \msg_none:nnxxxx . . . . . . . . . \msg_generic_set:nn . . 7727. . . . . . . . . 8345 \msg_none:nn . . . . . . . . . . . 8348 \msg_new:nnn . . . . . . . . . . . . . . . . . . . . . . . 144. . . . . . . . . . . . \msg_gset:nnnn 141. . . . . . . . . . . . . . . . . \msg_critical:nnxxxx . . . . 7823. . . . . 7808. . . . 7612. . . . . . 8316. \msg_info:nnn . 7856 \msg_none:nnnnnn . . . . . 8313 \msg_log:nnxx . . . . 146. . . . . . . \msg_critical:nn . \msg_critical:nnnn . . . . 143. . . . . . . . . . . . 7605. 7793. . . . . . . . \msg_fatal:nnx . . . . 7742. . . . \msg_fatal:nnnnn . . . . \msg_error:nn . 7846 \msg_interrupt:nnn . . . . \msg_fatal:nnxxxx . . . . . . . . 7836. . . . 7942. . . . . . . . 7992 \msg_new:nnnn . . . 8309. . . \msg_error_text:n . . . . . . . . 141. . . 8316. 8316. 8349 \msg_log:nn . . . . \msg_info:nnnn . . . . . 7819. . . . . . . . 7601. . . . . . . . . . . . 7850 \msg_log:nnx . . . . 8311 . . . . . . 7933 \msg_see_documentation_text:n . . 8344. . 7856 \msg_none:nnn . . 141. 7850 \msg_log:nnnnn . . 7850. . . . 142. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8307. . . . . . . . . . 7850. . . \msg_error:nnnn . . . . . \msg_fatal_text:n . . . . . . . . . 7856 \msg_none:nnnnn . . . . \moveright . \msg_error:nnnnn . . 7727. 7850 \msg_log:nnnn . . . . . . . . . . . . . . . . . . 7842 \msg_info:nnnnnn . . . . . . . . . 142. . 8310 \msg_log:x . . . . \msg_critical:nnx . . . . . . . . . . . . 4546. . . . 4512. . . . . . 4536 \muskip_gsub:Nn . . . . . . . 4543. . . . . . . . . . . . . . . . . . . . . . . . . . . . 4533. . 8309. . . . . . . . . . . 411 \nulldelimiterspace . 8310 \msg_two_newlines: . 4520 \muskip_gzero_new:c . . . . . . . . . . . . . . . 4527. 4528 751 \muskip_set_eq:cc . . . . . . . . . . . . . . 4508. . 7834 \msg_warning:nnxxxx . . . . . . . . . . . . . . . 4512. . . . . . 4536 \muskip_sub:Nn . . 4552. . . . . . 173. . . . . . . . . 4545 \muskip_gzero:c . 295. . . . . . 448 \nonstopmode . . . . . . . . 4512 \muskip_zero:N . . . . . . . . . . . 4523 \muskip_if_exist:N . . 4506 \muskip_const:Nn . . . 9350 inf . . . . . . 4512. . . . . . . . . . . . . . . . 4550 \muskip_show:N . . . 4514. . . . . . . . . . . 90. . .Index \msg_trace:nnxxxx . . . . . . . 4517. . . . 216. . 86. . . . 4548. . . . . 8040 \msg_warning_text:n 142. . . . . . . . . . . . . . . . . . . 631 \muskip_add:cn . 88. . . . . . . . . . . . . 87. . . . . . . . . . . . . . . 514 \nolimits . 4525 \muskip_gset:Nn 87. 4511. . . . . . . . . . . . . . . 7838 \mskip . . . . . . . . . . . . . . . 4548 \muskip_use:N . . . . . . . . . . . . . . . . 87. . . . . . 4538. . . . . . . 8344. . . . . . . . . . . . 87. . 86. . . . . . . . . . . 87. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7834 \msg_warning:nnnnnn . . . . . . 4536. . . . . . . . . . . 179. . . . . . . . . . . . . . . 87. 7745. . 212. . . . . . . 4188 \newlinechar . 4558. . 4543. 4538. . . 4512 \muskip_gzero:N 86. . . . . 4527. . . 4498. . . . . . 4530 \muskip_set_eq:cN . . . . 179 \noalign . . . . . . . . . . . . 4536. . . . . . . . 481 \nullfont . 4541. . . . . . 4521 \muskipdef . 3462 \newdimen . . . . 4525. 8346 \msg_warning:nn . . . . . . 468 \nonscript . . . . . . . . . . . . 4505. . . . 4517. .multichoices:nn . . . . . . 4523 \muskip_if_exist_p:N . . 353 \noboundary . . . 198. 4550. 41. . . . 4517 \muskip_gzero_new:N . . 180 ln . . 86. . 88. . . . 683 . . . . 4536. . . 7742. . 7834 \msg_warning:nnx . . . . . . 4525. 4523 \muskip_new:c . . . . . . . . . . . . . . . . . . . . . . . 4548. . . 297. . . 4536 \muskip_add:Nn . . . . . . . . . . . . . 86. . . . . 4530. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 N \N . 4518. . . . . . 6499 \newcatcodetable . . . . . . . . . . . . . . . 4549 \muskip_zero:c . . . . . . . . . . . . . . . . . . . . 143. . . . . . . 4530 \muskip_gset_eq:Nc . 214. . . . . . . 4506. 4552 \muskip_sub:cn . 191. . . . . . . . . . . . . 87. . . . . . . . . . . . 4502 \newread . . . . 4525. . 7834 \msg_warning:nnxxx . . . . 200. . . . . . 4515. . . . . . . . . . 153 . 4518 \muskip_zero_new:c . . 178 \newbox . . . . 434 \muexpr . . . . . . . . . . . . . . . . . 201. . 153 \multiply . . . 329 \mutoglue . . . . . . . . . . . . . . . 4530. . . . . . . . . 4530 \muskip_set_eq:Nc . . . . . . . . 40. . . . . . . 9257 \newskip . 7834 \msg_warning:nnnnn . . 7834 \msg_warning:nnn . . . . . . . . 4532 \muskip_show:c . . . 4520. . 608 \numexpr . 4554. . . . . . . . 4530 \muskip_set_eq:NN 87. . . . . . . . . . . . . . . . . . . 4559 \muskip_set:cn . . . . . . . . . . 599 \number . . . . . . . . . . . . 4517 \muskip_zero_new:N . . . . . . . 4519. . . . 4520. . . 7834 \msg_warning:nnxx . . . . . . . . . . . . . . . . . . . . . . 87. . . . . . . . 4522 \muskip_if_exist:c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4544 \muskip_use:c . . . . 36. . . 195. . 215. . . . . . 4525 \muskip_set:Nn . . . . . . . . . . . . . . . . . . . . . . 87. . . . . . . 680 . . . . . . . . . . . . . . . . . 290. . . . . . . . . . . . . 288. . . . . . . . . 213. 4534. . 196. . . . . . . . . . . . . 176. 2044 in . . . . . . . . . . . . 194. . . . . . . . . . .multichoice: . . . . 689 \my_map_dbl:nn . . . . . . 4529 \muskip_gset_eq:cc . . . . . . . 335 \muskip . . . . . 4551 \muskip_show:n . . . . . . . . . . . . . . . . 4517. . . . . . . 4506. . . . . 4557. . 4530 \muskip_gset_eq:cN . 4412 \newwrite . . . . . . . . . . . 4550. . . . . . 4546 \muskip_gadd:cn . . 7834 \msg_warning:nnnn . . . . . . . . . . . . . . . . . . 4539 \muskip_const:cn . . . . . 4531. . . . . . . 4516. . . . . . . . . . . . . . . 4530. . . . . . . . 181. . . . . . . 4555 \muskip_eval:n . . . . . 4536. . . 4556. . . . . . . . . . . . . . . . . . . . . . . . . . . . 210. . . 4498 \muskip_new:N 86. . . 488 \noexpand . . . 4523 \muskip_if_exist_p:c . . . 13943 \newcount . . . . . 7834. . . 4540 \muskip_gset:cn . . . . . 4523 \muskip_if_exist:NTF 86. . . . 4509. . . . . . . . . . . 4499. 4535 \muskip_gsub:cn . 346 \noindent . . . 4547. . . 4514. . . . . . . . . . . . . . . . . . . 4536. 4518. . . . . 86. . . . . . . . 385 \newmuskip . . . . . . . . . 182. . . . . . . 4530 \muskip_gset_eq:NN . . . . . . . 4536 \muskip_gadd:Nn . 4524 \muskip_if_exist:cTF . . . . . . . . . . . . . . 12698. . 12846. . . . . . . . . . . 12547. . .Index O \O . . . . 12926. . . . . . . . . 13539. . . . . . . . . . . . 92. . . . . . 12516. . . . . . . . . . . . . . 12862. . . . 11638. . 12874. . . 557 \pagedir . . . . . 9691. . . . . 11941. . . . . . . . . 13205. . 180 \PackageError . . . . . . . . 1310. . . . . 24. 1494. . . . . . . . . . . . 381 \or . 12857. . . . . . . . 180 sp . . . . . . 12889. . . . . 11767. . . 11003. . . . . . . . . . . . . . 11228. . . . 12735. . 9690. . 12919. . . 12887. 3885. . . . . . 12925. . 13235. . . 562 \pagestretch . . 13538. 12909. . . . . . . . . . 473 \overwithdelims . 34. . . . . . . . 559 \pagegoal . . . . . . . 721 \pdfsetmatrix . 713 \pdflastxform . . . . . . . . . . . 11937. . . . . . . . . . . . . 3487 . . . . . . . . . . . . . 11943. . . . . . . 179 round0 . 537 \parshape . . . 1302. . . . . . . 12886. . . . . . . . 12901. . . . . 12025. . . 179 cot . . 10257. . . . . . . . . . . . . 179 \outer . 677 \parshapelength . . 513. . . . . . 1309. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12860. . . 3881. . 1483. . . . . . . . . . . . . . . . . . . 12944. . . 12908. . . . . . . . . . . . . . . . 1506 \pdftex_if_engine:TF . . . . . . . . . 13241. 12845. . . 75. . . . . 12921. . 11944. . . . . . 12890. . . . . . . . . . 12877. . 74. . 565 \over . 11939. . 564 \par . . . 12917. . . . . . . . . . . 11945. 70. . . . . 561 \pagefillstretch . . . . . . . . . . . . . . . . . . 226 \pagedepth . . . 12022. . . . . . 179 round . . . 12894. . . . . . . . 13250. . . . . . . 12733. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3882. . . . . . . 558 \pagetotal . . 714 \pdfliteral . . . 3874. . . . . 6659. . . . . 1305. . . 12905. . . . 3868. 712 \pdfinfo . . . . . . . . . 145. . . . . 12840. . 12842. . . . . . . . . 678 \parskip . . . . .. . . . 3883. . . . . . . . . 12893. . . . . . 3877. . . . . 12871. . . . . . . . . . . 12888. 3876. . 560 \pagefilstretch . 13226. 12873. . . . . . . . . . . . . 3889. . . 544 \parindent . . . . . . . . . . 1493. . . . . . . . . . . . . . 718 \pdfpkresolution . 12844. 12903. 11942. . . . . . . 12853. . . 711 \pdfhorigin . . . . . . . . . . . 722 \pdfstrcmp . . . . . . . . . 12878. 12843. . 12907. . . . . . . 12872. 11227. . . . . . . . . . . . . 12910. . . . . 1508. . . . . . 1303. . . . . . 12855. . . . . . . . . 377 \or: . . . . . . . . . . . . . 3892. . . 12885. . . . . . 13220. 12892. . 23. 1482. 766. . 12861. 13607 cos . . . . 3886. . 3873. 3890. 15133 \omit . . . . . . . . . . . . . . 11190. . 12993. . . . 720 \pdfsave . . . . . . . . . 13488. . . 13181. . . . . . . . . . . . . . 563 \pageshrink . . . . . . . . . . . . 9689. . . 738 \parfillskip . . 13549. . . . . . . . 12743. . . . 179 round+ . 13113. . . . . . . . . 11851. . . . . . . . . . . . . . . . 3884. . 529 \parshapedimen . . . . . . . . . . . . 179 round. . . . 3891. 77. . . . . . . . . . 717 \pdfoutput . . . 13175. . . . . . . . . . . . 619 \pausing . . . . . . . . . 12549. . . . . . . . . . . . . . . . . 11189. 13128. 719 \pdfrestore . . . . . . . . . . . . . . . . . . . . . . . . . . 12918. . . . . . . . . . 6662. . 555 \outputpenalty . . . 708 \pdfdecimaldigits . . . . . . . 12551. . . . . . 442 \overfullrule . . . . . . . 11639. . . 13211. . . . . . 13606. . . . 12870. . . 11188. 12541. . . . . . 406 \pdf@strcmp . . . . . . . . 10311 bp . . . . . . 12891. . . 12906. . . . . . . . . . . . . . 679 \parshapeindent . . . . 6660. 12859. . . . . 60 \pdfcolorstack . . . . . . 1308. . 1897. . . . 354 \openin . . . 1307. . . . . . . . . 11637. 13196. . 3880. 3875. . . . . 3872. . . . . . . . . 13489. 443 752 P \P . . . 12920. . 1306. . . 12922. . . . . 12923. . . . . . . . . . . . 340 \output . 13256. . . . 6677. . 593 \overline . . . . . . . . . . 12856. . . . 12838. . . . 710 \pdfcreationdate . . 9841. . . . 709 \pdfcompresslevel . . . . . . . . . 13002. . . . . . . . . . 3879. 3870. . 12869. . . . . . . . 12858. . 11940. 12924. 698 \pagefilllstretch . . . . . . . . . . . . 3887. 12990. . . . 3871. 12854. . . . . . . . . . . . . 3869. . . . . . . . . . . . 6690 \pardir . . . 1492. . . . . . 1481. . 768. . . 12904. . . . . . 11938. . . . . 12548. . . . 12841. . . . . . . . . 6666. . . . . 1507 \pdftex_if_engine:T . . . . . 1607. . . . . . 12837. . . . . 12902. . 6664. . . . . . 715 \pdfminorversion . . . . . 12550. . 1304. . . 12876. . . . 13500. . . . 1478. . . 536 \patterns . 12839. . . . . . 723 \pdfrefxform . 716 \pdfobjcompresslevel . . . 380 \openout . . . . 13190. 6671. . . . . . . . . . . 12875. . . . . . . . . . . . . . . 727 \pdftex_if_engine:F . . . . . . . . . . . 12833. 60. . . . . 3888. . 3878. 737 \pagediscards . . . . . 60. . . 11348. . . 2760. 4266. . . . 6030. . 3638. . 4565 \prg_case_int:nnn . . . . . . . 2869. . . . . 14994 \prg_new_eq_conditional:NNn . . . . 9995. . . 460 \predisplaysize . . 4561. 912. . . 2808. . . 10677. . . . . 10690. . 1969. . . . 2468 \prg_case_str:nnn . 1431. 6472. . . . . . 3307 \peek_after:Nw . . 713 \pdftex_pdflastxform:D . . . . . . 8917. . . 3234 \peek_meaning_remove:NTF . . . . . . 4817. . . . . . . . 2329. 708 \pdftex_pdfdecimaldigits:D . 1515. . . 14444. 5229. . . . 2996. . 2827. . 8958. . . . . . . . . . . . 714 \pdftex_pdfliteral:D . . . . 6031. . . . 719 \pdftex_pdfrestore:D . . . 15168 \penalty . . . . . 5264. 5838. 6571. . . 6527. 2788. . 5521. 8964. . . 6474. . . . . . . . . 2152. . . 59. 4458. . 4523. . 3308 \peek_meaning:NTF . 2773. . . . 5837. . 37. . . . 14492. . . . . 15132. 5761. . . . 9969. . 3560. 614 \postdisplaypenalty . . . . 6196. . 11197. . . . . . . . . . 13780. 3025. . . . . . . . . . . . 2750. 4838. 14440. . 4848. 2534. . 2767. . . . . 897. . . 5766. . . . . 59. 2325. 2467. . . 4432. 2471 \prg_case_tl:cnn . 4271. . . 2539. . . 1510. . 1007. . . 3513. . . 5460. . 14451 \prg_new_conditional:Nnn . . 58. . . 3110. 2469 \prg_case_str:onn . 5191. . . 59. 58. . 718 \pdftex_pdfpkresolution:D . 3202 \peek_catcode_remove_ignore_spaces:NTF . . . . 2841. . . . . 13773. . . . . . . 716 \pdftex_pdfobjcompresslevel:D . . . . . . . . 5381. . . . . 2793. . 2120. . . . 1601 \pdftex_pdfcolorstack:D . . . . 15172 \peek_N_type:T . . . . . . 3608. . 2600. . . . 4467. 6748. . . . 3512. . . . . . . . 710 \pdftex_pdfcreationdate:D . . . . 9908. . . . 727. . . . 2517. . . . . 459 \pretolerance . . . 3234 \peek_meaning_ignore_spaces:NTF 60. . 23. . 2906. . . 9935. . 4822. . . . . . 709 \pdftex_pdfcompresslevel:D . . . . 6363. 1008. . . . . 5763. 2473 \prg_case_tl:Nnn . 3234 \peek_N_type:F . . . . 3087. . . 540 \prevdepth . . . 3218 \peek_charcode_ignore_spaces:NTF . . . 2755. 2091. 4524. 60. . . . . 720 \pdftex_pdfsave:D . . . . . . . . 2374. 722 \pdftex_pdftextrevision:D . 711 \pdftex_pdfhorigin:D . . . . . . 59. . . . . . . . 998. . . . . . . 6357. . 10846. 4640. . 721 \pdftex_pdfsetmatrix:D . . . . . . . . . . .Index \pdftex_if_engine_p: . . . . . . . . 2467. . . . 5459. 4929. . . 4881. . . . . . 5638. . 2984. . 6193. . . 726 \pdftex_strcmp:D . . . . 3202 \peek_catcode_remove:NTF . . 3128. . . . . 1498. 11335. 10003. . . . . . . . . . . . 5210. . . . 6561. . . . 4209. . 461 \predisplaydirection . . 60. . . 9883. . . . . . . . . . . . . . 3178. . . . 3218 \peek_charcode_remove_ignore_spaces:NTF . . . . . 2510. . . . . . . . . . . 6359. 2783. . 2470 \prg_case_str:xxn . . . . 712 \pdftex_pdfinfo:D . . . . . . . . . . . . 4455. . . . . . . 5432. . 4883. . 2457 \prg_do_nothing: . . . 1513. . . . 5270. . 2798. . . 2778. . . . . . . . . . 2467. . . . 3307 \peek_catcode:NTF . 2154. . . 1519. . 4860. 3005. . 2834. . . . . 9293 \prg_new_conditional:Npnn . . . . . . . 715 \pdftex_pdfminorversion:D . . . 6358. . . 3308 \peek_gafter:Nw . 1478. . . . . . . . . . . . . 1488. . . . . 2813. . 2966. . 1512. 2091. 3234 \peek_meaning_remove_ignore_spaces:NTF . 2547. . 6528. . . . . . . . 2803. . 725 \pdfxform . . 5764. 12982 \pdftexrevision . 4757. . . . 6559. 3085. . . . . . . 1964. . . 15170 753 \peek_N_type:TF . . . . . . . 2472 \prg_define_quicksort:nnn 2373. . . . . . . 725 \pdftex_pdfxform:D . . . . . . . . . . . . . 2602 \prg_case_dim:nnn . 4208. . . . . . . . . . 11334 . . . . . . . . . . . 7579. . . . . . . 3218 \peek_charcode_remove:NTF . . . . . 4433. . . . . . 2745. 3085. . . 198. . . 5439. . 5523. 6473. 60. . . 910. . . . 3306. . . . 2561. 3085. . . . . 59. . . . . . . . . . . . . 3218 \peek_gafter:NN . 2331. . 5373. . 2888. . . 5377. . . . . . . . . 2153. . 724 \pdfvorigin . . 2846. . . . 3202 \peek_catcode_ignore_spaces:NTF 58. . . . . . . 3630. . . . 13799. 35. . . . 5640. . . . 1512. . . 6195. 2091. 5379. . . 5765. . . . . . 1000. 4743. . 2878. 3306. . . . . 717 \pdftex_pdfoutput:D . 5285. . 3202 \peek_charcode:NTF . . 2570. . . . 10673. . . 587 \prevgraf . 58. . 2930. 1471. 6475. 2467. . . . . . . 2467. . . . 899. . 2559. . 5762. . . . 2467. 723 \pdftex_pdfrefxform:D . . . . . 6361. . . . . 1526. . . . 2948. . . . 5926. . . . . 2568. . . . . . 705 \predisplaypenalty . . 4639. . . . . . . . . . . . . . . . . . . . 4564. 546 \prg_break: . . . 11333. . . . 2327. 9. . . 1565. 6194. 1521. 724 \pdftex_pdfvorigin:D . 726 \peek_after:NN . . 5525. 2464 \prg_new_protected_conditional:Nnn . . . . 2125. 2951. . . . . 13778. 4462. 1139. . 9546. . . . . 6267 \prop_get:coNTF . . . 901. 910. . 6477. . . . . . . 4886. . . 893. . . 6479 \prop_display:c . 3045. 2550. . 6220. . 7911 \prop_get:coN . . . 6562. 5947. . . 11354. . 2748. . . . 3028. . . . . . . . . . . 1107. . 6784. . . 2456 \prg_quicksort_compare:nnTF . . 6477. 910. . . . . . . . . 6404. 2476 \prg_stepwise_inline:nnnn . . . . . 3635. 13580 \prg_return_false: . 41. 3558. . 35. 9298. . 6478 \prop_del:NV . 4460. . . . . 1434. . . . . . 6477. . 2542. . . . . . 6267 \prop_get:cVNTF . 2852. . 9130. . . 11343. . 916. . 6403. 7134 \prop_clear:N . . 4269. 897. . . . . 122. . . . . 1150. . . . . 2753. 2565. . . 13778. 2748. . . . 2781. 4876. 6220. 14816. . . . . 2816. 1133. . 6405. . 6222 \prop_gclear_new:c . . 5957. . 2936. . . . . . . . . . . . 35. . . . . . 37. . 14816. 13783. . 9134. . . . . . . 6394. . . . . . 6783. . . . . 1127. 5637. . . . . . 9303. . 6224. . . 6394 \prop_get:cVN . . . 2328. 2091 \prg_stepwise_function:nnnN . . 1153. 121. 194. . 9232 \prg_quicksort:n . 6477. . . . 13147. 1517. 897. . . . 2574. . . . 6267. 6477. 2477 \prg_stepwise_variable:nnnNn 2475. . 8921. . 8962. . . . . 7357. 7582. . 14496 \prg_set_conditional:Nnn . 1130. 6560. . . 10698. 2159. 13089. . . . . . . 1105. . 1135. 6225. 6560. . . . 2459. . 3643. . . 6754. 2796. . . . 9241. 6382. . . 6562. 3613. . . . . 5649. 893. . . . . 998. . 13783. 2123. 9135. 1099. 5639. . 1517. . 5226. 6046. . . . . 2330. . . . . 6477. 8360 \prop_clear_new:N . 2763. . . 6274. . 2332. . . . 2972. 3590. . 1522. . 6224. . 2786. 5203. 5242. . . 2544. 6477. . . 121. . . 6481 \prop_del:Nn . . . . . 5294. . . 6224. 13572. 3611. . . . 4306. . 2758. . . . 893. . 6394 \prop_get:Nn . . . 5651. 6032. 6380. . . . 3585. . 1529. 6399. . . 6483 \prop_get:cn . . 9301. 6401. . 4562. 10681. . . . 5647. 9913. 4895. 3585. . . . . . 5240. . 6447 \prop_gclear:c . . 897. 7444 \prop_get:NnNF . . 2791. . 2157. 754 11345. . . . . . . 4865. 6307. . . . . . . . 11356. 2475. . 2891. . 2091. 14816 \prop_get:cnN . 6572. . . . 2465 \prg_set_protected_conditional:Nnn . . . . . . 2806. . 2478 \prop_clear:c . 6267 \prop_get:cnNF . . 5280. 6482 \prop_gdel:NV . . . . 2910. 9911. 37. . . . . 5260. . . . . 6912 \prop_get:cnNT . 2461 \prg_quicksort_function:n . . 9244. . . . . . . 2916. . 10704. . . 5293. . . . . 4562. . . 6394. . . . 2786. 2460 \prg_replicate:nn . 3641. . . 2463. 4471. . 910. . 6221. . 2894. . . 6036. 2811. . 1122. . 6227 \prop_gclear_new:N . . 2753. . 6267. 6305. 2816. 9307. . . . 2844. 2844. 4888. . 6484 \prop_gdel:cV . 37. 2776. . 13545. 13310. 2091 \prg_set_map_functions:Nn . . 2463. . 5258. . . . 2776. . . . 7966 \prop_get:cnNTF . 121. . . . . . 2326. 6454. 6220 \prop_clear_new:c . 1522. 6480 \prop_del:cV . . . . . 7440. . . . . 10686. . 4851. 2770. 35. . . . 2091 \prg_set_conditional:Npnn . . 1111. . . . 14495 \prg_return_true: . . . . . 3633. . 5539. 5935. . 4306. 2796. 8922. . 6394. 6408. 6223 \prop_gclear:N . . . . 2933. 2913. 2811. 6273. . . . 4902. . 6224 \prop_del:cn . 4470. . . . . . 1527. 7891 \prop_get:NoN . 2326. 1125. . . . . 5938. . 2091 \prg_new_protected_conditional:Npnn . . 13140. . . . 2854. . . . . . . . . 4920. . . . 5941. 3064. . . 5565. . 4878. 8968. 4305. 5653. 6407 \prop_get:NnNT . . . . 2091 \prg_set_protected_conditional:Npnn . . . . 2801. 3047. . . 910. . . 121. 6485 \prop_gdel:Nn . . . . 6446. 2791. 897. . . 2908. . 2459. 6448 \prop_display:N . 4916. 6394. . 6046. 4863. 3071. . . . . 4290. 2563. 6267 . . 2781. 4853. 1102. 903. 5954. . . 8173. 6220. . . . 2091. . . . . . . 998. . 2475. . 6756. . 6446. . . . . 2552. 2954. . 2837. . . 5543. . . . . 6753. 6477. . . 2763. 6572. . . . 5282. . 8967. 2572. . . . . 2801. . . 2281. . . . 4920. . . . 1120. 6224. . . 2806. . . . . . 5224. . 2091 \prg_set_eq_conditional:NNn . 7582. . 2849. . 14831 \prop_get:NnN . . . 5562. 5250. 1148. . 6315. 6220. . . . 8961. 2281. . . . . 6226 \prop_gdel:cn . 2332. 7361. . 2328. . 2758. 6303. 5949. . .Index \prg_new_map_functions:Nn . . 2969. 2330. . . 5201. . 2835. . . 2091. 6297. . . . . . . 1434. . . 914. . . . . . 6313. . . 895. . . . 2770. 4905. . . . 3073. 6406 \prop_get:NnNTF 124. . . 4269. . . . . . . . . . . . . . . 6439. . . . . . . . . . . . . . . . . . . . . . 6363 \prop_if_in:NnF . . . . . . . . . 6466 \prop_if_in:NoTF . 6363 \prop_if_in_p:co . . . 6257. 125. . . . . . . . . . . . 6435. . . . . . . 6389. . . . . . . 14697. 14703. . . . . . . . 6323 \prop_gput:Non . . . . . . . . . . . . 7205. . . . . . . . . . . . . 6359. . . . . . . 6363 \prop_if_in_p:cn . . . . 6358 \prop_if_exist:cTF . . . . . . 6425. . . . 6363 \prop_if_in:Nn . 6323 \prop_gput:cVn . 6363 \prop_if_in:NVTF . 6323 \prop_gput:Nnn . 6464 \prop_if_in:NnTF 123. 14705 \prop_map_inline:Nn . . . . . . . . 6468 \prop_gput:cnn . . . . . . . . . 6391. . . . . . . . . . . . . . . . . . . . . . 6295. . 6386. 6251. 6390. . . . . 6363. . . 6357 \prop_if_exist_p:N . . . 6322 \prop_gpop:NoN . . . . . . . . 14805. 6938 \prop_gset_eq:cN . . 6323 \prop_gput:cno . . . . . . . . . . . . 7503 \prop_map_function:Nc . . . 121. . . 14637. . . . . . . . . . . . . . . . 6461 \prop_gpop:NnNF . . . . . 123. . . . . . . . 6473 \prop_if_eq:cNTF . . . . . . . . . . 6359 \prop_if_eq:cc . 6363 \prop_if_in_p:NV . . . . . . . . . . . . . . . . . . . 6443. . . . 6471 \prop_if_exist:c . . . . . . . . . . . . . . . . . . . . . 6297 \prop_gpop:coN . . . . . . . . 6275. . . . . . 6450 \prop_gget:NnN . 6266. . . . . . . . . . . . . . 6275 \prop_gput:ccx . . . . 6471 \prop_if_eq:cN . . . . . . . 6363 \prop_map_break: 125. . . . . 6343 \prop_gput_if_new:Nnn 122. . . . . . . . . . . . . . . . . . 14810 \prop_map_break:n . . 6436. . 6363 \prop_if_in_p:cV . . . . . 6345. . . . . 123.Index \prop_get:NoNTF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6409. 6284. . . . . . 6343. . . . . 6228. . . . . 14545. . . 6472 \prop_if_eq:NNTF . . 6363 \prop_if_in:coTF . . 122. . . 6436. . . . 6413. . . . . . . . . 6424. . . . . . . . . . . . . . . . . . . . . . . . . . . 7409. . . 6418. . . . 6232 \prop_if_empty:c . . . . . . . . . . . . . . . 123. . 6438 \prop_map_function:cc . . . . 6359 \prop_if_empty_p:N . . . 6265. . . . . . . . . 6450 \prop_gget:cVN . 124. . . . . . 14572. . 6323 \prop_gput:cnV . . . . 6425. . . . . . . 123. . . . . . . . . . . . . 6392. . . . . . . . . . . . . . . . . . . 6409. . 9218 \prop_gput:Nno . . . . . 6471 \prop_if_eq_p:cc . 6275 \prop_gpop:cnNTF . . . . 7224. . . 14550. . . . . . . . . . . . . . . . 6458 \prop_gget:NVN . . . . . . . . . 6363 \prop_if_in_p:Nn . . . . . . . 6409 \prop_map_function:NN . . . . . . . 6482 \prop_gremove:NV . . . . . . . 6785. . . . . . . . . 6341. . 6323 \prop_gput:NnV . . 9287 \prop_if_empty_p:c . 6323 \prop_gput:coo . . . . . 6450. . 6323 \prop_gput:con . 6483. . 6387 \prop_if_in_p:No . . . . . . . . . . . 6450 \prop_gpop:cnN . . . . . . . . . . . 6433. . . 14699. . . . . . . . . . . . . . . . . . . . . . . . 6323 \prop_gput:Nnx . . 123. . . . . . . . 6409. . . . . . . . 6325. . . . . . . 6251. 6356 \prop_gremove:cn . 6465 \prop_if_in:NnT . . . . . . . . . . 6437. 6484 \prop_gremove:cV . . . . . . . . . . . . . . . 6450 \prop_gget_aux:Nnnn . . . . . . . . 6452. . 6296. 6359 755 \prop_if_empty:NTF . . . 6471 \prop_if_eq_p:Nc . . 6471 \prop_if_eq_p:cN . . . . 6357 \prop_if_exist:NTF . . . . 6463 \prop_if_in:cnTF . 6457. . . . 9267. . . . . . 6363 \prop_if_in:cVTF . . . . . . . . . 6323 \prop_gput:NVn . . . . 6323. 6475 \prop_if_eq:ccTF . . . 6321 \prop_gpop:NnNT . 6461 \prop_gget:cnN . 6228. . . . . . . . . . . . 9275. . 14654 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6394 \prop_get_gdel:NnN . . . . . . . . . . . 6275 \prop_gpop:NnN . 124. . . . . . . . . . . . . . . . . 14547. . 6393. 9290 \prop_map_inline:cn . . . . . . . . . . . . 9360 \prop_gput:NVV . . . . . . 6323 \prop_gput_if_new:cnn . . . 6228. . . . . . . . . . . . . . . . . . . . . . . . . . 6235. . 6363. 6394 \prop_get:NVN . . 7418. . . . . . 6471 \prop_if_eq_p:NN . . . . . . . . . . . 6267 \prop_get:NVNTF . 6471 \prop_if_eq:Nc . . . . . . . . . . . . . . . . . . . . . 6460. . . . . 6251. . . . . . . . . . . . . . . . . . . . . . . . . . . 6307. . . . . . 6323 \prop_gput:Noo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6936. . 6474 \prop_if_eq:NcTF . 6251. . 6323 \prop_gput:cVV . . . . . . . . 6323 \prop_gput:cnx . . . . . . . . . 6425. . . . . . . . . . . . . 6233 \prop_gset_eq:NN . . . . . . . . . 122. . . . . 14570. . . 6339. 6787 \prop_gset_eq:Nc . . . . . 6228. . . . 123. . . 6409 \prop_map_function:cN . 9368 \prop_gset_eq:cc . . . . . 6485 \prop_gremove:Nn . . . . . . . . 6469. . 6361 \prop_if_empty:cTF . . . . . . 6388. . 6359 \prop_if_empty:N . . . 6471 \prop_if_eq:NN . . . . . . 8189. . 124. . . 6357 \prop_if_exist_p:c . . . . . . . . . . . 6234. . . . . . . . . . . . . . 6436. . . . 6357 \prop_if_in:ccTF . . . . . . . . . . . . . . . . . 6297. 6320 \prop_gpop:NnNTF . . . . . . . . 6423. . . . 6357 \prop_if_exist:N . . . . 6323. . . . . . . 6275 \prop_pop:NnN . . . 6733. . . . 6736 \prop_put:NnV . 48. . 5928. . . . . 2582 \q_mark . . 6323 \prop_put:NVV . . . . . . 121. . . . 14975. 6343 \prop_put_if_new:Nnn 122. 6440. 5046. . . 6974. . . . 2167. 9331. . 2177. . . . . 3576. . . 2581 \q__tl_act_stop . . 140. 2381. . . . 8415. 6929. . . 14457. . 7300. . . 5553. . . 293. 5849. . . 6231. . . . . . 14801 \prop_map_tokens:Nn . . . . . 1911. 6970. . . 15157 \q_nil . 140. . 14520. 2176. . . 6236. . . . 45. . 1087. . 193. . . 159. 5110. . . 5155. 6713. . . . 45. . 280. . . . . . 14801. . . . 6218. . 6725. . . . . . 3379. . 5077. . . 6297. . 6998. . . 14962. . . . 6219. . . 7005. . 14578. . 6447 \protected . . 6. . . . . . . 6263. . . . . 7294. . . . . 6478. . . . . . . 6931. . 2169. . 1943. . . . . . 13883. 6008. 707. 7304. . . 6218. . . . . . . 7897. 1966. . 5106. 6922. 2488. . 110. . 7229. 2490. . 220. . . . 8440. 6323 \prop_put:coo . . 2175. 2178. 6440. . . . . . . 9041. . . . 122. . 1908. . . . . . 6972. . . . . . 2173. . 7298. 3573. . 6229. . 6247. . . 8411. 6732. . 6323 \prop_put:NVn . . 4862. 7756 \prop_new:N . 2023. . . . 6228. 1086. . 2062. . 1952. 7407. . . 2488. 2562. . . 1918. . . 2222. . 6323. . . . . 2489. 6323 \prop_put:cVV . 152. 7288. 5067. 5092. 6343. . . 6230. . 5932. 121. 6448 \prop_show:N . . . 7902. . . 10267. 9329. . 7939. . . . . 7306. . . 2607. . . 2581. 2085. 6297 \prop_pop:coN . . . . . . . 7539. . . . 6027. . . . . . 5019. 5156. . . . . . . . . 6228 \prop_show:c . 14597. . 7290. 6239. . . 6251. 124. . . . . . . 7302. 14815 \prop_new:c . . . 5044. 6. . . 14529. . 7318. . 2001. . . 1092. 6728. 2167. 2177. . . . . 7316. . . 7308. . . . 5391. . . . . . . . 304. 2571. 6317 \prop_pop:NnNTF . . 6323. 157. 7296. 7283. . . . . . 6323 \prop_put:cnx . . . 8467 \q_no_value . . . . . 2168. . . 5797. 5059. . 247. 14755 \prop_put:con . . 7896. 7292. . . . . . 14734. . . . 5022. . 6275. 9333 \prop_put:Nno . . 6323. . 7314. . . . . . . . . 6337. . 5918. . 14535 \prop_pop:cnN . 14496. . . . . . . . . . . 6479 \prop_set_eq:cc 6228. . 6323. . 5956. . . . . 2165. 6720. . . . . . 14664. 164. . 6735. . 6323 \prop_put:Nnn . . . 4003. . 1090. . 1091. 5023. 6297 \prop_pop:NnNF . 6343. 2168. . 7399 \prop_set_eq:NN . . 1977. . . 6480. 14672. 6275. 6991. 7572. 10265. 6319 \prop_pop:NoN . . . . 6323 \prop_put:Noo . . 161 \ProvidesExplClass . 6335. . . . . . 5029. 6218. . . 881. . . . 6734. . . . . 2176. . . 6076. . . 2541. . 8455. 6723. . 14580. . . 6721. . 154 Q \q___tl_act_mark . 139. . 6293. . . . . 2051. . . 2483. . . 6211. 6976. . . 6323. . . 7312. . 4809. 4875. 14583. 6245. . . . 8432. 6323 \prop_put:Nnx . 6228. 5074. . . . 6. . . . . . . 9627. . . . . 3981. . . . . 9332. . . . 5077. . 286. . . 6238. . 7865. 7951 \prop_remove:cV . . 4177. 762. 9216. . . 2172. . 6491. . . . . 2172. . . . . . . . . . . . 5858. . 2174. . . 6318 \prop_pop:NnNT . 8444. . . 6355 \prop_remove:cn . . . 6323 \prop_put:cnV . . . 7324. 7284. . . . 5054. 7955. 139. . 6323 \prop_put:cVn . . . . . . . 9452 \ProvidesClass . 2549. 5090. . 6237. . 139. . 5043. 4813. 5070. . . 6323 \prop_put_if_new:cnn . 5016. . 2054. . 166 \ProvidesPackage . 2488. 6727. . . 5103. . . . . . . 14061 \ProvidesFile . . 5098. 164 \ProvidesExplPackage . . . . . . 1974. 6251. . 8441. 7404. 15150. . 6264. . . . . 14495. 14585. . . 124. . . 6248. . . . . . . . . 14505. 15149. 7310. . . 8403. . 6228. . . . . 14748. . . 2174. . 4591. . 2377. . . . 1986. . . . . . 6084. . . 2581. 8462. . . 7411. 6251. . . 14591 \prop_put:Non . . 122. . . 5113 \q__tl_act_mark . 2175. . 6986. 8376. . . . . . . 7286. . . . . . 6275 \prop_put:cnn . . . 2488. 1626. . . . . 152. 4800. . 1915. . . 14972. . . 6981. . . . . . . 6014. 6251. 125. . . . 5056. 5064. 5094 \q___tl_act_stop 5074. . . . . . . . 6724. . . 878. .Index \prop_map_tokens:cn . 6323. . 6924 \prop_set_eq:Nc . . . 6729. 5015. . . 14528. 5863. . 6964. . . . . . 3013 \protected@edef . . . 14961. . 7164 756 \prop_set_eq:cN . 1909. . . 7972 \prop_put:cno . . . 6440. . . . . . 7936 \prop_remove:NV . 7905. 14519. . . . 5050. . 5042. . . . . . 6251. . . 6722. . . . 6275 \prop_pop:cnNTF . 6731. 2173. . 159 \ProvidesExplFile . . . . . . . . . 6294. . 5081. . . . 4824. . 6445. . . 14801. 6481 \prop_remove:Nn 123. . . . . . . 4874. . . . . . . 2166. . 8431. 6. . . . . . . 3570. . . 947. . . 8565. . 10. . . 2412. . . 6291. . . . . . 1055. 5180. 2535. 2502. . . . . 983. . . 7. . . 2559 \quark_if_nil_p:N . . 5048. 6125 \quark_if_recursion_tail_stop:n . 1060. . 7359. 128. . 5188. . . . . . . . . 236. . 2559 \quark_if_recursion_tail_break:N . . . . 9133. 2496. . . 14521. 2580 \quark_if_nil:nT . . . . . . 988. . 2494. 2487. . . 2518. 2579 \quark_if_nil:NTF 45. 4384. . 2388. 46. . 5921. . . . 2492. 967. 242. . . 4. . . . 2492. 883. . . . . 4389. 14972. . . 138. 8555. 2377. 5198. 59 . 575 \read . . 952. . . 2508. 8436. 2577 757 \quark_if_nil_p:o . . . 4973. 134. 1041. 7442. . 14422. . . . . 3582. . . 10267. . 2995. . . 2490. . . 5165. . 8444. . . . . . 1982. . . . 6014. 14530. 4305. 2508. . 4934. . . . 2539 \quark_if_nil_p:n . . 5850. . . 5026. . . 2965. 5190. . 879. . . 6432. . . . . . . . . . . . . . . . 963. 46. 5576. . 2178. 14455. 5385. . . 1974. . 119. . . 6417. . . 3253. 2222. 5151. . . 1535. 1996. . 2394. . . 5901. . . 45. . 2582 R \R . 6368. . 2578 \quark_if_nil:oTF . . . . 2555 \quark_if_no_value_p:n . 5573. . . . . 2023. 1030. 6412. 2421. 2515. 6095. . . 14879. 5918. . 2487. 15151 \quark_if_nil:N . 2225. 14975. 5070. 8431. 478 \RequirePackage . . . . 8403 \q_recursion_tail . 9140. 2559. 4006. . . . . . 3622. 46. . 2363. . . . . . 2557 \quark_if_no_value:NT . 239. . 117. 5850. 882. . 116. . . 3037. 237. . 6248. 417 \relpenalty . . 46. . . . . . . 2005. 9471. . . . 6271. . 15099 \q_stop . . . 5585. 1947. . . . . . . . . . . . . 5573. 2899. . . . 2381. 14977. 2559 \quark_if_no_value_p:c . . 5595. 2883. . . 6062. 6155 \quark_if_recursion_tail_stop:o . . 2500 \quark_if_recursion_tail_stop_do:nn . . . 7363. 8403. . . 8413 \quark_if_recursion_tail_stop_do:Nn . . . 2559. . . . 880. . . . . . . . . . . 4. . . . 2539 \quark_if_no_value_p:N . 73. . . 9560. . . . . . 14872. 2599. . 238. 69. 5358. 14804. 2508 \quark_new:N 45. 2832. 6149. . 2494. . 2508. 2559 \quark_if_nil:nF . 6149. . 4824. . 6113. . 2929. 8442. 4279. 2494. . . 3015. 1892. 14874. 8437. . . . . . . 8464. . . . . . . 4313. 8467. 58. . 45. 2488. 241. . . 45. 14528. 5916. . 2351. . . 2539. 1088. . . . . 113. 5239. 2556 \quark_if_no_value:NTF . 5149. 2349. 8540. . . 2227. 4049. . . 14. . 2539. 129. . 2539 \quark_if_nil:n . 382 \readline . . 2403. . . . 1990. 112. . . . 2599 \quark_if_recursion_tail_break:n . 1546. 8675. . . . . 3984. . . . 45. . . 2558. 244. 4809. . . . . . 15137 \radical . . . 5929. 3034. . . . . . 2559 \quark_if_no_value:cF . 1978. . . . . 5. . . . . 2062. 5932. . . . 1912. . . . 2539 \quark_if_no_value:N . . 14505. . . . 2528. . . 240. . . . . 6245. . . 115. 2559. . . . 435 \raise . . . . . 947. . . 90. . . . . 2488. . . 45. . . . . 132. . 1554. . . . . 14497. . . 2524. 2369. . . . 3031. . 2921. . 1045. 4. . . . . . . . . . 8537. . . 2365. 45. 8440 \quark_if_nil:VTF . . 8907 \quark_if_no_value:cTF . . 2057. . . 2568 \quark_if_no_value:NF . 122. . . 2491. 2493. . 46. 4473. 63. . . 5019. . 1011. . 5217. 126. . 6113. 5903. . . . . . . . . . . 120. . . . . . . . 6076. 1011. . . . 2581. . . . . . . . . . 2492. 3278. . . 5854. 2947. . . . . 127. 5940. . . . . . 2559 \quark_if_nil_p:V . 131. . . 8546. . . 9240 \quark_if_no_value:nTF . 2601 \quark_if_recursion_tail_stop:N . . . . . . 2887. . 2525 \quark_if_recursion_tail_stop_do:on . . . 2508. . 7898. . . . 5956. 2493. 3568. . . . 4086. 1050. 8684. 7446. 2170. 1092. . 243. 45. . . . . 2990. . 2539. . 1898. . . . . . . 2983. . 8687. 4471. 8414. . . . . . . 130. . . . 2599. . 3552. 2959. . 657 \relax . . . 2491. . . . 135. . . . . . . 3059. . .Index 5561. . . . 1091. . . 2830. 6282. . . . . 5017. . . . . . . . . . 2489. 4947. . . . 3260. . . 4964. 2384. 3574. . . . . . 2905. 9228. 2547 \quark_if_no_value:n . . . . . 2977. 2941. . . . 14529. 133. 5024. . . . 3001. 2492. . 993. . 1918. . . . . 114. . . . . . 2511. . 14809. 45. . 2874. . 2449. . 5906. 9. 8418. 118. . 121. 5360. 1090. 14963. 3011. 46. . 8459 \quark_if_nil:nTF . . . 5584. . 10329. . 10326. . . . 9106 \q_recursion_stop . 10265. 3269. . 8. 10846 \s__fp_overflow . 9749. 9646. . . . . . . . . . . 11763. 10929. 487 \scriptstyle . 2337. 6215. . . . . . 13624. 771. . . . . . . 13483. 1898. 12958. . . . . . 14804. . . . 9651 \s__fp_exact . 9644. . 5409. 7396 S \S . 6379. . . 12748. 5188. . . . . 11474. . . 4298. 534 \romannumeral . . 11508. . 11646. 10176. . . . . . 13244. . 766. 11578. . . . . 15173 \scantokens . 13008. . . . 11648. 5411 \seq_gconcat:ccc . . 13214. 11513. . . . . . . 9657 \s__fp_invalid . . 4537. 5406 \seq_clear:N . . . . . 104. . . . 4547. . 3595. 11618. . . 11509. 13201. 9268. . 5455. . 5755. . 3148. . 9827. . 1976. 110. . . . . . . 9. 447 \scriptspace . . . 2337. 10185. . . . 11505. . . . 3262. . . 11675. . 4482. . 446 \scrollmode . 48. . . . . . . . . 11485. . . . . . 1077. . . . . . . . . 12435. . . . . . 12937. . . 12409. . 7392. . 13184. . . . . . . 12413. . 2843. 6350. 1101. . . . . 9833. . . . 5407 \seq_gclear_new:c . 9648. 9652. . . . . . . . . . 12980. 5455. 13186. . 5787 \seq_count:N . 9649. 14821. . . 13216. 5405. 6215. . . . . . 6371. 14952 \seq_display:c . 9729. . 9673. . . 9648. . . . . . . . 11340. . . . 11497. . 9648 \s__fp_mark . 11586 \s__fp_underflow . . 11482. . . 12978. . . 9891. 476 \righthyphenmin . . 9660 \s__fp_stop . . 9646. .Index \reverse_if:N . 734 \savinghyphcodes . 6245. . . . 10818. 2597. . . . 9717. . . . 9837. 9266. 13246. 5761 \seq_get:NNTF . . . . . . . . 1667. 13231. . . . . . 11659. 6605. . . 7894. 7957 \seq_clear_new:c . . 2044. 15169. . . 263. 602 \scriptscriptstyle . 9654. 12956. . . . . 14807. . . 9648. 6412. . . . 6248. 5455. . . 4477. 13199. . . 9660. . . . 13109. 4730. 12508. 13557. . . . . 10255 \s__fp 9640. . 14840. 1895. . . 105. 9359. . 11366. . . . 9647. . 6415. 9659 \s__fp_unknown . . . . . . 2340. . 10409 758 \s__prop . . . . 9656. . . 6432. . 14985. 5725. . . 11506. . . . . . . . . 126. . . 412 \seq_clear:c . 9655. . 9835. 2594. . . 5786. . 9656. . . 9825. . 277. 13844 \s__fp_division . . 5761 \seq_get:NN . . . 5781. 4732. 12175. 4526. . . 11687. . . . . 4124 \scan_stop: . 12178. . . . . . . . 1147. . . 6623. . . 12822. . 11644. . . . . . . . . . . 13511. . 5409. . 4446. . 1461. 4731. . 4485. . 5755. 4542. . . 11525. . . . 5755. 10187. . 7337. 5734. . . . . . 532 \rightskip . 15171. 104. . 13171. . 9697. 5457 \seq_concat:NNN . . . . . . . 9655. . . . . 12746. . 11949. . . . . . . . . . 9663. 5405. . . 9885. . . 12522. 12167. . . . . 13775. . 4451. . . . . . . . 12729. . 1892. 5409. . 11540. . 2597. 104. 3597. . 104. 11676. 12520. 12395. 5412 \seq_gclear_new:N . . . . 11914. 2766. . . . . . . . . . . . 13024. . . . . 9640. 790. . 1119. . . . . 24. 5405. . 9648. 13424. 11647. . . . . 11514. . 13229. . 2598. . . 5616. . 12961. . 14825 \s__stop . . 11496. . . . 3280. 12959. 3748. . . 3271. . . . 9650. . . 11656. 5458 \seq_gconcat:NNN . . . . . . . . 12994. 1934. . . . 5781. 5762 \seq_get:cNTF . . . . . 11512. . . 609 true . 13124. . . . . 13835. . . 10677. . . 9654. 13533. . . . . 9648. 11678. 5409. . . 10013. . . . . . . . . 10816. . . . 969. 5410 \seq_clear_new:N . 13299. 13508. . 13006. 7341. 5782 \seq_gclear:c . . . 2043. 10018. . 6330. 9669. . 13271. . 5725. 11510. . 13674. . . . . 12170. 9834. . . . . . . . . . . 11643. . . . 11952. . . . . . 5405. . . . 13122. . . . . . . 12807. 13451 \right . . . . 9696. . . . 11565. 3599. . 180 \rule . . . 6367. . . . . . . . . . 12031. . . . 9831. . . 790. 179 \scan_align_safe_stop: 42. 1129. . . . . . . . . . 5725. 5456 \seq_get:cN . 11528. . . 5783 \seq_display:N . . . . . . 9830. . . . . . . . . . 13465. . . . . 5409 \seq_concat:ccc . . . . 13964. 1897. . . . 1896. . . 13675. . . . . 13782. . . . . 11048. 11544. . 105. . . . 11555. 9659. . . . 696 \savingvdiscards . . . 5455. 4729. . . . 11948. 12404. 4304. . . . . . 5761 . . . . . . 110. 9653. . 5756. 3601. . . 14984. . 13005. . . . 655 \scriptfont . . 13469 \savecatcodetable . . 5485. 9887. 5455. . . 11621. 4435. 10815. . . . . . 9884. . 9693. . . . . . 697 csc . . 9707. . 12973. 5405. 11365. . . . . . . . 109. . . . . . . . 13259. . . . . 13601. 9829. . 11624. . . . 601 \scriptscriptfont . . . 10820. 1460. 9361. . . 5408 \seq_gclear:N . . 9646. 13290. 5187. . . . . . 13560. 4293. . . . . . 2355. 9653. . 9112 \seq_count:c . . 4302. . 9657. . . . . 13961. . . . . . 5760. . . . . . . . . . . . . . . . . . . . . 5469. 5666 \seq_gpush:cn . 195. . . . . . . . . . . . . . . . . . 5482. . . . . . . 14912. 5649. . . . . . . . . . . . . . . . . . . . . . 5459. . . . . 5636. 104. . . 5413. . . . . 5735. . . 5745 \seq_gpush:No . . . . . . 5476. 5755. . . . . . . . . . . . 5413. 110. 9212 \seq_gset_split:NnV . . . . . 5751 \seq_gpush:cv . . 5520 \seq_gremove_duplicates:c . . . . . . . . . . . . 14883 \seq_gset_from_clist:cn . . . . . . . . . . . . . . . . . 108. . . 5735. . . . . . . 5761. . . . . . . . . . . . . 5637 \seq_get_right:NN . 5469. 14927 \seq_gset_eq:cc . . . 5609 \seq_gpop_right:cNTF . 5749 \seq_gput_right:cn . . . 13950 \seq_gput_left:cn . 5640 \seq_get_right:NNF . . . . . . . 5748. . . 5761. 5494 \seq_greverse:c . . 14883 \seq_gset_from_clist:NN . . . . . . . . . 5748 \seq_gput_left:NV . 5479 \seq_gremove_duplicates:N . . . . 5753 \seq_gpush:cV . 5637 \seq_get_left:NN . 5746. . 14883. . . . . 110. . . . . . . . . . . . . . . . . 5474. . . . 5459 \seq_if_exist:NTF . 5523 \seq_if_empty:cTF . . . . . . 5754 \seq_gpush:Nn . . . . 5521 \seq_if_empty:N . . . 5481. . . . . 5747 \seq_gput_left:Nx . . . . . 5611. . . . 5658 \seq_gpop_left:NNTF . . . . 5637. . . . . . . . . . . . . . 107. . . . . . . 5756. 5766 \seq_gpop:cNTF . . . . . . . . . . . . . . . . . . 194. . 9157. 5568. 5469. . . . . . 14467 \seq_if_empty_p:c . 5645 \seq_get_right:NNT . . . . . . . . . 111. . . . . . . . . . . 5469 \seq_gremove_all:cn . . . 5469 \seq_gput_right:co . 5755. . . . . 5665 \seq_gpop_right:NNT . . . 195. . . . . .Index \seq_get_left:cN . . . . . . . . . . . 9205 \seq_gput_right:NV . . . . . . . . . 5579. . 9343 \seq_gpop_left:cN . . . 5469 \seq_gput_right:Nx . . . . . . . . . 14883 \seq_gset_from_clist:cN . . 107. . . . . . 5469. 5759. . . . . . 5646 \seq_gpop:cN . . . . . . 5753 \seq_gput_left:cV . . 5469. . . . 5735. . . . . . . . . . 5591. . . 5469 \seq_gput_right:cV . . 194. . . . . . . 5637. . . . . 106. . . . . . . . 105. . . . . . . 5608. . 105. . . . . . . . . . 5568. . . . . 5469. 5469. . . . . . . . . . 5592. . . . . . . 5460 \seq_if_exist:cTF . . . 5471. 9370 \seq_gpush:Nv . . 5643 \seq_get_right:cN . 9062 \seq_gput_right:Nv . . . 5637. . . 9162 \seq_gput_right:No . . . . . 5660 \seq_gpop_right:cN . . 5754 \seq_gput_left:Nn . 5568. 5579. 5420 \seq_gset_eq:cN . . . 14908 \seq_gset_map:NNn . . . . . . . 5766 \seq_gpop_left:cNTF . . . . 5469. . . . . . . . . . . 5779 \seq_get_left:cNTF . . . . . . . . . . . . . . . . . . . 5751 \seq_gput_left:cv . . . . . . . . . . 5469. . . . . . . . . 14898. 5521 \seq_if_empty:NTF . . . . . . . . . . . . 5473. . 5644 \seq_get_right:NNTF . 5761 \seq_gpop:NN . . . . . . . 5735. . . 9250. 5735. . . . . . . . . 14909 \seq_greverse:N . . . . . . . 5419 \seq_gset_eq:Nc . . . . . 14950 . 5592 \seq_get_right:cNTF . . . 5423. . . . . . . . . . . . . . . . 5521 \seq_if_exist:c . . . . . . . . . . . . . . . . 5421 \seq_if_empty:c . . . . . . . . . 105. . . 13963 \seq_gpop:NNTF . 8196. . 5745 759 \seq_gput_left:No . . . . . . . 14893. . . . . 14938. . . . . . . . 5639. . . 14940 \seq_gset_split:Nnn . . 5765. 9167. . . . . . . . 5647 \seq_gpop_right:NN . . . . . . . 5653 \seq_gpop_right:NNF . . . . . . 5735. . . 108. 5413. . . 107. . . . . . . . . 5755. . . 5581. . . . 5749. . 5469. 5479. 5752 \seq_gpush:cx . . 5647. . . . . . . . . . . . . . 5469 \seq_gput_right:cx . . . 106. . . . . 5759. . . . . . 5778 \seq_get_left:NNF . . . . . . . . . . . . . . 5413. . 5752 \seq_gput_left:cx . . . 5469 \seq_gput_right:Nn . . . . 5469. . . 5418 \seq_gset_eq:NN 104. . . . . . . . . 5421. . . . . . . . . . 5475. . 5647. . . . . 14928. . . . . . . . 14906. . . . 5469 \seq_gput_right:cv . . . . . . . . . . . . . . 5638. . . . . . . . . . . . . . . . 5641 \seq_get_left:NNTF . . . . . . 5647 \seq_gpop_left:NN . . . . 5592. . 5454. . . . 105. 14883 \seq_gset_from_clist:Nc . . . . . 5664 \seq_gpop_right:NNTF . 5750 \seq_gput_left:co . . . . . . . . . . 5735. 5578. . . . . . . . . . . . 5417. 5659 \seq_gpop_left:NNT . . 14909. . 5735. . 5765 \seq_gpop_left:NNF . . . 5469. . . 5642 \seq_get_left:NNT . . . . . . . . . . . . . . 5469. 5747 \seq_gpush:Nx . 14930 \seq_gset_from_clist:cc . . . 106. . . . . . . 9326 \seq_gset_filter:NNn . . . . 5495. . . . . 9164 \seq_gpush:NV . . . . . . . . 5735. . . . . . 5746 \seq_gput_left:Nv . . . . . . 5469. 5762. . . . . 9277. . 5497. . . 5521 \seq_if_empty_p:N . . 5521. 105. . . . . . . . . 5459 \seq_if_exist:N . . 106. . . . . . . . . . . . . 5750 \seq_gpush:co . . . . . . . . . . . 14883. . . . . . . . 5735. . . 14907 \seq_gset_from_clist:Nn . . . . . . . 5760. . 5495 \seq_gremove_all:Nn 108. . . . . . . . . . . . . 5609. . . . . . . . . . . . . . . . . . 107. . 7978. . . . . . 9198 \seq_map_variable:ccn . 7909. 5721. . . . . . . . 5647. 105. . 5743 \seq_put_left:cV . . . . . . . . . . . . . . 9056. . . . 5547. . . . 5755. . 5479 . . . 5761 \seq_pop_left:cN . . . . . . . 5590. . . . . . . . 5403. . . . . 5713 \seq_map_variable:NNn . . . . . . . 5713. . . 9072. . . . . . . 5761 \seq_pop:NN . . 14833. . . . . . . . . . . . . 5763 \seq_pop:NNTF . . . . . . . . . . 5495. 5735. 5758. . . . . . . . . . . . . 5647. . . . . . . 5736 \seq_push:Nv . . 5461 \seq_put_right:cv . . . . . . . 5459 \seq_if_exist_p:N . 5739 \seq_put_left:cn . . . 5404 \seq_new:N . 5741 \seq_put_left:cv . . 5635. . . . . 5735. . . 5706. . . . . . . . . . . 14857. . 5461 \seq_put_right:co . 14857 \seq_mapthread_function:NNN . . . . 5647 \seq_pop_right:NN . . . . . . . . . . . . . . 5525 \seq_if_in:cvTF . . 5774. . . . . . . . . . . . . . 5461. . . . 5667. . . . 5663 \seq_push:cn . 107. 5735. . . . . . 5461. . . . 14881. 5713. . . . . . . 5461 \seq_put_right:Nn . . . . . . . . . . . . . . . . . . . . . . . . . . . 5495. 5713 \seq_map_variable:Ncn . . 5758. . . . . . 5525 \seq_if_in:NnF . . . . . . 5712. . . . . 5738 \seq_push:NV . 5525 \seq_if_in:NxTF . . . . . . . . . . . . . . . . . 5706. . . 5545 \seq_if_in:NnTF . . 5478. . . 5544. . . . . . . . 5674. . . . . . . . . . . . 108. . . . . 5742 \seq_put_left:cx . . . 5743 \seq_push:cV . 5671. . . . . . . . 5546. 5738 \seq_put_left:NV . 5525 \seq_if_in:NvTF . . . 5742 \seq_push:cx . 5662 \seq_pop_right:NNT . . . . . . . . . . 5468. . . . . 5763 \seq_pop_left:NNF . . . . . . . . . 9122 \seq_map_break:n 109. . . 5525 \seq_item:cn . . . . . . . . . 5764 760 \seq_pop_left:cNTF . . . 110. . . . . . . . . 5737 \seq_put_left:Nx . . 5403. . . 105. . . . 5755. . . . . . . . . 5730. . 5735. . . . . . . 5790. . 7904 \seq_put_left:No . . . . . . . . . . . . . . 5525. . . . . . 5723. . . 5773. . 105. . 7866. . 4. 5466. 5737 \seq_push:Nx . 5757. . 5461. . . . 5647 \seq_pop_left:NN . 5786 \seq_map_break: 109. . . 5740 \seq_push:co . . 5461. 5735. . . . . . . . . . . 5744 \seq_put_left:Nn . . 9116. 9067. . . 5459 \seq_if_in:cnTF . . 7974. . . 9175 \seq_if_in:NnT . . . . . . . . . 111. . . . . . . . . . 5525 \seq_if_in:coTF . . 9176 \seq_put_right:No . . . 5785. . . . . . . 5713 \seq_map_variable:cNn . . 5525 \seq_if_in:NVF . . 5757. . . . . . . 110. . . . . . . . . . . . . . . . . 5486. . . . . . . . . . . . 5461. . . . 5740 \seq_put_left:co . . . . . . 5461. . . . 194. . 5461. . . . . . 5787 \seq_length:N . . . . . . . 5669. . . 5549 \seq_if_in:NoTF . 5525 \seq_if_in:cxTF . . 5495 \seq_remove_all:Nn . . . . . . . 5736 \seq_put_left:Nv . . . . 7980. 5519. . . . 5609. . . . . . . . . 5770. . . . . . . . . . 5775. . . . . . . . 5785. . . 5735. . . . . . . 5724 \seq_mapthread_function:ccN . . . . 5467. . . . 5463. . 14833 \seq_item:Nn . . . . . . . . . . . 5548. . 5741 \seq_push:cv . . . 106. . . . . . . . . . . . 104. .Index \seq_if_exist_p:c . . . . . . . . . . . . . . . . . . . . . . . . . . 5667. . . . . 9276. 5735. 5655 \seq_pop_left:NNTF . . 13916 \seq_pop:cN . . . . . . . 9324. . . . 5670. . . . . 14473 \seq_map_inline:cn . . . 2725. . . . . . . . . . . . 5489. . . 5461 \seq_put_right:cV . . 5710. . . . . . . . . 5668. . . . . 5579. 5579. . 5656 \seq_pop_left:NNT . . . 5461. . 14882 \seq_new:c . . . . . 9181 \seq_remove_duplicates:c . . . 5647. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5609 \seq_pop_right:cNTF . . . . . . . . 7928 \seq_map_function:cN . . . . . . . . . . . . 106. . . . . 7867. . . . . . . . . . 5675. . 7975. . . . . . . . 5776. . . 5461 \seq_put_right:Nx . . . . . . . 5683. . . 7965. . . . 108. . . . 5461. . . . . . . 5525 \seq_if_in:Nn . . . 14857. . . . 5651 \seq_pop_right:NNF . . . . 5657 \seq_pop_right:cN . . . . 108. . 5488. . . 5671. . . . . 5579. . . . . 5764 \seq_pop:cNTF . . 5609. . . . . . 5735. . . . . . 14857 \seq_mapthread_function:cNN . 5461 \seq_put_right:cx . 5671 \seq_map_function:NN 4. . . 5735. . . 194. . . . . 5461 \seq_remove_all:cn . . 5706 \seq_map_inline:Nn . . . . . . . . . 5403. . . . . . . . . . . . 5661 \seq_pop_right:NNTF . . . . . . . . . . . 14856 \seq_length:c . . . . . . . . . . . . . . . . . 9191 \seq_put_right:NV . . . . 5735. . 108. . 14833. 5461. 5461. . . . . . . . . 7914. . . . 5461 \seq_put_right:Nv . . . . . . . . . . 9057. . . . . . . . . . . . . 5461. . . . . . 9077. . . . 5461. . 5739 \seq_put_right:cn . . . . . 5667. . . . 14857 \seq_mapthread_function:NcN . . . 2742. . . . . . . 9210. 9069. . . . . . . . 5744 \seq_push:Nn . 9369 \seq_if_in:NVTF . . 5465. 108. . 5735 \seq_push:No . . . . . . . . . . . . 5525 \seq_if_in:cVTF . . . . . . 5735. . . . . . . . . . . . 5421. . . 195. . . . 4438 \skip_gset_eq:cc . . . 5789 \seq_use:N . . . . . . . . . . . . . . . 4561 \skip_if_infinite_glue:nTF . . 5791 \seq_use:Nnnn . . . . . . . . . . . 4449 . . . . . . . . 5415 \seq_set_eq:Nc . . . . . . . . . . . . . .skip_set:N . . . . . 14909 \seq_reverse:N . 194. . . 5421. . . 391 \showbox . . . . . 14909. . . . . . . . 14883. . . . . . . . . 638 \sffamily . . . . . 4416. . 84. . 7564 \setbox . . . . . . . . . 4480. . . . . . . . . . . . . . 4480. . . . . . . . 4429. . . . . . . . . . 5790. 4432 \skip_if_exist:N . . 4445. . . . . . . . . 84. . 4443. . 14928 \seq_set_from_clist:cc . 153 \skip_gset:cn . . . . . . . . . . . . . . 4496. . . . . . . . . . . . . . . . . . . . . . . . . . . 153 \skip_set:Nn . . . . . . . . . . . . . . . . 5779 \seq_top:NN . . . . . . 14903. . 4495. . . . . . . . 4436. . 5421. . 629 \skip_add:cn . 5767. 14883. . . . . . 4436. . 4434. 5416 \seq_set_eq:cN . . . . . . . 4481 \skip_if_eq:nn . . . . . . . . . . . . . . . . . . . 4423. 14883 \seq_set_from_clist:Nc . . . . . . . . . . 5493. . 4445. . . . . 4408 \skip_new:N 83. . . . . . . . 4494. . . . . 548 \show . . . . 4560 \skip_if_infinite_glue_p:n . 111. . 14910. 4465 \skip_if_infinite_glue:n . . . . . . . . . 5615. . . . . . . . . . . 407 \showboxdepth . 4427. . . . . . . . . . . . . . . . . 4562. . . . . . 9110. . . . . . . . 4442. . . . . . . . . . . . 4444 \skip_gsub:cn . 7330 \shipout . . . . 83. . 86. . 9111 \seq_show:c . . . . . . . . . 4452. . . . . 83. . 5767. . . . . . . 4445. . . 4445 \skip_add:Nn . . . . . . . . . . . . . . . 4439 \skip_gset_eq:NN 84. . . . 5413.skip_gset:N . 83. . . 4427. . . . . . . . . . . . . . . . 83. . 5772. . . . . . . . . . . . 4433 \skip_if_exist:cTF . . . . . . 5777. . . . . . 4486 \skip_horizontal:n . . . . . . . . 104. . . 84. . 4480 \skip_horizontal:N . . . 83. . . . . . . . . . 4455 \skip_if_exist:c . . . . . . . 4434. . . .Index \seq_remove_duplicates:N . . . . . . . . . . . . . 4465. . 4416 761 \skip_const:Nn . . . . . . . . . 194. . . 5778 \seq_use:c . . . . . . 4560 \skip_new:c . . . . . . 4445 \skip_gsub:Nn . . . . . . . . . 5783 \seq_show:N . . . . . . . . . . . . . . 4418. . . . . 4492. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4432 \skip_if_exist_p:c . . . . 4434 . . . . . . . . . . . . . 5628 \seq_top:cN . . . . . . . . . . . . . . . . . . . 5777. 4439 \skip_set_eq:cN . . . . . . . . 84. . . . . . . . 4447. . . . . . . . . . . 14883 \seq_set_from_clist:cn . . . . . . . . 14883 \seq_set_from_clist:cN . 107. . . . . . . 4439. . . . . . . . . . . . 104. . . . . . . . . . . . 341 \sfcode . . . . 5413. . . . . 4448 \skip_const:cn . . . . . . . 4432 \skip_if_exist:NTF . 4439. .skip_gset:c . 4434 . . . 14938 \seq_set_split:Nnn . 9127. . . . . . . . . 605 \skip . . . . . . . . . . . . . . . . . . . 669 \showlists . . 14883 \seq_set_from_clist:NN . . 4480. . . . 2743. 5789. . . . . . . . . . . 4454 \skip_gzero:c . . . . . . . . . . 14905 \seq_set_map:NNn . . . . 14888. . . . . . 4431 \skip_horizontal:c . . . . . . . . . . . 14948. . . . . . . 4439 \skip_gset_eq:cN . . 153 \skip_set:cn . . . . . . . . . . . . . . . 4447. . . . . . 9196 \seq_reverse:c . . . . . . . . . . 668 \showifs . . 14938. 4455 \skip_if_eq:nnTF . . . . . 4437 \skip_set_eq:cc . . . . . . . . . . . 5414 \seq_set_eq:NN . . . . . 5413. . . . . . . . . . . . . . . . . 4482. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2738. . . . . . . . . . . . . . . . . . . . 5413. . . . . . . . . . 583 \setlanguage . . . . . . . . . . . . . 84. . . . . . . 195. . . . . . . . . . 14948 \set@color . . . . . . . . . . . . . . . 4409. . . 656 \skewchar . 4445 \skip_gadd:Nn . . . . . . . . . . . . . 4434. . . . . . . . 4429. . . 4439 \skip_set_eq:NN 84. . . . . . . . 408 \showgroups . . . . . . . . . . 4425. . . . 4441 \skip_show:c . . 393 \showboxbreadth . . . . . . . . . . . . . . . . . . . . . . . . . . 4440. . . . . . . . . 4467 \skip_if_finite:nTF 84. . . . 4488 . . . 83. . . 4455 \skip_if_eq_p:nn . . 4432 \skip_if_exist_p:N . . . 4429 \skip_gzero_new:c . . . . 4439 \skip_set_eq:Nc . . . . . 4476. . . . . . . . . . . . . . . . . . . . . 4426. . 394 \showthe . . . . 392 \showtokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4428. . 7563. 5782 \seq_tmp:w . . . . . . . 4415. . 4445. 83. . . . . . 5453 \seq_set_split:NnV . . . . . . . . . . . 14928. . 14982 \skip_if_finite_p:n . . 4497 . . . . . 4422 \skip_gzero:N . . . . . . . . 195. . 83. . . . . . . . 5479. . . . . . . . 4458. . . . . 4408. . . 83. 14926 \seq_set_eq:cc . . . 14904 \seq_set_from_clist:Nn 14883. . . . . 4422. .skip_set:c . . . . . . . . . . . 4439 \skip_gset_eq:Nc . 153 \skip_gset:Nn . 4432 \skip_if_finite:n . 5413. . . . . . . 5480. . . . 4421. . 4419. . 9185 \seq_set_filter:NNn . . . 4439. . 4416. . 5767. . . . . 4493 \skip_eval:n . . . 4426 \skip_gzero_new:N . 5479. . . . 4476 \skip_gadd:cn . . . . . . . . . . . . . . 3283. 452 \tex_abovewithdelims:D . 4487 \skip_vertical:n . . 2078. 4477. . . . . . . . 1513. 22. . . . 15135 pt . . . . . . . . . . . . . . 426 \splitbotmarks . . . . . 652 \splitdiscards . . 4490 \skip_split_finite_else_action:nnNN . . . . 425 \splitfirstmarks . . . . . 617 \splitbotmark . . . 70 \string . 149. . . . . . . 2080. . . . . . . . . . . 100. . . . . . 3527. . . . . . . . . . . . 526 \tex_advance:D . . . . . . . . . . . . . . . . . . . . . 4485. . 4484 \skip_zero:c . . . . . . . . . . . . . . . . 13924 \tex_cleaders:D . . . . . 453 \tex_belowdisplayskip:D . . . . . . . . 477 \tex_botmark:D . . . . . 180 \tabskip . . . . . . . . 4480 \skip_vertical:N 86. . . . . . . . . . . . . 4452. . 5200. . . . . . . . . . 1615 \str_if_eq:xxTF . . 1539. . . . . . . . . . . . . . . . . . . . 4422 \skip_zero:N 83. . 1614 \str_if_eq_x:nn . 83. 825. . . . . 333. . . . . . 5599. . . . . . . . . . . . . . . 4424. . 2073 \str_if_eq:onTF . . . . . . . . . . 2356. . . . . . 5176. . 2073 \str_if_eq:nVTF . 7750. . 5184 \strcmp . . . . . . 4054. . . . . . . . . . . . . . . . . . . . . 4537. . . . . . . . 4732 \tex_char:D . . . . . . . . . 2471 \str_head:n . 14827 \str_if_eq_x_p:nn . 516 \tex_batchmode:D . . 547 \spaceskip . . . . . 821. . . . . 3092. 1897. 9359. . . . . . . . . . . . . . . 23. . . . . . . . 4450. . . . 4426. . . 823. . . . . . 356 \tex_above:D . 2073. . . . . . . . . . 8421 \str_if_eq:noTF . . . . . . . . 2075. . 4480. . . . . 2614. . 1613. . . . . . . . . . 454 \tex_binoppenalty:D . . . . . . . . . . . 2469. . . . . . . . . 438 \tex_abovedisplayshortskip:D . . 355 \special . . 2822. . . . . . . . . . . . . . . . . . . . . . . 1532. . . . . . . 4422. 4427 \skip_zero_new:c . . 2077. . . . . . . . . . . . 2470 \str_case_x:nnn . 3517. . . 2073 762 \str_if_eq_p:Vn . . . . . . . . . . . . . 344. . . 1616 \str_if_eq:xxT . . . . . 3515. . . . . . . . . . . . . . . . . . . 4423. 1550. . . . . 1066. . . . . . . . . 819. . . . . 6544 \tex_boxmaxdepth:D . . 4490. . . . . . 2115. . . . . . . . . . . . . . 5247 \str_if_eq:nn . . 4445 \skip_sub:Nn . . . . . . . . . . . 2073 \str_if_eq_p:xx . . . . . . 3021. . . 588 \tex_baselineskip:D . 699 \splitfirstmark . . . . . . . . . . . . . . 196. 7925 \str_if_eq:nnTF . . . . 3494. . . . . . . . . . . . . . . . . 5503. . . . . . . . . . . 820. . . . . . . . . . . . 4480. . . . . . 795 \tex_atop:D . . . . . . . . . . . . 451 \tex_abovedisplayskip:D . 1543. . . 508 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1078. . . . . 1896. . 7968 \str_if_eq_x:nnT . 230. . . . . . . . . 212 \spacefactor . . . 2073 \str_if_eq_p:VV . . 22. . . . . . . . 1532. 594 \tex_brokenpenalty:D . . . . . . . . 651 \splitmaxdepth . . . . . . 1513. . . . . . . . 2073. . . . . . 85. . . . . . . . . 4478. . . 1617 \str_if_eq_p:nn . . . . . . . 4479 \skip_vertical:c . . . . . . . . 5176. 9524. . . . . . . . 424 \tex_box:D . . . . . 1532. . . . . . . . . . 4446. . . . . . . . . . . . . . . . . . . . . . . . . 15078 \str_case:onn . . . . . . . . 542 \span . 5625 \tex_aftergroup:D . . . 50. . . 2341. . . . . . . . 100. . 4057. 1895. . . . . . . . . 1613. . . . . 22. . 610 T \T . . . . . . 2073 \str_if_eq:VnTF . . . . . 2074 \str_if_eq_p:no . . 4426 \skip_zero_new:N . . . . 439 \tex_accent:D . . . . . . 4478. 2073 \str_if_eq:VVTF . 1519 \str_if_eq_x:nnF . . 5176. 2076. . . . . . . . . . . 22. . . . . 328 \space . . . . . . . 3493. . . . . . . . . . . . . 636. . . . . . 2073 \str_if_eq_p:on . . . . . . 441 \tex_badness:D . . . . 551 \tex_catcode:D . 3017. . . . . 1513. . . 595 \splittopskip . . 1617. .Index \skip_show:N . . 409 \tex_begingroup:D . . . . . 4483. . 343. 2043. . . . . . . . . . 3529. . . . . . . . 4430 \skipdef . . . . . . . . 1616. 85. . . . . . . . 4426. . . 4451. . . . . . . . . . . . 8181 \str_if_eq:nnT . . 632. 490 \tex_chardef:D 325. . . . . . . . . . . . . . . . . . . . . . 4470. 1614 \str_tail:n . . . . 10312. . . . . 822. . . . . . 14980. . . . . . . . . . . . . . . . . . . 596 \str_case:nnn . 2079. . . 2073 \str_if_eq_p:nV . . . . . . . . . . . . . . . . . . . . 2081. . 4227. . . 4731. . . . . . . . . 4478 \skip_use:N 85. . . . . . . . . . . . . 1461. 4488. . . 2616. . . . . . . . . . . . 2612. . . . . . . . . . . . 347. . . . . . . . 84. . . 1513 \str_if_eq:nnF . 4453 \skip_use:c . 4445. . . . . . . . . . . 4542 \tex_afterassignment:D . . . . . 14980 \skip_sub:cn . . 791 \tex_belowdisplayshortskip:D . . . . 22. 4422. 1615 \str_if_eq_x:nnTF . . . . . . . . . . . . . . . . . 440 \tex_atopwithdelims:D . . . . . . . 2073 \str_if_eq:xxF . . . . . . . . . . . . 77. . . . . . . . . . . 489 \tex_adjdemerits:D . . . . . . . 4489 \skip_show:n . . . . . 6373. . . . . . . . 4222. . . . . . . 6522. . . . . . 1065. 1513. . . 9266. 2117. 1898. . . . . 4488. . . . . . . . . . . . . . . . . . . . . . . . . 591 \tex_hoffset:D . . . . . . . . . . . . . . . 323. . . . . . . 6685. 395. . 3531. . . . . 4514. . . . . 770. . . . . . . . . 359. . . . 826 \tex_emergencystretch:D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796. . . . . . . . 4423. . . . . . . . . . . 6652. . . . . . . . . . . . 9047. . 5324. . 6860. . . . 423 \tex_floatingpenalty:D . . . . . . . . . 3521. . . . . . . . 1272. . . . . . . . . . . . . . . . . . 743 \tex_everyhbox:D . . . . 321. 9608. . . . . . . 458. 262. . . . 830 \tex_else:D . . 7688 \tex_errmessage:D . 4452. 742. . . . 352 \tex_csname:D . . 783 \tex_endgroup:D . . . . . . . . . . . . . . . 6623. . . . . . . . . 263. 7811 \tex_endlinechar:D . . 3497. . . 6545 \tex_count:D . . . . 4647. . 9317 \tex_eqno:D . . . . 358. . . 332. . . . . . . . . . . 379. . . . 6624. . . . 326. . . . . . . . . . 627. 480 \tex_delimitershortfall:D . . . . 6673. . . . . 6667. . . . . . 4654. . . . . . . 784 \tex_fam:D . . . . . . . 6516. . . . . . . 431 \tex_delimiterfactor:D . . . . . . . . . . . . . . . . . 2915 \tex_cr:D . . . 456 \tex_displaylimits:D . . 4223. . . . . . . . . 530. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457 \tex_divide:D . . . . . . . . . . . 6654. . 337 \tex_fi:D . . . . . . . . . . . 6650 \tex_hfil:D . . . . . . . . . . . . . . . . . . 13924 \tex_globaldefs:D . . . 363. . . . . 519 \tex_copy:D . . . . . . . . . . . . . . . . . . . . . . . . . 338. . 6529 \tex_hyphen:D . 491 \tex_displayindent:D . 556 \tex_def:D . . . . . . . . . 322. . . . . . . . . 3477. . . . . . . . . . . . . . . . . . . . . . . . . . . 744 \tex_everypar:D . . . . . 396. . 521 \tex_expandafter:D . . . . . . . 607 \tex_delcode:D . 4436. . . 635. . . 740. . . . . 569 \tex_hrule:D . . . 6679. . . . . 495. . . 9059. . 628. . . . . . . . . . . . . . . . 4527. . . . 413. . . . . 7740 \tex_errorstopmode:D . 410 \tex_escapechar:D . 6530 \tex_dump:D . . . 6631. 376. . . . 539 \tex_end:D . 6817. . . . 4538. . . . . . 1185. . . . . . . . . . . . . . . . 9367 \tex_clubpenalty:D . . . 800. . . . . 327. . 622 \tex_deadcycles:D . . . 387. . . . . . 618 \tex_edef:D . . . . . . . . 6862. . . . . . . 6649. . . . . . . . . 6580. . . . . . . . . 9266. . 342 \tex_halign:D . . . . .Index \tex_closein:D . . . . 1279. . . . . . . . 4218. . . . . . . . . 773 \tex_ifcase:D . . . . . . . . . . . . 769. . . . . . . 9049. . . 4533. . . . . 6635. . . . 2890 \tex_dimendef:D . . 745 \tex_hyphenation:D . . 6625. . 349 \tex_hangafter:D . 566 \tex_holdinginserts:D . . . . 14297. . . 319. . . . 606 \tex_defaultskewchar:D . . . 444 \tex_displaywidowpenalty:D . . . . . . . . . . . . . . . . 3509. . . . . . 598 \tex_exhyphenpenalty:D . . 360. . 2893 \tex_discretionary:D . . . . . . . . 4447. . . . . . . . . 525 \tex_firstmark:D . 334 \tex_doublehyphendemerits:D . 603 \tex_fontname:D . . . . . . . . . . . 336 \tex_fontdimen:D . . . . . . . . . . 4480 \tex_hss:D . . . . . . . . . 772. . . . . . . . 6816. . . . . . . . . . 9315. . . . . 493 \tex_hfuzz:D . . . . . 828 \tex_finalhyphendemerits:D . 9606. . 357 \tex_everydisplay:D . . . . . . . . . . . . . . 1177. . . . . . . . . . . . 589 \tex_hbox:D . 545 \tex_everyvbox:D . . . . . . 774 \tex_ifdim:D . . . . . 415. 829 \tex_defaulthyphenchar:D . . . . . 782 \tex_day:D . . . . . . . . . . . . . . 527 \tex_hangindent:D . . . . . . . . 14306 \tex_ht:D . . . . . . . . 576. . . 3533. . . . . . . . . . . . 7800 \tex_endcsname:D . . . . . 6863 \tex_hskip:D . . 6814. . . . 2912 \tex_countdef:D . . . . . 384. . . . . . . 455 \tex_displaywidth:D . . . . . 626. . . . 4652. . . . . . 314. . . . . . . . . . . . . . . . . . 466 \tex_displaystyle:D . . 348. . . . . . . . . . 4748. 620 \tex_hyphenchar:D . . 604 \tex_hyphenpenalty:D . 9437. 4212. . . 9274 \tex_closeout:D . 449 \tex_errhelp:D . . . . . . . . . . . . . . . . . 427 \tex_futurelet:D . . . . . . . . . . 4645. . . 492 \tex_hfill:D . . . . . . . . . . . . . . 816. . . . 482. . . . . . . . . . . . 312. . . 2117. 9411. . . 801. . . 3086. . . . . . 9061 763 \tex_everymath:D . . . . . 429. . . 6637. 522 \tex_if:D . . . . . 4199. 3088. . . . 3540. . . . . . . . 3387 \tex_ifcat:D . . . 494 \tex_hfilneg:D . . . . . . 505 \tex_hsize:D . . . 345. . . . . . . . 479 \tex_dimen:D . . . 6629. 637 \tex_delimiter:D . . . . . . . . . . . . . 4442. 7715 \tex_errorcontextlines:D . . . . . . . . . . . . . . . 3519. . 277. . . . . . . . 6524. . . . . . . 792 \tex_endinput:D . . . . . . . . . . 4228. . . 496. 843 \tex_global:D 307. . . . 9359. . . 798. . . . . . . . . 414. 570 \tex_font:D . 4181 . . . . . 9443 \tex_everycr:D . . . . . . . . . . . . . . . . 3088 \tex_gdef:D . . . . . . . . . 428. . . . . . 4543. . . 597 \tex_everyjob:D . . 375. . . . . . . . . . . . . 524 \tex_dp:D . . . . . 634. . 528 \tex_hbadness:D . . . . . . . . . . . . . . . . . . 351 \tex_crcr:D . . 584. . 389. . . . . . . . . . . . . . 6518. . . . . . . . . 770. . 463 \tex_mathcode:D 641. . . . 568 \tex_insertpenalties:D . . 2355. 830. . . . . . . . . . . . . . . . 511 \tex_lccode:D . . 3490 \tex_mathchoice:D . . . . . . 743. . . . 751. . . . 778 \tex_ifvoid:D . . 801. 339. 796. 470 \tex_mathpunct:D . 550 \tex_italiccorrection:D . . . . . . . . . . 9361. 2682. . . . . 7485. . . . . . 2692. 330. . . . 2089. . . . . . . 834. . 430 \tex_mathclose:D . 1079. . 790. . . . . . . . . . . 14557 \tex_language:D . . . . . . . . . . . . . 432 \tex_mathbin:D . . . . . . . 472 \tex_mathsurround:D . . . . . . . . . . . . . . . . . . . . . . . . 755. . 1174. . . . . 512 \tex_input:D . . . . 623 \tex_moveleft:D . . . . . . . . . . . . . . . . 6578. . . 813. . . . . . . . . . . . . . . . . . 6556 \tex_ifhmode:D . . . . 752. 748. . . 767. . 1077. . . . . . . . . . . . . 471 \tex_mathrel:D . . . . . 385. . . . . . . . . 2340. . . . . . . 378. 749. . . . . . . . 745. 4733. 517 \tex_lineskiplimit:D . . . . 775. . . . . . . . 840. . . . . . . . . 7126. . . . . . . . . . . . . . . . . . . . . . 848. . 779. . . . . . . . . . . . 420 \tex_lastbox:D . 2932 \tex_muskipdef:D . . . . . . . . . . . . . . . . . . . . . . . . . 781. . . . 776 \tex_ifnum:D . . . . . . . . . . . . . 523 \tex_lineskip:D . . . . . . . . . . . . . . . 6558 \tex_ifx:D . . . . . 320. . . . 793 \tex_ifodd:D . 2045. . . . . . . . . . . . . . . . 795. . . . . . . . 373. 783. . . . . 346. . . . . . 7197. . . 518 \tex_long:D . . . . . . . . . . 611. . . . . . . . . . . . . 773. 535 \tex_lower:D . . . 2690. . . . . . . 827. 7131. . . . . . . . . 2090 764 \tex_limits:D . . . . 1192. . . . . . . . . 419 \tex_mark:D . . . . . . . . . . . . 4659. . . 312. . . . . . . . . . . . . . . 353 \tex_noboundary:D . . . . . . . 308. . . . 811. . 507 \tex_left:D . . . . . . 3489. . . . . . . . . . . 6707 \tex_lastkern:D . . . . . . . . . . . . . . 742. . . . . 362. . 14295. . . . . . . . . 613. . . . . . . . . . . . . . . . . . . . . . . . . . . . 7486. 2089. . 639. . 411 \tex_nulldelimiterspace:D . . . . . . . . . . 1268. . 574. . 746. . 608. . . . . . . 533 \tex_leqno:D . . . . . 329. . 843. . . . . . . . 785 \tex_noindent:D . . . 14319. . . . . . . . . . . . 766. . 484 \tex_message:D . 792. 757. . . . . . . . . 1460. . 554 \tex_meaning:D . . . . . 514 \tex_nolimits:D . . 625. . . 14317. . . . . . 854. . . . . . 465 \tex_mathopen:D . . . . . . . . . . . . . . . 475 \tex_lefthyphenmin:D . . 794. . . . 9385 \tex_indent:D . . . 4773 \tex_mag:D . . . . . . 756. . . . . . . . . . . . . . . . . . . . 571 \tex_interlinepenalty:D . . . . . . . 468 \tex_nonscript:D . . . 775 \tex_ignorespaces:D . . . . . . 2686. . . . . . . . . . . . . . . . . . 793. . . . . . . . . . . . . . . . . . 777. 388. . . . . . . . . 572. 2090. . . . 335 \tex_muskip:D . . . . 616 \tex_lastskip:D . 4729. 371. . . . . . 437 \tex_month:D . 787. . . . . . . . . . . . . . . . 2044. . . . . 6557 \tex_ifvmode:D . . . . . . . . . . . . . 390 \tex_mkern:D . . . 370. . . . . . . . . 450 \tex_let:D . . . . . . . . 510 \tex_lastpenalty:D . . . 366. 469 \tex_mathord:D . 7593 \tex_iftrue:D . 754. . . . 784. . . 767 \tex_ifhbox:D . . . 753. . . 6555 \tex_lowercase:D . 531 \tex_leftskip:D . . . 364. . . . . . . 386. . . . 3044 \tex_number:D . . . . . . . . . . . . . . . . . . . . . . . 787. 318. 779 \tex_ifmmode:D . . . . 1462. . 780. 798. . . . 766 \tex_ifvbox:D . 747 \tex_jobname:D . . 7198. . . . . 856 \tex_looseness:D . . 369. . . 744. . . . . . . . . . . 368. 14362. . . . . 314. . . . . 361. . . . . . . . . . . . . . . . 462 \tex_mathchar:D . . . . . . . . . . 750. . . . 782. . . . 9367. . 9292 \tex_iffalse:D . . . 7662 \tex_insert:D . . . . . . 433 \tex_mathchardef:D . . . . . . 786. . . . . . 488 \tex_noexpand:D . . . 829. 599. . . . . . . . . . . . . . . . . . . . . . . . 768. . . 6551 \tex_mskip:D . . . . . . . 3284 \tex_mathinner:D . . . . . . . . 776. . . . . 3383 . . . 769. 4730 \tex_leaders:D . 481 \tex_nullfont:D . . . . 416 \tex_immediate:D . 842. . . . 778. 464 \tex_mathop:D . . . . . . . . . . . . . 1202. 1899. 844. . 1611. 2684. . 789. . . . 789 \tex_medmuskip:D . . 772. . . . 832. . . . . . . . 777 \tex_ifinner:D . . 3386. 374. . . . 746. . . . . . . . . 14360. . . . . 1172. . . . . 3285. . . . . . . 367. . . . . . . . . . . . . . 553 \tex_maxdepth:D . . . . . . . . . . . 788. . . 4655. .Index \tex_ifeof:D . . . . . . 9050 \tex_kern:D 503. . . 774. . . . . . . 448 \tex_nonstopmode:D . . . . . . . . . . . . . . . 467 \tex_linepenalty:D . . . 6549 \tex_moveright:D . 434 \tex_multiply:D . . . 372. 573. . . 785. . . 365. . . . . . . . . . . 771. . . . . 9166 \tex_inputlineno:D . . . . . 747. . . 421 \tex_mathaccent:D . . . 846. . . 2038. . . . 791. . . . . . . . 14110. . . . . . . . . . . . . . . . . . . . . . 14304. 2688. . . . 2935 \tex_newlinechar:D . . 577. 483 \tex_maxdeadcycles:D . 631. . . . . . 4749 \tex_noalign:D . . . . . . . 4309. . 12827. . 561 \tex_pagefillstretch:D . . . . . . . 1655. 10675. . . . 6677. . . . . . . . 355 \tex_special:D . 3292. . . . 562 \tex_pagestretch:D . 10831. 11298. . . . 11221. 12771. . . 4933. . . 10527. . 558 \tex_pagetotal:D . . . . 10620. . . 3618. . 10728. 4278. 317 \tex_spacefactor:D . . . . . . . 10320. . 768 \tex_outer:D . 605 \tex_skip:D . 13603. . . . 10903. . 13485. . . . . 1745. 10591. . . . . . . . . 13636. 6666. 9361 \tex_or:D . 447 \tex_scriptspace:D . . 393. . . . 546 \tex_radical:D . 5287. . . . . . . 10446. . . . . . 1872. . 6616 \tex_showboxbreadth:D . . . . . . . . 529 \tex_parskip:D . . . . . 10898. . . . . . . . . . . . . . . . . . . . . . . . . 3295. . . . . . . . 11352. . . 10881. . . . . . . . . . . . 10346. . 10813. . . 617 . . . . . . . . . . . . . . . . 10245. . . . . . . . . . . . . 10389. . 1834. . 9310 \tex_relax:D 417. 392. . 10628. 10993. . . . . . . . . . . . . . . . . . . . . . . . . .Index \tex_omit:D . . . 3180. . 10438. . . . 8216. 1710. . . . . . . . . . . . . . . . . . . 460 \tex_predisplaysize:D . . . . . 6683. . . . 10381. 6578. . . . . . . 13531. 10425. . . . 4183. 7546 \tex_parfillskip:D . . . . . . 513. . . 6522. . . 11063. . . . . . . 487 \tex_scriptstyle:D . . . 1661. . . 3385. . 6629. . . . 1545. . . . 619 \tex_pausing:D . . . 1701. . . . 478 \tex_right:D . . . . . . 11295. . . . . . 10667. . . 3287 \tex_shipout:D . . . . . . . 435 \tex_raise:D . 790. . . . . . 10364. 10501. . . . . 564 \tex_par:D . . 10915. . . . . . . . . . . 443 \tex_pagedepth:D . . . . . . . . . . . . . . . . 10412. . . . . . . . 6612 \tex_showboxdepth:D . 11338. 12948. . 6705 \tex_setlanguage:D . . . . 12559. . . 10379. . . . . . . . 382. . . . . . . . . . . 10404. . . . . . . . . . . . . . . . 1747. 6613 \tex_showlists:D . . . 380. . . . 629. . . 1643. . . . 13309. . . . . 593 \tex_overline:D . 407. . . . . 1728. 341 \tex_sfcode:D . . . . . . . . . . 10551. . . 10353. . . . . 13705. . . . . 11274. 1705. . . . . 13640. . 10473. . . . . 15085 \tex_scriptfont:D . . . 406 \tex_penalty:D . . 6624. 10514. . . . . . . . . . . . . . . 354 \tex_openin:D . . . . . . . . . . . . 583. . . . . 575. . . . . . 10651. . . 13833. . . . . 548 \tex_show:D . . 11554. . . . . . . . 11203. . . . . . . 563 \tex_pageshrink:D . . . . . . . . . . . . . 10370. 2704. . . . 12767. 540 \tex_prevdepth:D . . . . . . . 10971. . . . . . . . 1831. . 394 \tex_showthe:D . 340 \tex_output:D . . . . . . . . . . . . . 11002. . . . 412 \tex_setbox:D . 13535. 587 \tex_prevgraf:D . 559 \tex_pagegoal:D . . . 11214. 602 \tex_scriptscriptstyle:D . . . . 10562. . . . . . . . 1534. . . . 10844. 10572. . . . . . 2700. . 537 \tex_parshape:D . 10409. . 11156. . . . . . . . 1856. . . . . 614 \tex_postdisplaypenalty:D . . 11231. . . . . . . 11543. 2704. 11240. 10604. . . . 10450. 1716. 638. . . . . . . . . . . . . . . . . . 11051. 560 \tex_pagefilstretch:D . . . . 13116. . . . . . 609. . . . . . . . . . . . . . . . . . 15004. . 10889. . . 11019. . . . 9889. 6516. 1821. . . . 15054. . . 1847. . . . 391 \tex_showbox:D . 555 \tex_outputpenalty:D . . 11182 \tex_relpenalty:D . 10716. . . . . 10676. 408. . . . . . . . . 1881. 3304 \tex_skewchar:D . . 328. . . . . . . . . 6635. . . . . . . 10337. . 459 \tex_pretolerance:D . 3298. 534 \tex_romannumeral:D . . . 547 \tex_spaceskip:D . . . . . . . . . . . 10291. . 2686. . . . . 1841. . . . . . 2616. 11585. . . . . . . . . . . 11003. . 11118. . . . . . . . . . . . . . . . 3301. . . . . . 11577. 542 \tex_span:D . 13580. . 1722. . 9724. . . . . . . . . . . . . . 10292. . . . . 11546. . . . 461 \tex_predisplaypenalty:D . . . . . . . 446 \tex_scrollmode:D . . . 9268 \tex_openout:D . 476 \tex_righthyphenmin:D . . . . . . . 1740. 794. . . . . 10770. . . 1754. . . . . . . . . . . 765 5124. . . 10569. . 10798. . . . 1816. 1876. . . 2702. . 544 \tex_parindent:D . 6671. . . . 442 \tex_overfullrule:D . . . . . . . 10601. . . . . . . . 10657. . . . 11256. . . 2953 \tex_space:D . . 2950 \tex_skipdef:D . . . . . . . . . . 377. . 10811. . . . . . . . . 10948. . 10713. . 10757. 10959. . . 1829. . 10873. . 11130. . . . . 6553 \tex_read:D . . . 10227. . . . . . . 11007. 15062. 11075. . . 2698. . . 10274. . . . . . 557 \tex_pagefilllstretch:D . . . . 1451. . . . . . . . . . . . . . . 565 \tex_over:D . . 11362. . . . . . . 11036. . . 13599. . . . . . 536 \tex_patterns:D . 10361. 10828. . . . 12790. 10080. 10908. . 381. 13476. . . . . . . 2692. . . 10640. . . . . . 1809. . . . 9786. . . . . 532 \tex_rightskip:D . . . . 601 \tex_scriptscriptfont:D . . . 473 \tex_overwithdelims:D . . . . . 3290. . 788 \tex_tabskip:D . . . . . 9382. . . 485 \tex_time:D . . . . . . . 10358. . . . 585. 4150. . . . . . . . . . . . . . . 1285. . . . . . . . . . . 9418 . . . 324. 4613. . . . . . 4931. . . . . . . . . . . . . . . . . 4155 \textdaggerdbl . 520 \tex_write:D . . . . . . . . . . . 4620. . . . . . . . . . . . . . . 4931. . . . . . . 3286. . . . . . 600 \textparagraph . . . . . . . . . . . . . 4617. . . . . 1293. . . . . . 552 \tex_tracingcommands:D . . . . . . . . . 580. . 500. . 621 \tex_toks:D . 8401. . 502 \tex_unvbox:D . . 445 \tex_the:D . . . . . 2690. . . 5405. . 2038. 4637. . . . . . . . . . . . 9916. . . . . . . . 6671 \tex_wd:D . . . 4601. . 595 \tex_splittopskip:D . . . 515 \tex_valign:D . . . . . . . . . . . . . . . . . . . 4151 \textstyle . . . . . . . . . . . . . . . . . . . . . . . . . . 4478. . . . . . . . . 405 \tex_uccode:D . . . . . . . . . 9460. . . . . 6660. . . . . 6614 \tex_tracingoutput:D . . . . . . . . . . 4396. 10856 \tex_uchyph:D . . . . . . . . . . . . . . . . . . . . . . 600 \tex_textstyle:D . . . 112. . . 581. . . . . . . . . . . . . . . . 5811. . . . . 9049. . . . . . . . . . . . . . . . . . . 2684. . . 4154 \textbardbl . . . . . . . . 115. . . . . . . 404 \tex_tracingstats:D . . 3293. . . . 9462. . . . . . . . . . . 398 \tex_tracingmacros:D . . . . 499 \tex_vfilneg:D . 4619. 485 \time . 586. . . . . . . . . . . . . . 4654. 497 \tex_vfill:D . . . 6701 \tex_unvcopy:D . . . . . . . . 7330 \tl_case:cnn . . . . 9379. . . . . . . 399 \tex_tracingonline:D . . 356 \tex_textfont:D . . . 6220. . 2696. . . 624 \textasteriskcentered . . 4152 \textsection . . 6659. . . 501 \tex_vtop:D . . . . . . . . . . . . . . . . 6221 \tl_clear:N . . . . . . . . 263. . 4931 \tl_case:Nnn . 6224 \tl_concat:ccc . . . . . . . . . . . . . . . 121. . . . 579. . 4775 \tex_vadjust:D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1172. . . . . . . . . . 9919 \tex_underline:D . . . . 4613. 4548. . . . . . . . . . . . . . . . . . . . . 1677. . . . . 2472. 6225. . 117. . . . . 3299. . . . . . . . 6677. . . . . . . . . . . . . . . . . . . . . . . . 426 \tex_splitfirstmark:D . . . . . . 10690. 4149. . . . . 6531 \tex_widowpenalty:D . . . . . . 640. . . . . . . . . . . . 314. . . . . . 3302. . 6664. . . . . . . 4942 \tl_clear:c . 486 \thinmuskip . . . . 8674. 6655 \tex_unkern:D . 397 \tex_tracinglostchars:D . . . . . 2694. . 2696. . . . . . . . . . . . . . . . 543 \tex_year:D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621 \tiny . . 418. . . . . 633. . . . . . . . . . . . . . 4153 \textdagger . . . . 116. . . 748 \tex_unhbox:D . 9061. . 5410. . . . . . . . . . . 425 \tex_splitmaxdepth:D . . . . . . . . . . . . . . . . . 2702. . . . . 9385 \tex_xdef:D . . . . . . . 7392 \tex_vsize:D . . . . . . 4553. . . . . . 91. . 4633. . . . . . . . . . . . . . . . . . . . . . . . 418 \thickmuskip . . . . . . . 6666. . . . . . 5810. . . . . . . . . . . . . 4633. . . . . . 401 \tex_tracingpages:D . . . . . . . . . 5409. . . . .Index \tex_splitbotmark:D . 113. . . . . 4156 \textdir . . . . . . . . 118. . . . . . . . . . . . 5406. . . . . . . . . . . . . . . . . . . . . 498 \tex_vfuzz:D . 5806. . . . . . 844 \tex_xleaders:D . . . . 9918. . . . . . . . . . . . . . . . . . . 509 \tex_xspaceskip:D . . . . . . . . 5807. 10322. . 6662. . . . . . . . . 119. . . 9533 \tl_clear_new:c . . . . . . . . . . . 10384. . . . . 541 \tex_topmark:D . . . 549 \tex_vskip:D . . . . . . . 6656 \tex_unhcopy:D . . . . . 4633. 4483 \tex_vsplit:D . . . . . . . . . 592 \tex_voffset:D . . . . . 422 \tex_topskip:D . 403 \tex_tracingrestores:D . . . . . . . . . . . 6605. . . . 95. . . . . . . . . 91. . . . . . . . . . 5457 \tl_concat:NNN . . . . . . . . . . . 445 \TeXXeTstate . . . . . . . . 567 \tex_vrule:D . . . . . . . . . . . . 350 \tex_vbadness:D . . 739 \textfont . . 9917. 2968 \tex_toksdef:D . . . . . . . . . 2473. . 630. 538 \tex_undefined:D . . 4619. . . 6700 \tex_uppercase:D . . 486 \tex_thinmuskip:D . 8286. . . . . . . . 331. . . . . . . . . . . . 1174. . . . . . . . . . . . . 4491. . . . . 474. . . . . . . 2698. . . . . . 6683 766 \tex_vcenter:D . . . . . . . 2614. . . 13950 \tex_thickmuskip:D . . . 582. . . . . . . . 615 \tex_unskip:D . . . . . . . . . . . . . . . . . . . . 402 \tex_tracingparagraphs:D . . . . . . 3543. . . . . . . . . . . 610. . . . . . . . . . . . . . . . . . . . 6705 \tex_vss:D . 4601 \tl_const:cx . . . . . . . 2971 \tex_tolerance:D . . . . . . . . . . . . . 383. . . . . . . . . . . 612. . 9905. . . . . . . 307. . . . . . . . . . . . . 4613. . . . . . . . . . 1192. . . . 120. . . . 3296. . . . . . . . . . . 4148. . . . . . . . . . . 8676 \tl_clear_new:N . . . . . . . . . . . . . . . . . 1673. . 700 \the . 8397. . 578. . . . 4647. . . . 91. . . . . . . . 506. . . . . . . . . . . . . 436 \tex_vfil:D . . . 9466. . . . . . . . 400. . . . . . . . . . . . . . . . 596 \tex_string:D . 504 \tex_unpenalty:D . 590 \tex_vbox:D . . 4623. . . . . . 5455 \tl_const:cn . 4619. . . 114. . . 7337. . . . . . . . . . . 9656. . . . . . 8335. 5370 \tl_count:V . 4785. . 4662 \tl_gset:Nv . . 5367 \tl_count:N . 5341 \tl_gremove_once:cn . . . . 9412. . . 4661. . . . . . . . . . . 197. . . . . . . . . . 2723. . 4701 \tl_gput_left:Nx . . 4999. . . . . 4826. . . . 4613. 4633. . . . . 4622. . 4703 \tl_gput_right:cn . 4680. . . 98. . . . . . 5348. . . . 4826. . . . . . . . . 5352. . . . 5950. . 5582. . . 12186. . . . . 4662. . . . . . . . . . 4690. . . . . 4736. . . 5331 \tl_greverse:c . . . . . . . 5353 \tl_elt_count:N . . . 4700. . . . . 7656. 14900. 4624. . . 4662 \tl_gset:Nn . . . . . . . . . . . . . . . . . . 7643. . 13719. . . 4636. . 92. 5346 \tl_gremove_all_in:Nn . 13844. . . . . 92. . 4776. 98. 7649. 6002. . . . 6226 \tl_gconcat:ccc . . . . . 15094 \tl_count:o . . . . . 196. . . . . 6326. . . . 6260. . . 931. 6312. . . . . . . . . 6223 \tl_gclear:N . . . 5332 \tl_greplace_once:Nnn . . 13795. 5353. 4726 \tl_gput_right:NV . 9657. . . 14913. . . . . . . . . . . 15050 \tl_gclear:c . . 4612. 5350 \tl_expandable_lowercase:n . . . . . . . . 4776. . 4611. . . 7641. . . . . . . 4692. . 4999. . . . . . . . 4778. . . 5338. . . 14895. 15045 \tl_const:Nx . . . . . . . 5813. 5145 . . . . . . . . 5456 \tl_gput_left:cn . . . .Index \tl_const:Nn . . 4662 \tl_gset:cV . 5912. . . . . . 4680 \tl_gput_left:cx . . . .tl_gset:N . 14464. . . 12505. 15058 \tl_expandable_uppercase:n . . . 7639. 4678. . 91. . . . . . . . . . 5351. . . . . . . . . . . 5349 \tl_elt_count:o . 5408. . . . 5348. 4725 \tl_gput_right:Nx . . . 5349. . . . 7630. . 15050. . . . 1330. . . . . 5323 \tl_gset:Nf . . . 5348. . . . . . . . . . . . 12506. 5350. . 5338. 13785. . . . . . . . . 8337. . . . . . . . . . . . . . . . . . . . 4655. . 5412. . . . . . . . . 7577. 4601. . 4787. . . . . . . . . 4662 \tl_gset:cn . . . . 4613. . . . . 9655. 4662 \tl_gset:cx . . . . 92. 4677. . 4601. . . . 4999. 14797. . . . . . . . . 4716. . . 5352 \tl_elt_count:n . . . . 12501. . . . . 4779. . . . . . 197. . . . . . 4680 \tl_gput_left:cV . . . 5010. . . 5142. 12462. . 4828. . 4832. . . 4704 767 \tl_gput_right:Nn . . . . 4619. 5033. . . . . . . . . . . 4680. . . . . . . . . . . . 4601. 13875. . 1368. . . . . . . . 5650. . . 5335 \tl_greplace_all_in:cnn . . . 4688. . . 5346 \tl_gremove_all:Nn . . . . . . . . . . . 15050. . 5654. . . . . . 4782. . . . 8490. . 4718. 6289. . . . . 91. 5345 \tl_gremove_all_in:cn . . . . . . . . . . 5809. 4831. 5336 \tl_greplace_all_in:Nnn . 4776. . . . . . 2593. . 4662 \tl_gset:cv . 5348. 5424. . 4741. . 5322. . . . . . . 5470 \tl_gput_left:No . . . . 4638. 5336 \tl_greplace_all:Nnn . . 6222 \tl_gclear_new:c . 6346 \tl_gremove_all:cn . . . 5351 \tl_elt_count:V . . 4662. 153 \tl_gset:Nc . . 4999. 5342 \tl_gremove_in:Nn . 9165 \tl_gset:No . 5342 \tl_gremove_once:Nn . . 5472 \tl_gput_right:No . 8494. . . . . . . 4999. . . . . . . 14490 \tl_count:c . . . . . . . . 15024. 4783. 13721. . . 8492. 5004. . . . . . . . . . 92. 5335 \tl_greplace_in:cnn . 4662 . . 4633. . 5825. . . . . . . . . . . 5612. . . 5328. . 5368. . . . 9050. 4712. . . . . 927. . 4837. . . 7637. . . . 15024. 9653. . . . . 6326. . . . . . . 98. . . . . . . . . 5341 \tl_greplace_all:cnn . 5407. . . 8493. . . . . 4618. . 4641. . . . . . . 5498. . . . . 14931. . . . 4704 \tl_gput_right:cV . . . 4704. 5369 \tl_count_tokens:n . . . . . 4668. . 9654. . . 4670 \tl_gset:NV . . . 5363. . . . . 5140. . . . 92. . 14941 . . . . . . 15039 \tl_elt_count:c . . . . 4694. . . . . 4680 \tl_gput_left:Nn 92. 4621. . . . 4615. . 5348. . . . . . 4714. 5332 \tl_greplace_in:Nnn . 5328. . . 5458 \tl_gconcat:NNN 91. . 4704. 9458 \tl_count:n . . . . . . . . . . . . . 5411. . . . . . 5328. . . . . . 5331 \tl_greplace_once:cnn . . . . . 12499. . 5011. . 4672. . . . . 4724. . . . 4834. . . . . . . 12502. . . . . . . . . . . . 4702 \tl_gput_left:NV . . . 4680 \tl_gput_left:co . . . . . . . . . 7578. . . . 8491. . . . . 4635. . . 4662 \tl_gset:Nx . 4999. . . . . . . . . . 4606. . . 12503. . 4829. . 12500. . . 5869. . . 5345 \tl_gremove_in:cn . . . . . . . . . . . . 4835. . 6227 \tl_gclear_new:N . . . 93. 5812. . . .tl_gset:c . . . . . . 12504. 4832. . . . . . 4680. . . 91. . . . . . . . . . 7648. . 5143. . . . . 4680. . . . . 5808. 5317. 4704 \tl_gput_right:co . . . 153 \tl_gset:cf . . . . 4662. . . 4727. . 4704. . . 5328. 2487. . . . 12507. 4704. . . 4776. . . . . 15040. . . . . . . 13853. . 9408. . 5338. . . . . . . . . . . . 5338. . . . . 7635. . 5140 \tl_greverse:N . . . . . . . . 4619. . 4679. . . . 4659. . . . 4662 \tl_gset:co . . . . . . . 4704 \tl_gput_right:cx . . . . . . . . . . . 5366. . . . . . . . 8456 768 \tl_if_empty:nTF . . 4895 \tl_if_eq_p:cc . . . . . . . . . . . . . . . 4616. . . . . . . . 1034. . . . . . 7916. . . . . . . . . . 91. . . 4738 \tl_gset_rescan:cnx . . . . . . . . . . . 6193. . . . . . . 4838 \tl_if_blank_p:n . 6235 \tl_gset_eq:cN 4625. . . 99. . 5360 \tl_if_blank:n . 4860 \tl_if_empty:NF . . 91. . . . 4847. . 4848. . . 5356 \tl_head:V . . . . 3963. 4842. 5523. . . 5191 \tl_if_head_eq_charcode:nNF . . . 6361 \tl_if_empty:cTF . 3036. . . . . . . . . . . . . . . . . . . . . . . . . 5420. . . . 6473 \tl_if_eq:cNTF . . . . . 6359 \tl_if_empty:n . . . . . . . 5356 \tl_head_i:w . . 153 \tl_gtrim_spaces:c . . . . . . . . . . . 5355. . . . . 5355. . . . . . . . . . . . . . . 94. 4841. 5427. . . . . . . . . 8285. . . . . 4869. . . 4848 \tl_if_empty_p:N . . 6455. . . . . . . 4838. 6195. 4738 \tl_gset_rescan:cno . . . . . . . . . . 5035 \tl_head:f . . . . 956. . 5373 \tl_if_empty:xTF . . . . 9054. . . 5146. . . . 5358. . 4639 \tl_if_exist_p:N . . . . .tl_gset_x:c . . . . . 4883 \tl_if_eq_p:cN . . . . . 5164. . . . . . 5165. . 5359 \tl_head_iii:w . . 3950. 6475 \tl_if_eq:ccTF . . . . . . . . . . . 4838 \tl_if_empty:c . . 6196. 4738 \tl_gset_rescan:Nnx . . . . 5208 \tl_if_head_eq_charcode:nNTF . . . . . . . . . . . 4883 \tl_if_eq_p:NN . . . . . . . . . . . 4892. 5183. 99. . . . 5372 \tl_if_eq:cc . . . . . . . . . . . . . . . . 8073. . 4843. . . . . 94. . . . . 6044. . . . . . . . 5820. . . 94. . . . . 94. 5191. . . . . 5357 \tl_head_iii:f . . . 5166. . . . . . . 5217. . . . . . . 4891 \tl_if_exist:c . . . . . . . 8069. . 5146. 153 . . . 6474 \tl_if_eq:NcTF . 4881 \tl_if_empty:oTF . . . . . . .tl_gset_x:N . . . . 4631. . . 4629. . . 4868 \tl_if_empty_p:o . . . . . 4860. . . . . 5146 \tl_head:N . . . . . 7406 \tl_if_eq:NNTF . . . . . . . . . . 94. . . . . . . . . . 4883 \tl_if_eq_p:Nc . 5028. . 5170. . . 4860 \tl_if_empty:x . . . . . 5146. . . 4870 \tl_if_empty:NTF . . . . 5146. . 4856 \tl_if_empty_p:n . . . . . . . . . 5191 \tl_if_head_eq_charcode:fNTF . . . 4639 \tl_if_exist:NTF . . . . . . . . . . . 4771 \tl_gset_rescan:Nno . . . . . . . 5146 \tl_head:w . . . . . . 4919. . 4045. . . . . . . . . . . . . . 101. . . . 4883. . 7671. 14443 \tl_if_blank:oTF . . . . . 93. 4840. 5819. 13726. . . 4848. . . 4838. . 6030. . 4790. . . . 5209 \tl_if_head_eq_charcode:nNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4844 \tl_if_blank_p:o . . . . . 4858 \tl_if_empty:nF . . . . . . . 6156 \tl_if_blank:nT . . . . . . . 100. . . . . 4938. . . 5818. . . . . 6031. 4738. . . . . . . . . . . . 94. . . . 9168. . . . . . . . . . 5521. . . . 4738 . 4087. 4625. . . . . 4871. . 94. . . . . . 4895 \tl_if_eq:NNF . . 5166 \tl_head:n . . 3196. . 4848 \tl_if_empty:N . . . . 5207 \tl_if_head_eq_charcode_p:fN . . . 5357 \tl_head_i:n . . . . . . . . . . 9479 \tl_if_eq:nnTF . . . . . . . . 15166 \tl_if_empty:o . . . . . . . . 5146 \tl_head:v . . . 7970. . . . . . 4995. . . . . . 7950. 100. 5198. . . 14501 \tl_if_empty:VTF . . . . . . . . . 7935. . 6234 \tl_gset_eq:Nc 4625. . . . . .Index \tl_gset_eq:cc 4625. 13821 \tl_gset_rescan:cnn . . . . . 5418. 4838 \tl_if_blank_p:V . . 13688 \tl_if_empty:NT . . . . 4632. . . . 5191 \tl_if_head_eq_charcode:nN . 4894 \tl_if_eq:NNT . . . . . . . . . . . 4893. . . . . . . . . . . . . . . . . . 4859. . . . 6194. . . . . . . 8919 \tl_if_eq:cN . . . . . . . 4872 \tl_if_empty_p:V . . . . 6472 \tl_if_eq:nn . . . . . . . . 5510. . . . 5028 \tl_gtrim_spaces:N . . . . . . . . . . 6233 \tl_gset_eq:NN . 6232. . . . . . . . . 4883. . . . . . . 4639. . . . . . . . . . . . . . . . . . . . . 5355. . 4872. . 4857 \tl_if_empty:nT . . . . . . . 4620. . . . . . . . . 5419. . . . 4622. . 5210 \tl_if_head_eq_catcode:nNTF . . . . . . . 4640 \tl_if_exist:cTF . 5191 . . . . . . . . . . . . . . . . . . . . . . . . . . 4883 \tl_if_eq:NN . . . . . . . . . 5372 \tl_if_empty_p:c . . . . . . . . . . . 4846. . 8410 \tl_if_blank:VTF . . 94. . . . 4738 \tl_gset_rescan:Nnn . . . 5032. . . . . . . . . 8566. . . . . . . 5355. . . . 5358. . . 100. . . . . . 4883. . . . . . . . . . . 4639 \tl_if_exist:N . . . . . 4630. . . . . . . . . . . . 5417. . . . . . . . . 4860 \tl_if_empty_p:x . . 4860. . . . . . . 5191 \tl_if_head_eq_catcode_p:nN . . . . . 4740. . . . 5821. . . . . 4838. . . . . . . . 14480. 91. . 5855. 5239. . . . . . . . . 5299 \tl_if_exist_p:c . . 6082. . . . . . . 4845 \tl_if_blank:nTF . . . . . . 4639 \tl_if_head_eq_catcode:nN . . . . . . . 7403. . . . . . . . . . 4883 \tl_if_eq:Nc . 4838 \tl_if_blank:nF . . . . 5355 \tl_head_iii:n . . 4883. . . . . 4770. . . . . . . . . . . . . . . . . . . 4848. . . . . . . . 5292. . . . . . . . . . . . . . . 94. . . . . . . . . . . . 4967. . . . . . . . . 4948. . . . 4680 \tl_put_left:cV . . . 4600. . . . . . . 4986. 5206 \tl_if_head_eq_meaning:nN . . . 4976. 4925. . 8500. . . 4914 \tl_if_in:nnF . . . 5255. . . . . 5002. . . . . . . . 5381 \tl_if_head_is_space:nTF . 4974. . . . 9045. . . . . . . . 5220. 4926 \tl_if_single:NTF . . . . . . . . . . . . . . . . . 4680. . 101. . . . . . . . . . 197. . . . . 9082 \tl_if_in:nnT . . . . 14996 \tl_if_head_is_N_type_p:n . . . . . . 5376 \tl_if_head_space_p:n . 101. 4970. . . 4929 \tl_if_single_token:n . . . . . 7212. 8382. 5007 \tl_map_function:nN . . . 4913. . . . . . . 4968. . . . 9399. . . . 5191 \tl_if_head_group:n . . 6218. . 4988 \tl_map_function:cN . . . . . 4969 \tl_map_inline:nn . . . . . 4910. 5264 \tl_if_head_is_space:n . . 4923 \tl_if_in:NnT . . . . . . 95. 8384. . . 95. . . . . . . 4958. 7576. . . . . 4951. 4697 \tl_put_left:Nx . 7325. . . . . . . . . 4684. . . . . . . 4957. 4704 \tl_put_right:cV . . . . 96. . . 9402. . . 5083. . . 101. . . . 4704 \tl_put_right:co . 5270 \tl_if_head_is_N_type:n . 4908. . . . . . . 4928 \tl_if_single:nTF . . . . . 4944. . . . . . . . . . . . 4910 \tl_if_in:nn . . 4686. . . . 5313. 5264. . . 4944. 4912. . 4680. . 8543. . . . . . 4981. . . . . . . . . 5365. 4704 \tl_put_right:cx . 5264. . . . . . . 5802. . 5319. . . . . . . . . . . . . . . 15109 \tl_length:c . . . . 14792 \tl_new:Nn . . . 8383. . . 95. . 5365. . . . . . . . . . . . 196. 5376 \tl_if_head_space:n . . . 4965. . . 4696. . . . . 2864. . . . . . . . . 5401. . . . . . . . . . . . . . . 4680. . . 5285 \tl_if_head_N_type:n . 8496. . . . . . . 6216. . . . 101. . 9401. . . . . . . . . . . . 5365. . . . . 101. . . . 4699 \tl_put_right:cn . . . . . . . 5462 \tl_put_left:No . . 4987. . 101. . . 5377 \tl_if_head_group:nTF . . . 9415. . . . 6742. . . 4928. . . . 5404. . . . 7863. 5191. . . . . . . . 95. . . . 8385. . . . 5365. . . . 5381 \tl_if_head_space:nTF . . . 5366 \tl_length:n . . . . . . 4986. . . . . . . . . . 4970. . . 5270 \tl_if_head_is_group_p:n . 9215. . . . . 5379 \tl_if_head_is_N_type:nTF . 5285 \tl_if_head_is_space_p:n . . . . 5313 \tl_put_left:cn . . . . . . . . . . 4911. . 5362. . . . 4704 . . . . . 5311. . . . . . . 95. . . 4682. . . 4970. . 14994 769 \tl_item:cn . 6719. . . . 9066. . . . 15087. 96. 4595. . 15110 \tl_item:nn . 4680 \tl_put_left:co . . 4915 \tl_if_in:nnTF . . 5312. . . . 4925. . . . . . . . 5379 \tl_if_head_N_type:nTF . . . . . . .Index \tl_if_head_eq_charcode_p:nN . . . . . . . . . 4912. . . 5195. . . . 5400. . 6219. . . . . . . . . . . 4970 \tl_map_variable:NNn 96. 4989 \tl_map_break:n . 4595. 10951 \tl_map_variable:cNn . . 9149 \tl_if_in:noTF . 95. 4910. 4927 \tl_if_single:nF . . . 5428 \tl_map_inline:cn . . 8437 \tl_if_head_eq_meaning_p:nN . . . . . . . . . . 5376 \tl_if_head_group_p:n . . . . . 4944. 10942. 4909. . . . . . 4958. 4680 \tl_put_left:cx . . 4680. . . . . . . 5403. . 4916. . . . . . . . . . . 5229 \tl_if_head_eq_meaning:nNTF . . . . 4929 \tl_if_single_p:N . . . . . 5805. . . 4958 \tl_map_inline:Nn . . . . . 96. . . . . . . . 97. . . . 5191. 9403. 101. . . . 5231. . 4954. . . . . . 4595. . 6743. . . 4925. . . . . . . . 4926 \tl_if_single:nT . . . . . 15164 \tl_if_in:onTF . 9400. . . . . 4929 \tl_if_single:NF . . . . . . . . 5376 \tl_if_in:cnTF . . . . . . . 5316. . . . . . . . 101. . . . . . . 5376 \tl_if_head_N_type_p:n . . . . . . 4958. . . . 5320 \tl_new:Nx . . . 14994 \tl_if_single_token_p:n . 4922 \tl_if_in:NnTF . 5368 \tl_length:o . . . 5285. . . . 15087. 5309. . . . . . . 15087. . . . . . . . . . 8503. 5314. . . . 2587. . 4916 \tl_if_in:VnTF . . . . . . . . . 5270. 2584. 4620. . . . . . . . . . . . . . . 96. . . . . . . . 4944 \tl_map_function:NN . 5369 \tl_length_tokens:n . . 5376 \tl_if_head_is_group:n . 5377 \tl_if_head_is_group:nTF . . . 5313 \tl_new:N . 101. 4985 \tl_map_variable:nNn 96. . . . 8501. . . . . . . . . . 4950. . 8498. . . . . . . . . 196. 14994 \tl_if_single_token:nTF . . 4680. . 7864. . . . 4916 \tl_if_single:n . 91. . . 4916 \tl_if_in:NnF . . . . . . . 4911. . . . . . 13986. . 4925 \tl_if_single_p:n . . . 4680 \tl_put_left:Nn 92. . . 5365. . . . . 5804. 8497. 4910. . 3080. . . 4924. . . . . . 5367 \tl_length:N . . . . . . . . 15109. 4927 \tl_if_single:NT . . . . . . . 9328. 15087 \tl_item:Nn . 8502. . . . . 5086. . . . 4977 \tl_new:c . . . 6451. . . . . . 4916. . . 9065. . . . . . . 8536. 95. . . 8654 \tl_new:cn . . . . . . . . . 5363 \tl_map_break: . . 5370 \tl_length:V . . 4622. . . . . . . 5214. . . 4698 \tl_put_left:NV . . . . . . . . . . . . . . . 4986. 5310. . . . . . . . . . . . . . . . . . . . 6301. . . . . 196. 5175 \tl_tail:n . 8445. 5340 \tl_remove_in:Nn . . . . . . . 4781. 9478. 14911. . 3740. . . . 5146 \tl_tail:v . 4722 \tl_put_right:NV . . . 4780. . . 4662 \tl_set:Nx . 5648. 6270. .tl_set:c . 92. . . . . 9545. . . 5328. 8657. 4738 \tl_set_rescan:Nnn . . . . . . . . 5600. 92. 8448. 5334 \tl_replace_all:Nnn . . . 5140 \tl_reverse:N . . . 4662 . . 3119. . . . . . . . . . . . 9351. . 6230 \tl_set_eq:Nc . . 8729 \tl_set_eq:cN 4625. 5306 \tl_show:n . . 3023. 8423. 8548. . . . . 5329 \tl_rescan:nn . . . . . . . . . . 4738. . 9101. . . . . . . . . 5175 \tl_tail:V . 5414. . . 5146 \tl_tail:N . 8877. . . . 13962 \tl_set:No . 6280. 5343 \tl_remove_in:cn . . . 93. . . . 4625. . . 5430. 6229. . . 5143 \tl_reverse:o . . . . . 100. . . 8845. . . . . . . . 5867. . 5141. . . 6271. 4628. . . . . 13725. . 5120 \tl_reverse_items:n . . 5553. . . . . . . . . . 92. . . 8287 \tl_set:Nn 92. . . 102. . . . . . 5333. 4662 \tl_set:cv . . . . . . 770 4980. . . . 93. . . 8911 \tl_set_eq:NN 91. . . . . 14890. . . 4664. . .tl_set_x:c . . . . . . . . . . . 6000. 5916. . 5901. . 4776. 5307 \tl_tail:f . 6282. . 4833. . . . . . 5464. . 4627. 6398. 4704. . 93. . 5146. . . 6279. . . . . . . . . . . .tl_set_x:N . 9106. . . . . . . . 5297 \tl_show:N . . 4662. 8470. . 4662 \tl_set:cx . . . . 4830. 4738 \tl_set_rescan:Nnx . . . 9456 \tl_replace_all_in:cnn . . . . 9121. . . . . . . . . 6254. . 5385 \tl_to_lowercase:n . . . . . 5344 \tl_remove_all:Nn . . . . . . 5344 \tl_remove_all_in:Nn . . . . . . . . . . 5174. . . 8878. . . . . . 4662. 6324. . 2357. . . . . . . . 7330. . . . . . . . 4704. . 9080. . . 4836. 5910. 5532. . 3098. . . 4832. . 6124. . 98. . . . . . 4662. 8454. . . . . . 4676. . 4777. . . 13870. . . . . . 9454. 5515. 9258. . . . . 5307. . . . . 5133. . . . 8642. . . 7927. . 14929. 5610. . . . . . . 6324. . . 4625. . . . 102. . . . 153 \tl_show:c . . . . . . . 5338. . . . 8904. . . 9504. . . . . 5384. . . . . . . . . . . . . . . . . . . . . . 4827. 4662. . 4666. . . . . . . 9530. . 8855. . . . 8860. . . . . . . . . 5167. 2866. . . 5416. . . 5012 \tl_reverse_tokens:n . 4662 \tl_set:Nv . 8675. 4662 \tl_set:cV . . . 5012. . . . . . . . . . . . . . 5325 \tl_set:Nf . 4720. 8461. . 4708. . . . . 8542. . . . . . . . . . . . 6291. . . . . 5031. . . 4832. . 8441. . 5496. . . . 153 . . . . . . . 5328. . . . 5588. . . 4721 \tl_put_right:Nx . 14939 \tl_set_eq:cc . . . . 4723. . . . . . . . 8616. . . . . . . . . . . . . . 5816. . 4776. . . . . 4739. . . . . 4675. . 7874. 5441. . . 5144 \tl_reverse:n . 4625. 5415. . . . . . . . . . . . 4614. . 13789. 4738 . . . . . . 8720. . . . . 8510. . . 5330 \tl_replace_in:Nnn . 4784. . . . . 9511. . 5141. . 4704. . . . 7956. 4738. 8469. . . 9539. . . . . . . 5506. . . . . . 6917. 5326 \tl_set:NV . . 7327. . . . . . . . . . . . . 4768. . 6726. 13784. . . . . . . . . . 9086 \tl_remove_all_in:cn . . . . . . . . . 4674. . . . . . . . . 5923. 5333 \tl_replace_in:cnn . . 4662. 14885. . . . . . . . . . . . . 5339 \tl_remove_once:cn . . . 4626. . . . 4738 \tl_set_rescan:cno . . . . . . . . . . . . . . . . . . 98. . . . . 5529. . . 5339 \tl_replace_all:cnn . . . . 5570. . . . . 5413. . . . . . 5561. 5329 \tl_replace_once:cnn . . . . . . . 4769 \tl_set_rescan:Nno . . . 153 \tl_set:cf . . . 5328. 8847. . . . . 4786. . . 92. . . . 4776. 9550 \tl_remove_all:cn . 14795. 7214. . . 6302. 4738 \tl_set_rescan:cnx . 5140. . 5817. . . 9518. . 5626. . . 5322. 4832. 5146 \tl_tail:w . . . 6329. . . . 9455. . 9449. . . . 5717. . . . . . . . . . . . 4742 \tl_reverse:c . . . 4899. . 93. .Index \tl_put_right:Nn . . . . . 13820 \tl_set_rescan:cnn . . 15000. . . . . 5330 \tl_replace_once:Nnn . 6288. . . . . . 8679 \tl_set:co . . .tl_set:N . 8398. . 5907. 5422. . . 5140. . 6344. . 4738. 5338. 4662. . . 4776. . . 4898. . . . . . 5652. . . . . . . 5120. . . . . . 4710. 5814. . 5343. . . . . . . . 5297. . 153 \tl_set:Nc . 8457 \tl_put_right:No . . 4826. . 8545. 15000. . . . . . . . 5948. . 4776. 7213. . . 5334 \tl_replace_all_in:Nnn . 5120. . 8535. . . . 5328. 8400. 8399. 4634. . . 4826. 6231. 7919. . . . . 98. . 6349. 9498. 15017 . 4826. . . 5338. . . . . . . 5120 \tl_reverse:V . . . . . . 4704. 5340 \tl_remove_once:Nn . 4706. . . . 8508. . . . 4662 \tl_set:cn . . . . . . . 2824. 5436. . 4704. . . . . . . . . 6228. . 5580. . 6311. 5324. . . 5338. . . . . . . . . 13717. . . 14462. . . 5297. . . . . . . . . . . . . . . 5815. . . . . . . . . . 5823. 6730. . 9079. 13851. . 4625. . . . . . . . 2342. . . . . . 5146. . . 3365 \token_if_math_shift_p:N . . . . . . 3372 \token_if_active_char:NT . 5188. . 2798. 2908 \token_if_chardef_p:N . . . . . . . . . 55. . 13630. . 4993. . 2788 \token_if_long_macro:N . . . 2858 \token_if_long_macro_p:N . 56. . . 56. . . . . 3359 \token_if_alignment:NTF . . . 2813 \token_if_eq_meaning:NN . . . . . . . . . 3362 \token_if_math_subscript:N . 3357. . 5034 \tl_trim_spaces:n . 2773 \token_if_math_toggle:N . . . . . . 2760. . . . . . . . . 2745 \token_if_group_begin:NTF . . . 9469 \tl_to_str:n . . 3364 \token_if_math_toggle:NT . . . . . . . 56. 3361 \token_if_alignment_p:N . . 61. . . 2858 \token_if_macro:N . 4772. . . . . 5028. . 2808 \token_if_eq_charcode:NN . . . 2996 \token_if_long_macro:NTF . . 3357. . . . . . . . . . . 4793. . . . . . . . 3370 \token_if_alignment:N . . 2367. . . . 5030. . 8298. . . 2818. . . . . . . . . . . . . . 6204 \token_get_arg_spec:N . . . . . . . . . . . . . . . . 54. 4283. . . . 15138 \tl_to_str:c . . . . . . . . . 15121. . . . . . . . . . 57. . . . . . . 56. . . 2888 771 \token_if_dim_register:NTF . 56. 54. . . 97. . 3360 \token_if_alignment:NT . . . . 4990. 2773 \token_if_math_superscript:NTF 55. . . . 6330. . . . . . . . . . 2778 \token_if_math_subscript_p:N . 5448. . . 5308. . . . 99. . . . 2798 \token_if_active:NF . . . 3266. . 809. . 7355. . 9408. . 57. 55. . . . .Index 4772. 2858 \token_if_eq_catcode:NN . . 10019 \token_if_eq_meaning:NNT . . . . 2818 \token_if_math_shift:NF . 4875. . . 56. . . . . . 61. . . 4990. . . . . . . . . . . . . 2803 \token_if_expandable:N . . . . . . 57. . 10313. 8210. . 7764. . . . . . . 2858 \token_if_cs:N . 4993. . . 6366. . 2750 \token_if_int_register:N . . . . . . . . 55. . . 4774 \tl_trim_spaces:c . 3251. . . . . . . 8542. . 13607. . . 55. . . . . . . 2858 \token_if_int_register_p:N . 5031. . . . . . . 54. . 2773 \token_if_math_superscript_p:N 55. . . 8845. . . . . 56. 3371 \token_if_active_char:NTF . 2750 \token_if_group_end_p:N . . . . . . . . 2827 \token_if_macro:NTF . . 3370 \token_if_active_p:N . . 4772. . . . 56. 8007. . . . . . 56. . . . . 3253. . . . . 2906 \token_if_int_register:NTF . 3357. . 4862. . . . . . . 5028 \tl_trim_spaces:N . 2755. . . . 3359 \token_if_alignment_tab:NTF . . . . . . . . . . 55. . . . 8955. . . 2745 \token_if_group_begin_p:N . . . . 7438. . 3372 \token_if_active:NT . . . . . . . 13608. . 7700. 2808 \token_if_eq_catcode:NNTF . . . . . 2813 \token_if_eq_charcode_p:NN . . . . . . 6205 \tl_use:N . . . . 3273 \token_if_active:N . . . . . 3251. . . . 54. . . . . . . 2745 \token_if_group_end:N . . . 5179. 14817. . . 2750 \token_if_group_end:NTF . . . . 2846 \token_if_group_begin:N . . . . . 56. . . 13627. . . . . . 8008. . 9468. . . . 2778 \token_if_math_subscript:NTF . 55. . . 3357. . 8303. 11046 \token_if_eq_meaning_p:NN . . 97. . . . . . . . . 4993. . 56. . 3027. 8299. . 2755 \token_if_math_toggle:NF . 99. 56. 3358 \token_if_chardef:N . . 3365 . 9081. 8971. . 4991. 61. . . . . . . 3357. . 13480. . . . . 7763. 4389. . . . . . 5028. . . . 55. 8855. . . . . 2858 \token_if_dim_register_p:N . . . 2808 \token_if_eq_catcode_p:NN . 3357. . . 2841 \token_if_cs:NTF . . . . . . . . . 2778 \token_if_math_superscript:N . . . 5156. 2788 \token_if_letter_p:N . 54. . . . 5033. . . . . . . . 2760 \token_if_alignment:NF . 54. . . . 8445. . 6241. . . . . 4991 \tl_to_str:N . . 2846 \token_if_expandable_p:N . . . . 3364 \token_if_math_shift:NT . 3255 \token_get_replacement_spec:N . 3363 \token_if_math_shift:NTF . 3363 \token_if_math_toggle:NTF 54. 55. 8294. . . . 8304. . . 9559. . . . . 8469 \tl_use:c . 94. . . . . . . . . 57. 3257. . . . . . . . 3361 \token_if_alignment_tab_p:N . 4991. . . . . . . . 97. 8877. 2858. 2798. 2841 \token_if_cs_p:N . . . . . 2813 \token_if_eq_charcode:NNTF . . . . . 3251. . 3371 \token_if_active:NTF . 2846 \token_if_expandable:NTF . . . . 2803 \token_if_eq_meaning:NNF . 15164 \tl_to_uppercase:n . . . . . 6367. 6350. . . 3373 \token_if_active_char:NF . . 55. 8391. 9413. 8508. . . 3373 \token_if_active_char_p:N . . . . 3264 \token_get_prefix_spec:N . . . . 10259. . 9455. 2869 \token_if_chardef:NTF . . . . 9205. . . 55. . 5028. 3275 \token_if_macro_p:N . . . 3360 \token_if_alignment_tab:NT . . . . 2788 \token_if_letter:NTF . 9192. 2841 \token_if_dim_register:N . . . . . . . 2858 \token_if_letter:N . . 2760. . 4992. . . . 2803. 4998. 9151. . . . . . . . 3358 \token_if_alignment_tab:NF . . 4475. . . . 2352 \token_if_eq_meaning:NNTF . . . . . . 55. . 939. . . . . 3367 \token_if_other:NTF . . . . . . . . . . 612 . . . . . . . . . . 54. . . . . . . . . . . . . .. 10274. . 661 \tracinglostchars . . . . .. . . 15134 . 2705 772 \token_to_str:N . . . . . . . . . 2910 \token_if_mathchardef_p:N . . . . . . . . . . . 2901. . . 2705. . . . . 541 \topmark . . . . . . 660 \tracingonline . . 1071. . .. 2138. . . . .. 2713. ... . . . . . . . . . . . \unpenalty \unskip . . . . . . . \unvbox . . . 2363. . . . . 3031. . 2590. 2874. . . . . . . . . . . . 10638. . . . . . . 2959. . . . . . . . . 3260. . . . 10273. 648 \topskip . 402 \tracingparagraphs . . . . . . . . . . . . . . . . . 57. . . . \unvcopy . . . 2714. . . 10588. . .. 10585. . . . . . . . . . . .Index \token_if_math_toggle_p:N 54. 2948 \token_if_skip_register:NTF . . . . . . . . . . . . . . . . 10560. 1927. 57. . . . . . . . . . 659 \tracingstats . . \uppercase . . 2858 \token_if_protected_macro_p:N . . . 930. . 10549. . . 1070. . . . . . . 800. . 8195. 10482. . . 57. . . . . . . . . . . . . 2941. 1469. . . . \uchyph . . . . . . . . . 3357. . . . . . .. . . . 10725. . . . . . . 2783 \token_if_toks_register:N . 787. . . . 9898. 538 . . 10648. . . 55. . 2921. . . 55. . . . . . . . . 504 .. . . . 3013. . 2858 \token_if_space:N . . 2858 \token_if_skip_register:N . . . . . . 6916. 2992. 398 \tracingmacros . . . . . . . . . . . 2858 \token_if_skip_register_p:N . 397 \tracinggroups . 2705. 3003. . 10523. . 401 \tracingpages . . . 8181. . . . . . 1208. . . . . . . 579 . 2712. . . . . . . . . 56. . . . . 3368 \token_if_other_char:NT . . . . . . . . . . . . 10649. . . 3278. . . . 400 \tracingoutput . 10461. 2876. . . 3017 \token_if_primitive_p:N . . . . . . . . . . 582 . . 404 \tracingscantokens . . . . . . . . . . . 2979. . 502 . . . . . . . . . 1023. . . . 57. . . . 57. . 10788. . . . . 3369 \token_if_other_char_p:N . . . . . . . 1372. . 2858 \token_new:Nn 53. . . 2885. . . . . . 5303. . . . 2883. . . . . U . 1198. . . 2783 \token_if_space:NTF . 2943. . . 422 \topmarks . . . . . . 10265. 57. . . . \unless . . 640 . . 10709. 800. . 9440. . . . . . . . . 2899. . . . . . . 57. . . 1038. . . . . 1988. . . 1198. 9078. . . 2858 \token_if_toks_register_p:N . . 3368 \token_if_other:NT . 405 \U . . 15148 \token_to_str:c . . 960. . . . . . . . . 57. . . . . . . . . 9897. . . . . . 5276. . 3366 \token_if_parameter:N . . . . . . . 56. . . 3367 \token_if_other_char:NTF . . . 3005 \token_if_protected_long_macro:NTF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2858 \token_if_protected_long_macro_p:N . 10736. . 3025 \token_if_primitive:NTF . . . 3001. . 2858 \token_if_other:N . 580 . . 2858 \token_if_protected_macro:N . . 787. . . 2966 \token_if_toks_register:NTF . . . 1208. . . 2923. . . . . . 787. . . . . . . . . . . . . 630 \toksdef . . . . 2767 \token_if_parameter:NTF . \unkern . . 10664. . 57. 2705 \token_to_meaning:N . . . . . 2719 \token_to_meaning:c . 2830. . 55. 3366 \token_if_other_p:N . . 665 \tracingifs . 55. . \unhcopy . . 9442. . 2878 \token_if_mathchardef:NTF 57. 2783 \token_if_space_p:N . . . . . 1221. 2858 \token_if_muskip_register_p:N . 190. 13755 \toks . . . . . 2755. . 10497. . . . 644 . . . 8188. . 54. 3369 \token_if_other_char:NF . . 2765 \token_if_parameter_p:N . . 2716. . . . . . . . 9439. . . . . . . 2977. 1210. . . . \uccode . 1454. . . . 3362 \token_if_mathchardef:N . . . . 2717. 399 \tracingnesting . . . . . . . . .. . . . . 3269. . . . . . 331 \tolerance . . . . . . . . . . . . . 7534. . . . . . . . . . . . . . . 3017 \token_if_protected_long_macro:N . . . . 2930 \token_if_muskip_register:NTF . . . 2984 \token_if_protected_macro:NTF . . . . 653 . . . . 2705. . . . . . . . 10510. . . 2793. . . 10558. . 2961. 2793 \token_if_other:NF . . . . 6768. . . . . . .. . . . . . 2718. . . . . . . . 1908. 2858 \token_if_muskip_register:N . . . 2990. 10665. . . . . . . . . . . . 800. . 2003. . . 658 \tracingcommands . . . . 1342. . . . . 3357. . . . . . . . . . . . . . . . . . . . . . . 2036. 10300. . . 581 . . 2858. .. . .. 2765 \token_if_primitive:N . . . 811. . . . 55. . . . . 788. . . . 56. . . . . . . . 403 \tracingrestores . . . . 615 . . . . . . . . . .. . . . . . . . . . . . 474 186. . . . . 552 \tracingassigns . . . . . 2793. 10524. . . . . . 9438. . . . . . . . . . . . . . . . . . . . . . 6619. . . . . . . . . . . . 7530. . . . . . . . . . . . 1018. . . . . . . . 980. . . . . \underline \unexpanded \unhbox . . 800. . 9441. . . . . . 2705. . . . . 3011. . . 2710. . . 56. . . . . . 5. . 10509. . . . 8278. . . . . 4287. 19. .value_required: . 868. . . . 9939. 9611. . . . . . 858. . \vbox_gset_to_ht:Nnn 133. . 9973. 1671. . . . 9999. . . . 11881 \use_none:nnnnnnnn . 8440. . 7839. . . . 1935. . . 1604. 9937. 804. 1040 \use_none:nnnnnnn . 4281. 2512 \use_none_delimit_by_q_stop:w . 4080. 8413. 7879. . . . . 4839. 940. 12943. . 870. 11867. 9811. 1451. . 9523 \use:n . 5928. . . 986. . 9842. . 8021. . 1497. 9959. 19. . . . . 1019. 5267. . 9817 \use_none:nnnn . . 4076. . . . . \vbox_gset_inline_begin:c . 869. . . . . . . . . . . . . 870. . . . 11865. . 4743. . . 2184. . . . . . 865. 6126. . . . 7897. . 874. . . 953. . . . . 47. 10005 \use_none:nnnnnn . 1479. . . 149. . . . 6667. . 9807. 4751. . 884. . \vbox:n . . 9813. . . 878 \use_none_delimit_by_q_recursion_stop:w . . 1937. . 7853. . . . . 1493. 6659. 864. 3278. . . 2180. . . . . . 4291. . . 8462 \use_ii:nnnn . 5295. . . 2004. 5071. 7847. . . 6008. 6247. . . 9756. . 8441. . . . 3840. 9818. . . 5159. \vbox_gset_inline_end: . . . . . . . 876 \use_iv:nnnn . 882. 19. . . . . 773 3955. . . 871. . . 10834. . 8410. 12776. 883. . . 1339 \use:nnnn . . 7807. 6682. 133. 886. . . 8455. . . . . 3065. . 3579.value_forbidden: . . . 864. . 2193. 8004. 8563. . . 14472. 5273. . . 13700. . 4982. . . 878. . . . 806. . 1114. 879. . 6682. . 2726. 1483. . 133. 12038 \use_i_after_else:nw . 970. . 4762. . 868. \vbox_gset:cn . . . 1098. . 15150 \usepackage . . \vbox_gset_top:cn . . . . . . 10207. . 47. . . . . . 9819. . 955. 6682. . 2735. . . 5599. . . \vbox_gset:cw . . . . . . 868. . 19. 875 \use_iii:nnn . . . . . 1484. 2214. 2505. 859. 1142. 13692 \use_ii:nnn . . 11841. 9805. . . . 11842. 5157. 4075. 11848. . 20. 7822. . . 14501 \use_none:nnn . 942. . 2519 \use_i_delimit_by_q_stop:nw . 8222. . 884. 1166. . 5605. . 6694. . . . . . . 6110. . . . . . . 20. . . . . 1604. . . . 1321. . 1004. . . . . 3260. . 4386. 3710 \use_none:nnnnn . . . . . 866. . 1096. . . 10007. . . 7831. . 864. 870. . . . . 5239. . . . . 9566. 20. . . . 1503. . . 5790. . . 1561. 9907. . 5027. . 1480. \valign . 6678. 864. . 8735. 894. . . . 7796. . 6021. 858. . . . . . 132. . 1024. 6248. 14851. 5172. . . 884. . 884. \vbox_gset:Nn . 5292. . 133. . . 1496. 6694. . . . 4801. . 9313. 9810. . . . . 986. 14877. 5248. . . 9806. 8683. . 19. 9879. 873. . 8073. . . 9815. . . . . 20. 2203. 878. . . . . . . . . 1607 \use_i_after_orelse:nw . . . . . . . . 1989. 9971. 6672. 881 \use_i_delimit_by_q_recursion_stop:nw . . \vbox_gset:Nw . 870. . . 870. . . . . 14997 \use_none:nn . . 3919. 12339. . 14419. 1608 \use_i_delimit_by_q_nil:nw . 9088. . . . . 6676. . . 1486. . 1168. . \vbadness . . 6687. 870. . 2503. . 1170. 14876. . 19. 6665. 2497. 1291. . . . . 5621. 1319. 880. 9976. . . . 8259. 5398. . . 6616. 1505. . . . . . 972. 6670. 9613. . . . . . 8556. 5625. 14414. . 1506. . . 12774. . . . 884. 7760. 5251. \vbox_gset_inline_begin:N . . 9814. . . . 3959. 5198. . . . . . 5511. 6694. 2197. . 864. 1604. 878. 6684. . . 870. 19. . . . 9809. 13382 \use_i:nnn 19. . 881. . \vbox_gset_to_ht:cnn . 870. 3909. . . . . . 884. . . . 1606 \use_i_after_fi:nw . . . 10012. 7718. . . 896. 20. . . 9984. 3251. 3964. . . 6693. 1556. 11845. . 1928. 888. . . . 2384. . . . . . 892 \use_none_delimit_by_q_nil:w 20. . 17. . 890. 5679. . 19. 887. . 1164. 6599. . . 12419. . . . 2215. 1478. 11823 \use_i:nnnn 19. 877 \use_none:n . . . . . 7777. . 13384. . 1646. . . 5156. 20. 1031. 4073. . 1504. . . . . . 870. . . . . 1482. 9552. . 881. . . . . 9997. . 1494. . . . 2521. 14427 \use_i_ii:nnn . . . 2193. 4062. . . . 872. . . . 1144. . 133. 884. . 867 \use:x . . . 932. 230 V \vadjust . . . . . . \vbox . 18. . . . 859. 1033. . . 3590. 1492. 4930. 9858 \use_iii:nnnn . . 515 350 153 153 590 585 6659 6665 6698 6669 6697 6699 6698 6697 6699 6676 6681 6670 6675 . . . . 2388. 9942. . . 1604. . . . 3269. . . . . . 9851. 884. 9464 \use_i:nn . . . . . . . . 2059. . 1481. . . . . . . . 1471. . . . . . . . 881. . . . . 8069.Index \use:c . . . 885. . . . 884. . 1508. . . . 12948 \use:nnn . . 12440. . . 19. . \vbox_gset_top:Nn . . . 1485. 13342 \use_ii:nn . 9950. 1495. . 889. 1507. \vbox_gset_end: . 1116. . . . . . . 4071. 5217. . . . 962. 9868. . 1605 \use_i_after_or:nw . . 1289. . . 884. . . 891 \use_none:nnnnnnnnn . . 14812 \use:nn . . . . 6700. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6693. . 6661. . . . . . . . . . . . . . . 6694 \vbox_set_inline_end: . . .. . . . . 6855. . . 6676. . . 6696. 136. . . . 728. . . . . . . . . . . . 6659. . . . . . . . . \write . . 6887 \vfil . . . . . 624 . 133. . . . . . . . . . . .. . . 6694. . . \vss . . . . . . . . . . . . . . . . . . . . .. . . 6668. . . . . . . . . . . 6694. . . . 6855. . . . . . . . 6682. . . . \vtop . . . . . . W . . .. . . . . \wd . . . . . . . . . . . . . . . . . . . . . . . 6702. . . . . . . . . . . . . 6700. . . . 6826. . . . . . . . . 1499. . . . . . . 6670 \vbox_set_top:Nn . . . 6686. . . . . . . 6700 \vbox_unpack_clear:N 134. . \voffset \vrule . . . . . . . . . . . 6665. . . . . . . . 436 \vcoffin_set:cnn . . . . . . . . . . . . . . . . 6855 \vcoffin_set:Nnn . . . . . . . . . . . . . . . . . . . . . . 6682. . . . . . . . . . . . . . . . . . . . . .Index \vbox_set:cn . 6695 \vbox_set:Nn . . . . . . . . . . . . . . . . . . . 6661 \vbox_to_zero:n . . . . . . . . . . .. . 6700 \vbox_unpack:N . . . . . . 509 exp . . . . . . . . 6679. . . . . . . . . . . . . . . . . . . . . . . 23. . . 6680 \vbox_set_top:cn . . . . 6665 \vbox_set:cw . . . . . . . . 6888 \vcoffin_set_end: . . . . . . . . . 178 \xspaceskip . . 6688. . . . . . . . . 6701. 6873 \vbox_to_ht:nn . . . . . 6663 \vbox_top:n .. . . . . 497 \vfill . . . . 1495 \xetex_if_engine:TF 5. . . . . . . 6695 \vbox_set_inline_begin:N . . . . . . . . 6859 \vbox_set_end: . . . . . . . ... . . . . 133. . . . . . 1496 \xetex_if_engine:T . . . . . . 1490 \XeTeXversion . 633 693 520 177 383 X \X . 6808 \vcoffin_set:cnw . . . 1478. . . 1485. . . . . . 180 \xdef . . . . . 133. . . 543 Y \year . . . . 133. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6808. . . 23. . . 6869 \vbox_set_inline_begin:c . . . . . \vsize . . 2043 ex . . . . . 6808. . 6665. . . . . . . 6661. . . . . . . . . . . . . . . . . . . . . . . . 6667. . . . . . . . . . . . . . . . . \vsplit . . . . . . . 499 774 \vfilneg \vfuzz . . . . . . TWOBARS . . . . . . . . . . 6866. . . . . . . . . . 132. . . \widowpenalties \widowpenalty . . . . 6685. . 6700. . . 324 \xetex_if_engine:F . . . . . . . . . . . . . . . . . . 6682. . 728 \xleaders . 498 592 567 506 549 500 578 501 586 . . . . . . . . . . . . . 6670. . .. . . . . . . . . . . . . . . . . 6694. . 6670. . . . . . . . . . . . 1478. . . . . . .. 6704. . . . . . . . . . . . . . . 6826. . . . . . . 6676 \vbox_set_to_ht:Nnn . . . . . . . . . . . . . . . . . 1484. . . . . . . 6674. . 6703 \vcenter . . . . . 6673. . 6660 \vbox_unpack:c . . . 6873 \vbox_unpack_clear:c . . . . . . . . . . . . . . . . . . 1486. 136. 6682. . . 6676. . . . . . . 6837 \vcoffin_set:Nnw . . . . . . . 133. . . . . . . 1497 \xetex_if_engine_p: . . 6696 \vbox_set_split_to_ht:NNn 133. . . . . . . . .. . 6812 \vbox_set:Nw . . . . . . . . . . . . . . . . . . . . .. . . . . . 6694. .. 6704 \vbox_set_to_ht:cnn . 1602 \xetex_XeTeXversion:D . . . . . . . . . 6661. . . . . . 136. . . . . . . . . . . 6661. . . . . . . . .. . . 133. . . . 6855. . . . . . 133. . . . \vskip . . . . . 1489. . . . . . . . . 134. . . . . .