Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / atoms / id.fun
CommitLineData
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
10structure 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
34functor Id (S: ID_STRUCTS): ID =
35struct
36
37open S
38
39structure Plist = PropertyList
40
41datatype t = T of {hash: word,
42 originalName: string,
43 printName: string option ref,
44 plist: Plist.t}
45
46local
47 fun make f (T r) = f r
48in
49 val hash = make #hash
50 val originalName = make #originalName
51 val plist = make #plist
52end
53
54fun isAlphaNum (s: string): bool =
55 String.forall (s, fn c => Char.isAlphaNum c orelse c = #"_")
56
57fun clearPrintName (T {originalName, printName, ...}): unit =
58 if isAlphaNum originalName
59 then ()
60 else printName := NONE
61
62val printNameAlphaNumeric: bool ref = ref false
63
64fun 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
105val layout = String.layout o toString
106
107fun equals (id, id') = Plist.equals (plist id, plist id')
108
109local
110 fun make (originalName, printName) =
111 T {hash = Random.word (),
112 originalName = originalName,
113 printName = ref printName,
114 plist = Plist.new ()}
115in
116 fun fromString s = make (s, SOME s)
117 fun newString s = make (s, NONE)
118end
119
120val new = newString o originalName
121
122fun newNoname () = newString noname
123
124val bogus = newString "bogus"
125
126val clear = Plist.clear o plist
127
128end