%%
%% 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/24} {0.1.1}
  {Typeset grading schemes in tabular format}
\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'.
