% Copyright 2012-2022, Alexander Shibakov
% This file is part of SPLinT
%
% SPLinT is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% SPLinT is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with SPLinT.  If not, see <http://www.gnu.org/licenses/>.

% tree evaluator macros.

% #1: first token of a leaf

\def\leafexpand#1{%
    \ifcat\noexpand#1\relax % the leaf starts with an expandable token or control sequence
        \xskiptofi{\expandafter\leafexpand}%
    \else
        \xskiptofi{\leafattach}%
    \fi
    #1%
}

% #1: the leaf
% #2: {{pruned tree}{last pruned branch}}

\def\leafattach#1\endleaf#2{%
    \leafatt@ch{#1}#2%
}

% #1: the leaf
% #2: pruned tree
% #3: last pruned branch

\def\leafatt@ch#1#2#3{%
    \leaf@tt@ch{#1}{#2}#3%
}

\def\xname{\expandafter\eatone\string}

% #1: the leaf
% #2: pruned tree
% #3: treenode type

\def\leaf@tt@ch#1#2#3{%
    \csname\xname#3.ifargdone\endcsname
        % all leaves of the last pruned node have been evaluated, evaluate the node
        \xskiptofi{\csname leafprune\csname\xname#3.arity\endcsname\endcsname{#2}#3{#1}}%
    \else
        % look at the next argument
        \xskiptofi{\csname nextargument\csname\xname#3.arity\endcsname\endcsname{#2}#3{#1}}% rest of the arguments follow
    \fi
}

% #1: pruned tree
% #2: treenode type
% #3: argument

\expandafter\def\csname leafprune0\endcsname#1#2#3{%
    #3%
}

% #1: pruned tree
% #2: treenode type
% #3: argument

\expandafter\def\csname leafprune1\endcsname#1#2#3{%
    \leafexpand#2{#3}\endleaf{#1}%
}

% #1: pruned tree
% #2: treenode type
% #3: argument1
% #4: argument2

\expandafter\def\csname leafprune2\endcsname#1#2#3#4{%
    \leafexpand#2{#3}{#4}\endleaf{#1}%
}

% #1: pruned tree
% #2: treenode type
% #3: argument1

\expandafter\def\csname nextargument1\endcsname#1#2#3{%
    \expandafter\expandafter\expandafter
    \treedesc@nd#3\endleaf{{#1}{#2}}%
}

% #1: pruned tree
% #2: treenode type
% #3: argument1
% #4: argument2

\expandafter\def\csname nextargument2\endcsname#1#2#3#4{%
    \expandafter\expandafter\expandafter
    \treedescend\csname\xname#2.argshift\endcsname{#4}{{#3}}{#1}%
}

% #1: treenode type
% #2: last argument
% #3: rest of arguments
% #4: pruned tree

\def\treedescend#1#2#3#4{%
    \treedesc@nd#2\endleaf{{#4}{#1#3}}%
}

% #1: treenode type or leaf

\def\treedesc@nd#1{%
    \ifcat\noexpand#1\noexpand\relax % in case someone redefined \relax
        % this is an argument that has to be expanded
        \xskiptofi{\csname treed@sc@nd\csname\xname#1.arity\endcsname\endcsname}%
    \else
        % this is a leaf
        \xskiptofi{\leafattach}%
    \fi
    #1%
}

% data type, expand it

\expandafter\def\csname treed@sc@nd0\endcsname{%
    \expandafter\leafattach % \leafattach will consume \endleaf
}

% unary operation
% #1: treenode type
% #2: argument1
% #3: pruned tree

\expandafter\def\csname treed@sc@nd1\endcsname#1#2\endleaf#3{%
    \csname nextargument1\endcsname{#3}#1{#2}%
}

% binary operation
% #1: treenode type
% #2: argument1
% #3: argument2
% #4: pruned tree

\expandafter\def\csname treed@sc@nd2\endcsname#1#2#3\endleaf#4{%
    \csname nextargument2\endcsname{#4}#1{#2}{#3}%
}

\def\treeeval#1{%
    \treeev@l#1%
}

\def\treeev@l#1{%
    \csname nextargument\csname\xname#1.arity\endcsname\endcsname{{}\xxttop}#1%
}

% #1: node name
% #2: arity

\def\nodesetup#1#2{%
    \expandafter\let\csname #1.ifargdone\endcsname\iftrue
    \ifnum#2>0
        \expandafter\edef\csname #1.argshift\endcsname{%
            \expandafter\noexpand\csname #11\endcsname
        }%
    \fi
    \expandafter\edef\csname #1.arity\endcsname{#2}%
    \tempca\@ne
    \loop
    \ifnum\tempca<#2 
        \expandafter\def\csname #1\the\tempca.arity\endcsname{#2}%
        \makeargdonefalse{#1}%
        \tempcb\tempca
        \advance\tempca\@ne
        \ifnum\tempca<#2 
            \expandafter\edef\csname #1\the\tempcb.argshift\endcsname{%
                \expandafter\noexpand\csname #1\the\tempca\endcsname
            }%
        \else
            \expandafter\edef\csname #1\the\tempcb.argshift\endcsname{%
                \expandafter\noexpand\csname #1\endcsname
            }%
        \fi
    \repeat
}

\def\makeargdonefalse#1{\expandafter\let\csname #1\the\tempca.ifargdone\endcsname\iffalse}