%%%==============================================================================
%% Copyright 2026-present by Alceu Frigeri
%%
%% This work may be distributed and/or modified under the conditions of
%%
%% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt),
%%   version 1.3c (or later), and/or
%% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html),
%%   version 3 (or later)
%%
%% This work has the LPPL maintenance status *maintained*.
%%
%% The Current Maintainer of this work is Alceu Frigeri
%%
%% This is version {1.0} {2026/02/18}
%%
%% The list of files that compose this work can be found in the README.md file at
%% https://ctan.org/pkg/xstacks
%%
%%%==============================================================================
\NeedsTeXFormat{LaTeX2e}[2025/06/01]

%%%%%%%
%%%
%%% Just an attempt at having my package's info in a regular way
%%%   \pkginfograb_set:nn {<pkg-name>} { props} sets package info
%%%
%%%   \pkginfograbProvidesExplPackage {<pkg-name>} { props} sets package's info
%%%     and calls \ProvidesExplPackage
%%%
%%%%%%%
\RequirePackage{pkginfograb}
\pkginfograbProvidesExplPackage {tokglobalstack}
  {
     name        = {tokglobalstack} ,
     prefix      = {globalstack} ,
     date        = {2026/02/18},
     version     = {1.0} ,
     description = {tokglobalstack - (multiple) global stack(s)}
  }
%%%%%%%
%%% End of cut-n-paste
%%%%%%%

