(***********************************************************************)
(* *)
(* HEVEA *)
(* *)
(* Luc Maranget, projet PARA, INRIA Rocquencourt *)
(* *)
(* Copyright 1998 Institut National de Recherche en Informatique et *)
(* Automatique. Distributed only by permission. *)
(* *)
(***********************************************************************)
let header = "$Id: mathML.ml,v 1.26 2006-04-13 16:55:56 maranget Exp $"
open Misc
open Parse_opts
open Element
open HtmlCommon
open Latexmacros
open Stack
(*----------*)
(* DISPLAYS *)
(*----------*)
let begin_item_display f is_freeze =
if !verbose > 2 then begin
Printf.fprintf stderr "begin_item_display: ncols=%d empty=%s" flags.ncols (sbool flags.empty) ;
prerr_newline ()
end ;
open_block (OTHER "mrow") "";
open_block INTERN "" ;
if is_freeze then(* push out_stack (Freeze f) ;*)freeze f;
and end_item_display () =
let f,is_freeze = pop_freeze () in
let _ = close_flow_loc check_empty INTERN in
if close_flow_loc check_empty (OTHER "mrow") then
flags.ncols <- flags.ncols + 1;
if !verbose > 2 then begin
Printf.fprintf stderr "end_item_display: ncols=%d stck: " flags.ncols;
pretty_stack out_stack
end;
flags.vsize,f,is_freeze
and open_display () =
if !verbose > 2 then begin
Printf.fprintf stderr "open_display: "
end ;
try_open_display () ;
open_block (OTHER "mrow") "";
do_put_char '\n';
open_block INTERN "" ;
if !verbose > 2 then begin
pretty_cur !cur_out ;
prerr_endline ""
end
and close_display () =
if !verbose > 2 then begin
prerr_flags "=> close_display"
end ;
if not (flush_freeze ()) then begin
close_flow INTERN ;
let n = flags.ncols in
if (n = 0 && not flags.blank) then begin
if !verbose > 2 then begin
prerr_string "No Display n=0" ;
(Out.debug stderr !cur_out.out);
prerr_endline ""
end;
let active = !cur_out.active and pending = !cur_out.pending in
do_close_mods () ;
let ps,_,ppout = pop_out out_stack in
if ps <> (OTHER "mrow") then
failclose "close_display" ps (OTHER "mrow") ;
try_close_block (OTHER "mrow");
let old_out = !cur_out in
cur_out := ppout ;
do_close_mods () ;
Out.copy old_out.out !cur_out.out ;
flags.empty <- false ; flags.blank <- false ;
free old_out ;
!cur_out.pending <- to_pending pending active
end else if (n=1 (*&& flags.blank*)) then begin
if !verbose > 2 then begin
prerr_string "No display n=1";
(Out.debug stderr !cur_out.out);
prerr_endline "" ;
end;
let active = !cur_out.active and pending = !cur_out.pending in
let ps,_,pout = pop_out out_stack in
if ps<> (OTHER "mrow") then
failclose "close_display" ps (OTHER "mrow");
try_close_block (OTHER "mrow") ;
let old_out = !cur_out in
cur_out := pout ;
do_close_mods () ;
if flags.blank then Out.copy_no_tag old_out.out !cur_out.out
else Out.copy old_out.out !cur_out.out;
flags.empty <- false ; flags.blank <- false ;
free old_out ;
!cur_out.pending <- to_pending pending active
end else begin
if !verbose > 2 then begin
prerr_string ("One Display n="^string_of_int n) ;
(Out.debug stderr !cur_out.out);
prerr_endline ""
end;
flags.empty <- flags.blank ;
close_flow (OTHER "mrow") ;
do_put_char '\n';
end ;
try_close_display ()
end ;
if !verbose > 2 then
prerr_flags ("<= close_display")
;;
let open_display_varg _ = open_display ()
let do_item_display _force =
if !verbose > 2 then begin
prerr_endline ("Item Display in mathML ncols="^string_of_int flags.ncols^" table_inside="^sbool flags.table_inside)
end ;
let f,is_freeze = pop_freeze () in
if ((*force && *)not flags.empty) || flags.table_inside then
flags.ncols <- flags.ncols + 1 ;
let active = !cur_out.active
and pending = !cur_out.pending in
close_flow INTERN ;
open_block INTERN "";
!cur_out.pending <- to_pending pending active;
!cur_out.active <- [] ;
if is_freeze then freeze f;
if !verbose > 2 then begin
prerr_string ("out item_display -> ncols="^string_of_int flags.ncols^" ") ;
pretty_stack out_stack
end ;
;;
let item_display () = do_item_display false
and force_item_display () = do_item_display true
;;
let erase_display () =
erase_block INTERN ;
erase_block (OTHER "mrow");
try_close_display ()
;;
let open_maths display =
if !verbose > 1 then prerr_endline "=> open_maths";
push stacks.s_in_math flags.in_math;
if display then do_put "
\n";
if not flags.in_math then open_block (OTHER "math") "align=\"center\""
else erase_mods [Style "mtext"];
do_put_char '\n';
flags.in_math <- true;
open_display ();
open_display ();
;;
let close_maths _display =
if !verbose >1 then prerr_endline "=> close_maths";
close_display ();
close_display ();
flags.in_math <- pop stacks.s_in_math ;
do_put_char '\n';
if not flags.in_math then begin
close_block (OTHER "math") end
else open_mod (Style "mtext");
;;
let insert_vdisplay open_fun =
if !verbose > 2 then begin
prerr_flags "=> insert_vdisplay" ;
end ;
try
let mods = to_pending !cur_out.pending !cur_out.active in
let bs,bargs,bout = pop_out out_stack in
if bs <> INTERN then
failclose "insert_vdisplay" bs INTERN ;
let ps,pargs,pout = pop_out out_stack in
if ps <> (OTHER "mrow") then
failclose "insert_vdisplay" ps (OTHER "mrow");
let new_out = create_status_from_scratch false [] in
push_out out_stack (ps,pargs,new_out) ;
push_out out_stack (bs,bargs,bout) ;
close_display () ;
cur_out := pout ;
open_fun () ;
do_put (Out.to_string new_out.out) ;
flags.empty <- false ; flags.blank <- false ;
free new_out ;
if !verbose > 2 then begin
prerr_string "insert_vdisplay -> " ;
pretty_mods stderr mods ;
prerr_newline ()
end ;
if !verbose > 2 then
prerr_flags "<= insert_vdisplay" ;
mods
with PopFreeze ->
raise (UserError "wrong parenthesization");
;;
(* delaying output .... *)
(*
let delay f =
if !verbose > 2 then
prerr_flags "=> delay" ;
push vsize_stack flags.vsize ;
flags.vsize <- 0;
push delay_stack f ;
open_block "DELAY" "" ;
if !verbose > 2 then
prerr_flags "<= delay"
;;
let flush x =
if !verbose > 2 then
prerr_flags ("=> flush arg is ``"^string_of_int x^"''");
try_close_block "DELAY" ;
let ps,_,pout = pop_out out_stack in
if ps <> "DELAY" then
raise (Misc.Fatal ("html: Flush attempt on: "^ps)) ;
let mods = !cur_out.active @ !cur_out.pending in
do_close_mods () ;
let old_out = !cur_out in
cur_out := pout ;
let f = pop "delay" delay_stack in
f x ;
Out.copy old_out.out !cur_out.out ;
flags.empty <- false ; flags.blank <- false ;
free old_out ;
!cur_out.pending <- mods ;
flags.vsize <- max (pop "vsive" vsize_stack) flags.vsize ;
if !verbose > 2 then
prerr_flags "<= flush"
;;
*)
(* put functions *)
let is_digit = function
'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'0'|'.'|',' -> true
| _ -> false
;;
let is_number s =
let r = ref true in
for i = 0 to String.length s -1 do
r := !r && is_digit s.[i]
done;
!r
;;
let is_op = function
"+" | "-"|"/"|"*"|"%"|"<"|">"|"="|"("|")"|"{"|"}"|"["|"]"|","|";"|":"|"|"|"&"|"#"|"!"|"~"|"$" -> true
| _ -> false
;;
let is_letter = function
| 'a'..'Z'|'A'..'Z' -> true
| _ -> false
let is_ident s =
let r = ref true in
for i = 0 to String.length s-1 do
r := !r && is_letter s.[i]
done ;
!r
let is_open_delim = function
| "(" | "[" | "{" | "<" -> true
| _ -> false
and is_close_delim = function
| ")" | "]" | "}" | ">" -> true
| _ -> false
;;
let open_delim () =
open_display ();
freeze
( fun () ->
close_display ();
close_display (););
and is_close () =
let f, is_freeze = pop_freeze () in
if is_freeze then begin
freeze f;
false
end else
true
and close_delim () =
let _, is_freeze = pop_freeze () in
if is_freeze then begin
close_display ();
end else begin
close_display ();
open_display ();
warning "Math expression improperly parenthesized";
end
;;
let put s =
if !verbose > 1 then
Printf.eprintf "MATH PUT: «%s»\n" s ;
let s_blank =
let r = ref true in
for i = 0 to String.length s - 1 do
r := !r && is_blank (String.get s i)
done ;
!r in
if not s_blank then begin
let s_op = is_op s
and s_number = is_number s in
if is_open_delim s then open_delim ();
let s_text = if is_close_delim s then is_close () else false in
if (s_op || s_number) && !Lexstate.display then force_item_display ();
do_pending () ;
flags.empty <- false;
flags.blank <- s_blank && flags.blank ;
if s_number then begin
do_put (" "^s^" \n")
end else if is_ident s then begin
do_put (" "^s^" \n")
end else if s_text then begin
do_put (""^s^"")
end else if s_op then begin
do_put (" "^s^" \n");
end else begin
do_put s
end;
if is_close_delim s then close_delim ()
end
;;
let put_char c =
let c_blank = is_blank c in
if c <> ' ' then begin
let s = String.make 1 c in
let c_op = is_op s in
let c_digit = is_digit c in
if is_open_delim s then open_delim ();
let c_text = if is_close_delim s then is_close () else false in
if (c_op || c_digit) && !Lexstate.display then force_item_display ();
do_pending () ;
flags.empty <- false;
flags.blank <- c_blank && flags.blank ;
if c_digit then begin
do_put (" "^s^" \n")
end else if c_text then begin
do_put (""^s^"")
end else if c_op then begin
do_put (" "^s^" \n");
end else begin
do_put_char c;
end;
if is_close_delim s then close_delim ();
end
;;
let put_in_math s =
if flags.in_pre && !pedantic then
put s
else begin
if !Lexstate.display then force_item_display ();
do_pending () ;
do_put " ";
do_put s;
do_put " \n";
flags.empty <- false; flags.blank <- false;
end
;;
(* Sup/Sub stuff *)
let put_sup_sub display scanner (arg : string Lexstate.arg) =
if display then open_display () else open_block INTERN "" ;
scanner arg ;
if display then close_display () else close_block INTERN ;
;;
(*
let insert_sub_sup tag s t =
let f, is_freeze = pop_freeze () in
let ps,pargs,pout = pop_out out_stack in
if ps <> INTERN then failclose "sup_sub" ps INTERN ;
let new_out = create_status_from_scratch false [] in
push_out out_stack (ps,pargs,new_out);
close_block INTERN;
cur_out := pout;
open_block tag "";
open_display ();
let texte = Out.to_string new_out.out in
do_put (if texte = "" then " ⁢ " else texte);
flags.empty <- false; flags.blank <- false;
free new_out;
close_display ();
put_sub_sup s;
if t<>"" then put_sub_sup t;
close_block tag;
open_block INTERN "";
if is_freeze then freeze f
;;
*)
let standard_sup_sub scanner what sup sub display =
if !verbose > 1 then
Printf.eprintf "STANDARD «%s, %s» display=%B\n"
sup.Lexstate.arg sub.Lexstate.arg display ;
let sup, _ =
hidden_to_string (fun () -> put_sup_sub display scanner sup) in
let sub,_ =
hidden_to_string (fun () -> put_sup_sub display scanner sub) in
if !verbose > 1 then
Printf.eprintf "STANDARD FORMAT «%s, %s»\n" sup sub ;
match sub,sup with
| "","" -> what ()
| a,"" ->
open_block (OTHER "msub") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
put a ;
close_block (OTHER "msub") ;
| "",b ->
open_block (OTHER "msup") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
put b ;
close_block (OTHER "msup") ;
| a,b ->
open_block (OTHER "msubsup") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
put a ; put "\n" ; put b ;
close_block (OTHER "msubsup") ;
;;
let limit_sup_sub scanner what sup sub display =
if !verbose > 1 then
Printf.eprintf "STANDARD «%s, %s»\n" sup.Lexstate.arg sub.Lexstate.arg ;
let sup, _ =
hidden_to_string (fun () -> put_sup_sub display scanner sup) in
let sub, _ =
hidden_to_string (fun () -> put_sup_sub display scanner sub) in
match sub,sup with
| "","" -> what ()
| a,"" ->
open_block (OTHER "munder") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
do_put a ;
close_block (OTHER "munder") ;
| "",b ->
open_block (OTHER "mover") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
do_put b ;
close_block (OTHER "mover") ;
| a,b ->
open_block (OTHER "munderover") "";
if display then open_display ();
what ();
if flags.empty then do_put " ⁢ " ;
if display then close_display ();
do_put a ; do_put "\n" ; do_put b ;
close_block (OTHER "munderover") ;
;;
let int_sup_sub _something _vsize scanner what sup sub display =
standard_sup_sub scanner what sup sub display
;;
let over _lexbuf =
force_item_display ();
let _mods = insert_vdisplay
(fun () ->
open_block (OTHER "mfrac") "";
open_display ()) in
force_item_display ();
flags.ncols <- flags.ncols +1;
close_display () ;
open_display () ;
freeze
(fun () ->
force_item_display ();
flags.ncols <- flags.ncols +1;
close_display () ;
close_block (OTHER "mfrac"))
;;
let box_around_display _scanner _arg = ();;
let over_align _align1 _align2 display lexbuf = over lexbuf
;;
let tr = function
"<" -> "<"
| ">" -> ">"
| "\\{" -> "{"
| "\\}" -> "}"
| s -> s
;;
let left delim _ k =
force_item_display ();
open_display ();
if delim <>"." then put (" "^ tr delim^" ");
k 0 ;
force_item_display ();
freeze
( fun () ->
force_item_display ();
close_display ();
warning "Left delimitor not matched with a right one.";
force_item_display ();
close_display ();)
;;
let right delim _ =
if !Lexstate.display then force_item_display ();
if delim <> "." then put (" "^tr delim^" ");
if !Lexstate.display then force_item_display ();
let f,is_freeze = pop_freeze () in
if not is_freeze then begin
warning "Right delimitor alone";
close_display ();
open_display ();
end else begin
try
let ps,parg,pout = pop_out out_stack in
let pps,pparg,ppout = pop_out out_stack in
if pblock() = (OTHER "mfrac") then begin
warning "Right delimitor not matched with a left one.";
push_out out_stack (pps,pparg,ppout);
push_out out_stack (ps,parg,pout);
freeze f;
close_display ();
open_display ();
end else begin
push_out out_stack (pps,pparg,ppout);
push_out out_stack (ps,parg,pout);
close_display ();
end;
with PopFreeze -> raise (UserError ("Bad placement of right delimitor"));
end;
3
;;