author | haftmann |
Sun, 06 May 2018 18:20:25 +0000 | |
changeset 68099 | 305f9f3edf05 |
parent 68028 | 1f9f973eed2a |
child 68939 | bcce5967e10e |
permissions | -rw-r--r-- |
21759 | 1 |
(* Title: HOL/Tools/string_syntax.ML |
2 |
Author: Makarius |
|
3 |
||
68028 | 4 |
Concrete syntax for characters and strings. |
21759 | 5 |
*) |
6 |
||
68028 | 7 |
signature STRING_SYNTAX = sig |
8 |
val hex: int -> string |
|
9 |
val mk_bits_syntax: int -> int -> term list |
|
10 |
val dest_bits_syntax: term list -> int |
|
11 |
val plain_strings_of: string -> string list |
|
12 |
datatype character = Char of string | Ord of int |
|
13 |
val classify_character: int -> character |
|
14 |
end |
|
15 |
||
16 |
structure String_Syntax: STRING_SYNTAX = |
|
21759 | 17 |
struct |
18 |
||
62597 | 19 |
(* numeral *) |
21759 | 20 |
|
62597 | 21 |
fun hex_digit n = if n = 10 then "A" |
22 |
else if n = 11 then "B" |
|
23 |
else if n = 12 then "C" |
|
24 |
else if n = 13 then "D" |
|
25 |
else if n = 14 then "E" |
|
26 |
else if n = 15 then "F" |
|
27 |
else string_of_int n; |
|
21759 | 28 |
|
62597 | 29 |
fun hex_prefix ms = "0x" ^ implode (replicate (2 - length ms) "0" @ ms); |
30 |
||
31 |
fun hex n = hex_prefix (map hex_digit (radixpand (16, n))); |
|
21759 | 32 |
|
33 |
||
68028 | 34 |
(* booleans as bits *) |
35 |
||
36 |
fun mk_bit_syntax b = |
|
37 |
Syntax.const (if b = 1 then @{const_syntax True} else @{const_syntax False}); |
|
38 |
||
39 |
fun mk_bits_syntax len = map mk_bit_syntax o Integer.radicify 2 len; |
|
40 |
||
41 |
fun dest_bit_syntax (Const (@{const_syntax True}, _)) = 1 |
|
42 |
| dest_bit_syntax (Const (@{const_syntax False}, _)) = 0 |
|
43 |
| dest_bit_syntax _ = raise Match; |
|
44 |
||
45 |
val dest_bits_syntax = Integer.eval_radix 2 o map dest_bit_syntax; |
|
46 |
||
47 |
||
21759 | 48 |
(* char *) |
49 |
||
68028 | 50 |
fun mk_char_syntax i = |
51 |
list_comb (Syntax.const @{const_syntax Char}, mk_bits_syntax 8 i); |
|
62597 | 52 |
|
53 |
fun mk_char_syntax' c = |
|
54 |
if Symbol.is_ascii c then mk_char_syntax (ord c) |
|
55 |
else if c = "\<newline>" then mk_char_syntax 10 |
|
56 |
else error ("Bad character: " ^ quote c); |
|
57 |
||
68028 | 58 |
fun plain_strings_of str = |
62597 | 59 |
map fst (Lexicon.explode_str (str, Position.none)); |
60 |
||
68028 | 61 |
datatype character = Char of string | Ord of int; |
21759 | 62 |
|
40627
becf5d5187cc
renamed raw "explode" function to "raw_explode" to emphasize its meaning;
wenzelm
parents:
35363
diff
changeset
|
63 |
val specials = raw_explode "\\\"`'"; |
21759 | 64 |
|
68028 | 65 |
fun classify_character i = |
66 |
let |
|
67 |
val c = chr i |
|
68 |
in |
|
69 |
if not (member (op =) specials c) andalso Symbol.is_ascii c andalso Symbol.is_printable c |
|
70 |
then Char c |
|
71 |
else if c = "\n" |
|
72 |
then Char "\<newline>" |
|
73 |
else Ord i |
|
74 |
end; |
|
75 |
||
76 |
fun dest_char_syntax b0 b1 b2 b3 b4 b5 b6 b7 = |
|
77 |
classify_character (dest_bits_syntax [b0, b1, b2, b3, b4, b5, b6, b7]) |
|
21759 | 78 |
|
62597 | 79 |
fun dest_char_ast (Ast.Appl [Ast.Constant @{syntax_const "_Char"}, Ast.Constant s]) = |
68028 | 80 |
plain_strings_of s |
62597 | 81 |
| dest_char_ast _ = raise Match; |
21759 | 82 |
|
62597 | 83 |
fun char_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] = |
84 |
c $ char_tr [t] $ u |
|
85 |
| char_tr [Free (str, _)] = |
|
68028 | 86 |
(case plain_strings_of str of |
62597 | 87 |
[c] => mk_char_syntax' c |
88 |
| _ => error ("Single character expected: " ^ str)) |
|
89 |
| char_tr ts = raise TERM ("char_tr", ts); |
|
21759 | 90 |
|
62597 | 91 |
fun char_ord_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] = |
92 |
c $ char_ord_tr [t] $ u |
|
93 |
| char_ord_tr [Const (num, _)] = |
|
94 |
(mk_char_syntax o #value o Lexicon.read_num) num |
|
95 |
| char_ord_tr ts = raise TERM ("char_ord_tr", ts); |
|
21759 | 96 |
|
68028 | 97 |
fun char_tr' [b1, b2, b3, b4, b5, b6, b7, b8] = |
98 |
(case dest_char_syntax b1 b2 b3 b4 b5 b6 b7 b8 of |
|
62597 | 99 |
Char s => Syntax.const @{syntax_const "_Char"} $ |
100 |
Syntax.const (Lexicon.implode_str [s]) |
|
68028 | 101 |
| Ord n => Syntax.const @{syntax_const "_Char_ord"} $ |
102 |
Syntax.free (hex n)) |
|
62597 | 103 |
| char_tr' _ = raise Match; |
21759 | 104 |
|
105 |
||
106 |
(* string *) |
|
107 |
||
62597 | 108 |
fun mk_string_syntax [] = Syntax.const @{const_syntax Nil} |
109 |
| mk_string_syntax (c :: cs) = |
|
110 |
Syntax.const @{const_syntax Cons} $ mk_char_syntax' c $ mk_string_syntax cs; |
|
21759 | 111 |
|
62597 | 112 |
fun mk_string_ast ss = |
113 |
Ast.Appl [Ast.Constant @{syntax_const "_inner_string"}, |
|
114 |
Ast.Variable (Lexicon.implode_str ss)]; |
|
115 |
||
116 |
fun string_tr [(c as Const (@{syntax_const "_constrain"}, _)) $ t $ u] = |
|
117 |
c $ string_tr [t] $ u |
|
118 |
| string_tr [Free (str, _)] = |
|
68028 | 119 |
mk_string_syntax (plain_strings_of str) |
68099 | 120 |
| string_tr ts = raise TERM ("string_tr", ts); |
21759 | 121 |
|
35115 | 122 |
fun list_ast_tr' [args] = |
42224
578a51fae383
discontinued special treatment of structure Ast: no pervasive content, no inclusion in structure Syntax;
wenzelm
parents:
40627
diff
changeset
|
123 |
Ast.Appl [Ast.Constant @{syntax_const "_String"}, |
62597 | 124 |
(mk_string_ast o maps dest_char_ast o Ast.unfold_ast @{syntax_const "_args"}) args] |
51160
599ff65b85e2
systematic conversions between nat and nibble/char;
haftmann
parents:
46483
diff
changeset
|
125 |
| list_ast_tr' _ = raise Match; |
21759 | 126 |
|
127 |
||
128 |
(* theory setup *) |
|
129 |
||
58822 | 130 |
val _ = |
131 |
Theory.setup |
|
62597 | 132 |
(Sign.parse_translation |
133 |
[(@{syntax_const "_Char"}, K char_tr), |
|
134 |
(@{syntax_const "_Char_ord"}, K char_ord_tr), |
|
135 |
(@{syntax_const "_String"}, K string_tr)] #> |
|
136 |
Sign.print_translation |
|
137 |
[(@{const_syntax Char}, K char_tr')] #> |
|
58822 | 138 |
Sign.print_ast_translation |
62597 | 139 |
[(@{syntax_const "_list"}, K list_ast_tr')]); |
21759 | 140 |
|
68028 | 141 |
end |