%
%	VDM documentstyle option for LaTeX
%
%	M. Wolczko 
%
%	Created from the ashes of VDM.tex and CBJ's vdm86.tex
%
%	Uses the AMS msym fonts if available: if you don't have them,
%	follow the instructions near the string FONT-CUSTOMIZING.
%
%	$Log:	vdm.doc,v $
%	Revision 2.5  88/03/25  18:52:29  mario
%	Improved use of AMS fonts.
%	Improved efficiency by eliminating unnecessary macros.
%	Enable line breaks after underscores in math mode.
%	Fixed used of penalties....were in wrong placeto have any effect.
%	Added \uniqueval, \cons, formbox environment, \R
%	Fixed composite environments so that they can be used in horizontal
%	mode.
%	Fixed a bug in the proof environment.
%
%	Revision 2.4  87/11/12  12:31:07  mario
%	Shortened lines for network mailers,
%	Changed mathcodes of digits,
%	Added \Rat, changed \DEF, added betweenFunctionAndPre hook,skip,
%	and penalty, added \Conc
%
%	Revision 2.3  87/02/26  11:36:07  miw
%	Absence of a blank line after \end{vdm} now forces \noindent.
%	Can now have pre- and post-conditions in function defns.
%	Added \mapinto macro.
%
%	Revision 2.2  86/12/18  12:00:17  miw
%	Added \@changeMathmodeCatcodes to \begin{vdm} to avoid as many
%	catcode problems with @ and _ as possible.
%	Fixed a bug in \If (was adding extra blank lines).
%	Added the \nexists macro.
%	Added the *-form of fn (which had been inadvertently omitted).
%	Fixed a bug in the proof environment (had a name clash with latex).
%	
%	Revision 2.1  86/11/24  13:08:34  miw
%	**** MAJOR REWRITE/EXTENSION ****
%	
%	Entry to the vdm env now is a no-op!
%	No mathcode changes to get the right letters in math mode.
%	Double quotes now delimit text in math mode.
%	\baselineskip within vdm mode is now \VDMbaselineskip.
%	Added the \amssy font.
%	Vertical VDM things (ops, fns, etc) shouldn't need blank lines
%	around them. 
%	Let the user choose whether some things are left- or right-aligned.
%	Added *-forms of quantifiers.
%	Added composite env and \scompose.
%	Added proof env.
%	
%	Revision 1.8  86/10/08  14:11:36  miw
%	Changed \or, \rd, \wr to \Or, \Rd, \Wr.
%	Changed keyword font to sans-serif.
%	Changed \makeNewKeyword to use \newcommand.
%	Added \where keyword.
%	Changed \Nat, \Int, \Bool, \Real to use `blackboard' font.
%	Added `Strachey brackets' using \term.
%	Added function composition, \compf.
%	Added a *-form to the fn environment to omit parens on args.
%	Added a *-form to \LambdaFn to place body on a new line.
%	Added \min and \max monadic operators.
%	Changed \serd and \busd to \rres and \rsub.
%	Added \const for constants.
%
%	Revision 1.7  86/08/14  17:52:32  miw
%	Fixed bugs in vdmfn and vdmop.
%	Moved the pre..Hooks in operations and functions to occur earlier
%	(allows one to change baselineskip).
%
%	Revision 1.6  86/06/03  12:23:05  miw
%	Added the formula env, and fixed a bug in \type.
%	
%	
%	Revision 1.5  86/05/07  17:51:48  miw
%	Parameterised more vertical skips.  Changed many dimensions from pts
%	to exs.  Fixed a bug in \type.  Altered externals so that field names
%	are flush right.
%	
%	Revision 1.4  86/04/17  11:09:04  miw
%	Tweaked some more.
%
%	Revision 1.3 86/03/14 20:44:22 miw
%	Added left margin control with \VDMindent.
%	Tweaked some penalties (esp. \hyphenpenalty)---first use of a
%	\discretionary in quantified expresssion.
%	Fixed a bug in IndentedPara (using box0 instead of copy0)
%	
%	Revision 1.2  86/03/12  16:26:23  miw
%	Changed the fn env. and \Cases.  Added \@raggedRight.
%	Fixed lots of other minor things.
%
%	Revision 1.1  86/03/03  18:42:40  miw
%	Initial revision
%
%
%	$Header: vdm.doc,v 2.5 88/03/25 18:52:29 mario Locked $
%
%
%
%----------------------------------------------------------------
%
%	Installation-dependent features
%
% FONT-CUSTOMIZING
\newif\ifams@
\ams@true  % change to \ams@false if you don't have the AMS fonts
%\ams@false  % change to \ams@true if you have the AMS fonts

\newif\ifps@ \ps@false % PostScript-based

\def\@fmtname{lplain}
\def\@psfmtname{pslplain}

