-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecode.mbt
95 lines (84 loc) · 2.41 KB
/
decode.mbt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/// Converts a Punycode string of ASCII-only symbols to a string of Unicode symbols.
pub fn decode(encoded : String) -> String? {
let decoded = []
let encoded_length = encoded.length().reinterpret_as_uint()
let delimiter_idx = encoded.last_index_of(delimiter.to_string())
let basic = match delimiter_idx < 0 {
true => 0U
false => delimiter_idx.reinterpret_as_uint()
}
// Basic ASCII code point extraction
let encoded = encoded.to_array()
for j = 0U; j < basic; j = j + 1U {
let c = encoded[j.reinterpret_as_int()]
let code = c.to_int()
if code >= 0x80 {
// Not basic ASCII code point
return None
}
decoded.push(c)
}
// Initialize the state
let mut n = initial_n
let mut i = 0U
let mut bias = initial_bias
// Main decoding loop
let mut idx = if basic > 0 { basic + 1 } else { 0 }
while idx < encoded_length {
let oldi = i
let mut w = 1U
for k = base; ; k = k + base {
let digit = decode_digit(encoded[idx.reinterpret_as_int()])
idx += 1
if digit > (@uint.max_value - i) / w {
return None // Overflow
}
i += digit * w
let t = if k <= bias {
tmin
} else if k >= bias + tmax {
tmax
} else {
k - bias
}
if digit < t {
break
}
if w > @uint.max_value / (base - t) {
return None // Overflow
}
w *= base - t
}
let out = decoded.length().reinterpret_as_uint() + 1U
bias = adapt(i - oldi, out, oldi == 0U)
if i / out > @uint.max_value - n {
return None // Overflow
}
n += i / out
i %= out
decoded.insert(i.reinterpret_as_int(), Char::from_int(n.reinterpret_as_int()))
i += 1U
}
// FIXME(chawyehsu): I was expecting to convert the array to a string
// using `.to_string()` here but it seems it's not the right way to
// do it in MoonBit, `.join("")` doesn't work as expected either.
let mut decoded_str = ""
let mut i = 0
while i < decoded.length() {
decoded_str = decoded_str + decoded[i].to_string()
i += 1
}
Some(decoded_str)
}
fn decode_digit(c : Char) -> UInt {
let code = c.to_int()
if code >= 48 && code < 58 {
code.reinterpret_as_uint() - 48U + 26U // 0-9
} else if code >= 65 && code < 91 {
code.reinterpret_as_uint() - 65U // A-Z
} else if code >= 97 && code < 123 {
code.reinterpret_as_uint() - 97U // a-z
} else {
abort("Invalid punycode")
}
}