src/Pure/General/symbol.ML
author haftmann
Tue, 28 Apr 2009 18:42:26 +0200
changeset 31013 69a476d6fea6
parent 29606 fedb8be05f24
child 31429 e8d5417a1831
permissions -rw-r--r--
Symbol.name_of and Name.desymbolize
     1 (*  Title:      Pure/General/symbol.ML
     2     Author:     Markus Wenzel, TU Muenchen
     3 
     4 Generalized characters with infinitely many named symbols.
     5 *)
     6 
     7 signature SYMBOL =
     8 sig
     9   type symbol
    10   val SOH: symbol
    11   val STX: symbol
    12   val ENQ: symbol
    13   val ACK: symbol
    14   val DEL: symbol
    15   val space: symbol
    16   val spaces: int -> string
    17   val is_char: symbol -> bool
    18   val is_symbolic: symbol -> bool
    19   val is_printable: symbol -> bool
    20   val is_utf8_trailer: symbol -> bool
    21   val name_of: symbol -> string
    22   val eof: symbol
    23   val is_eof: symbol -> bool
    24   val not_eof: symbol -> bool
    25   val stopper: symbol Scan.stopper
    26   val sync: symbol
    27   val is_sync: symbol -> bool
    28   val malformed: symbol
    29   val end_malformed: symbol
    30   val separate_chars: string -> string
    31   val is_regular: symbol -> bool
    32   val is_ascii: symbol -> bool
    33   val is_ascii_letter: symbol -> bool
    34   val is_ascii_digit: symbol -> bool
    35   val is_ascii_hex: symbol -> bool
    36   val is_ascii_quasi: symbol -> bool
    37   val is_ascii_blank: symbol -> bool
    38   val is_ascii_lower: symbol -> bool
    39   val is_ascii_upper: symbol -> bool
    40   val to_ascii_lower: symbol -> symbol
    41   val to_ascii_upper: symbol -> symbol
    42   val is_raw: symbol -> bool
    43   val decode_raw: symbol -> string
    44   val encode_raw: string -> string
    45   datatype sym = Char of string | Sym of string | Ctrl of string | Raw of string
    46   val decode: symbol -> sym
    47   datatype kind = Letter | Digit | Quasi | Blank | Other
    48   val kind: symbol -> kind
    49   val is_letter: symbol -> bool
    50   val is_digit: symbol -> bool
    51   val is_quasi: symbol -> bool
    52   val is_blank: symbol -> bool
    53   val is_quasi_letter: symbol -> bool
    54   val is_letdig: symbol -> bool
    55   val is_ident: symbol list -> bool
    56   val beginning: int -> symbol list -> string
    57   val scanner: string -> (string list -> 'a * string list) -> symbol list -> 'a
    58   val scan_id: string list -> string * string list
    59   val source: {do_recover: bool} -> (string, 'a) Source.source ->
    60     (symbol, (string, 'a) Source.source) Source.source
    61   val explode: string -> symbol list
    62   val escape: string -> string
    63   val strip_blanks: string -> string
    64   val bump_init: string -> string
    65   val bump_string: string -> string
    66   val length: symbol list -> int
    67   val xsymbolsN: string
    68   val output: string -> output * int
    69 end;
    70 
    71 structure Symbol: SYMBOL =
    72 struct
    73 
    74 (** type symbol **)
    75 
    76 (*Symbols, which are considered the smallest entities of any Isabelle
    77   string, may be of the following form:
    78 
    79     (1) ASCII symbols: a
    80     (2) regular symbols: \<ident>
    81     (3) control symbols: \<^ident>
    82     (4) raw control symbols: \<^raw:...>, where "..." may be any printable
    83         character (excluding ".", ">"), or \<^raw000>
    84 
    85   Output is subject to the print_mode variable (default: verbatim),
    86   actual interpretation in display is up to front-end tools.
    87 *)
    88 
    89 type symbol = string;
    90 
    91 val SOH = chr 1;
    92 val STX = chr 2;
    93 val ENQ = chr 5;
    94 val ACK = chr 6;
    95 val DEL = chr 127;
    96 
    97 val space = chr 32;
    98 
    99 local
   100   val small_spaces = Vector.tabulate (65, fn i => Library.replicate_string i space);
   101 in
   102   fun spaces k =
   103     if k < 64 then Vector.sub (small_spaces, k)
   104     else Library.replicate_string (k div 64) (Vector.sub (small_spaces, 64)) ^
   105       Vector.sub (small_spaces, k mod 64);
   106 end;
   107 
   108 fun is_char s = size s = 1;
   109 
   110 fun is_symbolic s =
   111   String.isPrefix "\\<" s andalso not (String.isPrefix "\\<^" s);
   112 
   113 fun is_printable s =
   114   if is_char s then ord space <= ord s andalso ord s <= ord "~"
   115   else not (String.isPrefix "\\<^" s);
   116 
   117 fun is_utf8_trailer s = is_char s andalso 128 <= ord s andalso ord s < 192;
   118 
   119 
   120 (* input source control *)
   121 
   122 val eof = "";
   123 fun is_eof s = s = eof;
   124 fun not_eof s = s <> eof;
   125 val stopper = Scan.stopper (K eof) is_eof;
   126 
   127 val sync = "\\<^sync>";
   128 fun is_sync s = s = sync;
   129 
   130 val malformed = "[[";
   131 val end_malformed = "]]";
   132 
   133 val separate_chars = explode #> space_implode space;
   134 fun malformed_msg s = "Malformed symbolic character: " ^ quote (separate_chars s);
   135 
   136 fun is_regular s =
   137   not_eof s andalso s <> sync andalso s <> malformed andalso s <> end_malformed;
   138 
   139 fun name_of s = if is_symbolic s
   140   then (unsuffix ">" o unprefix "\\<") s
   141   else error (malformed_msg s);
   142 
   143 
   144 (* ascii symbols *)
   145 
   146 fun is_ascii s = is_char s andalso ord s < 128;
   147 
   148 fun is_ascii_letter s =
   149   is_char s andalso
   150    (ord "A" <= ord s andalso ord s <= ord "Z" orelse
   151     ord "a" <= ord s andalso ord s <= ord "z");
   152 
   153 fun is_ascii_digit s =
   154   is_char s andalso ord "0" <= ord s andalso ord s <= ord "9";
   155 
   156 fun is_ascii_hex s =
   157   is_char s andalso
   158    (ord "0" <= ord s andalso ord s <= ord "9" orelse
   159     ord "A" <= ord s andalso ord s <= ord "F" orelse
   160     ord "a" <= ord s andalso ord s <= ord "f");
   161 
   162 fun is_ascii_quasi "_" = true
   163   | is_ascii_quasi "'" = true
   164   | is_ascii_quasi _ = false;
   165 
   166 val is_ascii_blank =
   167   fn " " => true | "\t" => true | "\n" => true | "\^K" => true | "\^L" => true | "\^M" => true
   168     | _ => false;
   169 
   170 fun is_ascii_lower s = is_char s andalso (ord "a" <= ord s andalso ord s <= ord "z");
   171 fun is_ascii_upper s = is_char s andalso (ord "A" <= ord s andalso ord s <= ord "Z");
   172 
   173 fun to_ascii_lower s = if is_ascii_upper s then chr (ord s + ord "a" - ord "A") else s;
   174 fun to_ascii_upper s = if is_ascii_lower s then chr (ord s + ord "A" - ord "a") else s;
   175 
   176 
   177 (* encode_raw *)
   178 
   179 fun raw_chr c =
   180   ord space <= ord c andalso ord c <= ord "~" andalso c <> "." andalso c <> ">"
   181   orelse ord c >= 128;
   182 
   183 fun encode_raw "" = ""
   184   | encode_raw str =
   185       let
   186         val raw0 = enclose "\\<^raw:" ">";
   187         val raw1 = raw0 o implode;
   188         val raw2 = enclose "\\<^raw" ">" o string_of_int o ord;
   189     
   190         fun encode cs = enc (Library.take_prefix raw_chr cs)
   191         and enc ([], []) = []
   192           | enc (cs, []) = [raw1 cs]
   193           | enc ([], d :: ds) = raw2 d :: encode ds
   194           | enc (cs, d :: ds) = raw1 cs :: raw2 d :: encode ds;
   195       in
   196         if exists_string (not o raw_chr) str then implode (encode (explode str))
   197         else raw0 str
   198       end;
   199 
   200 
   201 (* diagnostics *)
   202 
   203 fun beginning n cs =
   204   let
   205     val drop_blanks = #1 o Library.take_suffix is_ascii_blank;
   206     val all_cs = drop_blanks cs;
   207     val dots = if length all_cs > n then " ..." else "";
   208   in
   209     (drop_blanks (Library.take (n, all_cs))
   210       |> map (fn c => if is_ascii_blank c then space else c)
   211       |> implode) ^ dots
   212   end;
   213 
   214 
   215 (* decode_raw *)
   216 
   217 fun is_raw s =
   218   String.isPrefix "\\<^raw" s andalso String.isSuffix ">" s;
   219 
   220 fun decode_raw s =
   221   if not (is_raw s) then error (malformed_msg s)
   222   else if String.isPrefix "\\<^raw:" s then String.substring (s, 7, size s - 8)
   223   else chr (#1 (Library.read_int (explode (String.substring (s, 6, size s - 7)))));
   224 
   225 
   226 (* symbol variants *)
   227 
   228 datatype sym = Char of string | Sym of string | Ctrl of string | Raw of string;
   229 
   230 fun decode s =
   231   if is_char s then Char s
   232   else if is_raw s then Raw (decode_raw s)
   233   else if String.isPrefix "\\<^" s then Ctrl (String.substring (s, 3, size s - 4))
   234   else if String.isPrefix "\\<" s then Sym (String.substring (s, 2, size s - 3))
   235   else error (malformed_msg s);
   236 
   237 
   238 (* standard symbol kinds *)
   239 
   240 datatype kind = Letter | Digit | Quasi | Blank | Other;
   241 
   242 local
   243   val symbol_kinds = Symtab.make
   244    [("\\<A>", Letter),
   245     ("\\<B>", Letter),
   246     ("\\<C>", Letter),
   247     ("\\<D>", Letter),
   248     ("\\<E>", Letter),
   249     ("\\<F>", Letter),
   250     ("\\<G>", Letter),
   251     ("\\<H>", Letter),
   252     ("\\<I>", Letter),
   253     ("\\<J>", Letter),
   254     ("\\<K>", Letter),
   255     ("\\<L>", Letter),
   256     ("\\<M>", Letter),
   257     ("\\<N>", Letter),
   258     ("\\<O>", Letter),
   259     ("\\<P>", Letter),
   260     ("\\<Q>", Letter),
   261     ("\\<R>", Letter),
   262     ("\\<S>", Letter),
   263     ("\\<T>", Letter),
   264     ("\\<U>", Letter),
   265     ("\\<V>", Letter),
   266     ("\\<W>", Letter),
   267     ("\\<X>", Letter),
   268     ("\\<Y>", Letter),
   269     ("\\<Z>", Letter),
   270     ("\\<a>", Letter),
   271     ("\\<b>", Letter),
   272     ("\\<c>", Letter),
   273     ("\\<d>", Letter),
   274     ("\\<e>", Letter),
   275     ("\\<f>", Letter),
   276     ("\\<g>", Letter),
   277     ("\\<h>", Letter),
   278     ("\\<i>", Letter),
   279     ("\\<j>", Letter),
   280     ("\\<k>", Letter),
   281     ("\\<l>", Letter),
   282     ("\\<m>", Letter),
   283     ("\\<n>", Letter),
   284     ("\\<o>", Letter),
   285     ("\\<p>", Letter),
   286     ("\\<q>", Letter),
   287     ("\\<r>", Letter),
   288     ("\\<s>", Letter),
   289     ("\\<t>", Letter),
   290     ("\\<u>", Letter),
   291     ("\\<v>", Letter),
   292     ("\\<w>", Letter),
   293     ("\\<x>", Letter),
   294     ("\\<y>", Letter),
   295     ("\\<z>", Letter),
   296     ("\\<AA>", Letter),
   297     ("\\<BB>", Letter),
   298     ("\\<CC>", Letter),
   299     ("\\<DD>", Letter),
   300     ("\\<EE>", Letter),
   301     ("\\<FF>", Letter),
   302     ("\\<GG>", Letter),
   303     ("\\<HH>", Letter),
   304     ("\\<II>", Letter),
   305     ("\\<JJ>", Letter),
   306     ("\\<KK>", Letter),
   307     ("\\<LL>", Letter),
   308     ("\\<MM>", Letter),
   309     ("\\<NN>", Letter),
   310     ("\\<OO>", Letter),
   311     ("\\<PP>", Letter),
   312     ("\\<QQ>", Letter),
   313     ("\\<RR>", Letter),
   314     ("\\<SS>", Letter),
   315     ("\\<TT>", Letter),
   316     ("\\<UU>", Letter),
   317     ("\\<VV>", Letter),
   318     ("\\<WW>", Letter),
   319     ("\\<XX>", Letter),
   320     ("\\<YY>", Letter),
   321     ("\\<ZZ>", Letter),
   322     ("\\<aa>", Letter),
   323     ("\\<bb>", Letter),
   324     ("\\<cc>", Letter),
   325     ("\\<dd>", Letter),
   326     ("\\<ee>", Letter),
   327     ("\\<ff>", Letter),
   328     ("\\<gg>", Letter),
   329     ("\\<hh>", Letter),
   330     ("\\<ii>", Letter),
   331     ("\\<jj>", Letter),
   332     ("\\<kk>", Letter),
   333     ("\\<ll>", Letter),
   334     ("\\<mm>", Letter),
   335     ("\\<nn>", Letter),
   336     ("\\<oo>", Letter),
   337     ("\\<pp>", Letter),
   338     ("\\<qq>", Letter),
   339     ("\\<rr>", Letter),
   340     ("\\<ss>", Letter),
   341     ("\\<tt>", Letter),
   342     ("\\<uu>", Letter),
   343     ("\\<vv>", Letter),
   344     ("\\<ww>", Letter),
   345     ("\\<xx>", Letter),
   346     ("\\<yy>", Letter),
   347     ("\\<zz>", Letter),
   348     ("\\<alpha>", Letter),
   349     ("\\<beta>", Letter),
   350     ("\\<gamma>", Letter),
   351     ("\\<delta>", Letter),
   352     ("\\<epsilon>", Letter),
   353     ("\\<zeta>", Letter),
   354     ("\\<eta>", Letter),
   355     ("\\<theta>", Letter),
   356     ("\\<iota>", Letter),
   357     ("\\<kappa>", Letter),
   358     ("\\<lambda>", Other),      (*sic!*)
   359     ("\\<mu>", Letter),
   360     ("\\<nu>", Letter),
   361     ("\\<xi>", Letter),
   362     ("\\<pi>", Letter),
   363     ("\\<rho>", Letter),
   364     ("\\<sigma>", Letter),
   365     ("\\<tau>", Letter),
   366     ("\\<upsilon>", Letter),
   367     ("\\<phi>", Letter),
   368     ("\\<chi>", Letter),
   369     ("\\<psi>", Letter),
   370     ("\\<omega>", Letter),
   371     ("\\<Gamma>", Letter),
   372     ("\\<Delta>", Letter),
   373     ("\\<Theta>", Letter),
   374     ("\\<Lambda>", Letter),
   375     ("\\<Xi>", Letter),
   376     ("\\<Pi>", Letter),
   377     ("\\<Sigma>", Letter),
   378     ("\\<Upsilon>", Letter),
   379     ("\\<Phi>", Letter),
   380     ("\\<Psi>", Letter),
   381     ("\\<Omega>", Letter),
   382     ("\\<^isub>", Letter),
   383     ("\\<^isup>", Letter),
   384     ("\\<spacespace>", Blank)];
   385 in
   386   fun kind s =
   387     if is_ascii_letter s then Letter
   388     else if is_ascii_digit s then Digit
   389     else if is_ascii_quasi s then Quasi
   390     else if is_ascii_blank s then Blank
   391     else if is_char s then Other
   392     else the_default Other (Symtab.lookup symbol_kinds s);
   393 end;
   394 
   395 fun is_letter s = kind s = Letter;
   396 fun is_digit s = kind s = Digit;
   397 fun is_quasi s = kind s = Quasi;
   398 fun is_blank s = kind s = Blank;
   399 
   400 fun is_quasi_letter s = let val k = kind s in k = Letter orelse k = Quasi end;
   401 fun is_letdig s = let val k = kind s in k = Letter orelse k = Digit orelse k = Quasi end;
   402 
   403 fun is_ident [] = false
   404   | is_ident (c :: cs) = is_letter c andalso forall is_letdig cs;
   405 
   406 
   407 
   408 (** symbol input **)
   409 
   410 (* scanning through symbols *)
   411 
   412 fun scanner msg scan chs =
   413   let
   414     fun message (cs, NONE) = msg ^ ": " ^ quote (beginning 10 cs)
   415       | message (cs, SOME msg') = msg ^ ", " ^ msg' ^ ": " ^ quote (beginning 10 cs);
   416     val fin_scan = Scan.error (Scan.finite stopper (!! message scan));
   417   in
   418     (case fin_scan chs of
   419       (result, []) => result
   420     | (_, rest) => error (message (rest, NONE)))
   421   end;
   422 
   423 val scan_id = Scan.one is_letter ^^ (Scan.many is_letdig >> implode);
   424 
   425 
   426 (* source *)
   427 
   428 local
   429 
   430 fun is_plain s = s <> "\^M" andalso s <> "\\" andalso not_eof s;
   431 
   432 val scan_encoded_newline =
   433   $$ "\^M" -- $$ "\n" >> K "\n" ||
   434   $$ "\^M" >> K "\n" ||
   435   $$ "\\" -- Scan.optional ($$ "\\") "" -- Scan.this_string "<^newline>" >> K "\n";
   436 
   437 val scan_raw =
   438   Scan.this_string "raw:" ^^ (Scan.many raw_chr >> implode) ||
   439   Scan.this_string "raw" ^^ (Scan.many1 is_ascii_digit >> implode);
   440 
   441 val scan =
   442   Scan.one is_plain ||
   443   scan_encoded_newline ||
   444   (($$ "\\" --| Scan.optional ($$ "\\") "") ^^ $$ "<" ^^
   445     !! (fn (cs, _) => malformed_msg (beginning 10 ("\\" :: "<" :: cs)))
   446       (($$ "^" ^^ (scan_raw || scan_id) || scan_id) ^^ $$ ">")) ||
   447   Scan.one not_eof;
   448 
   449 val scan_resync =
   450   Scan.one is_ascii_blank || $$ "\"" || $$ "`" || $$ "\\" ||
   451   Scan.this_string "(*" || Scan.this_string "*)" ||
   452   Scan.this_string "{*" || Scan.this_string "*}";
   453 
   454 val recover =
   455   (Scan.this (explode "\\\\<") || Scan.this (explode "\\<")) @@@
   456     Scan.repeat (Scan.unless scan_resync (Scan.one not_eof))
   457   >> (fn ss => malformed :: ss @ [end_malformed]);
   458 
   459 in
   460 
   461 fun source {do_recover} src =
   462   Source.source stopper (Scan.bulk scan)
   463     (if do_recover then SOME (false, K recover) else NONE) src;
   464 
   465 end;
   466 
   467 
   468 (* explode *)
   469 
   470 local
   471 
   472 fun no_explode [] = true
   473   | no_explode ("\\" :: "<" :: _) = false
   474   | no_explode ("\^M" :: _) = false
   475   | no_explode (_ :: cs) = no_explode cs;
   476 
   477 in
   478 
   479 fun sym_explode str =
   480   let val chs = explode str in
   481     if no_explode chs then chs
   482     else Source.exhaust (source {do_recover = false} (Source.of_list chs))
   483   end;
   484 
   485 end;
   486 
   487 
   488 (* escape *)
   489 
   490 val escape = implode o map (fn s => if is_char s then s else "\\" ^ s) o sym_explode;
   491 
   492 
   493 (* blanks *)
   494 
   495 fun strip_blanks s =
   496   sym_explode s
   497   |> Library.take_prefix is_blank |> #2
   498   |> Library.take_suffix is_blank |> #1
   499   |> implode;
   500 
   501 
   502 (* bump string -- treat as base 26 or base 1 numbers *)
   503 
   504 fun symbolic_end (_ :: "\\<^isub>" :: _) = true
   505   | symbolic_end (_ :: "\\<^isup>" :: _) = true
   506   | symbolic_end (s :: _) = is_symbolic s
   507   | symbolic_end [] = false;
   508 
   509 fun bump_init str =
   510   if symbolic_end (rev (sym_explode str)) then str ^ "'"
   511   else str ^ "a";
   512 
   513 fun bump_string str =
   514   let
   515     fun bump [] = ["a"]
   516       | bump ("z" :: ss) = "a" :: bump ss
   517       | bump (s :: ss) =
   518           if is_char s andalso ord "a" <= ord s andalso ord s < ord "z"
   519           then chr (ord s + 1) :: ss
   520           else "a" :: s :: ss;
   521 
   522     val (ss, qs) = apfst rev (Library.take_suffix is_quasi (sym_explode str));
   523     val ss' = if symbolic_end ss then "'" :: ss else bump ss;
   524   in implode (rev ss' @ qs) end;
   525 
   526 
   527 
   528 (** symbol output **)
   529 
   530 (* length *)
   531 
   532 fun sym_len s =
   533   if not (is_printable s) then (0: int)
   534   else if String.isPrefix "\\<long" s then 2
   535   else if String.isPrefix "\\<Long" s then 2
   536   else if s = "\\<spacespace>" then 2
   537   else 1;
   538 
   539 fun sym_length ss = fold (fn s => fn n => sym_len s + n) ss 0;
   540 
   541 
   542 (* print mode *)
   543 
   544 val xsymbolsN = "xsymbols";
   545 
   546 fun output s = (s, sym_length (sym_explode s));
   547 
   548 
   549 (*final declarations of this structure!*)
   550 val explode = sym_explode;
   551 val length = sym_length;
   552 
   553 end;