src/Pure/General/symbol.ML
changeset 6272 52d99d68d3be
parent 6225 f453bd781dfd
child 6320 4df282137880
equal deleted inserted replaced
6271:957d8aa4a06b 6272:52d99d68d3be
    18   val is_digit: symbol -> bool
    18   val is_digit: symbol -> bool
    19   val is_quasi_letter: symbol -> bool
    19   val is_quasi_letter: symbol -> bool
    20   val is_letdig: symbol -> bool
    20   val is_letdig: symbol -> bool
    21   val is_blank: symbol -> bool
    21   val is_blank: symbol -> bool
    22   val is_printable: symbol -> bool
    22   val is_printable: symbol -> bool
       
    23   val length: symbol list -> int
    23   val beginning: symbol list -> string
    24   val beginning: symbol list -> string
    24   val scan: string list -> symbol * string list
    25   val scan: string list -> symbol * string list
    25   val explode: string -> symbol list
       
    26   val length: symbol list -> int
       
    27   val size: string -> int
       
    28   val input: string -> string
       
    29   val output: string -> string
       
    30   val source: bool -> (string, 'a) Source.source ->
    26   val source: bool -> (string, 'a) Source.source ->
    31     (symbol, (string, 'a) Source.source) Source.source
    27     (symbol, (string, 'a) Source.source) Source.source
       
    28   val explode: string -> symbol list
       
    29   val input: string -> string
    32   val use: Path.T -> unit
    30   val use: Path.T -> unit
       
    31   val add_mode: string -> (string -> string * real) -> unit
       
    32   val output: string -> string
       
    33   val output_width: string -> string * real
    33 end;
    34 end;
    34 
    35 
    35 structure Symbol: SYMBOL =
    36 structure Symbol: SYMBOL =
    36 struct
    37 struct
    37 
    38 
    38 
    39 
    39 (** encoding table (isabelle-0) **)
    40 (** generalized characters **)
       
    41 
       
    42 (*symbols, which are considered the smallest entities of any Isabelle
       
    43   string, may be of the following form:
       
    44     (a) ASCII symbols: a
       
    45     (b) printable symbols: \<ident>
       
    46     (c) control symbols: \<^ident>
       
    47 
       
    48   input may include non-ASCII characters according to isabelle-0 encoding;
       
    49   output is subject to the print_mode variable (default: verbatim);
       
    50 *)
       
    51 
       
    52 type symbol = string;
       
    53 
       
    54 val space = " ";
       
    55 val eof = "";
       
    56 
       
    57 
       
    58 (* kinds *)
       
    59 
       
    60 fun is_eof s = s = eof;
       
    61 fun not_eof s = s <> eof;
       
    62 val stopper = (eof, is_eof);
       
    63 
       
    64 fun is_ascii s = size s = 1 andalso ord s < 128;
       
    65 
       
    66 fun is_letter s =
       
    67   size s = 1 andalso
       
    68    (ord "A" <= ord s andalso ord s <= ord "Z" orelse
       
    69     ord "a" <= ord s andalso ord s <= ord "z");
       
    70 
       
    71 fun is_digit s =
       
    72   size s = 1 andalso ord "0" <= ord s andalso ord s <= ord "9";
       
    73 
       
    74 fun is_quasi_letter "_" = true
       
    75   | is_quasi_letter "'" = true
       
    76   | is_quasi_letter s = is_letter s;
       
    77 
       
    78 val is_blank =
       
    79   fn " " => true | "\t" => true | "\n" => true | "\^L" => true
       
    80     | "\160" => true | "\\<spacespace>" => true
       
    81     | _ => false;
       
    82 
       
    83 val is_letdig = is_quasi_letter orf is_digit;
       
    84 
       
    85 fun is_printable s =
       
    86   size s = 1 andalso ord space <= ord s andalso ord s <= ord "~" orelse
       
    87   size s > 2 andalso nth_elem (2, explode s) <> "^";
       
    88 
       
    89 fun sym_length ss = foldl (fn (n, s) => if is_printable s then n + 1 else n) (0, ss);
       
    90 
       
    91 
       
    92 (* beginning *)
       
    93 
       
    94 val smash_blanks = map (fn s => if is_blank s then space else s);
       
    95 
       
    96 fun beginning raw_ss =
       
    97   let
       
    98     val (all_ss, _) = take_suffix is_blank raw_ss;
       
    99     val dots = if length all_ss > 10 then " ..." else "";
       
   100     val (ss, _) = take_suffix is_blank (take (10, all_ss));
       
   101   in implode (smash_blanks ss) ^ dots end;
       
   102 
       
   103 
       
   104 
       
   105 (** isabelle-0 encoding table **)
    40 
   106 
    41 val enc_start = 160;
   107 val enc_start = 160;
    42 val enc_end = 255;
   108 val enc_end = 255;
    43 
   109 
    44 val enc_vector =
   110 val enc_vector =
   163     None => c
   229     None => c
   164   | Some s => "\\" ^ s);
   230   | Some s => "\\" ^ s);
   165 
   231 
   166 
   232 
   167 
   233 
   168 (** type symbol **)
   234 (** symbol input **)
   169 
       
   170 type symbol = string;
       
   171 
       
   172 val space = " ";
       
   173 val eof = "";
       
   174 
       
   175 
       
   176 (* kinds *)
       
   177 
       
   178 fun is_eof s = s = eof;
       
   179 fun not_eof s = s <> eof;
       
   180 val stopper = (eof, is_eof);
       
   181 
       
   182 fun is_ascii s = size s = 1 andalso ord s < 128;
       
   183 
       
   184 fun is_letter s =
       
   185   size s = 1 andalso
       
   186    (ord "A" <= ord s andalso ord s <= ord "Z" orelse
       
   187     ord "a" <= ord s andalso ord s <= ord "z");
       
   188 
       
   189 fun is_digit s =
       
   190   size s = 1 andalso ord "0" <= ord s andalso ord s <= ord "9";
       
   191 
       
   192 fun is_quasi_letter "_" = true
       
   193   | is_quasi_letter "'" = true
       
   194   | is_quasi_letter s = is_letter s;
       
   195 
       
   196 val is_blank =
       
   197   fn " " => true | "\t" => true | "\n" => true | "\^L" => true
       
   198     | "\160" => true | "\\<spacespace>" => true
       
   199     | _ => false;
       
   200 
       
   201 val is_letdig = is_quasi_letter orf is_digit;
       
   202 
       
   203 fun is_printable s =
       
   204   size s = 1 andalso ord space <= ord s andalso ord s <= ord "~" orelse
       
   205   size s > 2 andalso nth_elem (2, explode s) <> "^";
       
   206 
       
   207 
       
   208 (* beginning *)
       
   209 
       
   210 val smash_blanks = map (fn s => if is_blank s then space else s);
       
   211 
       
   212 fun beginning raw_ss =
       
   213   let
       
   214     val (all_ss, _) = take_suffix is_blank raw_ss;
       
   215     val dots = if length all_ss > 10 then " ..." else "";
       
   216     val (ss, _) = take_suffix is_blank (take (10, all_ss));
       
   217   in implode (smash_blanks ss) ^ dots end;
       
   218 
       
   219 
   235 
   220 (* scan *)
   236 (* scan *)
   221 
   237 
   222 val scan_id = Scan.one is_letter ^^ (Scan.any is_letdig >> implode);
   238 val scan_id = Scan.one is_letter ^^ (Scan.any is_letdig >> implode);
   223 
   239 
   247     if no_syms chs then chs     (*tune trivial case*)
   263     if no_syms chs then chs     (*tune trivial case*)
   248     else map symbol (the (Scan.read stopper (Scan.repeat scan) chs))
   264     else map symbol (the (Scan.read stopper (Scan.repeat scan) chs))
   249   end;
   265   end;
   250 
   266 
   251 
   267 
   252 (* printable length *)
   268 (* input *)
   253 
       
   254 fun sym_length ss = foldl (fn (n, c) => if is_printable c then n + 1 else n) (0, ss);
       
   255 val sym_size = sym_length o sym_explode;
       
   256 
       
   257 
       
   258 (* input / output *)
       
   259 
   269 
   260 fun input str =
   270 fun input str =
   261   let val chs = explode str in
   271   let val chs = explode str in
   262     if forall (fn c => ord c < enc_start) chs then str
   272     if forall (fn c => ord c < enc_start) chs then str
   263     else implode (map symbol' chs)
   273     else implode (map symbol' chs)
   264   end;
   274   end;
   265 
   275 
   266 fun char' s = if size s > 1 then "\\" ^ s else s;
       
   267 fun output s = let val chr = (* if "isabelle_font" mem_string !print_mode *)
       
   268 (* FIXME: does not work yet, because of static calls to output in printer.ML *)
       
   269 			     (* then *) char (* else char'*)
       
   270 		in (implode o map chr o sym_explode) s end;
       
   271 
       
   272 
   276 
   273 (* version of 'use' with input filtering *)
   277 (* version of 'use' with input filtering *)
   274 
   278 
   275 val use =
   279 val use =
   276   if not needs_filtered_use then File.use
   280   if not needs_filtered_use then File.use	(*ML system (wrongly!) accepts non-ASCII*)
   277   else
   281   else
   278     fn path =>
   282     fn path =>
   279       let
   283       let
   280         val txt = File.read path;
   284         val txt = File.read path;
   281         val txt_out = input txt;
   285         val txt_out = input txt;
   288             File.rm tmp_path
   292             File.rm tmp_path
   289           end
   293           end
   290       end;
   294       end;
   291 
   295 
   292 
   296 
       
   297 
       
   298 (** symbol output **)
       
   299 
       
   300 (* default_output *)
       
   301 
       
   302 fun string_size s = (s, real (size s));
       
   303 
       
   304 fun default_output s =
       
   305   let val cs = explode s in	(*sic!*)
       
   306     if not (exists (equal "\\") cs) then string_size s
       
   307     else string_size (implode (map (fn "\\" => "\\\\" | c => c) cs))
       
   308   end;
       
   309 
       
   310 
       
   311 (* isabelle_font_output *)
       
   312 
       
   313 fun isabelle_font_output s =
       
   314   let val cs = sym_explode s
       
   315   in (implode (map char cs), real (sym_length cs)) end;
       
   316 
       
   317 
       
   318 (* maintain modes *)
       
   319 
       
   320 val modes = ref (Symtab.make [("isabelle_font", isabelle_font_output)]);
       
   321 
       
   322 fun lookup_mode name = Symtab.lookup (! modes, name);
       
   323 
       
   324 fun add_mode name f =
       
   325  (if is_none (lookup_mode name) then ()
       
   326   else warning ("Duplicate declaration of symbol print mode " ^ quote name);
       
   327   modes := Symtab.update ((name, f), ! modes));
       
   328 
       
   329 
       
   330 (* mode output *)
       
   331 
       
   332 fun output_width s =
       
   333   (case get_first lookup_mode (! print_mode) of
       
   334     None => default_output s
       
   335   | Some f => f s);
       
   336 
       
   337 val output = #1 o output_width;
       
   338 
       
   339 
   293 (*final declarations of this structure!*)
   340 (*final declarations of this structure!*)
       
   341 val length = sym_length;
   294 val explode = sym_explode;
   342 val explode = sym_explode;
   295 val length = sym_length;
   343 
   296 val size = sym_size;
       
   297 
   344 
   298 end;
   345 end;