diff options
| author | Vexu <git@vexu.eu> | 2019-12-18 22:29:42 +0200 |
|---|---|---|
| committer | Vexu <git@vexu.eu> | 2019-12-18 22:29:42 +0200 |
| commit | cf7a5b7a4a77181a4c90fc9a92df496cfb48c3cd (patch) | |
| tree | c8614c7c0d818c2e787068498984792d7b70be00 | |
| parent | e65b9e8f7bcc38943f48ed44560a22c62ca222ce (diff) | |
| download | zig-cf7a5b7a4a77181a4c90fc9a92df496cfb48c3cd.tar.gz zig-cf7a5b7a4a77181a4c90fc9a92df496cfb48c3cd.zip | |
translate-c-2 member access
| -rw-r--r-- | src-self-hosted/c_tokenizer.zig | 108 | ||||
| -rw-r--r-- | src-self-hosted/clang.zig | 6 | ||||
| -rw-r--r-- | src-self-hosted/translate_c.zig | 84 | ||||
| -rw-r--r-- | test/translate_c.zig | 61 |
4 files changed, 154 insertions, 105 deletions
diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 9715661cd3..29a2d34773 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -27,6 +27,7 @@ pub const CToken = struct { Lt, Comma, Fn, + Arrow, }; pub const NumLitSuffix = enum { @@ -164,6 +165,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { NumLitIntSuffixL, NumLitIntSuffixLL, NumLitIntSuffixUL, + Minus, + Done, } = .Start; var result = CToken{ @@ -178,9 +181,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { const c = chars[i.*]; if (c == 0) { switch (state) { - .Start => { - return result; - }, .Identifier, .Decimal, .Hex, @@ -193,6 +193,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { result.bytes = chars[begin_index..i.*]; return result; }, + .Start, + .Minus, + .Done, .NumLitIntSuffixU, .NumLitIntSuffixL, .NumLitIntSuffixUL, @@ -212,7 +215,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { => return error.TokenizingFailed, } } - i.* += 1; switch (state) { .Start => { switch (c) { @@ -220,12 +222,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { '\'' => { state = .CharLit; result.id = .CharLit; - begin_index = i.* - 1; + begin_index = i.*; }, '\"' => { state = .String; result.id = .StrLit; - begin_index = i.* - 1; + begin_index = i.*; }, '/' => { state = .OpenComment; @@ -239,21 +241,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { 'a'...'z', 'A'...'Z', '_' => { state = .Identifier; result.id = .Identifier; - begin_index = i.* - 1; + begin_index = i.*; }, '1'...'9' => { state = .Decimal; result.id = .NumLitInt; - begin_index = i.* - 1; + begin_index = i.*; }, '0' => { state = .GotZero; result.id = .NumLitInt; - begin_index = i.* - 1; + begin_index = i.*; }, '.' => { result.id = .Dot; - return result; + state = .Done; }, '<' => { result.id = .Lt; @@ -261,40 +263,52 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { }, '(' => { result.id = .LParen; - return result; + state = .Done; }, ')' => { result.id = .RParen; - return result; + state = .Done; }, '*' => { result.id = .Asterisk; - return result; + state = .Done; }, '-' => { + state = .Minus; result.id = .Minus; - return result; }, '!' => { result.id = .Bang; - return result; + state = .Done; }, '~' => { result.id = .Tilde; - return result; + state = .Done; }, ',' => { result.id = .Comma; - return result; + state = .Done; }, else => return error.TokenizingFailed, } }, + .Done => return result, + .Minus => { + switch (c) { + '>' => { + result.id = .Arrow; + state = .Done; + }, + else => { + return result; + }, + } + }, .GotLt => { switch (c) { '<' => { result.id = .Shl; - return result; + state = .Done; }, else => { return result; @@ -310,19 +324,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { 'f', 'F', => { - i.* -= 1; result.num_lit_suffix = .F; result.bytes = chars[begin_index..i.*]; - return result; + state = .Done; }, 'l', 'L' => { - i.* -= 1; result.num_lit_suffix = .L; result.bytes = chars[begin_index..i.*]; - return result; + state = .Done; }, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -352,16 +363,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { '0'...'9' => {}, 'f', 'F' => { result.num_lit_suffix = .F; - result.bytes = chars[begin_index .. i.* - 1]; - return result; + result.bytes = chars[begin_index..i.*]; + state = .Done; }, 'l', 'L' => { result.num_lit_suffix = .L; - result.bytes = chars[begin_index .. i.* - 1]; - return result; + result.bytes = chars[begin_index..i.*]; + state = .Done; }, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -374,19 +384,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { 'u', 'U' => { state = .NumLitIntSuffixU; result.num_lit_suffix = .U; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, 'l', 'L' => { state = .NumLitIntSuffixL; result.num_lit_suffix = .L; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, '.' => { result.id = .NumLitFloat; state = .Float; }, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -407,12 +416,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { 'u', 'U' => { state = .NumLitIntSuffixU; result.num_lit_suffix = .U; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, 'l', 'L' => { state = .NumLitIntSuffixL; result.num_lit_suffix = .L; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, else => { i.* -= 1; @@ -425,7 +434,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { '0'...'7' => {}, '8', '9' => return error.TokenizingFailed, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -438,16 +446,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { // marks the number literal as unsigned state = .NumLitIntSuffixU; result.num_lit_suffix = .U; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, 'l', 'L' => { // marks the number literal as long state = .NumLitIntSuffixL; result.num_lit_suffix = .L; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -461,16 +468,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { // marks the number literal as unsigned state = .NumLitIntSuffixU; result.num_lit_suffix = .U; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, 'l', 'L' => { // marks the number literal as long state = .NumLitIntSuffixL; result.num_lit_suffix = .L; - result.bytes = chars[begin_index .. i.* - 1]; + result.bytes = chars[begin_index..i.*]; }, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, @@ -483,7 +489,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { state = .NumLitIntSuffixUL; }, else => { - i.* -= 1; return result; }, } @@ -496,10 +501,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { }, 'u', 'U' => { result.num_lit_suffix = .LU; - return result; + state = .Done; }, else => { - i.* -= 1; return result; }, } @@ -508,10 +512,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { switch (c) { 'u', 'U' => { result.num_lit_suffix = .LLU; - return result; + state = .Done; }, else => { - i.* -= 1; return result; }, } @@ -523,7 +526,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { return result; }, else => { - i.* -= 1; return result; }, } @@ -532,17 +534,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { switch (c) { '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, else => { - i.* -= 1; result.bytes = chars[begin_index..i.*]; return result; }, } }, - .String => { // TODO char escapes + .String => { switch (c) { '\"' => { - result.bytes = chars[begin_index..i.*]; - return result; + result.bytes = chars[begin_index .. i.* + 1]; + state = .Done; }, else => {}, } @@ -550,8 +551,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { .CharLit => { switch (c) { '\'' => { - result.bytes = chars[begin_index..i.*]; - return result; + result.bytes = chars[begin_index .. i.* + 1]; + state = .Done; }, else => {}, } @@ -566,7 +567,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { }, else => { result.id = .Slash; - return result; + state = .Done; }, } }, @@ -598,6 +599,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { } }, } + i.* += 1; } unreachable; } diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 19b6146109..9617802835 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -1096,5 +1096,9 @@ pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiter pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; -pub extern fn ZigClangStmtExpr_getSubStmt( *const ZigClangStmtExpr) *const ZigClangCompoundStmt; +pub extern fn ZigClangStmtExpr_getSubStmt(*const ZigClangStmtExpr) *const ZigClangCompoundStmt; + +pub extern fn ZigClangMemberExpr_getBase(*const ZigClangMemberExpr) *const ZigClangExpr; +pub extern fn ZigClangMemberExpr_isArrow(*const ZigClangMemberExpr) bool; +pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const ZigClangValueDecl; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 60eafc3596..8435629a7d 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -49,9 +49,6 @@ const Scope = struct { Root, Condition, FnDef, - - /// used when getting a member `a.b` - Ref, Loop, }; @@ -181,7 +178,6 @@ 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), .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), @@ -190,7 +186,6 @@ const Scope = struct { 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), @@ -230,7 +225,6 @@ const Context = struct { decl_table: DeclTable, alias_list: AliasList, global_scope: *Scope.Root, - ptr_params: std.BufSet, clang_context: *ZigClangASTContext, mangle_count: u64 = 0, @@ -316,7 +310,6 @@ pub fn translate( .decl_table = DeclTable.init(arena), .alias_list = AliasList.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.init(&context); @@ -856,6 +849,7 @@ fn transStmt( .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), + .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), else => { return revertAndWarn( rp, @@ -1147,7 +1141,6 @@ fn transDeclRefExpr( const value_decl = ZigClangDeclRefExpr_getDecl(expr); 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); } @@ -1990,6 +1983,18 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, return maybeSuppressResult(rp, scope, used, &grouped_expr.base); } +fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberExpr, result_used: ResultUsed) TransError!*ast.Node { + var container_node = try transExpr(rp, scope, ZigClangMemberExpr_getBase(stmt), .used, .r_value); + + if (ZigClangMemberExpr_isArrow(stmt)) { + container_node = try transCreateNodePtrDeref(rp.c, container_node); + } + + const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt)))); + const node = try transCreateNodeFieldAccess(rp.c, container_node, name); + return maybeSuppressResult(rp, scope, result_used, node); +} + fn transCPtrCast( rp: RestorePoint, loc: ZigClangSourceLocation, @@ -2213,8 +2218,8 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); - const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int"); - const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base); + const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); + const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access); try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node); log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); @@ -2446,7 +2451,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { return node; } -fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp { +fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { const field_access_node = try c.a().create(ast.Node.InfixOp); field_access_node.* = .{ .op_token = try appendToken(c, .Period, "."), @@ -2454,7 +2459,7 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c .op = .Period, .rhs = try transCreateNodeIdentifier(c, field_name), }; - return field_access_node; + return &field_access_node.base; } fn transCreateNodePrefixOp( @@ -2924,9 +2929,9 @@ fn transCreateNodeShiftOp( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangBinaryOperator, - comptime op: ast.Node.InfixOp.Op, - comptime op_tok_id: std.zig.Token.Id, - comptime bytes: []const u8, + op: ast.Node.InfixOp.Op, + op_tok_id: std.zig.Token.Id, + bytes: []const u8, ) !*ast.Node { std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight); @@ -2957,6 +2962,16 @@ fn transCreateNodeShiftOp( return &node.base; } +fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { + const node = try c.a().create(ast.Node.SuffixOp); + node.* = .{ + .lhs = .{ .node = lhs }, + .op = .Deref, + .rtoken = try appendToken(c, .PeriodAsterisk, ".*"), + }; + return &node.base; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -3862,16 +3877,21 @@ 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 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; + node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes); + }, + .Arrow => { + const name_tok = it.next().?; + if (name_tok.id != .Identifier) + return revertAndWarn( + rp, + error.ParseError, + source_loc, + "unable to translate C expr", + .{}, + ); + + const deref = try transCreateNodePtrDeref(rp.c, node); + node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes); }, .Asterisk => { if (it.peek().?.id == .RParen) { @@ -3887,14 +3907,14 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc // expr * expr const op_token = try appendToken(rp.c, .Asterisk, "*"); const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); - const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); - bitshift_node.* = .{ + const mul_node = try rp.c.a().create(ast.Node.InfixOp); + mul_node.* = .{ .op_token = op_token, .lhs = node, .op = .BitShiftLeft, .rhs = rhs, }; - node = &bitshift_node.base; + node = &mul_node.base; } }, .Shl => { @@ -3938,13 +3958,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc }, .Asterisk => { 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 }, - .op = .Deref, - .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"), - }; - return &node.base; + return try transCreateNodePtrDeref(rp.c, prefix_op_expr); }, else => { _ = it.prev(); diff --git a/test/translate_c.zig b/test/translate_c.zig index 475e066845..05f3f1960f 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1494,6 +1494,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("field access expression", + \\#define ARROW a->b + \\#define DOT a.b + \\extern struct Foo { + \\ int b; + \\}a; + \\float b = 2.0f; + \\int foo(void) { + \\ struct Foo *c; + \\ a.b; + \\ c->b; + \\} + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ b: c_int, + \\}; + \\pub extern var a: struct_Foo; + \\pub export var b: f32 = 2; + \\pub export fn foo() c_int { + \\ var c: [*c]struct_Foo = undefined; + \\ _ = a.b; + \\ _ = c.*.b; + \\} + , + \\pub const DOT = a.b; + , + \\pub const ARROW = a.*.b; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.addAllowWarnings("simple data types", @@ -1702,22 +1731,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("field access expression", - \\struct Foo { - \\ int field; - \\}; - \\int read_field(struct Foo *foo) { - \\ return foo->field; - \\} - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ field: c_int, - \\}; - \\pub export fn read_field(foo: [*c]struct_Foo) c_int { - \\ return foo.*.field; - \\} - }); - cases.addC("array access", \\int array[100]; \\int foo(int index) { @@ -2627,4 +2640,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ }; \\} }); + + cases.addC("field access expression", + \\struct Foo { + \\ int field; + \\}; + \\int read_field(struct Foo *foo) { + \\ return foo->field; + \\} + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ field: c_int, + \\}; + \\pub export fn read_field(foo: [*c]struct_Foo) c_int { + \\ return foo.*.field; + \\} + }); } |
