The grading-scheme package
Maximilian Keßler
∗Released 2022/02/24
version 0.1.1
Abstract
This package aims at an easy-to-use interface to typeset grading schemes in tab- ular format, in particular grading-schemes of exercises of mathematical olympiads where multiple solutions have to be graded and might offer mutual exclusive ways of receiving points.
Contents
1 General notions 2
2 Usage 3
3 LATEX3 interface 4
Change History 5
4 grading-scheme implementation 5
4.1 Dependencies and options . . . 5
4.2 A simple logging module . . . 5
4.3 Wrappers . . . 6
4.4 Customizable backends . . . 7
4.5 Resources . . . 7
4.6 Pointers . . . 9
4.7 Structs . . . 15
4.8 Entries . . . 15
4.9 Blocks. . . 19
4.10 Elements . . . 28
4.11 Facilities for populating data structures . . . 34
4.12 Grading scheme environment . . . 36
4.13 Implementing the pipe syntax . . . 39
Index 40
sum
At least one correct solution 1 P.
All correct solutions 1 P.
max
Uniqueness proofs
max
First solution
sum
Show that either 4|p−2 or 3|p−4. 3 P.
Show thatm= 5 2 P.
Show thatn= 4 1 P.
Conclude solutions 1 P.
Second solution
sum
Show thatpis even 2 P.
Reduce to at most 30 candidates 3 P.
Test all candidates 2 P.
min(2)
Plausible Arguments
sum
plausible argument that there are finitely many solutions 1 P.
suggestion that divisibility by 4 is useful 1 P.
suggesting that not both ofm,ncan be ’large’. 1 P.
Table 1: Example output of a grading scheme.
1 General notions
Probably, an example is fitting best at this point. If you want to set up a grading scheme, with thegrading-scheme package all you have to do to get the output ofTable 1is type the following:
\begin{gradingscheme}{sum}
| At least one correct solution & 1
| All correct solutions & 1
\begin{block}{max}
\begin{block}[Uniqueness proofs]{max}
\begin{block}[First solution]{sum}
| Show that either $4 \mid p - 2$ or $3 \mid p - 4$. & 3
| Show that $m = 5$ & 2
| Show that $ n = 4 $ & 1
| Conclude solutions & 1
\end{block}
\begin{block}[Second solution]{sum}
| Show that $p$ is even & 2
| Reduce to at most 30 candidates & 3
| Test all candidates & 2
\end{block}
\end{block}
\begin{block}{min(2)}
\begin{block}[Plausible Arguments]{sum}
| plausible argument that there are finitely many solutions & 1
| suggestion that divisibility by 4 is useful & 1
| suggesting that not both of $m$, $n$ can be ’large’. & 1
\end{block}
\end{block}
\end{block}
\end{gradingscheme}
Note in particular that the correct width of the rows and columns are automatically adjusted.
For us, a grading scheme consists of several statements, each worth some specific number of points, that will be combined into a final number of points using a nested expression of operations, typically sums, maximums or minimus.
An abstract grammar defining our notions is defined in Table 2. The meanings of
⟨balanced text⟩and⟨number⟩are as usual.
grading scheme := block
block := [⟨block description⟩],⟨block operation⟩,⟨element list⟩
element list :=⟨element⟩ | ⟨element⟩: ⟨element list⟩
element :=⟨block⟩ | ⟨entry⟩
entry :=⟨entry description⟩, ⟨entry points⟩
block description :=⟨balanced text⟩
block operation :=⟨balanced text⟩
entry description :=⟨balanced text⟩
entry points :=⟨number⟩
Table 2: Abstract grammer for a grading scheme
The package facilitates specifying a grading scheme according to this grammar and typesets these.
2 Usage
Load the package as usual by
\usepackage[pipe]{grading-scheme}
Thepipe option is of course optional and the only currently supported option. It activates the pipe syntax explained later.
gradingscheme \begin{gradingscheme}[⟨description text⟩]{⟨operator⟩}
\end{gradingscheme}
The main environment provided by this package. Inside the grading scheme, any number of blocks and entries can be specified. The grading scheme environment will act like the outer-most block and typeset all its contents.
Grading schemes cannot contain each other. As they are implemented astabulars, you can (and maybe should) put a grading scheme into atableenvironment as if it were a regulartabular.
TEXhackers note: Actually, the gradingscheme environment just sets up some hooks that further block environments and entries will fill and typesets these at the end of the environment.
You could technically put any regular text inside the grading scheme and this will be typeset as if it had been specified before the grading scheme. However, this is definitely not recommended.
block \begin{block}[⟨description text⟩]{⟨operator⟩}
\end{block}
The⟨description text⟩will be shown in a separate row on top of the block. If not specfied, no such row is inserted. The⟨operator⟩is printed in small capitals (and rotated) in a column that spans the left side of the block, indicating that this operation is applied to the block.
The block will be an element of the outer block or grading scheme it is contained in.
Inside the block, any number of blocks or entries can be specified (in order) that will be typeset as members of this block.
A block environment can only be used inside a gradingscheme. Block environments can contain each other in balanced form.
\entry{⟨entry description⟩}{⟨points⟩}
Specifies an entry with given description and points. The entry is typeset as part of the block/grading scheme containing it.
\entry
| ⟨entry description⟩ & ⟨points⟩ \n
This is an alternative form to specify an entry. The\nis to be interpreted as a newline in the source file, so|reads until the end of the line.
This is equivalent to calling\entry{⟨entry description⟩}{⟨points⟩}
The package optionpipehas to be specified to activate this syntax.
TEXhackers note: The| character (pipe) is made an active character for the scope of each gradingscheme environment. Thus, this syntax only works if the gradingscheme is read in expansion mode by LATEX, since otherwise the category code will be messed up.
|
3 L
ATEX3 interface
There is also a LATEX3 interface for dealing with this package that can deal with all of the mentioned notions separately, technically allowing you to combine them in other ways or formatting them into your custom tables.
These functions are for now not documented separately, since the author thinks that such use cases would be rather rare.
The LATEX3 interface is, however, not considered to be stable yet, so if you really have to rely on this, feel free to contact the author.
Change History
0.1
General: Initial release . . . 1 0.1.1
General: Bug fix (thanks to Denis
Bitouzé), typos. . . 1
4 grading-scheme implementation
1 ⟨∗package⟩
2 ⟨@@=grading_scheme⟩
4.1 Dependencies and options
Currently, there is only one option
\g__grading_scheme_pipe_syntax_bool This will toggle the pipe syntax option of the package.
3 \bool_new:N \g__grading_scheme_pipe_syntax_bool (End definition for\g__grading_scheme_pipe_syntax_bool.)
4 \keys_define:nn { grading-scheme }
5 {
6 pipe .bool_gset:N = \g__grading_scheme_pipe_syntax_bool,
7 pipe .default:n = { true },
8 unknown .code:n =
9 {
10 \msg_error:nnn { grading-scheme } { unknown-option} { \l_keys_key_str }
11 }
12 }
13 \msg_new:nnn { grading-scheme } { unknown-option}
14 {
15 Unknown ~ option ~ ’#1’.
16 }
17 \RequirePackage { l3keys2e }
18 \ProcessKeysOptions { grading-scheme }
19 \RequirePackage{multirow}
20 \RequirePackage{rotating}
4.2 A simple logging module
21 ⟨∗log⟩
We provide a simple log/debugging facility for this package.
\g__grading_scheme_log_depth_int Stores the log depth for indentation in the log file.
22 \int_new:N \g__grading_scheme_log_depth_int (End definition for\g__grading_scheme_log_depth_int.)
\__grading_scheme_log_incr: Increments the log depth
23 \cs_new:Npn \__grading_scheme_log_incr:
24 {
25 \int_gincr:N \g__grading_scheme_log_depth_int
26 }
(End definition for\__grading_scheme_log_incr:.)
\__grading_scheme_log_decr: Decrements the log depth
27 \cs_new:Npn \__grading_scheme_log_decr:
28 {
29 \int_gdecr:N \g__grading_scheme_log_depth_int
30 }
(End definition for\__grading_scheme_log_decr:.)
\__grading_scheme_log:n
\__grading_scheme_log:x
Logs to the terminal and log file using the current depth.
31 \cs_new:Npn \__grading_scheme_log:n #1
32 {
33 \iow_term:x
34 {
35 [gs] \prg_replicate:nn \g__grading_scheme_log_depth_int { . . }
36 \exp_not:n { #1 }
37 }
38 \iow_log:x
39 {
40 [gs] \prg_replicate:nn \g__grading_scheme_log_depth_int { . . }
41 \exp_not:n { #1 }
42 }
43 }
44 \cs_generate_variant:Nn \__grading_scheme_log:n { x } (End definition for\__grading_scheme_log:n.)
45 ⟨/log⟩
4.3 Wrappers
We provide some LATEX3 wrappers for private usage.
\__grading_scheme_multicolumn:nnn Just a wrapper around \multicolumnfrom LATEX 2ε.
46 \cs_set_eq:NN \__grading_scheme_multicolumn:nnn \multicolumn (End definition for\__grading_scheme_multicolumn:nnn.)
\__grading_scheme_multirow:nnn Just a wrapper around \multirowfrom LATEX 2ε.
47 \cs_set_eq:NN \__grading_scheme_multirow:nnn \multirow (End definition for\__grading_scheme_multirow:nnn.)
\__grading_scheme_cline:n
\__grading_scheme_cline:nn
A wrapper around\cline.
The second form takes the beginning and ending column as separate arguments.
48 \cs_set_eq:NN \__grading_scheme_cline:n \cline
49 \cs_new:Npn \__grading_scheme_cline:nn #1 #2
50 {
51 \__grading_scheme_cline:n { #1 - #2 }
52 }
(End definition for\__grading_scheme_cline:n and\__grading_scheme_cline:nn.)
\__grading_scheme_hline: Wrapper for a\hline
53 \cs_set_eq:NN \__grading_scheme_hline: \hline (End definition for\__grading_scheme_hline:.)
\__grading_scheme_rotatebox:nnn Wrapper around rotatebox
54 \cs_new:Npn \__grading_scheme_rotatebox:nnn #1 %implicit #2, #3
55 {
56 \rotatebox [ #1 ]
57 }
(End definition for\__grading_scheme_rotatebox:nnn.)
4.4 Customizable backends
We set up some functions that will be used internally, but could technically be customized at some point. For now, these are just constants.
\__grading_scheme_points:n Prints the number of points. Used in the last column of the grading scheme.
58 \cs_new:Npn \__grading_scheme_points:n #1
59 {
60 \textbf{ #1 ~ P. }
61 }
(End definition for\__grading_scheme_points:n.)
\__grading_scheme_operation:n Prints an operation. Used in the leftmost column of a block.
62 \cs_new:Npn \__grading_scheme_operation:n #1
63 {
64 { \sc #1 }
65 }
(End definition for\__grading_scheme_operation:n.)
4.5 Resources
4.5.1 Some general thoughts
This is some general reasoning about why we model data structures as we do in this package, comparing parts of LATEX3 to plainCcode.
We have to model elements, blocks and entries here. LATEX3 provides some data structures for this, and we will use property-lists to model our data structures for this package.
When thinking about what a property list is, a call to \prop_new:N essentially allocates some memory for us and makes our given argument apointerto a data structure that we refer to as a “property list”.
We want to think of these as pointers since modifying a property list at some place really also modifies this property list at another, so these behave like pointers.
Considering the grouping mechanism of TEX, this is of course not quite right for local variables (we assume that in the LATEX3 spirit, all variables are either local or global once and for all, to avoid confusion) since these rather correspond to one pointer at each grouping level, where upon entering such a grouping level, the (new) pointer is
initialized with a copy of the outer instance of the pointer and destroyed again when leaving the current grouping level.
In this spirit, we really want to think of grouping levels asscopeslike inC.
Considering functions now, a typical LATEX3 function has no return value (these would be functions with the_ppredicate or _use: functions that leave contents in the input stream), since this is in general not desired. Rather, we pass pointers as a func- tion argument and receive the desired “return value” as written into our given pointer (overwriting any prior data), which is also a common behaviour in large parts ofC.
Now, as mentioned earlier, data structures such as property queues are just pointers that refer to some tokens with specific internal structure. All functions dealing with such pointers have to ensure that these invariants remain satisfied, and this is what functions like \prop_get:NnN or \prop_put:Nn do. The key point here is that we refer to these structures only with pointers and do not deal with them directly. This is what gives us some very nice abstrict model, hiding the class invariants of a property queue from the user and providing high-level semantic access to such data structures.
Just for completeness, we mention that this is not the case for all data structures.
For example, aclisthas some structure that is well-known and can be dealt with by the user directly. That is why there are alsoclistcommands acceptiongn-type arguments for dealing with a clist, but no such commands for property-lists, as they only use N and thus essentially pointers.
If we want to model data structures now, especially ours from this package, we even want data structures containing other data structures. Although technically, storing all data of a grading scheme in a single macro would be possible, due to its recursive structure, parsing would be quite a challenge and possibly also rather slow. Also, this would requiredirect access to the representation of blocks contained in this block, which is undesired.
Compare this to the question of putting a property-list inside a property-list. Since there is no (semantic/provided) possibility of actually putting a property-list anywhere, we cannot store property-lists in property-lists directly. We can, however, store the name of a property list inside of another one, this amounts to actually storing the pointer to the first list inside the second one.
Now, back to our package, we essentially want to model blocks and alike as C-style structs that contain pointers to their elements and similar. The classic question of ownership arises in this context, so we would have to consider shallow or deep copies and a user has to watch out when dealing with our data structures.
Since only a limited set of operations is needed in our case, we take a simple approach by saying that each struct owns all its contents, that is, owns everythin its data member pointers point to, also recursively. This essentially forbids shallow-copying (violating our assumption) but we do not need this here, so this is okay.
Still, this hase some undesired consequences: Since in LATEX3 each pointer has some name, we need to construct a lot of pointers on the fly where we are not able to actually specify their names directly, so we have to indirectly deal with pointers. That means that we actually need double-pointers, i.e. local variablescontainingpointers to the data structures we are actually interested in. This is what a void**would correspond to in C. Also, note that once we store a pointer to some element in a property queue (e.g. the name of the list of members when dealing with a block), we actually also need avoid**
when retrieving this value again from the property queue, since we return by pointer.
Consequently, this leads to quite a lot of expansion-control when dealing with such pointers, and if not taking precautions, also to easy confusion about what is a pointer and what not.
Our approach to tackle these problems is described insubsection 4.6.
4.6 Pointers
This module should/will be reworked into an own package in the future. Also, there is no proper documentation for it apart from the comments in the implementation, since this is not meant to be used in other code than this package currently, nor regarded stable.
We introduce a new data type of pointer and a new argument type of P. The argument typePshall indicate a single expansionwith the assumption that this expansion will yield a single token. So, from an implementation point of view, this is the same as ano-type argument, just with further restricted assumptions.
This also enables us to generatePvariant arguments fromNvariant macros. Compare this to the usual deprecation warning that LATEX3 gives when generating an o variant from anN-type argument:
! LaTeX3 Error: Variant form ’o’ deprecated for base form ’\foo:N’. One (LaTeX3) should not change an argument from type ’N’ to type ’o’:
(LaTeX3) base form only accepts a single token argument.
Since basically anything in LATEX3 is in fact a pointer, we will introduce thepointer structure with theptrtype (suffix) and actually mean that this is avoid**.
Thus, we introduce the following conventions:
1. A TEX-pointer is a TEXcontrol sequence that represents some data.
2. Apointeris a control sequence that expands to a single TEX control sequence that is a TEX-pointer.
3. Thename of apointeris the name of the control sequence representing it. Thus, such a name always ends with_ptr by convetion.
4. Aptris said to beNULLif its expansion yields an undefined TEX control sequence.
We also refer to this as a nullptr.
5. A typed pointer is a pointer where the underlying type is specified. By this, we mean that expanding the token exactly once yields a token representing a data structure of the type we said this pointer to have or that the pointer isNULL.
6. A void pointer shall be a pointer whose actual type is unknown.
7. When aptris of typetype, we denote these by the suffix_type_ptr.
8. Dereferencing a pointer amounts to expanding it exactly once.
9. AP-type argument accepts a single token that has to be of typeptr. The token is expanded exactly once and then treated as anN-type argument in the corresponding function.
\g__ptr_counter_int Counts the number of pointers given by\ptr_new:N. This ensures that each pointer can have a unique name regardless of grouping.
66 \int_new:N \g__ptr_counter_int (End definition for\g__ptr_counter_int.)
\l__ptr_var_prefix_str Stores the prefix of new pointer variables.
67 \str_new:N \l__ptr_var_prefix_str (End definition for\l__ptr_var_prefix_str.)
\ptr_new:N \ptr_new:N⟨pointer⟩
Gives a new unique pointer that isNULL. Gives an error when the⟨pointer⟩already exists. The pointer variable is created globally.
68 \cs_new:Npn \ptr_new:N #1
69 {
70 \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str
71 \ptr_new:NVn #1 \l__ptr_var_prefix_str { any }
72 }
73 \cs_new:Npn \ptr_new:Nn #1 #2
74 {
75 \ptr_new:Nnn { #1 } { #2 } { any }
76 }
77 % ptr var, prefix, type
78 \cs_new:Npn \ptr_new:Nnn #1 #2 %i #3
79 {
80 \str_case:nnT
81 { #2 }
82 {
83 { l } { }
84 { g } { }
85 }
86 {
87 \tl_new:N #1
88 }
89 \__ptr_init:Nnn #1 { #2 } %i { #3 }
90 }
91 \cs_generate_variant:Nn \ptr_new:Nnn { N V n }
92 % ptr var, prefix, type
93 % assumes that the pointer name exists already in case of l or g prefix
94 \cs_new:Npn \__ptr_init:Nnn #1 #2 % implicit #3
95 {
96 \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str
97 \str_case:VnF
98 \l__ptr_var_prefix_str
99 {
100 { l }
101 {
102 \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_set:Nx
103 }
104 { g }
105 {
106 \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_gset:Nx
107 }
108 { c }
109 {
110 \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_const:Nx
111 }
112 }
113 {
114 \str_show:N \l__ptr_var_prefix_str % TODO: show error
115 }
116 \__ptr_init_aux:Nnn #1 { #2 }
117 }
118 \cs_generate_variant:Nn \__ptr_init:Nnn { N V n }
119 % ptr var, prefix, type. assumes poly_tl_set:Nx has been set
120 \cs_new:Npn \__ptr_init_aux:Nnn #1 #2 #3
121 {
122 \__ptr_poly_tl_set:Nx #1
123 {
124 \exp_not:c
125 {
126 #2
127 __ptr__unique__
128 \int_use:N \g__ptr_counter_int
129 _
130 #3
131 }
132 }
133 \int_gincr:N \g__ptr_counter_int
134 }
135 \cs_generate_variant:Nn \__ptr_init:Nnn { N V n } (End definition for\ptr_new:N. This function is documented on page??.)
\__ptr_get_var_prefix:NN Gets the first character of the name of the variable given as #1. The first character is assumed to be one ofc,lorgby usual naming conventions.
136 \cs_new:Npn \__ptr_get_var_prefix:NN #1 #2
137 {
138 \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } l
139 {
140 \str_set:Nn #2 { l }
141 }
142 {
143 \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } g
144 {
145 \str_set:Nn #2 { g }
146 }
147 {
148 \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } c
149 {
150 \str_set:Nn #2 { c }
151 }
152 {
153 \msg_error:nnx { ptr } { variable-name-illegal-prefix }
154 {
155 \token_to_str:N #1
156 }
157 }
158 }
159 }
160 }
161 \msg_new:nnnn { ptr } { variable-name-illegal-prefix }
162 {
163 Requested ~ new ~ pointer ~ ’#1’ ~ has ~ illegal ~ prefix.
164 }
165 {
166 Prefix ~ should ~ be ~ one ~ of ~ ’l’, ~ ’g’ ~ or ~ ’c’.
167 }
(End definition for\__ptr_get_var_prefix:NN.)
\ptr_clear:N Clears this pointer. This makes the pointer equivalent to a newnullptr.
168 \cs_new:Npn \ptr_clear:N #1
169 {
170 \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str
171 \__ptr_init:NVn #1 \l__ptr_var_prefix_str { any }
172 }
173 \cs_new:Npn \ptr_clear:Nn #1 #2
174 {
175 \__ptr_init:Nnn #1 { #2 } { any }
176 }
(End definition for\ptr_clear:N. This function is documented on page??.)
\ptr_set:NN Sets the pointer to represent the given argument.
177 \cs_set_eq:NN \ptr_set:NN \tl_set:Nn
(End definition for\ptr_set:NN. This function is documented on page??.)
\ptr_set_eq:NN Accepts two pointers. The first is set to be equivalent to the second.
178 \cs_set_eq:NN \ptr_set_eq:NN \tl_set_eq:NN
(End definition for\ptr_set_eq:NN. This function is documented on page??.)
\ptr_use:N Uses the pointer, i.e. expands to the stored TEX-pointer.
179 \cs_set_eq:NN \ptr_use:N \tl_use:N
(End definition for\ptr_use:N. This function is documented on page??.)
\__ptr_check:N Checks that the given argument is a pointer.
180 \cs_new:Npn \__ptr_check:N #1
181 {
182 \tl_if_single:NF #1
183 {
184 \msg_error:nnx { ptr } { is-not-a-pointer }
185 {
186 \token_to_str:N #1
187 }
188 }
189 }
190 \msg_new:nnn { ptr } { is-not-a-pointer }
191 {
192 The ~ control ~ sequence ~ ’#1’ ~ is ~ not ~ a ~ valid ~ pointer.
193 }
(End definition for\__ptr_check:N.)
\__ptr_check:NN Checks that the second argument is a pointer.
194 \cs_new:Npn \__ptr_check:NN #1 #2
195 {
196 \__ptr_check:N #2
197 #1 #2
198 }
(End definition for\__ptr_check:NN.)
\__ptr_check:nN Checks that the second argument is a pointer.
199 \cs_new:Npn \__ptr_check:nN #1 #2
200 {
201 \__ptr_check:N #2
202 { #1 } #2
203 }
(End definition for\__ptr_check:nN.)
\l__ptr_content_tl Stores the (internal) TEX-pointer of apointer.
204 \tl_new:N \l__ptr_content_tl (End definition for\l__ptr_content_tl.)
\exp_args:NP
\exp_args:NNP
\exp_args:NNNP
\exp_args:NNNNP
\exp_args:NPP
Expands a pointer. This leaves the first tokens as a single token in the input stream, followed by the value of the pointer as a single token.
If the last argument does not expand to a single token, an error is given.
205 \cs_new:Npn \exp_args:NP #1 #2
206 {
207 \__ptr_check:N #2
208 \exp_last_unbraced:No #1 #2
209 }
210 \cs_new:Npn \exp_args:NNP #1 #2 #3
211 {
212 \__ptr_check:N #3
213 \exp_last_unbraced:NNo #1 #2 #3
214 }
215 \cs_new:Npn \exp_args:NNNP #1 #2 #3 #4
216 {
217 \__ptr_check:N #4
218 \exp_last_unbraced:NNNo #1 #2 #3 #4
219 }
220 \cs_new:Npn \exp_args:NNNNP #1 #2 #3 #4 #5
221 {
222 \__ptr_check:N #5
223 \exp_last_unbraced:NNNNo #1 #2 #3 #4 #5
224 }
225 \cs_new:Npn \exp_args:NPP #1 #2 #3
226 {
227 \__ptr_check:N #2
228 \__ptr_check:N #3
229 \exp_last_two_unbraced:Noo #1 #2 #3
230 }
(End definition for\exp_args:NP and others. These functions are documented on page??.)
\ptr_if_null:NTF Checkes if the pointer isNULL.
231 \cs_new:Npn \ptr_if_null:NT
232 {
233 \exp_args:NP \cs_if_exist:NF
234 }
235 \cs_new:Npn \ptr_if_null:NF
236 {
237 \exp_args:NP \cs_if_exist:NT
238 }
239 \cs_new:Npn \ptr_if_null:NTF #1 #2 #3
240 {
241 \exp_args:NP \cs_if_exist:NTF #1 { #3 } { #2 }
242 }
(End definition for\ptr_if_null:NTF. This function is documented on page??.)
\tl_set_eq:NP
\tl_set_eq:PN
\tl_set_eq:PP
\tl_use:P
\exp_not:P
\clist_new:P
\clist_put_right:Pn
\clist_gput_right:Pn
\clist_map_function:PN
\prop_show:P
\clist_show:P
Just variants of\tl_set_eq:NNwith indicated signature.
243 \cs_new:Npn \tl_set_eq:NP
244 {
245 \exp_args:NNP \tl_set_eq:NN
246 }
247 \cs_new:Npn \tl_set_eq:PN
248 {
249 \exp_args:NP \tl_set_eq:NN
250 }
251 \cs_new:Npn \tl_set_eq:PP
252 {
253 \exp_args:NPP \tl_set_eq:NN
254 }
255 \cs_new:Npn \tl_use:P
256 {
257 \exp_args:NP \tl_use:N
258 }
259 \cs_new:Npn \exp_not:P
260 {
261 \exp_args:NP\exp_not:N
262 }
263 \cs_new:Npn \clist_new:P
264 {
265 \exp_args:NP \clist_new:N
266 }
267 \cs_new:Npn \clist_show:P
268 {
269 \exp_args:NP \clist_show:N
270 }
271 \cs_new:Npn \clist_put_right:Pn
272 {
273 \exp_args:NP \clist_put_right:Nn
274 }
275 \cs_new:Npn \clist_gput_right:Pn
276 {
277 \exp_args:NP \clist_gput_right:Nn
278 }
279 \cs_new:Npn \clist_map_function:PN
280 {
281 \exp_args:NP \clist_map_function:NN
282 }
283 \cs_new:Npn \prop_show:P
284 {
285 \exp_args:NP \prop_show:N
286 }
(End definition for\tl_set_eq:NP and others. These functions are documented on page??.)
\ptr_show:N Shows information about this pointer, namely:
If it isNULL, then it indicates this. If it is notNULL, then the TEX-pointer and the contained contents of the TEX-pointer (in unexpanded form) are shown.
287 \cs_new:Npn \ptr_show:N #1
288 {
289 \__ptr_check:N #1
290 \ptr_if_null:NTF #1
291 {
292 \tl_show:x
293 {
294 \token_to_str:N #1 -> \exp_not:P #1 = NULL
295 }
296 }
297 {
298 \tl_show:x
299 {
300 \token_to_str:N #1 -> \exp_not:P #1 -> \exp_args:NP \exp_not:V #1
301 }
302 }
303 }
(End definition for\ptr_show:N. This function is documented on page??.)
4.7 Structs
We will model C-style structs as property-lists in this package. Each struct member is put into the property list, using its ’name’ as a key, and we store the corresponding contents there.
We will also have a local variable named correspondingly for eachstructmember.
In case we deal with a struct and want to acces its data, we load the values from the property-list into these local variables. Thus, the full information about a struct is contained in the property-list, and we can work with them quite conveniently when implementing functions.
4.8 Entries
An entry is for us the following:
struct Entry { tl description;
int points;
}
\grading_scheme_entry_new:N
\grading_scheme_entry_clear:N
\grading_scheme_entry_set_eq:NN
\grading_scheme_entry_gclear:N
\grading_scheme_entry_gset_eq:NN
Do what their signature suggests. We just forward them to the property lists.
304 \cs_set_eq:NN \grading_scheme_entry_new:N \prop_new:N
305 \cs_set_eq:NN \grading_scheme_entry_clear:N \prop_clear:N
306 \cs_set_eq:NN \grading_scheme_entry_set_eq:NN \prop_set_eq:NN
307 \cs_set_eq:NN \grading_scheme_entry_gclear:N \prop_gclear:N
308 \cs_set_eq:NN \grading_scheme_entry_gset_eq:NN \prop_gset_eq:NN
(End definition for\grading_scheme_entry_new:N and others. These functions are documented on page
??.)
\l__grading_scheme_entry_points_int
\l__grading_scheme_entry_description_tl
The mentioned local variables where we retrieve values.
309 \int_new:N \l__grading_scheme_entry_points_int
310 \tl_new:N \l__grading_scheme_entry_description_tl
(End definition for\l__grading_scheme_entry_points_intand\l__grading_scheme_entry_description_- tl.)
\grading_scheme_entry_set_description:Nn
\grading_scheme_entry_gset_description:Nn
Sets the description.
311 \cs_new:Npn \grading_scheme_entry_set_description:Nn #1 % implicit description
312 {
313 \prop_put:Nnn #1 { description }
314 }
315 \cs_new:Npn \grading_scheme_entry_gset_description:Nn #1 % implicit description
316 {
317 \prop_gput:Nnn #1 { description }
318 }
(End definition for \grading_scheme_entry_set_description:Nn and \grading_scheme_entry_gset_- description:Nn. These functions are documented on page??.)
\grading_scheme_entry_set_points:Nn
\grading_scheme_entry_gset_points:Nn
Sets the points.
319 \cs_new:Npn \grading_scheme_entry_set_points:Nn #1 #2
320 {
321 \prop_put:Nnx #1 { points } { \int_eval:n { #2 } }
322 }
323 \cs_new:Npn \grading_scheme_entry_gset_points:Nn #1 #2
324 {
325 \prop_gput:Nnn #1 { points } { \int_eval:n { #2 } }
326 }
(End definition for\grading_scheme_entry_set_points:Nnand\grading_scheme_entry_gset_points:Nn.
These functions are documented on page??.)
\grading_scheme_entry_get_description:NN Gets the description of the entry and stores it in#2. The assignment is local.
327 \cs_new:Npn \grading_scheme_entry_get_description:NN #1 %implicit #2
328 {
329 \prop_get:NnN #1 { description }
330 }
(End definition for\grading_scheme_entry_get_description:NN. This function is documented on page
??.)
\grading_scheme_entry_get_points:NN Gets the points of the entry and stores it in#2. The assignment is local.
331 \cs_new:Npn \grading_scheme_entry_get_points:NN #1 %implicit #2
332 {
333 \prop_get:NnN #1 { points }
334 }
(End definition for\grading_scheme_entry_get_points:NN. This function is documented on page??.)
\__grading_scheme_entry_load_points:N Loads the points into the local variable
335 \cs_new:Npn \__grading_scheme_entry_load_points:N #1
336 {
337 \grading_scheme_entry_get_points:NN #1 \l__grading_scheme_entry_points_int
338 }
(End definition for\__grading_scheme_entry_load_points:N.)
\__grading_scheme_entry_load_description:N Loads the description of an entry
339 \cs_new:Npn \__grading_scheme_entry_load_description:N #1
340 {
341 \grading_scheme_entry_get_description:NN #1 \l__grading_scheme_entry_description_tl
342 }
(End definition for\__grading_scheme_entry_load_description:N.)
\grading_scheme_entry_format:NnnN
\grading_scheme_entry_gformat:NnnN
\grading_scheme_entry_format:PnnN
\grading_scheme_entry_gformat:PnnN
\grading_scheme_entry_put:NnnN{⟨entry⟩}{⟨indent⟩}{⟨width⟩}{⟨tl var⟩}
Puts the formatted contents of the entry into the⟨tl var⟩. The⟨indent⟩specify how many tabs will be inserted before adding the contents. The ⟨width⟩specifies how many columns this entry will occupy. This⟨width⟩has to be at least 2.
An\\is inserted at the end of the entry.
343 \cs_new:Npn \grading_scheme_entry_format:NnnN
344 {
345 \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_right:Nx
346 \__grading_scheme_entry_format:NnnN
347 }
348 \cs_new:Npn \grading_scheme_entry_gformat:NnnN
349 {
350 \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_gput_right:Nx
351 \__grading_scheme_entry_format:NnnN
352 }
353 \cs_new:Npn \grading_scheme_entry_format:PnnN
354 {
355 \exp_args:NP \grading_scheme_entry_format:NnnN
356 }
357 \cs_new:Npn \grading_scheme_entry_gformat:PnnN
358 {
359 \exp_args:NP \grading_scheme_entry_gformat:NnnN
360 }
(End definition for\grading_scheme_entry_format:NnnN and others. These functions are documented on page??.)
\__grading_scheme_entry_format:NnnN
\__grading_scheme_entry_format:PnnN
Aux function that assumes that \__grading_scheme_tl_put_right:Nxhas been so to globally or locally putting into the token list.
361 \cs_new:Npn \__grading_scheme_entry_format:NnnN #1 #2 #3 #4
362 {
363 ⟨∗log⟩
364 \__grading_scheme_log:x
365 { Formatting ~ entry ~ ’\token_to_str:N #1’ ~ into ~ ’\token_to_str:N #4’ with }
366 \__grading_scheme_log:n { indent = ’#2’ ~ and ~ width ~ ’#3’ }
367 \prop_log:N #1
368 \__grading_scheme_log_incr:
369 ⟨/log⟩
370 \__grading_scheme_entry_assert_description:N #1 % implicitly loads value
371 \__grading_scheme_entry_assert_points:N #1 % implicitly loads value
372 \__grading_scheme_tl_put_right:Nx #4
373 {
374 \prg_replicate:nn { #2 } { & }
375 \exp_not:N \__grading_scheme_multicolumn:nnn
376 {
377 \int_eval:n { #3 -1 }
378 }
379 { l }
380 {
381 \exp_not:V \l__grading_scheme_entry_description_tl
382 }
383 &
384 \exp_not:N \__grading_scheme_points:n
385 {
386 \tl_use:N \l__grading_scheme_entry_points_int
387 }
388 \\
389 }
390 ⟨∗log⟩
391 \__grading_scheme_log_decr:
392 \__grading_scheme_log:x { / Formatting ~ entry ~ ’\token_to_str:N #1’ }
393 ⟨/log⟩
394 }
395 \cs_new:Npn \__grading_scheme_entry_forrmat:PnnN % implicit #1-4
396 {
397 \exp_args:NP \__grading_scheme_entry_format:NnnN
398 }
(End definition for\__grading_scheme_entry_format:NnnNand\__grading_scheme_entry_format:PnnN.)
\__grading_scheme_entry_assert_description:N
\__grading_scheme_entry_assert_points:N
These functions check the presence of values of an entry. If an entry is absent, an error message is omitted.
399 \cs_new:Npn \__grading_scheme_entry_assert_description:N #1
400 {
401 \__grading_scheme_entry_load_description:N #1
402 \quark_if_no_value:NT \l__grading_scheme_entry_description_tl
403 {
404 \msg_error:nnxxx { grading-scheme } { missing-value }
405 { entry } { \token_to_str:N #1 } { description }
406 }
407 }
408 \cs_new:Npn \__grading_scheme_entry_assert_points:N #1
409 {
410 \__grading_scheme_entry_load_points:N #1
411 \quark_if_no_value:NT \l__grading_scheme_entry_points_int
412 {
413 \msg_error:nnxxx { grading-scheme } { missing-value }
414 { entry } { \token_to_str:N #1 } { points }
415 }
416 }
417 \msg_new:nnn { grading-scheme } { missing-value }
418 {
419 #1 ~ ’#2’ ~ has ~ no ~ #3.
420 }
(End definition for\__grading_scheme_entry_assert_description:N and \__grading_scheme_entry_- assert_points:N.)
4.9 Blocks
4.9.1 Struct setting / reading
A⟨block⟩is for us the following:
struct Block { clist* elements;
tl text;
tl operation;
}
\grading_scheme_block_new:N
\grading_scheme_block_clear:N
\grading_scheme_block_set_eq:NN
\grading_scheme_block_gclear:N
\grading_scheme_block_gset_eq:NN
Do what thear names suggest. We just forward these to the property lists.
421 \cs_set_eq:NN \grading_scheme_block_new:N \prop_new:N
422 \cs_set_eq:NN \grading_scheme_block_clear:N \prop_clear:N
423 \cs_set_eq:NN \grading_scheme_block_set_eq:NN \prop_gset_eq:NN
424 \cs_set_eq:NN \grading_scheme_block_gclear:N \prop_gclear:N
425 \cs_set_eq:NN \grading_scheme_block_gset_eq:NN \prop_gset_eq:NN
(End definition for\grading_scheme_block_new:N and others. These functions are documented on page
??.)
\l__grading_scheme_block_elements_clist_ptr
\l__grading_scheme_block_description_tl
\l__grading_scheme_block_operation_tl
The mentioned local variables where we retrieve values.
426 \ptr_new:N \l__grading_scheme_block_elements_clist_ptr
427 \tl_new:N \l__grading_scheme_block_description_tl
428 \tl_new:N \l__grading_scheme_block_operation_tl
(End definition for\l__grading_scheme_block_elements_clist_ptr,\l__grading_scheme_block_description_- tl, and\l__grading_scheme_block_operation_tl.)
\grading_scheme_block_set_description:Nn
\grading_scheme_block_gset_description:Nn
\grading_scheme_block_set_operation_tl:Nn
\grading_scheme_block_gset_operation_tl:Nn
\grading_scheme_block_set_elements:NN
\grading_scheme_block_gset_elements:NN
\grading_scheme_block_set_elements:NP
\grading_scheme_block_gset_elements:NP
Set the description / operation or elements of the block.
When setting elements, a⟨clist var⟩is expected.
429 \cs_new:Npn \grading_scheme_block_set_description:Nn #1 % implicit description
430 {
431 \prop_put:Nnn #1 { description }
432 }
433 \cs_new:Npn \grading_scheme_block_gset_description:Nn #1 % implicit description
434 {
435 \prop_gput:Nnn #1 { description }
436 }
437 \cs_new:Npn \grading_scheme_block_set_operation:Nn #1 % implicit operation
438 {
439 \prop_put:Nnn #1 { operation }
440 }
441 \cs_new:Npn \grading_scheme_block_gset_operation:Nn #1 % implicit operation
442 {
443 \prop_gput:Nnn #1 { operation }
444 }
445 \cs_new:Npn \grading_scheme_block_set_elements:NN #1 % implicit elements clist
446 {
447 \prop_put:Nnn #1 { elements }
448 }
449 \cs_new:Npn \grading_scheme_block_gset_elements:NN #1 % implicit elements clist
450 {
451 \prop_gput:Nnn #1 { elements }
452 }
453 \cs_new:Npn \grading_scheme_block_set_elements:NP
454 {
455 \exp_args:NNP \grading_scheme_block_set_elements:NN
456 }
457 \cs_new:Npn \grading_scheme_block_gset_elements:NP
458 {
459 \exp_args:NNP \grading_scheme_block_gset_elements:NN
460 }
(End definition for\grading_scheme_block_set_description:Nn and others. These functions are doc- umented on page??.)
\grading_scheme_block_get_description:NN
\grading_scheme_block_get_operation:NN
\grading_scheme_block_get_elements:NN
\grading_scheme_block_get_description:NN⟨block var⟩⟨tl var⟩
\grading_scheme_block_get_operation:NN⟨block var⟩⟨tl var⟩
\grading_scheme_block_get_elements:NN⟨block var⟩⟨clist ptr⟩
Get access to the members of the block. The assignment is local. The returned values might be\q_no_valueif no value is present.
461 \cs_new:Npn \grading_scheme_block_get_description:NN #1 % implicit #2
462 {
463 \prop_get:NnN #1 { description }
464 }
465 \cs_new:Npn \grading_scheme_block_get_operation:NN #1 % implicit #2
466 {
467 \prop_get:NnN #1 { operation }
468 }
469 \cs_new:Npn \grading_scheme_block_get_elements:NN #1 % implicit #2
470 {
471 \prop_get:NnN #1 { elements }
472 }
(End definition for\grading_scheme_block_get_description:NN,\grading_scheme_block_get_operation:NN, and\grading_scheme_block_get_elements:NN. These functions are documented on page??.)
\__grading_scheme_block_load_description:N
\__grading_scheme_block_load_operation:N
\__grading_scheme_block_load_elements:NN
Loads the members into the corresponding local variables.
473 \cs_new:Npn \__grading_scheme_block_load_description:N #1
474 {
475 \grading_scheme_block_get_description:NN #1 \l__grading_scheme_block_description_tl
476 }
477 \cs_new:Npn \__grading_scheme_block_load_operation:N #1
478 {
479 \grading_scheme_block_get_operation:NN #1 \l__grading_scheme_block_operation_tl
480 }
481 \cs_new:Npn \__grading_scheme_block_load_elements:N #1
482 {
483 \grading_scheme_block_get_elements:NN #1 \l__grading_scheme_block_elements_clist_ptr
484 }
(End definition for\__grading_scheme_block_load_description:N,\__grading_scheme_block_load_- operation:N, and\__grading_scheme_block_load_elements:NN.)
\__grading_scheme_block_ensure_elements:N Ensures that this block has an elements attribute that is a valid clist pointer.
If no value is present, or the pointer isNULL, a pointer and/or the clist variable are created.
485 \cs_new:Npn \__grading_scheme_block_ensure_elements:N % implicit #1
486 {
487 \cs_set_eq:NN
488 \__grading_scheme_block_set_elements_optg:NP
489 \grading_scheme_block_set_elements:NP
490 \__grading_scheme_block_ensure_elements_aux:nN { l }
491 }
492 \cs_new:Npn \__grading_scheme_block_gensure_elements:N % implicit #1
493 {
494 \cs_set_eq:NN
495 \__grading_scheme_block_set_elements_optg:NP
496 \grading_scheme_block_gset_elements:NP
497 \__grading_scheme_block_ensure_elements_aux:nN { g } %i #1
498 }
499 % prefix, block
500 % assumes that \__grading_scheme_block_set_elements_optg:NP has been
501 \cs_new:Npn \__grading_scheme_block_ensure_elements_aux:nN #1 #2
502 {
503 \__grading_scheme_block_load_elements:N #2
504 \quark_if_no_value:NT \l__grading_scheme_block_elements_clist_ptr
505 {
506 \ptr_clear:Nn \l__grading_scheme_block_elements_clist_ptr { #1 }
507 \__grading_scheme_block_set_elements_optg:NP
508 #2
509 \l__grading_scheme_block_elements_clist_ptr
510 }
511 \ptr_if_null:NT \l__grading_scheme_block_elements_clist_ptr
512 {
513 \clist_new:P \l__grading_scheme_block_elements_clist_ptr
514 }
515 }
(End definition for\__grading_scheme_block_ensure_elements:N.)
\grading_scheme_block_add_element:NN
\grading_scheme_block_gadd_element:NN
\grading_scheme_block_add_element:PP
\grading_scheme_block_gadd_element:PP
\grading_scheme_block_add_element:NN⟨block var⟩⟨element var⟩
Add an element to the block.
516 \cs_new:Npn \grading_scheme_block_add_element:NN #1 % implicit element
517 {
518 \__grading_scheme_block_ensure_elements:N #1 % also loads local variable
519 \clist_put_right:Pn \l__grading_scheme_block_elements_clist_ptr
520 }
521 \cs_new:Npn \grading_scheme_block_gadd_element:NN #1 % implicit element
522 {
523 \__grading_scheme_block_gensure_elements:N #1 % also loads local variable
524 \clist_gput_right:Pn \l__grading_scheme_block_elements_clist_ptr
525 }
526 \cs_new:Npn \grading_scheme_block_add_element:PP
527 {
528 \exp_args:NPP \grading_scheme_block_add_element:NN
529 }
530 \cs_new:Npn \grading_scheme_block_gadd_element:PP
531 {
532 \exp_args:NPP \grading_scheme_block_gadd_element:NN
533 }
534 \cs_new:Npn \grading_scheme_block_add_element:PN
535 {
536 \exp_args:NP \grading_scheme_block_add_element:NN
537 }
538 \cs_new:Npn \grading_scheme_block_gadd_element:PN
539 {
540 \exp_args:NP \grading_scheme_block_gadd_element:NN
541 }
(End definition for \grading_scheme_block_add_element:NN and others. These functions are docu- mented on page??.)
4.9.2 Formatting blocks
\grading_scheme_block_format:NnnnN
\grading_scheme_block_gformat:NnnnN
\grading_scheme_block_format:PnnnN
\grading_scheme_block_gformat:PnnnN
\grading_scheme_block_format:NnnnN⟨block var⟩{⟨indent⟩}{⟨width⟩}{⟨indent first row⟩}⟨tl var⟩
Formats this block and puts the control sequence into⟨tl var⟩.
The⟨indent⟩and⟨width⟩work as in \grading_scheme_entry_format:NnnN.
⟨indent first row⟩ can be any ⟨boolean expression⟩and indicates if the first row is also indented. Set this to false to start the block in a row of the tabular that already has contents.
542 \cs_new:Npn \grading_scheme_block_format:NnnnN %implicit #1-5
543 {
544 \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_right:Nx
545 \cs_set_eq:NN \__grading_scheme_element_format_optg:NnnnN \grading_scheme_element_format:NnnnN
546 \cs_set_eq:NN \__grading_scheme_tl_set:Nn \tl_set:Nn
547 \__grading_scheme_block_format:NnnnN
548 }
549 \cs_new:Npn \grading_scheme_block_gformat:NnnnN %implicit #1-5
550 {
551 \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_gput_right:Nx
552 \cs_set_eq:NN \__grading_scheme_element_format_optg:NnnnN \grading_scheme_element_gformat:NnnnN
553 \cs_set_eq:NN \__grading_scheme_tl_set:Nn \tl_gset:Nn
554 \__grading_scheme_block_format:NnnnN
555 }
556 \cs_new:Npn \grading_scheme_block_format:PnnnN % implicit #1-5
557 {
558 \exp_args:NP
559 \grading_scheme_block_format:NnnnN
560 }
561 \cs_new:Npn \grading_scheme_block_gformat:PnnnN % implicit #1-5
562 {
563 \exp_args:NP
564 \grading_scheme_block_gformat:NnnnN
565 }
(End definition for\grading_scheme_block_format:NnnnN and others. These functions are documented on page??.)
For formatting the block, we need some local variables:
\l__grading_scheme_block_indent_bool Controls whether the \__grading_scheme_block_indent:nN macro will actually per- form an indent.
566 \bool_new:N \l__grading_scheme_block_indent_bool (End definition for\l__grading_scheme_block_indent_bool.)
\__grading_scheme_block_height_int Locally stores the height of the block to be typeset.
567 \int_new:N \l__grading_scheme_block_height_int (End definition for\__grading_scheme_block_height_int.)
\__grading_scheme_block_format:NnnnN
\__grading_scheme_block_format:PnnnN
Aux function. Assumes that\__grading_scheme__tl_put_right:Nxhas been set prop- erly.
568 \cs_new:Npn \__grading_scheme_block_format:NnnnN #1 #2 #3 #4 #5
569 {
570 ⟨∗log⟩
571 \__grading_scheme_log:x
572 {
573 Formatting ~ block ~ ’\token_to_str:N #1’ ~ into ~ ’\token_to_str:N #5’
574 ~ with ~ indent =’#2’, ~ width ~ ’#3’ ~ and ~ first ~
575 row = ’\bool_to_str:n { #4 }’
576 }
577 \prop_log:N #1
578 \__grading_scheme_block_load_elements:N #1
579 \exp_args:NP \clist_log:N \l__grading_scheme_block_elements_clist_ptr
580 \__grading_scheme_log_incr:
581 ⟨/log⟩
We need grouping here so that our indentation boolean is not messed up by recursive calls:
582 \bool_set:Nn \l__grading_scheme_block_indent_bool { #4 && \c_true_bool }
583 \group_begin:
584 \__grading_scheme_block_load_description:N #1
585 \grading_scheme_block_get_height:NN #1 \l__grading_scheme_block_height_int We now format the description of the block if a value is present.
586 \quark_if_no_value:NF \l__grading_scheme_block_description_tl
587 {
588 \__grading_scheme_block_indent:nN { #2 } #5
589 \__grading_scheme_tl_put_right:Nx #5
590 {
591 \exp_not:N \__grading_scheme_multicolumn:nnn
592 {
593 \int_eval:n { #3 }
594 }
595 { l| }
596 {
597 \exp_not:V \l__grading_scheme_block_description_tl
598 }
599 \\
600 \exp_not:N \__grading_scheme_cline:nn
601 {
602 \int_eval:n { #2 + 2 }
603 }
604 {
605 \int_eval:n { #2 + #3 }
606 }
607 }
608 }
Now, we have to format the operation of this block. This is a multirow with rotated description
609 \__grading_scheme_block_indent:nN { #2 } #5
610 \__grading_scheme_block_assert_operation:N #1
611 \__grading_scheme_tl_put_right:Nx #5
612 {
613 \exp_not:N \__grading_scheme_multirow:nnn
614 {
615 \int_eval:n { \int_use:N \l__grading_scheme_block_height_int - 1 }
616 }
617 { * }
618 {
619 \exp_not:N \__grading_scheme_rotatebox:nnn
620 { origin = c }
621 { 90 }
622 {
623 \exp_not:N \__grading_scheme_operation:n
624 {
625 \exp_not:V \l__grading_scheme_block_operation_tl
626 }
627 }
628 }
629 &
630 }
The first element of our block must not be indented:
631 \bool_set_false:N \l__grading_scheme_block_indent_bool
Now, we want to recursively typeset all elements of this block. We need a customized function for this to map over the elements.
632 \cs_set:Npn \__grading_scheme_block_format_element:N ##1
633 {
634 \__grading_scheme_element_format_optg:NnnnN
635 ##1
636 { #2 + 1 } % indent is one more that the current block
637 { #3 - 1 } % width is one less than current block
638 { \l__grading_scheme_block_indent_bool }
639 #5
This ensures that the second and all further elements will get indented:
640 \bool_set_true:N \l__grading_scheme_block_indent_bool
641 }
642 \__grading_scheme_block_ensure_elements:N #1 % load + sanitize elements
643 \clist_map_function:PN
644 \l__grading_scheme_block_elements_clist_ptr
645 \__grading_scheme_block_format_element:N
Now, we need to ’smuggle out’ the output token list of the current group.
646 \exp_args:NNNV
647 \group_end:
648 \__grading_scheme_tl_set:Nn
649 #5
650 #5
651 ⟨∗log⟩
652 \__grading_scheme_log_decr:
653 \__grading_scheme_log:x { / Formatting ~ block ~ ’\token_to_str:N #1’ }
654 ⟨/log⟩
655 }
656 \cs_new:Npn \__grading_scheme_block_format:PnnnN
657 {
658 \exp_args:NP \__grading_scheme_block_format:NnnnN
659 }
(End definition for\__grading_scheme_block_format:NnnnNand\__grading_scheme_block_format:PnnnN.)
\__grading_scheme_block_assert_operation:N Asserts that the block has an operation and loads it. If no operation is set, an error is emitted.
660 \cs_new:Npn \__grading_scheme_block_assert_operation:N #1
661 {
662 \__grading_scheme_block_load_operation:N #1
663 \quark_if_no_value:NT \l__grading_scheme_block_operation_tl
664 {
665 \msg_error:nnxxx { grading-scheme } { missing-value}
666 { block }
667 { \token_to_str:N #1 }
668 { operation }
669 }
670 }
(End definition for\__grading_scheme_block_assert_operation:N.)
\__grading_scheme_block_indent:nN \__grading_scheme_block_indent:nN{⟨indent⟩}⟨tl var⟩
Performs the indent into ⟨tl var⟩ iff \l__grading_scheme_block_indent_bool is true.
Sets\l__grading_scheme_block_indent_boolto true afterwards.
671 \cs_new:Npn \__grading_scheme_block_indent:nN #1 #2
672 {
673 \bool_if:NT \l__grading_scheme_block_indent_bool
674 {
675 \__grading_scheme_tl_put_right:Nx #2
676 {
677 \prg_replicate:nn { #1 } { & }
678 }
679 }
680 \bool_set_true:N \l__grading_scheme_block_indent_bool
681 }
(End definition for\__grading_scheme_block_indent:nN.)
4.9.3 Width and height of a block
\l__grading_scheme_height_sum_int
\l__grading_scheme_height_acc_int
Some temporary int values
682 \int_new:N \l__grading_scheme_height_sum_int
683 \int_new:N \l__grading_scheme_height_acc_int
(End definition for\l__grading_scheme_height_sum_int and\l__grading_scheme_height_acc_int.)
\grading_scheme_block_get_height:NN
\grading_scheme_block_get_height:PN
\grading_scheme_block_get_height:NN⟨block var⟩⟨int var⟩ Gets the height of a block and stores it into the⟨int var⟩.
684 \cs_new:Npn \grading_scheme_block_get_height:NN #1 #2
685 {
686 ⟨∗log⟩
687 \__grading_scheme_log:x { Getting ~ height ~ of ~ block ~ ’\token_to_str:N #1’ }
688 \__grading_scheme_log_incr:
689 ⟨/log⟩
Grouping is needed to not mess up local variables in the recursion:
690 \group_begin:
691 \__grading_scheme_block_load_elements:N #1
692 \int_zero:N \l__grading_scheme_height_sum_int
693 \clist_map_function:PN
694 \l__grading_scheme_block_elements_clist_ptr
695 \__grading_scheme_block_height_accumulator:N
696 \grading_scheme_block_if_description:NT #1
697 {
698 \int_incr:N \l__grading_scheme_height_sum_int
699 }
Smuggle out this length at return it to the caller:
700 \exp_args:NNNV
701 \group_end:
702 \int_set:Nn #2 \l__grading_scheme_height_sum_int
703 ⟨∗log⟩
704 \__grading_scheme_log_decr:
705 \__grading_scheme_log:x
706 {
707 / Getting ~ height ~ of ~ block ~ ’\token_to_str:N #1’:
708 ’\int_use:N #2’
709 }
710 ⟨/log⟩
711 }
712 \cs_new:Npn \grading_scheme_block_get_height:PN
713 {
714 \exp_args:NP \grading_scheme_block_get_height:NN
715 }
(End definition for\grading_scheme_block_get_height:NNand\grading_scheme_block_get_height:PN.
These functions are documented on page??.)
\__grading_scheme_block_height_accumulator:N This is mapped on the elements of a block and accumulates the heights.
716 \cs_new:Npn \__grading_scheme_block_height_accumulator:N #1
717 {
718 \grading_scheme_element_get_height:NN #1 \l__grading_scheme_height_acc_int
719 \int_add:Nn \l__grading_scheme_height_sum_int
720 { \int_use:N \l__grading_scheme_height_acc_int }
721 }
(End definition for\__grading_scheme_block_height_accumulator:N.)
\grading_scheme_block_if_description:NTF Tests if the given⟨block var⟩has a description set or not. Also loads this description
722 \cs_new:Npn \grading_scheme_block_if_description:NT #1 % implicit #2
723 {
724 \__grading_scheme_block_load_description:N #1
725 \quark_if_no_value:NF \l__grading_scheme_block_description_tl
726 }
727 \cs_new:Npn \grading_scheme_block_if_description:NF #1 % implicit #2
728 {
729 \__grading_scheme_block_load_description:N #1
730 \quark_if_no_value:NT \l__grading_scheme_block_description_tl
731 }
732 \cs_new:Npn \grading_scheme_block_if_description:NTF #1 #2 #3
733 {
734 \__grading_scheme_block_load_description:N #1
735 \quark_if_no_value:NTF \l__grading_scheme_block_description_tl
736 { #3 }
737 { #2 }
738 }
(End definition for\grading_scheme_block_if_description:NTF. This function is documented on page
??.)
\l__grading_scheme_max_width_int
(End definition for\l__grading_scheme_max_width_int.)
\l__grading_scheme_width_acc_int
\l__grading_scheme_max_width_int
Some temporary int values
739 \int_new:N \l__grading_scheme_max_width_int
740 \int_new:N \l__grading_scheme_width_acc_int
(End definition for\l__grading_scheme_width_acc_int and\l__grading_scheme_max_width_int.)
\grading_scheme_block_get_natural_width:NN
\grading_scheme_block_get_natural_width:PN
Gets the “natural” width of a block, that is: The minimal width of this block so that it can be typeset properly.
741 \cs_new:Npn \grading_scheme_block_get_natural_width:NN #1 #2
742 {
743 ⟨∗log⟩
744 \__grading_scheme_log:x
745 { Getting ~ natural ~ width ~ of ~ block ~ ’\token_to_str:N #1’. }
746 \__grading_scheme_log_incr:
747 ⟨/log⟩