doc-src/rail.ML
changeset 32233 2b175fc6668a
parent 32132 29aed5725acb
child 32449 696d64ed85da
equal deleted inserted replaced
32232:6c394343360f 32233:2b175fc6668a
       
     1 (*  Title:      doc-src/rail.ML
       
     2     Author:     Michael Kerscher, TUM
       
     3 
       
     4 Railroad diagrams for LaTeX.
       
     5 *)
       
     6 
       
     7 structure Rail =
       
     8 struct
       
     9 
     1 datatype token =
    10 datatype token =
     2   Identifier of string |
    11   Identifier of string |
     3   Special_Identifier of string |
    12   Special_Identifier of string |
     4   Text of string |
    13   Text of string |
     5   Anot of string |
    14   Anot of string |
     7   EOF;
    16   EOF;
     8 
    17 
     9 fun is_identifier (Identifier _) = true
    18 fun is_identifier (Identifier _) = true
    10   | is_identifier (Special_Identifier _ ) = true
    19   | is_identifier (Special_Identifier _ ) = true
    11   | is_identifier _ = false;
    20   | is_identifier _ = false;
    12   
    21 
    13 fun is_text (Text _) = true
    22 fun is_text (Text _) = true
    14   | is_text _ = false;
    23   | is_text _ = false;
    15 
    24 
    16 fun is_anot (Anot _) = true
    25 fun is_anot (Anot _) = true
    17   | is_anot _ = false;
    26   | is_anot _ = false;
    63   ("setting", ("isatt", (fn _ => fn name => is_some (OS.Process.getEnv name)), true)),
    72   ("setting", ("isatt", (fn _ => fn name => is_some (OS.Process.getEnv name)), true)),
    64   ("inference", ("", no_check, true)),
    73   ("inference", ("", no_check, true)),
    65   ("executable", ("isatt", no_check, true)),
    74   ("executable", ("isatt", no_check, true)),
    66   ("tool", ("isatt", K check_tool, true)),
    75   ("tool", ("isatt", K check_tool, true)),
    67   ("file", ("isatt", K (File.exists o Path.explode), true)),
    76   ("file", ("isatt", K (File.exists o Path.explode), true)),
    68   ("theory", ("", K ThyInfo.known_thy, true)) 
    77   ("theory", ("", K ThyInfo.known_thy, true))
    69   ];
    78   ];
    70 
    79 
    71 in
    80 in
    72 
    81 
    73 fun decode_link ctxt (kind,index,logic,name) =
    82 fun decode_link ctxt (kind,index,logic,name) =
   121     (blanks |-- opt_quotes text) )
   130     (blanks |-- opt_quotes text) )
   122     >> (fn (((kind,index),logic),name) => (kind, index, logic, name))
   131     >> (fn (((kind,index),logic),name) => (kind, index, logic, name))
   123 end;
   132 end;
   124 
   133 
   125 (* escaped version *)
   134 (* escaped version *)
   126 fun scan_identifier ctxt = 
   135 fun scan_identifier ctxt =
   127   let fun is_identifier_start s =
   136   let fun is_identifier_start s =
   128     Symbol.is_letter s orelse
   137     Symbol.is_letter s orelse
   129     s = "_"
   138     s = "_"
   130   fun is_identifier_rest s =
   139   fun is_identifier_rest s =
   131     Symbol.is_letter s orelse
   140     Symbol.is_letter s orelse
   195 datatype body_kind =
   204 datatype body_kind =
   196   CAT | BAR | PLUS |
   205   CAT | BAR | PLUS |
   197   CR | EMPTY | ANNOTE | IDENT | STRING |
   206   CR | EMPTY | ANNOTE | IDENT | STRING |
   198   Null_Kind;
   207   Null_Kind;
   199 
   208 
   200 datatype body_type =	
   209 datatype body_type =
   201   Body of body_kind * string * string * id_type * body_type list |
   210   Body of body_kind * string * string * id_type * body_type list |
   202   Body_Pos of body_kind * string * string * id_type * body_type list * int * int |
   211   Body_Pos of body_kind * string * string * id_type * body_type list * int * int |
   203   Empty_Body |
   212   Empty_Body |
   204   Null_Body;
   213   Null_Body;
   205 
   214 
   206 datatype rule = 
   215 datatype rule =
   207   Rule of id_type * body_type;
   216   Rule of id_type * body_type;
   208 
   217 
   209 fun new_id id kind = Id (id, kind);
   218 fun new_id id kind = Id (id, kind);
   210 
   219 
   211 fun is_empty (Body(kind,_,_,_,_)) = kind = EMPTY;
   220 fun is_empty (Body(kind,_,_,_,_)) = kind = EMPTY;
   217   | is_kind_of _ _ = false;
   226   | is_kind_of _ _ = false;
   218 
   227 
   219 fun add_list (Body(kind, text, annot, id, bodies), body) =
   228 fun add_list (Body(kind, text, annot, id, bodies), body) =
   220   Body(kind, text, annot, id, bodies @ [body]);
   229   Body(kind, text, annot, id, bodies @ [body]);
   221 
   230 
   222 fun cat_body_lists (Body(kind, text, annot, id, bodies1), Body(_,_,_,_, bodies2)) = 
   231 fun cat_body_lists (Body(kind, text, annot, id, bodies1), Body(_,_,_,_, bodies2)) =
   223       Body(kind, text, annot, id, bodies1 @ bodies2);
   232       Body(kind, text, annot, id, bodies1 @ bodies2);
   224 
   233 
   225 fun add_body (kind, body1 as Body(kind1,_,_,_,_), body2 as Body(kind2,_,_,_,_)) =
   234 fun add_body (kind, body1 as Body(kind1,_,_,_,_), body2 as Body(kind2,_,_,_,_)) =
   226   if kind = kind1 andalso kind <> BAR then
   235   if kind = kind1 andalso kind <> BAR then
   227     if kind = kind2 then
   236     if kind = kind2 then
   297     (fn (body1, body2) =>
   306     (fn (body1, body2) =>
   298       if is_empty body2 then
   307       if is_empty body2 then
   299 	add_body(PLUS, new_empty_body, rev_body body1)
   308 	add_body(PLUS, new_empty_body, rev_body body1)
   300       else
   309       else
   301 	add_body(BAR, new_empty_body, add_body (PLUS, body1, rev_body body2)) ) ||
   310 	add_body(BAR, new_empty_body, add_body (PLUS, body1, rev_body body2)) ) ||
   302   parse_body2 -- ($$$ "+" |-- !!! "body4e expected" (parse_body4e)) >> 
   311   parse_body2 -- ($$$ "+" |-- !!! "body4e expected" (parse_body4e)) >>
   303     (fn (body1, body2) => new_body (PLUS, body1, rev_body body2) ) ||
   312     (fn (body1, body2) => new_body (PLUS, body1, rev_body body2) ) ||
   304   parse_body2e
   313   parse_body2e
   305   ) x
   314   ) x
   306 and parse_body2e x =
   315 and parse_body2e x =
   307   (
   316   (
   324   ) x
   333   ) x
   325 and parse_body4 x =
   334 and parse_body4 x =
   326   (
   335   (
   327   $$$ "(" |-- !!! "body0 or ')' expected" (parse_body --| $$$ ")") ||
   336   $$$ "(" |-- !!! "body0 or ')' expected" (parse_body --| $$$ ")") ||
   328   Scan.one is_text -- (Scan.optional (Scan.one is_anot) (Anot(""))) >>
   337   Scan.one is_text -- (Scan.optional (Scan.one is_anot) (Anot(""))) >>
   329     (fn (text, anot) => new_text_annote_body (text,anot)) ||    
   338     (fn (text, anot) => new_text_annote_body (text,anot)) ||
   330   Scan.one is_identifier -- (Scan.optional (Scan.one is_anot) (Anot(""))) >>
   339   Scan.one is_identifier -- (Scan.optional (Scan.one is_anot) (Anot(""))) >>
   331     (fn (id, anot) => new_ident_body (id,anot)) ||
   340     (fn (id, anot) => new_ident_body (id,anot)) ||
   332   $$$ "\\" >> (fn _ => new_body (CR, Null_Body, Null_Body))
   341   $$$ "\\" >> (fn _ => new_body (CR, Null_Body, Null_Body))
   333   ) x;
   342   ) x;
   334 end;
   343 end;
   399     let fun format_bodies([]) = ""
   408     let fun format_bodies([]) = ""
   400 	  | format_bodies(x::xs) = format_body (x, "") ^ format_bodies(xs)
   409 	  | format_bodies(x::xs) = format_body (x, "") ^ format_bodies(xs)
   401     in
   410     in
   402       format_bodies(bodies)
   411       format_bodies(bodies)
   403     end
   412     end
   404   | format_body (Body_Pos(BAR,_,_,_,bodies,_,_),cent) = 
   413   | format_body (Body_Pos(BAR,_,_,_,bodies,_,_),cent) =
   405     let fun format_bodies([]) = "\\rail@endbar\n"
   414     let fun format_bodies([]) = "\\rail@endbar\n"
   406 	  | format_bodies(x::xs) =
   415 	  | format_bodies(x::xs) =
   407 	      "\\rail@nextbar{" ^ string_of_int(getystart(x)) ^"}\n" ^
   416 	      "\\rail@nextbar{" ^ string_of_int(getystart(x)) ^"}\n" ^
   408 	      format_body(x, "") ^ format_bodies(xs)
   417 	      format_body(x, "") ^ format_bodies(xs)
   409     in
   418     in
   464   |> parse
   473   |> parse
   465   |> print;
   474   |> print;
   466 
   475 
   467 val _ = ThyOutput.antiquotation "rail" (Scan.lift ( OuterParse.position Args.name ))
   476 val _ = ThyOutput.antiquotation "rail" (Scan.lift ( OuterParse.position Args.name ))
   468   (fn {context = ctxt,...} => fn txt => process txt ctxt);
   477   (fn {context = ctxt,...} => fn txt => process txt ctxt);
       
   478 
       
   479 end;
       
   480