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; |