| author | |
| committer | |
| log | 9e8943736e34d28d1ea62229d6ca708303cd0eba |
| tree | 878057b9513b6801a19e60ab47aa923f575fbb27 |
| parent | d91605e27eb25ae9175f6e92d5f9f9db1ce6a714 |
| parent | 490654c332f2d8eaf7edffa35ea0523800df998d |
8 files changed, 111 insertions(+), 9 deletions(-)
lib/std/ascii.zig+20| ... | @@ -379,3 +379,23 @@ test "indexOfIgnoreCase" { | ... | @@ -379,3 +379,23 @@ test "indexOfIgnoreCase" { |
| 379 | 379 | ||
| 380 | std.testing.expect(indexOfIgnoreCase("FOO foo", "fOo").? == 0); | 380 | std.testing.expect(indexOfIgnoreCase("FOO foo", "fOo").? == 0); |
| 381 | } | 381 | } |
| 382 | |||
| 383 | /// Compares two slices of numbers lexicographically. O(n). | ||
| 384 | pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order { | ||
| 385 | const n = std.math.min(lhs.len, rhs.len); | ||
| 386 | var i: usize = 0; | ||
| 387 | while (i < n) : (i += 1) { | ||
| 388 | switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) { | ||
| 389 | .eq => continue, | ||
| 390 | .lt => return .lt, | ||
| 391 | .gt => return .gt, | ||
| 392 | } | ||
| 393 | } | ||
| 394 | return std.math.order(lhs.len, rhs.len); | ||
| 395 | } | ||
| 396 | |||
| 397 | /// Returns true if lhs < rhs, false otherwise | ||
| 398 | /// TODO rename "IgnoreCase" to "Insensitive" in this entire file. | ||
| 399 | pub fn lessThanIgnoreCase(lhs: []const u8, rhs: []const u8) bool { | ||
| 400 | return orderIgnoreCase(lhs, rhs) == .lt; | ||
| 401 | } |
lib/std/zig/fmt.zig+30-5| ... | @@ -12,7 +12,7 @@ pub fn formatId( | ... | @@ -12,7 +12,7 @@ pub fn formatId( |
| 12 | return writer.writeAll(bytes); | 12 | return writer.writeAll(bytes); |
| 13 | } | 13 | } |
| 14 | try writer.writeAll("@\""); | 14 | try writer.writeAll("@\""); |
| 15 | try formatEscapes(bytes, fmt, options, writer); | 15 | try formatEscapes(bytes, "", options, writer); |
| 16 | try writer.writeByte('"'); | 16 | try writer.writeByte('"'); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| ... | @@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool { | ... | @@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool { |
| 32 | return std.zig.Token.getKeyword(bytes) == null; | 32 | return std.zig.Token.getKeyword(bytes) == null; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | /// Print the string as escaped contents of a double quoted or single-quoted string. | ||
| 36 | /// Format `{}` treats contents as a double-quoted string. | ||
| 37 | /// Format `{'}` treats contents as a single-quoted string. | ||
| 35 | pub fn formatEscapes( | 38 | pub fn formatEscapes( |
| 36 | bytes: []const u8, | 39 | bytes: []const u8, |
| 37 | comptime fmt: []const u8, | 40 | comptime fmt: []const u8, |
| ... | @@ -43,8 +46,24 @@ pub fn formatEscapes( | ... | @@ -43,8 +46,24 @@ pub fn formatEscapes( |
| 43 | '\r' => try writer.writeAll("\\r"), | 46 | '\r' => try writer.writeAll("\\r"), |
| 44 | '\t' => try writer.writeAll("\\t"), | 47 | '\t' => try writer.writeAll("\\t"), |
| 45 | '\\' => try writer.writeAll("\\\\"), | 48 | '\\' => try writer.writeAll("\\\\"), |
| 46 | '"' => try writer.writeAll("\\\""), | 49 | '"' => { |
| 47 | '\'' => try writer.writeAll("\\'"), | 50 | if (fmt.len == 1 and fmt[0] == '\'') { |
| 51 | try writer.writeByte('"'); | ||
| 52 | } else if (fmt.len == 0) { | ||
| 53 | try writer.writeAll("\\\""); | ||
| 54 | } else { | ||
| 55 | @compileError("expected {} or {'}, found {" ++ fmt ++ "}"); | ||
| 56 | } | ||
| 57 | }, | ||
| 58 | '\'' => { | ||
| 59 | if (fmt.len == 1 and fmt[0] == '\'') { | ||
| 60 | try writer.writeAll("\\'"); | ||
| 61 | } else if (fmt.len == 0) { | ||
| 62 | try writer.writeByte('\''); | ||
| 63 | } else { | ||
| 64 | @compileError("expected {} or {'}, found {" ++ fmt ++ "}"); | ||
| 65 | } | ||
| 66 | }, | ||
| 48 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte), | 67 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte), |
| 49 | // Use hex escapes for rest any unprintable characters. | 68 | // Use hex escapes for rest any unprintable characters. |
| 50 | else => { | 69 | else => { |
| ... | @@ -54,7 +73,10 @@ pub fn formatEscapes( | ... | @@ -54,7 +73,10 @@ pub fn formatEscapes( |
| 54 | }; | 73 | }; |
| 55 | } | 74 | } |
| 56 | 75 | ||
| 57 | /// Return a Formatter for Zig Escapes | 76 | /// Return a Formatter for Zig Escapes of a double quoted string. |
| 77 | /// The format specifier must be one of: | ||
| 78 | /// * `{}` treats contents as a double-quoted string. | ||
| 79 | /// * `{'}` treats contents as a single-quoted string. | ||
| 58 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) { | 80 | pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) { |
| 59 | return .{ .data = bytes }; | 81 | return .{ .data = bytes }; |
| 60 | } | 82 | } |
| ... | @@ -67,6 +89,9 @@ test "escape invalid identifiers" { | ... | @@ -67,6 +89,9 @@ test "escape invalid identifiers" { |
| 67 | try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")}); | 89 | try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")}); |
| 68 | try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")}); | 90 | try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")}); |
| 69 | try expectFmt( | 91 | try expectFmt( |
| 70 | \\" \\ hi \x07 \x11 \" derp \'" | 92 | \\" \\ hi \x07 \x11 " derp \'" |
| 93 | , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); | ||
| 94 | try expectFmt( | ||
| 95 | \\" \\ hi \x07 \x11 \" derp '" | ||
| 71 | , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); | 96 | , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); |
| 72 | } | 97 | } |
src/clang.zig+10| ... | @@ -583,6 +583,16 @@ pub const MacroQualifiedType = opaque { | ... | @@ -583,6 +583,16 @@ pub const MacroQualifiedType = opaque { |
| 583 | extern fn ZigClangMacroQualifiedType_getModifiedType(*const MacroQualifiedType) QualType; | 583 | extern fn ZigClangMacroQualifiedType_getModifiedType(*const MacroQualifiedType) QualType; |
| 584 | }; | 584 | }; |
| 585 | 585 | ||
| 586 | pub const TypeOfType = opaque { | ||
| 587 | pub const getUnderlyingType = ZigClangTypeOfType_getUnderlyingType; | ||
| 588 | extern fn ZigClangTypeOfType_getUnderlyingType(*const TypeOfType) QualType; | ||
| 589 | }; | ||
| 590 | |||
| 591 | pub const TypeOfExprType = opaque { | ||
| 592 | pub const getUnderlyingExpr = ZigClangTypeOfExprType_getUnderlyingExpr; | ||
| 593 | extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr; | ||
| 594 | }; | ||
| 595 | |||
| 586 | pub const MemberExpr = opaque { | 596 | pub const MemberExpr = opaque { |
| 587 | pub const getBase = ZigClangMemberExpr_getBase; | 597 | pub const getBase = ZigClangMemberExpr_getBase; |
| 588 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; | 598 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; |
src/translate_c.zig+15-1| ... | @@ -2475,7 +2475,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined | ... | @@ -2475,7 +2475,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined |
| 2475 | 2475 | ||
| 2476 | fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { | 2476 | fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { |
| 2477 | return Tag.char_literal.create(c.arena, if (narrow) | 2477 | return Tag.char_literal.create(c.arena, if (narrow) |
| 2478 | try std.fmt.allocPrint(c.arena, "'{s}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})}) | 2478 | try std.fmt.allocPrint(c.arena, "'{'}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})}) |
| 2479 | else | 2479 | else |
| 2480 | try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val})); | 2480 | try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val})); |
| 2481 | } | 2481 | } |
| ... | @@ -3827,6 +3827,20 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan | ... | @@ -3827,6 +3827,20 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan |
| 3827 | const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty); | 3827 | const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty); |
| 3828 | return transQualType(c, scope, macroqualified_ty.getModifiedType(), source_loc); | 3828 | return transQualType(c, scope, macroqualified_ty.getModifiedType(), source_loc); |
| 3829 | }, | 3829 | }, |
| 3830 | .TypeOf => { | ||
| 3831 | const typeof_ty = @ptrCast(*const clang.TypeOfType, ty); | ||
| 3832 | return transQualType(c, scope, typeof_ty.getUnderlyingType(), source_loc); | ||
| 3833 | }, | ||
| 3834 | .TypeOfExpr => { | ||
| 3835 | const typeofexpr_ty = @ptrCast(*const clang.TypeOfExprType, ty); | ||
| 3836 | const underlying_expr = transExpr(c, scope, typeofexpr_ty.getUnderlyingExpr(), .used) catch |err| switch (err) { | ||
| 3837 | error.UnsupportedTranslation => { | ||
| 3838 | return fail(c, error.UnsupportedType, source_loc, "unsupported underlying expression for TypeOfExpr", .{}); | ||
| 3839 | }, | ||
| 3840 | else => |e| return e, | ||
| 3841 | }; | ||
| 3842 | return Tag.typeof.create(c.arena, underlying_expr); | ||
| 3843 | }, | ||
| 3830 | else => { | 3844 | else => { |
| 3831 | const type_name = c.str(ty.getTypeClassName()); | 3845 | const type_name = c.str(ty.getTypeClassName()); |
| 3832 | return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); | 3846 | return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); |
src/translate_c/ast.zig+3-3| ... | @@ -995,7 +995,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -995,7 +995,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 995 | 995 | ||
| 996 | const compile_error_tok = try c.addToken(.builtin, "@compileError"); | 996 | const compile_error_tok = try c.addToken(.builtin, "@compileError"); |
| 997 | _ = try c.addToken(.l_paren, "("); | 997 | _ = try c.addToken(.l_paren, "("); |
| 998 | const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.mangled)}); | 998 | const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(payload.mangled)}); |
| 999 | const err_msg = try c.addNode(.{ | 999 | const err_msg = try c.addNode(.{ |
| 1000 | .tag = .string_literal, | 1000 | .tag = .string_literal, |
| 1001 | .main_token = err_msg_tok, | 1001 | .main_token = err_msg_tok, |
| ... | @@ -2265,7 +2265,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { | ... | @@ -2265,7 +2265,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { |
| 2265 | _ = try c.addToken(.l_paren, "("); | 2265 | _ = try c.addToken(.l_paren, "("); |
| 2266 | const res = try c.addNode(.{ | 2266 | const res = try c.addNode(.{ |
| 2267 | .tag = .string_literal, | 2267 | .tag = .string_literal, |
| 2268 | .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}), | 2268 | .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), |
| 2269 | .data = undefined, | 2269 | .data = undefined, |
| 2270 | }); | 2270 | }); |
| 2271 | _ = try c.addToken(.r_paren, ")"); | 2271 | _ = try c.addToken(.r_paren, ")"); |
| ... | @@ -2347,7 +2347,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { | ... | @@ -2347,7 +2347,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { |
| 2347 | _ = try c.addToken(.l_paren, "("); | 2347 | _ = try c.addToken(.l_paren, "("); |
| 2348 | const res = try c.addNode(.{ | 2348 | const res = try c.addNode(.{ |
| 2349 | .tag = .string_literal, | 2349 | .tag = .string_literal, |
| 2350 | .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}), | 2350 | .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), |
| 2351 | .data = undefined, | 2351 | .data = undefined, |
| 2352 | }); | 2352 | }); |
| 2353 | _ = try c.addToken(.r_paren, ")"); | 2353 | _ = try c.addToken(.r_paren, ")"); |
src/zig_clang.cpp+10| ... | @@ -2613,6 +2613,16 @@ struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct | ... | @@ -2613,6 +2613,16 @@ struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct |
| 2613 | return bitcast(casted->getModifiedType()); | 2613 | return bitcast(casted->getModifiedType()); |
| 2614 | } | 2614 | } |
| 2615 | 2615 | ||
| 2616 | struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const struct ZigClangTypeOfType *self) { | ||
| 2617 | auto casted = reinterpret_cast<const clang::TypeOfType *>(self); | ||
| 2618 | return bitcast(casted->getUnderlyingType()); | ||
| 2619 | } | ||
| 2620 | |||
| 2621 | const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *self) { | ||
| 2622 | auto casted = reinterpret_cast<const clang::TypeOfExprType *>(self); | ||
| 2623 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr()); | ||
| 2624 | } | ||
| 2625 | |||
| 2616 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { | 2626 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { |
| 2617 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); | 2627 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); |
| 2618 | return bitcast(casted->getNamedType()); | 2628 | return bitcast(casted->getNamedType()); |
src/zig_clang.h+4| ... | @@ -1164,6 +1164,10 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangAttributedType_getEquivalentType(co | ... | @@ -1164,6 +1164,10 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangAttributedType_getEquivalentType(co |
| 1164 | 1164 | ||
| 1165 | ZIG_EXTERN_C struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct ZigClangMacroQualifiedType *); | 1165 | ZIG_EXTERN_C struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct ZigClangMacroQualifiedType *); |
| 1166 | 1166 | ||
| 1167 | ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const struct ZigClangTypeOfType *); | ||
| 1168 | |||
| 1169 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *); | ||
| 1170 | |||
| 1167 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); | 1171 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); |
| 1168 | ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); | 1172 | ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); |
| 1169 | 1173 |
test/run_translated_c.zig+19| ... | @@ -1054,4 +1054,23 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { | ... | @@ -1054,4 +1054,23 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1054 | \\ return 0; | 1054 | \\ return 0; |
| 1055 | \\} | 1055 | \\} |
| 1056 | , ""); | 1056 | , ""); |
| 1057 | |||
| 1058 | cases.add("typeof operator", | ||
| 1059 | \\#include <stdlib.h> | ||
| 1060 | \\static int FOO = 42; | ||
| 1061 | \\typedef typeof(FOO) foo_type; | ||
| 1062 | \\typeof(foo_type) myfunc(typeof(FOO) x) { return (typeof(FOO)) x; } | ||
| 1063 | \\int main(void) { | ||
| 1064 | \\ int x = FOO; | ||
| 1065 | \\ typeof(x) y = x; | ||
| 1066 | \\ foo_type z = y; | ||
| 1067 | \\ if (x != y) abort(); | ||
| 1068 | \\ if (myfunc(z) != x) abort(); | ||
| 1069 | \\ | ||
| 1070 | \\ const char *my_string = "bar"; | ||
| 1071 | \\ typeof (typeof (my_string)[4]) string_arr = {"a","b","c","d"}; | ||
| 1072 | \\ if (string_arr[0][0] != 'a' || string_arr[3][0] != 'd') abort(); | ||
| 1073 | \\ return 0; | ||
| 1074 | \\} | ||
| 1075 | , ""); | ||
| 1057 | } | 1076 | } |