src/HOL/Tools/string_syntax.ML
changeset 62597 b3f2b8c906a6
parent 58822 90a5e981af3e
child 68028 1f9f973eed2a
equal deleted inserted replaced
62596:cf79f8866bc3 62597:b3f2b8c906a6
     1 (*  Title:      HOL/Tools/string_syntax.ML
     1 (*  Title:      HOL/Tools/string_syntax.ML
     2     Author:     Makarius
     2     Author:     Makarius
     3 
     3 
     4 Concrete syntax for hex chars and strings.
     4 Concrete syntax for chars and strings.
     5 *)
     5 *)
     6 
     6 
     7 structure String_Syntax: sig end =
     7 structure String_Syntax: sig end =
     8 struct
     8 struct
     9 
     9 
    10 (* nibble *)
    10 (* numeral *)
    11 
    11 
    12 val mk_nib =
    12 fun hex_digit n = if n = 10 then "A"
    13   Ast.Constant o Lexicon.mark_const o
    13   else if n = 11 then "B"
    14     fst o Term.dest_Const o HOLogic.mk_nibble;
    14   else if n = 12 then "C"
       
    15   else if n = 13 then "D"
       
    16   else if n = 14 then "E"
       
    17   else if n = 15 then "F"
       
    18   else string_of_int n;
    15 
    19 
    16 fun dest_nib (Ast.Constant s) =
    20 fun hex_prefix ms = "0x" ^ implode (replicate (2 - length ms) "0" @ ms);
    17   (case try Lexicon.unmark_const s of
    21 
    18     NONE => raise Match
    22 fun hex n = hex_prefix (map hex_digit (radixpand (16, n)));
    19   | SOME c => (HOLogic.dest_nibble (Const (c, HOLogic.nibbleT)) handle TERM _ => raise Match));
       
    20 
    23 
    21 
    24 
    22 (* char *)
    25 (* char *)
    23 
    26 
    24 fun mk_char s =
    27 fun mk_char_syntax n =
    25   let
    28   if n = 0 then Syntax.const @{const_name Groups.zero}
    26     val c =
    29   else Syntax.const @{const_syntax Char} $ Numeral.mk_num_syntax n;
    27       if Symbol.is_ascii s then ord s
    30 
    28       else if s = "\<newline>" then 10
    31 fun mk_char_syntax' c =
    29       else error ("Bad character: " ^ quote s);
    32   if Symbol.is_ascii c then mk_char_syntax (ord c)
    30   in Ast.Appl [Ast.Constant @{const_syntax Char}, mk_nib (c div 16), mk_nib (c mod 16)] end;
    33   else if c = "\<newline>" then mk_char_syntax 10
       
    34   else error ("Bad character: " ^ quote c);
       
    35 
       
    36 fun plain_string_of str =
       
    37   map fst (Lexicon.explode_str (str, Position.none));
       
    38 
       
    39 datatype character = Char of string | Ord of int | Unprintable;
    31 
    40 
    32 val specials = raw_explode "\\\"`'";
    41 val specials = raw_explode "\\\"`'";
    33 
    42 
    34 fun dest_chr c1 c2 =
    43 fun dest_char_syntax c =
    35   let val s = chr (dest_nib c1 * 16 + dest_nib c2) in
    44   case try Numeral.dest_num_syntax c of
    36     if not (member (op =) specials s) andalso Symbol.is_ascii s andalso Symbol.is_printable s
    45     SOME n =>
    37     then s
    46       if n < 256 then
    38     else if s = "\n" then "\<newline>"
    47         let
    39     else raise Match
    48           val s = chr n
    40   end;
    49         in
       
    50           if not (member (op =) specials s) andalso Symbol.is_ascii s andalso Symbol.is_printable s
       
    51           then Char s
       
    52           else if s = "\n" then Char "\<newline>"
       
    53           else Ord n
       
    54         end
       
    55       else Unprintable
       
    56   | NONE => Unprintable;
    41 
    57 
    42 fun dest_char (Ast.Appl [Ast.Constant @{const_syntax Char}, c1, c2]) = dest_chr c1 c2
    58 fun dest_char_ast (Ast.Appl [Ast.Constant @{syntax_const "_Char"}, Ast.Constant s]) =
    43   | dest_char _ = raise Match;
    59       plain_string_of s
       
    60   | dest_char_ast _ = raise Match;
    44 
    61 
    45 fun syntax_string ss =
    62 fun char_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] =
    46   Ast.Appl [Ast.Constant @{syntax_const "_inner_string"},
    63       c $ char_tr [t] $ u
    47     Ast.Variable (Lexicon.implode_str ss)];
    64   | char_tr [Free (str, _)] =
       
    65       (case plain_string_of str of
       
    66         [c] => mk_char_syntax' c
       
    67       | _ => error ("Single character expected: " ^ str))
       
    68   | char_tr ts = raise TERM ("char_tr", ts);
    48 
    69 
       
    70 fun char_ord_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] =
       
    71       c $ char_ord_tr [t] $ u
       
    72   | char_ord_tr [Const (num, _)] =
       
    73       (mk_char_syntax o #value o Lexicon.read_num) num
       
    74   | char_ord_tr ts = raise TERM ("char_ord_tr", ts);
    49 
    75 
    50 fun char_ast_tr [Ast.Variable str] =
    76 fun char_tr' [t] = (case dest_char_syntax t of
    51       (case Lexicon.explode_str (str, Position.none) of
    77         Char s => Syntax.const @{syntax_const "_Char"} $
    52         [(s, _)] => mk_char s
    78           Syntax.const (Lexicon.implode_str [s])
    53       | _ => error ("Single character expected: " ^ str))
    79       | Ord n => 
    54   | char_ast_tr [Ast.Appl [Ast.Constant @{syntax_const "_constrain"}, ast1, ast2]] =
    80           if n = 0
    55       Ast.Appl [Ast.Constant @{syntax_const "_constrain"}, char_ast_tr [ast1], ast2]
    81           then Syntax.const @{const_syntax Groups.zero}
    56   | char_ast_tr asts = raise Ast.AST ("char_ast_tr", asts);
    82           else Syntax.const @{syntax_const "_Char_ord"} $
    57 
    83             Syntax.free (hex n)
    58 fun char_ast_tr' [c1, c2] =
    84       | _ => raise Match)
    59       Ast.Appl [Ast.Constant @{syntax_const "_Char"}, syntax_string [dest_chr c1 c2]]
    85   | char_tr' _ = raise Match;
    60   | char_ast_tr' _ = raise Match;
       
    61 
    86 
    62 
    87 
    63 (* string *)
    88 (* string *)
    64 
    89 
    65 fun mk_string [] = Ast.Constant @{const_syntax Nil}
    90 fun mk_string_syntax [] = Syntax.const @{const_syntax Nil}
    66   | mk_string (s :: ss) =
    91   | mk_string_syntax (c :: cs) =
    67       Ast.Appl [Ast.Constant @{const_syntax Cons}, mk_char s, mk_string ss];
    92       Syntax.const @{const_syntax Cons} $ mk_char_syntax' c $ mk_string_syntax cs;
    68 
    93 
    69 fun string_ast_tr [Ast.Variable str] =
    94 fun mk_string_ast ss =
    70       (case Lexicon.explode_str (str, Position.none) of
    95   Ast.Appl [Ast.Constant @{syntax_const "_inner_string"},
    71         [] =>
    96     Ast.Variable (Lexicon.implode_str ss)];
    72           Ast.Appl
    97 
    73             [Ast.Constant @{syntax_const "_constrain"},
    98 fun string_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] =
    74               Ast.Constant @{const_syntax Nil}, Ast.Constant @{type_syntax string}]
    99       c $ string_tr [t] $ u
    75       | ss => mk_string (map Symbol_Pos.symbol ss))
   100   | string_tr [Free (str, _)] =
    76   | string_ast_tr [Ast.Appl [Ast.Constant @{syntax_const "_constrain"}, ast1, ast2]] =
   101       mk_string_syntax (plain_string_of str)
    77       Ast.Appl [Ast.Constant @{syntax_const "_constrain"}, string_ast_tr [ast1], ast2]
   102   | string_tr ts = raise TERM ("char_tr", ts);
    78   | string_ast_tr asts = raise Ast.AST ("string_tr", asts);
       
    79 
   103 
    80 fun list_ast_tr' [args] =
   104 fun list_ast_tr' [args] =
    81       Ast.Appl [Ast.Constant @{syntax_const "_String"},
   105       Ast.Appl [Ast.Constant @{syntax_const "_String"},
    82         syntax_string (map dest_char (Ast.unfold_ast @{syntax_const "_args"} args))]
   106         (mk_string_ast o maps dest_char_ast o Ast.unfold_ast @{syntax_const "_args"}) args]
    83   | list_ast_tr' _ = raise Match;
   107   | list_ast_tr' _ = raise Match;
    84 
   108 
    85 
   109 
    86 (* theory setup *)
   110 (* theory setup *)
    87 
   111 
    88 val _ =
   112 val _ =
    89   Theory.setup
   113   Theory.setup
    90    (Sign.parse_ast_translation
   114    (Sign.parse_translation
    91      [(@{syntax_const "_Char"}, K char_ast_tr),
   115      [(@{syntax_const "_Char"}, K char_tr),
    92       (@{syntax_const "_String"}, K string_ast_tr)] #>
   116       (@{syntax_const "_Char_ord"}, K char_ord_tr),
       
   117       (@{syntax_const "_String"}, K string_tr)] #>
       
   118     Sign.print_translation
       
   119      [(@{const_syntax Char}, K char_tr')] #>
    93     Sign.print_ast_translation
   120     Sign.print_ast_translation
    94      [(@{const_syntax Char}, K char_ast_tr'),
   121      [(@{syntax_const "_list"}, K list_ast_tr')]);
    95       (@{syntax_const "_list"}, K list_ast_tr')]);
       
    96 
   122 
    97 end;
   123 end;