wenzelm@32240: (* Title: doc-src/rail.ML wenzelm@32240: Author: Michael Kerscher, TUM wenzelm@32240: wenzelm@32240: Railroad diagrams for LaTeX. wenzelm@32240: *) wenzelm@32240: wenzelm@32240: structure Rail = wenzelm@32240: struct wenzelm@32240: wenzelm@32132: datatype token = wenzelm@32132: Identifier of string | wenzelm@32132: Special_Identifier of string | wenzelm@32132: Text of string | wenzelm@32132: Anot of string | wenzelm@32132: Symbol of string | wenzelm@32132: EOF; wenzelm@32132: wenzelm@32132: fun is_identifier (Identifier _) = true wenzelm@32132: | is_identifier (Special_Identifier _ ) = true wenzelm@32132: | is_identifier _ = false; wenzelm@32240: wenzelm@32132: fun is_text (Text _) = true wenzelm@32132: | is_text _ = false; wenzelm@32132: wenzelm@32132: fun is_anot (Anot _) = true wenzelm@32132: | is_anot _ = false; wenzelm@32132: wenzelm@32132: fun is_symbol (Symbol _) = true wenzelm@32132: | is_symbol _ = false; wenzelm@32132: wenzelm@32132: fun is_ str = (fn s => s = Symbol str); wenzelm@32132: wenzelm@32132: wenzelm@32132: local (* copied from antiquote-setup... *) wenzelm@32132: fun translate f = Symbol.explode #> map f #> implode; wenzelm@32132: wenzelm@32132: fun clean_name "\" = "dots" wenzelm@32132: | clean_name ".." = "ddot" wenzelm@32132: | clean_name "." = "dot" wenzelm@32132: | clean_name "_" = "underscore" wenzelm@32132: | clean_name "{" = "braceleft" wenzelm@32132: | clean_name "}" = "braceright" wenzelm@32132: | clean_name s = s |> translate (fn "_" => "-" | "\" => "-" | c => c); wenzelm@32132: wenzelm@32132: fun no_check _ _ = true; wenzelm@32132: wenzelm@32132: fun false_check _ _ = false; wenzelm@32132: wenzelm@32132: fun thy_check intern defined ctxt = wenzelm@32132: let val thy = ProofContext.theory_of ctxt wenzelm@32132: in defined thy o intern thy end; wenzelm@32132: wenzelm@32132: fun check_tool name = wenzelm@32132: File.exists (Path.append (Path.explode "~~/lib/Tools") (Path.basic name)); wenzelm@32132: wenzelm@32132: val arg = enclose "{" "}"; wenzelm@32132: wenzelm@32132: val markup_table = wenzelm@32132: (* [(kind, (markup, check, style))*) wenzelm@32132: Symtab.make [ wenzelm@32132: ("syntax", ("", no_check, true)), wenzelm@36973: ("command", ("isacommand", K (is_some o Keyword.command_keyword), true)), wenzelm@36973: ("keyword", ("isakeyword", K Keyword.is_keyword, true)), wenzelm@36973: ("element", ("isakeyword", K Keyword.is_keyword, true)), wenzelm@32132: ("method", ("", thy_check Method.intern Method.defined, true)), wenzelm@32132: ("attribute", ("", thy_check Attrib.intern Attrib.defined, true)), wenzelm@32132: ("fact", ("", no_check, true)), wenzelm@32132: ("variable", ("", no_check, true)), wenzelm@32132: ("case", ("", no_check, true)), wenzelm@37216: ("antiquotation", ("", K Thy_Output.defined_command, true)), wenzelm@37216: ("antiquotation option", ("", K Thy_Output.defined_option, true)), (* kann mein scanner nicht erkennen *) wenzelm@32132: ("setting", ("isatt", (fn _ => fn name => is_some (OS.Process.getEnv name)), true)), wenzelm@32132: ("inference", ("", no_check, true)), wenzelm@32132: ("executable", ("isatt", no_check, true)), wenzelm@32132: ("tool", ("isatt", K check_tool, true)), wenzelm@32132: ("file", ("isatt", K (File.exists o Path.explode), true)), wenzelm@37216: ("theory", ("", K Thy_Info.known_thy, true)) wenzelm@32132: ]; wenzelm@32132: wenzelm@32132: in wenzelm@32132: wenzelm@32132: fun decode_link ctxt (kind,index,logic,name) = wenzelm@32132: let wenzelm@32132: val (markup, check, style) = case Symtab.lookup markup_table kind of wenzelm@32132: SOME x => x wenzelm@32132: | NONE => ("", false_check, false); wenzelm@32132: val hyper_name = wenzelm@32132: "{" ^ Long_Name.append kind (Long_Name.append logic (clean_name name)) ^ "}"; wenzelm@32132: val hyper = wenzelm@32132: enclose ("\\hyperlink" ^ hyper_name ^ "{") "}" #> wenzelm@32132: index = "def" ? enclose ("\\hypertarget" ^ hyper_name ^ "{") "}"; wenzelm@32132: val idx = wenzelm@32132: if index = "" then "" wenzelm@32132: else "\\index" ^ index ^ arg logic ^ arg kind ^ arg name; wenzelm@32132: in wenzelm@32132: if check ctxt name then wenzelm@32132: (idx ^ wenzelm@32132: (Output.output name wenzelm@32132: |> (if markup = "" then I else enclose ("\\" ^ markup ^ "{") "}") wenzelm@37216: |> (if ! Thy_Output.quotes then quote else I) wenzelm@37216: |> (if ! Thy_Output.display then enclose "\\begin{isabelle}%\n" "%\n\\end{isabelle}" wenzelm@32449: else hyper o enclose "\\mbox{\\isa{" "}}")), style) wenzelm@32132: else ("Bad " ^ kind ^ " " ^ name, false) wenzelm@32132: end; wenzelm@32132: end; wenzelm@32132: wenzelm@32132: val blanks = wenzelm@32132: Scan.many Symbol.is_blank >> implode; wenzelm@32132: wenzelm@32132: val scan_symbol = wenzelm@32132: $$ ";" || $$ ":"|| $$ "("|| $$ ")"|| $$ "+"|| $$ "|"|| $$ "*"|| $$ "?"|| $$ "\\"; wenzelm@32132: wenzelm@32132: (* escaped version *) wenzelm@32132: val scan_link = (* @{kind{_def|_ref (logic) name} *) wenzelm@32132: let wenzelm@32132: fun pseudo_antiquote inner_scan = ($$ "@" ^^ $$ "{") |-- inner_scan --| (blanks -- $$ "}"); wenzelm@32132: fun parens scan = $$ "(" |-- scan --| $$ ")"; wenzelm@32132: fun opt_quotes scan = $$ "'" |-- scan --| $$ "'" || scan; wenzelm@32132: val letters = Scan.many Symbol.is_letter >> implode; wenzelm@32132: val kind_name = letters; wenzelm@32132: val opt_kind_type = Scan.optional ( wenzelm@32132: $$ "_" |-- (Scan.this_string "def" || Scan.this_string "ref")) ""; wenzelm@32132: val logic_name = letters; wenzelm@32132: val escaped_singlequote = $$ "\\" |-- $$ "'"; wenzelm@32132: val text = Scan.repeat (Scan.one Symbol.is_letter || escaped_singlequote) >> implode; wenzelm@32132: in wenzelm@32132: pseudo_antiquote ( wenzelm@32132: kind_name -- opt_kind_type -- wenzelm@32132: (blanks |-- Scan.optional ( parens logic_name ) "") -- wenzelm@32132: (blanks |-- opt_quotes text) ) wenzelm@32132: >> (fn (((kind,index),logic),name) => (kind, index, logic, name)) wenzelm@32132: end; wenzelm@32132: wenzelm@32132: (* escaped version *) wenzelm@32240: fun scan_identifier ctxt = wenzelm@32132: let fun is_identifier_start s = wenzelm@32132: Symbol.is_letter s orelse wenzelm@32132: s = "_" wenzelm@32132: fun is_identifier_rest s = wenzelm@32132: Symbol.is_letter s orelse wenzelm@32132: Symbol.is_digit s orelse wenzelm@32132: s = "_" orelse wenzelm@32132: s = "." wenzelm@32132: in wenzelm@32132: (Scan.one is_identifier_start ::: wenzelm@32132: Scan.repeat (Scan.one is_identifier_rest || ($$ "\\" |-- $$ "'")) wenzelm@32132: ) >> (Identifier o enclose "\\isa{" "}" o Output.output o implode) || wenzelm@32132: scan_link >> (decode_link ctxt) >> wenzelm@32132: (fn (txt, style) => wenzelm@32449: if style then Special_Identifier(txt) wenzelm@32449: else Identifier(txt)) wenzelm@32132: end; wenzelm@32132: wenzelm@32132: fun scan_anot ctxt = wenzelm@32132: let val scan_anot = wenzelm@32132: Scan.many (fn s => wenzelm@32132: s <> "\n" andalso wenzelm@32132: s <> "\t" andalso wenzelm@32132: s <> "]" andalso wenzelm@32132: Symbol.is_regular s) >> implode wenzelm@32132: in wenzelm@32132: $$ "[" |-- scan_link --| $$ "]" >> (fst o (decode_link ctxt)) || wenzelm@32132: $$ "[" |-- scan_anot --| $$ "]" >> Output.output wenzelm@32132: end; wenzelm@32132: wenzelm@32132: (* escaped version *) wenzelm@32132: fun scan_text ctxt = wenzelm@32132: let wenzelm@32132: val text_sq = wenzelm@32132: Scan.repeat ( wenzelm@32132: Scan.one (fn s => wenzelm@32449: s <> "\n" andalso wenzelm@32449: s <> "\t" andalso wenzelm@32449: s <> "'" andalso wenzelm@32449: s <> "\\" andalso wenzelm@32449: Symbol.is_regular s) || wenzelm@32449: ($$ "\\" |-- $$ "'") wenzelm@32132: ) >> implode wenzelm@32132: fun quoted scan = $$ "'" |-- scan --| $$ "'"; wenzelm@32132: in wenzelm@32132: quoted scan_link >> (fst o (decode_link ctxt)) || wenzelm@32132: quoted text_sq >> (enclose "\\isa{" "}" o Output.output) wenzelm@32132: end; wenzelm@32132: wenzelm@32132: fun scan_rail ctxt = wenzelm@32132: Scan.repeat ( blanks |-- ( wenzelm@32132: scan_identifier ctxt || wenzelm@32132: scan_anot ctxt >> Anot || wenzelm@32132: scan_text ctxt >> Text || wenzelm@32132: scan_symbol >> Symbol) wenzelm@32132: ) --| blanks; wenzelm@32132: wenzelm@32132: fun lex_rail txt ctxt = (* Symbol_Pos fuer spaeter durchgereicht *) wenzelm@32132: Symbol.scanner "Malformed rail-declaration" (scan_rail ctxt) (map fst (Symbol_Pos.explode txt)); wenzelm@32132: wenzelm@32132: val lex = lex_rail; wenzelm@32132: wenzelm@32132: datatype id_kind = UNKNOWN | TOKEN | TERM | NTERM; wenzelm@32132: wenzelm@32132: datatype id_type = wenzelm@32132: Id of string * id_kind | wenzelm@32132: Null_Id; wenzelm@32132: wenzelm@32132: datatype body_kind = wenzelm@32132: CAT | BAR | PLUS | wenzelm@32132: CR | EMPTY | ANNOTE | IDENT | STRING | wenzelm@32132: Null_Kind; wenzelm@32132: wenzelm@32240: datatype body_type = wenzelm@32132: Body of body_kind * string * string * id_type * body_type list | wenzelm@32132: Body_Pos of body_kind * string * string * id_type * body_type list * int * int | wenzelm@32132: Empty_Body | wenzelm@32132: Null_Body; wenzelm@32132: wenzelm@32240: datatype rule = wenzelm@32132: Rule of id_type * body_type; wenzelm@32132: wenzelm@32132: fun new_id id kind = Id (id, kind); wenzelm@32132: wenzelm@32132: fun is_empty (Body(kind,_,_,_,_)) = kind = EMPTY; wenzelm@32132: wenzelm@32132: fun new_body (kind, Null_Body, Null_Body) = Body (kind, "", "", Null_Id, []) wenzelm@32132: | new_body (kind, body1, body2) = Body (kind, "", "", Null_Id, body1 :: [body2]); wenzelm@32132: wenzelm@32132: fun is_kind_of kind (Body(bodyKind,_,_,_,_)) = kind = bodyKind wenzelm@32132: | is_kind_of _ _ = false; wenzelm@32132: wenzelm@32132: fun add_list (Body(kind, text, annot, id, bodies), body) = wenzelm@32132: Body(kind, text, annot, id, bodies @ [body]); wenzelm@32132: wenzelm@32240: fun cat_body_lists (Body(kind, text, annot, id, bodies1), Body(_,_,_,_, bodies2)) = wenzelm@32132: Body(kind, text, annot, id, bodies1 @ bodies2); wenzelm@32132: wenzelm@32132: fun add_body (kind, body1 as Body(kind1,_,_,_,_), body2 as Body(kind2,_,_,_,_)) = wenzelm@32132: if kind = kind1 andalso kind <> BAR then wenzelm@32132: if kind = kind2 then wenzelm@32132: cat_body_lists(body1, body2) wenzelm@32132: else (* kind <> kind2 *) wenzelm@32132: add_list(body1, body2) wenzelm@32132: else (* kind <> kind1 orelse kind = BAR *) wenzelm@32132: if kind = kind2 then wenzelm@32132: cat_body_lists(add_list(new_body(kind,Null_Body,Null_Body), body1), body2) wenzelm@32132: else (* kind <> kind2 *) wenzelm@32132: add_list(add_list(new_body(kind,Null_Body,Null_Body), body1), body2); wenzelm@32132: wenzelm@32132: fun rev_body (body as Body (kind, text, annot, id, [])) = body wenzelm@32132: | rev_body (Body (CAT, text, annot, id, bodies)) = wenzelm@32132: Body(CAT, text, annot, id, map rev_body (rev bodies)) wenzelm@32132: | rev_body (Body (kind, text, annot, id, bodies)) = wenzelm@32132: Body(kind, text, annot, id, map rev_body bodies) wenzelm@32132: | rev_body body = body; wenzelm@32132: wenzelm@32132: fun set_body_text text (Body(k,_,a,i,b)) = Body(k,text,a,i,b); wenzelm@32132: fun set_body_anot anot (Body(k,t,_,i,b)) = Body(k,t,anot,i,b); wenzelm@32132: fun set_body_ident id (Body(k,t,a,_,b)) = Body(k,t,a, new_id id TOKEN,b); wenzelm@32132: fun set_body_special_ident id (Body(k,t,a,_,b)) = Body(k,t,a, new_id id TERM,b); wenzelm@32132: wenzelm@32132: wenzelm@32132: fun mk_eof _ = EOF; wenzelm@32132: fun is_eof s = s = EOF; wenzelm@32132: val stopper = Scan.stopper mk_eof is_eof; wenzelm@32132: wenzelm@32132: (* TODO: change this, so the next or next two tokens are printed *) wenzelm@32132: fun lex_err msg (cs, _) = "rail grammar error: " ^ msg cs; wenzelm@32132: fun !!! msg scan = Scan.!! (lex_err (K msg)) scan; wenzelm@32132: fun $$$ tok = Scan.one (is_ tok); wenzelm@32132: wenzelm@32132: wenzelm@32132: local wenzelm@32132: fun new_bar_body([], body2) = body2 wenzelm@32132: | new_bar_body(body1::bodies, body2) = wenzelm@32132: add_body(BAR, body1, new_bar_body(bodies, body2)); wenzelm@32132: wenzelm@32132: fun new_cat_body(body::[]) = body wenzelm@32132: | new_cat_body(body1::bodies) = add_body(CAT, body1, new_cat_body(bodies)); wenzelm@32132: wenzelm@32132: fun new_annote_body (Anot anot) = wenzelm@32132: set_body_text anot (new_body(ANNOTE, Empty_Body, Empty_Body)); wenzelm@32132: wenzelm@32132: fun new_text_annote_body (Text text, Anot anot) = wenzelm@32132: set_body_anot anot (set_body_text text (new_body(STRING, Empty_Body, Empty_Body))); wenzelm@32132: wenzelm@32132: fun new_ident_body (Identifier ident, Anot anot) = wenzelm@32132: set_body_anot anot (set_body_ident ident (new_body(IDENT, Empty_Body, Empty_Body))) wenzelm@32132: | new_ident_body (Special_Identifier ident, Anot anot) = wenzelm@32132: set_body_anot anot (set_body_special_ident ident (new_body(IDENT, Empty_Body, Empty_Body))); wenzelm@32132: wenzelm@32132: val new_empty_body = new_body(EMPTY, Null_Body, Null_Body); wenzelm@32132: in wenzelm@32132: wenzelm@32132: fun parse_body x = wenzelm@32132: ( wenzelm@32132: Scan.repeat1 (parse_body0 --| $$$ "|") -- !!! "body0 expected" (parse_body0) >> wenzelm@32132: new_bar_body || wenzelm@32132: parse_body0 wenzelm@32132: ) x wenzelm@32132: and parse_body0 x = wenzelm@32132: ( wenzelm@32132: Scan.one is_anot -- !!! "body1 expected" (parse_body1) >> wenzelm@32132: (fn (anot, body) => add_body(CAT, new_annote_body(anot), body)) || wenzelm@32132: parse_body1 wenzelm@32132: ) x wenzelm@32132: and parse_body1 x = wenzelm@32132: ( wenzelm@32132: parse_body2 -- ($$$ "*" |-- !!! "body4e expected" (parse_body4e)) >> wenzelm@32132: (fn (body1, body2) => wenzelm@32132: if is_empty body2 then wenzelm@32449: add_body(PLUS, new_empty_body, rev_body body1) wenzelm@32132: else wenzelm@32449: add_body(BAR, new_empty_body, add_body (PLUS, body1, rev_body body2)) ) || wenzelm@32240: parse_body2 -- ($$$ "+" |-- !!! "body4e expected" (parse_body4e)) >> wenzelm@32132: (fn (body1, body2) => new_body (PLUS, body1, rev_body body2) ) || wenzelm@32132: parse_body2e wenzelm@32132: ) x wenzelm@32132: and parse_body2e x = wenzelm@32132: ( wenzelm@32132: parse_body2 || wenzelm@32132: (fn toks => (new_empty_body, toks)) wenzelm@32132: ) x wenzelm@32132: and parse_body2 x = wenzelm@32132: ( wenzelm@32132: Scan.repeat1 (parse_body3) >> new_cat_body wenzelm@32132: ) x wenzelm@32132: and parse_body3 x = wenzelm@32132: ( wenzelm@32132: parse_body4 --| $$$ "?" >> (fn body => new_body (BAR, new_empty_body, body) ) || wenzelm@32132: parse_body4 wenzelm@32132: ) x wenzelm@32132: and parse_body4e x = wenzelm@32132: ( wenzelm@32132: parse_body4 || wenzelm@32132: (fn toks => (new_empty_body, toks)) wenzelm@32132: ) x wenzelm@32132: and parse_body4 x = wenzelm@32132: ( wenzelm@32132: $$$ "(" |-- !!! "body0 or ')' expected" (parse_body --| $$$ ")") || wenzelm@32132: Scan.one is_text -- (Scan.optional (Scan.one is_anot) (Anot(""))) >> wenzelm@32240: (fn (text, anot) => new_text_annote_body (text,anot)) || wenzelm@32132: Scan.one is_identifier -- (Scan.optional (Scan.one is_anot) (Anot(""))) >> wenzelm@32132: (fn (id, anot) => new_ident_body (id,anot)) || wenzelm@32132: $$$ "\\" >> (fn _ => new_body (CR, Null_Body, Null_Body)) wenzelm@32132: ) x; wenzelm@32132: end; wenzelm@32132: wenzelm@32132: fun new_named_rule (Identifier name, body) = Rule(Id(name, UNKNOWN), body) wenzelm@32132: | new_named_rule (Special_Identifier name, body) = Rule(Id(name, UNKNOWN), body); wenzelm@32132: fun new_anonym_rule body = Rule(Null_Id, body); wenzelm@32132: wenzelm@32132: val parse_rule = wenzelm@32132: (Scan.one (is_identifier) -- ($$$ ":" |-- !!! "body expected" (parse_body)) ) >> wenzelm@32132: new_named_rule || wenzelm@32132: parse_body >> new_anonym_rule; wenzelm@32132: wenzelm@32132: val parse_rules = wenzelm@32132: Scan.repeat ( parse_rule --| $$$ ";") @@@ Scan.single parse_rule; wenzelm@32132: wenzelm@32132: fun parse_rail s = wenzelm@32132: Scan.read stopper parse_rules s; wenzelm@32132: wenzelm@32132: val parse = parse_rail; wenzelm@32132: wenzelm@32132: fun getystart (Body_Pos(_,_,_,_,_,ystart,_)) = ystart; wenzelm@32132: fun getynext (Body_Pos(_,_,_,_,_,_,ynext)) = ynext; wenzelm@32132: wenzelm@32132: fun position_body (body as Body(kind, text, annot, id, bodies), ystart) = wenzelm@32132: let fun max (x,y) = if x > y then x else y wenzelm@32132: fun set_body_position (Body(kind, text, annot, id, bodies), ystart, ynext) = wenzelm@32449: Body_Pos(kind, text, annot, id, bodies, ystart, ynext) wenzelm@32132: fun pos_bodies_cat ([],_,ynext,liste) = (liste, ynext) wenzelm@32132: | pos_bodies_cat (x::xs, ystart, ynext, liste) = wenzelm@32449: if is_kind_of CR x then wenzelm@32449: (case set_body_position(x, ystart, ynext+1) of wenzelm@32449: body as Body_Pos(_,_,_,_,_,_,ynext1) => wenzelm@32449: pos_bodies_cat(xs, ynext1, max(ynext,ynext1), liste@[body]) wenzelm@32449: ) wenzelm@32449: else wenzelm@32449: (case position_body(x, ystart) of wenzelm@32449: body as Body_Pos(_,_,_,_,_,_,ynext1) => wenzelm@32449: pos_bodies_cat(xs, ystart, max(ynext,ynext1), liste@[body]) wenzelm@32449: ) wenzelm@32132: fun pos_bodies_bar_plus ([],_,ynext,liste) = (liste, ynext) wenzelm@32132: | pos_bodies_bar_plus (x::xs, ystart, ynext, liste) = wenzelm@32449: (case position_body(x, ystart) of wenzelm@32449: body as Body_Pos(_,_,_,_,_,_,ynext1) => wenzelm@32449: pos_bodies_bar_plus(xs, ynext1, max(ynext,ynext1), liste@[body]) wenzelm@32449: ) wenzelm@32132: in wenzelm@32132: (case kind of wenzelm@32132: CAT => (case pos_bodies_cat(bodies,ystart,ystart+1,[]) of wenzelm@32449: (bodiesPos, ynext) => wenzelm@32449: Body_Pos(kind, text, annot, id, bodiesPos, ystart, ynext)) wenzelm@32132: | BAR => (case pos_bodies_bar_plus(bodies,ystart,ystart+1,[]) of wenzelm@32449: (bodiesPos, ynext) => wenzelm@32449: Body_Pos(kind, text, annot, id, bodiesPos, ystart, ynext)) wenzelm@32132: | PLUS => (case pos_bodies_bar_plus(bodies,ystart,ystart+1,[]) of wenzelm@32449: (bodiesPos, ynext) => wenzelm@32449: Body_Pos(kind, text, annot, id, bodiesPos, ystart, ynext)) wenzelm@32132: | CR => set_body_position(body, ystart, ystart+3) wenzelm@32132: | EMPTY => set_body_position(body, ystart, ystart+1) wenzelm@32132: | ANNOTE => set_body_position(body, ystart, ystart+1) wenzelm@32132: | IDENT => set_body_position(body, ystart, ystart+1) wenzelm@32132: | STRING => set_body_position(body, ystart, ystart+1) wenzelm@32132: ) wenzelm@32132: end; wenzelm@32132: wenzelm@32132: fun format_body (Body_Pos(EMPTY,_,_,_,_,_,_), _) = "" wenzelm@32132: | format_body (Body_Pos(CAT,_,_,_,bodies,_,_), cent) = wenzelm@32132: let fun format_bodies([]) = "" wenzelm@32449: | format_bodies(x::xs) = format_body (x, "") ^ format_bodies(xs) wenzelm@32132: in wenzelm@32132: format_bodies(bodies) wenzelm@32132: end wenzelm@32240: | format_body (Body_Pos(BAR,_,_,_,bodies,_,_),cent) = wenzelm@32132: let fun format_bodies([]) = "\\rail@endbar\n" wenzelm@32449: | format_bodies(x::xs) = wenzelm@32449: "\\rail@nextbar{" ^ string_of_int(getystart(x)) ^"}\n" ^ wenzelm@32449: format_body(x, "") ^ format_bodies(xs) wenzelm@32132: in wenzelm@32132: "\\rail@bar\n" ^ format_body(hd(bodies), "") ^ format_bodies(tl(bodies)) wenzelm@32132: end wenzelm@32132: | format_body (Body_Pos(PLUS,_,_,_,x::y::xs,_,_),cent) = wenzelm@32132: "\\rail@plus\n" ^ format_body(x, cent) ^ wenzelm@32132: "\\rail@nextplus{" ^ string_of_int(getystart(y)) ^ "}\n" ^ wenzelm@32132: format_body(y, "c") ^ wenzelm@32132: "\\rail@endplus\n" wenzelm@32132: | format_body (Body_Pos(ANNOTE,text,_,_,_,_,_),cent) = wenzelm@32132: "\\rail@annote[" ^ text ^ "]\n" wenzelm@32132: | format_body (Body_Pos(IDENT,_,annot,Id(name,TERM),_,_,_),cent) = wenzelm@32132: "\\rail@" ^ cent ^ "token{" ^ name ^ "}" ^ "[" ^ annot ^ "]\n" wenzelm@32132: | format_body (Body_Pos(IDENT,_,annot,Id(name,_),_,_,_),cent) = wenzelm@32132: "\\rail@" ^ cent ^ "nont{" ^ name ^ "}" ^ "[" ^ annot ^ "]\n" wenzelm@32132: | format_body (Body_Pos(CR,_,_,_,_,_,ynext),cent) = wenzelm@32132: "\\rail@cr{" ^ string_of_int(ynext) ^ "}\n" wenzelm@32132: | format_body (Body_Pos(STRING,text,annot,_,_,_,_),cent) = wenzelm@32132: "\\rail@" ^ cent ^ "term{" ^ text ^ "}[" ^ annot ^ "]\n" wenzelm@32132: | format_body _ = wenzelm@32132: "\\rail@unknown\n"; wenzelm@32132: wenzelm@32132: fun out_body (Id(name,_), body) = wenzelm@32132: let val bodyPos as Body_Pos(_,_,_,_,_,_,ynext) = position_body(body,0) wenzelm@32132: in wenzelm@32132: "\\rail@begin{" ^ string_of_int(ynext) ^ "}{" ^ name ^ "}\n" ^ wenzelm@32132: format_body(bodyPos,"") ^ wenzelm@32132: "\\rail@end\n" wenzelm@32132: end wenzelm@32132: | out_body (Null_Id, body) = out_body (Id("", UNKNOWN), body); wenzelm@32132: wenzelm@32132: fun out_rule (Rule(id, body)) = wenzelm@32132: if is_empty body then "" wenzelm@32132: else out_body (id, body); wenzelm@32132: wenzelm@32132: fun out_rules ([]) = "" wenzelm@32132: | out_rules (rule::rules) = out_rule rule ^ out_rules rules; wenzelm@32132: wenzelm@32132: val output_no_rules = wenzelm@32132: "\\rail@begin{1}{}\n" ^ wenzelm@32132: "\\rail@setbox{\\bfseries ???}\n" ^ wenzelm@32132: "\\rail@oval\n" ^ wenzelm@32132: "\\rail@end\n"; wenzelm@32132: wenzelm@32132: wenzelm@32132: fun print (SOME rules) = wenzelm@32132: "\\begin{railoutput}\n" ^ wenzelm@32132: out_rules rules ^ wenzelm@32132: "\\end{railoutput}\n" wenzelm@32132: | print (NONE) = wenzelm@32132: "\\begin{railoutput}\n" ^ wenzelm@32132: output_no_rules ^ wenzelm@32132: "\\end{railoutput}\n"; wenzelm@32132: wenzelm@32132: fun process txt ctxt = wenzelm@32132: lex txt ctxt wenzelm@32132: |> parse wenzelm@32132: |> print; wenzelm@32132: wenzelm@37216: val _ = Thy_Output.antiquotation "rail" (Scan.lift (Parse.position Args.name)) wenzelm@32132: (fn {context = ctxt,...} => fn txt => process txt ctxt); wenzelm@32240: wenzelm@32240: end; wenzelm@32240: