commit c4d93497862e56412086ce74a6a5187cf3e7d732 Author: Brion Vibber Date: Sat Apr 9 00:39:40 2011 +0000 Initial stab at breaking math/texvc out to Math extension. * (bug 14202) $wgUseTeX has been superseded by the Math extension. To re-enable math conversion after upgrading, obtain the Math extension from SVN or from http://www.mediawiki.org/wiki/Extension:Math and add to LocalSettings.php: require_once "$IP/extensions/Math/Math.php"; This is an initial stab, and a few things remain to be cleaned up: * messages need to be moved from core to extension * MW_MATH_* constants should be moved to the extension from core * old back-compat math names interfaces using those constants should be removed from message files * classic edit toolbar's math button should be added from the extension (or else dropped) -- currently there's not a clean hook, but could do it by JS * couple of things like the 'armourMath' function on Language & LanguageConverter may want to be redone just as an unconditional, if that's simpler. Setting $wgUseTeX alone will no longer have any affect. The var's still there for the moment as a few bits still need to be fully moved out from core. diff --git a/Math.body.php b/Math.body.php new file mode 100644 index 0000000..449a2ee --- /dev/null +++ b/Math.body.php @@ -0,0 +1,348 @@ + parsing + * @file + * @ingroup Parser + */ + +/** + * Takes LaTeX fragments, sends them to a helper program (texvc) for rendering + * to rasterized PNG and HTML and MathML approximations. An appropriate + * rendering form is picked and returned. + * + * @author Tomasz Wegrzanowski, with additions by Brion Vibber (2003, 2004) + * @ingroup Parser + */ +class MathRenderer { + var $mode = MW_MATH_MODERN; + var $tex = ''; + var $inputhash = ''; + var $hash = ''; + var $html = ''; + var $mathml = ''; + var $conservativeness = 0; + + function __construct( $tex, $params=array() ) { + $this->tex = $tex; + $this->params = $params; + } + + function setOutputMode( $mode ) { + $this->mode = $mode; + } + + function render() { + global $wgTmpDirectory, $wgInputEncoding; + global $wgTexvc, $wgMathCheckFiles, $wgTexvcBackgroundColor; + + if( $this->mode == MW_MATH_SOURCE ) { + # No need to render or parse anything more! + # New lines are replaced with spaces, which avoids confusing our parser (bugs 23190, 22818) + return ('$ ' . str_replace( "\n", " ", htmlspecialchars( $this->tex ) ) . ' $'); + } + if( $this->tex == '' ) { + return; # bug 8372 + } + + if( !$this->_recall() ) { + if( $wgMathCheckFiles ) { + # Ensure that the temp and output directories are available before continuing... + if( !file_exists( $wgTmpDirectory ) ) { + if( !wfMkdirParents( $wgTmpDirectory ) ) { + return $this->_error( 'math_bad_tmpdir' ); + } + } elseif( !is_dir( $wgTmpDirectory ) || !is_writable( $wgTmpDirectory ) ) { + return $this->_error( 'math_bad_tmpdir' ); + } + } + + if( !is_executable( $wgTexvc ) ) { + return $this->_error( 'math_notexvc' ); + } + $cmd = $wgTexvc . ' ' . + escapeshellarg( $wgTmpDirectory ).' '. + escapeshellarg( $wgTmpDirectory ).' '. + escapeshellarg( $this->tex ).' '. + escapeshellarg( $wgInputEncoding ).' '. + escapeshellarg( $wgTexvcBackgroundColor ); + + if ( wfIsWindows() ) { + # Invoke it within cygwin sh, because texvc expects sh features in its default shell + $cmd = 'sh -c ' . wfEscapeShellArg( $cmd ); + } + + wfDebug( "TeX: $cmd\n" ); + $contents = wfShellExec( $cmd ); + wfDebug( "TeX output:\n $contents\n---\n" ); + + if (strlen($contents) == 0) { + return $this->_error( 'math_unknown_error' ); + } + + $retval = substr ($contents, 0, 1); + $errmsg = ''; + if (($retval == 'C') || ($retval == 'M') || ($retval == 'L')) { + if ($retval == 'C') { + $this->conservativeness = 2; + } else if ($retval == 'M') { + $this->conservativeness = 1; + } else { + $this->conservativeness = 0; + } + $outdata = substr ($contents, 33); + + $i = strpos($outdata, "\000"); + + $this->html = substr($outdata, 0, $i); + $this->mathml = substr($outdata, $i+1); + } else if (($retval == 'c') || ($retval == 'm') || ($retval == 'l')) { + $this->html = substr ($contents, 33); + if ($retval == 'c') { + $this->conservativeness = 2; + } else if ($retval == 'm') { + $this->conservativeness = 1; + } else { + $this->conservativeness = 0; + } + $this->mathml = null; + } else if ($retval == 'X') { + $this->html = null; + $this->mathml = substr ($contents, 33); + $this->conservativeness = 0; + } else if ($retval == '+') { + $this->html = null; + $this->mathml = null; + $this->conservativeness = 0; + } else { + $errbit = htmlspecialchars( substr($contents, 1) ); + switch( $retval ) { + case 'E': + $errmsg = $this->_error( 'math_lexing_error', $errbit ); + break; + case 'S': + $errmsg = $this->_error( 'math_syntax_error', $errbit ); + break; + case 'F': + $errmsg = $this->_error( 'math_unknown_function', $errbit ); + break; + default: + $errmsg = $this->_error( 'math_unknown_error', $errbit ); + } + } + + if ( !$errmsg ) { + $this->hash = substr ($contents, 1, 32); + } + + wfRunHooks( 'MathAfterTexvc', array( &$this, &$errmsg ) ); + + if ( $errmsg ) { + return $errmsg; + } + + if (!preg_match("/^[a-f0-9]{32}$/", $this->hash)) { + return $this->_error( 'math_unknown_error' ); + } + + if( !file_exists( "$wgTmpDirectory/{$this->hash}.png" ) ) { + return $this->_error( 'math_image_error' ); + } + + if( filesize( "$wgTmpDirectory/{$this->hash}.png" ) == 0 ) { + return $this->_error( 'math_image_error' ); + } + + $hashpath = $this->_getHashPath(); + if( !file_exists( $hashpath ) ) { + wfSuppressWarnings(); + $ret = wfMkdirParents( $hashpath, 0755 ); + wfRestoreWarnings(); + if( !$ret ) { + return $this->_error( 'math_bad_output' ); + } + } elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) { + return $this->_error( 'math_bad_output' ); + } + + if( !rename( "$wgTmpDirectory/{$this->hash}.png", "$hashpath/{$this->hash}.png" ) ) { + return $this->_error( 'math_output_error' ); + } + + # Now save it back to the DB: + if ( !wfReadOnly() ) { + $outmd5_sql = pack('H32', $this->hash); + + $md5_sql = pack('H32', $this->md5); # Binary packed, not hex + + $dbw = wfGetDB( DB_MASTER ); + $dbw->replace( 'math', array( 'math_inputhash' ), + array( + 'math_inputhash' => $dbw->encodeBlob($md5_sql), + 'math_outputhash' => $dbw->encodeBlob($outmd5_sql), + 'math_html_conservativeness' => $this->conservativeness, + 'math_html' => $this->html, + 'math_mathml' => $this->mathml, + ), __METHOD__ + ); + } + + // If we're replacing an older version of the image, make sure it's current. + global $wgUseSquid; + if ( $wgUseSquid ) { + $urls = array( $this->_mathImageUrl() ); + $u = new SquidUpdate( $urls ); + $u->doUpdate(); + } + } + + return $this->_doRender(); + } + + function _error( $msg, $append = '' ) { + $mf = htmlspecialchars( wfMsg( 'math_failure' ) ); + $errmsg = htmlspecialchars( wfMsg( $msg ) ); + $source = htmlspecialchars( str_replace( "\n", ' ', $this->tex ) ); + return "$mf ($errmsg$append): $source\n"; + } + + function _recall() { + global $wgMathDirectory, $wgMathCheckFiles; + + $this->md5 = md5( $this->tex ); + $dbr = wfGetDB( DB_SLAVE ); + $rpage = $dbr->selectRow( 'math', + array( 'math_outputhash','math_html_conservativeness','math_html','math_mathml' ), + array( 'math_inputhash' => $dbr->encodeBlob(pack("H32", $this->md5))), # Binary packed, not hex + __METHOD__ + ); + + if( $rpage !== false ) { + # Tailing 0x20s can get dropped by the database, add it back on if necessary: + $xhash = unpack( 'H32md5', $dbr->decodeBlob($rpage->math_outputhash) . " " ); + $this->hash = $xhash ['md5']; + + $this->conservativeness = $rpage->math_html_conservativeness; + $this->html = $rpage->math_html; + $this->mathml = $rpage->math_mathml; + + $filename = $this->_getHashPath() . "/{$this->hash}.png"; + + if( !$wgMathCheckFiles ) { + // Short-circuit the file existence & migration checks + return true; + } + + if( file_exists( $filename ) ) { + if( filesize( $filename ) == 0 ) { + // Some horrible error corrupted stuff :( + wfSuppressWarnings(); + unlink( $filename ); + wfRestoreWarnings(); + } else { + return true; + } + } + + if( file_exists( $wgMathDirectory . "/{$this->hash}.png" ) ) { + $hashpath = $this->_getHashPath(); + + if( !file_exists( $hashpath ) ) { + wfSuppressWarnings(); + $ret = wfMkdirParents( $hashpath, 0755 ); + wfRestoreWarnings(); + if( !$ret ) { + return false; + } + } elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) { + return false; + } + if ( function_exists( "link" ) ) { + return link ( $wgMathDirectory . "/{$this->hash}.png", + $hashpath . "/{$this->hash}.png" ); + } else { + return rename ( $wgMathDirectory . "/{$this->hash}.png", + $hashpath . "/{$this->hash}.png" ); + } + } + + } + + # Missing from the database and/or the render cache + return false; + } + + /** + * Select among PNG, HTML, or MathML output depending on + */ + function _doRender() { + if( $this->mode == MW_MATH_MATHML && $this->mathml != '' ) { + return Xml::tags( 'math', + $this->_attribs( 'math', + array( 'xmlns' => 'http://www.w3.org/1998/Math/MathML' ) ), + $this->mathml ); + } + if (($this->mode == MW_MATH_PNG) || ($this->html == '') || + (($this->mode == MW_MATH_SIMPLE) && ($this->conservativeness != 2)) || + (($this->mode == MW_MATH_MODERN || $this->mode == MW_MATH_MATHML) && ($this->conservativeness == 0))) { + return $this->_linkToMathImage(); + } else { + return Xml::tags( 'span', + $this->_attribs( 'span', + array( 'class' => 'texhtml', + 'dir' => 'ltr' + ) ), + $this->html ); + } + } + + function _attribs( $tag, $defaults=array(), $overrides=array() ) { + $attribs = Sanitizer::validateTagAttributes( $this->params, $tag ); + $attribs = Sanitizer::mergeAttributes( $defaults, $attribs ); + $attribs = Sanitizer::mergeAttributes( $attribs, $overrides ); + return $attribs; + } + + function _linkToMathImage() { + $url = $this->_mathImageUrl(); + + return Xml::element( 'img', + $this->_attribs( + 'img', + array( + 'class' => 'tex', + 'alt' => $this->tex ), + array( + 'src' => $url ) ) ); + } + + function _mathImageUrl() { + global $wgMathPath; + $dir = $this->_getHashSubPath(); + return "$wgMathPath/$dir/{$this->hash}.png"; + } + + function _getHashPath() { + global $wgMathDirectory; + $path = $wgMathDirectory .'/' . $this->_getHashSubPath(); + wfDebug( "TeX: getHashPath, hash is: $this->hash, path is: $path\n" ); + return $path; + } + + function _getHashSubPath() { + return substr($this->hash, 0, 1) + .'/'. substr($this->hash, 1, 1) + .'/'. substr($this->hash, 2, 1); + } + + public static function renderMath( $tex, $params=array(), ParserOptions $parserOptions = null ) { + $math = new MathRenderer( $tex, $params ); + if ( $parserOptions ) + $math->setOutputMode( $parserOptions->getMath() ); + return $math->render(); + } +} diff --git a/Math.hooks.php b/Math.hooks.php new file mode 100644 index 0000000..ae32d2f --- /dev/null +++ b/Math.hooks.php @@ -0,0 +1,44 @@ +setHook( 'math', array( 'MathHooks', 'mathTagHook' ) ); + return true; + } + + /** + * @param $content + * @param $attributes + * @param $parser Parser + * @return + */ + static function mathTagHook( $content, $attributes, $parser ) { + global $wgContLang; + return $wgContLang->armourMath( MathRenderer::renderMath( $content, $attributes, $parser->getOptions() ) ); + } + + static function onGetPreferences( $user, &$defaultPreferences ) { + global $wgLang; + $defaultPreferences['math'] = array( + 'type' => 'radio', + 'options' => array_flip( array_map( 'wfMsgHtml', $wgLang->getMathNames() ) ), + 'label' => ' ', + 'section' => 'rendering/math', + ); + return true; + } +} diff --git a/Math.php b/Math.php new file mode 100644 index 0000000..66080c7 --- /dev/null +++ b/Math.php @@ -0,0 +1,64 @@ + + +Be sure to properly quote the TeX code! + +Example: + + texvc /home/wiki/tmp /home/wiki/math "y=x+2" iso-8859-1 "rgb 1.0 1.0 1.0" + +=== Output format === + +Status codes and HTML/MathML transformations are returned on stdout. +A rasterized PNG file will be written to the output directory, named +for the MD5 hash code. + +texvc output format is like this: + +%5 ok, but not html or mathml + c%5%h ok, conservative html, no mathml + m%5%h ok, moderate html, no mathml + l%5%h ok, liberal html, no mathml + C%5%h\0%m ok, conservative html, with mathml + M%5%h\0%m ok, moderate html, with mathml + L%5%h\0%m ok, liberal html, with mathml + X%5%m ok, no html, with mathml + S syntax error + E lexing error + F%s unknown function %s + - other error + + \0 - null character + %5 - md5, 32 hex characters + %h - html code, without \0 characters + %m - mathml code, without \0 characters + + +== Troubleshooting == + +Unfortunately, many error conditions with rasterization are not well reported. +texvc will return as though everything is successful, and the only obvious +sign of problems for the user is a big X on a wiki page where an equation +should be. + +Try running texvc from the command line to ensure that the software it relies +upon is all set up. + +Ensure that the temporary and math directories exist and can be written to by +the user account the web server runs under; if you don't control the server, +you may have to make them world-writable. + +If some equations render correctly while others don't, you probably don't have +AMS* packages for LaTeX installed. Most distributions of TeX come with AMS*. +In Debian/Ubuntu AMS* is in tetex-extra package. +To check if that is the problem you can try those two equations: + x + y + x \implies y +The first uses only standard LaTeX, while the second uses symbol \implies from AMS*. +If the first renders, but the second doesn't, you need to install AMS*. + +== Hacking == + +Before you start hacking on the math package its good to know the workflow, +which is basically: + +1. texvc gets called by Math/Math.body.php (check out the line begining with "$cmd") +2. texvc does its magic, which is basically to check for invalid latex code. +3. texvc takes the user input if valid and creates a latex file containing it, see + get_preface in texutil.ml +4. dvipng(1) gets called to create a .png file + See render.ml for this process (commenting out the removal of + the temporary file is useful for debugging). diff --git a/math/TODO b/math/TODO new file mode 100644 index 0000000..bd8d1f4 --- /dev/null +++ b/math/TODO @@ -0,0 +1,3 @@ +* It would be better if PNGs were transparent +* CJK support +* Documentation, in particular about instalation of Latex support for Unicode diff --git a/math/html.ml b/math/html.ml new file mode 100644 index 0000000..e880f07 --- /dev/null +++ b/math/html.ml @@ -0,0 +1,142 @@ +open Render_info +open Tex +open Util + +exception Too_difficult_for_html +type context = CTX_NORMAL | CTX_IT | CTX_RM +type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL + +let conservativeness = ref CONSERVATIVE +let html_liberal () = conservativeness := LIBERAL +let html_moderate () = if !conservativeness = CONSERVATIVE then conservativeness := MODERATE else () + + +let new_ctx = function + FONTFORCE_IT -> CTX_IT + | FONTFORCE_RM -> CTX_RM +let font_render lit = function + (_, FONT_UFH) -> lit + | (_, FONT_UF) -> lit + | (CTX_IT,FONT_RTI) -> raise Too_difficult_for_html + | (_, FONT_RTI) -> lit + | (CTX_IT,FONT_RM) -> ""^lit^"" + | (_, FONT_RM) -> lit + | (CTX_RM,FONT_IT) -> lit + | (_, FONT_IT) -> ""^lit^"" + +let rec html_render_flat ctx = function + TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); (font_render sh (ctx,ft))^html_render_flat ctx r) + | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r + | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> (font_render sh (ctx,ft))^html_render_flat ctx r + | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); (font_render sh (ctx,ft))^html_render_flat ctx r) + | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); sh^html_render_flat ctx r) + | TEX_FUN1hl (_,(f1,f2),a)::r -> f1^(html_render_flat ctx [a])^f2^html_render_flat ctx r + | TEX_FUN1hf (_,ff,a)::r -> (html_render_flat (new_ctx ff) [a])^html_render_flat ctx r + | TEX_DECLh (_,ff,a)::r -> (html_render_flat (new_ctx ff) a)^html_render_flat ctx r + | TEX_CURLY ls::r -> html_render_flat ctx (ls @ r) + | TEX_DQ (a,b)::r -> (html_liberal (); + let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^""^bs^"")^html_render_flat ctx r + | TEX_UQ (a,b)::r -> (html_liberal (); + let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^""^bs^"")^html_render_flat ctx r + | TEX_FQ (a,b,c)::r -> (html_liberal (); + (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in + match html_render_size ctx a with + true, s -> raise Too_difficult_for_html + | false, s -> s^""^bs^""^cs^"")^html_render_flat ctx r) + | TEX_DQN (a)::r -> (html_liberal (); + let bs = html_render_flat ctx [a] in ""^bs^"")^html_render_flat ctx r + | TEX_UQN (a)::r -> (html_liberal (); + let bs = html_render_flat ctx [a] in ""^bs^"")^html_render_flat ctx r + | TEX_FQN (a,b)::r -> (html_liberal (); + (let bs = html_render_flat ctx [a] in let cs = html_render_flat ctx [b] in ""^bs^""^cs^"")^html_render_flat ctx r) + | TEX_BOX (_,s)::r -> s^html_render_flat ctx r + | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html + | TEX_FUN1 _::_ -> raise Too_difficult_for_html + | TEX_FUN2 _::_ -> raise Too_difficult_for_html + | TEX_FUN2nb _::_ -> raise Too_difficult_for_html + | TEX_FUN2h _::_ -> raise Too_difficult_for_html + | TEX_FUN2sq _::_ -> raise Too_difficult_for_html + | TEX_INFIX _::_ -> raise Too_difficult_for_html + | TEX_INFIXh _::_ -> raise Too_difficult_for_html + | TEX_MATRIX _::_ -> raise Too_difficult_for_html + | TEX_LR _::_ -> raise Too_difficult_for_html + | TEX_BIG _::_ -> raise Too_difficult_for_html + | [] -> "" +and html_render_size ctx = function + TEX_LITERAL (HTMLABLE_BIG (_,sh)) -> true,sh + | x -> false,html_render_flat ctx [x] + +let rec html_render_deep ctx = function + TEX_LITERAL (HTMLABLE (ft,_,sh))::r -> (html_liberal (); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r) + | TEX_LITERAL (HTMLABLEM(ft,_,sh))::r -> (html_moderate(); ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r) + | TEX_LITERAL (HTMLABLEC(ft,_,sh))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r + | TEX_LITERAL (MHTMLABLEC(ft,_,sh,_,_))::r -> ("",(font_render sh (ctx,ft)),"")::html_render_deep ctx r + | TEX_LITERAL (HTMLABLE_BIG (_,sh))::r -> (html_liberal (); ("",sh,"")::html_render_deep ctx r) + | TEX_FUN2h (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r) + | TEX_INFIXh (_,f,a,b)::r -> (html_liberal (); (f a b)::html_render_deep ctx r) + | TEX_CURLY ls::r -> html_render_deep ctx (ls @ r) + | TEX_DQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> "",""^s^"",bs + | false, s -> "",(s^""^bs^""),"")::html_render_deep ctx r + | TEX_UQ (a,b)::r -> (let bs = html_render_flat ctx [b] in match html_render_size ctx a with + true, s -> bs,""^s^"","" + | false, s -> "",(s^""^bs^""),"")::html_render_deep ctx r + | TEX_FQ (a,b,c)::r -> (html_liberal (); + (let bs = html_render_flat ctx [b] in let cs = html_render_flat ctx [c] in + match html_render_size ctx a with + true, s -> (cs,""^s^"",bs) + | false, s -> ("",(s^""^bs^""^cs^""),""))::html_render_deep ctx r) + | TEX_DQN (a)::r -> (let bs = html_render_flat ctx [a] in "",(""^bs^""),"")::html_render_deep ctx r + | TEX_UQN (a)::r -> (let bs = html_render_flat ctx [a] in "",(""^bs^""),"")::html_render_deep ctx r + | TEX_FQN (a,b)::r -> (html_liberal (); + (let bs = html_render_flat ctx [a] in let cs = html_render_flat ctx [b] in + ("",(""^bs^""^cs^""),""))::html_render_deep ctx r) + | TEX_FUN1hl (_,(f1,f2),a)::r -> ("",f1,"")::(html_render_deep ctx [a]) @ ("",f2,"")::html_render_deep ctx r + | TEX_FUN1hf (_,ff,a)::r -> (html_render_deep (new_ctx ff) [a]) @ html_render_deep ctx r + | TEX_DECLh (_,ff,a)::r -> (html_render_deep (new_ctx ff) a) @ html_render_deep ctx r + | TEX_BOX (_,s)::r -> ("",s,"")::html_render_deep ctx r + | TEX_LITERAL (TEX_ONLY _)::_ -> raise Too_difficult_for_html + | TEX_FUN1 _::_ -> raise Too_difficult_for_html + | TEX_FUN2 _::_ -> raise Too_difficult_for_html + | TEX_FUN2nb _::_ -> raise Too_difficult_for_html + | TEX_FUN2sq _::_ -> raise Too_difficult_for_html + | TEX_INFIX _::_ -> raise Too_difficult_for_html + | TEX_MATRIX _::_ -> raise Too_difficult_for_html + | TEX_LR _::_ -> raise Too_difficult_for_html + | TEX_BIG _::_ -> raise Too_difficult_for_html + | [] -> [] + +let rec html_render_table = function + sf,u,d,("",a,"")::("",b,"")::r -> html_render_table (sf,u,d,(("",a^b,"")::r)) + | sf,u,d,(("",a,"") as c)::r -> html_render_table (c::sf,u,d,r) + | sf,u,d,((_,a,"") as c)::r -> html_render_table (c::sf,true,d,r) + | sf,u,d,(("",a,_) as c)::r -> html_render_table (c::sf,u,true,r) + | sf,u,d,((_,a,_) as c)::r -> html_render_table (c::sf,true,true,r) + | sf,false,false,[] -> mapjoin (function (u,m,d) -> m) (List.rev sf) + | sf,true,false,[] -> let ustr,mstr = List.fold_left (fun (us,ms) (u,m,d) -> (us^""^u^"",ms^""^u^"")) + ("","") (List.rev sf) in + "\n\n" ^ + "\t\t" ^ ustr ^ "\n" ^ + "\t\t" ^ mstr ^ "\n" ^ + "
\n" + | sf,false,true,[] -> let mstr,dstr = List.fold_left (fun (ms,ds) (u,m,d) -> (ms^""^m^"",ds^""^d^"")) + ("","") (List.rev sf) in + "\n\n" ^ + "\t\t" ^ mstr ^ "\n" ^ + "\t\t" ^ dstr ^ "\n" ^ + "
\n" + | sf,true,true,[] -> let ustr,mstr,dstr = List.fold_left (fun (us,ms,ds) (u,m,d) -> + (us^""^u^"",ms^""^m^"",ds^""^d^"")) ("","","") (List.rev sf) in + "\n\n" ^ + "\t\t" ^ ustr ^ "\n" ^ + "\t\t" ^ mstr ^ "\n" ^ + "\t\t" ^ dstr ^ "\n" ^ + "
\n" + +let html_render tree = html_render_table ([],false,false,html_render_deep CTX_NORMAL tree) + +let render tree = try Some (html_render tree) with _ -> None diff --git a/math/html.mli b/math/html.mli new file mode 100644 index 0000000..00b41cf --- /dev/null +++ b/math/html.mli @@ -0,0 +1,5 @@ +val render : Tex.t list -> string option +val html_render : Tex.t list -> string + +type conservativeness_t = CONSERVATIVE | MODERATE | LIBERAL +val conservativeness : conservativeness_t ref diff --git a/math/lexer.mll b/math/lexer.mll new file mode 100644 index 0000000..1702084 --- /dev/null +++ b/math/lexer.mll @@ -0,0 +1,108 @@ +{ + open Parser + open Render_info + open Tex +} +let space = [' ' '\t' '\n' '\r'] +let alpha = ['a'-'z' 'A'-'Z'] +let literal_id = ['a'-'z' 'A'-'Z'] +let literal_mn = ['0'-'9'] +let literal_uf_lt = [',' ':' ';' '?' '!' '\''] +let delimiter_uf_lt = ['(' ')' '.'] +let literal_uf_op = ['+' '-' '*' '='] +let delimiter_uf_op = ['/' '|'] +let boxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' ' '\128'-'\255'] +let aboxchars = ['0'-'9' 'a'-'z' 'A'-'Z' '+' '-' '*' ',' '=' '(' ')' ':' '/' ';' '?' '.' '!' ' '] + +rule token = parse + space + { token lexbuf } + | "\\text" space * '{' boxchars + '}' + { Texutil.tex_use_ams (); let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\text", String.sub str n (String.length str - n - 1)) } + | "\\mbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\mbox", String.sub str n (String.length str - n - 1)) } + | "\\hbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\hbox", String.sub str n (String.length str - n - 1)) } + | "\\vbox" space * '{' aboxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + BOX ("\\vbox", String.sub str n (String.length str - n - 1)) } + | "\\mbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\mbox", String.sub str n (String.length str - n - 1)) } + | "\\hbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\hbox", String.sub str n (String.length str - n - 1)) } + | "\\vbox" space * '{' boxchars + '}' + { let str = Lexing.lexeme lexbuf in + let n = String.index str '{' + 1 in + Texutil.tex_use_nonascii(); + BOX ("\\vbox", String.sub str n (String.length str - n - 1)) } + | literal_id { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_IT, str,str,MI,str)) } + | literal_mn { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_RM, str,str,MN,str)) } + | literal_uf_lt { let str = Lexing.lexeme lexbuf in LITERAL (HTMLABLEC (FONT_UFH, str,str)) } + | delimiter_uf_lt { let str = Lexing.lexeme lexbuf in DELIMITER (HTMLABLEC (FONT_UFH, str,str)) } + | "-" { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH,"-"," − ",MO,str))} + | literal_uf_op { let str = Lexing.lexeme lexbuf in LITERAL (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) } + | delimiter_uf_op { let str = Lexing.lexeme lexbuf in DELIMITER (MHTMLABLEC (FONT_UFH, str," "^str^" ",MO,str)) } + | "\\" alpha + { Texutil.find (Lexing.lexeme lexbuf) } + | "\\sqrt" space * "[" { FUN_AR1opt "\\sqrt" } + | "\\xleftarrow" space * "[" { Texutil.tex_use_ams(); FUN_AR1opt "\\xleftarrow" } + | "\\xrightarrow" space * "[" { Texutil.tex_use_ams(); FUN_AR1opt "\\xrightarrow" } + | "\\," { LITERAL (HTMLABLE (FONT_UF, "\\,"," ")) } + | "\\ " { LITERAL (HTMLABLE (FONT_UF, "\\ "," ")) } + | "\\;" { LITERAL (HTMLABLE (FONT_UF, "\\;"," ")) } + | "\\!" { LITERAL (TEX_ONLY "\\!") } + | "\\{" { DELIMITER (HTMLABLEC(FONT_UFH,"\\{","{")) } + | "\\}" { DELIMITER (HTMLABLEC(FONT_UFH,"\\}","}")) } + | "\\|" { DELIMITER (HTMLABLE (FONT_UFH,"\\|","||")) } + | "\\_" { LITERAL (HTMLABLEC(FONT_UFH,"\\_","_")) } + | "\\#" { LITERAL (HTMLABLE (FONT_UFH,"\\#","#")) } + | "\\%" { LITERAL (HTMLABLE (FONT_UFH,"\\%","%")) } + | "\\$" { LITERAL (HTMLABLE (FONT_UFH,"\\$","$")) } + | "\\&" { LITERAL (HTMLABLEC (FONT_RM,"\\&","&")) } + | "&" { NEXT_CELL } + | "\\\\" { NEXT_ROW } + | "\\begin{matrix}" { Texutil.tex_use_ams(); BEGIN__MATRIX } + | "\\end{matrix}" { END__MATRIX } + | "\\begin{pmatrix}" { Texutil.tex_use_ams(); BEGIN_PMATRIX } + | "\\end{pmatrix}" { END_PMATRIX } + | "\\begin{bmatrix}" { Texutil.tex_use_ams(); BEGIN_BMATRIX } + | "\\end{bmatrix}" { END_BMATRIX } + | "\\begin{Bmatrix}" { Texutil.tex_use_ams(); BEGIN_BBMATRIX } + | "\\end{Bmatrix}" { END_BBMATRIX } + | "\\begin{vmatrix}" { Texutil.tex_use_ams(); BEGIN_VMATRIX } + | "\\end{vmatrix}" { END_VMATRIX } + | "\\begin{Vmatrix}" { Texutil.tex_use_ams(); BEGIN_VVMATRIX } + | "\\end{Vmatrix}" { END_VVMATRIX } + | "\\begin{array}" { Texutil.tex_use_ams(); BEGIN_ARRAY } + | "\\end{array}" { END_ARRAY } + | "\\begin{align}" { Texutil.tex_use_ams(); BEGIN_ALIGN } + | "\\end{align}" { END_ALIGN } + | "\\begin{alignat}" { Texutil.tex_use_ams(); BEGIN_ALIGNAT } + | "\\end{alignat}" { END_ALIGNAT } + | "\\begin{smallmatrix}" { Texutil.tex_use_ams(); BEGIN_SMALLMATRIX } + | "\\end{smallmatrix}" { END_SMALLMATRIX } + | "\\begin{cases}" { Texutil.tex_use_ams(); BEGIN_CASES } + | "\\end{cases}" { END_CASES } + | '>' { LITERAL (HTMLABLEC(FONT_UFH,">"," > ")) } + | '<' { LITERAL (HTMLABLEC(FONT_UFH,"<"," < ")) } + | '%' { LITERAL (HTMLABLEC(FONT_UFH,"\\%","%")) } + | '$' { LITERAL (HTMLABLEC(FONT_UFH,"\\$","$")) } + | '~' { LITERAL (HTMLABLE (FONT_UF, "~"," ")) } + | '[' { DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) } + | ']' { SQ_CLOSE } + | '{' { CURLY_OPEN } + | '}' { CURLY_CLOSE } + | '^' { SUP } + | '_' { SUB } + | eof { EOF } diff --git a/math/mathml.ml b/math/mathml.ml new file mode 100644 index 0000000..b6c76af --- /dev/null +++ b/math/mathml.ml @@ -0,0 +1,20 @@ +open Tex +open Render_info + +type t = TREE_MN of string | TREE_MO of string | TREE_MI of string + +let rec make_mathml_tree = function + TREE_MN a::otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,b))::itr -> make_mathml_tree(TREE_MN (a^b)::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MN,a))::itr -> make_mathml_tree(TREE_MN a::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MO,a))::itr -> make_mathml_tree(TREE_MO a::otr,itr) + | otr,TEX_LITERAL(MHTMLABLEC(_,_,_,MI,a))::itr -> make_mathml_tree(TREE_MI a::otr,itr) + | otr,TEX_CURLY(crl)::itr -> make_mathml_tree(otr,crl@itr) + | otr,[] -> List.rev otr + | _ -> failwith "failed to render mathml" + +let render_mathml_tree = function + TREE_MN s -> ""^s^"" + | TREE_MI s -> ""^s^"" + | TREE_MO s -> ""^s^"" + +let render tree = try Some (Util.mapjoin render_mathml_tree (make_mathml_tree ([],tree))) with _ -> None diff --git a/math/mathml.mli b/math/mathml.mli new file mode 100644 index 0000000..fcc2cd4 --- /dev/null +++ b/math/mathml.mli @@ -0,0 +1 @@ +val render : Tex.t list -> string option diff --git a/math/parser.mly b/math/parser.mly new file mode 100644 index 0000000..29882fb --- /dev/null +++ b/math/parser.mly @@ -0,0 +1,118 @@ +%{ + open Tex + open Render_info + + let sq_close_ri = HTMLABLEC(FONT_UFH,"]", "]") +%} +%token LITERAL DELIMITER +%token FUN_AR2 FUN_INFIX FUN_AR1 DECL FUN_AR1opt BIG FUN_AR2nb +%token BOX +%token FUN_AR1hl +%token FUN_AR1hf DECLh +%token Tex.t->string*string*string)> FUN_AR2h +%token Tex.t list->string*string*string)> FUN_INFIXh +%token EOF CURLY_OPEN CURLY_CLOSE SUB SUP SQ_CLOSE NEXT_CELL NEXT_ROW +%token BEGIN__MATRIX BEGIN_PMATRIX BEGIN_BMATRIX BEGIN_BBMATRIX BEGIN_VMATRIX BEGIN_VVMATRIX BEGIN_CASES BEGIN_ARRAY BEGIN_ALIGN BEGIN_ALIGNAT BEGIN_SMALLMATRIX +%token END__MATRIX END_PMATRIX END_BMATRIX END_BBMATRIX END_VMATRIX END_VVMATRIX END_CASES END_ARRAY END_ALIGN END_ALIGNAT END_SMALLMATRIX +%token LEFT RIGHT +%type tex_expr +%start tex_expr + +%% +tex_expr: + expr EOF { $1 } + | ne_expr FUN_INFIX ne_expr EOF + { [TEX_INFIX($2,$1,$3)] } + | ne_expr FUN_INFIXh ne_expr EOF + { let t,h=$2 in [TEX_INFIXh(t,h,$1,$3)] } +expr: + /* */ { [] } + | ne_expr { $1 } +ne_expr: + lit_aq expr { $1 :: $2 } + | litsq_aq expr { $1 :: $2 } + | DECLh expr { let t,h = $1 in [TEX_DECLh(t,h,$2)] } +litsq_aq: + litsq_zq { $1 } + | litsq_dq { let base,downi = $1 in TEX_DQ(base,downi) } + | litsq_uq { let base,upi = $1 in TEX_UQ(base,upi)} + | litsq_fq { $1 } +litsq_fq: + litsq_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) } + | litsq_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) } +litsq_uq: + litsq_zq SUP lit { $1,$3 } +litsq_dq: + litsq_zq SUB lit { $1,$3 } +litsq_zq: + | SQ_CLOSE { TEX_LITERAL sq_close_ri } +expr_nosqc: + /* */ { [] } + | lit_aq expr_nosqc { $1 :: $2 } +lit_aq: + lit { $1 } + | lit_dq { let base,downi = $1 in TEX_DQ(base,downi) } + | lit_uq { let base,upi = $1 in TEX_UQ(base,upi)} + | lit_dqn { TEX_DQN($1) } + | lit_uqn { TEX_UQN($1) } + | lit_fq { $1 } + +lit_fq: + lit_dq SUP lit { let base,downi = $1 in TEX_FQ(base,downi,$3) } + | lit_uq SUB lit { let base,upi = $1 in TEX_FQ(base,$3,upi) } + | lit_dqn SUP lit { TEX_FQN($1, $3) } + +lit_uq: + lit SUP lit { $1,$3 } +lit_dq: + lit SUB lit { $1,$3 } +lit_uqn: + SUP lit { $2 } +lit_dqn: + SUB lit { $2 } + + +left: + LEFT DELIMITER { $2 } + | LEFT SQ_CLOSE { sq_close_ri } +right: + RIGHT DELIMITER { $2 } + | RIGHT SQ_CLOSE { sq_close_ri } +lit: + LITERAL { TEX_LITERAL $1 } + | DELIMITER { TEX_LITERAL $1 } + | BIG DELIMITER { TEX_BIG ($1,$2) } + | BIG SQ_CLOSE { TEX_BIG ($1,sq_close_ri) } + | left expr right { TEX_LR ($1,$3,$2) } + | FUN_AR1 lit { TEX_FUN1($1,$2) } + | FUN_AR1hl lit { let t,h=$1 in TEX_FUN1hl(t,h,$2) } + | FUN_AR1hf lit { let t,h=$1 in TEX_FUN1hf(t,h,$2) } + | FUN_AR1opt expr_nosqc SQ_CLOSE lit { TEX_FUN2sq($1,TEX_CURLY $2,$4) } + | FUN_AR2 lit lit { TEX_FUN2($1,$2,$3) } + | FUN_AR2nb lit lit { TEX_FUN2nb($1,$2,$3) } + | FUN_AR2h lit lit { let t,h=$1 in TEX_FUN2h(t,h,$2,$3) } + | BOX { let bt,s = $1 in TEX_BOX (bt,s) } + | CURLY_OPEN expr CURLY_CLOSE + { TEX_CURLY $2 } + | CURLY_OPEN ne_expr FUN_INFIX ne_expr CURLY_CLOSE + { TEX_INFIX($3,$2,$4) } + | CURLY_OPEN ne_expr FUN_INFIXh ne_expr CURLY_CLOSE + { let t,h=$3 in TEX_INFIXh(t,h,$2,$4) } + | BEGIN__MATRIX matrix END__MATRIX { TEX_MATRIX ("matrix", $2) } + | BEGIN_PMATRIX matrix END_PMATRIX { TEX_MATRIX ("pmatrix", $2) } + | BEGIN_BMATRIX matrix END_BMATRIX { TEX_MATRIX ("bmatrix", $2) } + | BEGIN_BBMATRIX matrix END_BBMATRIX { TEX_MATRIX ("Bmatrix", $2) } + | BEGIN_VMATRIX matrix END_VMATRIX { TEX_MATRIX ("vmatrix", $2) } + | BEGIN_VVMATRIX matrix END_VVMATRIX { TEX_MATRIX ("Vmatrix", $2) } + | BEGIN_ARRAY matrix END_ARRAY { TEX_MATRIX ("array", $2) } + | BEGIN_ALIGN matrix END_ALIGN { TEX_MATRIX ("aligned", $2) } + | BEGIN_ALIGNAT matrix END_ALIGNAT { TEX_MATRIX ("alignedat", $2) } + | BEGIN_SMALLMATRIX matrix END_SMALLMATRIX { TEX_MATRIX ("smallmatrix", $2) } + | BEGIN_CASES matrix END_CASES { TEX_MATRIX ("cases", $2) } +matrix: + line { [$1] } + | line NEXT_ROW matrix { $1::$3 } +line: + expr { [$1] } + | expr NEXT_CELL line { $1::$3 } +;; diff --git a/math/render.ml b/math/render.ml new file mode 100644 index 0000000..5a02b67 --- /dev/null +++ b/math/render.ml @@ -0,0 +1,58 @@ +(* vim: set sw=8 ts=8 et: *) + +let cmd_dvips tmpprefix = "dvips -q -R -E " ^ tmpprefix ^ ".dvi -f >" ^ tmpprefix ^ ".ps" +let cmd_latex tmpprefix = "latex " ^ tmpprefix ^ ".tex >/dev/null" + +(* Putting -transparent white in converts arguments will sort-of give you transperancy *) +let cmd_convert tmpprefix finalpath = "convert -quality 100 -density 120 " ^ tmpprefix ^ ".ps " ^ finalpath ^ " >/dev/null 2>/dev/null" + +(* Putting -bg Transparent in dvipng's arguments will give full-alpha transparency *) +(* Note that IE have problems with such PNGs and need an additional javascript snippet *) +(* Putting -bg transparent in dvipng's arguments will give binary transparency *) +let cmd_dvipng tmpprefix finalpath backcolor = "dvipng -bg \'" ^ backcolor ^ "\' -gamma 1.5 -D 120 -T tight --strict " ^ tmpprefix ^ ".dvi -o " ^ finalpath ^ " >/dev/null 2>/dev/null" + +exception ExternalCommandFailure of string + +let render tmppath finalpath outtex md5 backcolor = + let tmpprefix0 = (string_of_int (Unix.getpid ()))^"_"^md5 in + let tmpprefix = (tmppath^"/"^tmpprefix0) in + let unlink_all () = + begin + (* Commenting this block out will aid in debugging *) + Sys.remove (tmpprefix ^ ".dvi"); + Sys.remove (tmpprefix ^ ".aux"); + Sys.remove (tmpprefix ^ ".log"); + Sys.remove (tmpprefix ^ ".tex"); + if Sys.file_exists (tmpprefix ^ ".ps") + then Sys.remove (tmpprefix ^ ".ps"); + end in + + let f = (Util.open_out_unless_exists (tmpprefix ^ ".tex")) in + begin + (* Assemble final output in file 'f' *) + output_string f (Texutil.get_preface ()); + output_string f outtex; + output_string f (Texutil.get_footer ()); + close_out f; + + (* TODO: document *) + if Util.run_in_other_directory tmppath (cmd_latex tmpprefix0) != 0 + then ( + unlink_all (); raise (ExternalCommandFailure "latex") + ) else if (Sys.command (cmd_dvipng tmpprefix (finalpath^"/"^md5^".png") backcolor) != 0) + then ( + if (Sys.command (cmd_dvips tmpprefix) != 0) + then ( + unlink_all (); + raise (ExternalCommandFailure "dvips") + ) else if (Sys.command (cmd_convert tmpprefix (finalpath^"/"^md5^".png")) != 0) + then ( + unlink_all (); + raise (ExternalCommandFailure "convert") + ) else ( + unlink_all () + ) + ) else ( + unlink_all () + ) + end diff --git a/math/render_info.mli b/math/render_info.mli new file mode 100644 index 0000000..d5e7fde --- /dev/null +++ b/math/render_info.mli @@ -0,0 +1,20 @@ +type font_force = + FONTFORCE_IT + | FONTFORCE_RM +type font_class = + FONT_IT (* IT default, may be forced to be RM *) + | FONT_RM (* RM default, may be forced to be IT *) + | FONT_UF (* not affected by IT/RM setting *) + | FONT_RTI (* RM - any, IT - not available in HTML *) + | FONT_UFH (* in TeX UF, in HTML RM *) +type math_class = + MN + | MI + | MO +type t = + HTMLABLEC of font_class * string * string + | HTMLABLEM of font_class * string * string + | HTMLABLE of font_class * string * string + | MHTMLABLEC of font_class * string * string * math_class * string + | HTMLABLE_BIG of string * string + | TEX_ONLY of string diff --git a/math/tex.mli b/math/tex.mli new file mode 100644 index 0000000..f2ed37c --- /dev/null +++ b/math/tex.mli @@ -0,0 +1,23 @@ +type t = + TEX_LITERAL of Render_info.t + | TEX_CURLY of t list + | TEX_FQ of t * t * t + | TEX_DQ of t * t + | TEX_UQ of t * t + | TEX_FQN of t * t + | TEX_DQN of t + | TEX_UQN of t + | TEX_LR of Render_info.t * Render_info.t * t list + | TEX_BOX of string * string + | TEX_BIG of string * Render_info.t + | TEX_FUN1 of string * t + | TEX_FUN2 of string * t * t + | TEX_FUN2nb of string * t * t + | TEX_INFIX of string * t list * t list + | TEX_FUN2sq of string * t * t + | TEX_FUN1hl of string * (string * string) * t + | TEX_FUN1hf of string * Render_info.font_force * t + | TEX_FUN2h of string * (t -> t -> string * string * string) * t * t + | TEX_INFIXh of string * (t list -> t list -> string * string * string) * t list * t list + | TEX_MATRIX of string * t list list list + | TEX_DECLh of string * Render_info.font_force * t list diff --git a/math/texutil.ml b/math/texutil.ml new file mode 100644 index 0000000..cc7f48f --- /dev/null +++ b/math/texutil.ml @@ -0,0 +1,760 @@ +(* vim: set sw=8 ts=8 et: *) +open Parser +open Render_info +open Tex +open Util + +let tex_part = function + HTMLABLE (_,t,_) -> t + | HTMLABLEM (_,t,_) -> t + | HTMLABLEC (_,t,_) -> t + | MHTMLABLEC (_,t,_,_,_) -> t + | HTMLABLE_BIG (t,_) -> t + | TEX_ONLY t -> t + +let rec render_tex = function + TEX_FQ (a,b,c) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}^{" ^ (render_tex c) ^ "}" + | TEX_DQ (a,b) -> (render_tex a) ^ "_{" ^ (render_tex b) ^ "}" + | TEX_UQ (a,b) -> (render_tex a) ^ "^{" ^ (render_tex b) ^ "}" + | TEX_FQN (a,b) -> "_{" ^ (render_tex a) ^ "}^{" ^ (render_tex b) ^ "}" + | TEX_DQN (a) -> "_{" ^ (render_tex a) ^ "}" + | TEX_UQN (a) -> "^{" ^ (render_tex a) ^ "}" + | TEX_LITERAL s -> tex_part s + | TEX_FUN1 (f,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_FUN1hl (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_FUN1hf (f,_,a) -> "{" ^ f ^ " " ^ (render_tex a) ^ "}" + | TEX_DECLh (f,_,a) -> "{" ^ f ^ "{" ^ (mapjoin render_tex a) ^ "}}" + | TEX_FUN2 (f,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}" + | TEX_FUN2nb (f,a,b) -> f ^ (render_tex a) ^ (render_tex b) + | TEX_FUN2h (f,_,a,b) -> "{" ^ f ^ " " ^ (render_tex a) ^ (render_tex b) ^ "}" + | TEX_FUN2sq (f,a,b) -> "{" ^ f ^ "[ " ^ (render_tex a) ^ "]" ^ (render_tex b) ^ "}" + | TEX_CURLY (tl) -> "{" ^ (mapjoin render_tex tl) ^ "}" + | TEX_INFIX (s,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}" + | TEX_INFIXh (s,_,ll,rl) -> "{" ^ (mapjoin render_tex ll) ^ " " ^ s ^ "" ^ (mapjoin render_tex rl) ^ "}" + | TEX_BOX (bt,s) -> "{"^bt^"{" ^ s ^ "}}" + | TEX_BIG (bt,d) -> "{"^bt^(tex_part d)^"}" + | TEX_MATRIX (t,rows) -> "{\\begin{"^t^"}"^(mapjoine "\\\\" (mapjoine "&" (mapjoin render_tex)) rows)^"\\end{"^t^"}}" + | TEX_LR (l,r,tl) -> "\\left "^(tex_part l)^(mapjoin render_tex tl)^"\\right "^(tex_part r) + + +(* Dynamic loading*) +type encoding_t = LATIN1 | LATIN2 | UTF8 + +(* module properties *) +let modules_ams = ref false +let modules_nonascii = ref false +let modules_encoding = ref UTF8 +let modules_color = ref false + +(* wrappers to easily set / reset module properties *) +let tex_use_ams () = modules_ams := true +let tex_use_nonascii () = modules_nonascii := true +let tex_use_color () = modules_color := true +let tex_mod_reset () = ( + modules_ams := false; + modules_nonascii := false; + modules_encoding := UTF8; + modules_color := false + ) + +(* Return TeX fragment for one of the encodings in (UTF8,LATIN1,LATIN2) *) +let get_encoding = function + UTF8 -> "\\usepackage{ucs}\n\\usepackage[utf8]{inputenc}\n" + | LATIN1 -> "\\usepackage[latin1]{inputenc}\n" + | LATIN2 -> "\\usepackage[latin2]{inputenc}\n" + +(* TeX fragment inserted before the output *) +let get_preface () = "\\nonstopmode\n\\documentclass[12pt]{article}\n" ^ + (if !modules_nonascii then get_encoding !modules_encoding else "") ^ + (if !modules_ams then "\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n" else "") ^ + (if !modules_color then "\\usepackage[dvips,usenames]{color}\n" else "") ^ + "\\usepackage{cancel}\n\\pagestyle{empty}\n\\begin{document}\n$$\n" + +(* TeX fragment appended after the content *) +let get_footer () = "\n$$\n\\end{document}\n" + +(* Default to UTF8 *) +let set_encoding = function + "ISO-8859-1" -> modules_encoding := LATIN1 + | "iso-8859-1" -> modules_encoding := LATIN1 + | "ISO-8859-2" -> modules_encoding := LATIN2 + | _ -> modules_encoding := UTF8 + +(* Turn that into hash table lookup *) +exception Illegal_tex_function of string + +let find = function + "\\alpha" -> LITERAL (HTMLABLEC (FONT_UF, "\\alpha ", "α")) + | "\\Alpha" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{A}", "Α"))) + | "\\beta" -> LITERAL (HTMLABLEC (FONT_UF, "\\beta ", "β")) + | "\\Beta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{B}", "Β"))) + | "\\gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\gamma ", "γ")) + | "\\Gamma" -> LITERAL (HTMLABLEC (FONT_UF, "\\Gamma ", "Γ")) + | "\\delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\delta ", "δ")) + | "\\Delta" -> LITERAL (HTMLABLEC (FONT_UF, "\\Delta ", "Δ")) + | "\\epsilon" -> LITERAL (TEX_ONLY "\\epsilon ") + | "\\Epsilon" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{E}", "Ε"))) + | "\\varepsilon" -> LITERAL (TEX_ONLY "\\varepsilon ") + | "\\zeta" -> LITERAL (HTMLABLEC (FONT_UF, "\\zeta ", "ζ")) + | "\\Zeta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{Z}", "Ζ"))) + | "\\eta" -> LITERAL (HTMLABLEC (FONT_UF, "\\eta ", "η")) + | "\\Eta" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{H}", "Η"))) + | "\\theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\theta ", "θ")) + | "\\Theta" -> LITERAL (HTMLABLEC (FONT_UF, "\\Theta ", "Θ")) + | "\\vartheta" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "ϑ")) + | "\\thetasym" -> LITERAL (HTMLABLE (FONT_UF, "\\vartheta ", "ϑ")) + | "\\iota" -> LITERAL (HTMLABLEC (FONT_UF, "\\iota ", "ι")) + | "\\Iota" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{I}", "Ι"))) + | "\\kappa" -> LITERAL (HTMLABLEC (FONT_UF, "\\kappa ", "κ")) + | "\\Kappa" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{K}", "Κ"))) + | "\\lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\lambda ", "λ")) + | "\\Lambda" -> LITERAL (HTMLABLEC (FONT_UF, "\\Lambda ", "Λ")) + | "\\mu" -> LITERAL (HTMLABLEC (FONT_UF, "\\mu ", "μ")) + | "\\Mu" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{M}", "Μ"))) + | "\\nu" -> LITERAL (HTMLABLEC (FONT_UF, "\\nu ", "ν")) + | "\\Nu" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{N}", "Ν"))) + | "\\omicron" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{o}", "ο"))) + | "\\Omicron" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{O}", "Ο"))) + | "\\pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\pi ", "π")) + | "\\Pi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Pi ", "Π")) + | "\\varpi" -> LITERAL (TEX_ONLY "\\varpi ") + | "\\rho" -> LITERAL (HTMLABLEC (FONT_UF, "\\rho ", "ρ")) + | "\\Rho" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{P}", "Ρ"))) + | "\\varrho" -> LITERAL (TEX_ONLY "\\varrho ") + | "\\sim" -> LITERAL (HTMLABLEC (FONT_UF, "\\sim ", "∼")) + | "\\sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\sigma ", "σ")) + | "\\Sigma" -> LITERAL (HTMLABLEC (FONT_UF, "\\Sigma ", "Σ")) + | "\\varsigma" -> LITERAL (TEX_ONLY "\\varsigma ") + | "\\tau" -> LITERAL (HTMLABLEC (FONT_UF, "\\tau ", "τ")) + | "\\Tau" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{T}", "Τ"))) + | "\\upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\upsilon ", "υ")) + | "\\Upsilon" -> LITERAL (HTMLABLEC (FONT_UF, "\\Upsilon ", "Υ")) + | "\\phi" -> LITERAL (TEX_ONLY "\\phi ") + | "\\Phi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Phi ", "Φ")) + | "\\varphi" -> LITERAL (TEX_ONLY "\\varphi ") + | "\\chi" -> LITERAL (HTMLABLEC (FONT_UF, "\\chi ", "χ")) + | "\\Chi" -> (tex_use_ams (); LITERAL (HTMLABLEC (FONT_UF, + "\\mathrm{X}", "Χ"))) + | "\\psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\psi ", "ψ")) + | "\\Psi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Psi ", "Ψ")) + | "\\omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\omega ", "ω")) + | "\\Omega" -> LITERAL (HTMLABLEC (FONT_UF, "\\Omega ", "Ω")) + | "\\xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\xi ", "ξ")) + | "\\Xi" -> LITERAL (HTMLABLEC (FONT_UF, "\\Xi ", "Ξ")) + | "\\aleph" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\alef" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\alefsym" -> LITERAL (HTMLABLE (FONT_UF, "\\aleph ", "ℵ")) + | "\\larr" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "←")) + | "\\leftarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\leftarrow ", "←")) + | "\\rarr" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "→")) + | "\\to" -> LITERAL (HTMLABLEM (FONT_UF, "\\to ", "→")) + | "\\gets" -> LITERAL (HTMLABLEM (FONT_UF, "\\gets ", "←")) + | "\\rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\rightarrow ", "→")) + | "\\longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longleftarrow ", "←")) + | "\\longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\longrightarrow ", "→")) + | "\\Larr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\lArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\Leftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftarrow ", "⇐")) + | "\\Rarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\rArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\Rightarrow" -> LITERAL (HTMLABLEM (FONT_UF, "\\Rightarrow ", "⇒")) + | "\\mapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\mapsto ", "→")) + | "\\longmapsto" -> LITERAL (HTMLABLE (FONT_UF, "\\longmapsto ", "→")) + | "\\Longleftarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longleftarrow ", "⇐")) + | "\\Longrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Longrightarrow ", "⇒")) + | "\\uarr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "↑")) + | "\\uparrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\uparrow ", "↑")) + | "\\uArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\Uarr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\Uparrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Uparrow ", "⇑")) + | "\\darr" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "↓")) + | "\\downarrow" -> DELIMITER (HTMLABLEM (FONT_UF, "\\downarrow ", "↓")) + | "\\dArr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\Darr" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\Downarrow" -> DELIMITER (HTMLABLE (FONT_UF, "\\Downarrow ", "⇓")) + | "\\updownarrow" -> DELIMITER (TEX_ONLY "\\updownarrow ") + | "\\Updownarrow" -> DELIMITER (TEX_ONLY "\\Updownarrow ") + | "\\ulcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\ulcorner ")) + | "\\urcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\urcorner ")) + | "\\llcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\llcorner ")) + | "\\lrcorner" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\lrcorner ")) + | "\\twoheadleftarrow" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\twoheadleftarrow ")) + | "\\twoheadrightarrow" -> (tex_use_ams (); DELIMITER (TEX_ONLY "\\twoheadrightarrow ")) + | "\\xleftarrow" -> (tex_use_ams (); FUN_AR1 "\\xleftarrow ") + | "\\xrightarrow" -> (tex_use_ams (); FUN_AR1 "\\xrightarrow ") + | "\\rightleftharpoons" -> DELIMITER (TEX_ONLY "\\rightleftharpoons ") + | "\\leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\harr" -> LITERAL (HTMLABLE (FONT_UF, "\\leftrightarrow ", "↔")) + | "\\Leftrightarrow" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\Lrarr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\Harr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\lrArr" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\hAar" -> LITERAL (HTMLABLE (FONT_UF, "\\Leftrightarrow ", "⇔")) + | "\\longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\longleftrightarrow ", "↔")) + | "\\Longleftrightarrow"->LITERAL (HTMLABLE (FONT_UF, "\\Longleftrightarrow ", "↔")) + | "\\iff" -> LITERAL (HTMLABLE (FONT_UF, "\\iff ", "↔")) + | "\\ll" -> LITERAL (TEX_ONLY "\\ll ") + | "\\gg" -> LITERAL (TEX_ONLY "\\gg ") + | "\\div" -> LITERAL (TEX_ONLY "\\div ") + | "\\searrow" -> LITERAL (TEX_ONLY "\\searrow ") + | "\\nearrow" -> LITERAL (TEX_ONLY "\\nearrow ") + | "\\swarrow" -> LITERAL (TEX_ONLY "\\swarrow ") + | "\\nwarrow" -> LITERAL (TEX_ONLY "\\nwarrow ") + | "\\simeq" -> LITERAL (TEX_ONLY "\\simeq ") + | "\\ast" -> LITERAL (TEX_ONLY "\\ast ") + | "\\star" -> LITERAL (TEX_ONLY "\\star ") + | "\\ell" -> LITERAL (TEX_ONLY "\\ell ") + | "\\P" -> LITERAL (TEX_ONLY "\\P ") + | "\\smile" -> LITERAL (TEX_ONLY "\\smile ") + | "\\frown" -> LITERAL (TEX_ONLY "\\frown ") + | "\\bigcap" -> LITERAL (TEX_ONLY "\\bigcap ") + | "\\bigodot" -> LITERAL (TEX_ONLY "\\bigodot ") + | "\\bigcup" -> LITERAL (TEX_ONLY "\\bigcup ") + | "\\bigotimes" -> LITERAL (TEX_ONLY "\\bigotimes ") + | "\\coprod" -> LITERAL (TEX_ONLY "\\coprod ") + | "\\bigsqcup" -> LITERAL (TEX_ONLY "\\bigsqcup ") + | "\\bigoplus" -> LITERAL (TEX_ONLY "\\bigoplus ") + | "\\bigvee" -> LITERAL (TEX_ONLY "\\bigvee ") + | "\\biguplus" -> LITERAL (TEX_ONLY "\\biguplus ") + | "\\oint" -> LITERAL (TEX_ONLY "\\oint ") + | "\\bigwedge" -> LITERAL (TEX_ONLY "\\bigwedge ") + | "\\models" -> LITERAL (TEX_ONLY "\\models ") + | "\\vdash" -> LITERAL (TEX_ONLY "\\vdash ") + | "\\triangle" -> LITERAL (TEX_ONLY "\\triangle ") + | "\\bowtie" -> LITERAL (TEX_ONLY "\\bowtie ") + | "\\wr" -> LITERAL (TEX_ONLY "\\wr ") + | "\\triangleleft" -> LITERAL (TEX_ONLY "\\triangleleft ") + | "\\triangleright" -> LITERAL (TEX_ONLY "\\triangleright ") + | "\\textvisiblespace" -> LITERAL (TEX_ONLY "\\textvisiblespace ") + | "\\ker" -> LITERAL (HTMLABLEC(FONT_UFH,"\\ker ","ker")) + | "\\lim" -> LITERAL (TEX_ONLY "\\lim ") + | "\\limsup" -> LITERAL (TEX_ONLY "\\limsup ") + | "\\liminf" -> LITERAL (TEX_ONLY "\\liminf ") + | "\\sup" -> LITERAL (TEX_ONLY "\\sup ") + | "\\Pr" -> LITERAL (TEX_ONLY "\\Pr ") + | "\\hom" -> LITERAL (HTMLABLEC(FONT_UFH,"\\hom ","hom")) + | "\\arg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arg ","arg")) + | "\\dim" -> LITERAL (HTMLABLEC(FONT_UFH,"\\dim ","dim")) + | "\\inf" -> LITERAL (TEX_ONLY "\\inf ") + | "\\circ" -> LITERAL (TEX_ONLY "\\circ ") + | "\\hbar" -> LITERAL (TEX_ONLY "\\hbar ") + | "\\imath" -> LITERAL (TEX_ONLY "\\imath ") + | "\\jmath" -> LITERAL (TEX_ONLY "\\jmath ") + | "\\lnot" -> LITERAL (TEX_ONLY "\\lnot ") + | "\\hookrightarrow" -> LITERAL (TEX_ONLY "\\hookrightarrow ") + | "\\hookleftarrow" -> LITERAL (TEX_ONLY "\\hookleftarrow ") + | "\\mp" -> LITERAL (TEX_ONLY "\\mp ") + | "\\approx" -> LITERAL (HTMLABLE (FONT_UF, "\\approx ", "≈")) + | "\\propto" -> LITERAL (TEX_ONLY "\\propto ") + | "\\flat" -> LITERAL (TEX_ONLY "\\flat ") + | "\\sharp" -> LITERAL (TEX_ONLY "\\sharp ") + | "\\natural" -> LITERAL (TEX_ONLY "\\natural ") + | "\\int" -> LITERAL (HTMLABLE_BIG ("\\int ", "∫")) + | "\\sum" -> LITERAL (HTMLABLE_BIG ("\\sum ", "∑")) + | "\\prod" -> LITERAL (HTMLABLE_BIG ("\\prod ", "∏")) + | "\\vdots" -> LITERAL (TEX_ONLY "\\vdots ") + | "\\limits" -> LITERAL (TEX_ONLY "\\limits ") + | "\\nolimits" -> LITERAL (TEX_ONLY "\\nolimits ") + | "\\top" -> LITERAL (TEX_ONLY "\\top ") + | "\\sin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sin ","sin")) + | "\\cos" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cos ","cos")) + | "\\sinh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sinh ","sinh")) + | "\\cosh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cosh ","cosh")) + | "\\tan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tan ","tan")) + | "\\tanh" -> LITERAL (HTMLABLEC(FONT_UFH,"\\tanh ","tanh")) + | "\\sec" -> LITERAL (HTMLABLEC(FONT_UFH,"\\sec ","sec")) + | "\\csc" -> LITERAL (HTMLABLEC(FONT_UFH,"\\csc ","csc")) + | "\\arcsin" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arcsin ","arcsin")) + | "\\arctan" -> LITERAL (HTMLABLEC(FONT_UFH,"\\arctan ","arctan")) + | "\\arccos" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccos}}","arccos"))) + | "\\arccot" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccot}}","arccot"))) + | "\\arcsec" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arcsec}}","arcsec"))) + | "\\arccsc" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{arccsc}}","arccsc"))) + | "\\sgn" -> (tex_use_ams (); LITERAL (HTMLABLEC(FONT_UFH,"\\mathop{\\mathrm{sgn}}","sgn"))) + | "\\cot" -> LITERAL (HTMLABLEC(FONT_UFH,"\\cot ","cot")) + | "\\coth" -> LITERAL (HTMLABLEC(FONT_UFH,"\\coth ","coth")) + | "\\log" -> LITERAL (HTMLABLEC(FONT_UFH,"\\log ", "log")) + | "\\lg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\lg ", "lg")) + | "\\ln" -> LITERAL (HTMLABLEC(FONT_UFH,"\\ln ", "ln")) + | "\\exp" -> LITERAL (HTMLABLEC(FONT_UFH,"\\exp ", "exp")) + | "\\min" -> LITERAL (HTMLABLEC(FONT_UFH,"\\min ", "min")) + | "\\max" -> LITERAL (HTMLABLEC(FONT_UFH,"\\max ", "max")) + | "\\gcd" -> LITERAL (HTMLABLEC(FONT_UFH,"\\gcd ", "gcd")) + | "\\deg" -> LITERAL (HTMLABLEC(FONT_UFH,"\\deg ", "deg")) + | "\\det" -> LITERAL (HTMLABLEC(FONT_UFH,"\\det ", "det")) + | "\\bullet" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "•")) + | "\\bull" -> LITERAL (HTMLABLE (FONT_UFH, "\\bullet ", "•")) + | "\\angle" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\angle ", "∠"))) + | "\\dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\dagger ", "†")) + | "\\ddagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "‡")) + | "\\Dagger" -> LITERAL (HTMLABLEM(FONT_UFH, "\\ddagger ", "‡")) + | "\\colon" -> LITERAL (HTMLABLEC(FONT_UFH, "\\colon ", ":")) + | "\\Vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\Vert ", "||")) + | "\\vert" -> DELIMITER (HTMLABLEM(FONT_UFH, "\\vert ", "|")) + | "\\wp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "℘")) + | "\\weierp" -> LITERAL (HTMLABLE (FONT_UF, "\\wp ", "℘")) + | "\\wedge" -> LITERAL (HTMLABLE (FONT_UF, "\\wedge ", "∧")) + | "\\and" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "∧")) + | "\\land" -> LITERAL (HTMLABLE (FONT_UF, "\\land ", "∧")) + | "\\vee" -> LITERAL (HTMLABLE (FONT_UF, "\\vee ", "∨")) + | "\\or" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "∨")) + | "\\lor" -> LITERAL (HTMLABLE (FONT_UF, "\\lor ", "∨")) + | "\\sub" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "⊂")) + | "\\supe" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "⊇")) + | "\\sube" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "⊆")) + | "\\supset" -> LITERAL (HTMLABLE (FONT_UF, "\\supset ", "⊃")) + | "\\subset" -> LITERAL (HTMLABLE (FONT_UF, "\\subset ", "⊂")) + | "\\supseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\supseteq ", "⊇")) + | "\\subseteq" -> LITERAL (HTMLABLE (FONT_UF, "\\subseteq ", "⊆")) + | "\\sqsupset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupset ")) + | "\\sqsubset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubset ")) + | "\\sqsupseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsupseteq ")) + | "\\sqsubseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqsubseteq ")) + | "\\perp" -> LITERAL (HTMLABLE (FONT_UF, "\\perp ", "⊥")) + | "\\bot" -> LITERAL (HTMLABLE (FONT_UF, "\\bot ", "⊥")) + | "\\lfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\lfloor ", "⌊")) + | "\\rfloor" -> DELIMITER (HTMLABLE (FONT_UF, "\\rfloor ", "⌋")) + | "\\lceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\lceil ", "⌈")) + | "\\rceil" -> DELIMITER (HTMLABLE (FONT_UF, "\\rceil ", "⌉")) + | "\\lbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\lbrace ", "{")) + | "\\rbrace" -> DELIMITER (HTMLABLEC(FONT_UFH, "\\rbrace ", "}")) + | "\\infty" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "∞")) + | "\\infin" -> LITERAL (HTMLABLEM(FONT_UF, "\\infty ", "∞")) + | "\\isin" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "∈")) + | "\\in" -> LITERAL (HTMLABLE (FONT_UF, "\\in ", "∈")) + | "\\ni" -> LITERAL (HTMLABLE (FONT_UF, "\\ni ", "∋")) + | "\\notin" -> LITERAL (HTMLABLE (FONT_UF, "\\notin ", "∉")) + | "\\smallsetminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsetminus ")) + | "\\And" -> (tex_use_ams (); LITERAL (HTMLABLEM(FONT_UFH, "\\And ", " & "))) + | "\\forall" -> LITERAL (HTMLABLE (FONT_UFH, "\\forall ", "∀")) + | "\\exists" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "∃")) + | "\\exist" -> LITERAL (HTMLABLE (FONT_UFH, "\\exists ", "∃")) + | "\\equiv" -> LITERAL (HTMLABLEM(FONT_UFH, "\\equiv ", "≡")) + | "\\ne" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "≠")) + | "\\neq" -> LITERAL (HTMLABLEM(FONT_UFH, "\\neq ", "≠")) + | "\\Re" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "ℜ")) + | "\\real" -> LITERAL (HTMLABLE (FONT_UF, "\\Re ", "ℜ")) + | "\\Im" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "ℑ")) + | "\\image" -> LITERAL (HTMLABLE (FONT_UF, "\\Im ", "ℑ")) + | "\\prime" -> LITERAL (HTMLABLE (FONT_UFH,"\\prime ", "′")) + | "\\backslash" -> DELIMITER (HTMLABLEM(FONT_UFH,"\\backslash ", "\\")) + | "\\setminus" -> LITERAL (HTMLABLEM(FONT_UFH,"\\setminus ", "\\")) + | "\\times" -> LITERAL (HTMLABLEM(FONT_UFH,"\\times ", "×")) + | "\\pm" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "±")) + | "\\plusmn" -> LITERAL (HTMLABLEM(FONT_UFH,"\\pm ", "±")) + | "\\cdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "⋅")) + | "\\AA" -> LITERAL (HTMLABLE (FONT_UFH,"\\AA ", "Å")) + | "\\cdots" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdots ", "⋅⋅⋅")) + | "\\sdot" -> LITERAL (HTMLABLE (FONT_UFH,"\\cdot ", "⋅")) + | "\\oplus" -> LITERAL (HTMLABLE (FONT_UF, "\\oplus ", "⊕")) + | "\\otimes" -> LITERAL (HTMLABLE (FONT_UF, "\\otimes ", "⊗")) + | "\\cap" -> LITERAL (HTMLABLEM(FONT_UF, "\\cap ", "∩")) + | "\\cup" -> LITERAL (HTMLABLE (FONT_UF, "\\cup ", "∪")) + | "\\uplus" -> LITERAL (TEX_ONLY "\\uplus ") + | "\\sqcap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcap ")) + | "\\sqcup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sqcup ")) + | "\\empty" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\emptyset" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\O" -> LITERAL (HTMLABLE (FONT_UF, "\\emptyset ", "∅")) + | "\\S" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "§")) + | "\\sect" -> LITERAL (HTMLABLEM(FONT_UFH,"\\S ", "§")) + | "\\nabla" -> LITERAL (HTMLABLE (FONT_UF, "\\nabla ", "∇")) + | "\\geq" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "≥")) + | "\\ge" -> LITERAL (HTMLABLE (FONT_UFH,"\\geq ", "≥")) + | "\\leq" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "≤")) + | "\\le" -> LITERAL (HTMLABLE (FONT_UFH,"\\leq ", "≤")) + | "\\cong" -> LITERAL (HTMLABLE (FONT_UF, "\\cong ", "≅")) + | "\\ang" -> LITERAL (HTMLABLE (FONT_UF, "\\angle ", "∠")) + | "\\part" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "∂")) + | "\\partial" -> LITERAL (HTMLABLEM(FONT_UF, "\\partial ", "∂")) + | "\\ldots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\ldots ", "...")) + | "\\dots" -> LITERAL (HTMLABLEM(FONT_UFH,"\\dots ", "...")) + | "\\quad" -> LITERAL (HTMLABLE (FONT_UF, "\\quad ","  ")) + | "\\qquad" -> LITERAL (HTMLABLE (FONT_UF, "\\qquad ","    ")) + | "\\mid" -> LITERAL (HTMLABLEM(FONT_UFH,"\\mid ", " | ")) + | "\\neg" -> LITERAL (HTMLABLEM(FONT_UFH,"\\neg ", "¬")) + | "\\langle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","⟨")) + | "\\rangle" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","⟩")) + | "\\lang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\langle ","⟨")) + | "\\rang" -> DELIMITER (HTMLABLE (FONT_UFH,"\\rangle ","⟩")) + | "\\lbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"[","[")) + | "\\rbrack" -> DELIMITER (HTMLABLEC(FONT_UFH,"]","]")) + | "\\surd" -> LITERAL (TEX_ONLY "\\surd ") + | "\\ddots" -> LITERAL (TEX_ONLY "\\ddots ") + | "\\clubs" -> LITERAL (TEX_ONLY "\\clubsuit ") + | "\\clubsuit" -> LITERAL (TEX_ONLY "\\clubsuit ") + | "\\spades" -> LITERAL (TEX_ONLY "\\spadesuit ") + | "\\spadesuit" -> LITERAL (TEX_ONLY "\\spadesuit ") + | "\\hearts" -> LITERAL (TEX_ONLY "\\heartsuit ") + | "\\heartsuit" -> LITERAL (TEX_ONLY "\\heartsuit ") + | "\\diamonds" -> LITERAL (TEX_ONLY "\\diamondsuit ") + | "\\diamond" -> LITERAL (TEX_ONLY "\\diamond ") + | "\\bigtriangleup" -> LITERAL (TEX_ONLY "\\bigtriangleup ") + | "\\bigtriangledown" -> LITERAL (TEX_ONLY "\\bigtriangledown ") + | "\\diamondsuit" -> LITERAL (TEX_ONLY "\\diamondsuit ") + | "\\ominus" -> LITERAL (TEX_ONLY "\\ominus ") + | "\\oslash" -> LITERAL (TEX_ONLY "\\oslash ") + | "\\odot" -> LITERAL (TEX_ONLY "\\odot ") + | "\\bigcirc" -> LITERAL (TEX_ONLY "\\bigcirc ") + | "\\amalg" -> LITERAL (TEX_ONLY "\\amalg ") + | "\\prec" -> LITERAL (TEX_ONLY "\\prec ") + | "\\succ" -> LITERAL (TEX_ONLY "\\succ ") + | "\\preceq" -> LITERAL (TEX_ONLY "\\preceq ") + | "\\succeq" -> LITERAL (TEX_ONLY "\\succeq ") + | "\\dashv" -> LITERAL (TEX_ONLY "\\dashv ") + | "\\asymp" -> LITERAL (TEX_ONLY "\\asymp ") + | "\\doteq" -> LITERAL (TEX_ONLY "\\doteq ") + | "\\parallel" -> LITERAL (TEX_ONLY "\\parallel ") + | "\\implies" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\implies ", "⇒"))) + | "\\mod" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mod ", "mod"))) + | "\\Diamond" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\Diamond ", "◊"))) + | "\\dotsb" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsb ", "⋅⋅⋅"))) + | "\\dotsc" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsc ", "..."))) + | "\\dotsi" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsi ", "⋅⋅⋅"))) + | "\\dotsm" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotsm ", "⋅⋅⋅"))) + | "\\dotso" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UF, "\\dotso ", "..."))) + | "\\reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "R"))) + | "\\Reals" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "R"))) + | "\\R" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{R}", "R"))) + | "\\C" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "C"))) + | "\\cnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "C"))) + | "\\Complex" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{C}", "C"))) + | "\\Z" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Z}", "Z"))) + | "\\natnums" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "N"))) + | "\\N" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{N}", "N"))) + | "\\Q" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\mathbb{Q}", "Q"))) + | "\\lVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\lVert ", "||"))) + | "\\rVert" -> (tex_use_ams (); LITERAL (HTMLABLE (FONT_UFH,"\\rVert ", "||"))) + | "\\nmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nmid ")) + | "\\lesssim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesssim ")) + | "\\ngeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeq ")) + | "\\smallsmile" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallsmile ")) + | "\\smallfrown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\smallfrown ")) + | "\\nleftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftarrow ")) + | "\\nrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nrightarrow ")) + | "\\trianglelefteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglelefteq ")) + | "\\trianglerighteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\trianglerighteq ")) + | "\\square" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\square ")) + | "\\checkmark" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\checkmark ")) + | "\\supsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneq ")) + | "\\subsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneq ")) + | "\\Box" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Box ")) + | "\\nleq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleq ")) + | "\\upharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonright ")) + | "\\restriction" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonright ")) + | "\\upharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upharpoonleft ")) + | "\\downharpoonright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonright ")) + | "\\downharpoonleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downharpoonleft ")) + | "\\rightharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoonup ")) + | "\\rightharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightharpoondown ")) + | "\\leftharpoonup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoonup ")) + | "\\leftharpoondown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftharpoondown ")) + | "\\nless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nless ")) + | "\\Vdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vdash ")) + | "\\vDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vDash ")) + | "\\varkappa" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varkappa ")) + | "\\digamma" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\digamma ")) + | "\\beth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\beth ")) + | "\\daleth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\daleth ")) + | "\\gimel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gimel ")) + | "\\complement" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\complement ")) + | "\\eth" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eth ")) + | "\\hslash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\hslash ")) + | "\\mho" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\mho ")) + | "\\Finv" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Finv ")) + | "\\Game" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Game ")) + | "\\varlimsup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varlimsup ")) + | "\\varliminf" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varliminf ")) + | "\\varinjlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varinjlim ")) + | "\\varprojlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varprojlim ")) + | "\\injlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\injlim ")) + | "\\projlim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\projlim ")) + | "\\iint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iint ")) + | "\\iiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiint ")) + | "\\iiiint" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\iiiint ")) + | "\\varnothing" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varnothing ")) + | "\\left" -> LEFT + | "\\right" -> RIGHT + | "\\hat" -> FUN_AR1 "\\hat " + | "\\hline" -> LITERAL (TEX_ONLY "\\hline ") + | "\\vline" -> LITERAL (TEX_ONLY "\\vline ") + | "\\widehat" -> LITERAL (TEX_ONLY "\\widehat ") + | "\\overline" -> LITERAL (TEX_ONLY "\\overline ") + | "\\overbrace" -> LITERAL (TEX_ONLY "\\overbrace ") + | "\\underline" -> LITERAL (TEX_ONLY "\\underline ") + | "\\underbrace" -> LITERAL (TEX_ONLY "\\underbrace ") + | "\\overleftarrow" -> LITERAL (TEX_ONLY "\\overleftarrow ") + | "\\overrightarrow" -> LITERAL (TEX_ONLY "\\overrightarrow ") + | "\\overleftrightarrow"-> (tex_use_ams(); LITERAL (TEX_ONLY "\\overleftrightarrow ")) + | "\\check" -> FUN_AR1 "\\check " + | "\\acute" -> FUN_AR1 "\\acute " + | "\\grave" -> FUN_AR1 "\\grave " + | "\\bar" -> FUN_AR1 "\\bar " + | "\\vec" -> FUN_AR1 "\\vec " + | "\\dot" -> FUN_AR1 "\\dot " + | "\\ddot" -> FUN_AR1 "\\ddot " + | "\\breve" -> FUN_AR1 "\\breve " + | "\\tilde" -> FUN_AR1 "\\tilde " + | "\\not" -> LITERAL (TEX_ONLY "\\not ") + | "\\choose" -> FUN_INFIX "\\choose " + | "\\atop" -> FUN_INFIX "\\atop " + | "\\binom" -> (tex_use_ams (); FUN_AR2 "\\binom ") + | "\\dbinom" -> (tex_use_ams (); FUN_AR2 "\\dbinom ") + | "\\tbinom" -> (tex_use_ams (); FUN_AR2 "\\tbinom ") + | "\\stackrel" -> FUN_AR2 "\\stackrel " + | "\\sideset" -> (tex_use_ams (); FUN_AR2nb "\\sideset ") + | "\\underset" -> (tex_use_ams (); FUN_AR2 "\\underset ") + | "\\overset" -> (tex_use_ams (); FUN_AR2 "\\overset ") + | "\\frac" -> FUN_AR2h ("\\frac ", fun num den -> Html.html_render [num], "
", Html.html_render [den]) + | "\\dfrac" -> (tex_use_ams () ; FUN_AR2 "\\dfrac ") + | "\\tfrac" -> (tex_use_ams () ; FUN_AR2h ("\\tfrac ", fun num den -> Html.html_render [num], "
", Html.html_render [den])) + | "\\cfrac" -> (tex_use_ams (); FUN_AR2h ("\\cfrac ", fun num den -> Html.html_render [num], "
", Html.html_render [den])) + | "\\over" -> FUN_INFIXh ("\\over ", fun num den -> Html.html_render num, "
", Html.html_render den) + | "\\sqrt" -> FUN_AR1 "\\sqrt " + | "\\cancel" -> FUN_AR1 "\\cancel " + | "\\bcancel" -> FUN_AR1 "\\bcancel " + | "\\xcancel" -> FUN_AR1 "\\xcancel " + | "\\cancelto" -> FUN_AR2 "\\cancelto " + | "\\pmod" -> FUN_AR1hl ("\\pmod ", ("(mod ", ")")) + | "\\bmod" -> FUN_AR1hl ("\\bmod ", ("mod ", "")) + | "\\emph" -> FUN_AR1 "\\emph " + | "\\texttt" -> FUN_AR1 "\\texttt " + | "\\textbf" -> FUN_AR1 "\\textbf " + | "\\textsf" -> FUN_AR1 "\\textsf " + | "\\textit" -> FUN_AR1hf ("\\textit ", FONTFORCE_IT) + | "\\textrm" -> FUN_AR1hf ("\\textrm ", FONTFORCE_RM) + | "\\rm" -> DECLh ("\\rm ", FONTFORCE_RM) + | "\\it" -> DECLh ("\\it ", FONTFORCE_IT) + | "\\cal" -> DECL "\\cal " + | "\\displaystyle" -> LITERAL (TEX_ONLY "\\displaystyle ") + | "\\scriptstyle" -> LITERAL (TEX_ONLY "\\scriptstyle ") + | "\\textstyle" -> LITERAL (TEX_ONLY "\\textstyle ") + | "\\scriptscriptstyle"-> LITERAL (TEX_ONLY "\\scriptscriptstyle ") + | "\\bf" -> DECL "\\bf " + | "\\big" -> BIG "\\big " + | "\\Big" -> BIG "\\Big " + | "\\bigg" -> BIG "\\bigg " + | "\\Bigg" -> BIG "\\Bigg " + | "\\bigl" -> (tex_use_ams ();BIG "\\bigl ") + | "\\bigr" -> (tex_use_ams ();BIG "\\bigr ") + | "\\Bigl" -> (tex_use_ams ();BIG "\\Bigl ") + | "\\Bigr" -> (tex_use_ams ();BIG "\\Bigr ") + | "\\biggl" -> (tex_use_ams ();BIG "\\biggl ") + | "\\biggr" -> (tex_use_ams ();BIG "\\biggr ") + | "\\Biggl" -> (tex_use_ams ();BIG "\\Biggl ") + | "\\Biggr" -> (tex_use_ams ();BIG "\\Biggr ") + | "\\vartriangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangle ")) + | "\\triangledown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\triangledown ")) + | "\\lozenge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lozenge ")) + | "\\circledS" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledS ")) + | "\\measuredangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\measuredangle ")) + | "\\nexists" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nexists ")) + | "\\Bbbk" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Bbbk ")) + | "\\backprime" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backprime ")) + | "\\blacktriangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangle ")) + | "\\blacktriangledown"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangledown ")) + | "\\blacksquare" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacksquare ")) + | "\\blacklozenge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacklozenge ")) + | "\\bigstar" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\bigstar ")) + | "\\sphericalangle" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\sphericalangle ")) + | "\\diagup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\diagup ")) + | "\\diagdown" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\diagdown ")) + | "\\dotplus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\dotplus ")) + | "\\Cap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cap ")) + | "\\doublecap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cap ")) + | "\\Cup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cup ")) + | "\\doublecup" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Cup ")) + | "\\barwedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\barwedge ")) + | "\\veebar" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\veebar ")) + | "\\doublebarwedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doublebarwedge ")) + | "\\boxminus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxminus ")) + | "\\boxtimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxtimes ")) + | "\\boxdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxdot ")) + | "\\boxplus" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\boxplus ")) + | "\\divideontimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\divideontimes ")) + | "\\ltimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ltimes ")) + | "\\rtimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rtimes ")) + | "\\leftthreetimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftthreetimes ")) + | "\\rightthreetimes" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightthreetimes ")) + | "\\curlywedge" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlywedge ")) + | "\\curlyvee" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyvee ")) + | "\\circleddash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circleddash ")) + | "\\circledast" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledast ")) + | "\\circledcirc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circledcirc ")) + | "\\centerdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\centerdot ")) + | "\\intercal" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\intercal ")) + | "\\leqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leqq ")) + | "\\leqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leqslant ")) + | "\\eqslantless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqslantless ")) + | "\\lessapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessapprox ")) + | "\\approxeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\approxeq ")) + | "\\lessdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessdot ")) + | "\\lll" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lll ")) + | "\\lessgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lessgtr ")) + | "\\lesseqgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesseqgtr ")) + | "\\lesseqqgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lesseqqgtr ")) + | "\\doteqdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doteqdot ")) + | "\\Doteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\doteqdot ")) + | "\\risingdotseq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\risingdotseq ")) + | "\\fallingdotseq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\fallingdotseq ")) + | "\\backsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backsim ")) + | "\\backsimeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backsimeq ")) + | "\\subseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subseteqq ")) + | "\\Subset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Subset ")) + | "\\preccurlyeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\preccurlyeq ")) + | "\\curlyeqprec" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyeqprec ")) + | "\\precsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precsim ")) + | "\\precapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precapprox ")) + | "\\vartriangleleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangleleft ")) + | "\\Vvdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Vvdash ")) + | "\\bumpeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\bumpeq ")) + | "\\Bumpeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Bumpeq ")) + | "\\geqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\geqq ")) + | "\\geqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\geqslant ")) + | "\\eqslantgtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqslantgtr ")) + | "\\gtrsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrsim ")) + | "\\gtrapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrapprox ")) + | "\\eqsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqsim ")) + | "\\gtrdot" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrdot ")) + | "\\ggg" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ggg ")) + | "\\gggtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ggg ")) + | "\\gtrless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtrless ")) + | "\\gtreqless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtreqless ")) + | "\\gtreqqless" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gtreqqless ")) + | "\\eqcirc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\eqcirc ")) + | "\\circeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circeq ")) + | "\\triangleq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\triangleq ")) + | "\\thicksim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\thicksim ")) + | "\\thickapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\thickapprox ")) + | "\\supseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supseteqq ")) + | "\\Supset" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Supset ")) + | "\\succcurlyeq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succcurlyeq ")) + | "\\curlyeqsucc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curlyeqsucc ")) + | "\\succsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succsim ")) + | "\\succapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succapprox ")) + | "\\vartriangleright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\vartriangleright ")) + | "\\shortmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\shortmid ")) + | "\\shortparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\shortparallel ")) + | "\\between" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\between ")) + | "\\pitchfork" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\pitchfork ")) + | "\\varpropto" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varpropto ")) + | "\\blacktriangleleft"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangleleft ")) + | "\\therefore" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\therefore ")) + | "\\backepsilon" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\backepsilon ")) + | "\\blacktriangleright"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\blacktriangleright ")) + | "\\because" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\because ")) + | "\\nleqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleqslant ")) + | "\\nleqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleqq ")) + | "\\lneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lneq ")) + | "\\lneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lneqq ")) + | "\\lvertneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lvertneqq ")) + | "\\lnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lnsim ")) + | "\\lnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\lnapprox ")) + | "\\nprec" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nprec ")) + | "\\npreceq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\npreceq ")) + | "\\precneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precneqq ")) + | "\\precnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precnsim ")) + | "\\precnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\precnapprox ")) + | "\\nsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsim ")) + | "\\nshortmid" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nshortmid ")) + | "\\nvdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nvdash ")) + | "\\nVdash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nVdash ")) + | "\\ntriangleleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntriangleleft ")) + | "\\ntrianglelefteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntrianglelefteq ")) + | "\\nsubseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsubseteq ")) + | "\\nsubseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsubseteqq ")) + | "\\varsubsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsubsetneq ")) + | "\\subsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\subsetneqq ")) + | "\\varsubsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsubsetneqq ")) + | "\\ngtr" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngtr ")) + | "\\ngeqslant" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeqslant ")) + | "\\ngeqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ngeqq ")) + | "\\gneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gneq ")) + | "\\gneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gneqq ")) + | "\\gvertneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gvertneqq ")) + | "\\gnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gnsim ")) + | "\\gnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\gnapprox ")) + | "\\nsucc" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsucc ")) + | "\\nsucceq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsucceq ")) + | "\\succneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succneqq ")) + | "\\succnsim" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succnsim ")) + | "\\succnapprox" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\succnapprox ")) + | "\\ncong" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ncong ")) + | "\\nshortparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nshortparallel ")) + | "\\nparallel" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nparallel ")) + | "\\nvDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nvDash ")) + | "\\nVDash" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nVDash ")) + | "\\ntriangleright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntriangleright ")) + | "\\ntrianglerighteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\ntrianglerighteq ")) + | "\\nsupseteq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsupseteq ")) + | "\\nsupseteqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nsupseteqq ")) + | "\\varsupsetneq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsupsetneq ")) + | "\\supsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\supsetneqq ")) + | "\\varsupsetneqq" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\varsupsetneqq ")) + | "\\leftleftarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftleftarrows ")) + | "\\leftrightarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightarrows ")) + | "\\Lleftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Lleftarrow ")) + | "\\leftarrowtail" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftarrowtail ")) + | "\\looparrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\looparrowleft ")) + | "\\leftrightharpoons"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightharpoons ")) + | "\\curvearrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curvearrowleft ")) + | "\\circlearrowleft" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circlearrowleft ")) + | "\\Lsh" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Lsh ")) + | "\\upuparrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\upuparrows ")) + | "\\rightrightarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightrightarrows ")) + | "\\rightleftarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightleftarrows ")) + | "\\Rrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Rrightarrow ")) + | "\\rightarrowtail" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightarrowtail ")) + | "\\looparrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\looparrowright ")) + | "\\curvearrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\curvearrowright ")) + | "\\circlearrowright" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\circlearrowright ")) + | "\\Rsh" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\Rsh ")) + | "\\downdownarrows" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\downdownarrows ")) + | "\\multimap" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\multimap ")) + | "\\leftrightsquigarrow"-> (tex_use_ams (); LITERAL (TEX_ONLY "\\leftrightsquigarrow ")) + | "\\rightsquigarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\rightsquigarrow ")) + | "\\nLeftarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nLeftarrow ")) + | "\\nleftrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nleftrightarrow ")) + | "\\nRightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nRightarrow ")) + | "\\nLeftrightarrow" -> (tex_use_ams (); LITERAL (TEX_ONLY "\\nLeftrightarrow ")) + | "\\mathit" -> (tex_use_ams (); FUN_AR1hf ("\\mathit ", FONTFORCE_IT)) + | "\\mathrm" -> (tex_use_ams (); FUN_AR1hf ("\\mathrm ", FONTFORCE_RM)) + | "\\mathord" -> (tex_use_ams (); FUN_AR1 "\\mathord ") + | "\\mathop" -> (tex_use_ams (); FUN_AR1 "\\mathop ") + | "\\mathbin" -> (tex_use_ams (); FUN_AR1 "\\mathbin ") + | "\\mathrel" -> (tex_use_ams (); FUN_AR1 "\\mathrel ") + | "\\mathopen" -> (tex_use_ams (); FUN_AR1 "\\mathopen ") + | "\\mathclose" -> (tex_use_ams (); FUN_AR1 "\\mathclose ") + | "\\mathpunct" -> (tex_use_ams (); FUN_AR1 "\\mathpunct ") + | "\\boldsymbol" -> (tex_use_ams (); FUN_AR1 "\\boldsymbol ") + | "\\bold" -> (tex_use_ams (); FUN_AR1 "\\mathbf ") + | "\\Bbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ") + | "\\mathbf" -> (tex_use_ams (); FUN_AR1 "\\mathbf ") + | "\\mathsf" -> (tex_use_ams (); FUN_AR1 "\\mathsf ") + | "\\mathcal" -> (tex_use_ams (); FUN_AR1 "\\mathcal ") + | "\\mathbb" -> (tex_use_ams (); FUN_AR1 "\\mathbb ") + | "\\mathtt" -> (tex_use_ams (); FUN_AR1 "\\mathtt ") + | "\\mathfrak" -> (tex_use_ams (); FUN_AR1 "\\mathfrak ") + | "\\operatorname" -> (tex_use_ams (); FUN_AR1 "\\operatorname ") + | "\\text" -> raise (Failure "malformatted \\text") + | "\\mbox" -> raise (Failure "malformatted \\mbox") + | "\\vbox" -> raise (Failure "malformatted \\vbox") + | "\\hbox" -> raise (Failure "malformatted \\hbox") + | "\\color" -> (tex_use_color (); LITERAL (TEX_ONLY "\\color")) + | "\\pagecolor" -> (tex_use_color (); LITERAL (TEX_ONLY "\\pagecolor")) + | "\\definecolor" -> (tex_use_color (); LITERAL (TEX_ONLY "\\definecolor")) + | s -> raise (Illegal_tex_function s) diff --git a/math/texutil.mli b/math/texutil.mli new file mode 100644 index 0000000..99d0e4e --- /dev/null +++ b/math/texutil.mli @@ -0,0 +1,11 @@ +val render_tex : Tex.t -> string + +val set_encoding : string -> unit +val tex_use_nonascii: unit -> unit +val tex_use_ams: unit -> unit + +val get_preface : unit -> string +val get_footer : unit -> string + +exception Illegal_tex_function of string +val find: string -> Parser.token diff --git a/math/texvc.ml b/math/texvc.ml new file mode 100644 index 0000000..33a14b7 --- /dev/null +++ b/math/texvc.ml @@ -0,0 +1,58 @@ +(* vim: set sw=8 ts=8 et: *) +exception LexerException of string + +(* *) +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) + +(* *) +let render tmppath finalpath tree backcolor = + let outtex = Util.mapjoin Texutil.render_tex tree in + let md5 = Digest.to_hex (Digest.string outtex) in + begin + let mathml = Mathml.render tree + and html = Html.render tree + in print_string (match (html,!Html.conservativeness,mathml) with + None,_,None -> "+" ^ md5 + | Some h,Html.CONSERVATIVE,None -> "c" ^ md5 ^ h + | Some h,Html.MODERATE,None -> "m" ^ md5 ^ h + | Some h,Html.LIBERAL,None -> "l" ^ md5 ^ h + | Some h,Html.CONSERVATIVE,Some m -> "C" ^ md5 ^ h ^ "\000" ^ m + | Some h,Html.MODERATE,Some m -> "M" ^ md5 ^ h ^ "\000" ^ m + | Some h,Html.LIBERAL,Some m -> "L" ^ md5 ^ h ^ "\000" ^ m + | None,_,Some m -> "X" ^ md5 ^ m + ); + Render.render tmppath finalpath outtex md5 backcolor + end + +(* TODO: document + * Arguments: + * 1st : + * 2nd : + * 3rd : + * 4th : encoding (Default: UTF-8) + * 5th : color (Default: rgb 1.0 1.0 1.0) + * + * Output one character: + * S : Parsing error + * E : Lexer exception raised + * F : TeX function not recognized + * - : Generic/Default failure code. Might be an invalid argument, + * output file already exist, a problem with an external + * command ... + * *) +let _ = + Texutil.set_encoding (try Sys.argv.(4) with _ -> "UTF-8"); + try render Sys.argv.(1) Sys.argv.(2) ( + Parser.tex_expr lexer_token_safe ( + Lexing.from_string Sys.argv.(3)) + ) (try Sys.argv.(5) with _ -> "rgb 1.0 1.0 1.0") + with Parsing.Parse_error -> print_string "S" + | LexerException _ -> print_string "E" + | Texutil.Illegal_tex_function s -> print_string ("F" ^ s) + | Util.FileAlreadyExists -> print_string "-" + | Invalid_argument _ -> print_string "-" + | Failure _ -> print_string "-" + | Render.ExternalCommandFailure s -> () + | _ -> print_string "-" diff --git a/math/texvc_cgi.ml b/math/texvc_cgi.ml new file mode 100644 index 0000000..2e6079f --- /dev/null +++ b/math/texvc_cgi.ml @@ -0,0 +1,62 @@ +open Netcgi;; +open Netcgi_types;; +open Netcgi_env;; +open Netchannels;; + +let cgi = new Netcgi.std_activation () +let out = cgi # output # output_string +let math = cgi # argument_value ~default:"" "math" +let tmppath = "/home/taw/public_html/wiki/tmp/" +let finalpath = "/home/taw/public_html/wiki/math/" +let finalurl = "http://wroclaw.taw.pl.eu.org/~taw/wiki/math/" +;; + +let h_header = "\n"^ + "texvc"^ + "
"^ + "
" +let h_footer = "\n" + +let render tmppath finalpath tree = + let outtex = Texutil.mapjoin Texutil.print tree in + let md5 = Digest.to_hex (Digest.string outtex) in + begin + out "

