Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2017 Matthew Fluet. |
2 | * Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * Copyright (C) 1997-2000 NEC Research Institute. | |
5 | * | |
6 | * MLton is released under a BSD-style license. | |
7 | * See the file MLton-LICENSE for details. | |
8 | *) | |
9 | ||
10 | structure UniqueString: | |
11 | sig | |
12 | val unique: string -> string | |
13 | end = | |
14 | struct | |
15 | val set: {counter: Counter.t, | |
16 | hash: word, | |
17 | original: string} HashSet.t = | |
18 | HashSet.new {hash = #hash} | |
19 | ||
20 | fun unique (s: string): string = | |
21 | let | |
22 | val hash = String.hash s | |
23 | val {counter, ...} = | |
24 | HashSet.lookupOrInsert | |
25 | (set, hash, fn {original, ...} => s = original, | |
26 | fn () => {counter = Counter.new 0, | |
27 | hash = hash, | |
28 | original = s}) | |
29 | in | |
30 | concat [s, "_", Int.toString (Counter.next counter)] | |
31 | end | |
32 | end | |
33 | ||
34 | functor Id (S: ID_STRUCTS): ID = | |
35 | struct | |
36 | ||
37 | open S | |
38 | ||
39 | structure Plist = PropertyList | |
40 | ||
41 | datatype t = T of {hash: word, | |
42 | originalName: string, | |
43 | printName: string option ref, | |
44 | plist: Plist.t} | |
45 | ||
46 | local | |
47 | fun make f (T r) = f r | |
48 | in | |
49 | val hash = make #hash | |
50 | val originalName = make #originalName | |
51 | val plist = make #plist | |
52 | end | |
53 | ||
54 | fun isAlphaNum (s: string): bool = | |
55 | String.forall (s, fn c => Char.isAlphaNum c orelse c = #"_") | |
56 | ||
57 | fun clearPrintName (T {originalName, printName, ...}): unit = | |
58 | if isAlphaNum originalName | |
59 | then () | |
60 | else printName := NONE | |
61 | ||
62 | val printNameAlphaNumeric: bool ref = ref false | |
63 | ||
64 | fun toString (T {originalName, printName, ...}) = | |
65 | case !printName of | |
66 | NONE => | |
67 | let | |
68 | val s = | |
69 | if not (!printNameAlphaNumeric) | |
70 | orelse isAlphaNum originalName | |
71 | then originalName | |
72 | else | |
73 | String.translate | |
74 | (originalName, | |
75 | fn #"!" => "Bang" | |
76 | | #"#" => "Hash" | |
77 | | #"$" => "Dollar" | |
78 | | #"%" => "Percent" | |
79 | | #"&" => "Ampersand" | |
80 | | #"'" => "Prime" | |
81 | | #"*" => "Star" | |
82 | | #"+" => "Plus" | |
83 | | #"-" => "Minus" | |
84 | | #"." => "Dot" | |
85 | | #"/" => "Divide" | |
86 | | #":" => "Colon" | |
87 | | #"<" => "Lt" | |
88 | | #"=" => "Eq" | |
89 | | #">" => "Gt" | |
90 | | #"?" => "Ques" | |
91 | | #"@" => "At" | |
92 | | #"\\" => "Slash" | |
93 | | #"^" => "Caret" | |
94 | | #"`" => "Quote" | |
95 | | #"|" => "Pipe" | |
96 | | #"~" => "Tilde" | |
97 | | c => str c) | |
98 | val s = UniqueString.unique s | |
99 | val _ = printName := SOME s | |
100 | in | |
101 | s | |
102 | end | |
103 | | SOME s => s | |
104 | ||
105 | val layout = String.layout o toString | |
106 | ||
107 | fun equals (id, id') = Plist.equals (plist id, plist id') | |
108 | ||
109 | local | |
110 | fun make (originalName, printName) = | |
111 | T {hash = Random.word (), | |
112 | originalName = originalName, | |
113 | printName = ref printName, | |
114 | plist = Plist.new ()} | |
115 | in | |
116 | fun fromString s = make (s, SOME s) | |
117 | fun newString s = make (s, NONE) | |
118 | end | |
119 | ||
120 | val new = newString o originalName | |
121 | ||
122 | fun newNoname () = newString noname | |
123 | ||
124 | val bogus = newString "bogus" | |
125 | ||
126 | val clear = Plist.clear o plist | |
127 | ||
128 | end |