\msg_new:nnnn { tokglobalstack } {defined}
  {
    (#1)~#2~already~defined.
  }
  {
    #2~ is ~ already~ defined, ~and~ will~ not~ be~ redefined.
    ~Error~Code~ ID:<#1>.
  }


%%%%%%%
%%%  'cs' generate case.
%%%%%%%

\cs_new_protected:Npn \globalstack_csnew:n #1
  {
    \cs_if_exist:cTF {#1_gpush:n}
      {
        \msg_error:nnnn { tokglobalstack } {defined}
          {new01} {#1}
      }
      {
        \int_new:c {g__globalstack_ #1 _int}
        
        \cs_new:cpe  {#1_gpush:n} % ##1
          {
            \exp_not:N \int_gincr:N \exp_not:c {g__globalstack_ #1 _int}
    
            \exp_not:N \exp_args:NNc
              \exp_not:N \tl_gset:Nn 
              \exp_not:c {g__globalstack_ #1 _ref_tl}
              {g__globalstack_ #1 _ \exp_not:N \int_use:N \exp_not:c {g__globalstack_ #1 _int} _tl}
            \exp_not:N \exp_args:No
              \exp_not:N \tl_gset:Nn
                \exp_not:c {g__globalstack_ #1 _ref_tl}  % {##1}
          }
          
        \cs_new:cpe  {#1_gput_right:n} %##1
          {
            \exp_not:N \exp_args:No
            \exp_not:N \tl_gput_right:Nn 
                \exp_not:c {g__globalstack_ #1 _ref_tl}  % {##1}
          }
          
        \cs_new:cpe  {#1_gput_left:n} %##1
          {
            \exp_not:N \exp_args:No
            \exp_not:N \tl_gput_left:Nn 
                \exp_not:c {g__globalstack_ #1 _ref_tl}  % {##1}
          }
          
        \cs_new:cpe  {#1_gpop:} 
          {
            \exp_not:N \if_int_compare:w \exp_not:c {g__globalstack_ #1 _int} =  \c_zero_int
            \exp_not:N \else:
              \exp_not:c {g__globalstack_ #1 _ref_tl}
              \exp_not:N \int_gdecr:N \exp_not:c {g__globalstack_ #1 _int}
              \exp_not:N \exp_args:NNc
                \exp_not:N \tl_gset:Nn 
                \exp_not:c {g__globalstack_ #1 _ref_tl}
                {g__globalstack_ #1 _ \exp_not:N \int_use:N \exp_not:c {g__globalstack_ #1 _int} _tl}            
            \exp_not:N \fi:
          }
      }
  }


%%%%%%%
%%%  Note: 
%%%  \__globalstack:wn absorbs 5 tokens, 
%%%       4 'internal' (including a quark marker) + 1 given by the user
%%%       except in two cases: (whereas only the 4 internal tokens will be consumed)
%%%          the 'default' cmd (...\use_none:nnnn so the variable expands to nothing)
%%%          and the \...pop: case
%%%
%%% a local group is created (except in the pop case)
%%% so there is no need to reset \__globalstack:wn
%%%%%%%


\cs_set_eq:NN \__globalstack:wn \use_none:nnnn
\tl_new:N \l__globalstack_tmpA_tl

\cs_new_protected:Npn \globalstack_new:N #1
  {
    \tl_if_exist:NTF #1
      {
        \msg_error:nnnn { tokglobalstack } {defined}
          {new02} {#1}
      }
      {
        \tl_set:Ne \l__globalstack_tmpA_tl {\cs_to_str:N #1}
        \exp_args:Ncc \tl_gset:Nn {g__globalstack_ \l__globalstack_tmpA_tl _ref_tl} {g__globalstack_ \l__globalstack_tmpA_tl _tl}
        \tl_gset:cn {g__globalstack_ \l__globalstack_tmpA_tl _tl} {}
        \int_new:c {g__globalstack_ \l__globalstack_tmpA_tl _int}
        \tl_gset:Ne #1
          {
            \exp_not:N \__globalstack:wn
            \exp_not:c {g__globalstack_ \l__globalstack_tmpA_tl _ref_tl}
            \exp_not:c {g__globalstack_ \l__globalstack_tmpA_tl _int}
            {\l__globalstack_tmpA_tl}
            \exp_not:N \q_stop
          }
      }
  }


\cs_new_protected:Npn \__globalstack_gpush:wn #1#2#3 \q_stop % #4
  {
    \int_gincr:N #2
    \exp_args:NNc \tl_gset:Nn #1 {g__globalstack_ #3 _ \int_use:N #2 _tl}
    \exp_args:No \tl_gset:Nn #1 % {#4}
  }



\cs_new_protected:Npn \globalstack_gpush:Nn #1#2
  {
    {
      \cs_set_eq:NN \__globalstack:wn \__globalstack_gpush:wn
      #1 {#2}  
    }
  }


\cs_new_protected:Npn \globalstack_gput_right:Nn #1#2
  {
    {
      \cs_set_eq:NN \__globalstack:wn \__globalstack_gput_right:wn
      #1 {#2}   
    }
  }
\cs_new_protected:Npn \__globalstack_gput_right:wn #1#2#3 \q_stop % #4
  { 
    \exp_args:No \tl_gput_right:Nn #1 % {#4}
  }  


\cs_new_protected:Npn \globalstack_gput_left:Nn #1#2
  {
    {
      \cs_set_eq:NN \__globalstack:wn \__globalstack_gput_left:wn
      #1 {#2}   
    }
  }
\cs_new_protected:Npn \__globalstack_gput_left:wn #1#2#3 \q_stop % #4
  { 
    \exp_args:No \tl_gput_left:Nn #1 % {#4}
  }  


\cs_new_protected:Npn \__globalstack_gpop:w #1#2#3 \q_stop
  {
    \cs_set_eq:NN \__globalstack:wn \use_none:nnnn
    \if_int_compare:w #2 = \c_zero_int
    \else:
      \int_gdecr:N #2
      #1
      \exp_args:NNc \tl_gset:Nn #1 {g__globalstack_ #3 _ \int_use:N #2 _tl}
    \fi:
  }


\cs_new_protected:Npn \globalstack_gpop:N % #1
  {
    \cs_set_eq:NN \__globalstack:wn \__globalstack_gpop:w  
    % #1
  }
