%
% This is derived from alltt.sty
%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{sml}[1998/12/17 defines sml environment]

%
%  Font for typesetting sml code, default is \tt
%
\newcommand{\smlFont}{\verbatim@font}
\newcommand{\smlCommentSize}{\small}
\newcommand{\smlCommentFont}{\it}
\newcommand{\smlNumberFont}{\smlFont}
\newcommand{\smlNumberStyle}[1]{\arabic{#1}}
\newcommand{\sml@font}{\smlFont}


%
% Turn on and off dollar sign
%
\newif\ifsml@dollar
\newcommand{\smlDollarOn}{\sml@dollartrue}
\newcommand{\smlDollarOff}{\sml@dollarfalse}
\smlDollarOff

%
%  Font for typesetting sml type variables, default is \it
%
\newcommand{\smlTypeVarFont}{\it}

%
%  Commands for typesetting type variables and keywords.
%  Can be overridden by user.
%
\newcommand{\makeSmlTypeVar}[1]{'{\smlTypeVarFont#1}}
\newcommand{\makeSmlKeyword}[1]{{\bf#1}}
\newcommand{\BeginSmlComment}{\begingroup\smlCommentSize\smlCommentFont}
\newcommand{\EndSmlComment}{\endgroup}

%
%  Command to declare a new type variable translation
%  and keywords
%
\newcommand{\smlTypeVar}[2]{
  \expandafter\newcommand\csname smltv@#1\endcsname{#2}
}
\newcommand{\smlRemoveTypeVar}[1]{
  \expandafter\newcommand\csname smltv@#1\endcsname\relax
}
\newcommand{\smlNewKeyword}[1]{
   \expandafter\def\csname smlkw@#1\endcsname{\makeSmlKeyword{#1}}
}
\newcommand{\smlDefineNewKeyword}[2]{
   \expandafter\def\csname smlkw@#1\endcsname{#2}
}
\newcommand{\smlRemoveKeyword}[1]{
  \expandafter\newcommand\csname smlkw@#1\endcsname\relax
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%

%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\sml@expandtv}[1]{%
\if\csname smltv@#1\endcsname\relax\makeSmlTypeVar{#1}\else%
\csname smltv@#1\endcsname\fi}

\newcommand{\sml@expandkw}[1]{%
\if\csname smlkw@#1\endcsname\relax{#1}\else\csname smlkw@#1\endcsname\fi}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This is a lexer that translates type variables and keywords
% #1 is the eof character
% #2 is the current state (actually a macro)
%    which can be:
%       0 -- program text
%       1 -- type variable
%       2 -- program text found (  
%       3 -- in comment 
%       4 -- in comment type variable
%       5 -- in comment found *
% #3 is the current string 
% #4 is the next token 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\sml@startlexer}[1]{\sml@lexer{#1}{0}{}}
\newcommand{\sml@lexer}[4]{%
   \ifx#4a\let\sml@nexttok=\sml@getletter%
   \else\ifx#4b\let\sml@nexttok=\sml@getletter%
   \else\ifx#4c\let\sml@nexttok=\sml@getletter%
   \else\ifx#4d\let\sml@nexttok=\sml@getletter%
   \else\ifx#4e\let\sml@nexttok=\sml@getletter%
   \else\ifx#4f\let\sml@nexttok=\sml@getletter%
   \else\ifx#4g\let\sml@nexttok=\sml@getletter%
   \else\ifx#4h\let\sml@nexttok=\sml@getletter%
   \else\ifx#4i\let\sml@nexttok=\sml@getletter%
   \else\ifx#4j\let\sml@nexttok=\sml@getletter%
   \else\ifx#4k\let\sml@nexttok=\sml@getletter%
   \else\ifx#4l\let\sml@nexttok=\sml@getletter%
   \else\ifx#4m\let\sml@nexttok=\sml@getletter%
   \else\ifx#4n\let\sml@nexttok=\sml@getletter%
   \else\ifx#4o\let\sml@nexttok=\sml@getletter%
   \else\ifx#4p\let\sml@nexttok=\sml@getletter%
   \else\ifx#4q\let\sml@nexttok=\sml@getletter%
   \else\ifx#4r\let\sml@nexttok=\sml@getletter%
   \else\ifx#4s\let\sml@nexttok=\sml@getletter%
   \else\ifx#4t\let\sml@nexttok=\sml@getletter%
   \else\ifx#4u\let\sml@nexttok=\sml@getletter%
   \else\ifx#4v\let\sml@nexttok=\sml@getletter%
   \else\ifx#4w\let\sml@nexttok=\sml@getletter%
   \else\ifx#4x\let\sml@nexttok=\sml@getletter%
   \else\ifx#4y\let\sml@nexttok=\sml@getletter%
   \else\ifx#4z\let\sml@nexttok=\sml@getletter%
   \else\ifx#4_\let\sml@nexttok=\sml@getletter%
   \else%
     \let\sml@nexttok=\sml@transition% is not a letter
   \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi%
   \sml@nexttok{#1}{#2}{#3}{#4}%
}

\newcommand{\sml@getletter}[4]{\sml@lexer{#1}{#2}{#3#4}}  % get more character

%
% Do something according to the lookahead character
%
\newcommand{\sml@transition}[4]{% 
   %\message{|#3|}%
   \if\noexpand#4'%
       \let\sml@nextaction=\sml@tokenizetv%
   \else\if\noexpand#4#1%
       \let\sml@nextaction=\sml@endlexer%
   \else\ifx#4(%
       \let\sml@nextaction=\sml@lparen%
   \else\ifx#4)%
       \let\sml@nextaction=\sml@rparen%
   \else\ifx#4*%
       \let\sml@nextaction=\sml@star%
   \else%
       \let\sml@nextaction=\sml@tokenizekw%
   \fi\fi\fi\fi\fi%
   \sml@nextaction{#1}{#2}{#3}{#4}%
}

%       0 -- program text
%       1 -- type variable
%       2 -- program text found (  
%       3 -- in comment 
%       4 -- in comment type variable
%       5 -- in comment found *
\newcommand{\sml@expand}[2]{%
   \ifcase#1\let\sml@process=\sml@expandkw\or%
            \let\sml@process=\sml@expandtv\or%
            \let\sml@process=\sml@expandkw\or%
            \let\sml@process=\sml@expandkw\or%
            \let\sml@process=\sml@expandtv\or%
            \let\sml@process=\sml@expandkw%
   \else\ERROR%
   \fi%
   \sml@process{#2}%
}
\newcommand{\sml@tokenizekw}[4]{\sml@expand{#2}{#3}#4\sml@lexer{#1}{\sml@deltakw{#2}}{}}
\newcommand{\sml@tokenizetv}[4]{\sml@expand{#2}{#3}\sml@lexer{#1}{\sml@deltatv{#2}}{}}
\newcommand{\sml@endlexer}[4]{\sml@expand{#2}{#3}}
\newcommand{\sml@lparen}[4]{\sml@expand{#2}{#3}%
(\sml@lexer{#1}{\sml@deltal{#2}}{}}
\newcommand{\sml@rparen}[4]{\sml@expand{#2}{#3}%
\sml@closecomment{#2})\sml@lexer{#1}{\sml@deltar{#2}}{}}
\newcommand{\sml@star}[4]{\sml@expand{#2}{#3}*%
\sml@opencomment{#2}\sml@lexer{#1}{\sml@deltas{#2}}{}}

%       0 -- program text
%       1 -- type variable
%       2 -- program text found (  
%       3 -- in comment 
%       4 -- in comment type variable
%       5 -- in comment found *
\newcommand{\sml@opencomment}[1]{\if2#1\BeginSmlComment\else\fi}
\newcommand{\sml@closecomment}[1]{\if5#1\EndSmlComment\else\fi}
\newcommand{\sml@deltakw}[1]{\ifcase#1 0\or0\or0\or3\or3\or3\else\ERROR\fi}
\newcommand{\sml@deltatv}[1]{\ifcase#1 1\or1\or1\or4\or4\or4\else\ERROR\fi}
\newcommand{\sml@deltal}[1]{\ifcase#1 2\or2\or2\or3\or3\or3\else\ERROR\fi}
\newcommand{\sml@deltas}[1]{\ifcase#1 0\or0\or3\or5\or5\or5\else\ERROR\fi}
\newcommand{\sml@deltar}[1]{\ifcase#1 0\or0\or0\or3\or3\or0\else\ERROR\fi}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% How to process type variables as active character:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\sml@processtypevar}{\sml@lexty{}}
\newcommand{\sml@lexty}[2]{\ifcat\noexpand#2a\let\sml@nextty=\sml@morety\else\let\sml@nextty=\sml@donety\fi\sml@nextty{#1}#2}
\newcommand{\sml@morety}[2]{\sml@lexty{#1#2}}
\newcommand{\sml@donety}[1]{\sml@expandtv{#1}}
\newcommand{\sml@aftertypevar}{}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Macros for setting up verbatim mode 
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Set up catcodes for verbatim mode
%
\begingroup
\lccode`\~=`\'
\lowercase{\endgroup
\newcommand{\sml@settick}{\catcode`\'=\active\let~=\sml@processtypevar}
\newcommand{\sml@verbatimmode}{%
\let\sml@origprime=~%
\sml@font%
\@noligs%
\catcode`\^=12%
\catcode`\_=12%  
\ifsml@dollar\else\catcode`\$=12\fi% 
\catcode`\#=12%
\catcode`\&=12%
\catcode`\~=12%
\catcode`\%=12%
\everymath\expandafter{\the\everymath\sml@mathmode}%
\everydisplay\expandafter{\the\everydisplay\sml@mathmode}%
\everypar\expandafter{\the\everypar\unpenalty}%
\sml@settick%
\frenchspacing\@vobeyspaces% Preserve all spaces  
}

%
% Set up catcodes for math mode
%
\newcommand{\sml@mathmode}{
   \catcode`\^=7       % Superscript 
   \catcode`\_=8       % Subscript
   \catcode`\'=12      % prime
   \let~=\sml@origprime%
}
}

%
% Set up display format 
%
\newcommand{\sml@begindisplay}{%
    \begingroup
    %\trivlist \item
    \if@minipage% Insert paragraph break
    \else
       \vskip\parskip
    \fi
    \leftskip\@totalleftmargin
    \rightskip\z@skip
    \parindent\z@
    \parfillskip\@flushglue
    \parskip\z@skip
    \@@par
    \@tempswafalse 
    \def\par{%
      \if@tempswa
        \leavevmode\null\@@par\penalty\interlinepenalty
    \else
      \@tempswatrue
      \ifhmode\@@par\penalty\interlinepenalty\fi
    \fi}
    \obeylines       % Lines breaks are meaningful
}

%
% End display format 
%
%\newcommand{\sml@enddisplay}{\endtrivlist\endgroup}
\newcommand{\sml@enddisplay}{\endgroup}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  The main macros
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newenvironment{smldisplay}{\sml@begindisplay\trivlist\item\sml@verbatimmode}{\endtrivlist\sml@enddisplay}

\newcommand{\sml}{\begingroup\sml@verbatimmode\sml@verb}
\newcommand{\sml@verb}[1]{#1\endgroup}

\newsavebox{\sml@box}
   \newenvironment{sml@boxit}{\begin{lrbox}{\sml@box}
   \begin{minipage}[b]{\columnwidth}}
    {\end{minipage}\end{lrbox}\begin{center}\framebox[\columnwidth]{\usebox{\sml@box}}\end{center}}

\newenvironment{smlboxeddisplay}{\begin{sml@boxit}\begin{smldisplay}}{\end{smldisplay}\end{sml@boxit}}

\newcounter{sml@linecount}
\newcounter{sml@increment}
\newcommand{\sml@setuplineno}[2]{%
\setcounter{sml@linecount}{#1}%
\setcounter{sml@increment}{1}%
\newcommand{\sml@showlinecount}%
{\llap{\smlNumberFont\smlNumberStyle{sml@linecount}\ }}%
\newcommand{\sml@inclineno}{\addtocounter{sml@increment}{-1}%
\ifnum\value{sml@increment}=0\sml@showlinecount\setcounter{sml@increment}{#2}\else \fi%
\addtocounter{sml@linecount}{1}}%
\everypar{\sml@inclineno}%
}

\newenvironment{smllisting}[2]%
   {\sml@begindisplay\sml@verbatimmode\sml@setuplineno{#1}{#2}}%
   {\sml@enddisplay}
\newenvironment{smlboxedlisting}[2]%
   {\begin{sml@boxit}\begin{smllisting}{#1}{#2}}{\end{smllisting}\end{sml@boxit}}
\newenvironment{smldisplay*}[1]{%
   \sml@begindisplay
   \let\sml@settick=\relax
   \sml@verbatimmode
   \sml@startlexer{#1}
  }{\sml@enddisplay}
\newenvironment{smlboxeddisplay*}[1]%
  {\begin{sml@boxit}\begin{smldisplay*}{#1}}{\end{smldisplay*}\end{sml@boxit}}


\begingroup
\catcode`\^^A=12%
\catcode`\<=1%
\catcode`\>=2%
\catcode`\?=0%
\catcode`\{=12%
\catcode`\}=12%
%\catcode`\\=12%
\lowercase<\endgroup%
\def\sml@glob#1\end<\sml@startlexer<^^A>#1^^A\sml@enddisplay\end>%
\def\smldisp<%
   \sml@begindisplay%
   \let\sml@settick=\relax%
   \sml@verbatimmode%
   \catcode`\^^A=12%
   \sml@glob%
>
\def\endsmldisp<>
>

\begingroup
\catcode`\^^A=12
\lowercase{\endgroup
\newcommand{\Sml}{%
   \begingroup%
   \let\sml@settick=\relax%
   \sml@verbatimmode%
   \catcode`\^^A=12%
   \long\def\sml@grab##1{\sml@startlexer{^^A}##1^^A\endgroup}%
   \sml@grab%
}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Set up the default keywords
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\smlSetupAllKeywords}
{  \smlNewKeyword{functor}
   \smlNewKeyword{structure}
   \smlNewKeyword{signature}
   \smlNewKeyword{struct}
   \smlNewKeyword{sharing}
   \smlNewKeyword{sig}
   \smlNewKeyword{include}
   \smlNewKeyword{fun}
   \smlNewKeyword{val}
   \smlNewKeyword{rec}
   \smlNewKeyword{type}
   \smlNewKeyword{datatype}
   \smlNewKeyword{case}
   \smlNewKeyword{of}
   \smlNewKeyword{and}
   \smlNewKeyword{where}
   \smlNewKeyword{withtype}
   \smlNewKeyword{end}
   \smlNewKeyword{let}
   \smlNewKeyword{in}
   \smlNewKeyword{end}
   \smlNewKeyword{handle}
   \smlNewKeyword{raise}
   \smlNewKeyword{exception}
   \smlNewKeyword{local}
   \smlNewKeyword{open}
   \smlNewKeyword{if}
   \smlNewKeyword{then}
   \smlNewKeyword{else}
   \smlNewKeyword{infix}
   \smlNewKeyword{infixr}
   \smlNewKeyword{nonfix}
}

\smlSetupAllKeywords

\endinput
