From c3724a6e723dfb5ec78c6ca87e2f02e121d39bc2 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 10:30:38 +0200 Subject: [PATCH 1/9] translate-c-2 c tokenizer --- src-self-hosted/c_tokenizer.zig | 458 ++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 src-self-hosted/c_tokenizer.zig diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig new file mode 100644 index 0000000000..6899e3efba --- /dev/null +++ b/src-self-hosted/c_tokenizer.zig @@ -0,0 +1,458 @@ +const std = @import("std"); + +pub const TokenList = std.SegmentedList(CToken, 32); + +pub const CToken = struct { + id: Id, + bytes: []const u8, + num_lit_suffix: NumLitSuffix = undefined, + + pub const Id = enum { + CharLit, + StrLit, + NumLitInt, + NumLitFloat, + Identifier, + Minus, + Slash, + LParen, + RParen, + Eof, + Dot, + Asterisk, + Bang, + Tilde, + Shl, + Lt, + }; + + pub const NumLitSuffix = enum { + None, + L, + U, + LU, + LL, + LLU, + }; +}; + +pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void { + var index: usize = 0; + while (true) { + const tok = try next(chars[index..], &index); + tl.push(tok); + if (tok.id == .Eof) + return; + } +} + +fn next(chars: [*]const u8, index: *usize) !CToken { + var state: enum { + Start, + GotLt, + ExpectChar, + ExpectEndQuot, + OpenComment, + Comment, + CommentStar, + Backslash, + String, + Identifier, + Decimal, + Octal, + GotZero, + Hex, + Float, + ExpSign, + FloatExp, + FloatExpFirst, + NumLitIntSuffixU, + NumLitIntSuffixL, + NumLitIntSuffixLL, + NumLitIntSuffixUL, + GotLt, + } = .Start; + + var result = CToken{ + .bytes = "", + .id = .Eof, + }; + var begin_index: usize = 0; + var digits: u8 = 0; + var pre_escape = .Start; + + for (chars[begin_index..]) |c, i| { + if (c == 0) { + switch (state) { + .Start => { + return result; + }, + .Identifier, + .Decimal, + .Hex, + .Octal, + .GotZero, + .NumLitIntSuffixU, + .NumLitIntSuffixL, + .NumLitIntSuffixUL, + .NumLitIntSuffixLL, + .Float, + .FloatExp, + .GotLt, + => { + return result; + }, + .ExpectChar, + .ExpectEndQuot, + .OpenComment, + .LineComment, + .Comment, + .CommentStar, + .Backslash, + .String, + .ExpSign, + .FloatExpFirst, + => return error.TokenizingFailed, + } + } + index.* += 1; + switch (state) { + .Start => { + switch (c) { + ' ', '\t', '\x0B', '\x0C' => {}, + '\'' => { + state = .ExpectChar; + result.id = .CharLit; + begin_index = i; + }, + '\"' => { + state = .String; + result.id = .StrLit; + begin_index = i; + }, + '/' => { + state = .OpenComment; + }, + '\\' => { + state = .Backslash; + }, + '\n', '\r' => { + return result; + }, + 'a'...'z', 'A'...'Z', '_' => { + state = .Identifier; + result.id = .Identifier; + begin_index = i; + }, + '1'...'9' => { + state = .Decimal; + result.id = .NumLitInt; + begin_index = i; + }, + '0' => { + state = .GotZero; + result.id = .NumLitInt; + begin_index = i; + }, + '.' => { + result.id = .Dot; + return result; + }, + '<' => { + result.id = .Lt; + state = .GotLt; + }, + '(' => { + result.id = .LParen; + return result; + }, + ')' => { + result.id = .RParen; + return result; + }, + '*' => { + result.id = .Asterisk; + return result; + }, + '-' => { + result.id = .Minus; + return result; + }, + '!' => { + result.id = .Bang; + return result; + }, + '~' => { + result.id = .Tilde; + return result; + }, + else => return error.TokenizingFailed, + } + }, + .GotLt => { + switch (c) { + '<' => { + result.id = .Shl; + return result; + }, + else => { + return result; + }, + } + }, + .Float => { + switch (c) { + '.', '0'...'9' => {}, + 'e', 'E' => { + state = .ExpSign; + }, + 'f', 'F', 'l', 'L' => { + result.bytes = chars[begin_index..i]; + return result; + }, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .ExpSign => { + switch (c) { + '+', '-' => { + state = .FloatExpFirst; + }, + '0'...'9' => { + state = .FloatExp; + }, + else => return error.TokenizingFailed, + } + }, + .FloatExpFirst => { + switch (c) { + '0'...'9' => { + state = .FloatExp; + }, + else => return error.TokenizingFailed, + } + }, + .FloatExp => { + switch (c) { + '0'...'9' => {}, + 'f', 'F', 'l', 'L' => { + result.bytes = chars[begin_index..i]; + return result; + }, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .Decimal => { + switch (c) { + '0'...'9' => {}, + '\'' => {}, + 'u', 'U' => { + state = .NumLitIntSuffixU; + result.num_lit_suffix = .U; + }, + 'l', 'L' => { + state = .NumLitIntSuffixL; + result.num_lit_suffix = .L; + }, + '.' => { + result.id = .NumLitFloat; + state = .Float; + }, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .GotZero => { + switch (c) { + 'x', 'X' => { + state = .Hex; + }, + '.' => { + state = .Float; + result.id = .NumLitFloat; + }, + 'l', 'L', 'u', 'U' => { + c -= 1; + state = .Decimal; + }, + else => { + state = .Octal; + }, + } + }, + .Octal => { + switch (c) { + '0'...'7' => {}, + '8', '9' => return error.TokenizingFailed, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .Hex => { + switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => {}, + + 'p', 'P' => { + result.id = .NumLitFloat; + state = .ExpSign; + }, + 'u', 'U' => { + // marks the number literal as unsigned + state = .NumLitIntSuffixU; + result.num_lit_suffix = .U; + }, + 'l', 'L' => { + // marks the number literal as long + state = .NumLitIntSuffixL; + result.num_lit_suffix = .L; + }, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .NumLitIntSuffixU => { + switch (c) { + 'l', 'L' => { + result.num_lit_suffix = .LU; + state = .NumLitIntSuffixUL; + }, + else => { + result.bytes = chars[begin_index..i - 1]; + return result; + }, + } + }, + .NumLitIntSuffixL => { + switch (c) { + 'l', 'L' => { + result.num_lit_suffix = .LL; + state = .NumLitIntSuffixLL; + }, + 'u', 'U' => { + result.num_lit_suffix = .LU; + result.bytes = chars[begin_index..i - 2]; + return result; + }, + else => { + result.bytes = chars[begin_index..i - 1]; + return result; + }, + } + }, + .NumLitIntSuffixLL => { + switch (c) { + 'u', 'U' => { + result.num_lit_suffix = .LLU; + result.bytes = chars[begin_index..i - 3]; + return result; + }, + else => { + result.bytes = chars[begin_index..i - 2]; + return result; + }, + } + }, + .NumLitIntSuffixUL => { + switch (c) { + 'l', 'L' => { + result.num_lit_suffix = .LLU; + result.bytes = chars[begin_index..i - 3]; + return result; + }, + else => { + result.bytes = chars[begin_index..i - 2]; + return result; + }, + } + }, + .Identifier => { + switch (c) { + '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, + else => { + result.bytes = chars[begin_index..i]; + return result; + }, + } + }, + .String => { + switch (c) { + '\"' => { + result.bytes = chars[begin_index + 1 .. i]; + return result; + }, + else => {}, + } + }, + .ExpectChar => { + switch (c) { + '\'' => return error.TokenizingFailed, + else => { + state = .ExpectEndQuot; + }, + } + }, + .ExpectEndQuot => { + switch (c) { + '\'' => { + result.bytes = chars[begin_index + 1 .. i]; + return result; + }, + else => return error.TokenizingFailed, + } + }, + .OpenComment => { + switch (c) { + '/' => { + return result; + }, + '*' => { + state = .Comment; + }, + else => { + result.id = .Slash; + return result; + }, + } + }, + .Comment => { + switch (c) { + '*' => { + state = .CommentStar; + }, + else => {}, + } + }, + .CommentStar => { + switch (c) { + '/' => { + state = .Start; + }, + else => { + state = .Comment; + }, + } + }, + .Backslash => { + switch (c) { + ' ', '\t', '\x0B', '\x0C' => {}, + '\n', '\r' => { + state = .Start; + }, + else => return error.TokenizingFailed, + } + }, + } + } +} From 75218d4765bdf0dbdf97581b7dd05b45570ab940 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 14:44:11 +0200 Subject: [PATCH 2/9] translate-c-2 macros --- src-self-hosted/c_tokenizer.zig | 216 ++++++++++++++++------ src-self-hosted/clang.zig | 22 +++ src-self-hosted/translate_c.zig | 305 ++++++++++++++++++++++++++++++-- test/translate_c.zig | 82 +++++++-- 4 files changed, 543 insertions(+), 82 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 6899e3efba..704cd268f7 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const expect = std.testing.expect; pub const TokenList = std.SegmentedList(CToken, 32); @@ -28,6 +29,7 @@ pub const CToken = struct { pub const NumLitSuffix = enum { None, + F, L, U, LU, @@ -39,19 +41,18 @@ pub const CToken = struct { pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void { var index: usize = 0; while (true) { - const tok = try next(chars[index..], &index); - tl.push(tok); + const tok = try next(chars, &index); + try tl.push(tok); if (tok.id == .Eof) return; } } -fn next(chars: [*]const u8, index: *usize) !CToken { +fn next(chars: [*]const u8, i: *usize) !CToken { var state: enum { Start, GotLt, - ExpectChar, - ExpectEndQuot, + CharLit, OpenComment, Comment, CommentStar, @@ -62,6 +63,7 @@ fn next(chars: [*]const u8, index: *usize) !CToken { Octal, GotZero, Hex, + Bin, Float, ExpSign, FloatExp, @@ -70,7 +72,6 @@ fn next(chars: [*]const u8, index: *usize) !CToken { NumLitIntSuffixL, NumLitIntSuffixLL, NumLitIntSuffixUL, - GotLt, } = .Start; var result = CToken{ @@ -79,9 +80,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken { }; var begin_index: usize = 0; var digits: u8 = 0; - var pre_escape = .Start; + var pre_escape = state; - for (chars[begin_index..]) |c, i| { + while (true) { + const c = chars[i.*]; if (c == 0) { switch (state) { .Start => { @@ -90,22 +92,25 @@ fn next(chars: [*]const u8, index: *usize) !CToken { .Identifier, .Decimal, .Hex, + .Bin, .Octal, .GotZero, + .Float, + .FloatExp, + => { + result.bytes = chars[begin_index..i.*]; + return result; + }, .NumLitIntSuffixU, .NumLitIntSuffixL, .NumLitIntSuffixUL, .NumLitIntSuffixLL, - .Float, - .FloatExp, .GotLt, => { return result; }, - .ExpectChar, - .ExpectEndQuot, + .CharLit, .OpenComment, - .LineComment, .Comment, .CommentStar, .Backslash, @@ -115,20 +120,20 @@ fn next(chars: [*]const u8, index: *usize) !CToken { => return error.TokenizingFailed, } } - index.* += 1; + i.* += 1; switch (state) { .Start => { switch (c) { ' ', '\t', '\x0B', '\x0C' => {}, '\'' => { - state = .ExpectChar; + state = .CharLit; result.id = .CharLit; - begin_index = i; + begin_index = i.* - 1; }, '\"' => { state = .String; result.id = .StrLit; - begin_index = i; + begin_index = i.* - 1; }, '/' => { state = .OpenComment; @@ -142,17 +147,17 @@ fn next(chars: [*]const u8, index: *usize) !CToken { 'a'...'z', 'A'...'Z', '_' => { state = .Identifier; result.id = .Identifier; - begin_index = i; + begin_index = i.* - 1; }, '1'...'9' => { state = .Decimal; result.id = .NumLitInt; - begin_index = i; + begin_index = i.* - 1; }, '0' => { state = .GotZero; result.id = .NumLitInt; - begin_index = i; + begin_index = i.* - 1; }, '.' => { result.id = .Dot; @@ -206,12 +211,23 @@ fn next(chars: [*]const u8, index: *usize) !CToken { 'e', 'E' => { state = .ExpSign; }, - 'f', 'F', 'l', 'L' => { - result.bytes = chars[begin_index..i]; + 'f', + 'F', + => { + i.* -= 1; + result.num_lit_suffix = .F; + result.bytes = chars[begin_index..i.*]; + return result; + }, + 'l', 'L' => { + i.* -= 1; + result.num_lit_suffix = .L; + result.bytes = chars[begin_index..i.*]; return result; }, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } @@ -238,12 +254,19 @@ fn next(chars: [*]const u8, index: *usize) !CToken { .FloatExp => { switch (c) { '0'...'9' => {}, - 'f', 'F', 'l', 'L' => { - result.bytes = chars[begin_index..i]; + 'f', 'F' => { + result.num_lit_suffix = .F; + result.bytes = chars[begin_index .. i.* - 1]; + return result; + }, + 'l', 'L' => { + result.num_lit_suffix = .L; + result.bytes = chars[begin_index .. i.* - 1]; return result; }, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } @@ -255,17 +278,20 @@ fn next(chars: [*]const u8, index: *usize) !CToken { 'u', 'U' => { state = .NumLitIntSuffixU; result.num_lit_suffix = .U; + result.bytes = chars[begin_index .. i.* - 1]; }, 'l', 'L' => { state = .NumLitIntSuffixL; result.num_lit_suffix = .L; + result.bytes = chars[begin_index .. i.* - 1]; }, '.' => { result.id = .NumLitFloat; state = .Float; }, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } @@ -275,15 +301,25 @@ fn next(chars: [*]const u8, index: *usize) !CToken { 'x', 'X' => { state = .Hex; }, + 'b', 'B' => { + state = .Bin; + }, '.' => { state = .Float; result.id = .NumLitFloat; }, - 'l', 'L', 'u', 'U' => { - c -= 1; - state = .Decimal; + 'u', 'U' => { + state = .NumLitIntSuffixU; + result.num_lit_suffix = .U; + result.bytes = chars[begin_index .. i.* - 1]; + }, + 'l', 'L' => { + state = .NumLitIntSuffixL; + result.num_lit_suffix = .L; + result.bytes = chars[begin_index .. i.* - 1]; }, else => { + i.* -= 1; state = .Octal; }, } @@ -293,7 +329,8 @@ fn next(chars: [*]const u8, index: *usize) !CToken { '0'...'7' => {}, '8', '9' => return error.TokenizingFailed, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } @@ -301,23 +338,44 @@ fn next(chars: [*]const u8, index: *usize) !CToken { .Hex => { switch (c) { '0'...'9', 'a'...'f', 'A'...'F' => {}, - - 'p', 'P' => { - result.id = .NumLitFloat; - state = .ExpSign; - }, 'u', 'U' => { // marks the number literal as unsigned state = .NumLitIntSuffixU; result.num_lit_suffix = .U; + result.bytes = chars[begin_index .. i.* - 1]; }, 'l', 'L' => { // marks the number literal as long state = .NumLitIntSuffixL; result.num_lit_suffix = .L; + result.bytes = chars[begin_index .. i.* - 1]; }, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; + return result; + }, + } + }, + .Bin => { + switch (c) { + '0'...'1' => {}, + '2'...'9' => return error.TokenizingFailed, + 'u', 'U' => { + // marks the number literal as unsigned + state = .NumLitIntSuffixU; + result.num_lit_suffix = .U; + result.bytes = chars[begin_index .. i.* - 1]; + }, + 'l', 'L' => { + // marks the number literal as long + state = .NumLitIntSuffixL; + result.num_lit_suffix = .L; + result.bytes = chars[begin_index .. i.* - 1]; + }, + else => { + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } @@ -329,7 +387,7 @@ fn next(chars: [*]const u8, index: *usize) !CToken { state = .NumLitIntSuffixUL; }, else => { - result.bytes = chars[begin_index..i - 1]; + i.* -= 1; return result; }, } @@ -342,11 +400,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken { }, 'u', 'U' => { result.num_lit_suffix = .LU; - result.bytes = chars[begin_index..i - 2]; return result; }, else => { - result.bytes = chars[begin_index..i - 1]; + i.* -= 1; return result; }, } @@ -355,11 +412,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken { switch (c) { 'u', 'U' => { result.num_lit_suffix = .LLU; - result.bytes = chars[begin_index..i - 3]; return result; }, else => { - result.bytes = chars[begin_index..i - 2]; + i.* -= 1; return result; }, } @@ -368,11 +424,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken { switch (c) { 'l', 'L' => { result.num_lit_suffix = .LLU; - result.bytes = chars[begin_index..i - 3]; return result; }, else => { - result.bytes = chars[begin_index..i - 2]; + i.* -= 1; return result; }, } @@ -381,35 +436,28 @@ fn next(chars: [*]const u8, index: *usize) !CToken { switch (c) { '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, else => { - result.bytes = chars[begin_index..i]; + i.* -= 1; + result.bytes = chars[begin_index..i.*]; return result; }, } }, - .String => { + .String => { // TODO char escapes switch (c) { '\"' => { - result.bytes = chars[begin_index + 1 .. i]; + result.bytes = chars[begin_index + 1 .. i.* - 1]; return result; }, else => {}, } }, - .ExpectChar => { - switch (c) { - '\'' => return error.TokenizingFailed, - else => { - state = .ExpectEndQuot; - }, - } - }, - .ExpectEndQuot => { + .CharLit => { switch (c) { '\'' => { - result.bytes = chars[begin_index + 1 .. i]; + result.bytes = chars[begin_index + 1 .. i.* - 1]; return result; }, - else => return error.TokenizingFailed, + else => {}, } }, .OpenComment => { @@ -455,4 +503,56 @@ fn next(chars: [*]const u8, index: *usize) !CToken { }, } } + unreachable; +} + +test "tokenize macro" { + var tl = TokenList.init(std.heap.page_allocator); + defer tl.deinit(); + + const src = "TEST 0\n"; + try tokenizeCMacro(&tl, src); + var it = tl.iterator(0); + expect(it.next().?.id == .Identifier); + expect(std.mem.eql(u8, it.next().?.bytes, "0")); + expect(it.next().?.id == .Eof); + expect(it.next() == null); + tl.shrink(0); + + const src2 = "__FLT_MIN_10_EXP__ -37\n"; + try tokenizeCMacro(&tl, src2); + it = tl.iterator(0); + expect(std.mem.eql(u8, it.next().?.bytes, "__FLT_MIN_10_EXP__")); + expect(it.next().?.id == .Minus); + expect(std.mem.eql(u8, it.next().?.bytes, "37")); + expect(it.next().?.id == .Eof); + expect(it.next() == null); + tl.shrink(0); + + const src3 = "__llvm__ 1\n#define"; + try tokenizeCMacro(&tl, src3); + it = tl.iterator(0); + expect(std.mem.eql(u8, it.next().?.bytes, "__llvm__")); + expect(std.mem.eql(u8, it.next().?.bytes, "1")); + expect(it.next().?.id == .Eof); + expect(it.next() == null); + tl.shrink(0); + + const src4 = "TEST 2"; + try tokenizeCMacro(&tl, src4); + it = tl.iterator(0); + expect(it.next().?.id == .Identifier); + expect(std.mem.eql(u8, it.next().?.bytes, "2")); + expect(it.next().?.id == .Eof); + expect(it.next() == null); + tl.shrink(0); + + const src5 = "FOO 0l"; + try tokenizeCMacro(&tl, src5); + it = tl.iterator(0); + expect(it.next().?.id == .Identifier); + expect(std.mem.eql(u8, it.next().?.bytes, "0")); + expect(it.next().?.id == .Eof); + expect(it.next() == null); + tl.shrink(0); } diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 4b3aa44fab..901660adce 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -75,6 +75,7 @@ pub const struct_ZigClangWhileStmt = @OpaqueType(); pub const struct_ZigClangFunctionType = @OpaqueType(); pub const struct_ZigClangPredefinedExpr = @OpaqueType(); pub const struct_ZigClangInitListExpr = @OpaqueType(); +pub const ZigClangPreprocessingRecord = @OpaqueType(); pub const ZigClangBO = extern enum { PtrMemD, @@ -717,6 +718,18 @@ pub const ZigClangEnumDecl_enumerator_iterator = extern struct { opaque: *c_void, }; +pub const ZigClangPreprocessingRecord_iterator = extern struct { + I: c_int, + Self: *ZigClangPreprocessingRecord, +}; + +pub const ZigClangPreprocessedEntity_EntityKind = extern enum { + InvalidKind, + MacroExpansionKind, + MacroDefinitionKind, + InclusionDirectiveKind, +}; + pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; @@ -1014,3 +1027,12 @@ pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) str pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr; pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt; + +pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_begin(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator; +pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_end(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator; +pub extern fn ZigClangPreprocessingRecord_iterator_deref(ZigClangPreprocessingRecord_iterator) *ZigClangPreprocessedEntity; +pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEntity) ZigClangPreprocessedEntity_EntityKind; + +pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8; +pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; +pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 5cd0198911..c36d0f3d5e 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -6,6 +6,8 @@ const assert = std.debug.assert; const ast = std.zig.ast; const Token = std.zig.Token; usingnamespace @import("clang.zig"); +const ctok = @import("c_tokenizer.zig"); +const CToken = ctok.CToken; const CallingConvention = std.builtin.TypeInfo.CallingConvention; @@ -31,6 +33,7 @@ fn addrEql(a: usize, b: usize) bool { return a == b; } +const MacroTable = std.StringHashMap(*ast.Node); const SymbolTable = std.StringHashMap(void); const AliasList = std.SegmentedList(struct { alias: []const u8, @@ -106,6 +109,7 @@ const Context = struct { decl_table: DeclTable, alias_list: AliasList, sym_table: SymbolTable, + macro_table: MacroTable, global_scope: *Scope.Root, ptr_params: std.BufSet, clang_context: *ZigClangASTContext, @@ -193,6 +197,7 @@ pub fn translate( .decl_table = DeclTable.init(arena), .alias_list = AliasList.init(arena), .sym_table = SymbolTable.init(arena), + .macro_table = MacroTable.init(arena), .global_scope = try arena.create(Scope.Root), .ptr_params = std.BufSet.init(arena), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, @@ -207,6 +212,14 @@ pub fn translate( if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { return context.err; } + + try transPreprocessorEntities(&context, ast_unit); + + var macro_it = context.macro_table.iterator(); + while (macro_it.next()) |kv| { + try addTopLevelDecl(&context, kv.key, kv.value); + } + var it = context.alias_list.iterator(0); while (it.next()) |alias| { if (!context.sym_table.contains(alias.alias)) { @@ -1931,18 +1944,18 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { return &node.base; } -fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { - const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType"); - _ = try appendToken(c, .LParen, "("); - const rparen_tok = try appendToken(c, .RParen, ")"); - - const call_node = try c.a().create(ast.Node.BuiltinCall); - call_node.* = ast.Node.BuiltinCall{ - .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, - .builtin_token = builtin_tok, - .params = ast.Node.BuiltinCall.ParamList.init(c.a()), - .rparen_token = rparen_tok, +fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { + const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int}); + const node = try c.a().create(ast.Node.FloatLiteral); + node.* = .{ + .token = token, }; + return &node.base; +} + +fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { + const call_node = try transCreateNodeBuiltinFnCall(c, "@OpaqueType"); + call_node.rparen_token = try appendToken(c, .RParen, ")"); return &call_node.base; } @@ -2441,3 +2454,273 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { pub fn freeErrors(errors: []ClangErrMsg) void { ZigClangErrorMsg_delete(errors.ptr, errors.len); } + +fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { + // TODO if we see #undef, delete it from the table + var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); + const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); + var tok_list = ctok.TokenList.init(c.a()); + + while (it.I != it_end.I) : (it.I += 1) { + const entity = ZigClangPreprocessingRecord_iterator_deref(it); + tok_list.shrink(0); + + switch (ZigClangPreprocessedEntity_getKind(entity)) { + .MacroExpansionKind => { + // TODO + }, + .MacroDefinitionKind => { + const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); + const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); + const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); + + const name = try c.str(raw_name); + // if (name_exists_global(c, name)) { // TODO + // continue; + // } + + const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); + try transMacroDefine(c, &tok_list, name, begin_c, begin_loc); + }, + else => {}, + } + } +} + +fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) Error!void { + ctok.tokenizeCMacro(tok_list, char_ptr) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + else => return failDecl(c, source_loc, name, "unable to tokenize macro definition", .{}), + }; + const rp = makeRestorePoint(c); + + var it = tok_list.iterator(0); + const first_tok = it.next().?; + assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); + const next = it.peek().?; + switch (next.id) { + .Identifier => { + // if it equals itself, ignore. for example, from stdio.h: + // #define stdin stdin + if (std.mem.eql(u8, name, next.bytes)) { + return; + } + }, + .Eof => { + // this means it is a macro without a value + // we don't care about such things + return; + }, + else => {}, + } + + const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const mut_tok = try appendToken(c, .Keyword_const, "const"); + const name_tok = try appendIdentifier(c, name); + + const eq_tok = try appendToken(c, .Equal, "="); + + const init_node = parseCExpr(rp, &it, source_loc) catch |err| switch (err) { + error.UnsupportedTranslation, + error.ParseError, + => return failDecl(c, source_loc, name, "unable to translate macro", .{}), + error.OutOfMemory => |e| return e, + }; + + const node = try c.a().create(ast.Node.VarDecl); + node.* = ast.Node.VarDecl{ + .doc_comments = null, + .visib_token = visib_tok, + .thread_local_token = null, + .name_token = name_tok, + .eq_token = eq_tok, + .mut_token = mut_tok, + .comptime_token = null, + .extern_export_token = null, + .lib_name = null, + .type_node = null, + .align_node = null, + .section_node = null, + .init_node = init_node, + .semicolon_token = try appendToken(c, .Semicolon, ";"), + }; + _ = try c.macro_table.put(name, &node.base); +} + +const ParseError = Error || error{ + ParseError, + UnsupportedTranslation, +}; + +fn parseCExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { + return parseCPrefixOpExpr(rp, it, source_loc); +} + +fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { + if (tok.id == .NumLitInt) { + if (tok.num_lit_suffix == .None) { + if (tok.bytes.len > 2 and tok.bytes[0] == '0') { + switch (tok.bytes[1]) { + '0'...'7' => { + // octal + return transCreateNodeInt(rp.c, try std.fmt.allocPrint(rp.c.a(), "0o{}", .{tok.bytes})); + }, + else => {}, + } + } + return transCreateNodeInt(rp.c, tok.bytes); + } + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) { + .U => "c_uint", + .L => "c_long", + .LU => "c_ulong", + .LL => "c_longlong", + .LLU => "c_ulonglong", + else => unreachable, + })); + _ = try appendToken(rp.c, .Comma, ","); + try cast_node.params.push(try transCreateNodeInt(rp.c, tok.bytes)); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return &cast_node.base; + } else if (tok.id == .NumLitFloat) { + if (tok.num_lit_suffix == .None) { + return transCreateNodeFloat(rp.c, tok.bytes); + } + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) { + .F => "f32", + .L => "f64", + else => unreachable, + })); + _ = try appendToken(rp.c, .Comma, ","); + try cast_node.params.push(try transCreateNodeFloat(rp.c, tok.bytes)); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return &cast_node.base; + } else + return revertAndWarn( + rp, + error.ParseError, + source_loc, + "expected number literal", + .{}, + ); +} + +fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { + const tok = it.next().?; + switch (tok.id) { + .CharLit => { + const buf = try rp.c.a().alloc(u8, tok.bytes.len + "''".len); + buf[0] = '\''; + writeEscapedString(buf[1..], tok.bytes); + buf[buf.len - 1] = '\''; + const token = try appendToken(rp.c, .CharLiteral, buf); + const node = try rp.c.a().create(ast.Node.CharLiteral); + node.* = ast.Node.CharLiteral{ + .token = token, + }; + return &node.base; + }, + .StrLit => { + const buf = try rp.c.a().alloc(u8, tok.bytes.len + "\"\"".len); + buf[0] = '"'; + writeEscapedString(buf[1..], tok.bytes); + buf[buf.len - 1] = '"'; + const token = try appendToken(rp.c, .StringLiteral, buf); + const node = try rp.c.a().create(ast.Node.StringLiteral); + node.* = ast.Node.StringLiteral{ + .token = token, + }; + return &node.base; + }, + .Minus => { + const node = try transCreateNodePrefixOp( + rp.c, + .Negation, + .Minus, + "-", + ); + node.rhs = try parseCNumLit(rp, it.next().?, source_loc); + return &node.base; + }, + .NumLitInt, .NumLitFloat => { + return parseCNumLit(rp, tok, source_loc); + }, + .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes), + .LParen => { + _ = try appendToken(rp.c, .LParen, "("); + const inner_node = try parseCExpr(rp, it, source_loc); + _ = try appendToken(rp.c, .RParen, ")"); + + return inner_node; // TODO + }, + else => return revertAndWarn( + rp, + error.UnsupportedTranslation, + source_loc, + "unable to translate C expr", + .{}, + ), + } +} + +fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { + var node = try parseCPrimaryExpr(rp, it, source_loc); + while (true) { + const tok = it.next().?; + switch (tok.id) { + .Dot => { + const name_tok = it.next().?; + if (name_tok.id != .Identifier) + return revertAndWarn( + rp, + error.ParseError, + source_loc, + "unable to translate C expr", + .{}, + ); + + const op_token = try appendToken(rp.c, .Period, "."); + const rhs = try transCreateNodeIdentifier(rp.c, tok.bytes); + const access_node = try rp.c.a().create(ast.Node.InfixOp); + access_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .Period, + .rhs = rhs, + }; + node = &access_node.base; + }, + .Shl => { + const rhs_node = try parseCPrimaryExpr(rp, it, source_loc); + + const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); + const rhs = try parseCPrimaryExpr(rp, it, source_loc); + const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); + bitshift_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BitShiftLeft, + .rhs = rhs, + }; + node = &bitshift_node.base; + }, + else => { + _ = it.prev(); + return node; + }, + } + } +} + +fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { + const op_tok = it.next().?; + + switch (op_tok.id) { + else => { + _ = it.prev(); + return try parseCSuffixOpExpr(rp, it, source_loc); + }, + } +} diff --git a/test/translate_c.zig b/test/translate_c.zig index 97cfc129f7..0f2a0e83e9 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -214,6 +214,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ Clear: c_int, \\ }, \\}; + , \\pub const OpenGLProcs = union_OpenGLProcs; }); @@ -280,9 +281,64 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ o, \\ p, \\}; + , \\pub const Baz = struct_Baz; }); + cases.add_2("#define a char literal", + \\#define A_CHAR 'a' + , &[_][]const u8{ + \\pub const A_CHAR = 'a'; + }); + + cases.add_2("comment after integer literal", + \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = 0x00000020; + }); + + cases.add_2("u integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); + }); + + cases.add_2("l integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); + }); + + cases.add_2("ul integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); + }); + + cases.add_2("lu integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); + }); + + cases.add_2("ll integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); + }); + + cases.add_2("ull integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); + }); + + cases.add_2("llu integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", @@ -314,7 +370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add("macro with left shift", + cases.add_both("macro with left shift", \\#define REDISMODULE_READ (1<<0) , &[_][]const u8{ \\pub const REDISMODULE_READ = 1 << 0; @@ -637,13 +693,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const A_CHAR = 97; }); - cases.add("#define an unsigned integer literal", + cases.add_both("#define an unsigned integer literal", \\#define CHANNEL_COUNT 24 , &[_][]const u8{ \\pub const CHANNEL_COUNT = 24; }); - cases.add("#define referencing another #define", + cases.add_both("#define referencing another #define", \\#define THING2 THING1 \\#define THING1 1234 , &[_][]const u8{ @@ -692,7 +748,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("#define string", + cases.add_both("#define string", \\#define foo "a string" , &[_][]const u8{ \\pub const foo = "a string"; @@ -788,7 +844,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const FOO_CHAR = 63; }); - cases.add("macro with parens around negative number", + cases.add_both("macro with parens around negative number", \\#define LUA_GLOBALSINDEX (-10002) , &[_][]const u8{ \\pub const LUA_GLOBALSINDEX = -10002; @@ -1732,7 +1788,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC( + cases.add_both( "u integer suffix after 0 (zero) in macro definition", "#define ZERO 0U", &[_][]const u8{ @@ -1740,7 +1796,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "l integer suffix after 0 (zero) in macro definition", "#define ZERO 0L", &[_][]const u8{ @@ -1748,7 +1804,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "ul integer suffix after 0 (zero) in macro definition", "#define ZERO 0UL", &[_][]const u8{ @@ -1756,7 +1812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "lu integer suffix after 0 (zero) in macro definition", "#define ZERO 0LU", &[_][]const u8{ @@ -1764,7 +1820,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "ll integer suffix after 0 (zero) in macro definition", "#define ZERO 0LL", &[_][]const u8{ @@ -1772,7 +1828,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "ull integer suffix after 0 (zero) in macro definition", "#define ZERO 0ULL", &[_][]const u8{ @@ -1780,7 +1836,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.add_both( "llu integer suffix after 0 (zero) in macro definition", "#define ZERO 0LLU", &[_][]const u8{ @@ -1788,7 +1844,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC( + cases.addC(//todo "bitwise not on u-suffixed 0 (zero) in macro definition", "#define NOT_ZERO (~0U)", &[_][]const u8{ From 57170f9eb662f17f361ebf4cd19f86283a80b74f Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 16:50:20 +0200 Subject: [PATCH 3/9] translate-c-2 macro inline fn --- src-self-hosted/translate_c.zig | 219 ++++++++++++++++++++++++++------ test/translate_c.zig | 60 ++++++++- 2 files changed, 239 insertions(+), 40 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index c36d0f3d5e..f1232d65da 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -33,8 +33,7 @@ fn addrEql(a: usize, b: usize) bool { return a == b; } -const MacroTable = std.StringHashMap(*ast.Node); -const SymbolTable = std.StringHashMap(void); +const SymbolTable = std.StringHashMap(*ast.Node); const AliasList = std.SegmentedList(struct { alias: []const u8, name: []const u8, @@ -109,7 +108,7 @@ const Context = struct { decl_table: DeclTable, alias_list: AliasList, sym_table: SymbolTable, - macro_table: MacroTable, + macro_table: SymbolTable, global_scope: *Scope.Root, ptr_params: std.BufSet, clang_context: *ZigClangASTContext, @@ -197,7 +196,7 @@ pub fn translate( .decl_table = DeclTable.init(arena), .alias_list = AliasList.init(arena), .sym_table = SymbolTable.init(arena), - .macro_table = MacroTable.init(arena), + .macro_table = SymbolTable.init(arena), .global_scope = try arena.create(Scope.Root), .ptr_params = std.BufSet.init(arena), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, @@ -215,11 +214,7 @@ pub fn translate( try transPreprocessorEntities(&context, ast_unit); - var macro_it = context.macro_table.iterator(); - while (macro_it.next()) |kv| { - try addTopLevelDecl(&context, kv.key, kv.value); - } - + try addMacros(&context); var it = context.alias_list.iterator(0); while (it.next()) |alias| { if (!context.sym_table.contains(alias.alias)) { @@ -962,12 +957,11 @@ fn transReturnStmt( ) !TransResult { const node = try transCreateNodeReturnExpr(rp.c); if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { - const ret_node = node.cast(ast.Node.ControlFlowExpression).?; - ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node; + node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node; } _ = try appendToken(rp.c, .Semicolon, ";"); return TransResult{ - .node = node, + .node = &node.base, .child_scope = scope, .node_scope = scope, }; @@ -1327,7 +1321,7 @@ fn maybeSuppressResult( fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { try c.tree.root_node.decls.push(decl_node); - _ = try c.sym_table.put(name, {}); + _ = try c.sym_table.put(name, decl_node); } fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { @@ -1767,7 +1761,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { _ = try appendToken(c, .LParen, "("); const node = try c.a().create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ - .lhs = fn_expr, + .lhs = .{ .node = fn_expr }, .op = ast.Node.SuffixOp.Op{ .Call = ast.Node.SuffixOp.Op.Call{ .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), @@ -1881,7 +1875,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { return &node.base; } -fn transCreateNodeReturnExpr(c: *Context) !*ast.Node { +fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { const ltoken = try appendToken(c, .Keyword_return, "return"); const node = try c.a().create(ast.Node.ControlFlowExpression); node.* = ast.Node.ControlFlowExpression{ @@ -1889,7 +1883,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node { .kind = .Return, .rhs = null, }; - return &node.base; + return node; } fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { @@ -1959,6 +1953,100 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { return &call_node.base; } +fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node { + const pub_tok = try appendToken(c, .Keyword_pub, "pub"); + const inline_tok = try appendToken(c, .Keyword_inline, "inline"); + const fn_tok = try appendToken(c, .Keyword_fn, "fn"); + const name_tok = try appendIdentifier(c, name); + _ = try appendToken(c, .LParen, "("); + + const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?; + + var fn_params = ast.Node.FnProto.ParamList.init(c.a()); + var it = proto_alias.params.iterator(0); + while (it.next()) |pn| { + if (it.index != 0) { + _ = try appendToken(c, .Comma, ","); + } + const param = pn.*.cast(ast.Node.ParamDecl).?; + + const param_name_tok = param.name_token orelse + try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()}); + + _ = try appendToken(c, .Colon, ":"); + + const param_node = try c.a().create(ast.Node.ParamDecl); + param_node.* = .{ + .doc_comments = null, + .comptime_token = null, + .noalias_token = param.noalias_token, + .name_token = param_name_tok, + .type_node = param.type_node, + .var_args_token = null, + }; + try fn_params.push(¶m_node.base); + } + + _ = try appendToken(c, .RParen, ")"); + + const fn_proto = try c.a().create(ast.Node.FnProto); + fn_proto.* = .{ + .doc_comments = null, + .visib_token = pub_tok, + .fn_token = fn_tok, + .name_token = name_tok, + .params = fn_params, + .return_type = proto_alias.return_type, + .var_args_token = null, + .extern_export_inline_token = inline_tok, + .cc_token = null, + .body_node = null, + .lib_name = null, + .align_expr = null, + .section_expr = null, + }; + + const block = try c.a().create(ast.Node.Block); + block.* = .{ + .label = null, + .lbrace = try appendToken(c, .LBrace, "{"), + .statements = ast.Node.Block.StatementList.init(c.a()), + .rbrace = undefined, + }; + + const return_expr = try transCreateNodeReturnExpr(c); + const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); + const call_expr = try transCreateNodeFnCall(c, unwrap_expr); + it = fn_params.iterator(0); + while (it.next()) |pn| { + if (it.index != 0) { + _ = try appendToken(c, .Comma, ","); + } + const param = pn.*.cast(ast.Node.ParamDecl).?; + try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?))); + } + call_expr.rtoken = try appendToken(c, .RParen, ")"); + return_expr.rhs = &call_expr.base; + _ = try appendToken(c, .Semicolon, ";"); + + block.rbrace = try appendToken(c, .RBrace, "}"); + try block.statements.push(&return_expr.base); + fn_proto.body_node = &block.base; + return &fn_proto.base; +} + +fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { + _ = try appendToken(c, .Period, "."); + const qm = try appendToken(c, .QuestionMark, "?"); + const node = try c.a().create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ + .op = .UnwrapOptional, + .lhs = .{ .node = wrapped }, + .rtoken = qm, + }; + return &node.base; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -1982,28 +2070,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour switch (ZigClangType_getTypeClass(ty)) { .Builtin => { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - .Void => return transCreateNodeIdentifier(rp.c, "c_void"), - .Bool => return transCreateNodeIdentifier(rp.c, "bool"), - .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"), - .SChar => return transCreateNodeIdentifier(rp.c, "i8"), - .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"), - .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"), - .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"), - .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"), - .Short => return transCreateNodeIdentifier(rp.c, "c_short"), - .Int => return transCreateNodeIdentifier(rp.c, "c_int"), - .Long => return transCreateNodeIdentifier(rp.c, "c_long"), - .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"), - .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"), - .Int128 => return transCreateNodeIdentifier(rp.c, "i128"), - .Float => return transCreateNodeIdentifier(rp.c, "f32"), - .Double => return transCreateNodeIdentifier(rp.c, "f64"), - .Float128 => return transCreateNodeIdentifier(rp.c, "f128"), - .Float16 => return transCreateNodeIdentifier(rp.c, "f16"), - .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"), + return transCreateNodeIdentifier(rp.c, switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Void => "c_void", + .Bool => "bool", + .Char_U, .UChar, .Char_S, .Char8 => "u8", + .SChar => "i8", + .UShort => "c_ushort", + .UInt => "c_uint", + .ULong => "c_ulong", + .ULongLong => "c_ulonglong", + .Short => "c_short", + .Int => "c_int", + .Long => "c_long", + .LongLong => "c_longlong", + .UInt128 => "u128", + .Int128 => "i128", + .Float => "f32", + .Double => "f64", + .Float128 => "f128", + .Float16 => "f16", + .LongDouble => "c_longdouble", else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), - } + }); }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); @@ -2693,8 +2781,6 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc node = &access_node.base; }, .Shl => { - const rhs_node = try parseCPrimaryExpr(rp, it, source_loc); - const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); const rhs = try parseCPrimaryExpr(rp, it, source_loc); const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); @@ -2718,9 +2804,64 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc const op_tok = it.next().?; switch (op_tok.id) { + .Bang => { + const node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + return &node.base; + }, + .Minus => { + const node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-"); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + return &node.base; + }, + .Tilde => { + const node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~"); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + return &node.base; + }, else => { _ = it.prev(); return try parseCSuffixOpExpr(rp, it, source_loc); }, } } + +fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { + const tok = c.tree.tokens.at(token); + return c.source_buffer.toSliceConst()[tok.start..tok.end]; +} + +fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { + const init = ref.cast(ast.Node.VarDecl).?.init_node.?; + const name = if (init.cast(ast.Node.Identifier)) |id| + tokenSlice(c, id.token) + else + return null; + // TODO a.b.c + if (c.sym_table.get(name)) |kv| { + if (kv.value.cast(ast.Node.VarDecl)) |val| { + if (val.type_node) |type_node| { + if (type_node.cast(ast.Node.PrefixOp)) |casted| { + if (casted.rhs.id == .FnProto) { + return casted.rhs; + } + } + } + } + } + return null; +} + +fn addMacros(c: *Context) !void { + var macro_it = c.macro_table.iterator(); + while (macro_it.next()) |kv| { + if (getFnDecl(c, kv.value)) |proto_node| { + // If a macro aliases a global variable which is a function pointer, we conclude that + // the macro is intended to represent a function that assumes the function pointer + // variable is non-null and calls it. + try addTopLevelDecl(c, kv.key, try transCreateNodeMacroFn(c, kv.key, kv.value, proto_node)); + } else { + try addTopLevelDecl(c, kv.key, kv.value); + } + } +} diff --git a/test/translate_c.zig b/test/translate_c.zig index 0f2a0e83e9..201ab9993a 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -339,6 +339,64 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); }); + cases.add_2("generate inline func for #define global extern fn", + \\extern void (*fn_ptr)(void); + \\#define foo fn_ptr + \\ + \\extern char (*fn_ptr2)(int, float); + \\#define bar fn_ptr2 + , &[_][]const u8{ + \\pub extern var fn_ptr: ?extern fn () void; + , + \\pub inline fn foo() void { + \\ return fn_ptr.?(); + \\} + , + \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; + , + \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { + \\ return fn_ptr2.?(arg_1, arg_2); + \\} + }); + + cases.add_2("macros with field targets", + \\typedef unsigned int GLbitfield; + \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); + \\typedef void(*OpenGLProc)(void); + \\union OpenGLProcs { + \\ OpenGLProc ptr[1]; + \\ struct { + \\ PFNGLCLEARPROC Clear; + \\ } gl; + \\}; + \\extern union OpenGLProcs glProcs; + \\#define glClearUnion glProcs.gl.Clear + \\#define glClearPFN PFNGLCLEARPROC + , &[_][]const u8{ + \\pub const GLbitfield = c_uint; + , + \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; + , + \\pub const OpenGLProc = ?extern fn () void; + , + \\pub const union_OpenGLProcs = extern union { + \\ ptr: [1]OpenGLProc, + \\ gl: extern struct { + \\ Clear: PFNGLCLEARPROC, + \\ }, + \\}; + , + \\pub extern var glProcs: union_OpenGLProcs; + , + \\pub const glClearPFN = PFNGLCLEARPROC; + // , // TODO + // \\pub inline fn glClearUnion(arg_1: GLbitfield) void { + // \\ return glProcs.gl.Clear.?(arg_1); + // \\} + , + \\pub const OpenGLProcs = union_OpenGLProcs; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", @@ -1844,7 +1902,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC(//todo + cases.add_both( "bitwise not on u-suffixed 0 (zero) in macro definition", "#define NOT_ZERO (~0U)", &[_][]const u8{ From ed2a19dcecf5470ae2529e0fc7f86bf89d532162 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 21:32:30 +0200 Subject: [PATCH 4/9] translate-c-2 macro cast --- src-self-hosted/c_tokenizer.zig | 5 + src-self-hosted/translate_c.zig | 173 +++++++++++++++++++++++++++++--- test/translate_c.zig | 6 ++ 3 files changed, 169 insertions(+), 15 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 704cd268f7..426ff61fe6 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -25,6 +25,7 @@ pub const CToken = struct { Tilde, Shl, Lt, + Comma, }; pub const NumLitSuffix = enum { @@ -191,6 +192,10 @@ fn next(chars: [*]const u8, i: *usize) !CToken { result.id = .Tilde; return result; }, + ',' => { + result.id = .Comma; + return result; + }, else => return error.TokenizingFailed, } }, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index f1232d65da..3934aca275 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2039,7 +2039,7 @@ fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { _ = try appendToken(c, .Period, "."); const qm = try appendToken(c, .QuestionMark, "?"); const node = try c.a().create(ast.Node.SuffixOp); - node.* = ast.Node.SuffixOp{ + node.* = .{ .op = .UnwrapOptional, .lhs = .{ .node = wrapped }, .rtoken = qm, @@ -2047,6 +2047,39 @@ fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { return &node.base; } +fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { + const node = try c.a().create(ast.Node.EnumLiteral); + node.* = .{ + .dot = try appendToken(c, .Period, "."), + .name = try appendIdentifier(c, name), + }; + return &node.base; +} + +fn transCreateNodeIf(c: *Context) !*ast.Node.If { + const if_tok = try appendToken(c, .Keyword_if, "if"); + _ = try appendToken(c, .LParen, "("); + const node = try c.a().create(ast.Node.If); + node.* = .{ + .if_token = if_tok, + .condition = undefined, + .payload = null, + .body = undefined, + .@"else" = null, + }; + return node; +} + +fn transCreateNodeElse(c: *Context) !*ast.Node.Else { + const node = try c.a().create(ast.Node.Else); + node.* = .{ + .else_token = try appendToken(c, .Keyword_else, "else"), + .payload = null, + .body = undefined, + }; + return node; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -2722,26 +2755,102 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: }; return &node.base; }, - .Minus => { - const node = try transCreateNodePrefixOp( - rp.c, - .Negation, - .Minus, - "-", - ); - node.rhs = try parseCNumLit(rp, it.next().?, source_loc); - return &node.base; - }, .NumLitInt, .NumLitFloat => { return parseCNumLit(rp, tok, source_loc); }, .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes), .LParen => { - _ = try appendToken(rp.c, .LParen, "("); const inner_node = try parseCExpr(rp, it, source_loc); - _ = try appendToken(rp.c, .RParen, ")"); - return inner_node; // TODO + // hack to get zig fmt to render a comma in builtin calls + _ = try appendToken(rp.c, .Comma, ","); + + if (it.peek().?.id == .RParen) { + _ = it.next(); + return inner_node; + } + + const node_to_cast = try parseCExpr(rp, it, source_loc); + + if (it.next().?.id != .RParen) { + return revertAndWarn( + rp, + error.ParseError, + source_loc, + "unable to translate C expr", + .{}, + ); + } + + //if (@typeId(@TypeOf(x)) == .Pointer) + // @ptrCast(dest, x) + //else if (@typeId(@TypeOf(x)) == .Integer) + // @intToPtr(dest, x) + //else + // @as(dest, x) + + const if_1 = try transCreateNodeIf(rp.c); + const type_id_1 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId"); + const type_of_1 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf"); + try type_id_1.params.push(&type_of_1.base); + try type_of_1.params.push(node_to_cast); + type_of_1.rparen_token = try appendToken(rp.c, .LParen, ")"); + type_id_1.rparen_token = try appendToken(rp.c, .LParen, ")"); + + const cmp_1 = try rp.c.a().create(ast.Node.InfixOp); + cmp_1.* = .{ + .op_token = try appendToken(rp.c, .EqualEqual, "=="), + .lhs = &type_id_1.base, + .op = .EqualEqual, + .rhs = try transCreateNodeEnumLiteral(rp.c, "Pointer"), + }; + if_1.condition = &cmp_1.base; + _ = try appendToken(rp.c, .LParen, ")"); + + const ptr_cast = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); + try ptr_cast.params.push(inner_node); + try ptr_cast.params.push(node_to_cast); + ptr_cast.rparen_token = try appendToken(rp.c, .LParen, ")"); + if_1.body = &ptr_cast.base; + + const else_1 = try transCreateNodeElse(rp.c); + if_1.@"else" = else_1; + + const if_2 = try transCreateNodeIf(rp.c); + const type_id_2 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId"); + const type_of_2 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf"); + try type_id_2.params.push(&type_of_2.base); + try type_of_2.params.push(node_to_cast); + type_of_2.rparen_token = try appendToken(rp.c, .LParen, ")"); + type_id_2.rparen_token = try appendToken(rp.c, .LParen, ")"); + + const cmp_2 = try rp.c.a().create(ast.Node.InfixOp); + cmp_2.* = .{ + .op_token = try appendToken(rp.c, .EqualEqual, "=="), + .lhs = &type_id_2.base, + .op = .EqualEqual, + .rhs = try transCreateNodeEnumLiteral(rp.c, "Int"), + }; + if_2.condition = &cmp_2.base; + else_1.body = &if_2.base; + _ = try appendToken(rp.c, .LParen, ")"); + + const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); + try int_to_ptr.params.push(inner_node); + try int_to_ptr.params.push(node_to_cast); + int_to_ptr.rparen_token = try appendToken(rp.c, .LParen, ")"); + if_2.body = &int_to_ptr.base; + + const else_2 = try transCreateNodeElse(rp.c); + if_2.@"else" = else_2; + + const as = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + try as.params.push(inner_node); + try as.params.push(node_to_cast); + as.rparen_token = try appendToken(rp.c, .LParen, ")"); + else_2.body = &as.base; + + return &if_1.base; }, else => return revertAndWarn( rp, @@ -2780,6 +2889,30 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc }; node = &access_node.base; }, + .Asterisk => { + if (it.peek().?.id == .RParen) { + // type *) + + // hack to get zig fmt to render a comma in builtin calls + _ = try appendToken(rp.c, .Comma, ","); + + const ptr = try transCreateNodePtrType(rp.c, false, false, .Identifier); + ptr.rhs = node; + return &ptr.base; + } else { + // expr * expr + const op_token = try appendToken(rp.c, .Asterisk, "*"); + const rhs = try parseCPrimaryExpr(rp, it, source_loc); + const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); + bitshift_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BitShiftLeft, + .rhs = rhs, + }; + node = &bitshift_node.base; + } + }, .Shl => { const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); const rhs = try parseCPrimaryExpr(rp, it, source_loc); @@ -2819,6 +2952,16 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); return &node.base; }, + .Asterisk => { + const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc); + const node = try rp.c.a().create(ast.Node.SuffixOp); + node.* = .{ + .lhs = .{ .node = prefix_op_expr }, + .op = .Deref, + .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"), + }; + return &node.base; + }, else => { _ = it.prev(); return try parseCSuffixOpExpr(rp, it, source_loc); @@ -2833,7 +2976,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { const init = ref.cast(ast.Node.VarDecl).?.init_node.?; - const name = if (init.cast(ast.Node.Identifier)) |id| + const name = if (init.cast(ast.Node.Identifier)) |id| tokenSlice(c, id.token) else return null; diff --git a/test/translate_c.zig b/test/translate_c.zig index 201ab9993a..163323d56c 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -397,6 +397,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const OpenGLProcs = union_OpenGLProcs; }); + cases.add_2("macro pointer cast", + \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) + , &[_][]const u8{ + \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", From 9f0e83a5710a85273f12b7e9ecf68c93e0f763e8 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Dec 2019 23:46:35 +0200 Subject: [PATCH 5/9] translate-c-2 macro functions --- src-self-hosted/c_tokenizer.zig | 16 ++- src-self-hosted/translate_c.zig | 181 ++++++++++++++++++++++++-------- test/translate_c.zig | 8 ++ 3 files changed, 162 insertions(+), 43 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 426ff61fe6..f14f26ae55 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -26,6 +26,7 @@ pub const CToken = struct { Shl, Lt, Comma, + Fn, }; pub const NumLitSuffix = enum { @@ -41,11 +42,22 @@ pub const CToken = struct { pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void { var index: usize = 0; + var first = true; while (true) { const tok = try next(chars, &index); try tl.push(tok); if (tok.id == .Eof) return; + if (first) { + // distinguish NAME (EXPR) from NAME(ARGS) + first = false; + if (chars[index] == '(') { + try tl.push(.{ + .id = .Fn, + .bytes = "", + }); + } + } } } @@ -515,10 +527,12 @@ test "tokenize macro" { var tl = TokenList.init(std.heap.page_allocator); defer tl.deinit(); - const src = "TEST 0\n"; + const src = "TEST(0\n"; try tokenizeCMacro(&tl, src); var it = tl.iterator(0); expect(it.next().?.id == .Identifier); + expect(it.next().?.id == .Fn); + expect(it.next().?.id == .LParen); expect(std.mem.eql(u8, it.next().?.bytes, "0")); expect(it.next().?.id == .Eof); expect(it.next() == null); diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 3934aca275..4dcf03b5a3 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2585,11 +2585,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { while (it.I != it_end.I) : (it.I += 1) { const entity = ZigClangPreprocessingRecord_iterator_deref(it); tok_list.shrink(0); - switch (ZigClangPreprocessedEntity_getKind(entity)) { - .MacroExpansionKind => { - // TODO - }, .MacroDefinitionKind => { const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); @@ -2599,54 +2595,64 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { // if (name_exists_global(c, name)) { // TODO // continue; // } - const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); - try transMacroDefine(c, &tok_list, name, begin_c, begin_loc); + ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + else => { + try failDecl(c, begin_loc, name, "unable to tokenize macro definition", .{}); + continue; + }, + }; + + var tok_it = tok_list.iterator(0); + const first_tok = tok_it.next().?; + assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); + const next = tok_it.peek().?; + switch (next.id) { + .Identifier => { + // if it equals itself, ignore. for example, from stdio.h: + // #define stdin stdin + if (std.mem.eql(u8, name, next.bytes)) { + continue; + } + }, + .Eof => { + // this means it is a macro without a value + // we don't care about such things + continue; + }, + else => {}, + } + const macro_fn = if (tok_it.peek().?.id == .Fn) blk: { + _ = tok_it.next(); + break :blk true; + } else false; + + (if (macro_fn) + transMacroFnDefine(c, &tok_it, name, begin_c, begin_loc) + else + transMacroDefine(c, &tok_it, name, begin_c, begin_loc)) catch |err| switch (err) { + error.UnsupportedTranslation, + error.ParseError, + => try failDecl(c, begin_loc, name, "unable to translate macro", .{}), + error.OutOfMemory => |e| return e, + }; }, else => {}, } } } -fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) Error!void { - ctok.tokenizeCMacro(tok_list, char_ptr) catch |err| switch (err) { - error.OutOfMemory => |e| return e, - else => return failDecl(c, source_loc, name, "unable to tokenize macro definition", .{}), - }; +fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { const rp = makeRestorePoint(c); - var it = tok_list.iterator(0); - const first_tok = it.next().?; - assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); - const next = it.peek().?; - switch (next.id) { - .Identifier => { - // if it equals itself, ignore. for example, from stdio.h: - // #define stdin stdin - if (std.mem.eql(u8, name, next.bytes)) { - return; - } - }, - .Eof => { - // this means it is a macro without a value - // we don't care about such things - return; - }, - else => {}, - } - const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); - const init_node = parseCExpr(rp, &it, source_loc) catch |err| switch (err) { - error.UnsupportedTranslation, - error.ParseError, - => return failDecl(c, source_loc, name, "unable to translate macro", .{}), - error.OutOfMemory => |e| return e, - }; + const init_node = try parseCExpr(rp, it, source_loc); const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ @@ -2668,6 +2674,97 @@ fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, ch _ = try c.macro_table.put(name, &node.base); } +fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { + const rp = makeRestorePoint(c); + const pub_tok = try appendToken(c, .Keyword_pub, "pub"); + const inline_tok = try appendToken(c, .Keyword_inline, "inline"); + const fn_tok = try appendToken(c, .Keyword_fn, "fn"); + const name_tok = try appendIdentifier(c, name); + _ = try appendToken(c, .LParen, "("); + + if (it.next().?.id != .LParen) { + return error.ParseError; + } + var fn_params = ast.Node.FnProto.ParamList.init(c.a()); + while (true) { + const param_tok = it.next().?; + if (param_tok.id != .Identifier) + return error.ParseError; + + // TODO avoid name collisions + const param_name_tok = try appendIdentifier(c, param_tok.bytes); + _ = try appendToken(c, .Colon, ":"); + + const token_index = try appendToken(c, .Keyword_var, "var"); + const identifier = try c.a().create(ast.Node.Identifier); + identifier.* = ast.Node.Identifier{ + .base = ast.Node{ .id = ast.Node.Id.Identifier }, + .token = token_index, + }; + + const param_node = try c.a().create(ast.Node.ParamDecl); + param_node.* = .{ + .doc_comments = null, + .comptime_token = null, + .noalias_token = null, + .name_token = param_name_tok, + .type_node = &identifier.base, + .var_args_token = null, + }; + try fn_params.push(¶m_node.base); + + if (it.peek().?.id != .Comma) + break; + _ = it.next(); + _ = try appendToken(c, .Comma, ","); + } + + if (it.next().?.id != .RParen) { + return error.ParseError; + } + + _ = try appendToken(c, .RParen, ")"); + + const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); + type_of.rparen_token = try appendToken(c, .LParen, ")"); + + const fn_proto = try c.a().create(ast.Node.FnProto); + fn_proto.* = .{ + .visib_token = pub_tok, + .extern_export_inline_token = inline_tok, + .fn_token = fn_tok, + .name_token = name_tok, + .params = fn_params, + .return_type = .{ .Explicit = &type_of.base }, + .doc_comments = null, + .var_args_token = null, + .cc_token = null, + .body_node = null, + .lib_name = null, + .align_expr = null, + .section_expr = null, + }; + + const block = try c.a().create(ast.Node.Block); + block.* = .{ + .label = null, + .lbrace = try appendToken(c, .LBrace, "{"), + .statements = ast.Node.Block.StatementList.init(c.a()), + .rbrace = undefined, + }; + + const return_expr = try transCreateNodeReturnExpr(c); + const expr = try parseCExpr(rp, it, source_loc); + _ = try appendToken(c, .Semicolon, ";"); + try type_of.params.push(expr); + return_expr.rhs = expr; + + block.rbrace = try appendToken(c, .RBrace, "}"); + try block.statements.push(&return_expr.base); + fn_proto.body_node = &block.base; + _ = try c.macro_table.put(name, &fn_proto.base); +} + const ParseError = Error || error{ ParseError, UnsupportedTranslation, @@ -2762,14 +2859,14 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: .LParen => { const inner_node = try parseCExpr(rp, it, source_loc); - // hack to get zig fmt to render a comma in builtin calls - _ = try appendToken(rp.c, .Comma, ","); - if (it.peek().?.id == .RParen) { _ = it.next(); return inner_node; } + // hack to get zig fmt to render a comma in builtin calls + _ = try appendToken(rp.c, .Comma, ","); + const node_to_cast = try parseCExpr(rp, it, source_loc); if (it.next().?.id != .RParen) { @@ -2879,7 +2976,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc ); const op_token = try appendToken(rp.c, .Period, "."); - const rhs = try transCreateNodeIdentifier(rp.c, tok.bytes); + const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); const access_node = try rp.c.a().create(ast.Node.InfixOp); access_node.* = .{ .op_token = op_token, @@ -2975,7 +3072,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { } fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { - const init = ref.cast(ast.Node.VarDecl).?.init_node.?; + const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; const name = if (init.cast(ast.Node.Identifier)) |id| tokenSlice(c, id.token) else diff --git a/test/translate_c.zig b/test/translate_c.zig index 163323d56c..f603dd3837 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -403,6 +403,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); }); + cases.add_2("basic macro function", + \\#define BASIC(c) (c*2) + , &[_][]const u8{ + \\pub inline fn BASIC(c: var) @TypeOf(c * 2) { + \\ return c * 2; + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", From ab60c8e28fb89e33b094e457d477a19d1f015c62 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 16 Dec 2019 00:22:41 +0200 Subject: [PATCH 6/9] c tokenizer escape sequences --- src-self-hosted/c_tokenizer.zig | 89 +++++++++++++++++++++++++++++++-- src-self-hosted/clang.zig | 2 +- src-self-hosted/translate_c.zig | 20 +++----- test/translate_c.zig | 9 ++++ 4 files changed, 100 insertions(+), 20 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index f14f26ae55..2aea0d57d3 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -40,12 +40,15 @@ pub const CToken = struct { }; }; -pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void { +pub fn tokenizeCMacro(tl: *TokenList, chars: [*:0]const u8) !void { var index: usize = 0; var first = true; while (true) { const tok = try next(chars, &index); - try tl.push(tok); + if (tok.id == .StrLit or tok.id == .CharLit) + try tl.push(try zigifyEscapeSequences(tl.allocator, tok)) + else + try tl.push(tok); if (tok.id == .Eof) return; if (first) { @@ -61,7 +64,83 @@ pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void { } } -fn next(chars: [*]const u8, i: *usize) !CToken { +fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken { + for (tok.bytes) |c| { + if (c == '\\') { + break; + } + } else return tok; + var bytes = try allocator.alloc(u8, tok.bytes.len * 2); + var escape = false; + var i: usize = 0; + for (tok.bytes) |c| { + if (escape) { + switch (c) { + 'n', 'r', 't', '\\', '\'', '\"', 'x' => { + bytes[i] = c; + }, + 'a' => { + bytes[i] = 'x'; + i += 1; + bytes[i] = '0'; + i += 1; + bytes[i] = '7'; + }, + 'b' => { + bytes[i] = 'x'; + i += 1; + bytes[i] = '0'; + i += 1; + bytes[i] = '8'; + }, + 'f' => { + bytes[i] = 'x'; + i += 1; + bytes[i] = '0'; + i += 1; + bytes[i] = 'C'; + }, + 'v' => { + bytes[i] = 'x'; + i += 1; + bytes[i] = '0'; + i += 1; + bytes[i] = 'B'; + }, + '?' => { + i -= 1; + bytes[i] = '?'; + }, + 'u', 'U' => { + // TODO unicode escape sequences + return error.TokenizingFailed; + }, + '0'...'7' => { + // TODO octal escape sequences + return error.TokenizingFailed; + }, + else => { + // unknown escape sequence + return error.TokenizingFailed; + }, + } + i += 1; + escape = false; + } else { + if (c == '\\') { + escape = true; + } + bytes[i] = c; + i += 1; + } + } + return CToken{ + .id = tok.id, + .bytes = bytes[0..i], + }; +} + +fn next(chars: [*:0]const u8, i: *usize) !CToken { var state: enum { Start, GotLt, @@ -462,7 +541,7 @@ fn next(chars: [*]const u8, i: *usize) !CToken { .String => { // TODO char escapes switch (c) { '\"' => { - result.bytes = chars[begin_index + 1 .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; return result; }, else => {}, @@ -471,7 +550,7 @@ fn next(chars: [*]const u8, i: *usize) !CToken { .CharLit => { switch (c) { '\'' => { - result.bytes = chars[begin_index + 1 .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; return result; }, else => {}, diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 901660adce..ee76585f77 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -734,7 +734,7 @@ pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClang pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; -pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*c]const u8; +pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*:0]const u8; pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType; pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 4dcf03b5a3..43f0aa0853 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2629,9 +2629,9 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { } else false; (if (macro_fn) - transMacroFnDefine(c, &tok_it, name, begin_c, begin_loc) + transMacroFnDefine(c, &tok_it, name, begin_loc) else - transMacroDefine(c, &tok_it, name, begin_c, begin_loc)) catch |err| switch (err) { + transMacroDefine(c, &tok_it, name, begin_loc)) catch |err| switch (err) { error.UnsupportedTranslation, error.ParseError, => try failDecl(c, begin_loc, name, "unable to translate macro", .{}), @@ -2643,7 +2643,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { } } -fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { +fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { const rp = makeRestorePoint(c); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); @@ -2674,7 +2674,7 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, _ = try c.macro_table.put(name, &node.base); } -fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) ParseError!void { +fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { const rp = makeRestorePoint(c); const pub_tok = try appendToken(c, .Keyword_pub, "pub"); const inline_tok = try appendToken(c, .Keyword_inline, "inline"); @@ -2829,11 +2829,7 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: const tok = it.next().?; switch (tok.id) { .CharLit => { - const buf = try rp.c.a().alloc(u8, tok.bytes.len + "''".len); - buf[0] = '\''; - writeEscapedString(buf[1..], tok.bytes); - buf[buf.len - 1] = '\''; - const token = try appendToken(rp.c, .CharLiteral, buf); + const token = try appendToken(rp.c, .CharLiteral, tok.bytes); const node = try rp.c.a().create(ast.Node.CharLiteral); node.* = ast.Node.CharLiteral{ .token = token, @@ -2841,11 +2837,7 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: return &node.base; }, .StrLit => { - const buf = try rp.c.a().alloc(u8, tok.bytes.len + "\"\"".len); - buf[0] = '"'; - writeEscapedString(buf[1..], tok.bytes); - buf[buf.len - 1] = '"'; - const token = try appendToken(rp.c, .StringLiteral, buf); + const token = try appendToken(rp.c, .StringLiteral, tok.bytes); const node = try rp.c.a().create(ast.Node.StringLiteral); node.* = ast.Node.StringLiteral{ .token = token, diff --git a/test/translate_c.zig b/test/translate_c.zig index f603dd3837..7edbb0ea70 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -411,6 +411,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("macro escape sequences", + \\#define FOO "aoeu\xab derp" + \\#define FOO2 "aoeu\a derp" + , &[_][]const u8{ + \\pub const FOO = "aoeu\xab derp"; + , + \\pub const FOO2 = "aoeu\x07 derp"; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", From 620bf695e8d595c67acbf1457a8a14a7013a8522 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 16 Dec 2019 07:43:18 +0200 Subject: [PATCH 7/9] organize tests --- test/translate_c.zig | 780 +++++++++++++++++++++---------------------- 1 file changed, 382 insertions(+), 398 deletions(-) diff --git a/test/translate_c.zig b/test/translate_c.zig index 7edbb0ea70..51069b65d6 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -162,6 +162,270 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_both("enums", + \\enum Foo { + \\ FooA, + \\ FooB, + \\ Foo1, + \\}; + , &[_][]const u8{ + \\pub const enum_Foo = extern enum { + \\ A, + \\ B, + \\ @"1", + \\}; + , + \\pub const FooA = enum_Foo.A; + , + \\pub const FooB = enum_Foo.B; + , + \\pub const Foo1 = enum_Foo.@"1"; + , + \\pub const Foo = enum_Foo; + }); + + cases.add_both("enums", + \\enum Foo { + \\ FooA = 2, + \\ FooB = 5, + \\ Foo1, + \\}; + , &[_][]const u8{ + \\pub const enum_Foo = extern enum { + \\ A = 2, + \\ B = 5, + \\ @"1" = 6, + \\}; + , + \\pub const FooA = enum_Foo.A; + , + \\pub const FooB = enum_Foo.B; + , + \\pub const Foo1 = enum_Foo.@"1"; + , + \\pub const Foo = enum_Foo; + }); + + cases.add_both("typedef of function in struct field", + \\typedef void lws_callback_function(void); + \\struct Foo { + \\ void (*func)(void); + \\ lws_callback_function *callback_http; + \\}; + , &[_][]const u8{ + \\pub const lws_callback_function = extern fn () void; + \\pub const struct_Foo = extern struct { + \\ func: ?extern fn () void, + \\ callback_http: ?lws_callback_function, + \\}; + }); + + cases.add_both("pointer to struct demoted to opaque due to bit fields", + \\struct Foo { + \\ unsigned int: 1; + \\}; + \\struct Bar { + \\ struct Foo *foo; + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = @OpaqueType() + , + \\pub const struct_Bar = extern struct { + \\ foo: ?*struct_Foo, + \\}; + }); + + cases.add_both("macro with left shift", + \\#define REDISMODULE_READ (1<<0) + , &[_][]const u8{ + \\pub const REDISMODULE_READ = 1 << 0; + }); + + cases.add_both("double define struct", + \\typedef struct Bar Bar; + \\typedef struct Foo Foo; + \\ + \\struct Foo { + \\ Foo *a; + \\}; + \\ + \\struct Bar { + \\ Foo *a; + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ a: [*c]Foo, + \\}; + , + \\pub const Foo = struct_Foo; + , + \\pub const struct_Bar = extern struct { + \\ a: [*c]Foo, + \\}; + , + \\pub const Bar = struct_Bar; + }); + + cases.add_both("simple struct", + \\struct Foo { + \\ int x; + \\ char *y; + \\}; + , &[_][]const u8{ + \\const struct_Foo = extern struct { + \\ x: c_int, + \\ y: [*c]u8, + \\}; + , + \\pub const Foo = struct_Foo; + }); + + cases.add_both("self referential struct with function pointer", + \\struct Foo { + \\ void (*derp)(struct Foo *foo); + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ derp: ?extern fn ([*c]struct_Foo) void, + \\}; + , + \\pub const Foo = struct_Foo; + }); + + cases.add_both("struct prototype used in func", + \\struct Foo; + \\struct Foo *some_func(struct Foo *foo, int x); + , &[_][]const u8{ + \\pub const struct_Foo = @OpaqueType(); + , + \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; + , + \\pub const Foo = struct_Foo; + }); + + cases.add_both("#define an unsigned integer literal", + \\#define CHANNEL_COUNT 24 + , &[_][]const u8{ + \\pub const CHANNEL_COUNT = 24; + }); + + cases.add_both("#define referencing another #define", + \\#define THING2 THING1 + \\#define THING1 1234 + , &[_][]const u8{ + \\pub const THING1 = 1234; + , + \\pub const THING2 = THING1; + }); + + cases.add_both("circular struct definitions", + \\struct Bar; + \\ + \\struct Foo { + \\ struct Bar *next; + \\}; + \\ + \\struct Bar { + \\ struct Foo *next; + \\}; + , &[_][]const u8{ + \\pub const struct_Bar = extern struct { + \\ next: [*c]struct_Foo, + \\}; + , + \\pub const struct_Foo = extern struct { + \\ next: [*c]struct_Bar, + \\}; + }); + + cases.add_both("#define string", + \\#define foo "a string" + , &[_][]const u8{ + \\pub const foo = "a string"; + }); + + cases.add_both("zig keywords in C code", + \\struct comptime { + \\ int defer; + \\}; + , &[_][]const u8{ + \\pub const struct_comptime = extern struct { + \\ @"defer": c_int, + \\}; + , + \\pub const @"comptime" = struct_comptime; + }); + + cases.add_both("macro with parens around negative number", + \\#define LUA_GLOBALSINDEX (-10002) + , &[_][]const u8{ + \\pub const LUA_GLOBALSINDEX = -10002; + }); + + cases.add_both( + "u integer suffix after 0 (zero) in macro definition", + "#define ZERO 0U", + &[_][]const u8{ + "pub const ZERO = @as(c_uint, 0);", + }, + ); + + cases.add_both( + "l integer suffix after 0 (zero) in macro definition", + "#define ZERO 0L", + &[_][]const u8{ + "pub const ZERO = @as(c_long, 0);", + }, + ); + + cases.add_both( + "ul integer suffix after 0 (zero) in macro definition", + "#define ZERO 0UL", + &[_][]const u8{ + "pub const ZERO = @as(c_ulong, 0);", + }, + ); + + cases.add_both( + "lu integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LU", + &[_][]const u8{ + "pub const ZERO = @as(c_ulong, 0);", + }, + ); + + cases.add_both( + "ll integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LL", + &[_][]const u8{ + "pub const ZERO = @as(c_longlong, 0);", + }, + ); + + cases.add_both( + "ull integer suffix after 0 (zero) in macro definition", + "#define ZERO 0ULL", + &[_][]const u8{ + "pub const ZERO = @as(c_ulonglong, 0);", + }, + ); + + cases.add_both( + "llu integer suffix after 0 (zero) in macro definition", + "#define ZERO 0LLU", + &[_][]const u8{ + "pub const ZERO = @as(c_ulonglong, 0);", + }, + ); + + cases.add_both( + "bitwise not on u-suffixed 0 (zero) in macro definition", + "#define NOT_ZERO (~0U)", + &[_][]const u8{ + "pub const NOT_ZERO = ~@as(c_uint, 0);", + }, + ); + /////////////// Cases that pass for only stage2 //////////////// cases.add_2("Parameterless function prototypes", @@ -202,22 +466,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("field struct", - \\union OpenGLProcs { - \\ struct { - \\ int Clear; - \\ } gl; - \\}; - , &[_][]const u8{ - \\pub const union_OpenGLProcs = extern union { - \\ gl: extern struct { - \\ Clear: c_int, - \\ }, - \\}; - , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - cases.add_2("enums", \\typedef enum { \\ a, @@ -422,41 +670,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// - cases.add_both("typedef of function in struct field", - \\typedef void lws_callback_function(void); - \\struct Foo { - \\ void (*func)(void); - \\ lws_callback_function *callback_http; - \\}; - , &[_][]const u8{ - \\pub const lws_callback_function = extern fn () void; - \\pub const struct_Foo = extern struct { - \\ func: ?extern fn () void, - \\ callback_http: ?lws_callback_function, - \\}; - }); - - cases.add_both("pointer to struct demoted to opaque due to bit fields", - \\struct Foo { - \\ unsigned int: 1; - \\}; - \\struct Bar { - \\ struct Foo *foo; - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = @OpaqueType() - , - \\pub const struct_Bar = extern struct { - \\ foo: ?*struct_Foo, - \\}; - }); - - cases.add_both("macro with left shift", - \\#define REDISMODULE_READ (1<<0) - , &[_][]const u8{ - \\pub const REDISMODULE_READ = 1 << 0; - }); - if (builtin.os != builtin.Os.windows) { // Windows treats this as an enum with type c_int cases.add("big negative enum init values when C ABI supports long long enums", @@ -594,31 +807,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_both("double define struct", - \\typedef struct Bar Bar; - \\typedef struct Foo Foo; - \\ - \\struct Foo { - \\ Foo *a; - \\}; - \\ - \\struct Bar { - \\ Foo *a; - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ a: [*c]Foo, - \\}; - , - \\pub const Foo = struct_Foo; - , - \\pub const struct_Bar = extern struct { - \\ a: [*c]Foo, - \\}; - , - \\pub const Bar = struct_Bar; - }); - cases.addAllowWarnings("simple data types", \\#include \\int foo(char a, unsigned char b, signed char c); @@ -643,70 +831,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_both("enums", - \\enum Foo { - \\ FooA, - \\ FooB, - \\ Foo1, - \\}; - , &[_][]const u8{ - \\pub const enum_Foo = extern enum { - \\ A, - \\ B, - \\ @"1", - \\}; - , - \\pub const FooA = enum_Foo.A; - , - \\pub const FooB = enum_Foo.B; - , - \\pub const Foo1 = enum_Foo.@"1"; - , - \\pub const Foo = enum_Foo; - }); - - cases.add_both("enums", - \\enum Foo { - \\ FooA = 2, - \\ FooB = 5, - \\ Foo1, - \\}; - , &[_][]const u8{ - \\pub const enum_Foo = extern enum { - \\ A = 2, - \\ B = 5, - \\ @"1" = 6, - \\}; - , - \\pub const FooA = enum_Foo.A; - , - \\pub const FooB = enum_Foo.B; - , - \\pub const Foo1 = enum_Foo.@"1"; - , - \\pub const Foo = enum_Foo; - }); - cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , &[_][]const u8{ \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; }); - cases.add_both("simple struct", - \\struct Foo { - \\ int x; - \\ char *y; - \\}; - , &[_][]const u8{ - \\const struct_Foo = extern struct { - \\ x: c_int, - \\ y: [*c]u8, - \\}; - , - \\pub const Foo = struct_Foo; - }); - cases.add("qualified struct and enum", \\struct Foo { \\ int x; @@ -745,162 +875,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn func(array: [*c]c_int) void; }); - cases.add_both("self referential struct with function pointer", - \\struct Foo { - \\ void (*derp)(struct Foo *foo); - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ derp: ?extern fn ([*c]struct_Foo) void, - \\}; - , - \\pub const Foo = struct_Foo; - }); - - cases.add_both("struct prototype used in func", - \\struct Foo; - \\struct Foo *some_func(struct Foo *foo, int x); - , &[_][]const u8{ - \\pub const struct_Foo = @OpaqueType(); - , - \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; - , - \\pub const Foo = struct_Foo; - }); - - cases.add("#define a char literal", - \\#define A_CHAR 'a' - , &[_][]const u8{ - \\pub const A_CHAR = 97; - }); - - cases.add_both("#define an unsigned integer literal", - \\#define CHANNEL_COUNT 24 - , &[_][]const u8{ - \\pub const CHANNEL_COUNT = 24; - }); - - cases.add_both("#define referencing another #define", - \\#define THING2 THING1 - \\#define THING1 1234 - , &[_][]const u8{ - \\pub const THING1 = 1234; - , - \\pub const THING2 = THING1; - }); - - cases.add_both("circular struct definitions", - \\struct Bar; - \\ - \\struct Foo { - \\ struct Bar *next; - \\}; - \\ - \\struct Bar { - \\ struct Foo *next; - \\}; - , &[_][]const u8{ - \\pub const struct_Bar = extern struct { - \\ next: [*c]struct_Foo, - \\}; - , - \\pub const struct_Foo = extern struct { - \\ next: [*c]struct_Bar, - \\}; - }); - - cases.add("generate inline func for #define global extern fn", - \\extern void (*fn_ptr)(void); - \\#define foo fn_ptr - \\ - \\extern char (*fn_ptr2)(int, float); - \\#define bar fn_ptr2 - , &[_][]const u8{ - \\pub extern var fn_ptr: ?extern fn () void; - , - \\pub inline fn foo() void { - \\ return fn_ptr.?(); - \\} - , - \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; - , - \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { - \\ return fn_ptr2.?(arg0, arg1); - \\} - }); - - cases.add_both("#define string", - \\#define foo "a string" - , &[_][]const u8{ - \\pub const foo = "a string"; - }); - cases.add("__cdecl doesn't mess up function pointers", \\void foo(void (__cdecl *fn_ptr)(void)); , &[_][]const u8{ \\pub extern fn foo(fn_ptr: ?extern fn () void) void; }); - cases.add("comment after integer literal", - \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = 32; - }); - - cases.add("u integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); - }); - - cases.add("l integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_long, 32); - }); - - cases.add("ul integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); - }); - - cases.add("lu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); - }); - - cases.add("ll integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); - }); - - cases.add("ull integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); - }); - - cases.add("llu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); - }); - - cases.add_both("zig keywords in C code", - \\struct comptime { - \\ int defer; - \\}; - , &[_][]const u8{ - \\pub const struct_comptime = extern struct { - \\ @"defer": c_int, - \\}; - , - \\pub const @"comptime" = struct_comptime; - }); - cases.add("macro defines string literal with hex", \\#define FOO "aoeu\xab derp" \\#define FOO2 "aoeu\x0007a derp" @@ -925,12 +905,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const FOO_CHAR = 63; }); - cases.add_both("macro with parens around negative number", - \\#define LUA_GLOBALSINDEX (-10002) - , &[_][]const u8{ - \\pub const LUA_GLOBALSINDEX = -10002; - }); - cases.addC("post increment", \\unsigned foo1(unsigned a) { \\ a++; @@ -1658,44 +1632,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("macros with field targets", - \\typedef unsigned int GLbitfield; - \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); - \\typedef void(*OpenGLProc)(void); - \\union OpenGLProcs { - \\ OpenGLProc ptr[1]; - \\ struct { - \\ PFNGLCLEARPROC Clear; - \\ } gl; - \\}; - \\extern union OpenGLProcs glProcs; - \\#define glClearUnion glProcs.gl.Clear - \\#define glClearPFN PFNGLCLEARPROC - , &[_][]const u8{ - \\pub const GLbitfield = c_uint; - , - \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; - , - \\pub const OpenGLProc = ?extern fn () void; - , - \\pub const union_OpenGLProcs = extern union { - \\ ptr: [1]OpenGLProc, - \\ gl: extern struct { - \\ Clear: PFNGLCLEARPROC, - \\ }, - \\}; - , - \\pub extern var glProcs: union_OpenGLProcs; - , - \\pub const glClearPFN = PFNGLCLEARPROC; - , - \\pub inline fn glClearUnion(arg0: GLbitfield) void { - \\ return glProcs.gl.Clear.?(arg0); - \\} - , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - cases.add("variable name shadowing", \\int foo(void) { \\ int x = 1; @@ -1762,12 +1698,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("macro pointer cast", - \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) - , &[_][]const u8{ - \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); - }); - cases.add("if on non-bool", \\enum SomeEnum { A, B, C }; \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { @@ -1869,70 +1799,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_both( - "u integer suffix after 0 (zero) in macro definition", - "#define ZERO 0U", - &[_][]const u8{ - "pub const ZERO = @as(c_uint, 0);", - }, - ); - - cases.add_both( - "l integer suffix after 0 (zero) in macro definition", - "#define ZERO 0L", - &[_][]const u8{ - "pub const ZERO = @as(c_long, 0);", - }, - ); - - cases.add_both( - "ul integer suffix after 0 (zero) in macro definition", - "#define ZERO 0UL", - &[_][]const u8{ - "pub const ZERO = @as(c_ulong, 0);", - }, - ); - - cases.add_both( - "lu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LU", - &[_][]const u8{ - "pub const ZERO = @as(c_ulong, 0);", - }, - ); - - cases.add_both( - "ll integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LL", - &[_][]const u8{ - "pub const ZERO = @as(c_longlong, 0);", - }, - ); - - cases.add_both( - "ull integer suffix after 0 (zero) in macro definition", - "#define ZERO 0ULL", - &[_][]const u8{ - "pub const ZERO = @as(c_ulonglong, 0);", - }, - ); - - cases.add_both( - "llu integer suffix after 0 (zero) in macro definition", - "#define ZERO 0LLU", - &[_][]const u8{ - "pub const ZERO = @as(c_ulonglong, 0);", - }, - ); - - cases.add_both( - "bitwise not on u-suffixed 0 (zero) in macro definition", - "#define NOT_ZERO (~0U)", - &[_][]const u8{ - "pub const NOT_ZERO = ~@as(c_uint, 0);", - }, - ); - cases.addC("implicit casts", \\#include \\ @@ -2073,4 +1939,122 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn foo() void {} \\pub export fn bar() void {} }); + + cases.add("#define a char literal", + \\#define A_CHAR 'a' + , &[_][]const u8{ + \\pub const A_CHAR = 97; + }); + + cases.add("generate inline func for #define global extern fn", + \\extern void (*fn_ptr)(void); + \\#define foo fn_ptr + \\ + \\extern char (*fn_ptr2)(int, float); + \\#define bar fn_ptr2 + , &[_][]const u8{ + \\pub extern var fn_ptr: ?extern fn () void; + , + \\pub inline fn foo() void { + \\ return fn_ptr.?(); + \\} + , + \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; + , + \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { + \\ return fn_ptr2.?(arg0, arg1); + \\} + }); + cases.add("comment after integer literal", + \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = 32; + }); + + cases.add("u integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); + }); + + cases.add("l integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_long, 32); + }); + + cases.add("ul integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); + }); + + cases.add("lu integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); + }); + + cases.add("ll integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); + }); + + cases.add("ull integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); + }); + + cases.add("llu integer suffix after hex literal", + \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ + , &[_][]const u8{ + \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); + }); + + cases.add("macros with field targets", + \\typedef unsigned int GLbitfield; + \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); + \\typedef void(*OpenGLProc)(void); + \\union OpenGLProcs { + \\ OpenGLProc ptr[1]; + \\ struct { + \\ PFNGLCLEARPROC Clear; + \\ } gl; + \\}; + \\extern union OpenGLProcs glProcs; + \\#define glClearUnion glProcs.gl.Clear + \\#define glClearPFN PFNGLCLEARPROC + , &[_][]const u8{ + \\pub const GLbitfield = c_uint; + , + \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; + , + \\pub const OpenGLProc = ?extern fn () void; + , + \\pub const union_OpenGLProcs = extern union { + \\ ptr: [1]OpenGLProc, + \\ gl: extern struct { + \\ Clear: PFNGLCLEARPROC, + \\ }, + \\}; + , + \\pub extern var glProcs: union_OpenGLProcs; + , + \\pub const glClearPFN = PFNGLCLEARPROC; + , + \\pub inline fn glClearUnion(arg0: GLbitfield) void { + \\ return glProcs.gl.Clear.?(arg0); + \\} + , + \\pub const OpenGLProcs = union_OpenGLProcs; + }); + + cases.add("macro pointer cast", + \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) + , &[_][]const u8{ + \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); + }); + } From a37caaa5285ed6c040675a94dbd639e881ad72b6 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 16 Dec 2019 09:55:37 +0200 Subject: [PATCH 8/9] translate-c-2 parameter name aliasing --- src-self-hosted/clang.zig | 16 +- src-self-hosted/stage1.zig | 2 +- src-self-hosted/translate_c.zig | 350 ++++++++++++++++++++------------ test/translate_c.zig | 7 +- 4 files changed, 235 insertions(+), 140 deletions(-) diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index ee76585f77..b9435f96f4 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -764,14 +764,14 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator; pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl; pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool; -pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8; +pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*:0]const u8; pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool; pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl; pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType; pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType; pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass; pub extern fn ZigClangQualType_getTypePtr(self: struct_ZigClangQualType) *const struct_ZigClangType; -pub extern fn ZigClangQualType_addConst(self: [*c]struct_ZigClangQualType) void; +pub extern fn ZigClangQualType_addConst(self: *struct_ZigClangQualType) void; pub extern fn ZigClangQualType_eq(self: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool; pub extern fn ZigClangQualType_isConstQualified(self: struct_ZigClangQualType) bool; pub extern fn ZigClangQualType_isVolatileQualified(self: struct_ZigClangQualType) bool; @@ -799,7 +799,7 @@ pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool; pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool; pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt; pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void; -pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*c]const u64; +pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64; pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint; pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64; @@ -931,25 +931,25 @@ pub const struct_ZigClangAPValueLValueBase = extern struct { Version: c_uint, }; -pub extern fn ZigClangErrorMsg_delete(ptr: [*c]Stage2ErrorMsg, len: usize) void; +pub extern fn ZigClangErrorMsg_delete(ptr: [*]Stage2ErrorMsg, len: usize) void; pub extern fn ZigClangLoadFromCommandLine( args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, errors_ptr: *[*]Stage2ErrorMsg, errors_len: *usize, - resources_path: [*c]const u8, + resources_path: [*:0]const u8, ) ?*ZigClangASTUnit; pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8; -pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt; +pub const ZigClangCompoundStmt_const_body_iterator = [*]const *struct_ZigClangStmt; pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; -pub const ZigClangDeclStmt_const_decl_iterator = [*c]const *struct_ZigClangDecl; +pub const ZigClangDeclStmt_const_decl_iterator = [*]const *struct_ZigClangDecl; pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; @@ -1017,7 +1017,7 @@ pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigC pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType; pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind; -pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8; +pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*]const u8; pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr; diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index baa4c17ed0..6f1faa3f3f 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -93,7 +93,7 @@ export fn stage2_translate_c( out_errors_len: *usize, args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, - resources_path: [*]const u8, + resources_path: [*:0]const u8, ) Error { var errors: []translate_c.ClangErrMsg = undefined; out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 43f0aa0853..9135e9cc56 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -49,7 +49,9 @@ const Scope = struct { Block, Root, While, + FnDef, }; + const Switch = struct { base: Scope, }; @@ -65,21 +67,14 @@ const Scope = struct { block_node: *ast.Node.Block, /// Don't forget to set rbrace token later - fn create(c: *Context, parent: *Scope, lbrace_tok: ast.TokenIndex) !*Block { + fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block { const block = try c.a().create(Block); - block.* = Block{ - .base = Scope{ - .id = Id.Block, + block.* = .{ + .base = .{ + .id = .Block, .parent = parent, }, - .block_node = try c.a().create(ast.Node.Block), - }; - block.block_node.* = ast.Node.Block{ - .base = ast.Node{ .id = ast.Node.Id.Block }, - .label = null, - .lbrace = lbrace_tok, - .statements = ast.Node.Block.StatementList.init(c.a()), - .rbrace = undefined, + .block_node = block_node, }; return block; } @@ -87,11 +82,91 @@ const Scope = struct { const Root = struct { base: Scope, + sym_table: SymbolTable, + macro_table: SymbolTable, + + fn init(c: *Context) Root { + return .{ + .base = .{ + .id = .Root, + .parent = null, + }, + .sym_table = SymbolTable.init(c.a()), + .macro_table = SymbolTable.init(c.a()), + }; + } + + fn contains(scope: *Root, name: []const u8) bool { + return scope.sym_table.contains(name) or scope.macro_table.contains(name); + } }; const While = struct { base: Scope, }; + + const FnDef = struct { + base: Scope, + params: AliasList, + + fn init(c: *Context) FnDef { + return .{ + .base = .{ + .id = .FnDef, + .parent = &c.global_scope.base, + }, + .params = AliasList.init(c.a()), + }; + } + + fn getAlias(scope: *FnDef, name: []const u8) ?[]const u8 { + var it = scope.params.iterator(0); + while (it.next()) |p| { + if (std.mem.eql(u8, p.name, name)) + return p.alias; + } + return scope.base.parent.?.getAlias(name); + } + + fn contains(scope: *FnDef, name: []const u8) bool { + var it = scope.params.iterator(0); + while (it.next()) |p| { + if (std.mem.eql(u8, p.name, name)) + return true; + } + return scope.base.parent.?.contains(name); + } + }; + + fn findBlockScope(inner: *Scope) *Scope.Block { + var scope = inner; + while (true) : (scope = scope.parent orelse unreachable) { + if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope); + } + } + + fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 { + if (scope.contains(name)) { + return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }); + } + return null; + } + + fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { + return switch (scope.id) { + .Root => null, + .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), + else => @panic("TODO Scope.getAlias"), + }; + } + + fn contains(scope: *Scope, name: []const u8) bool { + return switch (scope.id) { + .Root => @fieldParentPtr(Root, "base", scope).contains(name), + .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), + else => @panic("TODO Scope.contains"), + }; + } }; const TransResult = struct { @@ -107,8 +182,6 @@ const Context = struct { source_manager: *ZigClangSourceManager, decl_table: DeclTable, alias_list: AliasList, - sym_table: SymbolTable, - macro_table: SymbolTable, global_scope: *Scope.Root, ptr_params: std.BufSet, clang_context: *ZigClangASTContext, @@ -145,7 +218,7 @@ pub fn translate( args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, errors: *[]ClangErrMsg, - resources_path: [*]const u8, + resources_path: [*:0]const u8, ) !*ast.Tree { const ast_unit = ZigClangLoadFromCommandLine( args_begin, @@ -195,18 +268,11 @@ pub fn translate( .err = undefined, .decl_table = DeclTable.init(arena), .alias_list = AliasList.init(arena), - .sym_table = SymbolTable.init(arena), - .macro_table = SymbolTable.init(arena), .global_scope = try arena.create(Scope.Root), .ptr_params = std.BufSet.init(arena), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, }; - context.global_scope.* = Scope.Root{ - .base = Scope{ - .id = Scope.Id.Root, - .parent = null, - }, - }; + context.global_scope.* = Scope.Root.init(&context); if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { return context.err; @@ -217,7 +283,7 @@ pub fn translate( try addMacros(&context); var it = context.alias_list.iterator(0); while (it.next()) |alias| { - if (!context.sym_table.contains(alias.alias)) { + if (!context.global_scope.sym_table.contains(alias.alias)) { try createAlias(&context, alias); } } @@ -276,7 +342,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); const fn_qt = ZigClangFunctionDecl_getType(fn_decl); const fn_type = ZigClangQualType_getTypePtr(fn_qt); - var scope = &c.global_scope.base; + var fndef_scope = Scope.FnDef.init(c); + var scope = &fndef_scope.base; const has_body = ZigClangFunctionDecl_hasBody(fn_decl); const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); const decl_ctx = FnDeclContext{ @@ -343,7 +410,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { else try appendToken(c, .Keyword_threadlocal, "threadlocal"); - var scope = &c.global_scope.base; + const scope = &c.global_scope.base; const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); @@ -364,7 +431,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { else try appendToken(c, .Keyword_var, "var"); - const name_tok = try appendIdentifier(c, var_name); + const name_tok = try appendIdentifier(c, var_name, null); _ = try appendToken(c, .Colon, ":"); const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { @@ -425,7 +492,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); - const name_tok = try appendIdentifier(c, typedef_name); + const name_tok = try appendIdentifier(c, typedef_name, null); const eq_tok = try appendToken(c, .Equal, "="); const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); @@ -478,7 +545,7 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); - const name_tok = try appendIdentifier(c, name); + const name_tok = try appendIdentifier(c, name, null); const eq_tok = try appendToken(c, .Equal, "="); const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { @@ -514,10 +581,10 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! fn createAlias(c: *Context, alias: var) !void { const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, alias.alias); + const name_tok = try appendIdentifier(c, alias.alias, null); const eq_tok = try appendToken(c, .Equal, "="); - const init_node = try transCreateNodeIdentifier(c, alias.name); + const init_node = try transCreateNodeIdentifier(c, alias.name, null); const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ @@ -731,7 +798,7 @@ fn transCompoundStmtInline( const end_it = ZigClangCompoundStmt_body_end(stmt); var scope = parent_scope; while (it != end_it) : (it += 1) { - const result = try transStmt(rp, parent_scope, it.*, .unused, .r_value); + const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); scope = result.child_scope; if (result.node != &block_node.base) try block_node.statements.push(result.node); @@ -743,13 +810,13 @@ fn transCompoundStmtInline( }; } -fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) !TransResult { - const lbrace_tok = try appendToken(rp.c, .LBrace, "{"); - const block_scope = try Scope.Block.create(rp.c, scope, lbrace_tok); - const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); +fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!TransResult { + const block_node = try transCreateNodeBlock(rp.c, null, null); + const block_scope = try Scope.Block.init(rp.c, scope, block_node); + const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); + block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); return TransResult{ - .node = &block_scope.block_node.base, + .node = &block_node.base, .node_scope = inline_result.node_scope, .child_scope = inline_result.child_scope, }; @@ -779,17 +846,17 @@ fn transCStyleCastExprClass( return maybeSuppressResult(rp, scope, result_used, cast_res); } -fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) !TransResult { +fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!TransResult { const c = rp.c; - const block_scope = findBlockScope(parent_scope); + const block_scope = parent_scope.findBlockScope(); var scope = parent_scope; var it = ZigClangDeclStmt_decl_begin(stmt); const end_it = ZigClangDeclStmt_decl_end(stmt); while (it != end_it) : (it += 1) { - switch (ZigClangDecl_getKind(it.*)) { + switch (ZigClangDecl_getKind(it[0])) { .Var => { - const var_decl = @ptrCast(*const ZigClangVarDecl, it.*); + const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]); const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) null @@ -803,7 +870,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe const c_name = try c.str(ZigClangDecl_getName_bytes_begin( @ptrCast(*const ZigClangDecl, var_decl), )); - const name_token = try appendIdentifier(c, c_name); + const name_token = try appendIdentifier(c, c_name, null); // TODO parent_scope); const var_scope = try c.a().create(Scope.Var); var_scope.* = Scope.Var{ @@ -871,7 +938,7 @@ fn transDeclRefExpr( const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); const zig_name = transLookupZigIdentifier(scope, c_name); if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name); - const node = try transCreateNodeIdentifier(rp.c, zig_name); + const node = try transCreateNodeIdentifier(rp.c, zig_name, null); // TODO scope); return TransResult{ .node = node, .node_scope = scope, @@ -1240,13 +1307,6 @@ fn transImplicitValueInitExpr( }; } -fn findBlockScope(inner: *Scope) *Scope.Block { - var scope = inner; - while (true) : (scope = scope.parent orelse unreachable) { - if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope); - } -} - fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { var scope = inner; while (true) : (scope = scope.parent orelse return c_name) { @@ -1303,7 +1363,7 @@ fn maybeSuppressResult( if (used == .used) return result; // NOTE: This is backwards, but the semicolon must immediately follow the node. _ = try appendToken(rp.c, .Semicolon, ";"); - const lhs = try transCreateNodeIdentifier(rp.c, "_"); + const lhs = try transCreateNodeIdentifier(rp.c, "_", null); const op_token = try appendToken(rp.c, .Equal, "="); const op_node = try rp.c.a().create(ast.Node.InfixOp); op_node.* = ast.Node.InfixOp{ @@ -1321,7 +1381,7 @@ fn maybeSuppressResult( fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { try c.tree.root_node.decls.push(decl_node); - _ = try c.sym_table.put(name, decl_node); + _ = try c.global_scope.sym_table.put(name, decl_node); } fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { @@ -1383,7 +1443,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro return node; } - const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); + const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))), null); _ = try appendToken(c, .Colon, ":"); const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); @@ -1407,7 +1467,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| - return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice + return try transCreateNodeIdentifier(c, name.value, null); // Avoid processing this decl twice const rp = makeRestorePoint(c); const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); @@ -1423,7 +1483,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); - const name_tok = try appendIdentifier(c, name); + const name_tok = try appendIdentifier(c, name, null); const eq_tok = try appendToken(c, .Equal, "="); const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { @@ -1490,7 +1550,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No else enum_val_name; - const field_name_tok = try appendIdentifier(c, field_name); + const field_name_tok = try appendIdentifier(c, field_name, null); const int_node = if (!pure_enum) blk: { _ = try appendToken(c, .Colon, "="); @@ -1543,18 +1603,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No try addTopLevelDecl(c, name, &node.base); if (!is_unnamed) try c.alias_list.push(.{ .alias = bare_name, .name = name }); - return transCreateNodeIdentifier(c, name); + return transCreateNodeIdentifier(c, name, null); } fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const const_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, enum_val_name); + const name_tok = try appendIdentifier(c, enum_val_name, null); const eq_tok = try appendToken(c, .Equal, "="); - const enum_ident = try transCreateNodeIdentifier(c, enum_name); + const enum_ident = try transCreateNodeIdentifier(c, enum_name, null); const period_tok = try appendToken(c, .Period, "."); - const field_ident = try transCreateNodeIdentifier(c, field_name); + const field_ident = try transCreateNodeIdentifier(c, field_name, null); const field_access_node = try c.a().create(ast.Node.InfixOp); field_access_node.* = .{ @@ -1836,7 +1896,7 @@ fn transCreateNodePtrType( .Identifier => blk: { const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token _ = try appendToken(c, .Asterisk, "*"); - _ = try appendIdentifier(c, "c"); + _ = try appendIdentifier(c, "c", null); // not really an identifier _ = try appendToken(c, .RBracket, "]"); break :blk lbracket; }, @@ -1954,10 +2014,12 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { } fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node { + const scope = &c.global_scope.base; + const pub_tok = try appendToken(c, .Keyword_pub, "pub"); const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); - const name_tok = try appendIdentifier(c, name); + const name_tok = try appendIdentifier(c, name, null); _ = try appendToken(c, .LParen, "("); const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?; @@ -2006,13 +2068,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a .section_expr = null, }; - const block = try c.a().create(ast.Node.Block); - block.* = .{ - .label = null, - .lbrace = try appendToken(c, .LBrace, "{"), - .statements = ast.Node.Block.StatementList.init(c.a()), - .rbrace = undefined, - }; + const block = try transCreateNodeBlock(c, null, null); const return_expr = try transCreateNodeReturnExpr(c); const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); @@ -2023,7 +2079,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a _ = try appendToken(c, .Comma, ","); } const param = pn.*.cast(ast.Node.ParamDecl).?; - try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?))); + try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?), null)); } call_expr.rtoken = try appendToken(c, .RParen, ")"); return_expr.rhs = &call_expr.base; @@ -2051,7 +2107,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { const node = try c.a().create(ast.Node.EnumLiteral); node.* = .{ .dot = try appendToken(c, .Period, "."), - .name = try appendIdentifier(c, name), + .name = try appendIdentifier(c, name, null), // scoped to an enum }; return &node.base; } @@ -2080,6 +2136,22 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { return node; } +fn transCreateNodeBlock(c: *Context, label: ?[]const u8, scope: ?*Scope) !*ast.Node.Block { + const label_node = if (label) |l| blk: { + const ll = try appendIdentifier(c, l, scope); + _ = try appendToken(c, .Colon, ":"); + break :blk ll; + } else null; + const block_node = try c.a().create(ast.Node.Block); + block_node.* = .{ + .label = label_node, + .lbrace = try appendToken(c, .LBrace, "{"), + .statements = ast.Node.Block.StatementList.init(c.a()), + .rbrace = undefined, + }; + return block_node; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -2124,7 +2196,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour .Float16 => "f16", .LongDouble => "c_longdouble", else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), - }); + }, null); }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); @@ -2202,14 +2274,21 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - return transCreateNodeIdentifier(rp.c, typedef_name); + return transCreateNodeIdentifier(rp.c, typedef_name, null); }, .Record => { const record_ty = @ptrCast(*const ZigClangRecordType, ty); + // TODO this sould get the name from decl_table + // struct Foo { + // struct Bar{ + // int b; + // }; + // struct Bar c; + // }; const record_decl = ZigClangRecordType_getDecl(record_ty); if (try getContainerName(rp, record_decl)) |name| - return transCreateNodeIdentifier(rp.c, name) + return transCreateNodeIdentifier(rp.c, name, null) else return transRecordDecl(rp.c, record_decl); }, @@ -2334,6 +2413,9 @@ fn finishTransFnProto( // TODO check for always_inline attribute // TODO check for align attribute + var fndef_scope = Scope.FnDef.init(rp.c); + const scope = &fndef_scope.base; + // pub extern fn name(...) T const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; @@ -2344,7 +2426,7 @@ fn finishTransFnProto( else null; const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); - const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; + const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name, null) else null; const lparen_tok = try appendToken(rp.c, .LParen, "("); var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a()); @@ -2359,13 +2441,17 @@ fn finishTransFnProto( const param_name_tok: ?ast.TokenIndex = blk: { if (fn_decl != null) { const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i)); - const param_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); - if (param_name.len > 0) { - // TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank? - const result = try appendIdentifier(rp.c, param_name); - _ = try appendToken(rp.c, .Colon, ":"); - break :blk result; - } + var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); + if (param_name.len < 1) + param_name = "arg"[0..]; + const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: { + try fndef_scope.params.push(.{ .name = param_name, .alias = a }); + break :blk a; + } else param_name; + + const result = try appendIdentifier(rp.c, checked_param_name, null); + _ = try appendToken(rp.c, .Colon, ":"); + break :blk result; } break :blk null; }; @@ -2411,12 +2497,12 @@ fn finishTransFnProto( const return_type_node = blk: { if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { - break :blk try transCreateNodeIdentifier(rp.c, "noreturn"); + break :blk try transCreateNodeIdentifier(rp.c, "noreturn", null); } else { const return_qt = ZigClangFunctionType_getReturnType(fn_ty); if (isCVoid(return_qt)) { // convert primitive c_void to actual void (only for return type) - break :blk try transCreateNodeIdentifier(rp.c, "void"); + break :blk try transCreateNodeIdentifier(rp.c, "void", null); } else { break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { error.UnsupportedType => { @@ -2469,7 +2555,7 @@ fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []cons fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: var) !void { // const name = @compileError(msg); const const_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, name); + const name_tok = try appendIdentifier(c, name, null); const eq_tok = try appendToken(c, .Equal, "="); const builtin_tok = try appendToken(c, .Builtin, "@compileError"); const lparen_tok = try appendToken(c, .LParen, "("); @@ -2554,7 +2640,11 @@ fn isValidZigIdentifier(name: []const u8) bool { return true; } -fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { +fn appendIdentifier(c: *Context, name: []const u8, scope: ?*Scope) !ast.TokenIndex { + if (scope) |s| + if (s.getAlias(name)) |alias| { + return appendTokenFmt(c, .Identifier, "{}", .{alias}); + }; if (!isValidZigIdentifier(name) or std.zig.Token.getKeyword(name) != null) { return appendTokenFmt(c, .Identifier, "@\"{}\"", .{name}); } else { @@ -2562,8 +2652,8 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { } } -fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { - const token_index = try appendIdentifier(c, name); +fn transCreateNodeIdentifier(c: *Context, name: []const u8, scope: ?*Scope) !*ast.Node { + const token_index = try appendIdentifier(c, name, scope); const identifier = try c.a().create(ast.Node.Identifier); identifier.* = ast.Node.Identifier{ .base = ast.Node{ .id = ast.Node.Id.Identifier }, @@ -2581,6 +2671,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); var tok_list = ctok.TokenList.init(c.a()); + const scope = &c.global_scope.base; while (it.I != it_end.I) : (it.I += 1) { const entity = ZigClangPreprocessingRecord_iterator_deref(it); @@ -2592,9 +2683,9 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); const name = try c.str(raw_name); - // if (name_exists_global(c, name)) { // TODO - // continue; - // } + if (scope.contains(name)) { + continue; + } const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { error.OutOfMemory => |e| return e, @@ -2645,14 +2736,14 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { const rp = makeRestorePoint(c); + const scope = &c.global_scope.base; const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, name); - + const name_tok = try appendIdentifier(c, name, null); const eq_tok = try appendToken(c, .Equal, "="); - const init_node = try parseCExpr(rp, it, source_loc); + const init_node = try parseCExpr(rp, it, source_loc, scope); const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ @@ -2671,15 +2762,18 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, .init_node = init_node, .semicolon_token = try appendToken(c, .Semicolon, ";"), }; - _ = try c.macro_table.put(name, &node.base); + _ = try c.global_scope.macro_table.put(name, &node.base); } fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { const rp = makeRestorePoint(c); + var fndef_scope = Scope.FnDef.init(c); + const scope = &fndef_scope.base; + const pub_tok = try appendToken(c, .Keyword_pub, "pub"); const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); - const name_tok = try appendIdentifier(c, name); + const name_tok = try appendIdentifier(c, name, null); _ = try appendToken(c, .LParen, "("); if (it.next().?.id != .LParen) { @@ -2691,8 +2785,12 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u if (param_tok.id != .Identifier) return error.ParseError; - // TODO avoid name collisions - const param_name_tok = try appendIdentifier(c, param_tok.bytes); + const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: { + try fndef_scope.params.push(.{ .name = param_tok.bytes, .alias = alias }); + break :blk alias; + } else param_tok.bytes; + + const param_name_tok = try appendIdentifier(c, checked_name, null); _ = try appendToken(c, .Colon, ":"); const token_index = try appendToken(c, .Keyword_var, "var"); @@ -2745,16 +2843,10 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u .section_expr = null, }; - const block = try c.a().create(ast.Node.Block); - block.* = .{ - .label = null, - .lbrace = try appendToken(c, .LBrace, "{"), - .statements = ast.Node.Block.StatementList.init(c.a()), - .rbrace = undefined, - }; + const block = try transCreateNodeBlock(c, null, null); const return_expr = try transCreateNodeReturnExpr(c); - const expr = try parseCExpr(rp, it, source_loc); + const expr = try parseCExpr(rp, it, source_loc, scope); _ = try appendToken(c, .Semicolon, ";"); try type_of.params.push(expr); return_expr.rhs = expr; @@ -2762,7 +2854,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u block.rbrace = try appendToken(c, .RBrace, "}"); try block.statements.push(&return_expr.base); fn_proto.body_node = &block.base; - _ = try c.macro_table.put(name, &fn_proto.base); + _ = try c.global_scope.macro_table.put(name, &fn_proto.base); } const ParseError = Error || error{ @@ -2770,8 +2862,8 @@ const ParseError = Error || error{ UnsupportedTranslation, }; -fn parseCExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { - return parseCPrefixOpExpr(rp, it, source_loc); +fn parseCExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node { + return parseCPrefixOpExpr(rp, it, source_loc, scope); } fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { @@ -2796,7 +2888,7 @@ fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocati .LL => "c_longlong", .LLU => "c_ulonglong", else => unreachable, - })); + }, null)); _ = try appendToken(rp.c, .Comma, ","); try cast_node.params.push(try transCreateNodeInt(rp.c, tok.bytes)); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -2810,7 +2902,7 @@ fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocati .F => "f32", .L => "f64", else => unreachable, - })); + }, null)); _ = try appendToken(rp.c, .Comma, ","); try cast_node.params.push(try transCreateNodeFloat(rp.c, tok.bytes)); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -2825,7 +2917,7 @@ fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocati ); } -fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { +fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node { const tok = it.next().?; switch (tok.id) { .CharLit => { @@ -2847,9 +2939,9 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: .NumLitInt, .NumLitFloat => { return parseCNumLit(rp, tok, source_loc); }, - .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes), + .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes, scope), .LParen => { - const inner_node = try parseCExpr(rp, it, source_loc); + const inner_node = try parseCExpr(rp, it, source_loc, scope); if (it.peek().?.id == .RParen) { _ = it.next(); @@ -2859,7 +2951,7 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: // hack to get zig fmt to render a comma in builtin calls _ = try appendToken(rp.c, .Comma, ","); - const node_to_cast = try parseCExpr(rp, it, source_loc); + const node_to_cast = try parseCExpr(rp, it, source_loc, scope); if (it.next().?.id != .RParen) { return revertAndWarn( @@ -2951,8 +3043,8 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: } } -fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { - var node = try parseCPrimaryExpr(rp, it, source_loc); +fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node { + var node = try parseCPrimaryExpr(rp, it, source_loc, scope); while (true) { const tok = it.next().?; switch (tok.id) { @@ -2968,7 +3060,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc ); const op_token = try appendToken(rp.c, .Period, "."); - const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); + const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes, null); // TODO scope); const access_node = try rp.c.a().create(ast.Node.InfixOp); access_node.* = .{ .op_token = op_token, @@ -2991,7 +3083,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc } else { // expr * expr const op_token = try appendToken(rp.c, .Asterisk, "*"); - const rhs = try parseCPrimaryExpr(rp, it, source_loc); + const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); bitshift_node.* = .{ .op_token = op_token, @@ -3004,7 +3096,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc }, .Shl => { const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); - const rhs = try parseCPrimaryExpr(rp, it, source_loc); + const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); bitshift_node.* = .{ .op_token = op_token, @@ -3022,27 +3114,27 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc } } -fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { +fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node { const op_tok = it.next().?; switch (op_tok.id) { .Bang => { const node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); - node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope); return &node.base; }, .Minus => { const node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-"); - node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope); return &node.base; }, .Tilde => { const node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~"); - node.rhs = try parseCPrefixOpExpr(rp, it, source_loc); + node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope); return &node.base; }, .Asterisk => { - const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc); + const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); const node = try rp.c.a().create(ast.Node.SuffixOp); node.* = .{ .lhs = .{ .node = prefix_op_expr }, @@ -3053,7 +3145,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc }, else => { _ = it.prev(); - return try parseCSuffixOpExpr(rp, it, source_loc); + return try parseCSuffixOpExpr(rp, it, source_loc, scope); }, } } @@ -3070,7 +3162,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { else return null; // TODO a.b.c - if (c.sym_table.get(name)) |kv| { + if (c.global_scope.sym_table.get(name)) |kv| { if (kv.value.cast(ast.Node.VarDecl)) |val| { if (val.type_node) |type_node| { if (type_node.cast(ast.Node.PrefixOp)) |casted| { @@ -3085,7 +3177,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { } fn addMacros(c: *Context) !void { - var macro_it = c.macro_table.iterator(); + var macro_it = c.global_scope.macro_table.iterator(); while (macro_it.next()) |kv| { if (getFnDecl(c, kv.value)) |proto_node| { // If a macro aliases a global variable which is a function pointer, we conclude that diff --git a/test/translate_c.zig b/test/translate_c.zig index 51069b65d6..8363c3b79f 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -652,10 +652,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add_2("basic macro function", + \\extern int c; \\#define BASIC(c) (c*2) , &[_][]const u8{ - \\pub inline fn BASIC(c: var) @TypeOf(c * 2) { - \\ return c * 2; + \\pub extern var c: c_int; + , + \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) { + \\ return c_1 * 2; \\} }); From 04dc0bd0e4f7bc7c23e9d0e30b5d2b6153e2c0d5 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 16 Dec 2019 12:18:56 +0200 Subject: [PATCH 9/9] translate-c-2 variable aliasing --- src-self-hosted/c_tokenizer.zig | 2 +- src-self-hosted/translate_c.zig | 404 ++++++++++++-------------------- test/translate_c.zig | 33 ++- 3 files changed, 178 insertions(+), 261 deletions(-) diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 2aea0d57d3..9715661cd3 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -6,7 +6,7 @@ pub const TokenList = std.SegmentedList(CToken, 32); pub const CToken = struct { id: Id, bytes: []const u8, - num_lit_suffix: NumLitSuffix = undefined, + num_lit_suffix: NumLitSuffix = .None, pub const Id = enum { CharLit, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 9135e9cc56..9e156f1fb5 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -45,26 +45,26 @@ const Scope = struct { const Id = enum { Switch, - Var, Block, Root, While, FnDef, + Ref, }; const Switch = struct { base: Scope, }; - const Var = struct { + /// used when getting a member `a.b` + const Ref = struct { base: Scope, - c_name: []const u8, - zig_name: []const u8, }; const Block = struct { base: Scope, block_node: *ast.Node.Block, + variables: AliasList, /// Don't forget to set rbrace token later fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block { @@ -75,9 +75,28 @@ const Scope = struct { .parent = parent, }, .block_node = block_node, + .variables = AliasList.init(c.a()), }; return block; } + + fn getAlias(scope: *Block, name: []const u8) ?[]const u8 { + var it = scope.variables.iterator(0); + while (it.next()) |p| { + if (std.mem.eql(u8, p.name, name)) + return p.alias; + } + return scope.base.parent.?.getAlias(name); + } + + fn contains(scope: *Block, name: []const u8) bool { + var it = scope.variables.iterator(0); + while (it.next()) |p| { + if (std.mem.eql(u8, p.name, name)) + return true; + } + return scope.base.parent.?.contains(name); + } }; const Root = struct { @@ -155,26 +174,24 @@ const Scope = struct { fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { return switch (scope.id) { .Root => null, + .Ref => null, .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), + .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), else => @panic("TODO Scope.getAlias"), }; } fn contains(scope: *Scope, name: []const u8) bool { return switch (scope.id) { + .Ref => false, .Root => @fieldParentPtr(Root, "base", scope).contains(name), .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), + .Block => @fieldParentPtr(Block, "base", scope).contains(name), else => @panic("TODO Scope.contains"), }; } }; -const TransResult = struct { - node: *ast.Node, - node_scope: *Scope, - child_scope: *Scope, -}; - const Context = struct { tree: *ast.Tree, source_buffer: *std.Buffer, @@ -388,14 +405,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { // actual function definition with body const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); - const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { + const body_node = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { error.OutOfMemory => |e| return e, error.UnsupportedTranslation, error.UnsupportedType, => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), }; - assert(result.node.id == ast.Node.Id.Block); - proto_node.body_node = result.node; + assert(body_node.id == .Block); + proto_node.body_node = body_node; return addTopLevelDecl(c, fn_name, &proto_node.base); } @@ -431,7 +448,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { else try appendToken(c, .Keyword_var, "var"); - const name_tok = try appendIdentifier(c, var_name, null); + const name_tok = try appendIdentifier(c, var_name); _ = try appendToken(c, .Colon, ":"); const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { @@ -446,17 +463,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { if (ZigClangVarDecl_hasInit(var_decl)) { eq_tok = try appendToken(c, .Equal, "="); - init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| blk: { - var res = transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { + init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| + transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { error.UnsupportedTranslation, error.UnsupportedType, => { return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{}); }, error.OutOfMemory => |e| return e, - }; - break :blk res.node; - } else + } + else try transCreateNodeUndefinedLiteral(c); } else if (storage_class != .Extern) { return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{}); @@ -492,7 +508,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); - const name_tok = try appendIdentifier(c, typedef_name, null); + const name_tok = try appendIdentifier(c, typedef_name); const eq_tok = try appendToken(c, .Equal, "="); const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); @@ -545,7 +561,7 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { @@ -581,10 +597,10 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! fn createAlias(c: *Context, alias: var) !void { const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, alias.alias, null); + const name_tok = try appendIdentifier(c, alias.alias); const eq_tok = try appendToken(c, .Equal, "="); - const init_node = try transCreateNodeIdentifier(c, alias.name, null); + const init_node = try transCreateNodeIdentifier(c, alias.name); const node = try c.a().create(ast.Node.VarDecl); node.* = ast.Node.VarDecl{ @@ -622,7 +638,7 @@ fn transStmt( stmt: *const ZigClangStmt, result_used: ResultUsed, lrvalue: LRValue, -) TransError!TransResult { +) TransError!*ast.Node { const sc = ZigClangStmt_getStmtClass(stmt); switch (sc) { .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used), @@ -654,7 +670,7 @@ fn transBinaryOperator( scope: *Scope, stmt: *const ZigClangBinaryOperator, result_used: ResultUsed, -) TransError!TransResult { +) TransError!*ast.Node { const op = ZigClangBinaryOperator_getOpcode(stmt); const qt = ZigClangBinaryOperator_getType(stmt); switch (op) { @@ -665,67 +681,43 @@ fn transBinaryOperator( "TODO: handle more C binary operators: {}", .{op}, ), - .Assign => return TransResult{ - .node = &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base, - .child_scope = scope, - .node_scope = scope, - }, + .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base, .Add => { const node = if (cIsUnsignedInteger(qt)) try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true) else try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, node); }, .Sub => { const node = if (cIsUnsignedInteger(qt)) try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true) else try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, node); }, .Mul => { const node = if (cIsUnsignedInteger(qt)) try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true) else try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, node); }, .Div => { if (!cIsUnsignedInteger(qt)) { // signed integer division uses @divTrunc const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); - try div_trunc_node.params.push(lhs.node); + try div_trunc_node.params.push(lhs); _ = try appendToken(rp.c, .Comma, ","); const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - try div_trunc_node.params.push(rhs.node); + try div_trunc_node.params.push(rhs); div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = &div_trunc_node.base, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); } else { // unsigned/float division uses the operator const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, node); } }, .Rem => { @@ -733,24 +725,16 @@ fn transBinaryOperator( // signed integer division uses @rem const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); - try rem_node.params.push(lhs.node); + try rem_node.params.push(lhs); _ = try appendToken(rp.c, .Comma, ","); const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - try rem_node.params.push(rhs.node); + try rem_node.params.push(rhs); rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = &rem_node.base, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, &rem_node.base); } else { // unsigned/float division uses the operator const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true); - return maybeSuppressResult(rp, scope, result_used, TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }); + return maybeSuppressResult(rp, scope, result_used, node); } }, .Shl, @@ -793,33 +777,22 @@ fn transCompoundStmtInline( parent_scope: *Scope, stmt: *const ZigClangCompoundStmt, block_node: *ast.Node.Block, -) TransError!TransResult { +) TransError!void { var it = ZigClangCompoundStmt_body_begin(stmt); const end_it = ZigClangCompoundStmt_body_end(stmt); - var scope = parent_scope; while (it != end_it) : (it += 1) { const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); - scope = result.child_scope; - if (result.node != &block_node.base) - try block_node.statements.push(result.node); + if (result != &block_node.base) + try block_node.statements.push(result); } - return TransResult{ - .node = &block_node.base, - .child_scope = scope, - .node_scope = scope, - }; } -fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!TransResult { - const block_node = try transCreateNodeBlock(rp.c, null, null); +fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { + const block_node = try transCreateNodeBlock(rp.c, null); const block_scope = try Scope.Block.init(rp.c, scope, block_node); - const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); + try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - return TransResult{ - .node = &block_node.base, - .node_scope = inline_result.node_scope, - .child_scope = inline_result.child_scope, - }; + return &block_node.base; } fn transCStyleCastExprClass( @@ -828,7 +801,7 @@ fn transCStyleCastExprClass( stmt: *const ZigClangCStyleCastExpr, result_used: ResultUsed, lrvalue: LRValue, -) !TransResult { +) TransError!*ast.Node { const sub_expr = ZigClangCStyleCastExpr_getSubExpr(stmt); const cast_node = (try transCCast( rp, @@ -836,20 +809,14 @@ fn transCStyleCastExprClass( ZigClangCStyleCastExpr_getBeginLoc(stmt), ZigClangCStyleCastExpr_getType(stmt), ZigClangExpr_getType(sub_expr), - (try transExpr(rp, scope, sub_expr, .used, lrvalue)).node, + try transExpr(rp, scope, sub_expr, .used, lrvalue), )); - const cast_res = TransResult{ - .node = cast_node, - .child_scope = scope, - .node_scope = scope, - }; - return maybeSuppressResult(rp, scope, result_used, cast_res); + return maybeSuppressResult(rp, scope, result_used, cast_node); } -fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!TransResult { +fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { const c = rp.c; - const block_scope = parent_scope.findBlockScope(); - var scope = parent_scope; + const block_scope = scope.findBlockScope(); var it = ZigClangDeclStmt_decl_begin(stmt); const end_it = ZigClangDeclStmt_decl_end(stmt); @@ -867,18 +834,14 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var"); - const c_name = try c.str(ZigClangDecl_getName_bytes_begin( + const name = try c.str(ZigClangDecl_getName_bytes_begin( @ptrCast(*const ZigClangDecl, var_decl), )); - const name_token = try appendIdentifier(c, c_name, null); // TODO parent_scope); - - const var_scope = try c.a().create(Scope.Var); - var_scope.* = Scope.Var{ - .base = Scope{ .id = .Var, .parent = scope }, - .c_name = c_name, - .zig_name = c_name, // TODO: getWantedName - }; - scope = &var_scope.base; + const checked_name = if (try scope.createAlias(c, name)) |a| blk: { + try block_scope.variables.push(.{ .name = name, .alias = a }); + break :blk a; + } else name; + const name_token = try appendIdentifier(c, checked_name); const colon_token = try appendToken(c, .Colon, ":"); const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); @@ -886,7 +849,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe const eq_token = try appendToken(c, .Equal, "="); const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| - (try transExpr(rp, scope, expr, .used, .r_value)).node + try transExpr(rp, scope, expr, .used, .r_value) else try transCreateNodeUndefinedLiteral(c); const semicolon_token = try appendToken(c, .Semicolon, ";"); @@ -910,7 +873,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe }; try block_scope.block_node.statements.push(&node.base); }, - else => |kind| return revertAndWarn( rp, error.UnsupportedTranslation, @@ -920,12 +882,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe ), } } - - return TransResult{ - .node = &block_scope.block_node.base, - .node_scope = scope, - .child_scope = scope, - }; + return &block_scope.block_node.base; } fn transDeclRefExpr( @@ -933,17 +890,12 @@ fn transDeclRefExpr( scope: *Scope, expr: *const ZigClangDeclRefExpr, lrvalue: LRValue, -) !TransResult { +) TransError!*ast.Node { const value_decl = ZigClangDeclRefExpr_getDecl(expr); - const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); - const zig_name = transLookupZigIdentifier(scope, c_name); - if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name); - const node = try transCreateNodeIdentifier(rp.c, zig_name, null); // TODO scope); - return TransResult{ - .node = node, - .node_scope = scope, - .child_scope = scope, - }; + const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); + const checked_name = if (scope.getAlias(name)) |a| a else name; + if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name); + return transCreateNodeIdentifier(rp.c, checked_name); } fn transImplicitCastExpr( @@ -951,7 +903,7 @@ fn transImplicitCastExpr( scope: *Scope, expr: *const ZigClangImplicitCastExpr, result_used: ResultUsed, -) !TransResult { +) TransError!*ast.Node { const c = rp.c; const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); @@ -959,20 +911,12 @@ fn transImplicitCastExpr( .BitCast => { const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); const src_type = getExprQualType(c, sub_expr); - return TransResult{ - .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node), - .node_scope = scope, - .child_scope = scope, - }; + return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); }, .IntegralCast => { const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr)); const src_type = ZigClangExpr_getType(sub_expr); - return TransResult{ - .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node), - .node_scope = scope, - .child_scope = scope, - }; + return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); }, .FunctionToPointerDecay, .ArrayToPointerDecay => { return maybeSuppressResult(rp, scope, result_used, sub_expr_node); @@ -981,11 +925,7 @@ fn transImplicitCastExpr( return transExpr(rp, scope, sub_expr, .used, .r_value); }, .NullToPointer => { - return TransResult{ - .node = try transCreateNodeNullLiteral(rp.c), - .node_scope = scope, - .child_scope = scope, - }; + return transCreateNodeNullLiteral(rp.c); }, else => |kind| return revertAndWarn( rp, @@ -1002,36 +942,27 @@ fn transIntegerLiteral( scope: *Scope, expr: *const ZigClangIntegerLiteral, result_used: ResultUsed, -) !TransResult { +) TransError!*ast.Node { var eval_result: ZigClangExprEvalResult = undefined; if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) { const loc = ZigClangIntegerLiteral_getBeginLoc(expr); return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); } const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); - const res = TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }; - return maybeSuppressResult(rp, scope, result_used, res); + return maybeSuppressResult(rp, scope, result_used, node); } fn transReturnStmt( rp: RestorePoint, scope: *Scope, expr: *const ZigClangReturnStmt, -) !TransResult { +) TransError!*ast.Node { const node = try transCreateNodeReturnExpr(rp.c); if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { - node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node; + node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value); } _ = try appendToken(rp.c, .Semicolon, ";"); - return TransResult{ - .node = &node.base, - .child_scope = scope, - .node_scope = scope, - }; + return &node.base; } fn transStringLiteral( @@ -1039,7 +970,7 @@ fn transStringLiteral( scope: *Scope, stmt: *const ZigClangStringLiteral, result_used: ResultUsed, -) !TransResult { +) TransError!*ast.Node { const kind = ZigClangStringLiteral_getKind(stmt); switch (kind) { .Ascii, .UTF8 => { @@ -1061,12 +992,7 @@ fn transStringLiteral( node.* = ast.Node.StringLiteral{ .token = token, }; - const res = TransResult{ - .node = &node.base, - .child_scope = scope, - .node_scope = scope, - }; - return maybeSuppressResult(rp, scope, result_used, res); + return maybeSuppressResult(rp, scope, result_used, &node.base); }, .UTF16, .UTF32, .Wide => return revertAndWarn( rp, @@ -1159,7 +1085,7 @@ fn transExpr( expr: *const ZigClangExpr, used: ResultUsed, lrvalue: LRValue, -) TransError!TransResult { +) TransError!*ast.Node { return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue); } @@ -1168,7 +1094,7 @@ fn transInitListExpr( scope: *Scope, expr: *const ZigClangInitListExpr, used: ResultUsed, -) TransError!TransResult { +) TransError!*ast.Node { const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr)); const qual_type = ZigClangQualType_getTypePtr(qt); const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr)); @@ -1199,16 +1125,12 @@ fn transInitListExpr( var i: c_uint = 0; while (i < init_count) : (i += 1) { const elem_expr = ZigClangInitListExpr_getInit(expr, i); - try init_node.op.ArrayInitializer.push((try transExpr(rp, scope, elem_expr, .used, .r_value)).node); + try init_node.op.ArrayInitializer.push(try transExpr(rp, scope, elem_expr, .used, .r_value)); _ = try appendToken(rp.c, .Comma, ","); } init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); if (leftover_count == 0) { - return TransResult{ - .node = &init_node.base, - .child_scope = scope, - .node_scope = scope, - }; + return &init_node.base; } cat_tok = try appendToken(rp.c, .PlusPlus, "++"); } @@ -1216,7 +1138,7 @@ fn transInitListExpr( const dot_tok = try appendToken(rp.c, .Period, "."); var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); - try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node); + try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value)); filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); const rhs_node = if (leftover_count == 1) @@ -1234,11 +1156,7 @@ fn transInitListExpr( }; if (init_count == 0) { - return TransResult{ - .node = rhs_node, - .child_scope = scope, - .node_scope = scope, - }; + return rhs_node; } const cat_node = try rp.c.a().create(ast.Node.InfixOp); @@ -1248,11 +1166,7 @@ fn transInitListExpr( .op = .ArrayCat, .rhs = rhs_node, }; - return TransResult{ - .node = &cat_node.base, - .child_scope = scope, - .node_scope = scope, - }; + return &cat_node.base; } fn transImplicitValueInitExpr( @@ -1260,7 +1174,7 @@ fn transImplicitValueInitExpr( scope: *Scope, expr: *const ZigClangExpr, used: ResultUsed, -) TransError!TransResult { +) TransError!*ast.Node { const source_loc = ZigClangExpr_getBeginLoc(expr); const qt = getExprQualType(rp.c, expr); const ty = ZigClangQualType_getTypePtr(qt); @@ -1268,9 +1182,7 @@ fn transImplicitValueInitExpr( .Builtin => blk: { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); switch (ZigClangBuiltinType_getKind(builtin_ty)) { - .Bool => { - break :blk try transCreateNodeBoolLiteral(rp.c, false); - }, + .Bool => return transCreateNodeBoolLiteral(rp.c, false), .Char_U, .UChar, .Char_S, @@ -1291,30 +1203,13 @@ fn transImplicitValueInitExpr( .Float128, .Float16, .LongDouble, - => { - break :blk try transCreateNodeInt(rp.c, 0); - }, + => return transCreateNodeInt(rp.c, 0), else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), } }, - .Pointer => try transCreateNodeNullLiteral(rp.c), + .Pointer => return transCreateNodeNullLiteral(rp.c), else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}), }; - return TransResult{ - .node = node, - .child_scope = scope, - .node_scope = scope, - }; -} - -fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { - var scope = inner; - while (true) : (scope = scope.parent orelse return c_name) { - if (scope.id == .Var) { - const var_scope = @ptrCast(*const Scope.Var, scope); - if (std.mem.eql(u8, var_scope.c_name, c_name)) return var_scope.zig_name; - } - } } fn transCPtrCast( @@ -1358,25 +1253,21 @@ fn maybeSuppressResult( rp: RestorePoint, scope: *Scope, used: ResultUsed, - result: TransResult, -) !TransResult { + result: *ast.Node, +) TransError!*ast.Node { if (used == .used) return result; // NOTE: This is backwards, but the semicolon must immediately follow the node. _ = try appendToken(rp.c, .Semicolon, ";"); - const lhs = try transCreateNodeIdentifier(rp.c, "_", null); + const lhs = try transCreateNodeIdentifier(rp.c, "_"); const op_token = try appendToken(rp.c, .Equal, "="); const op_node = try rp.c.a().create(ast.Node.InfixOp); op_node.* = ast.Node.InfixOp{ .op_token = op_token, .lhs = lhs, .op = .Assign, - .rhs = result.node, - }; - return TransResult{ - .node = &op_node.base, - .child_scope = scope, - .node_scope = scope, + .rhs = result, }; + return &op_node.base; } fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { @@ -1443,7 +1334,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro return node; } - const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))), null); + const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); _ = try appendToken(c, .Colon, ":"); const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); @@ -1467,7 +1358,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| - return try transCreateNodeIdentifier(c, name.value, null); // Avoid processing this decl twice + return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice const rp = makeRestorePoint(c); const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); @@ -1483,7 +1374,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { @@ -1550,7 +1441,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No else enum_val_name; - const field_name_tok = try appendIdentifier(c, field_name, null); + const field_name_tok = try appendIdentifier(c, field_name); const int_node = if (!pure_enum) blk: { _ = try appendToken(c, .Colon, "="); @@ -1603,18 +1494,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No try addTopLevelDecl(c, name, &node.base); if (!is_unnamed) try c.alias_list.push(.{ .alias = bare_name, .name = name }); - return transCreateNodeIdentifier(c, name, null); + return transCreateNodeIdentifier(c, name); } fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const const_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, enum_val_name, null); + const name_tok = try appendIdentifier(c, enum_val_name); const eq_tok = try appendToken(c, .Equal, "="); - const enum_ident = try transCreateNodeIdentifier(c, enum_name, null); + const enum_ident = try transCreateNodeIdentifier(c, enum_name); const period_tok = try appendToken(c, .Period, "."); - const field_ident = try transCreateNodeIdentifier(c, field_name, null); + const field_ident = try transCreateNodeIdentifier(c, field_name); const field_access_node = try c.a().create(ast.Node.InfixOp); field_access_node.* = .{ @@ -1780,11 +1671,11 @@ fn transCreateNodeAssign( _ = try appendToken(rp.c, .Semicolon, ";"); const node = try rp.c.a().create(ast.Node.InfixOp); - node.* = ast.Node.InfixOp{ + node.* = .{ .op_token = eq_token, - .lhs = lhs_node.node, + .lhs = lhs_node, .op = .Assign, - .rhs = rhs_node.node, + .rhs = rhs_node, }; return node; } @@ -1864,9 +1755,9 @@ fn transCreateNodeInfixOp( const node = try rp.c.a().create(ast.Node.InfixOp); node.* = ast.Node.InfixOp{ .op_token = op_token, - .lhs = lhs.node, + .lhs = lhs, .op = op, - .rhs = rhs.node, + .rhs = rhs, }; if (!grouped) return &node.base; const rparen = try appendToken(rp.c, .RParen, ")"); @@ -1896,7 +1787,7 @@ fn transCreateNodePtrType( .Identifier => blk: { const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token _ = try appendToken(c, .Asterisk, "*"); - _ = try appendIdentifier(c, "c", null); // not really an identifier + _ = try appendIdentifier(c, "c"); _ = try appendToken(c, .RBracket, "]"); break :blk lbracket; }, @@ -2019,7 +1910,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a const pub_tok = try appendToken(c, .Keyword_pub, "pub"); const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); _ = try appendToken(c, .LParen, "("); const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?; @@ -2068,7 +1959,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a .section_expr = null, }; - const block = try transCreateNodeBlock(c, null, null); + const block = try transCreateNodeBlock(c, null); const return_expr = try transCreateNodeReturnExpr(c); const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); @@ -2079,7 +1970,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a _ = try appendToken(c, .Comma, ","); } const param = pn.*.cast(ast.Node.ParamDecl).?; - try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?), null)); + try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?))); } call_expr.rtoken = try appendToken(c, .RParen, ")"); return_expr.rhs = &call_expr.base; @@ -2107,7 +1998,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { const node = try c.a().create(ast.Node.EnumLiteral); node.* = .{ .dot = try appendToken(c, .Period, "."), - .name = try appendIdentifier(c, name, null), // scoped to an enum + .name = try appendIdentifier(c, name), }; return &node.base; } @@ -2136,9 +2027,9 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { return node; } -fn transCreateNodeBlock(c: *Context, label: ?[]const u8, scope: ?*Scope) !*ast.Node.Block { +fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { const label_node = if (label) |l| blk: { - const ll = try appendIdentifier(c, l, scope); + const ll = try appendIdentifier(c, l); _ = try appendToken(c, .Colon, ":"); break :blk ll; } else null; @@ -2196,7 +2087,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour .Float16 => "f16", .LongDouble => "c_longdouble", else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), - }, null); + }); }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); @@ -2274,7 +2165,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - return transCreateNodeIdentifier(rp.c, typedef_name, null); + return transCreateNodeIdentifier(rp.c, typedef_name); }, .Record => { const record_ty = @ptrCast(*const ZigClangRecordType, ty); @@ -2288,7 +2179,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour // }; const record_decl = ZigClangRecordType_getDecl(record_ty); if (try getContainerName(rp, record_decl)) |name| - return transCreateNodeIdentifier(rp.c, name, null) + return transCreateNodeIdentifier(rp.c, name) else return transRecordDecl(rp.c, record_decl); }, @@ -2426,7 +2317,7 @@ fn finishTransFnProto( else null; const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); - const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name, null) else null; + const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; const lparen_tok = try appendToken(rp.c, .LParen, "("); var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a()); @@ -2449,7 +2340,7 @@ fn finishTransFnProto( break :blk a; } else param_name; - const result = try appendIdentifier(rp.c, checked_param_name, null); + const result = try appendIdentifier(rp.c, checked_param_name); _ = try appendToken(rp.c, .Colon, ":"); break :blk result; } @@ -2497,12 +2388,12 @@ fn finishTransFnProto( const return_type_node = blk: { if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { - break :blk try transCreateNodeIdentifier(rp.c, "noreturn", null); + break :blk try transCreateNodeIdentifier(rp.c, "noreturn"); } else { const return_qt = ZigClangFunctionType_getReturnType(fn_ty); if (isCVoid(return_qt)) { // convert primitive c_void to actual void (only for return type) - break :blk try transCreateNodeIdentifier(rp.c, "void", null); + break :blk try transCreateNodeIdentifier(rp.c, "void"); } else { break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { error.UnsupportedType => { @@ -2555,7 +2446,7 @@ fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []cons fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: var) !void { // const name = @compileError(msg); const const_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const builtin_tok = try appendToken(c, .Builtin, "@compileError"); const lparen_tok = try appendToken(c, .LParen, "("); @@ -2640,11 +2531,7 @@ fn isValidZigIdentifier(name: []const u8) bool { return true; } -fn appendIdentifier(c: *Context, name: []const u8, scope: ?*Scope) !ast.TokenIndex { - if (scope) |s| - if (s.getAlias(name)) |alias| { - return appendTokenFmt(c, .Identifier, "{}", .{alias}); - }; +fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { if (!isValidZigIdentifier(name) or std.zig.Token.getKeyword(name) != null) { return appendTokenFmt(c, .Identifier, "@\"{}\"", .{name}); } else { @@ -2652,8 +2539,8 @@ fn appendIdentifier(c: *Context, name: []const u8, scope: ?*Scope) !ast.TokenInd } } -fn transCreateNodeIdentifier(c: *Context, name: []const u8, scope: ?*Scope) !*ast.Node { - const token_index = try appendIdentifier(c, name, scope); +fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { + const token_index = try appendIdentifier(c, name); const identifier = try c.a().create(ast.Node.Identifier); identifier.* = ast.Node.Identifier{ .base = ast.Node{ .id = ast.Node.Id.Identifier }, @@ -2740,7 +2627,7 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const mut_tok = try appendToken(c, .Keyword_const, "const"); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); const eq_tok = try appendToken(c, .Equal, "="); const init_node = try parseCExpr(rp, it, source_loc, scope); @@ -2773,7 +2660,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u const pub_tok = try appendToken(c, .Keyword_pub, "pub"); const inline_tok = try appendToken(c, .Keyword_inline, "inline"); const fn_tok = try appendToken(c, .Keyword_fn, "fn"); - const name_tok = try appendIdentifier(c, name, null); + const name_tok = try appendIdentifier(c, name); _ = try appendToken(c, .LParen, "("); if (it.next().?.id != .LParen) { @@ -2790,7 +2677,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u break :blk alias; } else param_tok.bytes; - const param_name_tok = try appendIdentifier(c, checked_name, null); + const param_name_tok = try appendIdentifier(c, checked_name); _ = try appendToken(c, .Colon, ":"); const token_index = try appendToken(c, .Keyword_var, "var"); @@ -2843,7 +2730,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u .section_expr = null, }; - const block = try transCreateNodeBlock(c, null, null); + const block = try transCreateNodeBlock(c, null); const return_expr = try transCreateNodeReturnExpr(c); const expr = try parseCExpr(rp, it, source_loc, scope); @@ -2888,7 +2775,7 @@ fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocati .LL => "c_longlong", .LLU => "c_ulonglong", else => unreachable, - }, null)); + })); _ = try appendToken(rp.c, .Comma, ","); try cast_node.params.push(try transCreateNodeInt(rp.c, tok.bytes)); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -2902,7 +2789,7 @@ fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocati .F => "f32", .L => "f64", else => unreachable, - }, null)); + })); _ = try appendToken(rp.c, .Comma, ","); try cast_node.params.push(try transCreateNodeFloat(rp.c, tok.bytes)); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -2939,7 +2826,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: .NumLitInt, .NumLitFloat => { return parseCNumLit(rp, tok, source_loc); }, - .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes, scope), + .Identifier => { + const name = if (scope.getAlias(tok.bytes)) |a| a else tok.bytes; + return transCreateNodeIdentifier(rp.c, name); + }, .LParen => { const inner_node = try parseCExpr(rp, it, source_loc, scope); @@ -3060,7 +2950,7 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc ); const op_token = try appendToken(rp.c, .Period, "."); - const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes, null); // TODO scope); + const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); const access_node = try rp.c.a().create(ast.Node.InfixOp); access_node.* = .{ .op_token = op_token, diff --git a/test/translate_c.zig b/test/translate_c.zig index 8363c3b79f..9a4c364d1d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -637,11 +637,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern var glProcs: union_OpenGLProcs; , \\pub const glClearPFN = PFNGLCLEARPROC; - // , // TODO + // , // TODO // \\pub inline fn glClearUnion(arg_1: GLbitfield) void { // \\ return glProcs.gl.Clear.?(arg_1); // \\} - , + , \\pub const OpenGLProcs = union_OpenGLProcs; }); @@ -671,6 +671,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const FOO2 = "aoeu\x07 derp"; }); + cases.add_2("variable aliasing", + \\static long a = 2; + \\static long b = 2; + \\static int c = 4; + \\void foo(char c) { + \\ int a; + \\ char b = 123; + \\ b = (char) a; + \\ { + \\ int d = 5; + \\ } + \\ unsigned d = 440; + \\} + , &[_][]const u8{ + \\pub var a: c_long = @as(c_long, 2); + \\pub var b: c_long = @as(c_long, 2); + \\pub var c: c_int = 4; + \\pub export fn foo(c_1: u8) void { + \\ var a_2: c_int = undefined; + \\ var b_3: u8 = @as(u8, 123); + \\ b_3 = @as(u8, a_2); + \\ { + \\ var d: c_int = 5; + \\ } + \\ var d: c_uint = @as(c_uint, 440); + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// if (builtin.os != builtin.Os.windows) { @@ -2059,5 +2087,4 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); }); - }