\def\@testcmsy{\if@usecmsy \else 
  \@latexerr{Can't use vdm with this PSLaTeX}%
	{This PSLaTeX does not have the CMSY symbols
	available, and cannot be used with VDM style.  Get
	a guru to rebuild PSLaTeX with the CMSY and CMMI
	fonts included.}\fi}
\def\@testcmmi{\if@usecmmi \else
  \@latexerr{Can't use vdm with this PSLaTeX}%
	{This PSLaTeX does not have the CMMI symbols
	available, and cannot be used with VDM style.  Get
	a guru to rebuild PSLaTeX with the CMSY and CMMI
	fonts included.}\fi}

\ifx\fmtname\@fmtname % standard LaTeX is OK
\else \ifx\fmtname\@psfmtname \global\ps@true \@testcmsy \@testcmmi
      \else \ams@false \fi\fi % don't use AMS for SliTeX

\newfam\msxfam
\newfam\msyfam

\ifams@
	% this is lifted from amssymbols.sty
	\ifcase\@ptsize
	 \font\tenmsx=msxm10
	 \font\sevenmsx=msxm7
	 \font\fivemsx=msxm5
	 \font\tenmsy=msym10
	 \font\sevenmsy=msym7
	 \font\fivemsy=msym5
	\or
	 \font\tenmsx=msxm10 scaled \magstephalf
	 \font\sevenmsx=msxm8
	 \font\fivemsx=msxm6
	 \font\tenmsy=msym10 scaled \magstephalf
	 \font\sevenmsy=msym8
	 \font\fivemsy=msym6
	\or
	 \font\tenmsx=msxm10 scaled \magstep1
	 \font\sevenmsx=msxm8
	 \font\fivemsx=msxm6
	 \font\tenmsy=msym10 scaled \magstep1
	 \font\sevenmsy=msym8
	 \font\fivemsy=msym6
	\fi

	\textfont\msxfam=\tenmsx  \scriptfont\msxfam=\sevenmsx
	  \scriptscriptfont\msxfam=\fivemsx
	\textfont\msyfam=\tenmsy  \scriptfont\msyfam=\sevenmsy
	  \scriptscriptfont\msyfam=\fivemsy

	\def\hexnumber@#1{\ifnum#1<10 \number#1\else
	 \ifnum#1=10 A\else\ifnum#1=11 B\else\ifnum#1=12 C\else
	 \ifnum#1=13 D\else\ifnum#1=14 E\else
	 \ifnum#1=15 F\fi\fi\fi\fi\fi\fi\fi}
	\def\msx@{\hexnumber@\msxfam}
	\def\msy@{\hexnumber@\msyfam}
\fi

%----------------------------------------------------------------
%
%	The vdm environment
%
\def\vdm{\@changeMathmodeCatcodes\@postUnderPenalty10000 }

% after an \end{vdm} the next paragraph is not indented unless a \par
% comes first
\def\endvdm{\global\let\par=\@undonoindent
  \global\everypar={{\setbox0=\lastbox}\global\everypar={}%
			\global\let\par=\@@par}}

\def\@undonoindent{\global\everypar={}\global\let\par=\@@par\@@par}

%-----------------------------------------------------------------
%
% 	Controlling line and page breaks
% 
% Text within the vdm environment is essentially mathematical in
% nature, so requires special care.  Whenever outer vertical mode is
% entered, the \@beginVerticalVDM command should be used.  This sets
% up \leftskip, \rightskip, \baselineskip, \lineskip and
% \lineskiplimit to conform with the overall style.
%
% When entering unrestricted horizontal mode, the \@beginHorizontalVDM
% command should be used.  This sets up:
%	\leftskip and \rightskip to 0,
%	\\ to do line breaking
%	ragged right line breaking, with special penalties, and
%	enters math mode.
% \@endHorizontalVDM should be called when leaving unrestricted
% horizontal mode.

\def\@beginVerticalVDM{\@changeMargins\@changeBaselineskip}

\def\@beginHorizontalVDM{\@restoreLineSeparator
  \@restoreMargins\@raggedRight\noindent$\strut\relax}
\def\@endHorizontalVDM{\relax\strut$}

% \VDMindent is used for \leftskip within VDM, \VDMrindent for
% \rightskip, \VDMbaselineskip for \baselineskip
\newdimen\VDMindent \VDMindent=\parindent
\newdimen\VDMrindent \VDMrindent=\parindent
\def\VDMbaselineskip{\baselineskip}

\def\@changeMargins{\leftskip=\VDMindent \rightskip=\VDMrindent}
\def\@restoreMargins{\advance\hsize by-\leftskip
  \advance\hsize by-\rightskip
  \leftskip=0pt \rightskip=0pt}
\def\@changeBaselineskip{\baselineskip=\VDMbaselineskip
  \lineskip=0pt \lineskiplimit=0pt
  % need to alter the size of struts, too
  \setbox\strutbox\hbox{\vrule height.7\baselineskip
      depth.3\baselineskip width\z@}}

% these are used in externals, records and cases
\def\@changeLineSeparator{\let\\=\cr} % for usr within \halign
\def\@restoreLineSeparator{\let\\=\newline}

\def\@raggedRight{\rightskip=0pt plus 1fil
  \hyphenpenalty=-100 \linepenalty=200
  \binoppenalty=10000 \relpenalty=10000 \pretolerance=-1}

%------------------------------------------------------------------------
%
%	Font and Character Changes
%
% make a-zA-Z use the \it family within math mode, and ~ mean \hook.
% Digits 0-9 remain as normal.
\newcount\@mathFamily  \@mathFamily=\itfam
\everymath=\expandafter{\the\everymath\fam\@mathFamily
	\@changeMathmodeCatcodes}
\everydisplay=\expandafter{\the\everydisplay\fam\@mathFamily
	\@changeMathmodeCatcodes}
\mathcode`\0="0030
\mathcode`\1="0031
\mathcode`\2="0032
\mathcode`\3="0033
\mathcode`\4="0034
\mathcode`\5="0035
\mathcode`\6="0036
\mathcode`\7="0037
\mathcode`\8="0038
\mathcode`\9="0039

% If the user really wants the normal codes, she can call \defaultMathcodes
\def\defaultMathcodes{\@mathFamily=-1}

% make a : into punctuation, a - into a letter, and | mean \mid
\ifps@
 \def\@changeOtherMathcodes{\mathcode`\:="603A \mathcode`\-="002D
  \mathcode`\|="327C \mathchardef\Or="32DA % this is a rel to get 5mu spacing
  \mathcode`\f="0166} % normal letter spacing
\else
 \def\@changeOtherMathcodes{\mathcode`\:="603A \mathcode`\-="042D
  \mathcode`\|="326A \mathchardef\Or="325F }% this is a rel to get 5mu spacing
\fi

% alternative underscore
\def\@VDMunderscore{\leavevmode
  \kern.06em\vbox{\hrule\@height .2ex\@width .3em}\penalty\@postUnderPenalty
  \hskip 0.1em}

% Allow line breaks after an underscore, but not in vdm mode (see
% \vdm).  This is so long identifiers can be broken when run
% into paragraphs. 
\newcount\@postUnderPenalty \@postUnderPenalty=200

% now require some catcode trickery to enable us to change _ when we want to
{\catcode`\_=\active \catcode`\"=\active
 \gdef\@changeGlobalCatcodes{% make _ a normal char
	\catcode`\_=\active \let_=\@VDMunderscore}
 \gdef\@changeMathmodeCatcodes{%
	% make ~ mean \hook, " do text, @ mean subscript
	\let~=\hook
	\catcode`\@=8
	\catcode`\"=\active  \let"=\@mathText}
 \gdef\underscoreoff{% make _ a normal char
	\catcode`\_=\active \let_=\@VDMunderscore}
 \gdef\underscoreon{% restore underscore to usual meaning
	\catcode`\_=8}
 \gdef\@mathText#1"{\hbox{\mathTextFont #1\/}}}

\def\mathTextFont{\rm}

%----------------------------------------------------------------
%
%	Keywords
%
\ifx\fmtname\@fmtname
	\def\keywordFontBeginSequence{\small\sf}%	user-definable
\else\ifx\fmtname\@psfmtname
	\def\keywordFontBeginSequence{\sf}%	user-definable
\else
	\def\keywordFontBeginSequence{\bf}%	good for SliTeX
\fi\fi

\def\kw#1{\hbox{\keywordFontBeginSequence #1\/}}

\def\makeNewKeyword#1#2{% use \newcommand for extra checks
	\newcommand{#1}{\hbox{\keywordFontBeginSequence #2\/}}}

\makeNewKeyword{\nil}{nil}
\makeNewKeyword{\True}{true}
\makeNewKeyword{\true}{true}
\makeNewKeyword{\False}{false}
\makeNewKeyword{\false}{false}

\def\where{\par\moveright\VDMindent\hbox{\keywordFontBeginSequence where\/}}

%----------------------------------------------------------------
%
%	monadic operator creation
%
\def\newMonadicOperator#1#2{\newcommand{#1}{\kw{#2\kern.16667em}\nobreak}}

%----------------------------------------------------------------
%
%	primitive numeric types
%
% use the AMS fonts for these if possible

\ifams@
  \mathchardef\Bool="0\msy@42	% Booleans
  \mathchardef\Nat="0\msy@4E	% Natural numbers
  \def\Nati{\Nat_1}		% Positive natural numbers
  \mathchardef\Int="0\msy@5A	% Integers
  \mathchardef\Real="0\msy@52	% Reals
  \mathchardef\Rat="0\msy@51	% Rationals
\else
  \def\Bool{\hbox{\bf B\/}}
  \def\Nat{\hbox{\bf N\/}}
  \def\Nati{\hbox{$\hbox{\bf N}_1$}}
  \def\Int{\hbox{\bf Z\/}}
  \def\Real{\hbox{\bf R\/}}
  \def\Rat{\hbox{\bf Q\/}}
\fi
\let\Natone=\Nati % just for an alternative

%----------------------------------------------------------------
%
%	Operations
%
% The op environment.  Within op you can specify args,
% result, etc. which are gathered into registers, and output when the
% op env. ends.
%
% The optional argument is the operation name

% shorthand for an operation on its own: the vdmop env.
\def\vdmop{\vdm\op} \def\endvdmop{\endop\endvdm}

% registers constructed within an op environment
\newtoks\@operationName
\newbox\@operationNameBox
\newif\ifArgumentListEncountered@
\newtoks\@argumentListTokens
\newtoks\@resultNameAndTypeTokens
\newbox\@externalsBox
\newbox\@preConditionBox
\newbox\@postConditionBox

\def\op{% clear temporaries, deal with optional arg
	\setbox\@operationNameBox=\hbox{}
	\@argumentListTokens={} \ArgumentListEncountered@false
	\@resultNameAndTypeTokens={}
	\setbox\@externalsBox=\box\voidb@x
	\setbox\@preConditionBox=\box\voidb@x
	\setbox\@postConditionBox=\box\voidb@x
	\par\preOperationHook
	\vskip\preOperationSkip
	\@beginVerticalVDM
	\@ifnextchar [{\@opname}{}}

% breaking parameters
\newcount\preOperationPenalty \preOperationPenalty=0
\newcount\preExternalPenalty \preExternalPenalty=2000
\newcount\prePreConditionPenalty \prePreConditionPenalty=800
\newcount\prePostConditionPenalty \prePostConditionPenalty=500
\newcount\postOperationPenalty \postOperationPenalty=-500

% gaps between bits of operations
\newskip\preOperationSkip \preOperationSkip=2ex plus 0.5ex minus 0.2ex
\newskip\postOperationSkip \postOperationSkip=2ex plus 0.5ex minus 0.2ex
\newskip\postHeaderSkip \postHeaderSkip=.5ex plus .2ex minus .2ex
\newskip\postExternalsSkip \postExternalsSkip=.5ex plus .2ex minus .2ex
\newskip\postPreConditionSkip \postPreConditionSkip=.5ex plus .2ex minus .2ex

\def\endop{% make up operation
	% IMPORTANT---don't remove the vskips in this macro
	% if you don't want one, set it to 0pt
	\vskip 0pt
	\@setOperationHeader
	\betweenHeaderAndExternalsHook
	\vskip\postHeaderSkip
	\ifvoid\@externalsBox
	      \betweenExternalsAndPreConditionHook
	\else \moveright\VDMindent\box\@externalsBox
	      \betweenExternalsAndPreConditionHook
	      \vskip\postExternalsSkip
	\fi
	\ifvoid\@preConditionBox
	      \betweenPreAndPostConditionHook
	\else \moveright\VDMindent\box\@preConditionBox
	      \betweenPreAndPostConditionHook
	      \vskip\postPreConditionSkip
	\fi
	\ifvoid\@postConditionBox
	      \postOperationHook
	\else \moveright\VDMindent\box\@postConditionBox
	      \postOperationHook
	      \vskip\postOperationSkip
	\fi}

% hooks for user-defined expansion
% TeX is in outer vertical mode when these are called.
% ALWAYS leave TeX in vertical mode after these macros have been called
\def\preOperationHook{\penalty\preOperationPenalty }
\def\betweenHeaderAndExternalsHook{\penalty\preExternalPenalty }
\def\betweenExternalsAndPreConditionHook{\penalty\prePreConditionPenalty }
\def\betweenPreAndPostConditionHook{\penalty\prePostConditionPenalty }
\def\postOperationHook{\penalty\postOperationPenalty }

% combine the operation name, argument list and result
\def\@setOperationHeader{%
	\moveright\VDMindent\vtop{%
		\ifArgumentListEncountered@
			\setbox\@operationNameBox=
				\hbox{\unhbox\@operationNameBox\ $($}\fi
		\hangindent=\wd\@operationNameBox \hangafter=1
		\noindent\kern-.05em\box\@operationNameBox
		\@beginHorizontalVDM
		\ifArgumentListEncountered@\the\@argumentListTokens)\fi
		\ \the\@resultNameAndTypeTokens
		\@endHorizontalVDM}}

% set the operation name
% \opname{name-of-operation}
\def\opname#1{\@opname[#1]}
\def\@opname[#1]{\@operationName={#1}%
  \global\setbox\@operationNameBox=\hbox{$\relax#1$\ }}

% set up the argument list
% \args{ argument \\ argument \\ argument... } where \\ forces a line break
% This is also used in the fn environment
\def\args{\global\ArgumentListEncountered@true \global\@argumentListTokens=}

% result name and type
\def\res{\global\@resultNameAndTypeTokens=}

% externals list
%
% An external list could be either very long or very short, so we provide
% two forms.  One is the short \ext{..} command, the other is the externals 
% environment.
% Externals are always separated by \\
%

% we have to mess a little to get the catcode of : right
\def\ext{\bgroup\@makeColonActive\@ext}
\def\@ext#1{\externals#1\endexternals\egroup}

\def\externals{\global\setbox\@externalsBox=%
	\@beginIndentedPara{\hsize}{ext }{\@setUpExternals}}
\def\endexternals{\@endIndentedPara{\@endAlignment}}

\def\@setUpExternals{\@makeColonActive\@changeLineSeparator\@beginAlignment}

% more catcode trickery for :
{\catcode`\:=\active
 \gdef\@makeColonActive{\catcode`\:=\active \let:=&}}

% the \expandafters are necessary because TeX doesn't expand
% \halign specs when scanning for # and &
\def\@beginAlignment{\expandafter\halign\expandafter\bgroup
	\the\@extAlign\strut\enspace&:\enspace$##$\hfil\cr}
\def\@endAlignment{\crcr\egroup}

% the user can decide on the exact alignment of the field names
\newtoks\@extAlign
\def\leftExternals{\@extAlign={$##$\hfil}}
\def\rightExternals{\@extAlign={\hfil$##$}}
\leftExternals

\makeNewKeyword{\Rd}{rd } \makeNewKeyword{\Wr}{wr }

% pre-condition and post-condition
%
% once again we provide short forms \pre and \post, and environments
% precond and postcond
\def\pre#1{\precond#1\endprecond}
\def\precond{\global\setbox\@preConditionBox=%
	\@beginMathIndentedPara{\hsize}{pre }}
\def\endprecond{\@endMathIndentedPara}

\def\post#1{\postcond#1\endpostcond}
\def\postcond{\global\setbox\@postConditionBox=%
	\@beginMathIndentedPara{\hsize}{post }}
\def\endpostcond{\@endMathIndentedPara}


%----------------------------------------------------------------
%
%	Box man\oe uvres
%
% Here's where all the tricky box manipulation commands go
%
% \@beginIndentedPara begins construction of a \hbox of width #1
% which contains keyword #2 to the left of a para in a vtop.
% #3 is evaluated within the inner vtop.
% endIndentedPara closes the box off; its arg. is evaluated just
% before closing the box.
%
\def\@beginIndentedPara#1#2#3{\hbox to #1\bgroup \setbox0=\kw{#2}%
	\copy0 \strut \vtop\bgroup \advance\hsize by -\wd0 #3}
\def\@endIndentedPara#1{\strut#1\egroup\hss\egroup}

% \@beginMathIndentedPara places the para in vdm mode
\def\@beginMathIndentedPara#1#2{\@beginIndentedPara{#1}{#2}%
	{\@beginHorizontalVDM}}
\def\@endMathIndentedPara{\@endIndentedPara{\@endHorizontalVDM}}

% \@belowAndIndent#1#2 places #2 in a vbox below and to the right of #1
\def\@belowAndIndent#1#2{#1\hfil\break
	\@beginMathIndentedPara{\hsize}{\qquad}#2\@endMathIndentedPara}

%----------------------------------------------------------------
%
%	Constructions
%
% Here are all the standard constructions.
% The only tricky one is \cases.
% Those that construct a box must be made to make that box of 0 width,
% and force a line break immediately afterwards.

% \If mm-exp \Then mm-exp \Else mm-exp \Fi
% multi-line indented if-then-else
%
\def\If#1\Then#2\Else#3\Fi{\vtop{%
	\@beginMathIndentedPara{0pt}{if }#1\@endMathIndentedPara
	\@beginMathIndentedPara{0pt}{then }#2\@endMathIndentedPara
	\@beginMathIndentedPara{0pt}{else }#3\@endMathIndentedPara}}

% \SIf mm-exp \Then mm-exp \Else mm-exp \Fi
% single line if-then-else
\def\SIf#1\Then#2\Else#3\Fi{\hbox to 0pt{\vtop{\@beginHorizontalVDM
	\kw{if }\nobreak#1\penalty0\hskip 0.5em
	\kw{then }\nobreak#2\penalty-100\hskip 0.5em % break here OK
	\kw{else }\nobreak#3\@endHorizontalVDM}\hss}\hfil\break}

% \Let mm-exp \In mm-exp2
% multi-line let..in ; mm-exp2 is `curried'
\def\Let#1\In{\vtop{%
	\@beginMathIndentedPara{0pt}{let }#1\hskip 0.5em
	\kw{in}\@endMathIndentedPara}\hfil\break}

% \SLet mm-exp \In mm-exp
% single-line let..in
\def\SLet#1\In#2{\hbox to 0pt{\vtop{\@beginHorizontalVDM
	\kw{let }\nobreak#1\hskip 0.5em
	\kw{in }\penalty-200 #2\@endHorizontalVDM}\hss}\hfil\break}

% multi-line cases
% 
% \Cases{ selecting-mm-exp }
% from-case1 & to-case1 \\
% from-case2 & to-case2 \\
%	    ...
% from-casen & to-casen
% \Otherwise{ mm-exp }
% \Endcases[optional text for the rest of the line]

\newif\ifOtherwiseEncountered@
\newtoks\@OtherwiseTokens

\def\Cases#1{\hbox to 0pt\bgroup \vtop\bgroup
		\@beginMathIndentedPara{\hsize}{cases }\strut
			#1\hskip 0.5em\strut\kw{of}%
		\@endMathIndentedPara
		\bgroup % we might be in a nested case, so we have to
			% save the \Otherwise bits we might lose
		\OtherwiseEncountered@false \@changeLineSeparator 
		\@beginCasesAlignment}

% the user can decide on the exact alignment
\newtoks\@casesDef
\def\leftCases{\@casesDef={$##$\hfil}}
\def\rightCases{\@casesDef={\hfil$##$}}
\rightCases

% the \expandafters are necessary because TeX doesn't expand
% \halign specs when scanning for # and &
\def\@beginCasesAlignment{\expandafter\halign\expandafter\bgroup
	\the\@casesDef&$\,\rightarrow##$\hfil\cr}

\def\Otherwise{\global\OtherwiseEncountered@true \global\@OtherwiseTokens=}

\def\Endcases{\@endCasesAlignment \@setOtherwise \egroup \@setEndcases}
\def\@endCasesAlignment{\crcr\egroup}
\def\@setOtherwise{\ifOtherwiseEncountered@ % have an otherwise clause
	\@beginMathIndentedPara{\hsize}{otherwise }%
	\strut\the\@OtherwiseTokens\strut
	\@endMathIndentedPara
	\fi}

% must test for the optional arg to follow the end
\def\@setEndcases{\noindent
	\strut\kw{end}\@ifnextchar [{\@unbracket}{\@finalCaseEnd}}
\def\@unbracket[#1]{$#1$\@finalCaseEnd}
\def\@finalCaseEnd{\egroup\hss\egroup\hfil\break}

%----------------------------------------------------------------
%
%	special symbols

% defined as
\ifps@
 \def\DEF{\raise.5ex
	\hbox{\footnotesize\underline{$\mathchar"3\cmsy@34$}}}% a \triangle
\else
 \def\DEF{\raise.5ex
	\hbox{\footnotesize\underline{$\mathchar"3234$}}}% a \triangle
\fi

% cross product
\let\x=\times

%	logical connectives
%
\def\Iff{\penalty-50\mskip 7mu plus 2mu minus 2mu
	\Leftrightarrow\mskip 7mu plus 2mu minus 2mu}
\let\iff=\Iff
\def\Implies{\penalty-35\mskip 6mu plus 2mu minus 1mu \Rightarrow
	\mskip 6mu plus 2mu minus 1mu}
\let\implies=\Implies
% see changeOtherMathcodes for \Or
\let\And=\land
\let\and=\And
%  use \neg for logical not, or
\let\Not=\neg

%	quantification
%
\ifps@
 \mathchardef\Exists="0224
 \mathchardef\Forall="0222
 \mathchardef\suchthat="22D7
\else
 \mathchardef\Exists="0239
 \mathchardef\Forall="0238
 \mathchardef\suchthat="2201
\fi
\def\exists{\@ifstar{\@splitExists}{\@normalExists}}
\ifams@
  \mathchardef\@nexists="0\msy@40 % crossed out existential quantifier
\else
  \def\@nexists{\hbox to 0pt{\raise0.15ex\hbox{/}\hss}\Exists}
\fi
\def\nexists{\@ifstar{\@splitNExists}{\@normalNExists}}
\def\forall{\@ifstar{\@splitForall}{\@normalForall}}
\def\unique{\@ifstar{\@splitUnique}{\@normalUnique}}
\def\uniqueval{\@ifstar{\@splitUniqueval}{\@normalUniqueval}}

\def\@normalExists#1#2{{\Exists#1}\suchthat #2}
\def\@normalNExists#1#2{{\@nexists#1}\suchthat #2}
\def\@normalForall#1#2{{\Forall#1}\suchthat #2}
\def\@normalUnique#1#2{{\Exists!\,#1}\suchthat #2}
\def\@normalUniqueval#1#2{{\iota\,#1}\suchthat #2}

\def\@splitExists#1{\@belowAndIndent{\Exists#1\suchthat}}
\def\@splitNExists#1{\@belowAndIndent{\@nexists#1\suchthat}}
\def\@splitForall#1{\@belowAndIndent{\Forall#1\suchthat}}
\def\@splitUnique#1{\@belowAndIndent{\Exists!\,#1\suchthat}}
\def\@splitUniqueval#1{\@belowAndIndent{\iota\,#1\suchthat}}

%	strachey brackets
%
% (see TeXbook, p.437)
\def\term#1{[\mkern-\thinmuskip[#1\relax]\mkern-\thinmuskip]}

%	function composition
%
\let\compf=\circ

%----------------------------------------------------------------
%
%	function environment
%
% This environment is similar to the op environment, but is used for
% function definition.  
%
% The mandatory first parameter is the name of the function, the
% second is the argument list.
%
% The *-form simply doesn't force the parentheses round the argument list

\def\fn{\parens@true\@beginVDMfunction}
\@namedef{fn*}{\parens@false\@beginVDMfunction}
\@namedef{endfn*}{\endfn}

% short form
\def\vdmfn{\vdm\parens@true \@beginVDMfunction}
\def\endvdmfn{\endfn\endvdm}
\@namedef{vdmfn*}{\vdm\parens@false \@beginVDMfunction}
\@namedef{endvdmfn*}{\endfn\endvdm}

% registers used within the fn environment
\newtoks\@fnName
\newbox\@fnNameBox
\newif\ifsignatureEncountered@
\newtoks\@signatureTokens
\newbox\@fnDefnBox
\newif\ifparens@

\def\@beginVDMfunction#1#2{%
	\@fnName={#1}
	\setbox\@fnNameBox=\hbox{$#1$}%
	\setbox\@preConditionBox=\box\voidb@x % for people who want to do
	\setbox\@postConditionBox=\box\voidb@x% implicit defns
	\@signatureTokens={}\signatureEncountered@false
	\ifparens@
		\@argumentListTokens={(#2)}%
	\else
		\@argumentListTokens={#2}%
	\fi
	\par\preFunctionHook
	\vskip\preFunctionSkip
	\@beginVerticalVDM 
	\@beginFnDefn}

% read in a signature
\def\signature{\global\signatureEncountered@true \global\@signatureTokens=}

\def\@beginFnDefn{\global\setbox\@fnDefnBox=\vtop\bgroup
	\hangindent=2em \hangafter=1 \@beginHorizontalVDM
	\advance\hsize by-2em % this fools vboxes within the
	% function body about the hanging indent...yuk.
	% If you change the size of the indent, change the
	% corresponding line in \endfn.
	\copy\@fnNameBox \the\@argumentListTokens 
	\quad\DEF\penalty-100\quad }

\newskip\preFunctionSkip \preFunctionSkip=2ex plus .5ex minus .2ex
\newskip\postFunctionSkip \postFunctionSkip=2ex plus .5ex minus .2ex
\newskip\betweenSignatureAndBodySkip
\betweenSignatureAndBodySkip=1.2ex plus .3ex minus .2ex
\newskip\betweenFunctionAndPreSkip
\betweenFunctionAndPreSkip=1.2ex plus .3ex minus .2ex

\def\endfn{%
	\advance\hsize by 2em% matches the dirty \advance in \@beginFnDefn
	\@endHorizontalVDM
	\egroup  % this ends the vtop we started in \@beginFnDefn
	\ifsignatureEncountered@
		\setbox0=\hbox{\unhbox\@fnNameBox$\;\mathpunct:\,$}%
		\dimen255=\wd0 \noindent \box0
		\vtop{\advance\hsize by-\dimen255 \@beginHorizontalVDM
			\the\@signatureTokens \@endHorizontalVDM}\par
		\betweenSignatureAndBodyHook
		\vskip\betweenSignatureAndBodySkip
	\fi
	\moveright\VDMindent\box\@fnDefnBox
	\ifvoid\@preConditionBox
	      \betweenPreAndPostConditionHook
	      \vskip\postFunctionSkip
	\else \betweenFunctionAndPreHook
	      \vskip\betweenFunctionAndPreSkip
	      \moveright\VDMindent\box\@preConditionBox
	      \betweenPreAndPostConditionHook
	      \vskip\postPreConditionSkip
	\fi
	\ifvoid\@postConditionBox
	      \postFunctionHook
	\else \moveright\VDMindent\box\@postConditionBox
	      \postFunctionHook
	      \vskip\postOperationSkip
	\fi}

\newcount\preFunctionPenalty \preFunctionPenalty=0
\newcount\betweenSignatureAndBodyPenalty \betweenSignatureAndBodyPenalty=500
\newcount\betweenFunctionAndPrePenalty \betweenFunctionAndPrePenalty=1000
\newcount\postFunctionPenalty \postFunctionPenalty=-500

% These are called in outer vertical mode---they must also exit in this mode
\def\preFunctionHook{\penalty\preFunctionPenalty }
\def\betweenSignatureAndBodyHook{\penalty\betweenSignatureAndBodyPenalty }
\def\betweenFunctionAndPreHook{\penalty\betweenFunctionAndPrePenalty }
\def\postFunctionHook{\penalty\postFunctionPenalty }

%	other function-related things
%

% function arrow
\def\to{\penalty-100\rightarrow}

% explicit lamdba function
\def\LambdaFn{\@ifstar{\@splitLambdaFn}{\@normalLambdaFn}}
\def\@normalLambdaFn#1#2{{\lambda#1}\suchthat#2}
\def\@splitLambdaFn#1#2{% place body in a separate box below and to the right
	{\lambda#1}\suchthat\hfil\break
	\@beginMathIndentedPara{\hsize}{\qquad}#2\@endMathIndentedPara}

%----------------------------------------------------------------
%
%	Sets

% new set type
\def\setof#1{\kw{set of }#1}

% set enumeration
\def\set#1{\{#1\}}

% empty set
\def\emptyset{\{\,\}}

% usual LaTeX operators apply: \in \notin \subset \subseteq
\let\inter=\cap \let\intersection=\inter
\let\Inter=\bigcap \let\Intersection=\Inter
\let\union=\cup
\let\Union=\bigcup
\ifps@
 \mathchardef\minus="222D
\else
 \mathchardef\minus="2200
\fi
\def\diff{\minus} \let\difference=\diff

\newMonadicOperator{\card}{card}
\newMonadicOperator{\Min}{min}
\newMonadicOperator{\Max}{max}

%----------------------------------------------------------------
%
% 	Map type

% new map type
\def\mapof#1#2{\kw{map }\nobreak#1\penalty-50\hskip .3em \kw{to }\nobreak#2}

% one-one map
\def\mapinto#1#2{\kw{map }\nobreak#1\penalty-50
	\hskip .3em \kw{into }\nobreak#2}

% map enumeration
\def\map#1{\{#1\}}

% empty map
\def\emptymap{\{\,\}}

%	map operators
%
% use \mapsto for |->
% overwrite
\def\owr{\dagger}

\ifams@
  % domain restriction
  \mathchardef\dres="2\msx@43
  % range restriction
  \mathchardef\rres="2\msx@42 % the right hand version
\else % for those without AMS fonts
  \let\dres=\lhd
  \let\rres=\rhd
\fi

% domain subtraction
\ifps@
 \def\dsub{\mathbin{\hbox{$\rlap{$\mathord\minus$}\mkern-1.5mu\dres$}}}
\else
 \def\dsub{\mathbin{\hbox{$\rlap{$\mathord\minus$}\mkern-1.5mu
	\lower.1ex\hbox{$\dres$}$}}}
\fi

% range subtraction
\ifps@
 \def\rsub{\mathbin{\hbox{$\rlap{$\mathord\minus$}\mkern-1.5mu\rres$}}}
\else
 \def\rsub{\mathbin{\hbox{$\rlap{$\mathord\minus$}\mkern-1.5mu
	\lower.1ex\hbox{$\rres$}$}}}
\fi

\newMonadicOperator{\dom}{dom}
\newMonadicOperator{\rng}{rng}

%----------------------------------------------------------------
%
%	Sequences
%

% new type
\def\seqof#1{\kw{seq of }#1}

% enumeration
\def\seq#1{[#1]}

% empty sequence
\def\emptyseq{[\,]}

\newMonadicOperator{\len}{len}
\newMonadicOperator{\hd}{hd}
\newMonadicOperator{\tl}{tl}
\newMonadicOperator{\elems}{elems}
\newMonadicOperator{\inds}{inds}
\def\cons#1{\kw{cons}\nobreak(#1)}

% sequence concatenation
\ifams@
  \mathchardef\sconc="2\msy@79
\else
  % this is truly yukky
  \def\sconc{\mathbin{\hbox{\raise1ex\hbox{$\frown$}\kern-0.47em
	\raise0.2ex\hbox{\it\char"12}}}}
\fi

% distributed concatenation
\newMonadicOperator{\Conc}{conc}

%----------------------------------------------------------------
%
%	type equation
%
\newtoks\@typeName
\def\type#1#2{{\@typeName{#1} \preTypeHook \vskip\preTypeSkip
	\@beginVerticalVDM
	\moveright\VDMindent\vtop{\@beginHorizontalVDM #1=#2
		\@endHorizontalVDM}
	\postTypeHook \vskip\postTypeSkip}}

\def\preTypeHook{} \def\postTypeHook{}
\newskip\preTypeSkip \preTypeSkip=1.2ex plus .5ex minus .3ex
\newskip\postTypeSkip \postTypeSkip=1.2ex plus .5ex minus .3ex

%----------------------------------------------------------------
%
%	Composite Objects
%

% literal composition; we have a compose and a composite env.

% single line compose
\@namedef{composite*}#1{\kw{compose }$\relax#1\relax$\kw{ of }$\relax}
\@namedef{endcomposite*}{\relax$\kw{ end}}

% multiple line version
\def\composite#1{\bgroup\vskip\preCompositeSkip
    \@beginVerticalVDM
    \moveright\VDMindent\vtop\bgroup
	\@beginHorizontalVDM
	\kw{compose }#1\kw{ of}%\hfil\break
	\@endHorizontalVDM
	\@makeColonActive\@changeLineSeparator
	\expandafter\halign\expandafter\bgroup\expandafter\qquad
		\the\@recordAlign\strut\enspace&:\enspace$##$\hfil\cr}
\def\endcomposite{\crcr\egroup % closes \halign
	\kw{end}\egroup % ends the \vtop
	\vskip\postCompositeSkip\egroup}

\def\scompose#1#2{\@nameuse{composite*}{#1}{#2}\@nameuse{endcomposite*}}

\newskip\preCompositeSkip \preCompositeSkip=1.2ex plus .5ex minus .3ex
\newskip\postCompositeSkip \postCompositeSkip=1.2ex plus .5ex minus .3ex

% record composites; likewise we have a short and a long form
\newtoks\@recordName

\def\record#1{\@recordName{#1}
  \par\preRecordHook
  \vskip\preRecordSkip
  \@beginVerticalVDM
  \moveright\VDMindent\hbox\bgroup
	  \setbox0=\hbox{$#1$\enspace::\enspace}%
	  \@makeColonActive\@changeLineSeparator
	  \advance\hsize by-\wd0 \box0
	  \@restoreMargins
	  %
	  % the \expandafters are necessary because TeX doesn't expand
	  % \halign specs when scanning for # and &
	  \vtop\bgroup\expandafter\halign\expandafter\bgroup
		  \the\@recordAlign\strut\enspace&:\enspace$##$\hfil\cr}

\def\endrecord{\crcr\egroup% closes halign
	\egroup% closes vtop
	\egroup% closes hbox
	\par\postRecordHook
	\vskip\postRecordSkip}

% the user can decide on the exact alignment of the field names
\newtoks\@recordAlign
\def\leftRecord{\@recordAlign={$##$\hfil}}
\def\rightRecord{\@recordAlign={\hfil$##$}}
\rightRecord

% more catcode trickery
\def\defrecord{\bgroup\@makeColonActive\@defrecord}
\def\@defrecord#1#2{\record{#1}#2\endrecord\egroup}

\newskip\preRecordSkip \preRecordSkip=.75ex plus .3ex minus .2ex
\newskip\postRecordSkip \postRecordSkip=.75ex plus .3ex minus .2ex
\newcount\preRecordPenalty \preRecordPenalty=0
\newcount\postRecordPenalty \postRecordPenalty=-100
\def\preRecordHook{\penalty\preRecordPenalty }
\def\postRecordHook{\penalty\postRecordPenalty }

% \chg: mu function on composites
\def\chg#1#2#3{\mu(#1,#2\mapsto#3)}

%----------------------------------------------------------------
%
%	Hooks
%
% hooked identifiers --- these are taken from the TeXbook, p.357, 359
\ifps@
 \def\leftharpoonupfill{$\m@th \mathord\leftharpoonup \mkern-6mu
  \cleaders\hbox{$\mkern-2mu \mathchar"0\cmsy@00 \mkern-2mu$}\hfill
  \mkern-6mu \mathchar"0\cmsy@00$}  % p.357, \leftarrowfill
\else
 \def\leftharpoonupfill{$\m@th \mathord\leftharpoonup \mkern-6mu
  \cleaders\hbox{$\mkern-2mu \mathord\minus \mkern-2mu$}\hfill
  \mkern-6mu \mathord\minus$}  % p.357, \leftarrowfill
\fi
\def\overleftharpoonup#1{{%
  \boxmaxdepth=\maxdimen % this fixes Lamport's figures, but isn't necessary
  			 % for versions after 15 Dec 87
  \vbox{\ialign{##\crcr % p.359, \overleftarrow
    \leftharpoonupfill\crcr\noalign{\kern-\p@\nointerlineskip}
    $\hfil\displaystyle{#1}\hfil$\crcr}}}}

\let\hook=\overleftharpoonup  % c'est simple comme bonjour

%-----------------------------------------------------------------
%
% 	General formula environment, a bit like \[ \] but is
%	indented to \VDMindent and will take \\
%
%
\def\form#1{\formula #1\endformula}

\def\formula{\par\preFormulaHook
	\vskip\preFormulaSkip
	\@beginVerticalVDM
	\bgroup
	\moveright\VDMindent\vtop\bgroup\@beginHorizontalVDM}
\def\endformula{\@endHorizontalVDM\egroup % ends the vtop
	\egroup % ends the overall group
	\par\postFormulaHook
	\vskip\postFormulaSkip}

\newskip\preFormulaSkip \preFormulaSkip=1.2ex plus .5ex minus .3ex
\newskip\postFormulaSkip \postFormulaSkip=1.2ex plus .5ex minus .3ex
\newcount\preFormulaPenalty \preFormulaPenalty=0
\newcount\postFormulaPenalty \postFormulaPenalty=-100
\def\preFormulaHook{\penalty\preFormulaPenalty }
\def\postFormulaHook{\penalty\postFormulaPenalty }

%----------------------------------------------------------------
%
%	Formula within a box, when width is unknown
%
%	equivalent to \parbox[t]{\hsize}{\@beginHorizontalVDM
%		...\@endHorizontalVDM}
%
\def\formbox{\vtop\bgroup\@beginHorizontalVDM}
\def\endformbox{\strut\@endHorizontalVDM\egroup}

%----------------------------------------------------------------
%
%	special font for constants
%
\def\constantFont{\sc}
\def\const#1{\hbox{\constantFont #1\/}}

%----------------------------------------------------------------
%
%	line break and indent
%
\def\T#1{\\\hbox to #1em{}}

%----------------------------------------------------------------
%
%	line break and push line after to RHS
%
\def\R{\\\hspace*{\fill}}

%----------------------------------------------------------------
%
%	Proofs
%
% a proof environment for typesetting proofs in the "natural
% deduction" style.

\newdimen\ProofIndent \ProofIndent=\VDMindent
\newdimen\ProofNumberWidth \ProofNumberWidth=\parindent

\def\proof{\par\preProofHook
	\vskip\preProofSkip
	\let\&=\@proofLine
	\moveright\ProofIndent\vtop\bgroup
		\@indentLevel=1
		\advance\linewidth by-\ProofIndent
		\begin{tabbing}%
		\hbox to\ProofNumberWidth{}\=\kill}	% template line
\def\endproof{\end{tabbing}\advance\linewidth by\ProofIndent
	\egroup % ends the \vtop
	\par\postProofHook
	\vskip\postProofSkip}

\newskip\preProofSkip \preProofSkip=1.2ex plus .5ex minus .3ex
\newskip\postProofSkip \postProofSkip=1.2ex plus .5ex minus .3ex

\newcount\preProofPenalty \preProofPenalty=-100
\newcount\postProofPenalty \postProofPenalty=0
\def\preProofHook{\penalty\preProofPenalty }
\def\postProofHook{\penalty\postProofPenalty }

\def\From{\@indentProof\kw{from }\=%
	\global\advance\@indentLevel by 1
	\@enterMathMode}
\def\Infer{\global\advance\@indentLevel by-1
	\@indentProof\kw{infer }\@enterMathMode}
\def\@proofLine{\@indentProof\@enterMathMode}
\def\by{\`}

\newcount\@indentLevel
\newcount\@indentCount
\def\@indentProof{% do \>, \@indentLevel times
	\global\@indentCount=\@indentLevel
	\@gloop \>\global\advance\@indentCount by-1
	\ifnum\@indentCount>0
	\repeat}

% need special loop macros that works in across boxes
\def\@gloop#1\repeat{\gdef\@body{#1}\@giterate}
\def\@giterate{\@body \global\let\@gloopNext=\@giterate
	\else \global\let\@gloopNext=\relax \fi \@gloopNext}

% this enters math mode and sets the LaTeX macros \@stopfield up
% to exit math mode
\def\@enterMathMode{\def\@stopfield{$\egroup}$}

%----------------------------------------------------------------
\def\VDMauthor{M.Wolczko,
CS Dept.,
Univ. of Manchester, UK. 
mario@uk.ac.man.cs.ux
mcvax!man.cs.r5!mario}

\def\VDMversion{2.5}

\typeout{vdm style option <25 Mar 88>}
%----------------------------------------------------------------
%
%	Global changes
%
% All things that have to be invoked before the user's stuff appears
% should go here.
%
% by default the math spacing and changes to @ and _ apply everywhere
\@changeOtherMathcodes \@changeGlobalCatcodes
%
%-------------------the end--------------------------------------
\endinput
%
%	Summary of penalties
%
%	Penalties in vertical mode
%
% \preOperationPenalty		before an op begins
% \preExternalPenalty		between the header and externals of an op
% \prePreConditionPenalty	before the precondition
% \prePostConditionPenalty	before the postcondition
% \postOperationPenalty		at the end of an op
%
% \preFunctionPenalty		before a fn begins
% \betweenSignatureAndBodyPenalty 
% \postFunctionPenalty		after a fn ends
%
% \preRecordPenalty		before a record
% \postRecordPenalty		after a record
%
%	etc for formula, proof
%
%	Penalties in horizontal mode in boxes
%
% \linepenalty			101		\@raggedRight
% `if mm-exp ^ then..'		0		\SIf
% `if ... then mm-exp ^ else'	-100		\SIf
% `let mm-exp in ^ ...'		-200		\SLet
% `map mm-exp ^ to ...'		-50		\map
% ^\iff				-50		\iff
% ^\implies			-35		\implies
% func(args) \DEF^		-100		\begin{fn}
% \binoppenalty			10000
% \relpenalty			10000
% \hyphenpenalty		-100		\suchthat
% ^\to				-100		\to
% _^				100		\@VDMunderscore
%
