% Release 0.2a (2021-05-06) of xintsession.tex
% author: Jean-Francois Burnol
% License: LPPL 1.3c (author-maintained)
% Usage: execute etex or pdftex
%        then enter "xintsession" at the ** prompt
\input xintexpr.sty\relax%
% AJOUTER CHECK DE VERSION ICI
\input xintbinhex.sty\relax%
\input polexpr.sty\relax% attention will crash if < 0.8
\let\PolToExprOneTerm\PolToExprOneTermStyleB%
%\let\PolToExprTimes\empty%
% we do assume standard catcodes on loading and use
% \XINTrestorecatcodes as a convenience facility.
% It stores \endlinechar but not \newlinechar
% and was renamed at 1.4e
\edef\xsrestorecatcodes{\XINTrestorecatcodes%
                        \newlinechar\the\newlinechar\relax}%
\endlinechar 13 %
\newlinechar 10
\catcode`_ 11
\catcode`& 11
\catcode`@ 11
\catcode`^ 11 
\catcode`" 7
\catcode0 12
\newwrite\xs_out
\edef\xs_name{\jobname-\expandafter\xint_gobble_ii\the\year
                      \expandafter\xint_gobble_i\the\numexpr100+\month\relax
                      \expandafter\xint_gobble_i\the\numexpr100+\day\relax
                      _%
                      \expandafter\xint_gobble_i\the\numexpr(\time+30)/60+99h%
                      \expandafter\xint_gobble_i\the\numexpr100+\time-60*((\time+30)/60-1).tex}%
\immediate\openout\xs_out=\xs_name\relax
\begingroup\catcode37 12
\long\gdef\xs_message#1{\message{#1}\immediate\write\xs_out{%#1}}\endgroup
{\catcode13\active\def
{""J}\catcode32\active\edef {\string }%
\catcode`?=0\catcode`\\=12\relax%
?xdef?xs_logo{%
                _____       _____
         ____  ____(_)________  /_________  _________________
         __  |/_/_  /__  __ \  __/  _ \_  |/_/__  __ \_  ___/
         __>  < _  / _  / / / /_ /  __/_>  < __  /_/ /  /
         /_/|_| /_/  /_/ /_/\__/ \___//_/|_| _  .___//_/
                                              /_/
  _____       _____                         __________
  ___(_)________  /__________________ ________  /___(_)__   ______
  __  /__  __ \  __/  _ \_  ___/  __ `/  ___/  __/_  /__ | / /  _ \
  _  / _  / / / /_ /  __/  /   / /_/ // /__ / /_ _  / __ |/ //  __/
  /_/  /_/ /_/\__/ \___//_/    \__,_/ \___/ \__/ /_/  _____/ \___/%
}%
?immediate?write128{%

  xintsession 0.2
  Copyright (c) Jean-Francois Burnol, 2021.

  \jobname is ?jobname
  Transcript will go to log and to ?xs_name

  ===> HIT THE <RET> KEY NOW! <===%
}}%
\def\xs_no{0}%
\XINT_expr_defvar_one{@___}{{0}}%
\XINT_expr_defvar_one{@__}{{0}}%
\XINT_expr_defvar_one{@_}{{0}}%
\def\xs_fetch{\let\xs_in\empty\xs_fetch_a}%
\begingroup
\catcode13\active%
\long\gdef\xs_fetch_a#1
{%
  \odef\xs_firstitem{\romannumeral0\xintfirstitem{#1.}}%
  \ifcat\relax\expandafter\noexpand\xs_firstitem%
    \expandafter\xs_cs%
  \else%
   \if &\expandafter\noexpand\xs_firstitem%
    \expandafter\expandafter\expandafter\xs_magic%
   \fi%
  \fi%
  \if;\expandafter\noexpand\romannumeral0\xintlastitem{#1}%
    \xs_fetch_b#1^%
  \else%
    \message{(Use ; to end multi-line input)}%
    \odef\xs_in{\xs_in#1}\expandafter\xs_fetch_a%
  \fi%
}%
\endgroup
\long\def\xs_cs\if;\expandafter\noexpand\romannumeral0\xintlastitem#1#2\fi
{%
   \xs_message{(executing \detokenize{#1} in background)}%
   #1\xs_fetch_a
}%
\def\xs_firstfour#1#2#3#4#5\xint_bye{\edef\xs_magic_in{#1#2#3#4}\def\xs_magic_inb{#5}}%
\long\def\xs_magic\if;\expandafter\noexpand\romannumeral0\xintlastitem#1#2\fi
{%
  \xs_firstfour#1\empty\empty\empty\empty\xint_bye
  \ifcsname xs_magic@\xs_magic_in\endcsname
      \csname xs_magic@\xs_magic_in\expandafter\endcsname
  \else
   \xs_message{(\detokenize\expandafter{\xint_gobble_i#1} is not a magic keyword:
            ignored)}%
  \fi\xs_fetch_a
}%
\long\def\xs_fetch_b#1;^%
{%
   \odef\xs_in{\xs_in#1}\expandafter\xs_fetch_c
}%
\def\xs_fetch_c
{%
   \if\relax\romannumeral`""@\detokenize\expandafter{\xs_in}\relax\expandafter\xs_pause\fi
   \expandafter\xs_parse_a\xs_in:=^%
}%
\def\xs_pause\expandafter\xs_parse_a\xs_in:=^{\xs_pause_a\xs_fetch_a}%
\def\xs_pause_a\xs_fetch_a
{%
   \xs_message{Need a break? OK, use \string\xintresume\space if you change your mind.}%
   \xs_resetcats
}%
\def\xs_bye\xs_fetch_a
{%
   \xs_message{Did I say something wrong?}%
   \xs_message{Session transcript written on \xs_name}%
%   \xs_resetcats
   \immediate\closeout\xs_out
% expeditive exit because I need to think about generating new output
% filename with a check that it is not same (a minute may be too coarse?).
% Add random postfix? or simply do not bother rather...
   \csname bye\endcsname
}%
\def\xs_parse_a#1:=#2%
{%
   \xint_gob_til_^#2\xs_calc ^%
   \def\xs_left{#1}\xs_parse_b#2%
}%
\def\xs_calc ^#1^%
{%
   \edef\xs_no{\the\numexpr1+\xs_no}%
   \xs_xintdefvar @_\xs_no=\xs_in;%
   \immediate\write\xs_out
   {\expandafter\string\xs_xintdefvar\space @_\xs_no:=%
                \detokenize\expandafter{\xs_in};}%
   \XINT_expr_defvar_one{@___}{\csname XINT_expr_varvalue_@__\endcsname}%
   \XINT_expr_defvar_one{@__}{\csname XINT_expr_varvalue_@_\endcsname}%
   \XINT_expr_defvar_one{@_}{\csname XINT_expr_varvalue_@_\xs_no\endcsname}%
   \xs_message{(@_\xs_no)\space\space\space\space\xs_xinteval{@_\xs_no}}%
   \xs_fetch
}%
\def\xs_parse_b #1:=^%
{%
   \def\xs_right{#1}\expandafter\xs_parse_c\xs_left(;%
}%
\def\xs_parse_c #1(#2%
{%
   \edef\xs_funcname{\expandafter\xint_zapspaces\detokenize{#1} \xint_gobble_i}%
   \xint_gob_til_sc#2\xs_defvar;\xs_deffunc
}%
\def\xs_deffunc #1;%
{%
% attention: \xs_xintdeffunc needs to see parentheses immediately
   \expandafter\xs_xintdeffunc\xs_left=\xs_right;%
   \immediate\write\xs_out
   {\expandafter\string\xs_xintdeffunc\space\detokenize\expandafter{\xs_left}:=%
                \detokenize\expandafter{\xs_right};}%
   \expandafter\ifx\xs_xintdeffunc\poldef
        \xs_message{\xs_funcname\space = \PolToExpr{\xs_funcname}}%
        \xs_message{Issue \string\PolGenFloatVariant{\xs_funcname} if fp evaluations
                 with \xs_funcname\space are intended}%
   \else\xs_message{Function \xs_funcname\space defined}%
   \fi\xs_fetch
}%
\def\xs_defvar;\xs_deffunc
{%
   \edef\xs_no{\the\numexpr1+\xs_no}%
   \xs_xintdefvar @_\xs_no=\xs_right;%
   \immediate\write\xs_out
   {\expandafter\string\xs_xintdefvar\space\detokenize\expandafter{\xs_left}:=%
                \detokenize\expandafter{\xs_right};}%
   \XINT_expr_defvar_one{@___}{\csname XINT_expr_varvalue_@__\endcsname}%
   \XINT_expr_defvar_one{@__}{\csname XINT_expr_varvalue_@_\endcsname}%
   \XINT_expr_defvar_one{@_}{\csname XINT_expr_varvalue_@_\xs_no\endcsname}%
   % this is to allow multiple assignments
   \expandafter\xs_xintdefvar\xs_left=@_\xs_no;%
   \xs_message{(@_\xs_no)\space\space\space\space\xs_xinteval{@_\xs_no}}%
   \xs_fetch
}%
\let\xs_magic@&pau\xs_pause_a
\let\xs_magic@&bye\xs_bye
\def\xs_magic@&fp
{%
   \xs_message{fp mode (\xinttheDigits\space digits)}%
   \def\xs_mode{fp (Digits=\xinttheDigits)}%
   \def\xs_xintdefvar{\xintdeffloatvar}%
   \def\xs_xintdeffunc{\xintdeffloatfunc}%
   \def\xs_xinteval{\xintfloateval}%
}%
\expandafter\def\csname xs_magic@&fp=\endcsname
{%
   \xintDigits*:=\xs_magic_inb\relax
   \xs_message{fp mode (log and trig reloaded at Digits=\xinttheDigits)}%
   \def\xs_mode{fp=\xinttheDigits}%
   \def\xs_xintdefvar{\xintdeffloatvar}%
   \def\xs_xintdeffunc{\xintdeffloatfunc}%
   \def\xs_xinteval{\xintfloateval}%
}%
\def\xs_magic@&exa
{%
   \xs_message{exact mode (floating point evaluations use \xinttheDigits\space digits)}%
   \def\xs_mode{exact}%
   \def\xs_xintdefvar{\xintdefvar}%
   \def\xs_xintdeffunc{\xintdeffunc}%
   \def\xs_xinteval{\xinteval}%
}%
\def\xs_magic@&int
{%
   \xs_message{int mode (integer only: / rounds, // is floored division, /: is modulo)}%
   \def\xs_mode{int}%
   \def\xs_xintdefvar{\xintdefiivar}%
   \def\xs_xintdeffunc{\xintdefiifunc}%
   \def\xs_xinteval{\xintiieval}%
}%
\def\xs_magic@&pol
{%
   \xs_message{pol mode (i.e. function definitions use \string\poldef)}%
   \def\xs_mode{pol}%
   \def\xs_xintdefvar{\xintdefvar}%
   \def\xs_xintdeffunc{\poldef}%
   \def\xs_xinteval{\xinteval}%
}%
\def\xs_magic@&mod{\xs_message{current mode: \xs_mode}}%
\def\xs_setcats
{%
    \newlinechar10\endlinechar13%
    \catcode13\active\catcode`@ 11\relax
}%
\def\xs_storecats{\edef\xs_resetcats
{%
    \newlinechar\the\newlinechar
    \endlinechar\the\endlinechar
    \catcode13=\the\catcode13
    \catcode`@\the\catcode`@\relax
}}%
\begingroup
\catcode13\active\catcode32\active%
\gdef\xintstart{\edef {\string }\xs_setcats\def
{""J}\message{\xs_logo

  Welcome to xintexpr interactive mode!
  - input is `;'-terminated and can extend over multiple lines,
  - definitions must be done using the `:=' syntax, not `='.
  - any line starting with a control sequence is executed in the
    background, the interrupted numerical input resumes at prompt.

  Magic words: `&pause' (or `;'), `&help', `&bye',
               `&exact', `&fp', `&int', `&pol'.
  Say e.g. `&fp=24' to activate floating point mode  with Digits=24.
  Starting in}\xs_magic@&exa\let
=\xs_fetch}\gdef\xintresume{\edef {\string }\xs_storecats\xs_setcats%
\message{Welcome back to xintexpr interactive mode!}\let
=\xs_fetch}\catcode`?0\catcode`\\12?gdef?xs_help?xs_fetch_a{?def
{""J}?edef {?string }?message{%
  - Terminate inputs using the `;' character. Input can extend over
    multiple lines (<RET> terminated).

  - An empty input (`;' terminated) or the magic word `&pause' puts
    the session on hold and switches to normal TeX interaction. Use
    \xintresume to resume the session.

  - Lines starting with any control sequence are handed over to
    TeX, and numerical input resumes on next line.

  - The numerical engine can work in various modes:
    exact (uses \xintexpr), fp (uses \xintfloatexpr), int (uses
    (\xintiiexpr), and pol (makes definitions using \poldef).
    To activate a mode enter `&<mode name>' at the prompt

  - Issue `&mode' if you forgot in what mode you are currently in.

  - Say `&exact' resp. `&fp' to go back and forth between exact
    and floating point mode

(1/5) HIT <RET> KEY%
}?let
=?xs_help_b}?gdef?xs_help_b{?def
{""J}?message{%
  - Say `&fp=<number>' for example `&fp=32' at the prompt to activate
    fp mode at a given Digits setting. This can be done in the midst
    of the input of a  multi-line computation!

  - Math functions are supported up to Digits=62 (since xint 1.4e);
    sqrt() and powers with integer exponents work in fp mode with Digits
    arbitrary.

  - Definitions (variables or functions) are done using `:='.

    *  Parentheses present before the `:=' trigger a function
       definition, else a variable definition is done.

    *  IMPORTANT: using a `=' by oversight will cause breakage as
    xintsession thinks it is then handling a numerical evaluation,
    not a definition, but there is no `=' operator in xintexpr syntax.

%    Perhaps in future it will be allowed to make definitions using `='
%    and xintsession will check if it is not misinterpreting a `=' from
%    `<=', `>=', `!=', `==' or `seq()' syntax but this currently was
%    considered to add too much overhead for the benefit.
%    
(2/5) HIT <RET> KEY%
}?let
=?xs_help_c}?gdef?xs_help_c{?def
{""J}?message{%
  - Functions defined in one mode are not available for usage in
    other modes without further steps; check xintexpr doc.

  - Polynomials in pol mode are defined using polname(x):=expression;
    (or with another letter). They can serve as functions in the exact
    mode. To use a polynomial also as an fp mode function, issue
    \PolGenFloatVariant{<polname>} at the prompt.

  - Whenever a variable is defined, or a computation is performed,
    the result is assigned a label @_<integer>. These labels are
    variables which can then be used in subsequent computations.

  - The special variables @_, @__, and @___ hold the last, next
    to last and next to next to last evaluation results.

  - In the case of a multi-variable assignment (see xintexpr doc)
    the automatic variable @_<integer> holds the whole thing, which
    may be a nutple or an ople, in addition to individual variables.

(3/5) HIT <RET> KEY%
}?let
=?xs_help_d}?gdef?xs_help_d{?def
{""J}?message{%
  - Variables defined in any mode can be used in any mode except:
    * polynomials can be used as variables only in the pol and the
      exact modes,
    * integer-only mode requires... integer-only variables, also
      internally. Use num() or \xintiexpr...\relax as wrappers in int
      mode around exact or fp variables (even integer-valued ones).

  Known issues:

  - The [P] optional argument of \xintfloateval can not be used
    because it is not recognized by \xintdeffloatvar, one can use
    the float() function with its second argument.

  - An \xintexpr...\relax wrapper can not start a line, as it would
    trigger control sequence execution. Use parentheses or 0+\...

  - Exact mode does not reduce to lowest terms, use reduce().

(4/5) HIT <RET> KEY%
}?let
=?xs_help_e}?gdef?xs_help_e{?def
{""J}?message{%
  (cont.)
  - A session transcript file is created which can be executed by
    eTeX to redo all calculations; however @_, @__, and @___ will
    not be defined in this context so need to be manually replaced
    by the suitable @_<integer>. The format of the transcript
    is to be considered unstable at this stage.

  Future:

  - a plot() function will be added at some point to export
    coordinates into a .tex file for usage either with PSTricks or
    TikZ/pgf.

  Miscellany:

  Misformed xintexpr input can drop you into TeX error mode. In that
  case, try escaping using `S'.  It does work sometimes.

(5/5) You are back to the xintexpr interactive session! (mode: ?xs_mode)
      Use `&bye' to terminate the session and the TeX run.%
}?let
=?xs_fetch?xs_fetch_a}?endgroup
\let\xs_magic@&hel\xs_help
\xsrestorecatcodes
\csname xs_storecats\endcsname
\catcode13\active\def
{\xintstart
}\endinput%
