| ... | @@ -231,11 +231,10 @@ test "parseCharLiteral" { | ... | @@ -231,11 +231,10 @@ test "parseCharLiteral" { |
| 231 | ); | 231 | ); |
| 232 | } | 232 | } |
| 233 | | 233 | |
| 234 | /// Parses `bytes` as a Zig string literal and appends the result to `buf`. | 234 | /// Parses `bytes` as a Zig string literal and writes the result to the std.io.Writer type. |
| 235 | /// Asserts `bytes` has '"' at beginning and end. | 235 | /// Asserts `bytes` has '"' at beginning and end. |
| 236 | pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory}!Result { | 236 | pub fn parseWrite(writer: anytype, bytes: []const u8) error{OutOfMemory}!Result { |
| 237 | assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"'); | 237 | assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"'); |
| 238 | try buf.ensureUnusedCapacity(bytes.len - 2); | | |
| 239 | | 238 | |
| 240 | var index: usize = 1; | 239 | var index: usize = 1; |
| 241 | while (true) { | 240 | while (true) { |
| ... | @@ -248,11 +247,13 @@ pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory | ... | @@ -248,11 +247,13 @@ pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory |
| 248 | switch (result) { | 247 | switch (result) { |
| 249 | .success => |codepoint| { | 248 | .success => |codepoint| { |
| 250 | if (bytes[escape_char_index] == 'u') { | 249 | if (bytes[escape_char_index] == 'u') { |
| 251 | buf.items.len += utf8Encode(codepoint, buf.unusedCapacitySlice()) catch { | 250 | var buf: [4]u8 = undefined; |
| | 251 | const len = utf8Encode(codepoint, &buf) catch { |
| 252 | return Result{ .failure = .{ .invalid_unicode_codepoint = escape_char_index + 1 } }; | 252 | return Result{ .failure = .{ .invalid_unicode_codepoint = escape_char_index + 1 } }; |
| 253 | }; | 253 | }; |
| | 254 | try writer.writeAll(buf[0..len]); |
| 254 | } else { | 255 | } else { |
| 255 | buf.appendAssumeCapacity(@intCast(u8, codepoint)); | 256 | try writer.writeByte(@intCast(u8, codepoint)); |
| 256 | } | 257 | } |
| 257 | }, | 258 | }, |
| 258 | .failure => |err| return Result{ .failure = err }, | 259 | .failure => |err| return Result{ .failure = err }, |
| ... | @@ -261,7 +262,7 @@ pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory | ... | @@ -261,7 +262,7 @@ pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory |
| 261 | '\n' => return Result{ .failure = .{ .invalid_character = index } }, | 262 | '\n' => return Result{ .failure = .{ .invalid_character = index } }, |
| 262 | '"' => return Result.success, | 263 | '"' => return Result.success, |
| 263 | else => { | 264 | else => { |
| 264 | try buf.append(b); | 265 | try writer.writeByte(b); |
| 265 | index += 1; | 266 | index += 1; |
| 266 | }, | 267 | }, |
| 267 | } | 268 | } |
| ... | @@ -280,44 +281,6 @@ pub fn parseAlloc(allocator: std.mem.Allocator, bytes: []const u8) ParseError![] | ... | @@ -280,44 +281,6 @@ pub fn parseAlloc(allocator: std.mem.Allocator, bytes: []const u8) ParseError![] |
| 280 | } | 281 | } |
| 281 | } | 282 | } |
| 282 | | 283 | |
| 283 | /// Parses `bytes` as a Zig string literal and writes the result to the std.io.Writer type. | | |
| 284 | /// Asserts `bytes` has '"' at beginning and end. | | |
| 285 | pub fn parseWrite(writer: anytype, bytes: []const u8) error{OutOfMemory}!Result { | | |
| 286 | assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"'); | | |
| 287 | | | |
| 288 | var index: usize = 1; | | |
| 289 | while (true) { | | |
| 290 | const b = bytes[index]; | | |
| 291 | | | |
| 292 | switch (b) { | | |
| 293 | '\\' => { | | |
| 294 | const escape_char_index = index + 1; | | |
| 295 | const result = parseEscapeSequence(bytes, &index); | | |
| 296 | switch (result) { | | |
| 297 | .success => |codepoint| { | | |
| 298 | if (bytes[escape_char_index] == 'u') { | | |
| 299 | var buf: [3]u8 = undefined; | | |
| 300 | const len = utf8Encode(codepoint, &buf) catch { | | |
| 301 | return Result{ .failure = .{ .invalid_unicode_codepoint = escape_char_index + 1 } }; | | |
| 302 | }; | | |
| 303 | try writer.writeAll(buf[0..len]); | | |
| 304 | } else { | | |
| 305 | try writer.writeByte(@intCast(u8, codepoint)); | | |
| 306 | } | | |
| 307 | }, | | |
| 308 | .failure => |err| return Result{ .failure = err }, | | |
| 309 | } | | |
| 310 | }, | | |
| 311 | '\n' => return Result{ .failure = .{ .invalid_character = index } }, | | |
| 312 | '"' => return Result.success, | | |
| 313 | else => { | | |
| 314 | try writer.writeByte(b); | | |
| 315 | index += 1; | | |
| 316 | }, | | |
| 317 | } | | |
| 318 | } else unreachable; // TODO should not need else unreachable on while(true) | | |
| 319 | } | | |
| 320 | | | |
| 321 | test "parse" { | 284 | test "parse" { |
| 322 | const expect = std.testing.expect; | 285 | const expect = std.testing.expect; |
| 323 | const expectError = std.testing.expectError; | 286 | const expectError = std.testing.expectError; |