TeX

"; + out outtex; (* <, & and > should be protected *) + (try out ("

HTML

" ^ (Texutil.html_render tree)) + with _ -> out "

HTML could not be rendered

"); + try Render.render tmppath finalpath outtex md5; + out ("

Image:

") + with Util.FileAlreadyExists -> out ("

Image:

") + | Failure s -> out ("

Other failure: " ^ s ^ "

") + | Render.ExternalCommandFailure "latex" -> out "

latex failed

" + | Render.ExternalCommandFailure "dvips" -> out "

dvips failed

" + | _ -> out "

Other failure

" + end +;; + +cgi#set_header ();; + +out h_header;; +out math;; +out h_middle;; + +exception LexerException of string +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) +;; +if math = "" +then () +else try + render tmppath finalpath (Parser.tex_expr lexer_token_safe (Lexing.from_string math)) + with Parsing.Parse_error -> out "

Parse error

" + | LexerException s -> out "

Lexing failure

" + | Texutil.Illegal_tex_function s -> out ("

Illegal TeX function: " ^ s ^ "

") + | Failure s -> out ("

Other failure: " ^ s ^ "

") + | _ -> out "

Other failure

" +;; + +out h_footer diff --git a/math/texvc_test.ml b/math/texvc_test.ml new file mode 100644 index 0000000..cd3a1df --- /dev/null +++ b/math/texvc_test.ml @@ -0,0 +1,24 @@ +exception LexerException of string +let lexer_token_safe lexbuf = + try Lexer.token lexbuf + with Failure s -> raise (LexerException s) + +let rec foo () = + try + let line = input_line stdin in + (try + let tree = Parser.tex_expr lexer_token_safe (Lexing.from_string line) in + (match Html.render tree with + Some _ -> print_string "$^\n" + | None -> print_string "$_\n"; + ) + with + Texutil.Illegal_tex_function s -> print_string ("$T" ^ s ^ " " ^ line ^ "\n") + | LexerException s -> print_string ("$L" ^ line ^ "\n") + | _ -> print_string ("$ " ^ line ^ "\n")); + flush stdout; + foo (); + with + End_of_file -> () +;; +foo ();; diff --git a/math/texvc_tex.ml b/math/texvc_tex.ml new file mode 100644 index 0000000..30c0f67 --- /dev/null +++ b/math/texvc_tex.ml @@ -0,0 +1,3 @@ +Texutil.set_encoding (try Sys.argv.(2) with _ -> "UTF-8"); +try print_string (Util.mapjoin Texutil.render_tex (Parser.tex_expr Lexer.token (Lexing.from_string Sys.argv.(1)))) +with _ -> () diff --git a/math/util.ml b/math/util.ml new file mode 100644 index 0000000..ece0160 --- /dev/null +++ b/math/util.ml @@ -0,0 +1,26 @@ +(* vim: set sw=8 ts=8 et: *) + +(* TODO document *) +let mapjoin f l = (List.fold_left (fun a b -> a ^ (f b)) "" l) + +(* TODO document *) +let mapjoine e f = function + [] -> "" + | h::t -> (List.fold_left (fun a b -> a ^ e ^ (f b)) (f h) t) + +(* Exception used by open_out_unless_exists below *) +exception FileAlreadyExists + +(* Wrapper which raise an exception when output path already exist *) +let open_out_unless_exists path = + if Sys.file_exists path + then raise FileAlreadyExists + else open_out path + +(* *) +let run_in_other_directory tmppath cmd = + let prevdir = Sys.getcwd () in( + Sys.chdir tmppath; + let retval = Sys.command cmd in + (Sys.chdir prevdir; retval) + ) diff --git a/mathParserTests.txt b/mathParserTests.txt new file mode 100644 index 0000000..7e0a050 --- /dev/null +++ b/mathParserTests.txt @@ -0,0 +1,41 @@ + +!! test +pre-save transform: comment containing math +!! options +pst +!! input + +!!result + +!!end + +#!! test +#BUG 1887: A with a thumbnail- we don't render math in the parsertests by default, +#so math is not stripped and turns up as escaped <math> tags. +#!! input +#[[Image:foobar.jpg|thumb|2+2]] +#!! result +#
<math>2+2</math>
+# +#!! end + +!! test +BUG 1887, part 2: A with a thumbnail- math enabled +!! options +math +!! input +[[Image:foobar.jpg|thumb|2+2]] +!! result +
2 + 2
+ +!! end + +#!! test +#Math section safety when disabled +#!! input +# +#!! result +#

<math><script>alert(document.cookies);</script></math> +#

+#!! end +