diff options
-rw-r--r-- | Master/texmf-dist/doc/latex/grading-scheme/README.md | 27 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/grading-scheme/grading-scheme.pdf | bin | 0 -> 793342 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/latex/grading-scheme/grading-scheme.dtx | 2768 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/grading-scheme/grading-scheme.ins | 32 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/grading-scheme/grading-scheme.sty | 1143 | ||||
-rwxr-xr-x | Master/tlpkg/bin/tlpkg-ctan-check | 2 | ||||
-rwxr-xr-x | Master/tlpkg/libexec/ctan2tds | 1 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc | 1 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/grading-scheme.tlpsrc | 0 |
9 files changed, 3973 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/grading-scheme/README.md b/Master/texmf-dist/doc/latex/grading-scheme/README.md new file mode 100644 index 00000000000..fc4d708364d --- /dev/null +++ b/Master/texmf-dist/doc/latex/grading-scheme/README.md @@ -0,0 +1,27 @@ +# The grading-scheme package +Copyiright (C) 2020 Maximilian Keßler <ctan@maximilian-kessler.de> + +This matrial is subject to the LaTeX Project Public License 1.3c. +The latest version of this license is at: http://www.latex-project.org/lppl.txt + + +This bundle contains the files: + +README.md this file +grading-scheme.dtx documented LaTeX source file +grading-scheme.pdf documentation produced from the dtx file +grading-scheme.ins run to generate the package + +This work is author-maintained. + +This is version 0.1 of the package, dated 2022-02-22 + +# Description + +This package aims at an easy-to-use interface to typeset +grading schemes in tabular 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. + +It can be run with LaTeX directly. diff --git a/Master/texmf-dist/doc/latex/grading-scheme/grading-scheme.pdf b/Master/texmf-dist/doc/latex/grading-scheme/grading-scheme.pdf Binary files differnew file mode 100644 index 00000000000..7dbe25d6f27 --- /dev/null +++ b/Master/texmf-dist/doc/latex/grading-scheme/grading-scheme.pdf diff --git a/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.dtx b/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.dtx new file mode 100644 index 00000000000..a63a466573d --- /dev/null +++ b/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.dtx @@ -0,0 +1,2768 @@ +% \iffalse meta-comment +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This LaTeX docstrip file is free software and is dual-licensed % +% under the LPPLv1.3c and the GPLv3 licenses. % +% You may use it freely for your purposes. % +% The latest version of the docstrip file sources can be obtained % +% via GitLab under % +% https://gitlab.com/latexci/packages/LatexPackages % +% The latest version of the built packages can be obtained via GitLab under % +% https://gitlab.com/latexci/packages/LatexPackagesBuild % +% For further information see the urls above. % +% Reportings of bugs, suggestions and improvements are welcome, see the README % +% at the Git repository for further information. % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%<*internal> +% \begingroup +% \input docstrip.tex +% \keepsilent +% \preamble +% ___________________________________________________________ +% The grading-scheme package +% Copyright (C) 2022 Maximilian Kessler +% License information appended. +% +% \endpreamble +% \postamble +% +% Copyright 2022 Maximilian Kessler <ctan@maximilian-kessler.de> +% +% Distributable under the LaTeX Project Public License, +% version 1.3c or higher (your choice). The latest version of +% this license is at: http://www.latex-project.org/lppl.txt +% +% This work is "author-maintained" +% +% This work consists of the files grading-scheme.dtx, +% grading-scheme.ins, a README file +% and the derived files grading-scheme.sty and grading-scheme.pdf. +% +% \endpostamble +% \askforoverwritefalse +% +% \generate{\file{grading-scheme.sty}{\from{grading-scheme.dtx}{package}}} +% +% \def\tmpa{plain} +% \ifx\tmpa\fmtname\endgroup\expandafter\bye\fi +% \endgroup +%</internal> +% +%<package>\ProvidesExplPackage {grading-scheme} {2022/02/22} {bla} +%<package> {test} +% +%<*driver> +\documentclass[full]{l3doc} +\usepackage{grading-scheme} +\begin{document} +\DocInput{grading-scheme.dtx} +\end{document} +%</driver> +% \fi +% +% +% \title{The \pkg{grading-scheme} package} +% +% \author{Maximilian Keßler\thanks{ctan@maximilian-kessler.de}} +% \date{Released 2022/02/22\\ \vskip 1.5em {\small version 0.1}} +% +% \maketitle +% +% \begin{abstract} +% This package aims at an easy-to-use interface to typeset +% grading schemes in tabular 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. +% \end{abstract} +% +% \setcounter{tocdepth}{2} +% \tableofcontents +% +% \begin{documentation} +% +% \section{General notions} +% +% Probably, an example is fitting best at this point. +% If you want to set up a grading scheme, with the \pkg{grading-scheme} package +% all you have to do to get the output of \autoref{tab:grading-scheme} +% is type the following: +% +% \iffalse +% Since the docstrip format already uses the pipe character +% to denote verbatim, we actually use \entry to typeset the table. +% In a user document, one could of course use the pipe syntax again. +% \fi +% \begin{table}[tp] +% \centering +% \begin{gradingscheme}{sum} +% \entry{At least one correct solution}{1} +% \entry{All correct solutions}{1} +% \begin{block}{max} +% \begin{block}[Uniqueness proofs]{max} +% \begin{block}[First solution]{sum} +% \entry{Show that either $4 \mid p - 2$ or $3 \mid p - 4$.}{3} +% \entry{Show that $m = 5$}{2} +% \entry{Show that $ n = 4 $}{1} +% \entry{Conclude solutions}{1} +% \end{block} +% \begin{block}[Second solution]{sum} +% \entry{Show that $p$ is even}{2} +% \entry{Reduce to at most 30 candidates}{3} +% \entry{Test all candidates}{2} +% \end{block} +% \end{block} +% \begin{block}{min(2)} +% \begin{block}[Plausible Arguments]{sum} +% \entry{plausible argument that there are finitely many solutions}{1} +% \entry{suggestion that divisibility by 4 is useful}{1} +% \entry{suggesting that not both of $m$, $n$ can be 'large'.}{1} +% \end{block} +% \end{block} +% \end{block} +% \end{gradingscheme} +% \caption{Example output of a grading scheme.} +% \label{tab:grading-scheme} +% \end{table} +% +% \begin{verbatim} +% \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} +% \end{verbatim} +% +% 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 +% \autoref{tab:grading-scheme-grammar}. +% The meanings of \meta{balanced text} and \meta{number} are +% as usual. +% +% \begin{table}[htpb] +% \centering +% \begin{tabular}{r@{\;:=\;}l} +% grading scheme & block \\ +% block & [\meta{block description}], \meta{block operation}, \meta{element list} \\ +% element list & \meta{element} $\mid$ \meta{element} : \meta{element list} \\ +% element & \meta{block} $\mid$ \meta{entry} \\ +% entry & \meta{entry description}, \meta{entry points} \\ +% block description & \meta{balanced text} \\ +% block operation & \meta{balanced text} \\ +% entry description & \meta{balanced text} \\ +% entry points & \meta{number} \\ +% \end{tabular} +% \caption{Abstract grammer for a grading scheme} +% \label{tab:grading-scheme-grammar} +% \end{table} +% +% The package facilitates specifying a grading scheme according to this grammar +% and typesets these. +% +% \section{Usage} +% +% Load the package as usual by +% \begin{verbatim} +% \usepackage[pipe]{grading-scheme} +% \end{verbatim} +% +% The |pipe| option is of course optional and the only currently supported option. +% It activates the pipe syntax explained later. +% +% \begin{environment}{gradingscheme} +% \begin{syntax} +% \cs{begin}\{gradingscheme\}\oarg{description text}\Arg{operator} +% \cs{end}\{gradingscheme\} +% \end{syntax} +% 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 +% as |tabular|s, you can (and maybe should) put a grading scheme +% into a |table| environment as if it were a regular |tabular|. +% +% \begin{texnote} +% 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. +% \end{texnote} +% \end{environment} +% +% \begin{environment}{block} +% \begin{syntax} +% \cs{begin}\{block\}\oarg{description text}\Arg{operator} +% \cs{end}\{block\} +% \end{syntax} +% +% The \meta{description text} will be shown in a separate row +% on top of the block. If not specfied, no such row is inserted. +% The \meta{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. +% \end{environment} +% +% \begin{function}{\entry} +% \begin{syntax} +% \cs{entry}\Arg{entry description}\Arg{points} +% \end{syntax} +% +% Specifies an entry with given description and points. +% The entry is typeset as part of the block/grading scheme +% containing it. +% \end{function} +% +% \begin{function}{|} +% \begin{syntax} +% $\mid$ \meta{entry description} \& \meta{points} \textbackslash{}n +% \end{syntax} +% This is an alternative form to specify an entry. The |\n| +% is to be interpreted as a newline in the source file, so $\mid$ reads +% until the end of the line. +% +% This is equivalent to calling \cs{entry}\Arg{entry description}\Arg{points} +% +% The package option |pipe| has to be specified to activate this +% syntax. +% +% \begin{texnote} +% The $\mid$ 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. +% \end{texnote} +% \end{function} +% +% +% \section{\LaTeX3 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, \emph{not} considered to be stable +% yet, so if you really have to rely on this, feel free to contact +% the author. +% +% \end{documentation} +% +% +% \begin{implementation} +% +% \section{\pkg{grading-scheme} implementation} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=grading_scheme> +% \end{macrocode} +% +% \subsection{Dependencies and options} +% +% Currently, there is only one option +% +% \begin{variable}{\g_@@_pipe_syntax_bool} +% +% This will toggle the pipe syntax option of the package. +% +% \begin{macrocode} +\bool_new:N \g_@@_pipe_syntax_bool +% \end{macrocode} +% \end{variable} +% +% +% \begin{macrocode} +\keys_define:nn { grading-scheme } + { + pipe .bool_gset:N = \g_@@_pipe_syntax_bool, + pipe .default:n = { true }, + unknown .code:n = + { + \msg_error:nnn { grading-scheme } { unknown-option} { \l_keys_key_str } + } + } +\msg_new:nnn { grading-scheme } { unknown-option} + { + Unknown ~ option ~ '#1'. + } +\RequirePackage { l3keys2e } +\ProcessKeysOptions { grading-scheme } +\RequirePackage{multirow} +\RequirePackage{rotating} +% \end{macrocode} +% +% \subsection{A simple logging module} +% +% \begin{macrocode} +%<*log> +% \end{macrocode} +% +% We provide a simple log/debugging facility for this package. +% +% \begin{variable}{\g_@@_log_depth_int} +% Stores the log depth for indentation in the log file. +% \begin{macrocode} +\int_new:N \g_@@_log_depth_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_log_incr:} +% +% Increments the log depth +% +% \begin{macrocode} +\cs_new:Npn \@@_log_incr: + { + \int_gincr:N \g_@@_log_depth_int + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_log_decr:} +% +% Decrements the log depth +% +% \begin{macrocode} +\cs_new:Npn \@@_log_decr: + { + \int_gdecr:N \g_@@_log_depth_int + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_log:n, \@@_log:x} +% +% Logs to the terminal and log file using the current depth. +% +% \begin{macrocode} +\cs_new:Npn \@@_log:n #1 + { + \iow_term:x + { + [gs] \prg_replicate:nn \g_@@_log_depth_int { . . } + \exp_not:n { #1 } + } + \iow_log:x + { + [gs] \prg_replicate:nn \g_@@_log_depth_int { . . } + \exp_not:n { #1 } + } + } +\cs_generate_variant:Nn \@@_log:n { x } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +%</log> +% \end{macrocode} +% +% \subsection{Wrappers} +% +% We provide some \LaTeX3 wrappers for private usage. +% +% \begin{macro}{\@@_multicolumn:nnn} +% +% Just a wrapper around \cs{multicolumn} from \LaTeXe. +% +% \begin{macrocode} +\cs_set_eq:NN \@@_multicolumn:nnn \multicolumn +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_multirow:nnn} +% +% Just a wrapper around \cs{multirow} from \LaTeXe. +% +% \begin{macrocode} +\cs_set_eq:NN \@@_multirow:nnn \multirow +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_cline:n, \@@_cline:nn} +% +% A wrapper around \cs{cline}. +% +% The second form takes the beginning and ending +% column as separate arguments. +% +% \begin{macrocode} +\cs_set_eq:NN \@@_cline:n \cline +\cs_new:Npn \@@_cline:nn #1 #2 + { + \@@_cline:n { #1 - #2 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_hline:} +% +% Wrapper for a \cs{hline} +% +% \begin{macrocode} +\cs_set_eq:NN \@@_hline: \hline +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_rotatebox:nnn} +% +% Wrapper around rotatebox +% +% \begin{macrocode} +\cs_new:Npn \@@_rotatebox:nnn #1 %implicit #2, #3 + { + \rotatebox [ #1 ] + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{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. +% +% \begin{macro}{\@@_points:n} +% +% Prints the number of points. +% Used in the last column of the grading scheme. +% +% \begin{macrocode} +\cs_new:Npn \@@_points:n #1 + { + \textbf{ #1 ~ P. } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_operation:n} +% +% Prints an operation. +% Used in the leftmost column of a block. +% +% \begin{macrocode} +\cs_new:Npn \@@_operation:n #1 + { + { \sc #1 } + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Resources} +% +% \subsubsection{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 plain |C| code. +% +% 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 \cs{prop_new:N} essentially allocates some memory for us +% and makes our given argument a \emph{pointer} to a data structure +% that we refer to as a \enquote{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 as \emph{scopes} +% like in \texttt{C}. +% +% Considering functions now, a typical \LaTeX3 function has no return value +% (these would be functions with the |_p| predicate or |_use:| functions +% that leave contents in the input stream), +% since this is in general not desired. +% Rather, we pass pointers as a function argument and receive the desired +% \enquote{return value} as written into our given pointer (overwriting +% any prior data), which is also a common behaviour in large parts of |C|. +% +% 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 +% \cs{prop_get:NnN} or \cs{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 \emph{all} +% data structures. +% For example, a |clist| has some structure that is well-known and can be +% dealt with by the user directly. +% That is why there are also |clist| commands acceptiong |n|-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 require \emph{direct} 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 \emph{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 |struct|s that contain \emph{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 variables +% \emph{containing} pointers 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 a |void**| 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 in \autoref{subsec:pointers}. +% +% \subsection{Pointers} +% \label{subsec: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 type |P| shall indicate a single expansion +% \emph{with the assumption that this expansion will yield a single token}. +% So, from an implementation point of view, this is the same as an |o|-type +% argument, just with further restricted assumptions. +% +% This also enables us to generate |P| variant arguments from |N| variant +% macros. Compare this to the usual deprecation warning that \LaTeX3 +% gives when generating an |o| variant from an |N|-type argument: +% +% \begin{verbatim} +% ! 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. +% \end{verbatim} +% +% +% Since basically anything in \LaTeX3 is in fact a pointer, we will +% introduce the |pointer| structure with the |ptr| type (suffix) +% and actually mean that this is a |void**|. +% +% Thus, we introduce the following conventions: +% \begin{enumerate} +% \item +% A \TeX-pointer is a \TeX control sequence that represents +% some data. +% \item +% A |pointer| is a control sequence that +% expands to a single \TeX{} control sequence that is a +% \TeX-pointer. +% \item +% The \emph{name} of a |pointer| is the name of the control sequence +% representing it. +% Thus, such a name always ends with |_ptr| by convetion. +% \item +% A |ptr| is said to be |NULL| if its expansion yields an undefined +% \TeX{} control sequence. +% We also refer to this as a |nullptr|. +% \item +% A \emph{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 is |NULL|. +% \item +% A \emph{void pointer} shall be a pointer whose actual type is unknown. +% \item +% When a |ptr| is of type |type|, we denote these by the suffix +% |_type_ptr|. +% \item +% \emph{Dereferencing} a pointer amounts to expanding it exactly once. +% \item +% A |P|-type argument accepts a single token that has to be of type |ptr|. +% The token is expanded exactly once and then treated as an |N|-type argument +% in the corresponding function. +% \end{enumerate} +% +% +% \begin{variable}{\g__ptr_counter_int} +% +% Counts the number of pointers given by \cs{ptr_new:N}. +% This ensures that each pointer can have a unique name +% regardless of grouping. +% +% \begin{macrocode} +\int_new:N \g__ptr_counter_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l__ptr_var_prefix_str} +% +% Stores the prefix of new pointer variables. +% +% \begin{macrocode} +\str_new:N \l__ptr_var_prefix_str +% \end{macrocode} +% \end{variable} +% +% +% +% \begin{macro}{\ptr_new:N} +% \begin{syntax} +% \cs{ptr_new:N}\meta{pointer} +% \end{syntax} +% +% Gives a new unique pointer that is |NULL|. +% Gives an error when the \meta{pointer} already exists. +% The pointer variable is created globally. +% +% \begin{macrocode} +\cs_new:Npn \ptr_new:N #1 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \ptr_new:NVn #1 \l__ptr_var_prefix_str { any } + } +\cs_new:Npn \ptr_new:Nn #1 #2 + { + \ptr_new:Nnn { #1 } { #2 } { any } + } +% ptr var, prefix, type +\cs_new:Npn \ptr_new:Nnn #1 #2 %i #3 + { + \str_case:nnT + { #2 } + { + { l } { } + { g } { } + } + { + \tl_new:N #1 + } + \__ptr_init:Nnn #1 { #2 } %i { #3 } + } +\cs_generate_variant:Nn \ptr_new:Nnn { N V n } +% ptr var, prefix, type +% assumes that the pointer name exists already in case of l or g prefix +\cs_new:Npn \__ptr_init:Nnn #1 #2 % implicit #3 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \str_case:VnF + \l__ptr_var_prefix_str + { + { l } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_set:Nx + } + { g } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_gset:Nx + } + { c } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_const:Nx + } + } + { + \str_show:N \l__ptr_var_prefix_str % TODO: show error + } + \__ptr_init_aux:Nnn #1 { #2 } + } +\cs_generate_variant:Nn \__ptr_init:Nnn { N V n } +% ptr var, prefix, type. assumes poly_tl_set:Nx has been set +\cs_new:Npn \__ptr_init_aux:Nnn #1 #2 #3 + { + \__ptr_poly_tl_set:Nx #1 + { + \exp_not:c + { + #2 + __ptr__unique__ + \int_use:N \g__ptr_counter_int + _ + #3 + } + } + \int_gincr:N \g__ptr_counter_int + } +\cs_generate_variant:Nn \__ptr_init:Nnn { N V n } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\__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 of |c|, |l| or |g| by +% usual naming conventions. +% +% \begin{macrocode} +\cs_new:Npn \__ptr_get_var_prefix:NN #1 #2 + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } l + { + \str_set:Nn #2 { l } + } + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } g + { + \str_set:Nn #2 { g } + } + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } c + { + \str_set:Nn #2 { c } + } + { + \msg_error:nnx { ptr } { variable-name-illegal-prefix } + { + \token_to_str:N #1 + } + } + } + } + } +% \end{macrocode} +% \begin{macrocode} + \msg_new:nnnn { ptr } { variable-name-illegal-prefix } + { + Requested ~ new ~ pointer ~ '#1' ~ has ~ illegal ~ prefix. + } + { + Prefix ~ should ~ be ~ one ~ of ~ 'l', ~ 'g' ~ or ~ 'c'. + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\ptr_clear:N} +% +% Clears this pointer. +% This makes the pointer equivalent to a new |nullptr|. +% +% \begin{macrocode} +\cs_new:Npn \ptr_clear:N #1 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \__ptr_init:NVn #1 \l__ptr_var_prefix_str { any } + } +\cs_new:Npn \ptr_clear:Nn #1 #2 + { + \__ptr_init:Nnn #1 { #2 } { any } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ptr_set:NN} +% +% Sets the pointer to represent the given argument. +% +% \begin{macrocode} +\cs_set_eq:NN \ptr_set:NN \tl_set:Nn +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ptr_set_eq:NN} +% +% Accepts two pointers. +% The first is set to be equivalent to the second. +% +% \begin{macrocode} +\cs_set_eq:NN \ptr_set_eq:NN \tl_set_eq:NN +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ptr_use:N} +% +% Uses the pointer, i.e.~expands to the stored \TeX{}-pointer. +% +% \begin{macrocode} +\cs_set_eq:NN \ptr_use:N \tl_use:N +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__ptr_check:N} +% +% Checks that the given argument is a pointer. +% +% \begin{macrocode} +\cs_new:Npn \__ptr_check:N #1 + { + \tl_if_single:NF #1 + { + \msg_error:nnx { ptr } { is-not-a-pointer } + { + \token_to_str:N #1 + } + } + } +% \end{macrocode} +% \begin{macrocode} +\msg_new:nnn { ptr } { is-not-a-pointer } + { + The ~ control ~ sequence ~ '#1' ~ is ~ not ~ a ~ valid ~ pointer. + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__ptr_check:NN} +% +% Checks that the second argument is a pointer. +% +% \begin{macrocode} +\cs_new:Npn \__ptr_check:NN #1 #2 + { + \__ptr_check:N #2 + #1 #2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__ptr_check:nN} +% +% Checks that the second argument is a pointer. +% +% \begin{macrocode} +\cs_new:Npn \__ptr_check:nN #1 #2 + { + \__ptr_check:N #2 + { #1 } #2 + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{variable}{\l__ptr_content_tl} +% +% Stores the (internal) \TeX-pointer +% of a |pointer|. +% +% \begin{macrocode} +\tl_new:N \l__ptr_content_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\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. +% +% \begin{macrocode} +\cs_new:Npn \exp_args:NP #1 #2 + { + \__ptr_check:N #2 + \exp_last_unbraced:No #1 #2 + } +\cs_new:Npn \exp_args:NNP #1 #2 #3 + { + \__ptr_check:N #3 + \exp_last_unbraced:NNo #1 #2 #3 + } +\cs_new:Npn \exp_args:NNNP #1 #2 #3 #4 + { + \__ptr_check:N #4 + \exp_last_unbraced:NNNo #1 #2 #3 #4 + } +\cs_new:Npn \exp_args:NNNNP #1 #2 #3 #4 #5 + { + \__ptr_check:N #5 + \exp_last_unbraced:NNNNo #1 #2 #3 #4 #5 + } +\cs_new:Npn \exp_args:NPP #1 #2 #3 + { + \__ptr_check:N #2 + \__ptr_check:N #3 + \exp_last_two_unbraced:Noo #1 #2 #3 + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}[TF]{\ptr_if_null:N} +% +% Checkes if the pointer is |NULL|. +% +% \begin{macrocode} +\cs_new:Npn \ptr_if_null:NT + { + \exp_args:NP \cs_if_exist:NF + } +\cs_new:Npn \ptr_if_null:NF + { + \exp_args:NP \cs_if_exist:NT + } +\cs_new:Npn \ptr_if_null:NTF #1 #2 #3 + { + \exp_args:NP \cs_if_exist:NTF #1 { #3 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\tl_set_eq:NP, \tl_set_eq:PN, \tl_set_eq:PP, \tl_use:P} +% \begin{macro}{\exp_not:P} +% \begin{macro}{\clist_new:P, \clist_put_right:Pn, \clist_gput_right:Pn, \clist_map_function:PN, \prop_show:P, \clist_show:P} +% +% +% Just variants of \cs{tl_set_eq:NN} with indicated signature. +% +% \begin{macrocode} +\cs_new:Npn \tl_set_eq:NP + { + \exp_args:NNP \tl_set_eq:NN + } +\cs_new:Npn \tl_set_eq:PN + { + \exp_args:NP \tl_set_eq:NN + } +\cs_new:Npn \tl_set_eq:PP + { + \exp_args:NPP \tl_set_eq:NN + } +\cs_new:Npn \tl_use:P + { + \exp_args:NP \tl_use:N + } +\cs_new:Npn \exp_not:P + { + \exp_args:NP\exp_not:N + } +\cs_new:Npn \clist_new:P + { + \exp_args:NP \clist_new:N + } +\cs_new:Npn \clist_show:P + { + \exp_args:NP \clist_show:N + } +\cs_new:Npn \clist_put_right:Pn + { + \exp_args:NP \clist_put_right:Nn + } +\cs_new:Npn \clist_gput_right:Pn + { + \exp_args:NP \clist_gput_right:Nn + } +\cs_new:Npn \clist_map_function:PN + { + \exp_args:NP \clist_map_function:NN + } +\cs_new:Npn \prop_show:P + { + \exp_args:NP \prop_show:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% \begin{macro}{\ptr_show:N} +% +% Shows information about this pointer, +% namely: +% +% If it is |NULL|, then it indicates this. +% If it is not |NULL|, then the \TeX-pointer +% and the contained contents of the \TeX-pointer +% (in unexpanded form) are shown. +% +% \begin{macrocode} +\cs_new:Npn \ptr_show:N #1 + { + \__ptr_check:N #1 + \ptr_if_null:NTF #1 + { + \tl_show:x + { + \token_to_str:N #1 -> \exp_not:P #1 = NULL + } + } + { + \tl_show:x + { + \token_to_str:N #1 -> \exp_not:P #1 -> \exp_args:NP \exp_not:V #1 + } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Structs} +% +% We will model |C|-style |struct|s 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 each +% |struct| member. 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. +% +% +% \subsection{Entries} +% +% An entry is for us the following: +% +% \begin{verbatim} +% struct Entry { +% tl description; +% int points; +% } +% \end{verbatim} +% +% \begin{macro}{\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. +% +% \begin{macrocode} +\cs_set_eq:NN \grading_scheme_entry_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_entry_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_entry_set_eq:NN \prop_set_eq:NN +\cs_set_eq:NN \grading_scheme_entry_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_entry_gset_eq:NN \prop_gset_eq:NN +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_entry_points_int, \l_@@_entry_description_tl} +% +% The mentioned local variables where we retrieve values. +% +% \begin{macrocode} +\int_new:N \l_@@_entry_points_int +\tl_new:N \l_@@_entry_description_tl +% \end{macrocode} +% \end{variable} +% +% +% \begin{macro}{\grading_scheme_entry_set_description:Nn, \grading_scheme_entry_gset_description:Nn} +% +% Sets the description. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_set_description:Nn #1 % implicit description + { + \prop_put:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_entry_gset_description:Nn #1 % implicit description + { + \prop_gput:Nnn #1 { description } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\grading_scheme_entry_set_points:Nn, \grading_scheme_entry_gset_points:Nn} +% +% Sets the points. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_set_points:Nn #1 #2 + { + \prop_put:Nnx #1 { points } { \int_eval:n { #2 } } + } +\cs_new:Npn \grading_scheme_entry_gset_points:Nn #1 #2 + { + \prop_gput:Nnn #1 { points } { \int_eval:n { #2 } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_entry_get_description:NN} +% +% Gets the description of the entry and stores it in |#2|. +% The assignment is local. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_get_description:NN #1 %implicit #2 + { + \prop_get:NnN #1 { description } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_entry_get_points:NN} +% +% Gets the points of the entry and stores it in |#2|. +% The assignment is local. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_get_points:NN #1 %implicit #2 + { + \prop_get:NnN #1 { points } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_entry_load_points:N} +% +% Loads the points into the local variable +% +% \begin{macrocode} +\cs_new:Npn \@@_entry_load_points:N #1 + { + \grading_scheme_entry_get_points:NN #1 \l_@@_entry_points_int + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_entry_load_description:N} +% +% Loads the description of an entry +% +% \begin{macrocode} +\cs_new:Npn \@@_entry_load_description:N #1 + { + \grading_scheme_entry_get_description:NN #1 \l@@_entry_description_tl + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\grading_scheme_entry_format:NnnN, \grading_scheme_entry_gformat:NnnN,\grading_scheme_entry_format:PnnN, \grading_scheme_entry_gformat:PnnN} +% \begin{syntax} +% \cs{grading_scheme_entry_put:NnnN}\Arg{entry}\Arg{indent}\Arg{width}\Arg{tl var} +% \end{syntax} +% +% Puts the formatted contents of the entry into the \meta{tl var}. +% The \meta{indent} specify how many tabs will be inserted +% before adding the contents. +% The \meta{width} specifies how many columns this entry will occupy. +% This \meta{width} has to be at least 2. +% +% An |\\| is inserted at the end of the entry. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_format:NnnN + { + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_put_right:Nx + \@@_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_gformat:NnnN + { + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_gput_right:Nx + \@@_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_format:PnnN + { + \exp_args:NP \grading_scheme_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_gformat:PnnN + { + \exp_args:NP \grading_scheme_entry_gformat:NnnN + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_entry_format:NnnN, \@@_entry_format:PnnN} +% +% Aux function that assumes that \cs{@@_tl_put_right:Nx} +% has been so to globally or locally putting into the token list. +% +% \begin{macrocode} +\cs_new:Npn \@@_entry_format:NnnN #1 #2 #3 #4 + { +%<*log> + \@@_log:x + { Formatting ~ entry ~ '\token_to_str:N #1' ~ into ~ '\token_to_str:N #4' with } + \@@_log:n { indent = '#2' ~ and ~ width ~ '#3' } + \prop_log:N #1 + \@@_log_incr: +%</log> + \@@_entry_assert_description:N #1 % implicitly loads value + \@@_entry_assert_points:N #1 % implicitly loads value + \@@_tl_put_right:Nx #4 + { + \prg_replicate:nn { #2 } { & } + \exp_not:N \@@_multicolumn:nnn + { + \int_eval:n { #3 -1 } + } + { l } + { + \exp_not:V \l_@@_entry_description_tl + } + & + \exp_not:N \@@_points:n + { + \tl_use:N \l_@@_entry_points_int + } + \\ + } +%<*log> + \@@_log_decr: + \@@_log:x { / Formatting ~ entry ~ '\token_to_str:N #1' } +%</log> + } +\cs_new:Npn \@@_entry_forrmat:PnnN % implicit #1-4 + { + \exp_args:NP \@@_entry_format:NnnN + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_entry_assert_description:N, \@@_entry_assert_points:N} +% +% These functions check the presence of values of an entry. +% If an entry is absent, an error message is omitted. +% +% \begin{macrocode} +\cs_new:Npn \@@_entry_assert_description:N #1 + { + \@@_entry_load_description:N #1 + \quark_if_no_value:NT \l_@@_entry_description_tl + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { entry } { \token_to_str:N #1 } { description } + } + } +\cs_new:Npn \@@_entry_assert_points:N #1 + { + \@@_entry_load_points:N #1 + \quark_if_no_value:NT \l_@@_entry_points_int + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { entry } { \token_to_str:N #1 } { points } + } + } +\msg_new:nnn { grading-scheme } { missing-value } + { + #1 ~ '#2' ~ has ~ no ~ #3. + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Blocks} +% +% \subsubsection{Struct setting / reading} +% +% A \meta{block} is for us the following: +% +% \begin{verbatim} +% struct Block { +% clist* elements; +% tl text; +% tl operation; +% } +% \end{verbatim} +% +% \begin{macro}{\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. +% +% \begin{macrocode} +\cs_set_eq:NN \grading_scheme_block_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_block_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_block_set_eq:NN \prop_gset_eq:NN +\cs_set_eq:NN \grading_scheme_block_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_block_gset_eq:NN \prop_gset_eq:NN +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_block_elements_clist_ptr, \l_@@_block_description_tl, \l_@@_block_operation_tl} +% +% The mentioned local variables where we retrieve values. +% +% \begin{macrocode} +\ptr_new:N \l_@@_block_elements_clist_ptr +\tl_new:N \l_@@_block_description_tl +\tl_new:N \l_@@_block_operation_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \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 \meta{clist var} is expected. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_set_description:Nn #1 % implicit description + { + \prop_put:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_block_gset_description:Nn #1 % implicit description + { + \prop_gput:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_block_set_operation:Nn #1 % implicit operation + { + \prop_put:Nnn #1 { operation } + } +\cs_new:Npn \grading_scheme_block_gset_operation:Nn #1 % implicit operation + { + \prop_gput:Nnn #1 { operation } + } +\cs_new:Npn \grading_scheme_block_set_elements:NN #1 % implicit elements clist + { + \prop_put:Nnn #1 { elements } + } +\cs_new:Npn \grading_scheme_block_gset_elements:NN #1 % implicit elements clist + { + \prop_gput:Nnn #1 { elements } + } +\cs_new:Npn \grading_scheme_block_set_elements:NP + { + \exp_args:NNP \grading_scheme_block_set_elements:NN + } +\cs_new:Npn \grading_scheme_block_gset_elements:NP + { + \exp_args:NNP \grading_scheme_block_gset_elements:NN + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_block_get_description:NN, \grading_scheme_block_get_operation:NN, \grading_scheme_block_get_elements:NN} +% +% \begin{syntax} +% \cs{grading_scheme_block_get_description:NN}\meta{block var}\meta{tl var} +% \cs{grading_scheme_block_get_operation:NN}\meta{block var}\meta{tl var} +% \cs{grading_scheme_block_get_elements:NN}\meta{block var}\meta{clist ptr} +% \end{syntax} +% +% Get access to the members of the block. +% The assignment is local. +% The returned values might be \cs{q_no_value} +% if no value is present. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_get_description:NN #1 % implicit #2 + { + \prop_get:NnN #1 { description } + } +\cs_new:Npn \grading_scheme_block_get_operation:NN #1 % implicit #2 + { + \prop_get:NnN #1 { operation } + } +\cs_new:Npn \grading_scheme_block_get_elements:NN #1 % implicit #2 + { + \prop_get:NnN #1 { elements } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_block_load_description:N, \@@_block_load_operation:N, \@@_block_load_elements:NN} +% +% Loads the members into the corresponding local variables. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_load_description:N #1 + { + \grading_scheme_block_get_description:NN #1 \l_@@_block_description_tl + } +\cs_new:Npn \@@_block_load_operation:N #1 + { + \grading_scheme_block_get_operation:NN #1 \l_@@_block_operation_tl + } +\cs_new:Npn \@@_block_load_elements:N #1 + { + \grading_scheme_block_get_elements:NN #1 \l_@@_block_elements_clist_ptr + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_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 is |NULL|, +% a pointer and/or the clist variable +% are created. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_ensure_elements:N % implicit #1 + { + \cs_set_eq:NN + \@@_block_set_elements_optg:NP + \grading_scheme_block_set_elements:NP + \@@_block_ensure_elements_aux:nN { l } + } +\cs_new:Npn \@@_block_gensure_elements:N % implicit #1 + { + \cs_set_eq:NN + \@@_block_set_elements_optg:NP + \grading_scheme_block_gset_elements:NP + \@@_block_ensure_elements_aux:nN { g } %i #1 + } +% prefix, block +% assumes that \@@_block_set_elements_optg:NP has been +\cs_new:Npn \@@_block_ensure_elements_aux:nN #1 #2 + { + \@@_block_load_elements:N #2 + \quark_if_no_value:NT \l_@@_block_elements_clist_ptr + { + \ptr_clear:Nn \l_@@_block_elements_clist_ptr { #1 } + \@@_block_set_elements_optg:NP + #2 + \l_@@_block_elements_clist_ptr + } + \ptr_if_null:NT \l_@@_block_elements_clist_ptr + { + \clist_new:P \l_@@_block_elements_clist_ptr + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\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:PN, \grading_scheme_block_gadd_element:PN} +% \begin{syntax} +% \cs{grading_scheme_block_add_element:NN}\meta{block var}\meta{element var} +% \end{syntax} +% +% Add an element to the block. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_add_element:NN #1 % implicit element + { + \@@_block_ensure_elements:N #1 % also loads local variable + \clist_put_right:Pn \l_@@_block_elements_clist_ptr + } +\cs_new:Npn \grading_scheme_block_gadd_element:NN #1 % implicit element + { + \@@_block_gensure_elements:N #1 % also loads local variable + \clist_gput_right:Pn \l_@@_block_elements_clist_ptr + } +\cs_new:Npn \grading_scheme_block_add_element:PP + { + \exp_args:NPP \grading_scheme_block_add_element:NN + } +\cs_new:Npn \grading_scheme_block_gadd_element:PP + { + \exp_args:NPP \grading_scheme_block_gadd_element:NN + } +\cs_new:Npn \grading_scheme_block_add_element:PN + { + \exp_args:NP \grading_scheme_block_add_element:NN + } +\cs_new:Npn \grading_scheme_block_gadd_element:PN + { + \exp_args:NP \grading_scheme_block_gadd_element:NN + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Formatting blocks} +% +% +% \begin{macro}{\grading_scheme_block_format:NnnnN, \grading_scheme_block_gformat:NnnnN, \grading_scheme_block_format:PnnnN, \grading_scheme_block_gformat:PnnnN} +% +% \begin{syntax} +% \cs{grading_scheme_block_format:NnnnN}\meta{block var}\Arg{indent}\Arg{width}\Arg{indent first row}\meta{tl var} +% \end{syntax} +% +% Formats this block and puts the control sequence into \meta{tl var}. +% +% The \meta{indent} and \meta{width} work as in \cs{grading_scheme_entry_format:NnnN}. +% +% \meta{indent first row} can be any \meta{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. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_format:NnnnN %implicit #1-5 + { + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_put_right:Nx + \cs_set_eq:NN \@@_element_format_optg:NnnnN \grading_scheme_element_format:NnnnN + \cs_set_eq:NN \@@_tl_set:Nn \tl_set:Nn + \@@_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_gformat:NnnnN %implicit #1-5 + { + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_gput_right:Nx + \cs_set_eq:NN \@@_element_format_optg:NnnnN \grading_scheme_element_gformat:NnnnN + \cs_set_eq:NN \@@_tl_set:Nn \tl_gset:Nn + \@@_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_format:PnnnN % implicit #1-5 + { + \exp_args:NP + \grading_scheme_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_gformat:PnnnN % implicit #1-5 + { + \exp_args:NP + \grading_scheme_block_gformat:NnnnN + } +% \end{macrocode} +% \end{macro} +% +% +% For formatting the block, we need some local variables: +% +% +% \begin{variable}{\l_@@_block_indent_bool} +% +% Controls whether the \cs{@@_block_indent:nN} macro +% will actually perform an indent. +% +% \begin{macrocode} +\bool_new:N \l_@@_block_indent_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\@@_block_height_int} +% +% Locally stores the height of the block to be typeset. +% +% \begin{macrocode} +\int_new:N \l_@@_block_height_int +% \end{macrocode} +% \end{variable} +% +% +% +% \begin{macro}{\@@_block_format:NnnnN, \@@_block_format:PnnnN} +% +% Aux function. +% Assumes that \cs{@@__tl_put_right:Nx} +% has been set properly. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_format:NnnnN #1 #2 #3 #4 #5 + { +%<*log> + \@@_log:x + { + Formatting ~ block ~ '\token_to_str:N #1' ~ into ~ '\token_to_str:N #5' + ~ with ~ indent ='#2', ~ width ~ '#3' ~ and ~ first ~ + row = '\bool_to_str:n { #4 }' + } + \prop_log:N #1 + \@@_block_load_elements:N #1 + \exp_args:NP \clist_log:N \l_@@_block_elements_clist_ptr + \@@_log_incr: +%</log> +% \end{macrocode} +% We need grouping here so that our indentation boolean +% is not messed up by recursive calls: +% \begin{macrocode} + \bool_set:Nn \l_@@_block_indent_bool { #4 && \c_true_bool } + \group_begin: + \@@_block_load_description:N #1 + \grading_scheme_block_get_height:NN #1 \l_@@_block_height_int +% \end{macrocode} +% We now format the description of the block if a value is present. +% \begin{macrocode} + \quark_if_no_value:NF \l_@@_block_description_tl + { + \@@_block_indent:nN { #2 } #5 + \@@_tl_put_right:Nx #5 + { + \exp_not:N \@@_multicolumn:nnn + { + \int_eval:n { #3 } + } + { |l| } + { + \exp_not:V \l_@@_block_description_tl + } + \\ + \exp_not:N \@@_cline:nn + { + \int_eval:n { #2 + 2 } + } + { + \int_eval:n { #2 + #3 } + } + } + } +% \end{macrocode} +% Now, we have to format the operation of this block. +% This is a multirow with rotated description +% \begin{macrocode} + \@@_block_indent:nN { #2 } #5 + \@@_block_assert_operation:N #1 + \@@_tl_put_right:Nx #5 + { + \exp_not:N \@@_multirow:nnn + { + \int_eval:n { \int_use:N \l_@@_block_height_int - 1 } + } + { * } + { + \exp_not:N \@@_rotatebox:nnn + { origin = c } + { 90 } + { + \exp_not:N \@@_operation:n + { + \exp_not:V \l_@@_block_operation_tl + } + } + } + & + } +% \end{macrocode} +% The first element of our block must not be indented: +% \begin{macrocode} + \bool_set_false:N \l_@@_block_indent_bool +% \end{macrocode} +% Now, we want to recursively typeset all elements of this block. +% We need a customized function for this to map over the elements. +% \begin{macrocode} + \cs_set:Npn \@@_block_format_element:N ##1 + { + \@@_element_format_optg:NnnnN + ##1 + { #2 + 1 } % indent is one more that the current block + { #3 - 1 } % width is one less than current block + { \l_@@_block_indent_bool } + #5 +% \end{macrocode} +% This ensures that the second and all further elements will get indented: +% \begin{macrocode} + \bool_set_true:N \l_@@_block_indent_bool + } + \@@_block_ensure_elements:N #1 % load + sanitize elements + \clist_map_function:PN + \l_@@_block_elements_clist_ptr + \@@_block_format_element:N +% \end{macrocode} +% Now, we need to 'smuggle out' the output token list of the current group. +% \begin{macrocode} + \exp_args:NNNV + \group_end: + \@@_tl_set:Nn + #5 + #5 +%<*log> + \@@_log_decr: + \@@_log:x { / Formatting ~ block ~ '\token_to_str:N #1' } +%</log> + } +\cs_new:Npn \@@_block_format:PnnnN + { + \exp_args:NP \@@_block_format:NnnnN + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_block_assert_operation:N} +% +% Asserts that the block has an operation +% and loads it. +% If no operation is set, +% an error is emitted. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_assert_operation:N #1 + { + \@@_block_load_operation:N #1 + \quark_if_no_value:NT \l_@@_block_operation_tl + { + \msg_error:nnxxx { grading-scheme } { missing-value} + { block } + { \token_to_str:N #1 } + { operation } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_block_indent:nN} +% \begin{syntax} +% \cs{@@_block_indent:nN}\Arg{indent}\meta{tl var} +% \end{syntax} +% +% Performs the indent into \meta{tl var} +% iff \cs{l_@@_block_indent_bool} is true. +% +% Sets \cs{l_@@_block_indent_bool} to true afterwards. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_indent:nN #1 #2 + { + \bool_if:NT \l_@@_block_indent_bool + { + \@@_tl_put_right:Nx #2 + { + \prg_replicate:nn { #1 } { & } + } + } + \bool_set_true:N \l_@@_block_indent_bool + } +% \end{macrocode} +% \end{macro} +% +% +% \subsubsection{Width and height of a block} +% +% \begin{variable}{\l_@@_height_sum_int, \l_@@_height_acc_int} +% +% Some temporary int values +% +% \begin{macrocode} +\int_new:N \l_@@_height_sum_int +\int_new:N \l_@@_height_acc_int +% \end{macrocode} +% \end{variable} +% +% +% \begin{macro}{\grading_scheme_block_get_height:NN, \grading_scheme_block_get_height:PN} +% \begin{syntax} +% \cs{grading_scheme_block_get_height:NN}\meta{block var}\meta{int var} +% \end{syntax} +% +% Gets the height of a block and stores +% it into the \meta{int var}. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_get_height:NN #1 #2 +{ +%<*log> + \@@_log:x { Getting ~ height ~ of ~ block ~ '\token_to_str:N #1' } + \@@_log_incr: +%</log> +% \end{macrocode} +% Grouping is needed to not mess up local variables in the recursion: +% \begin{macrocode} + \group_begin: + \@@_block_load_elements:N #1 + \int_zero:N \l_@@_height_sum_int + \clist_map_function:PN + \l_@@_block_elements_clist_ptr + \@@_block_height_accumulator:N + \grading_scheme_block_if_description:NT #1 + { + \int_incr:N \l_@@_height_sum_int + } +% \end{macrocode} +% Smuggle out this length at return it to the caller: +% \begin{macrocode} + \exp_args:NNNV + \group_end: + \int_set:Nn #2 \l_@@_height_sum_int +%<*log> + \@@_log_decr: + \@@_log:x + { + / Getting ~ height ~ of ~ block ~ '\token_to_str:N #1': + '\int_use:N #2' + } +%</log> +} +\cs_new:Npn \grading_scheme_block_get_height:PN + { + \exp_args:NP \grading_scheme_block_get_height:NN + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_block_height_accumulator:N} +% +% This is mapped on the elements of a block +% and accumulates the heights. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_height_accumulator:N #1 + { + \grading_scheme_element_get_height:NN #1 \l_@@_height_acc_int + \int_add:Nn \l_@@_height_sum_int + { \int_use:N \l_@@_height_acc_int } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\grading_scheme_block_if_description:N} +% +% Tests if the given \meta{block var} has a description +% set or not. +% Also loads this description +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_if_description:NT #1 % implicit #2 + { + \@@_block_load_description:N #1 + \quark_if_no_value:NF \l_@@_block_description_tl + } +\cs_new:Npn \grading_scheme_block_if_description:NF #1 % implicit #2 + { + \@@_block_load_description:N #1 + \quark_if_no_value:NT \l_@@_block_description_tl + } +\cs_new:Npn \grading_scheme_block_if_description:NTF #1 #2 #3 + { + \@@_block_load_description:N #1 + \quark_if_no_value:NTF \l_@@_block_description_tl + { #3 } + { #2 } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{variable}{\l_@@_max_width_int} +% +% \begin{macrocode} +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_width_acc_int,\l_@@_max_width_int} +% +% Some temporary int values +% +% \begin{macrocode} +\int_new:N \l_@@_max_width_int +\int_new:N \l_@@_width_acc_int +% \end{macrocode} +% \end{variable} +% +% +% +% +% \begin{macro}{\grading_scheme_block_get_natural_width:NN,\grading_scheme_block_get_natural_width:PN} +% +% Gets the \enquote{natural} width of a block, +% that is: The minimal width of this block so +% that it can be typeset properly. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_get_natural_width:NN #1 #2 + { +%<*log> + \@@_log:x + { Getting ~ natural ~ width ~ of ~ block ~ '\token_to_str:N #1'. } + \@@_log_incr: +%</log> + \group_begin: + \@@_block_load_elements:N #1 + \int_zero:N \l_@@_max_width_int + \clist_map_function:PN + \l_@@_block_elements_clist_ptr + \@@_block_width_accumulator:N + \int_incr:N \l_@@_max_width_int + \exp_args:NNNV + \group_end: + \int_set:Nn #2 \l_@@_max_width_int +%<*log> + \@@_log_decr: + \@@_log:x + { / Getting ~ natural ~ width ~ of ~ block ~ '\token_to_str:N #1'. } +%</log> + } +\cs_new:Npn \grading_scheme_block_get_natural_width:PN + { + \exp_args:NP \grading_scheme_block_get_natural_width:NN + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_block_width_accumulator:N} +% +% Gets the natural width of subelements +% and accumulates the maximum of them. +% +% \begin{macrocode} +\cs_new:Npn \@@_block_width_accumulator:N #1 + { +%<*log> + \@@_log:x { Accumulating ~ width ~ of ~ '\token_to_str:N #1' } + \@@_log_incr: +%</log> + \grading_scheme_element_get_natural_width:NN #1 \l_@@_width_acc_int + \int_set:Nn \l_@@_max_width_int + { + \int_max:nn + \l_@@_width_acc_int + \l_@@_max_width_int + } +%<*log> + \@@_log_decr: + \@@_log:x { / Accumulationg ~ width ~ of ~ '\token_to_str:N #1' } +%</log> + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Elements} +% +% As discussed earlier, an \meta{element} is either a \meta{block} +% or an \meta{entry}. +% Thus, our natural representation is as follows: +% +% \begin{verbatim} +% struct Element { +% void* content; +% tl type; +% } +% \end{verbatim} +% +% which essentially just implements a |union| that knows of its current +% member. +% +% +% \begin{macro}{\@@_element_new:N, \@@_element_clear:N, \@@_element_set_eq:NN, \@@_element_gclear:N, \@@_element_gset_eq:NN} +% +% Do what these say. Forward to the underlying property lists. +% +% \begin{macrocode} +\cs_set_eq:NN \grading_scheme_element_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_element_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_element_set_eq:NN \prop_set_eq:NN +\cs_set_eq:NN \grading_scheme_element_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_element_gset_eq:NN \prop_gset_eq:NN +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_element_content_void_ptr, \l_@@_element_type_str} +% +% Mentioned local variables. +% +% \begin{macrocode} +\ptr_new:N \l_@@_element_content_void_ptr +\str_new:N \l_@@_element_type_str +% \end{macrocode} +% \end{variable} +% +% +% \begin{macro}{\grading_scheme_element_set_block:NN, \grading_scheme_element_gset_block:NN, \grading_scheme_element_set_entry:NN, \grading_scheme_element_gset_entry:NN} +% \begin{syntax} +% \cs{grading_scheme_element_set_block:NN} \meta{element var}\meta{block var} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_set_block:NN #1 % implicit #2 + { + \prop_put:Nnn #1 { type } { block } + \prop_put:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_gset_block:NN #1 % implicit #2 + { + \prop_gput:Nnn #1 { type } { block } + \prop_gput:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_set_entry:NN #1 % implicit #2 + { + \prop_put:Nnn #1 { type } { entry } + \prop_put:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_gset_entry:NN #1 % implicit #2 + { + \prop_gput:Nnn #1 { type } { entry } + \prop_gput:Nnn #1 { content } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_element_get_content:NN, \grading_scheme_element_get_type:NN} +% \begin{syntax} +% \cs{grading_scheme_element_get_content:NN} \meta{element var}\meta{void ptr} +% \cs{grading_scheme_element_get_type:NN} \meta{element var}\meta{str var} +% \end{syntax} +% +% Get the contents. The assignment is local. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_get_content:NN #1 % implicit #2 + { + \prop_get:NnN #1 { content } + } +\cs_new:Npn \grading_scheme_element_get_type:NN #1 % implicit #2 + { + \prop_get:NnN #1 { type } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_element_load_content:N, \@@_element_load_type:NN} +% +% Loads the element into the local variables. +% +% \begin{macrocode} +\cs_new:Npn \@@_element_load_content:N #1 + { + \grading_scheme_element_get_content:NN #1 \l_@@_element_content_void_ptr + } +\cs_new:Npn \@@_element_load_type:N #1 + { + \grading_scheme_element_get_type:NN #1 \l_@@_element_type_str + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[noTF]{\grading_scheme_element_cases:Nnn} +% \begin{syntax} +% \cs{grading_scheme_element_cases}\meta{element var}\Arg{entry code}\Arg{block code} +% \end{syntax} +% +% Distinguishes between the +% cases of the element type. +% +% Also loads the element type. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_cases:Nnn % implicit #1-3 + { + \cs_set_eq:NN \@@_str_case:Vnw \str_case:Vn + \@@_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnT % implicit #1-4 + { + \cs_set_eq:NN \@@_str_case:Vnw \str_case:VnT + \@@_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnF % implicit #1-4 + { + \cs_set_eq:NN \@@_str_case:Vnw \str_case:VnF + \@@_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnTF % implicit #1-5 + { + \cs_set_eq:NN \@@_str_case:Vnw \str_case:VnTF + \@@_element_cases:Nnnw + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_element_cases:Nnnw} +% +% This assumes that \cs{@@_str_case:Vnw} +% has been set to a \cs{str_case:VnTF} +% variant and uses this variant for +% switching the type cases. +% +% \begin{macrocode} +\cs_new:Npn \@@_element_cases:Nnnw #1 #2 #3 % implicit branches + { + \@@_element_load_type:N #1 + \@@_str_case:Vnw \l_@@_element_type_str + { + { entry } { #2 } + { block } { #3 } + } + % implicit branches + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_element_format:NnnnN, \grading_scheme_element_gformat:NnnnN, \grading_scheme_element_format:PnnnN, \grading_scheme_element_gformat:PnnnN} +% +% Same syntax as \cs{grading_scheme_block_format:NnnnN}. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_format:NnnnN % implicit #1-5 + { + \cs_set_eq:NN \@@_entry_format_aux:PnnN \grading_scheme_entry_format:PnnN + \cs_set_eq:NN \@@_block_format_aux:PnnnN \grading_scheme_block_format:PnnnN + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_put_right:Nx + \@@_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_gformat:NnnnN % implicit #1-5 + { + \cs_set_eq:NN \@@_entry_format_aux:PnnN \grading_scheme_entry_gformat:PnnN + \cs_set_eq:NN \@@_block_format_aux:PnnnN \grading_scheme_block_gformat:PnnnN + \cs_set_eq:NN \@@_tl_put_right:Nx \tl_put_gright:Nx + \@@_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_format:PnnnN % implicit #1-5 + { + \exp_args:NP \grading_scheme_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_gformat:PnnnN % implicit #1-5 + { + \exp_args:NP \grading_scheme_element_gformat:NnnnN + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_element_format:NnnnN, \@@_element_format:PnnnN} +% +% Aux function. +% +% \begin{macrocode} +\cs_new:Npn \@@_element_format:NnnnN #1 #2 #3 #4 #5 + { +%<*log> + \@@_log:x + { + Formatting ~ element ~ '\token_to_str:N #1' ~ into ~ '\token_to_str:N #5'. + } + \@@_log_incr: + \prop_log:N #1 +%</log> + \@@_element_load_content:N #1 + \grading_scheme_element_cases:NnnF #1 + { + \bool_if:nTF { #4 } + { + \@@_entry_format_aux:PnnN + \l_@@_element_content_void_ptr + { #2 } + { #3 } + #5 + } + { + \@@_entry_format_aux:PnnN + \l_@@_element_content_void_ptr + { 0 } + { #3 } + #5 + } + } + { + \@@_block_format_aux:PnnnN + \l_@@_element_content_void_ptr + { #2 } + { #3 } + { #4 } + #5 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + \@@_tl_put_right:Nx #5 + { + \exp_not:N \@@_cline:nn + { + \int_eval:n { #2 +1 } + } + { + \int_eval:n { #2 + #3 } + } + } +%<*log> + \@@_log_decr: + \@@_log:x { Done typesetting ~ element ~ '\token_to_str:N #1' } +%</log> + } +\cs_new:Npn \@@_element_format:PnnnN % implicit #1-5 + { + \exp_args:NP \@@_element_format:NnnnN + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\grading_scheme_element_get_height:NN, \grading_scheme_element_get_height:PN} +% +% Get the the height of an element. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_get_height:NN #1 #2 + { + \grading_scheme_element_cases:NnnF #1 + { + \int_set:Nn #2 { 1 } + } + { + \@@_element_load_content:N #1 + \grading_scheme_block_get_height:PN + \l_@@_element_content_void_ptr + #2 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + } +\cs_new:Npn \grading_scheme_element_get_height:PN + { + \exp_args:NP \grading_scheme_element_get_height:NN + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_element_get_natural_width:NN, \grading_scheme_element_get_natural_width:PN} +% +% Get the natural width of an element +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_get_natural_width:NN #1 #2 + { + \grading_scheme_element_cases:NnnF #1 + { + \int_set:Nn { #2 } { 2 } + } + { + \@@_element_load_content:N #1 + \grading_scheme_block_get_natural_width:PN + \l_@@_element_content_void_ptr + #2 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + } +\cs_new:Npn \grading_scheme_element_get_natural_width:PN + { + \exp_args:NP \grading_scheme_element_get_natural_width:NN + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{variable}{\l_@@_width_int} +% +% Local int vars for typesetting. +% +% \begin{macrocode} +\int_new:N \l_@@_width_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_table_tl} +% +% Token list where we will build the table. +% +% \begin{macrocode} +\tl_new:N \g_@@_table_tl +% \end{macrocode} +% \end{variable} +% +% +% +% +% \begin{macro}{\grading_scheme_element_typeset:N, \grading_scheme_element_typeset:P} +% +% Typesets this element as a tabular and inserts this into the output stream. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_typeset:N #1 + { + \grading_scheme_element_get_natural_width:NN #1 \l_@@_width_int + \tl_gclear:N \g_@@_table_tl + \tl_gput_right:Nn \g_@@_table_tl + { + \begin{tabular} + } + \tl_gput_right:Nx \g_@@_table_tl + { + { + \prg_replicate:nn { \l_@@_width_int -1 } { |l } + | l | + } + \exp_not:N \@@_hline: + } + \grading_scheme_element_gformat:NnnnN + #1 + { 0 } + { \l_@@_width_int } + { \c_false_bool } + \g_@@_table_tl + \tl_gput_right:Nn \g_@@_table_tl + { + \end{tabular} + } + \group_begin: + \tl_set:Nn \arraystretch { 1.5 } + \tl_use:N \g_@@_table_tl + \group_end: + } +\cs_new:Npn \grading_scheme_element_typeset:P + { + \exp_args:NP \grading_scheme_element_typeset:N + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Facilities for populating data structures} +% +% TODO: what about global / local assignments here? +% +% +% \begin{macro}{\grading_scheme_entry_new:Nnn, \grading_scheme_entry_new:Pnn} +% \begin{syntax} +% \cs{grading_scheme_entry_new:Nnn}\meta{entry var}\Arg{description}\Arg{points} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_entry_new:Nnn #1 #2 % implcit #3 + { + \grading_scheme_entry_new:N #1 + \grading_scheme_entry_gset_description:Nn #1 { #2 } + \grading_scheme_entry_gset_points:Nn #1 + } +\cs_new:Npn \grading_scheme_entry_new:Pnn + { + \exp_args:NP \grading_scheme_entry_new:Nnn + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_block_new:Nnn, \grading_scheme_block_new:Pnn} +% \begin{syntax} +% \cs{grading_scheme_block_new:Nnn}\meta{block var}\Arg{description}\Arg{operation} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_new:Nnn #1 #2 % implicit #3 + { + \grading_scheme_block_new:N #1 + \grading_scheme_block_gset_description:Nn #1 { #2 } + \grading_scheme_block_gset_operation:Nn #1 + } +\cs_new:Npn \grading_scheme_block_new:Pnn + { + \exp_args:NP \grading_scheme_block_new:Nnn + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_block_new:Nn, \grading_scheme_block_new:Pn} +% \begin{syntax} +% \cs{grading_scheme_block_new:Nn}\meta{block var}\Arg{operation} +% \end{syntax} +% +% Same as above, but no description provided. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_block_new:Nn #1 % implicit #2 + { + \grading_scheme_block_new:N #1 + \grading_scheme_block_gset_operation:Nn #1 + } +\cs_new:Npn \grading_scheme_block_new:Pn + { + \exp_args:NP \grading_scheme_block_new:Nn + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_element_from_entry_new:NN, \grading_scheme_element_from_entry_new:NP, \grading_scheme_element_from_entry_new:PP, +% \grading_scheme_element_gfrom_entry_new:NN, \grading_scheme_element_gfrom_entry_new:NP, \grading_scheme_element_gfrom_entry_new:PP} +% \begin{syntax} +% \cs{grading_scheme_element_from_entry_new:NN}\meta{element var}\meta{entry var} +% \end{syntax} +% +% wraps the entry into a new element. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_from_entry_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_set_entry:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_from_entry_new:NP + { + \exp_args:NP \grading_scheme_element_from_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_from_entry_new:PP + { + \exp_args:NPP \grading_scheme_element_from_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_gset_entry:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:NP + { + \exp_args:NP \grading_scheme_element_gfrom_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:PP + { + \exp_args:NPP \grading_scheme_element_gfrom_entry_new:NN + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\grading_scheme_element_from_block_new:NN, \grading_scheme_element_from_block_new:NP, \grading_scheme_element_from_block_new:NP, +% \grading_scheme_element_gfrom_block_new:NN, \grading_scheme_element_from_gblock_new:NP, \grading_scheme_element_gfrom_block_new:NP} +% \begin{syntax} +% \cs{grading_scheme_element_from_block_new:NN}\meta{element var}\meta{block var} +% \end{syntax} +% +% wraps the block into a new element. +% +% \begin{macrocode} +\cs_new:Npn \grading_scheme_element_from_block_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_set_block:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_from_block_new:NP + { + \exp_args:NP \grading_scheme_element_from_block_new:NN + } +\cs_new:Npn \grading_scheme_element_from_block_new:PP + { + \exp_args:NPP \grading_scheme_element_from_block_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_gset_block:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:NP + { + \exp_args:NP \grading_scheme_element_gfrom_block_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:PP + { + \exp_args:NPP \grading_scheme_element_gfrom_block_new:NN + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Grading scheme environment} +% +% When building a grading scheme, +% we introduce a \cs{g_@@_curr_block_ptr} +% that is a pointer to the current block +% that is being populated. +% +% Block environments and entries will create +% new blocks/entries and add themselves to +% the block pointed out by \cs{g_@@_curr_block_ptr} +% +% +% \begin{variable}{\l_@@_entry_ptr, \l_@@_element_ptr, \l_@@_curr_block_ptr} +% +% \begin{macrocode} +\ptr_new:Nn \l_@@_entry_ptr { g } +\ptr_new:Nn \l_@@_element_ptr { g } +\ptr_new:Nn \l_@@_curr_block_ptr { g } +% \end{macrocode} +% \end{variable} +% +% +% +% \begin{macro}{\@@_entry:nn} +% +% Creates an entry in the current block. +% +% \begin{macrocode} +\cs_new:Npn \@@_entry:nn #1 #2 + { + \ptr_clear:Nn \l_@@_entry_ptr { g } + \ptr_clear:Nn \l_@@_element_ptr { g } + \grading_scheme_entry_new:Pnn + \l_@@_entry_ptr + { #1 } + { #2 } + \grading_scheme_element_gfrom_entry_new:PP + \l_@@_element_ptr + \l_@@_entry_ptr + \grading_scheme_block_gadd_element:PP + \l_@@_curr_block_ptr + \l_@@_element_ptr + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_block_begin:nn, \@@_block_begin:n, \@@_block_end:} +% +% +% +% \begin{macrocode} +\cs_new:Npn \@@_block_begin:nn % implicit #1, #2 + { + \ptr_clear:Nn \l_@@_curr_block_ptr { g } + \grading_scheme_block_new:Pnn \l_@@_curr_block_ptr + } +\cs_new:Npn \@@_block_begin:n % implicit #1 + { + \ptr_clear:Nn \l_@@_curr_block_ptr { g } + \grading_scheme_block_new:Pn \l_@@_curr_block_ptr + } +\cs_new:Npn \@@_block_end: + { + \ptr_clear:Nn \l_@@_element_ptr { g } + \grading_scheme_element_gfrom_block_new:PP + \l_@@_element_ptr + \l_@@_curr_block_ptr + \cs_gset:Npx \@@_after_group: + { + \exp_not:N \grading_scheme_block_gadd_element:PN + \exp_not:N \l_@@_curr_block_ptr + \exp_not:P \l_@@_element_ptr + } + \group_insert_after:N \@@_after_group: + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\entry} +% +% +% +% \begin{macrocode} +\NewDocumentCommand \entry { m m } + { + \@@_entry:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{block} +% +% \begin{macrocode} +\NewDocumentEnvironment { block } { o m } + { + \IfValueTF { #1 } + { + \@@_block_begin:nn { #1 } { #2 } + } + { + \@@_block_begin:n { #2 } + } + } + { + \@@_block_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{gradingscheme} +% +% +% +% \begin{macrocode} +\NewDocumentEnvironment {gradingscheme} { o m } + { + \bool_if:NT \g_@@_pipe_syntax_bool + { + \char_set_active_eq:NN | \@@_entry_oneline:w + \char_set_catcode_active:N | + } + \IfValueTF { #1 } + { + \@@_block_begin:nn { #1 } { #2 } + } + { + \@@_block_begin:n { #2 } + } + } + { + \ptr_clear:Nn \l_@@_element_ptr { g } + \grading_scheme_element_gfrom_block_new:PP + \l_@@_element_ptr + \l_@@_curr_block_ptr + \grading_scheme_element_typeset:P \l_@@_element_ptr + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Implementing the pipe syntax} +% +% Everything left is conditional on the pipe option having been specified: +% \begin{macrocode} +\bool_if:NF \g_@@_pipe_syntax_bool + { + \endinput + } +% \end{macrocode} +% +% +% In order to offer syntax based on $\mid$, we make $\mid$ an active character +% that will read until the end of the line, split at the |@| character, +% and pass this on to a \cs{@@_entry:nn} +% +% \begin{macro}{\s_@@_endline} +% +% A scan mark that will denote the end of the line +% for us. +% +% \begin{macrocode} +\scan_new:N \s_@@_endline +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_parse_entry:w} +% \begin{syntax} +% \cs{@@_parse_entry:w} \meta{description} \& \meta{points} \cs{s_endline} +% \end{syntax} +% +% Creates a new entry based on our scan mark. +% +% \begin{macrocode} +\cs_new:Npn \@@_parse_entry:w #1 & #2 \s_endline + { + \@@_entry:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_replace_newline:w, \@@_replace_newline_aux:w} +% +% Calling \cs{@@_replace_newline:w} +% replaces the next occurence of a newline character with +% \cs{s_@@_endline}. +% +% This is done by briefly switching category codes. +% +% \begin{macrocode} +\cs_new:Npn \@@_replace_newline:w + { + \group_begin: + \char_set_catcode_active:N\^^M + \@@_replace_newline_aux:w + } +% \end{macrocode} +% +% We need to briefly make the newline character an active character +% in this source file so that pattern matching works correctly. +% \begin{macrocode} +\char_set_catcode_active:N\^^M +\cs_new:Npn \@@_replace_newline_aux:w #1 ^^M + { + \group_end: + #1 \s_endline + } +\char_set_catcode_end_line:N\^^M +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_entry_oneline:w} +% +% Parses a one-line entry. +% +% \begin{macrocode} +\cs_new:Npn \@@_entry_oneline:w + { + \@@_replace_newline:w + \@@_parse_entry:w + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex +% diff --git a/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.ins b/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.ins new file mode 100644 index 00000000000..e67d3353669 --- /dev/null +++ b/Master/texmf-dist/source/latex/grading-scheme/grading-scheme.ins @@ -0,0 +1,32 @@ +\begingroup +\input docstrip.tex +\keepsilent +\preamble + ___________________________________________________________ + The grading-scheme package + Copyright (C) 2022 Maximilian Kessler + License information appended. + +\endpreamble +\postamble + +Copyright 2022 Maximilian Kessler <ctan@maximilian-kessler.de> + +Distributable under the LaTeX Project Public License, +version 1.3c or higher (your choice). The latest version of +this license is at: http://www.latex-project.org/lppl.txt + +This work is "author-maintained" + +This work consists of the files grading-scheme.dtx, grading-scheme.ins, +a README file +and the derived files grading-scheme.sty and grading-scheme.pdf. + +\endpostamble +\askforoverwritefalse + +\generate{\file{grading-scheme.sty}{\from{grading-scheme.dtx}{package}}} + +\def\tmpa{plain} +\ifx\tmpa\fmtname\endgroup\expandafter\bye\fi +\endgroup diff --git a/Master/texmf-dist/tex/latex/grading-scheme/grading-scheme.sty b/Master/texmf-dist/tex/latex/grading-scheme/grading-scheme.sty new file mode 100644 index 00000000000..2ee191440cc --- /dev/null +++ b/Master/texmf-dist/tex/latex/grading-scheme/grading-scheme.sty @@ -0,0 +1,1143 @@ +%% +%% This is file `grading-scheme.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% grading-scheme.dtx (with options: `package') +%% ___________________________________________________________ +%% The grading-scheme package +%% Copyright (C) 2022 Maximilian Kessler +%% License information appended. +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\ProvidesExplPackage {grading-scheme} {2022/02/22} {bla} + {test} +\bool_new:N \g__grading_scheme_pipe_syntax_bool +\keys_define:nn { grading-scheme } + { + pipe .bool_gset:N = \g__grading_scheme_pipe_syntax_bool, + pipe .default:n = { true }, + unknown .code:n = + { + \msg_error:nnn { grading-scheme } { unknown-option} { \l_keys_key_str } + } + } +\msg_new:nnn { grading-scheme } { unknown-option} + { + Unknown ~ option ~ '#1'. + } +\RequirePackage { l3keys2e } +\ProcessKeysOptions { grading-scheme } +\RequirePackage{multirow} +\RequirePackage{rotating} +\cs_set_eq:NN \__grading_scheme_multicolumn:nnn \multicolumn +\cs_set_eq:NN \__grading_scheme_multirow:nnn \multirow +\cs_set_eq:NN \__grading_scheme_cline:n \cline +\cs_new:Npn \__grading_scheme_cline:nn #1 #2 + { + \__grading_scheme_cline:n { #1 - #2 } + } +\cs_set_eq:NN \__grading_scheme_hline: \hline +\cs_new:Npn \__grading_scheme_rotatebox:nnn #1 %implicit #2, #3 + { + \rotatebox [ #1 ] + } +\cs_new:Npn \__grading_scheme_points:n #1 + { + \textbf{ #1 ~ P. } + } +\cs_new:Npn \__grading_scheme_operation:n #1 + { + { \sc #1 } + } +\int_new:N \g__ptr_counter_int +\str_new:N \l__ptr_var_prefix_str +\cs_new:Npn \ptr_new:N #1 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \ptr_new:NVn #1 \l__ptr_var_prefix_str { any } + } +\cs_new:Npn \ptr_new:Nn #1 #2 + { + \ptr_new:Nnn { #1 } { #2 } { any } + } +\cs_new:Npn \ptr_new:Nnn #1 #2 %i #3 + { + \str_case:nnT + { #2 } + { + { l } { } + { g } { } + } + { + \tl_new:N #1 + } + \__ptr_init:Nnn #1 { #2 } %i { #3 } + } +\cs_generate_variant:Nn \ptr_new:Nnn { N V n } +\cs_new:Npn \__ptr_init:Nnn #1 #2 % implicit #3 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \str_case:VnF + \l__ptr_var_prefix_str + { + { l } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_set:Nx + } + { g } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_gset:Nx + } + { c } + { + \cs_set_eq:NN \__ptr_poly_tl_set:Nx \tl_const:Nx + } + } + { + \str_show:N \l__ptr_var_prefix_str % TODO: show error + } + \__ptr_init_aux:Nnn #1 { #2 } + } +\cs_generate_variant:Nn \__ptr_init:Nnn { N V n } +\cs_new:Npn \__ptr_init_aux:Nnn #1 #2 #3 + { + \__ptr_poly_tl_set:Nx #1 + { + \exp_not:c + { + #2 + __ptr__unique__ + \int_use:N \g__ptr_counter_int + _ + #3 + } + } + \int_gincr:N \g__ptr_counter_int + } +\cs_generate_variant:Nn \__ptr_init:Nnn { N V n } +\cs_new:Npn \__ptr_get_var_prefix:NN #1 #2 + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } l + { + \str_set:Nn #2 { l } + } + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } g + { + \str_set:Nn #2 { g } + } + { + \tl_if_head_eq_charcode:fNTF { \cs_to_str:N #1 } c + { + \str_set:Nn #2 { c } + } + { + \msg_error:nnx { ptr } { variable-name-illegal-prefix } + { + \token_to_str:N #1 + } + } + } + } + } + \msg_new:nnnn { ptr } { variable-name-illegal-prefix } + { + Requested ~ new ~ pointer ~ '#1' ~ has ~ illegal ~ prefix. + } + { + Prefix ~ should ~ be ~ one ~ of ~ 'l', ~ 'g' ~ or ~ 'c'. + } +\cs_new:Npn \ptr_clear:N #1 + { + \__ptr_get_var_prefix:NN #1 \l__ptr_var_prefix_str + \__ptr_init:NVn #1 \l__ptr_var_prefix_str { any } + } +\cs_new:Npn \ptr_clear:Nn #1 #2 + { + \__ptr_init:Nnn #1 { #2 } { any } + } +\cs_set_eq:NN \ptr_set:NN \tl_set:Nn +\cs_set_eq:NN \ptr_set_eq:NN \tl_set_eq:NN +\cs_set_eq:NN \ptr_use:N \tl_use:N +\cs_new:Npn \__ptr_check:N #1 + { + \tl_if_single:NF #1 + { + \msg_error:nnx { ptr } { is-not-a-pointer } + { + \token_to_str:N #1 + } + } + } +\msg_new:nnn { ptr } { is-not-a-pointer } + { + The ~ control ~ sequence ~ '#1' ~ is ~ not ~ a ~ valid ~ pointer. + } +\cs_new:Npn \__ptr_check:NN #1 #2 + { + \__ptr_check:N #2 + #1 #2 + } +\cs_new:Npn \__ptr_check:nN #1 #2 + { + \__ptr_check:N #2 + { #1 } #2 + } +\tl_new:N \l__ptr_content_tl +\cs_new:Npn \exp_args:NP #1 #2 + { + \__ptr_check:N #2 + \exp_last_unbraced:No #1 #2 + } +\cs_new:Npn \exp_args:NNP #1 #2 #3 + { + \__ptr_check:N #3 + \exp_last_unbraced:NNo #1 #2 #3 + } +\cs_new:Npn \exp_args:NNNP #1 #2 #3 #4 + { + \__ptr_check:N #4 + \exp_last_unbraced:NNNo #1 #2 #3 #4 + } +\cs_new:Npn \exp_args:NNNNP #1 #2 #3 #4 #5 + { + \__ptr_check:N #5 + \exp_last_unbraced:NNNNo #1 #2 #3 #4 #5 + } +\cs_new:Npn \exp_args:NPP #1 #2 #3 + { + \__ptr_check:N #2 + \__ptr_check:N #3 + \exp_last_two_unbraced:Noo #1 #2 #3 + } +\cs_new:Npn \ptr_if_null:NT + { + \exp_args:NP \cs_if_exist:NF + } +\cs_new:Npn \ptr_if_null:NF + { + \exp_args:NP \cs_if_exist:NT + } +\cs_new:Npn \ptr_if_null:NTF #1 #2 #3 + { + \exp_args:NP \cs_if_exist:NTF #1 { #3 } { #2 } + } +\cs_new:Npn \tl_set_eq:NP + { + \exp_args:NNP \tl_set_eq:NN + } +\cs_new:Npn \tl_set_eq:PN + { + \exp_args:NP \tl_set_eq:NN + } +\cs_new:Npn \tl_set_eq:PP + { + \exp_args:NPP \tl_set_eq:NN + } +\cs_new:Npn \tl_use:P + { + \exp_args:NP \tl_use:N + } +\cs_new:Npn \exp_not:P + { + \exp_args:NP\exp_not:N + } +\cs_new:Npn \clist_new:P + { + \exp_args:NP \clist_new:N + } +\cs_new:Npn \clist_show:P + { + \exp_args:NP \clist_show:N + } +\cs_new:Npn \clist_put_right:Pn + { + \exp_args:NP \clist_put_right:Nn + } +\cs_new:Npn \clist_gput_right:Pn + { + \exp_args:NP \clist_gput_right:Nn + } +\cs_new:Npn \clist_map_function:PN + { + \exp_args:NP \clist_map_function:NN + } +\cs_new:Npn \prop_show:P + { + \exp_args:NP \prop_show:N + } +\cs_new:Npn \ptr_show:N #1 + { + \__ptr_check:N #1 + \ptr_if_null:NTF #1 + { + \tl_show:x + { + \token_to_str:N #1 -> \exp_not:P #1 = NULL + } + } + { + \tl_show:x + { + \token_to_str:N #1 -> \exp_not:P #1 -> \exp_args:NP \exp_not:V #1 + } + } + } +\cs_set_eq:NN \grading_scheme_entry_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_entry_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_entry_set_eq:NN \prop_set_eq:NN +\cs_set_eq:NN \grading_scheme_entry_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_entry_gset_eq:NN \prop_gset_eq:NN +\int_new:N \l__grading_scheme_entry_points_int +\tl_new:N \l__grading_scheme_entry_description_tl +\cs_new:Npn \grading_scheme_entry_set_description:Nn #1 % implicit description + { + \prop_put:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_entry_gset_description:Nn #1 % implicit description + { + \prop_gput:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_entry_set_points:Nn #1 #2 + { + \prop_put:Nnx #1 { points } { \int_eval:n { #2 } } + } +\cs_new:Npn \grading_scheme_entry_gset_points:Nn #1 #2 + { + \prop_gput:Nnn #1 { points } { \int_eval:n { #2 } } + } +\cs_new:Npn \grading_scheme_entry_get_description:NN #1 %implicit #2 + { + \prop_get:NnN #1 { description } + } +\cs_new:Npn \grading_scheme_entry_get_points:NN #1 %implicit #2 + { + \prop_get:NnN #1 { points } + } +\cs_new:Npn \__grading_scheme_entry_load_points:N #1 + { + \grading_scheme_entry_get_points:NN #1 \l__grading_scheme_entry_points_int + } +\cs_new:Npn \__grading_scheme_entry_load_description:N #1 + { + \grading_scheme_entry_get_description:NN #1 \l__grading_scheme_entry_description_tl + } +\cs_new:Npn \grading_scheme_entry_format:NnnN + { + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_right:Nx + \__grading_scheme_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_gformat:NnnN + { + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_gput_right:Nx + \__grading_scheme_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_format:PnnN + { + \exp_args:NP \grading_scheme_entry_format:NnnN + } +\cs_new:Npn \grading_scheme_entry_gformat:PnnN + { + \exp_args:NP \grading_scheme_entry_gformat:NnnN + } +\cs_new:Npn \__grading_scheme_entry_format:NnnN #1 #2 #3 #4 + { + \__grading_scheme_entry_assert_description:N #1 % implicitly loads value + \__grading_scheme_entry_assert_points:N #1 % implicitly loads value + \__grading_scheme_tl_put_right:Nx #4 + { + \prg_replicate:nn { #2 } { & } + \exp_not:N \__grading_scheme_multicolumn:nnn + { + \int_eval:n { #3 -1 } + } + { l } + { + \exp_not:V \l__grading_scheme_entry_description_tl + } + & + \exp_not:N \__grading_scheme_points:n + { + \tl_use:N \l__grading_scheme_entry_points_int + } + \\ + } + } +\cs_new:Npn \__grading_scheme_entry_forrmat:PnnN % implicit #1-4 + { + \exp_args:NP \__grading_scheme_entry_format:NnnN + } +\cs_new:Npn \__grading_scheme_entry_assert_description:N #1 + { + \__grading_scheme_entry_load_description:N #1 + \quark_if_no_value:NT \l__grading_scheme_entry_description_tl + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { entry } { \token_to_str:N #1 } { description } + } + } +\cs_new:Npn \__grading_scheme_entry_assert_points:N #1 + { + \__grading_scheme_entry_load_points:N #1 + \quark_if_no_value:NT \l__grading_scheme_entry_points_int + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { entry } { \token_to_str:N #1 } { points } + } + } +\msg_new:nnn { grading-scheme } { missing-value } + { + #1 ~ '#2' ~ has ~ no ~ #3. + } +\cs_set_eq:NN \grading_scheme_block_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_block_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_block_set_eq:NN \prop_gset_eq:NN +\cs_set_eq:NN \grading_scheme_block_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_block_gset_eq:NN \prop_gset_eq:NN +\ptr_new:N \l__grading_scheme_block_elements_clist_ptr +\tl_new:N \l__grading_scheme_block_description_tl +\tl_new:N \l__grading_scheme_block_operation_tl +\cs_new:Npn \grading_scheme_block_set_description:Nn #1 % implicit description + { + \prop_put:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_block_gset_description:Nn #1 % implicit description + { + \prop_gput:Nnn #1 { description } + } +\cs_new:Npn \grading_scheme_block_set_operation:Nn #1 % implicit operation + { + \prop_put:Nnn #1 { operation } + } +\cs_new:Npn \grading_scheme_block_gset_operation:Nn #1 % implicit operation + { + \prop_gput:Nnn #1 { operation } + } +\cs_new:Npn \grading_scheme_block_set_elements:NN #1 % implicit elements clist + { + \prop_put:Nnn #1 { elements } + } +\cs_new:Npn \grading_scheme_block_gset_elements:NN #1 % implicit elements clist + { + \prop_gput:Nnn #1 { elements } + } +\cs_new:Npn \grading_scheme_block_set_elements:NP + { + \exp_args:NNP \grading_scheme_block_set_elements:NN + } +\cs_new:Npn \grading_scheme_block_gset_elements:NP + { + \exp_args:NNP \grading_scheme_block_gset_elements:NN + } +\cs_new:Npn \grading_scheme_block_get_description:NN #1 % implicit #2 + { + \prop_get:NnN #1 { description } + } +\cs_new:Npn \grading_scheme_block_get_operation:NN #1 % implicit #2 + { + \prop_get:NnN #1 { operation } + } +\cs_new:Npn \grading_scheme_block_get_elements:NN #1 % implicit #2 + { + \prop_get:NnN #1 { elements } + } +\cs_new:Npn \__grading_scheme_block_load_description:N #1 + { + \grading_scheme_block_get_description:NN #1 \l__grading_scheme_block_description_tl + } +\cs_new:Npn \__grading_scheme_block_load_operation:N #1 + { + \grading_scheme_block_get_operation:NN #1 \l__grading_scheme_block_operation_tl + } +\cs_new:Npn \__grading_scheme_block_load_elements:N #1 + { + \grading_scheme_block_get_elements:NN #1 \l__grading_scheme_block_elements_clist_ptr + } +\cs_new:Npn \__grading_scheme_block_ensure_elements:N % implicit #1 + { + \cs_set_eq:NN + \__grading_scheme_block_set_elements_optg:NP + \grading_scheme_block_set_elements:NP + \__grading_scheme_block_ensure_elements_aux:nN { l } + } +\cs_new:Npn \__grading_scheme_block_gensure_elements:N % implicit #1 + { + \cs_set_eq:NN + \__grading_scheme_block_set_elements_optg:NP + \grading_scheme_block_gset_elements:NP + \__grading_scheme_block_ensure_elements_aux:nN { g } %i #1 + } +\cs_new:Npn \__grading_scheme_block_ensure_elements_aux:nN #1 #2 + { + \__grading_scheme_block_load_elements:N #2 + \quark_if_no_value:NT \l__grading_scheme_block_elements_clist_ptr + { + \ptr_clear:Nn \l__grading_scheme_block_elements_clist_ptr { #1 } + \__grading_scheme_block_set_elements_optg:NP + #2 + \l__grading_scheme_block_elements_clist_ptr + } + \ptr_if_null:NT \l__grading_scheme_block_elements_clist_ptr + { + \clist_new:P \l__grading_scheme_block_elements_clist_ptr + } + } +\cs_new:Npn \grading_scheme_block_add_element:NN #1 % implicit element + { + \__grading_scheme_block_ensure_elements:N #1 % also loads local variable + \clist_put_right:Pn \l__grading_scheme_block_elements_clist_ptr + } +\cs_new:Npn \grading_scheme_block_gadd_element:NN #1 % implicit element + { + \__grading_scheme_block_gensure_elements:N #1 % also loads local variable + \clist_gput_right:Pn \l__grading_scheme_block_elements_clist_ptr + } +\cs_new:Npn \grading_scheme_block_add_element:PP + { + \exp_args:NPP \grading_scheme_block_add_element:NN + } +\cs_new:Npn \grading_scheme_block_gadd_element:PP + { + \exp_args:NPP \grading_scheme_block_gadd_element:NN + } +\cs_new:Npn \grading_scheme_block_add_element:PN + { + \exp_args:NP \grading_scheme_block_add_element:NN + } +\cs_new:Npn \grading_scheme_block_gadd_element:PN + { + \exp_args:NP \grading_scheme_block_gadd_element:NN + } +\cs_new:Npn \grading_scheme_block_format:NnnnN %implicit #1-5 + { + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_right:Nx + \cs_set_eq:NN \__grading_scheme_element_format_optg:NnnnN \grading_scheme_element_format:NnnnN + \cs_set_eq:NN \__grading_scheme_tl_set:Nn \tl_set:Nn + \__grading_scheme_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_gformat:NnnnN %implicit #1-5 + { + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_gput_right:Nx + \cs_set_eq:NN \__grading_scheme_element_format_optg:NnnnN \grading_scheme_element_gformat:NnnnN + \cs_set_eq:NN \__grading_scheme_tl_set:Nn \tl_gset:Nn + \__grading_scheme_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_format:PnnnN % implicit #1-5 + { + \exp_args:NP + \grading_scheme_block_format:NnnnN + } +\cs_new:Npn \grading_scheme_block_gformat:PnnnN % implicit #1-5 + { + \exp_args:NP + \grading_scheme_block_gformat:NnnnN + } +\bool_new:N \l__grading_scheme_block_indent_bool +\int_new:N \l__grading_scheme_block_height_int +\cs_new:Npn \__grading_scheme_block_format:NnnnN #1 #2 #3 #4 #5 + { + \bool_set:Nn \l__grading_scheme_block_indent_bool { #4 && \c_true_bool } + \group_begin: + \__grading_scheme_block_load_description:N #1 + \grading_scheme_block_get_height:NN #1 \l__grading_scheme_block_height_int + \quark_if_no_value:NF \l__grading_scheme_block_description_tl + { + \__grading_scheme_block_indent:nN { #2 } #5 + \__grading_scheme_tl_put_right:Nx #5 + { + \exp_not:N \__grading_scheme_multicolumn:nnn + { + \int_eval:n { #3 } + } + { |l| } + { + \exp_not:V \l__grading_scheme_block_description_tl + } + \\ + \exp_not:N \__grading_scheme_cline:nn + { + \int_eval:n { #2 + 2 } + } + { + \int_eval:n { #2 + #3 } + } + } + } + \__grading_scheme_block_indent:nN { #2 } #5 + \__grading_scheme_block_assert_operation:N #1 + \__grading_scheme_tl_put_right:Nx #5 + { + \exp_not:N \__grading_scheme_multirow:nnn + { + \int_eval:n { \int_use:N \l__grading_scheme_block_height_int - 1 } + } + { * } + { + \exp_not:N \__grading_scheme_rotatebox:nnn + { origin = c } + { 90 } + { + \exp_not:N \__grading_scheme_operation:n + { + \exp_not:V \l__grading_scheme_block_operation_tl + } + } + } + & + } + \bool_set_false:N \l__grading_scheme_block_indent_bool + \cs_set:Npn \__grading_scheme_block_format_element:N ##1 + { + \__grading_scheme_element_format_optg:NnnnN + ##1 + { #2 + 1 } % indent is one more that the current block + { #3 - 1 } % width is one less than current block + { \l__grading_scheme_block_indent_bool } + #5 + \bool_set_true:N \l__grading_scheme_block_indent_bool + } + \__grading_scheme_block_ensure_elements:N #1 % load + sanitize elements + \clist_map_function:PN + \l__grading_scheme_block_elements_clist_ptr + \__grading_scheme_block_format_element:N + \exp_args:NNNV + \group_end: + \__grading_scheme_tl_set:Nn + #5 + #5 + } +\cs_new:Npn \__grading_scheme_block_format:PnnnN + { + \exp_args:NP \__grading_scheme_block_format:NnnnN + } +\cs_new:Npn \__grading_scheme_block_assert_operation:N #1 + { + \__grading_scheme_block_load_operation:N #1 + \quark_if_no_value:NT \l__grading_scheme_block_operation_tl + { + \msg_error:nnxxx { grading-scheme } { missing-value} + { block } + { \token_to_str:N #1 } + { operation } + } + } +\cs_new:Npn \__grading_scheme_block_indent:nN #1 #2 + { + \bool_if:NT \l__grading_scheme_block_indent_bool + { + \__grading_scheme_tl_put_right:Nx #2 + { + \prg_replicate:nn { #1 } { & } + } + } + \bool_set_true:N \l__grading_scheme_block_indent_bool + } +\int_new:N \l__grading_scheme_height_sum_int +\int_new:N \l__grading_scheme_height_acc_int +\cs_new:Npn \grading_scheme_block_get_height:NN #1 #2 +{ + \group_begin: + \__grading_scheme_block_load_elements:N #1 + \int_zero:N \l__grading_scheme_height_sum_int + \clist_map_function:PN + \l__grading_scheme_block_elements_clist_ptr + \__grading_scheme_block_height_accumulator:N + \grading_scheme_block_if_description:NT #1 + { + \int_incr:N \l__grading_scheme_height_sum_int + } + \exp_args:NNNV + \group_end: + \int_set:Nn #2 \l__grading_scheme_height_sum_int +} +\cs_new:Npn \grading_scheme_block_get_height:PN + { + \exp_args:NP \grading_scheme_block_get_height:NN + } +\cs_new:Npn \__grading_scheme_block_height_accumulator:N #1 + { + \grading_scheme_element_get_height:NN #1 \l__grading_scheme_height_acc_int + \int_add:Nn \l__grading_scheme_height_sum_int + { \int_use:N \l__grading_scheme_height_acc_int } + } +\cs_new:Npn \grading_scheme_block_if_description:NT #1 % implicit #2 + { + \__grading_scheme_block_load_description:N #1 + \quark_if_no_value:NF \l__grading_scheme_block_description_tl + } +\cs_new:Npn \grading_scheme_block_if_description:NF #1 % implicit #2 + { + \__grading_scheme_block_load_description:N #1 + \quark_if_no_value:NT \l__grading_scheme_block_description_tl + } +\cs_new:Npn \grading_scheme_block_if_description:NTF #1 #2 #3 + { + \__grading_scheme_block_load_description:N #1 + \quark_if_no_value:NTF \l__grading_scheme_block_description_tl + { #3 } + { #2 } + } +\int_new:N \l__grading_scheme_max_width_int +\int_new:N \l__grading_scheme_width_acc_int +\cs_new:Npn \grading_scheme_block_get_natural_width:NN #1 #2 + { + \group_begin: + \__grading_scheme_block_load_elements:N #1 + \int_zero:N \l__grading_scheme_max_width_int + \clist_map_function:PN + \l__grading_scheme_block_elements_clist_ptr + \__grading_scheme_block_width_accumulator:N + \int_incr:N \l__grading_scheme_max_width_int + \exp_args:NNNV + \group_end: + \int_set:Nn #2 \l__grading_scheme_max_width_int + } +\cs_new:Npn \grading_scheme_block_get_natural_width:PN + { + \exp_args:NP \grading_scheme_block_get_natural_width:NN + } +\cs_new:Npn \__grading_scheme_block_width_accumulator:N #1 + { + \grading_scheme_element_get_natural_width:NN #1 \l__grading_scheme_width_acc_int + \int_set:Nn \l__grading_scheme_max_width_int + { + \int_max:nn + \l__grading_scheme_width_acc_int + \l__grading_scheme_max_width_int + } + } +\cs_set_eq:NN \grading_scheme_element_new:N \prop_new:N +\cs_set_eq:NN \grading_scheme_element_clear:N \prop_clear:N +\cs_set_eq:NN \grading_scheme_element_set_eq:NN \prop_set_eq:NN +\cs_set_eq:NN \grading_scheme_element_gclear:N \prop_gclear:N +\cs_set_eq:NN \grading_scheme_element_gset_eq:NN \prop_gset_eq:NN +\ptr_new:N \l__grading_scheme_element_content_void_ptr +\str_new:N \l__grading_scheme_element_type_str +\cs_new:Npn \grading_scheme_element_set_block:NN #1 % implicit #2 + { + \prop_put:Nnn #1 { type } { block } + \prop_put:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_gset_block:NN #1 % implicit #2 + { + \prop_gput:Nnn #1 { type } { block } + \prop_gput:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_set_entry:NN #1 % implicit #2 + { + \prop_put:Nnn #1 { type } { entry } + \prop_put:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_gset_entry:NN #1 % implicit #2 + { + \prop_gput:Nnn #1 { type } { entry } + \prop_gput:Nnn #1 { content } + } +\cs_new:Npn \grading_scheme_element_get_content:NN #1 % implicit #2 + { + \prop_get:NnN #1 { content } + } +\cs_new:Npn \grading_scheme_element_get_type:NN #1 % implicit #2 + { + \prop_get:NnN #1 { type } + } +\cs_new:Npn \__grading_scheme_element_load_content:N #1 + { + \grading_scheme_element_get_content:NN #1 \l__grading_scheme_element_content_void_ptr + } +\cs_new:Npn \__grading_scheme_element_load_type:N #1 + { + \grading_scheme_element_get_type:NN #1 \l__grading_scheme_element_type_str + } +\cs_new:Npn \grading_scheme_element_cases:Nnn % implicit #1-3 + { + \cs_set_eq:NN \__grading_scheme_str_case:Vnw \str_case:Vn + \__grading_scheme_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnT % implicit #1-4 + { + \cs_set_eq:NN \__grading_scheme_str_case:Vnw \str_case:VnT + \__grading_scheme_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnF % implicit #1-4 + { + \cs_set_eq:NN \__grading_scheme_str_case:Vnw \str_case:VnF + \__grading_scheme_element_cases:Nnnw + } +\cs_new:Npn \grading_scheme_element_cases:NnnTF % implicit #1-5 + { + \cs_set_eq:NN \__grading_scheme_str_case:Vnw \str_case:VnTF + \__grading_scheme_element_cases:Nnnw + } +\cs_new:Npn \__grading_scheme_element_cases:Nnnw #1 #2 #3 % implicit branches + { + \__grading_scheme_element_load_type:N #1 + \__grading_scheme_str_case:Vnw \l__grading_scheme_element_type_str + { + { entry } { #2 } + { block } { #3 } + } + % implicit branches + } +\cs_new:Npn \grading_scheme_element_format:NnnnN % implicit #1-5 + { + \cs_set_eq:NN \__grading_scheme_entry_format_aux:PnnN \grading_scheme_entry_format:PnnN + \cs_set_eq:NN \__grading_scheme_block_format_aux:PnnnN \grading_scheme_block_format:PnnnN + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_right:Nx + \__grading_scheme_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_gformat:NnnnN % implicit #1-5 + { + \cs_set_eq:NN \__grading_scheme_entry_format_aux:PnnN \grading_scheme_entry_gformat:PnnN + \cs_set_eq:NN \__grading_scheme_block_format_aux:PnnnN \grading_scheme_block_gformat:PnnnN + \cs_set_eq:NN \__grading_scheme_tl_put_right:Nx \tl_put_gright:Nx + \__grading_scheme_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_format:PnnnN % implicit #1-5 + { + \exp_args:NP \grading_scheme_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_gformat:PnnnN % implicit #1-5 + { + \exp_args:NP \grading_scheme_element_gformat:NnnnN + } +\cs_new:Npn \__grading_scheme_element_format:NnnnN #1 #2 #3 #4 #5 + { + \__grading_scheme_element_load_content:N #1 + \grading_scheme_element_cases:NnnF #1 + { + \bool_if:nTF { #4 } + { + \__grading_scheme_entry_format_aux:PnnN + \l__grading_scheme_element_content_void_ptr + { #2 } + { #3 } + #5 + } + { + \__grading_scheme_entry_format_aux:PnnN + \l__grading_scheme_element_content_void_ptr + { 0 } + { #3 } + #5 + } + } + { + \__grading_scheme_block_format_aux:PnnnN + \l__grading_scheme_element_content_void_ptr + { #2 } + { #3 } + { #4 } + #5 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + \__grading_scheme_tl_put_right:Nx #5 + { + \exp_not:N \__grading_scheme_cline:nn + { + \int_eval:n { #2 +1 } + } + { + \int_eval:n { #2 + #3 } + } + } + } +\cs_new:Npn \__grading_scheme_element_format:PnnnN % implicit #1-5 + { + \exp_args:NP \__grading_scheme_element_format:NnnnN + } +\cs_new:Npn \grading_scheme_element_get_height:NN #1 #2 + { + \grading_scheme_element_cases:NnnF #1 + { + \int_set:Nn #2 { 1 } + } + { + \__grading_scheme_element_load_content:N #1 + \grading_scheme_block_get_height:PN + \l__grading_scheme_element_content_void_ptr + #2 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + } +\cs_new:Npn \grading_scheme_element_get_height:PN + { + \exp_args:NP \grading_scheme_element_get_height:NN + } +\cs_new:Npn \grading_scheme_element_get_natural_width:NN #1 #2 + { + \grading_scheme_element_cases:NnnF #1 + { + \int_set:Nn { #2 } { 2 } + } + { + \__grading_scheme_element_load_content:N #1 + \grading_scheme_block_get_natural_width:PN + \l__grading_scheme_element_content_void_ptr + #2 + } + { + \msg_error:nnxxx { grading-scheme } { missing-value } + { element } + { \token_to_str:N #1 } + { type / content } + } + } +\cs_new:Npn \grading_scheme_element_get_natural_width:PN + { + \exp_args:NP \grading_scheme_element_get_natural_width:NN + } +\int_new:N \l__grading_scheme_width_int +\tl_new:N \g__grading_scheme_table_tl +\cs_new:Npn \grading_scheme_element_typeset:N #1 + { + \grading_scheme_element_get_natural_width:NN #1 \l__grading_scheme_width_int + \tl_gclear:N \g__grading_scheme_table_tl + \tl_gput_right:Nn \g__grading_scheme_table_tl + { + \begin{tabular} + } + \tl_gput_right:Nx \g__grading_scheme_table_tl + { + { + \prg_replicate:nn { \l__grading_scheme_width_int -1 } { |l } + | l | + } + \exp_not:N \__grading_scheme_hline: + } + \grading_scheme_element_gformat:NnnnN + #1 + { 0 } + { \l__grading_scheme_width_int } + { \c_false_bool } + \g__grading_scheme_table_tl + \tl_gput_right:Nn \g__grading_scheme_table_tl + { + \end{tabular} + } + \group_begin: + \tl_set:Nn \arraystretch { 1.5 } + \tl_use:N \g__grading_scheme_table_tl + \group_end: + } +\cs_new:Npn \grading_scheme_element_typeset:P + { + \exp_args:NP \grading_scheme_element_typeset:N + } +\cs_new:Npn \grading_scheme_entry_new:Nnn #1 #2 % implcit #3 + { + \grading_scheme_entry_new:N #1 + \grading_scheme_entry_gset_description:Nn #1 { #2 } + \grading_scheme_entry_gset_points:Nn #1 + } +\cs_new:Npn \grading_scheme_entry_new:Pnn + { + \exp_args:NP \grading_scheme_entry_new:Nnn + } +\cs_new:Npn \grading_scheme_block_new:Nnn #1 #2 % implicit #3 + { + \grading_scheme_block_new:N #1 + \grading_scheme_block_gset_description:Nn #1 { #2 } + \grading_scheme_block_gset_operation:Nn #1 + } +\cs_new:Npn \grading_scheme_block_new:Pnn + { + \exp_args:NP \grading_scheme_block_new:Nnn + } +\cs_new:Npn \grading_scheme_block_new:Nn #1 % implicit #2 + { + \grading_scheme_block_new:N #1 + \grading_scheme_block_gset_operation:Nn #1 + } +\cs_new:Npn \grading_scheme_block_new:Pn + { + \exp_args:NP \grading_scheme_block_new:Nn + } +\cs_new:Npn \grading_scheme_element_from_entry_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_set_entry:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_from_entry_new:NP + { + \exp_args:NP \grading_scheme_element_from_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_from_entry_new:PP + { + \exp_args:NPP \grading_scheme_element_from_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_gset_entry:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:NP + { + \exp_args:NP \grading_scheme_element_gfrom_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_entry_new:PP + { + \exp_args:NPP \grading_scheme_element_gfrom_entry_new:NN + } +\cs_new:Npn \grading_scheme_element_from_block_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_set_block:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_from_block_new:NP + { + \exp_args:NP \grading_scheme_element_from_block_new:NN + } +\cs_new:Npn \grading_scheme_element_from_block_new:PP + { + \exp_args:NPP \grading_scheme_element_from_block_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:NN #1 #2 + { + \grading_scheme_element_new:N #1 + \grading_scheme_element_gset_block:NN #1 #2 + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:NP + { + \exp_args:NP \grading_scheme_element_gfrom_block_new:NN + } +\cs_new:Npn \grading_scheme_element_gfrom_block_new:PP + { + \exp_args:NPP \grading_scheme_element_gfrom_block_new:NN + } +\ptr_new:Nn \l__grading_scheme_entry_ptr { g } +\ptr_new:Nn \l__grading_scheme_element_ptr { g } +\ptr_new:Nn \l__grading_scheme_curr_block_ptr { g } +\cs_new:Npn \__grading_scheme_entry:nn #1 #2 + { + \ptr_clear:Nn \l__grading_scheme_entry_ptr { g } + \ptr_clear:Nn \l__grading_scheme_element_ptr { g } + \grading_scheme_entry_new:Pnn + \l__grading_scheme_entry_ptr + { #1 } + { #2 } + \grading_scheme_element_gfrom_entry_new:PP + \l__grading_scheme_element_ptr + \l__grading_scheme_entry_ptr + \grading_scheme_block_gadd_element:PP + \l__grading_scheme_curr_block_ptr + \l__grading_scheme_element_ptr + } +\cs_new:Npn \__grading_scheme_block_begin:nn % implicit #1, #2 + { + \ptr_clear:Nn \l__grading_scheme_curr_block_ptr { g } + \grading_scheme_block_new:Pnn \l__grading_scheme_curr_block_ptr + } +\cs_new:Npn \__grading_scheme_block_begin:n % implicit #1 + { + \ptr_clear:Nn \l__grading_scheme_curr_block_ptr { g } + \grading_scheme_block_new:Pn \l__grading_scheme_curr_block_ptr + } +\cs_new:Npn \__grading_scheme_block_end: + { + \ptr_clear:Nn \l__grading_scheme_element_ptr { g } + \grading_scheme_element_gfrom_block_new:PP + \l__grading_scheme_element_ptr + \l__grading_scheme_curr_block_ptr + \cs_gset:Npx \__grading_scheme_after_group: + { + \exp_not:N \grading_scheme_block_gadd_element:PN + \exp_not:N \l__grading_scheme_curr_block_ptr + \exp_not:P \l__grading_scheme_element_ptr + } + \group_insert_after:N \__grading_scheme_after_group: + } +\NewDocumentCommand \entry { m m } + { + \__grading_scheme_entry:nn { #1 } { #2 } + } +\NewDocumentEnvironment { block } { o m } + { + \IfValueTF { #1 } + { + \__grading_scheme_block_begin:nn { #1 } { #2 } + } + { + \__grading_scheme_block_begin:n { #2 } + } + } + { + \__grading_scheme_block_end: + } +\NewDocumentEnvironment {gradingscheme} { o m } + { + \bool_if:NT \g__grading_scheme_pipe_syntax_bool + { + \char_set_active_eq:NN | \__grading_scheme_entry_oneline:w + \char_set_catcode_active:N | + } + \IfValueTF { #1 } + { + \__grading_scheme_block_begin:nn { #1 } { #2 } + } + { + \__grading_scheme_block_begin:n { #2 } + } + } + { + \ptr_clear:Nn \l__grading_scheme_element_ptr { g } + \grading_scheme_element_gfrom_block_new:PP + \l__grading_scheme_element_ptr + \l__grading_scheme_curr_block_ptr + \grading_scheme_element_typeset:P \l__grading_scheme_element_ptr + } +\bool_if:NF \g__grading_scheme_pipe_syntax_bool + { + \endinput + } +\scan_new:N \s__grading_scheme_endline +\cs_new:Npn \__grading_scheme_parse_entry:w #1 & #2 \s_endline + { + \__grading_scheme_entry:nn { #1 } { #2 } + } +\cs_new:Npn \__grading_scheme_replace_newline:w + { + \group_begin: + \char_set_catcode_active:N\^^M + \__grading_scheme_replace_newline_aux:w + } +\char_set_catcode_active:N\^^M +\cs_new:Npn \__grading_scheme_replace_newline_aux:w #1 ^^M + { + \group_end: + #1 \s_endline + } +\char_set_catcode_end_line:N\^^M +\cs_new:Npn \__grading_scheme_entry_oneline:w + { + \__grading_scheme_replace_newline:w + \__grading_scheme_parse_entry:w + } +%% +%% Copyright 2022 Maximilian Kessler <ctan@maximilian-kessler.de> +%% +%% Distributable under the LaTeX Project Public License, +%% version 1.3c or higher (your choice). The latest version of +%% this license is at: http://www.latex-project.org/lppl.txt +%% +%% This work is "author-maintained" +%% +%% This work consists of the files grading-scheme.dtx, grading-scheme.ins, +%% a README file +%% and the derived files grading-scheme.sty and grading-scheme.pdf. +%% +%% +%% End of file `grading-scheme.sty'. diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index c387438d2a1..9a3c235dbf1 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -371,7 +371,7 @@ my @TLP_working = qw( gmdoc gmdoc-enhance gmiflink gmp gmutils gmverb gmverse gnuplottex go gobble gofonts gost gothic gotoh - grabbox gradientframe gradstudentresume grafcet grant + grabbox gradientframe grading-scheme gradstudentresume grafcet grant graph35 graphbox graphics graphics-cfg graphics-def graphics-pln graphicx-psmin graphicscache graphicxbox graphicxpsd diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds index 208326c5fb8..af738344106 100755 --- a/Master/tlpkg/libexec/ctan2tds +++ b/Master/tlpkg/libexec/ctan2tds @@ -3027,6 +3027,7 @@ my $core_latex = "$Master/texmf-dist/tex/latex"; 'german' => 'tex', 'gost' => 'tex', 'grabbox' => 'tex', + 'grading-scheme' => 'etex-answer-y', 'graphics-pln' => "env TEXINPUTS=$Master/texmf-dist/source/latex/base: latex", 'grffile' => 'tex', 'halloweenmath' => 'latex', # requires interaction diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc index 96b25a490c0..031bb12bb1b 100644 --- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc @@ -587,6 +587,7 @@ depend gmiflink depend gmutils depend gmverb depend grabbox +depend grading-scheme depend graphbox depend graphicscache depend graphicx-psmin diff --git a/Master/tlpkg/tlpsrc/grading-scheme.tlpsrc b/Master/tlpkg/tlpsrc/grading-scheme.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/Master/tlpkg/tlpsrc/grading-scheme.tlpsrc |