| ... | @@ -84,7 +84,7 @@ pub fn binNameAlloc( | ... | @@ -84,7 +84,7 @@ pub fn binNameAlloc( |
| 84 | /// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between. | 84 | /// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between. |
| 85 | pub fn parseCharLiteral( | 85 | pub fn parseCharLiteral( |
| 86 | slice: []const u8, | 86 | slice: []const u8, |
| 87 | bad_index: *usize, // populated if error.InvalidCharacter is returned) | 87 | bad_index: *usize, // populated if error.InvalidCharacter is returned |
| 88 | ) error{InvalidCharacter}!u32 { | 88 | ) error{InvalidCharacter}!u32 { |
| 89 | std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\''); | 89 | std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\''); |
| 90 | | 90 | |
| ... | @@ -101,24 +101,23 @@ pub fn parseCharLiteral( | ... | @@ -101,24 +101,23 @@ pub fn parseCharLiteral( |
| 101 | bad_index.* = slice.len - 2; | 101 | bad_index.* = slice.len - 2; |
| 102 | return error.InvalidCharacter; | 102 | return error.InvalidCharacter; |
| 103 | } | 103 | } |
| 104 | | | |
| 105 | var value: u32 = 0; | 104 | var value: u32 = 0; |
| 106 | for (slice[3..5]) |c, i| { | 105 | for (slice[3..5]) |c, i| { |
| 107 | switch (slice[3]) { | 106 | switch (c) { |
| 108 | '0'...'9' => { | 107 | '0'...'9' => { |
| 109 | value *= 16; | 108 | value *= 16; |
| 110 | value += c - '0'; | 109 | value += c - '0'; |
| 111 | }, | 110 | }, |
| 112 | 'a'...'f' => { | 111 | 'a'...'f' => { |
| 113 | value *= 16; | 112 | value *= 16; |
| 114 | value += c - 'a'; | 113 | value += c - 'a' + 10; |
| 115 | }, | 114 | }, |
| 116 | 'A'...'F' => { | 115 | 'A'...'F' => { |
| 117 | value *= 16; | 116 | value *= 16; |
| 118 | value += c - 'a'; | 117 | value += c - 'A' + 10; |
| 119 | }, | 118 | }, |
| 120 | else => { | 119 | else => { |
| 121 | bad_index.* = i; | 120 | bad_index.* = 3 + i; |
| 122 | return error.InvalidCharacter; | 121 | return error.InvalidCharacter; |
| 123 | }, | 122 | }, |
| 124 | } | 123 | } |
| ... | @@ -126,16 +125,12 @@ pub fn parseCharLiteral( | ... | @@ -126,16 +125,12 @@ pub fn parseCharLiteral( |
| 126 | return value; | 125 | return value; |
| 127 | }, | 126 | }, |
| 128 | 'u' => { | 127 | 'u' => { |
| 129 | if (slice.len < 6 or slice[3] != '{') { | 128 | if (slice.len < "'\\u{0}'".len or slice[3] != '{' or slice[slice.len - 2] != '}') { |
| 130 | bad_index.* = 2; | 129 | bad_index.* = 2; |
| 131 | return error.InvalidCharacter; | 130 | return error.InvalidCharacter; |
| 132 | } | 131 | } |
| 133 | var value: u32 = 0; | 132 | var value: u32 = 0; |
| 134 | for (slice[4..]) |c, i| { | 133 | for (slice[4 .. slice.len - 2]) |c, i| { |
| 135 | if (value > 0x10ffff) { | | |
| 136 | bad_index.* = i; | | |
| 137 | return error.InvalidCharacter; | | |
| 138 | } | | |
| 139 | switch (c) { | 134 | switch (c) { |
| 140 | '0'...'9' => { | 135 | '0'...'9' => { |
| 141 | value *= 16; | 136 | value *= 16; |
| ... | @@ -143,25 +138,28 @@ pub fn parseCharLiteral( | ... | @@ -143,25 +138,28 @@ pub fn parseCharLiteral( |
| 143 | }, | 138 | }, |
| 144 | 'a'...'f' => { | 139 | 'a'...'f' => { |
| 145 | value *= 16; | 140 | value *= 16; |
| 146 | value += c - 'a'; | 141 | value += c - 'a' + 10; |
| 147 | }, | 142 | }, |
| 148 | 'A'...'F' => { | 143 | 'A'...'F' => { |
| 149 | value *= 16; | 144 | value *= 16; |
| 150 | value += c - 'A'; | 145 | value += c - 'A' + 10; |
| 151 | }, | 146 | }, |
| 152 | '}' => break, | | |
| 153 | else => { | 147 | else => { |
| 154 | bad_index.* = i; | 148 | bad_index.* = 4 + i; |
| 155 | return error.InvalidCharacter; | 149 | return error.InvalidCharacter; |
| 156 | }, | 150 | }, |
| 157 | } | 151 | } |
| | 152 | if (value > 0x10ffff) { |
| | 153 | bad_index.* = 4 + i; |
| | 154 | return error.InvalidCharacter; |
| | 155 | } |
| 158 | } | 156 | } |
| 159 | return value; | 157 | return value; |
| 160 | }, | 158 | }, |
| 161 | else => { | 159 | else => { |
| 162 | bad_index.* = 2; | 160 | bad_index.* = 2; |
| 163 | return error.InvalidCharacter; | 161 | return error.InvalidCharacter; |
| 164 | } | 162 | }, |
| 165 | } | 163 | } |
| 166 | } | 164 | } |
| 167 | return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable; | 165 | return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable; |
| ... | @@ -172,13 +170,23 @@ test "parseCharLiteral" { | ... | @@ -172,13 +170,23 @@ test "parseCharLiteral" { |
| 172 | std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a'); | 170 | std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a'); |
| 173 | std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä'); | 171 | std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä'); |
| 174 | std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0); | 172 | std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0); |
| | 173 | std.testing.expectEqual(try parseCharLiteral("'\\x4f'", &bad_index), 0x4f); |
| | 174 | std.testing.expectEqual(try parseCharLiteral("'\\x4F'", &bad_index), 0x4f); |
| 175 | std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041); | 175 | std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041); |
| | 176 | std.testing.expectEqual(try parseCharLiteral("'\\u{0}'", &bad_index), 0); |
| 176 | std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041); | 177 | std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041); |
| | 178 | std.testing.expectEqual(try parseCharLiteral("'\\u{7f}'", &bad_index), 0x7f); |
| | 179 | std.testing.expectEqual(try parseCharLiteral("'\\u{7FFF}'", &bad_index), 0x7FFF); |
| 177 | | 180 | |
| 178 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index)); | 181 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index)); |
| | 182 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x000'", &bad_index)); |
| 179 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index)); | 183 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index)); |
| 180 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index)); | 184 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index)); |
| | 185 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\uFFFF'", &bad_index)); |
| | 186 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{}'", &bad_index)); |
| 181 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index)); | 187 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index)); |
| | 188 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF'", &bad_index)); |
| | 189 | std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFF}x'", &bad_index)); |
| 182 | } | 190 | } |
| 183 | | 191 | |
| 184 | test "" { | 192 | test "" { |