diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/stex/modules.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/stex/modules.dtx | 1054 |
1 files changed, 1054 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/stex/modules.dtx b/Master/texmf-dist/source/latex/stex/modules.dtx new file mode 100644 index 00000000000..3f9f8e46d86 --- /dev/null +++ b/Master/texmf-dist/source/latex/stex/modules.dtx @@ -0,0 +1,1054 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (C) 2004-2006 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The development version of this file can be found at +% https://svn.kwarc.info/repos/kwarc/projects/stex/sty/modules.dtx +% \fi +% +% \iffalse +%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%<package>\ProvidesPackage{modules}[2006/01/13 v0.9a Semantic Markup] +% +%<*driver> +\documentclass{ltxdoc} +\usepackage{url,array,modules,float} +\usepackage[show]{ed} +\usepackage{hyperref} +\makeindex +\floatstyle{boxed} +\newfloat{exfig}{thp}{lop} +\floatname{exfig}{Example} +\begin{document}\DocInput{modules.dtx}\end{document} +%</driver> +% \fi +% +% \CheckSum{539} +% +% \changes{v0.9}{2005/06/14}{First Version with Documentation} +% \changes{v0.9a}{2005/07/01}{Completed Documentation} +% \changes{v0.9b}{2005/08/06}{Complete functionality and Updated Documentation} +% \changes{v0.9c}{2006/01/13}{more packaging} +% \changes{v0.9d}{2007/12/12}{fixing double loading of .tex and .sms} +% +% \GetFileInfo{modules.sty} +% +% \MakeShortVerb{\|} +%\def\scsys#1{{{\sc #1}}\index{#1@{\sc #1}}} +% \def\stex{{\raisebox{-.5ex}S\kern-.5ex\TeX}} +% \def\sTeX{\stex} +% \def\xml{\scsys{Xml}} +% \def\mathml{\scsys{MathML}} +% \def\omdoc{\scsys{OMDoc}} +% \def\openmath{\scsys{OpenMath}} +% \def\latexml{\scsys{LaTeXML}} +% \def\perl{\scsys{Perl}} +% \def\cmathml{Content-{\sc MathML}\index{Content {\sc MathML}}\index{MathML@{\sc MathML}!content}} +% \def\activemath{\scsys{ActiveMath}} +% \def\twin#1#2{\index{#1!#2}\index{#2!#1}} +% \def\twintoo#1#2{{#1 #2}\twin{#1}{#2}} +% \def\atwin#1#2#3{\index{#1!#2!#3}\index{#3!#2 (#1)}} +% \def\atwintoo#1#2#3{{#1 #2 #3}\atwin{#1}{#2}{#3}} +% \title{Semantic Macros and Module Scoping in {\stex}\thanks{Version {\fileversion} (last revised +% {\filedate})}} +% \author{Michael Kohlhase \& Rares Ambrus\\ +% Jacobs University, Bremen\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +% \begin{abstract} +% The |modules| packge is a central part of the {\stex} collection, a version of +% {\TeX/\LaTeX} that allows to markup {\TeX/\LaTeX} documents semantically without +% leaving the document format, essentially turning {\TeX/\LaTeX} into a document format +% for mathematical knowledge management (MKM). +% +% This package supplies a definition mechanism for semantic macros and a non-standard +% scoping construct for them, which is oriented at the semantic depency relation rather +% than the document structure. This structure can be used by MKM systems for +% added-value services, either directly from the {\sTeX} sources, or after translation. +% \end{abstract} +%\newpage +% \section{Introduction}\label{sec:intro} +% +% Following general practice in the {\TeX/\LaTeX} community, we use the term ``semantic +% macro'' for a macro whose expansion stands for a mathematical object, and whose name +% takes up the name of the mathematical object. This can range from simple definitions +% like |\def\Reals{{\mathbb R}}| for indivicual mathematical objects to more complex +% (functional) ones object constructors like +% |\def\SmoothFunctionsOn#1{{\cal{C}}^\infty(#1)}|. Semantic macros are traditionally used +% to make {\TeX/\LaTeX} code more portable. However, the {\TeX/\LaTeX} scoping model +% (macro definitions are scoped either in the local group or until the rest of the +% document), does not mirror mathematical practice, where notations are scoped by +% mathematical environments like statements, theories, or such. +% +% \section{The User Interface} +% +% The main contributions of the |modules| package are the |module| environment, which +% allows for lexical scoping of semantic macros with inheritance and the |\symdef| macro +% for declaration of semantic macros that underly the |module| scoping. +% +% \subsection{Modules}\label{sec:modules} +% +% \DescribeEnv{module} The |module| environment takes an optional |KeyVal| +% argument. Currently, only the |id| key is supported for specifying the identifier of a +% module (also called the {\twintoo{module}{name}}). +% +% \DescribeMacro{\importmodule} A module introduced by |\begin{module}[id=foo]| restricts +% the scope the semantic macros defined by the |\symdef| form to the end of this module +% given by the corresponding |\end{module}|, and to any other |module| environments that +% import them by a |\importmodule{foo}| directive. If the module |foo| contains +% |\importmodule| directives of its own, these are also exported to the importing +% module. Thus |\importmodule| induces the {\atwintoo{semantic}{inheritance}{relation}} +% and |usesqualified|\ednote{do an importqualified as well} for macros imported with a +% prefix (this is used whenever we have conflicting names for macros inherited from +% different modules). +% +% \subsection{Semantic Macros}\label{sec:symdef} +% +% \DescribeMacro{\symdef}A call to the |\symdef| macro has the general form +% \begin{quote} +% |\symdef[|\meta{keys}|]{|\meta{cseq}|}[|\meta{args}|]{|\meta{definiens}|}| +% \end{quote} +% where {\meta{cseq}} is a control sequence (the name of the semantic macro) {\meta{args}} +% is a number between 0 and 9 for the number of arguments {\meta{definiens}} is the token +% sequence used in macro expansion for {\meta{cseq}}. Finally {\meta{keys}} is a keyword +% list that further specifies the semantic status of the defined macro. +% +% A key |local| can be added to {\meta{keys}} to specify that the symbol is local to the +% module and is invisible outside. The key-value pair |aliases=|\meta{symname} specifies +% that the defined symbol {\meta{cseq}} is a presentational variant of the symbol +% {\meta{symname}}. +% +% Finallly, the keys |cmml|, |cattrs|, and |definitionURL| can be used to specify the +% {\cmathml} encoding of the symbols. They key-value pair |cmml=|\meta{elt} specifies that +% the semantic macro corresponds to the {\cmathml} element with the name \meta{elt}, +% |cattrs=|\meta{attrtring} its argument string and |definitionURL| allows to specify the +% |definitionURL| attribute on that element. The most common case will be a symbol +% definition of the following form: +% +% \begin{quote} +% |\symdef[cmml=csymbol,definitionURL=|\meta{URI}|]{|\meta{cseq}|}[|\meta{args}|]{|\meta{definiens}|}| +% \end{quote} +% +% where \meta{URI} is the URI pointing to the location of the {\xml} file generated from +% the current {\LaTeX} file. +% +% \DescribeMacro{\abbrdef}The |\abbrdef| macro is a variant of |\symdef| that is only +% different in semantics, not in presentation. An abbreviative macro is like a semantic +% macro, and underlies the same scoping and inheritance rules, but it is just an +% abbreviation that is meant to be expanded, it does not stand for an atomic mathematical +% object. +% +% We will use a simple module for natural number arithmetics as a running example. It +% defines exponentiation and summation as new concepts while drawing on the basic +% operations like $+$ and $-$ from {\LaTeX}. In our example, we will define a semantic +% macro for summation |\Sumfromto|, which will allow us to express an expression like +% $\sum{i=1}^nx^i$ as |\Sumfromto{i}1n{2i-1}| (see Example~\ref{fig:semmodule} for an +% example). In this example we have also made use of a local semantic symbol for $n$, +% which is treated as an arbitrary (but fixed) symbol. +% +% \begin{module}[id=arith] +% \symdef{Sumfromto}[4]{\sum_{#1=#2}^{#3}{#4}} +% \symdef[local]{arbitraryn}{n} +% +%\begin{exfig} +% \begin{verbatim} +% \begin{module}[id=arith] +% \symdef{Sumfromto}[4]{\sum_{#1=#2}^{#3}{#4}} +% \symdef[local]{arbitraryn}{n} +% What is the sum of the first $\arbitraryn$ odd numbers, i.e. +% $\Sumfromto{i}1\arbitraryn{2i-1}?$ +% \end{module} +% \end{verbatim} +% \vspace{-2em}is formatted by {\sTeX} to \medskip\par\noindent +% What is the sum of the first $\arbitraryn$ odd numbers, i.e. +% $\Sumfromto{i}1\arbitraryn{2i-1}?$ +% \caption{Semantic Markup in a {\tt{module}} context}\label{fig:semmodule} +% \end{exfig} +% \end{module} +% +% \subsection{Dealing with multiple Files}\label{sec:user:multiple} +% +% The infrastructure presented above works well if we are dealing with small files or +% small collections of modules. In reality, collections of modules tend to grow, get +% re-used, etc, making it much more difficult to keep everything in one file. This general +% trend towards increasing enthropy is aggravated by the fact that modules are very +% self-contiained objects that are ideal for re-used. Therefore in the absence of a +% content management system for {\LaTeX} document (fragments), module collections tend to +% develop towards the ``one module one file'' rule, which leads to situations with lots +% and lots of little files. +% +% Moreover, most mathematical documents are not self-contained, i.e. they do not build up +% the theory from scratch, but pre-suppose the knowledge (and notation) from other +% documents. In this case we want to make use of the semantic macros from these +% prerequisite documents without including their text into the current document. One way +% to do this would be to have {\LaTeX} read the prerequisite documents without producing +% output. For efficiency reasons, {\stex} chooses a different route. It comes with a +% utility |sms| (see Section~\ref{sec:utilities}) that exports the modules and macros +% defined inside them from a particular document and stores them inside |.sms| files. This +% way we can avoid overloading LaTeX with useless information, while retaining the +% important information which can then be imported in a more efficient way. +% +% \DescribeMacro{\importmodule} For such situations, the |\importmodule| macro can be +% given an optional first argument that is a path to a file that contains a path to the +% module file, whose module definition (the |.sms| file) is read. Note that the +% |\importmodule| macro can be used to make module files truly self-contained. To arrive +% at a file-based content management system, it is good practice to reuse the module +% identifiers as module names and to prefix module files with corresponding +% |\importmodule| statements that pre-load the corresponing module files. +% +%\begin{exfig} +% \begin{verbatim} +% \begin{module}[id=foo] +% \importmodule[../other/bar]{bar} +% \importmodule[../mycolleaguesmodules]{baz} +% \importmodule[../other/bar]{foobar} +% ... +% \end{module} +% \end{verbatim} +% \vspace{-1.7em} +% \caption{Self-contained Modules via {\tt{importmodule}}}\label{exf:importmodule} +% \end{exfig} +% +% In Example~\ref{exf:importmodule}, we have shown the typical setup of a module +% file. The |\importmodule| macro takes great care that files are only read once, as +% {\sTeX} allows multiple inheritance and this setup would lead to an exponential (in the +% module inheritance depth) number of file loads. +% +% Note that the recursive (depth-first) nature of the file loads induced by this setup is +% very natural, but can lead to problems with the depth of the file stack in the {\TeX} +% formatte (it is usually set to something like 15). Therefore, it may be necessary to +% circumvent the recursive load pattern providing (logically spurious) |\importmodule| +% commands. Consider for instance module |bar| in Example~\ref{exf:importmodule}, say that +% |bar| already has load deph 15, then we cannot naivedly import it in this way. If module +% |bar| depended say on a module |base| on the critical load path, then we could add a +% statement \DescribeMacro{\requiremodules} |\requiremodules{../base}| in the second +% line. This would load the modules from |../base.sms| in advance (uncritical, since it +% has load depth 10), so that it would not have to be re-loaded in the critical path of +% the module |foo|. Solving the load depth problem. +% +% \subsection{Including Externally Defined Semantic Macros } +% +% In some cases, we use an existing {\LaTeX} macro package for typesetting objects that +% have a conventionalized mathematical meaning. In this case, the macros are ``semantic'' +% even though they have not been defined by a |\symdef|. This is no problem, if we are +% only interested in the {\LaTeX} workflow. But if we want to e.g. transform them to +% {\omdoc} via {\latexml}, the {\latexml} bindings will need to contain references to an +% {\omdoc} theory that semantically correponds to the {\LaTeX} package. In particular, +% this theory will have to be imported in the generated {\omdoc} file to make it +% {\omdoc}-valid. +% + +% \DescribeMacro{\requirepackage} To deal with this situation, the |modules| package +% provides the |\requirepackage| macro. It takes two arguments: a package name, and a URI +% of the corresponing {\omdoc} theory. In the {\LaTeX} workflow this macro behaves like a +% |\usepackage| on the first argument, except that it can --- and should --- be used +% outside the {\LaTeX} preamble. In the {\latexml} workflow, this loads the {\latexml} +% bindings of the package specified in the first argument and generates an appropriate +% |imports| element using the URI in the second argument. +% +% \StopEventually{\ednotemessage} +% +% \section{The Implementation} +% +% We declare some switches which will modify the behavior accoring to the package +% options. Generally, an option |xxx| will just set the appropriate switches to true +% (otherwise they stay false). +% \begin{macrocode} +%<*package> +\newif\ifmod@env\mod@envfalse +\newif\ifmod@id\mod@idfalse +\newif\ifmod@display\mod@displayfalse +\newif\ifmod@uses\mod@usesfalse +\newif\ifmod@usesqualified\mod@usesqualifiedfalse +\DeclareOption{env}{\mod@envtrue} +\DeclareOption{id}{\mod@idtrue} +\DeclareOption{uses}{\mod@usestrue} +\DeclareOption{display}{\mod@displaytrue} +\DeclareOption{usesqualified}{\mod@usesqualifiedtrue} +% \end{macrocode} +% Now, we define two collective options, which are equivalent to turning on all the other +% options. +% \begin{macrocode} +\def\modtrue{\mod@idtrue\mod@usestrue\mod@displaytrue\mod@usesqualifiedtrue} +\DeclareOption{draft}{\modtrue} +\DeclareOption{all}{\modtrue} +% \end{macrocode} +% Finally, we need to declare the end of the option declaration section to {\LaTeX}. +% \begin{macrocode} +\ProcessOptions +%</package> +% \end{macrocode} +% +% {\latexml} does not support module options yet, so we do not have to do anything here +% for the {\latexml} bindings. We only set up the {\perl} packages (and tell {\tt{emacs}} +% about the appropriate mode for convenience +% +% The next measure is to ensure that the |KeyVal| package is loaded (in the right +% version). for {\latexml}, we also initialize the package inclusions. +% \begin{macrocode} +%<package>\RequirePackage{keyval}[1997/11/10] +%<*ltxml> +# -*- CPERL -*- +package LaTeXML::Package::Pool; +use strict; +use LaTeXML::Global; +use LaTeXML::Package; +RequirePackage('keyval'); +%</ltxml> +% \end{macrocode} +% +% \subsection{Modules}\label{sec:impl:modules} +% +% We define the keys for the |module| environment and the actions that are undertaken, +% when the keys are encountered. +% +% \begin{macro}{module:cd} +% This |KeyVal| key is only needed for {\latexml} at the moment; use this to specify a +% content dictionary name that is different from the module name. +% \begin{macrocode} +%<package>\define@key{module}{cd}{} +%<*ltxml> +DefKeyVal('Module','cd','Semiverbatim'); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{module:id} +% For a module with |[id=name]|, we create a macro |\module@defs@name| and initialize +% it. Furthermore, we save the name in |\mod@id|. +% \begin{macrocode} +%<*package> +\define@key{module}{id}{% + \edef\this@module{\expandafter\noexpand\csname module@defs@#1\endcsname}% + \edef\this@qualified@module{\expandafter\noexpand\csname module@defs@qualified@#1\endcsname}% + \global\@namedef{module@defs@#1}{} + \global\@namedef{module@defs@qualified@#1}{} + \def\mod@id{#1}} +%</package> +%<*ltxml> +DefKeyVal('Module','id','Semiverbatim'); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{module} +% finally, we define the begin module command for the module environment. All the work +% has already been done in the keyval bindings, so this is very simple. +% \begin{macrocode} +%<package>\newenvironment{module}[1][]{\setkeys{module}{#1}\ifmod@env\show@mod@keys{module}\fi}{} +% \end{macrocode} +% for the {\latexml} bindings, we have to do the work all at once. +% \begin{macrocode} +%<*ltxml> +DefEnvironment('{module} OptionalKeyVals:Module', + "?#excluded()(<omdoc:theory ?&KeyVal(#1,'id')(xml:id='&KeyVal(#1,'id')')> #body</omdoc:theory>)", + #closed bracket ) seems to work fine now + + #commented this out - do we need current_theory? + #plus: keyvals->getValue seems to be undefined?! + + #beforeConstruct=> sub { + #my ($doc, $keyvals, %props) = @_; + #my $theory = $keyvals->getValue('id') if $keyvals; + #$theory = ref $theory ? $theory->toString : 'UNDEFINED'; + #AssignValue(current_theory => $theory); + #return;}, +# $Doc->openElement('omdoc:theory', 'xml:id' => $theory); +# my $uses = $keyvals->getValue('usses'); +# $uses = ref $uses ? $uses->toString || '' : ''; +# $uses =~ s/\s+//g; $uses=~ s/^\{//; $uses=~ s/\}$//; +# my $module_paths = LookupValue('module_paths') || {}; +# foreach my $used(split(',',$uses)) { +# my $file = $module_paths->{$used}; $file .= '.omdoc#' if $file; +# $doc->openElement('omdoc:imports', 'from' => $file.$used); +# $doc->closeElement('omdoc:imports'); } +# $doc->absorb($props{body}) if $props{body}; +# $doc->closeElement('omdoc:theory'); } +# return; }, + beforeDigest=>\&useTheoryItemizations, + afterDigestBegin=>sub { + my($stomach, $whatsit)=@_; + $whatsit->setProperty(excluded=>LookupValue('excluding_modules')); + + my $keys = $whatsit->getArg(1); + my($id, $cd)=$keys + && map(ToString($keys->getValue($_)),qw(id cd)); + $cd = $id unless $cd; + # update the catalog with paths for modules + my $module_paths = LookupValue('module_paths') || {}; + $module_paths->{$id} = LookupValue('last_module_path'); + AssignValue('module_paths', $module_paths, 'global'); + + #Update the current module position + AssignValue(current_module => $id); + AssignValue(module_cd => $cd) if $cd; +# my @uses = (); +# if($uses){ +# $uses =~ s/\s//g; $uses=~ s/^\{//; $uses=~ s/\}$//; +# @uses = split(',',$uses); } +############### AssignValue("module_${id}_uses" => [@uses], 'global'); + #Idea: introdcue global list of used modules and activateScope on it once at the + # main block. + #use_module($id); #22.02.08 need to ALWAYS invoke this to make things global + + #activate the module in our current scope + $STATE->activateScope("module:".$id); #changed from use_module as only needs to take care of current module + return; }); +%</ltxml> +% \end{macrocode} +% \end{environment} +% +% +% \begin{macro}{usemodule} +% The |use_module| subroutine +% performs depth-first load of definitions of the used modules +% \begin{macrocode} +%<*ltxml> +sub use_module { + my($module)=@_; + $module = ToString($module); + # Depth-first load definitions from used modules + foreach my $used_module (@{ LookupValue("module_${module}_uses") || []}){ + use_module($used_module); } + # then load definitions for this module + $STATE->activateScope("module:$module"); } +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\show@mod@keys} +% The |\show@mod@keys| macro is used for the draft mode, they allow to annotate the +% document with reminders of the key values in the modules. +% \begin{macrocode} +%<*package> +\def\show@mod@keys@aux{% +\@ifundefined{mod@id}{}{\ifmod@id{id=\mod@id},\fi}% +\@ifundefined{mod@display}{}{\ifmod@display{display=\mod@display}\fi} +\@ifundefined{mod@uses}{\relax}{\ifmod@uses{uses=\mod@uses},\fi} +\@ifundefined{mod@usesqualified}\relax\else + \ifmod@usesqualified{usesqualified=\mod@usesqualified},\fi\fi} +\def\clear@mod@keys{\let\mod@usesqualified=\relax\mod@uses=\relax + \let\st@id=\relax\let\st@display=\relax} +\def\show@mod@keys#1{\footnote{#1[\show@mod@keys@aux]}\clear@mod@keys} +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{activate@defs} +% To activate the symdefs from a given module xxx, we call the macro |\module@defs@xxx|. +% \begin{macrocode} +%<package>\def\activate@defs#1{\csname module@defs@#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{export@defs} +% To export a the symdefs from the current module, we all the macros |\module@defs@xxx| +% to |\module@defs@xxx| (if the current module has a name and it is xxx) +% \begin{macrocode} +%<*package> +\def\export@defs#1{\@ifundefined{mod@id}{}{ + \expandafter\expandafter\expandafter + \g@addto@macro\expandafter + \this@module\expandafter{\csname module@defs@#1\endcsname}}} +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\importmodule} +% The |\importmodule[|\meta{file}|]{|\meta{mod}|}| macro is an interface macro that +% loads \meta{file} and activates and re-exports the symdefs from module +% \meta{mod}.\ednote{document it above, and implement it in {\latexml}} +% \begin{macrocode} +%<*package> +\newcommand{\importmodule}[2][]{\def\@test{#1}% +\ifx\@test\@empty\else\requiremodules{#1}\fi +\activate@defs{#2}\export@defs{#2}} +%</package> +%<*ltxml> +DefConstructor('\importmodule[]{}',"<omdoc:imports from='?#1(#1)\# #2'/>", + afterDigest=>sub { + my($stomach,$whatsit)=@_; + my $file = $whatsit->getArg(1); + my $module = $whatsit->getArg(2); + $module = ToString($module); + #if filepath is not supply simply look for the $module.sms file + if (!$file) {$file=ToString($module)}; + my $containing_module = LookupValue('current_module'); + #set the relation between the current module and the one to be imported + PushValue("module_".$containing_module."_uses"=>$module); + #check if we've already loaded this module + if(LookupValue('module_'.$module.'_loaded')) {use_module($module);} #if so activate it! + else { + #if not: + my $gullet = $stomach->getGullet; + #1) mark as loaded + AssignValue('module_'.$module.'_loaded' => 1, 'global'); + #open a group for its definitions so that they are localized + $stomach->bgroup; + #update the last module path + AssignValue('last_module_path', $file); + #queue the closing tag for this module in the gullet where it will be executed + #after all other definitions of the imported module have been taken care of + $gullet->unread(Invocation(T_CS('\end@requiredmodule'), T_OTHER($module))->unlist); + #we only need to load the sms definitions without generating any xml output, so we set the flag to 1 + AssignValue('excluding_modules' => 1); + #queue this module's sms file in the gullet so that its definitions are imported + $gullet->input($file,['sms']); + } + return;}); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \subsection{Semantic Macros}\label{sec:impl:symdef} +% +% We first define the optional KeyVal arguments for the |\symdef| form and the actions +% that are taken when they are encountered. +% +% \begin{macro}{symdef:aliases} +% This optional key aliases for the symdef function allows us to provide additional +% arguments representing other functions that are aliased by the one currently being +% defined. +% \begin{macrocode} +%<package>\define@key{symdef}{aliases}{} +%<*ltxml> +DefKeyVal('symdef','aliases','Semiverbatim'); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{symdef:local} +% The optional argument local specifies the scope of the function to be defined. If +% local is not present as an optional argument then |\symdef| assumes the scope of the +% function is global and it will include it in the pool of macros of the current +% module. Otherwise, if local is present then the function will be defined only locally +% and it will not be added to the current module (i.e. we cannot inherit a local +% function). Note, the optional key local does not need a value: we write +% |\symdef[local]{somefunction}[0]{some expansion}| +% \begin{macrocode} +%<package>\define@key{symdef}{local}[true]{\@symdeflocaltrue} +%<*ltxml> +DefKeyVal('symdef','local','Semiverbatim','true'); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{symdef:} +% The keys |cmmml|, |cattrs|, and |definitionURL| are not used in {\TeX/\LaTeX} +% bindings\ednote{decide what we want to do about them in the future.}. +% \begin{macrocode} +%<*package> +\define@key{symdef}{cmml}{} +\define@key{symdef}{cattrs}{} +\define@key{symdef}{definitionURL}{} +%</package> +%<*ltxml> +DefKeyVal('symdef','cmml','Semiverbatim','true'); +DefKeyVal('symdef','cattrs','Semiverbatim','true'); +DefKeyVal('symdef','definitionURL','Semiverbatim','true'); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\symdef} +% The the |\symdef|, and |\@symdef| macros just handle optional arguments. +% \begin{macrocode} +%<*package> +\newif\if@symdeflocal +\def\symdef{\@ifnextchar[{\@symdef}{\@symdef[]}} +\def\@symdef[#1]#2{\@ifnextchar[{\@@symdef[#1]{#2}}{\@@symdef[#1]{#2}[0]}} +% \end{macrocode} +% now comes the real meat: the |\@@symdef| macro does two things, it adds the macro +% definition to the macro definition pool of the current module and also provides it. +% \begin{macrocode} +\def\@@symdef[#1]#2[#3]#4{% +% \end{macrocode} +% We use a switch to keep track of the local optional argument. We initialize the switch +% to false and check for the local keyword. Then we set all the keys that have been +% provided as arguments: aliases, local. First, using |\providecommand| we +% initialize the intermediate function, the one that can be changed internally with +% |\redefine| and then we link the actual function to it, again with |\providecommand|. We +% check if the switch for the local scope is set: if it is we are done, since this +% function has a local scope. Otherwise, we add these two functions to the module's pool +% of defined macros using |\g@addto@macro|. We add both functions so that we can keep the +% link between the real and the intermediate function whenever we inherit the +% module. Finally, using |\g@addto@macro| we add the two functions to the qualified +% version of the module. +% \begin{macrocode} +\@symdeflocalfalse\setkeys{symdef}{#1} + \expandafter\providecommand\csname modules@#2@pres\endcsname[#3]{#4} + \expandafter\def\csname#2\endcsname{\csname modules@#2@pres\endcsname} + \if@symdeflocal\else + \@ifundefined{mod@id}{}{ + \expandafter\g@addto@macro\this@module{\expandafter\providecommand\csname modules@#2@pres\endcsname[#3]{#4}}% + \expandafter\g@addto@macro\this@module{\expandafter\def\csname#2\endcsname{\csname modules@#2@pres\endcsname}} + \expandafter\g@addto@macro\this@qualified@module{\expandafter\providecommand\csname modules@#2@pres@qualified\endcsname[#3]{#4}}% + \expandafter\g@addto@macro\this@qualified@module{\expandafter\def\csname#2atqualified\endcsname{\csname modules@#2@pres@qualified\endcsname}} + }\fi} +%</package> +% \end{macrocode} +% In the {\latexml} bindings, we have a top-level macro that delegates the work to two +% internal macros: |\@symdef|, which defines the content macro and |\@symdef@pres|, which +% generates the {\omdoc} |symbol| and |presentation| elements (see +% Section~\ref{sec:impl:presentation}). +% \begin{macrocode} +%<*ltxml> +DefMacro('\symdef OptionalKeyVals:symdef {}[][]{}', + sub { +my($self,@args)=@_; +# print STDERR "excluding" if LookupValue('excluding_modules'); +((Invocation(T_CS('\@symdef'),@args)->unlist), + (LookupValue('excluding_modules') ? () + : (Invocation(T_CS('\@symdef@pres'), @args)->unlist))); +}); + +DefPrimitive('\@symdef OptionalKeyVals:symdef {}[][]{}', sub { + my($stomach,$keys,$cs,$nargs,$opt,$presentation)=@_; + my($name,$cd,$role,$cmml,$cattrs,$definitionURL)=$keys + && map($_ && $_->toString,map($keys->getValue($_), qw(name cd role cmml cattrs definitionURL))); + $cd = LookupValue('module_cd') unless $cd; + $nargs = (ref $nargs ? $nargs->toString : $nargs || 0); + my $module = LookupValue('current_module'); +# print STDERR "Define ".Stringify($cs)." in $module\n"; + my $scope = (($keys && ($keys->getValue('local') || '' eq 'true')) ? 'module_local' : 'module').":".$module; + my $attr="name='#name' meaning='#meaning' omcd='#omcd'"; + DefConstructorI("\\".$cs->toString,convertLaTeXArgs($nargs,$opt), + ($nargs == 0 + ? "<ltx:XMTok $attr scriptpos='#scriptpos'/>" + : "<ltx:XMApp scriptpos='#scriptpos'>" + . "<ltx:XMTok $attr scriptpos='#operator_scriptpos'/>" + . join('',map("<ltx:XMArg>#$_</ltx:XMArg>", (1..$nargs))) + ."</ltx:XMApp>"), + properties => {name=>$name, meaning=>$cs->toString,omcd=>$cd,role => $role}, + scope=>$scope); + return; }); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +%\begin{macro}{\redefine} +% We can use this function to redefine our intermediate presentational function inside +% the modules\ednote{does not seem to have a {\latexml} counterpart yet!} +% \begin{macrocode} +%<package>\def\redefine#1[#2]#3{\expandafter\renewcommand\csname modules@#1@pres\endcsname[#2]{#3}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\abbrdef} +% The |\abbrdef| macro is a variant of |\symdef| that does the same on the {\LaTeX} level. +% \begin{macrocode} +%<package>\let\abbrdef\symdef +%<*ltxml> +DefPrimitive('\abbrdef OptionalKeyVals:symdef {}[][]{}', sub { + my($stomach,$keys,$cs,$nargs,$opt,$presentation)=@_; + my $module = LookupValue('current_module'); + my $scope = (($keys && ($keys->getValue('local') || '' eq 'true')) ? 'module_local' : 'module').":$module"; + DefMacroI("\\".$cs->toString,convertLaTeXArgs($nargs,$opt),$presentation, + scope=>$scope); + return; }); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \subsection{Loading Module Signatures}\ednote{talk about module signatures above (SMS +% files)} +% Before we can come to the functionality we want to offer, we need some auxiliary +% functions that deal with path names. +% \begin{macro}{\mod@simplify} +% The |\mod@simplify| macro removes |xxx/..| from a string. eg: |aaa/bbb/../ddd| goes to +% |aaa/ddd|. This is used to normalize relative path names below. +% \begin{macrocode} +%<*package> +\def\mod@simplify#1{\expandafter\mod@simpl#1/\relax} +% \end{macrocode} +% It is based on the |\mod@simpl| macro +% \begin{macrocode} +\def\mod@simpl#1/#2\relax{%\message{ 1 = #1, 2 = #2 }% +\def\mod@test{}\ifx\mod@blaaaa\mod@test\edef\mod@savedprefix{}\def\mod@blaaaa{aaa}\else\fi +\def\mod@comp{#2}\ifx\mod@test\mod@comp\edef\mod@savedprefix{\mod@savedprefix#1}% +\else\mod@simplhelp#1/#2\relax\fi} +% \end{macrocode} +% which in turn is based on a helper macro +% \begin{macrocode} +\def\mod@simplhelp#1/#2/#3\relax{% +\def\mod@test{}\def\mod@tust{#2}\def\mod@tist{#3}\def\mod@tost{..}\ifx\mod@test\mod@tist% +\ifx\mod@tost\mod@tust\edef\mod@savedprefix{}\else\edef\mod@savedprefix +{\mod@savedprefix#1/#2}\fi \else\ifx\mod@tost\mod@tust\mod@simpl#3\relax% +\else\edef\mod@savedprefix{\mod@savedprefix#1/}\mod@simplhelp#2/#3\relax\fi\fi}% +% \end{macrocode} +% \end{macro} +% We will need a switch\ednote{Rares, say why?} +% \begin{macrocode} +\newif\ifmodules +% \end{macrocode} +% and a ``registry'' macro whose expansion represents the list of added macros (or files) +% \begin{macro}{\reg} +% We initialize the |\reg| macro with the empty string. +% \begin{macrocode} +\gdef\reg{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@update} +% This macro provides special append functionality. It takes a string and appends it +% to the expansion of the |\reg| macro in the following way: |string@\reg|. +% \begin{macrocode} +\def\mod@update#1{\def\mod@empty{} +\ifx\reg\mod@empty\xdef\reg{#1}\else\xdef\reg{#1@\reg}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@check} +% The |\mod@check| takes as input a file path (arg 3), and searches the registry. If the +% file path is not in the registry it means it means it has not been already added, so +% we make modulestrue, otherwise make modulesfalse. The macro |\mod@search| will look at +% ifinclude and update the registry for modulestrue or do nothing for modulesfalse. +% \begin{macrocode} +\def\mod@check#1@#2///#3\relax{% +\def\mod@empty{}\def\mod@one{#1}\def\mod@two{#2}\def\mod@three{#3}% +% \end{macrocode} +% Define a few intermediate macros so that we can split the registry into separate file +% paths and compare to the new one +% \begin{macrocode} +\expandafter\ifx\mod@three\mod@one\modulestrue\else\ifx\mod@two\mod@empty\modulesfalse% +\else\mod@check#2///#3\relax\fi\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@search} +% Macro for updating the registry after the execution of |\mod@check| +% \begin{macrocode} +\def\mod@search#1{% +% \end{macrocode} +% We put the registry as the first argument for |\mod@check| and the other +% argument is the new file path. +% \begin{macrocode} +\modulesfalse\expandafter\mod@check\reg @///#1\relax% +% \end{macrocode} +% We run |\mod@check| with these arguments and the check |\ifmodules| for +% the result +% \begin{macrocode} +\ifmodules\else\mod@update{#1}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@reguse} +% The macro operates almost as the |mod@search| function, but it does not update the +% registry. Its purpose is to check whether some file is or not inside the registry but +% without updating it. Will be used before deciding on a new sms file +% \begin{macrocode} +\def\mod@reguse#1{\modulesfalse\expandafter\mod@check\reg @///#1\relax} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@prefix} +% This is a local macro for storing the path prefix, we initialize it as the empty +% string. +% \begin{macrocode} +\def\mod@prefix{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@updatedpre} +% This macro allows to update the path prefix with the last part of the new path +% \begin{macrocode} +\def\mod@updatedpre#1{ + \edef\mod@prefix{\mod@prefix\mod@pathprefix@check#1/\relax}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mod@pathprefix@check} +% |\mod@pathprefix@check| returns the last word in a string composed of words separated +% by slashes +% \begin{macrocode} +\def\mod@pathprefix@check#1/#2\relax{% +\ifx\\#2\\% no slash in string +\else\mod@ReturnAfterFi{#1/\mod@pathprefix@help#2\relax}% +\fi} +% \end{macrocode} +% It needs two helper macros: +% \begin{macrocode} +\def\mod@pathprefix@help#1/#2\relax{% +\ifx\\#2\\% end of recursion +\else\mod@ReturnAfterFi{#1/\mod@pathprefix@help#2\relax}% +\fi} +\long\def\mod@ReturnAfterFi#1\fi{\fi#1} +% \end{macrocode} +% \end{macro} +% +%\begin{macro}{\mod@pathpostfix@check} +% |\mod@pathpostfix@check| takes a string composed of words separated by slashes and +% returns the part of the string until the last slash +% \begin{macrocode} +\def\mod@pathpostfix@check#1/#2\relax{% slash +\ifx\\#2\\%no slash in string +#1\else\mod@ReturnAfterFi{\mod@pathpostfix@help#2\relax}% +\fi} +% \end{macrocode} +% Helper function for the pathpostfix@check function defined above +% \begin{macrocode} +\def\mod@pathpostfix@help#1/#2\relax{% +\ifx\\#2\\% +#1\else\mod@ReturnAfterFi{\mod@pathpostfix@help#2\relax}% +\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\def\mod@updatedpost#1{% +\edef\mod@savedprefix{\mod@savedprefix\mod@pathpostfix@check#1/\relax} } +% \end{macrocode} +% Macro that will add a |.sms| extension to a path. Will be used when adding a |.sms| file +% \begin{macrocode} +\def\mod@updatesms{\edef\mod@savedprefix{\mod@savedprefix.sms}} +%</package> +% \end{macrocode} +% +% \subsection{Selective Inclusion} +% +% \begin{macro}{\requiremodules} +% \begin{macrocode} +%<*package> +\newcommand{\requiremodules}[1]{% +{\mod@updatedpre{#1} % add the new file to the already existing path +\let\mod@savedprefix\mod@prefix % add the path to the new file to the prefix +\mod@updatedpost{#1} +\def\mod@blaaaa{} % macro used in the simplify function (remove .. from the prefix) +\mod@simplify{\mod@savedprefix} % remove |xxx/..| from the path (in case it exists) +\mod@reguse{\mod@savedprefix} +\ifmodules\else +\mod@updatesms % update the file to contain the .sms extension +\let\newreg\reg % use to compare, in case the .sms file was loaded before +\mod@search{\mod@savedprefix} % update registry +\ifx\newreg\reg\else\input{\mod@savedprefix}\fi % check if the registry was updated and load if necessary +\fi}} +%</package> +%<*ltxml> +DefPrimitive('\requiremodules{}', sub { + my($stomach,$module)=@_; + my $GULLET = $stomach->getGullet; + $module = Digest($module)->toString; + if(LookupValue('module_'.$module.'_loaded')) {} + else { + AssignValue('module_'.$module.'_loaded' => 1, 'global'); + $stomach->bgroup; + AssignValue('last_module_path', $module); + $GULLET->unread(T_CS('\end@requiredmodule')); + AssignValue('excluding_modules' => 1); + $GULLET->input($module,['sms']); + } + return;}); + +DefPrimitive('\end@requiredmodule{}',sub { + #close the group + $_[0]->egroup; + #print STDERR "END: ".ToString(Digest($_[1])->toString); + #Take care of any imported elements in this current module by activating it and all its dependencies + #print STDERR "Important: ".ToString(Digest($_[1])->toString)."\n"; + use_module(ToString(Digest($_[1])->toString)); + return; }); +%</ltxml> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sinput} +% \begin{macrocode} +%<*package> +\def\sinput#1{ +{\mod@updatedpre{#1} % add the new file to the already existing path +\let\mod@savedprefix\mod@prefix % add the path to the new file to the prefix +\mod@updatedpost{#1} +\def\mod@blaaaa{} % macro used in the simplify function (remove .. from the prefix) +\mod@simplify{\mod@savedprefix} % remove |xxx/..| from the path (in case it exists) +\mod@reguse{\mod@savedprefix} +\let\newreg\reg % use to compare, in case the .sms file was loaded before +\mod@search{\mod@savedprefix} % update registry +\ifx\newreg\reg%\message{This file has been previously introduced} +\else\input{\mod@savedprefix}\fi}} +%</package> +%<*ltxml> +DefPrimitive('\sinput{}', sub { + my($stomach,$module)=@_; + my $GULLET = $stomach->getGullet; + $module = Digest($module)->toString; + AssignValue('module_'.$module.'_loaded' => 1, 'global'); + $stomach->bgroup; + AssignValue('last_module_path', $module); + $GULLET->unread(Invocation(T_CS('\end@requiredmodule'),T_OTHER($module))->unlist); + $GULLET->input($module,['tex']); + return;}); +%</ltxml> +% \end{macrocode} +% \end{macro} +% \ednote{the sinput macro is just faked, it should be more like requiremodules, except +% that the tex file is inputted; I wonder if this can be simplified.} +% +% \subsection{Generating {\texorpdfstring\omdoc{OMDoc}} Presentation Elements}\label{sec:impl:presentation} +% +% Additional bundle of code to generate presentation encodings. Redefined to an expandable +% (macro) so that we can add conversions. +% +% \begin{macrocode} +%<*ltxml> +DefMacro('\@symdef@pres OptionalKeyVals:symdef {}[][]{}', sub { + my($self,$keys, $cs,$nargs,$opt,$presentation)=@_; + Invocation(T_CS('\@symdef@pres@aux'), + $cs, + ($nargs || Tokens(T_OTHER(0))), + symdef_presentation_pmml($cs,ToString($nargs)||0,$presentation), + symdef_presentation_TeX($presentation), + $keys)->unlist; }); +% \end{macrocode} +% Generate the expansion of a symdef'd macro using special arguments +% \begin{macrocode} +sub symdef_presentation_pmml { + my($cs,$nargs,$presentation)=@_; + my @toks = $presentation->unlist; + while(@toks && $toks[0]->equals(T_SPACE)){ pop(@toks); } # Remove leading space + $presentation = Tokens(@toks); + # Wrap with \@use, unless already has a recognized formatter. + $presentation = Invocation(T_CS('\@use'),$presentation) # Using simple text for now, until getting a proper \@use + unless @toks && ($toks[0]->toString =~ /^\\(infix|prefix|postfix|assoc|use|mixfixi|mixfixa|mixfixii|mixfixia|mixfixai|mixfixiii)$/); + # Low level substitution. + my @args = map(Invocation(T_CS('\@SYMBOL'),T_OTHER("pres_arg:".($_+1))),1..$nargs); + $presentation = Tokens(LaTeXML::Expandable::substituteTokens($presentation,@args)); + $presentation; } +% \end{macrocode} +% The |\@use| macro just generates the contents of the notation element +% \begin{macrocode} +DefConstructor('\@use {}', + "<omdoc:prototype>" + . "<om:OMS cd='' name=''/>" + ."</omdoc:prototype>" + ."<omdoc:rendering>" + . "<ltx:Math><ltx:XMath>#1</ltx:XMath></ltx:Math>" + ."</omdoc:rendering>", + mode=>'inline_math'); +% \end{macrocode} +% The |get_cd| procedure reads of the cd from our list of keys. +% \begin{macrocode} +sub get_cd { + my($name,$cd,$role,$cmml,$cattrs,$definitionURL)=@_; + return $cd;} +% \end{macrocode} +% The |\@symdef@pres@aux| creates the |symbol| element and the outer layer of the of the +% |notation| element. The content of the latter is generated by applying the {\latexml} to +% the definiens of the |\symdef| form. +% \begin{macrocode} +DefConstructor('\@symdef@pres@aux{}{}{}{} OptionalKeyVals:symdef', + "<omdoc:symbol name='#1'/>" + ."<omdoc:notation name='#name' cd='&get_cd(#5)'>" + ."#3" + ."</omdoc:notation>", + afterDigest=>sub { my ($stomach, $whatsit) = @_; + my $keys = $whatsit->getArg(5); + my $module = LookupValue('current_module'); + $whatsit->setProperties(for=>ToString($whatsit->getArg(1))); + $whatsit->setProperty(role=>($keys ? $keys->getValue('role') + : (ToString($whatsit->getArg(2)) ? 'applied' + : undef))); }); +% \end{macrocode} +% Convert a macro body (tokens with parameters |#1|,..) into a Presentation |style=TeX| form. +% walk through the tokens, breaking into chunks of neutralized (|T_OTHER|) tokens and +% parameter specs. +% \begin{macrocode} +sub symdef_presentation_TeX { + my($presentation)=@_; + my @tokens = $presentation->unlist; + my(@frag,@frags) = (); + while(my $tok = shift(@tokens)){ + if($tok->equals(T_PARAM)){ + push(@frags,Invocation(T_CS('\@symdef@pres@text'),Tokens(@frag))) if @frag; + @frag=(); + my $n = shift(@tokens)->getString; + push(@frags,Invocation(T_CS('\@symdef@pres@arg'),T_OTHER($n+1))); } + else { + push(@frag,T_OTHER($tok->getString)); }} # IMPORTANT! Neutralize the tokens! + push(@frags,Invocation(T_CS('\@symdef@pres@text'),Tokens(@frag))) if @frag; + Tokens(map($_->unlist,@frags)); } + +DefConstructor('\@symdef@pres@arg{}', "<omdoc:recurse select='#select'/>", + afterDigest=>sub { my ($stomach, $whatsit) = @_; + my $select = $whatsit->getArg(1); + $select = ref $select ? $select->toString : ''; + $whatsit->setProperty(select=>"*[".$select."]"); }); + +DefConstructor('\@symdef@pres@text{}', "<omdoc:text>#1</omdoc:text>"); +%</ltxml> +% \end{macrocode} +% +% +% \subsection{Including Externally Defined Semantic Macros }\label{sec:impl:packages} +% +% \begin{macro}{\requirepackage} +% \begin{macrocode} +%<package>\def\requirepackage#1#2{\makeatletter\input{#1.sty}\makeatother} +%<*ltxml> +DefConstructor('\requirepackage{} Semiverbatim',"<omdoc:imports from='#2'/>", + afterDigest=>sub { my ($stomach, $whatsit) = @_; + my $select = $whatsit->getArg(1); + RequirePackage($select->toString); }); +% \end{macrocode} +% \end{macro} +% +% \subsection{Deprecated Functionality}\label{sec:impl:deprecated} +% +% In this section we centralize old interfaces that are only partially supported any more. +% \begin{macro}{module:uses} +% For each the module name |xxx| specified in the |uses| key, we activate their symdefs +% and we export the local symdefs.\ednote{this isue is deprecated, it will be removed +% before 1.0.} +% \begin{macrocode} +%<*package> +\define@key{module}{uses}{% + \@for\module@tmp:=#1\do{\activate@defs\module@tmp\export@defs\module@tmp}} +%</package> +% \end{macrocode} +% +% \begin{macro}{module:usesqualified} +% This option operates similarly to the module:uses option defined above. The only +% difference is that here we import modules with a prefix. This is useful when two +% modules provide a macro with the same name. +% \begin{macrocode} +%<*package> +\define@key{module}{usesqualified}{% + \@for\module@tmp:=#1\do{\activate@defs{qualified@\module@tmp}\export@defs\module@tmp}} +%</package> +% \end{macrocode} +% \end{macro} +% +% \subsection{Finale} +% +% Finally, we need to terminate the file with a success mark for perl. +% \begin{macrocode} +%<ltxml>1; +% \end{macrocode} +% +% \section {Utility}\label{sec:utilities} +% \Finale +\endinput +% \iffalse +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% LocalWords: GPL structuresharing STR dtx env envfalse idfalse displayfalse +% LocalWords: usesfalse usesqualified usesqualifiedfalse envtrue idtrue CPERL +% LocalWords: usestrue displaytrue usesqualifiedtrue RequirePackage keyval tmp +% LocalWords: defs foreach LookupValue activateScope DefEnvironment keyvals cd +% LocalWords: OptionalKeyVals getValue toString AssignValue openElement omdoc +% LocalWords: closeElement beforeDigest useTheoryItemizations afterDigestBegin +% LocalWords: whatsit setProperty getArg qw symdef cmml cattrs definitionURL +% LocalWords: DefKeyVal Semiverbatim symdeflocal atqualified DefMacro STDERR +% LocalWords: args unlist DefPrimitive nargs Stringify eq attr omcd ltx XMTok +% LocalWords: DefConstructorI convertLaTeXArgs scriptpos XMApp OMA XMArg simpl +% LocalWords: DefMacroI blaaaa savedprefix aaa simplhelp tust tist tost reguse +% LocalWords: updatedpre ReturnAfterFi updateall updatedpost updatesms bgroup +% LocalWords: texclude tinclude getGullet requiredmodule tex sms egroup pmml +% LocalWords: toks mixfixi mixfixa mixfixii mixfixia mixfixai mixfixiii arg +% LocalWords: DefConstructor afterDigest setProperties undef tok PARAM +% LocalWords: getString +% \fi |