diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index 29a2d34773..7685cdc537 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -28,6 +28,8 @@ pub const CToken = struct { Comma, Fn, Arrow, + LBrace, + RBrace, }; pub const NumLitSuffix = enum { @@ -289,6 +291,14 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { result.id = .Comma; state = .Done; }, + '[' => { + result.id = .LBrace; + state = .Done; + }, + ']' => { + result.id = .RBrace; + state = .Done; + }, else => return error.TokenizingFailed, } }, diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 9617802835..a3ad42225a 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -1102,3 +1102,6 @@ pub extern fn ZigClangMemberExpr_getBase(*const ZigClangMemberExpr) *const ZigCl pub extern fn ZigClangMemberExpr_isArrow(*const ZigClangMemberExpr) bool; pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const ZigClangValueDecl; +pub extern fn ZigClangArraySubscriptExpr_getBase(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; +pub extern fn ZigClangArraySubscriptExpr_getIdx(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; + diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 8435629a7d..e13e28608b 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -850,6 +850,7 @@ fn transStmt( .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), + .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used), else => { return revertAndWarn( rp, @@ -1523,7 +1524,7 @@ fn transInitListExpr( var cat_tok: ast.TokenIndex = undefined; if (init_count != 0) { const dot_tok = try appendToken(rp.c, .Period, "."); - init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); + init_node = try transCreateNodeContainerInitializer(rp.c, dot_tok); var i: c_uint = 0; while (i < init_count) : (i += 1) { const elem_expr = ZigClangInitListExpr_getInit(expr, i); @@ -1538,7 +1539,7 @@ fn transInitListExpr( } const dot_tok = try appendToken(rp.c, .Period, "."); - var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); + var filler_init_node = try transCreateNodeContainerInitializer(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)); filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); @@ -1995,6 +1996,14 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE return maybeSuppressResult(rp, scope, result_used, node); } +fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArraySubscriptExpr, result_used: ResultUsed) TransError!*ast.Node { + const container_node = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getBase(stmt), .used, .r_value); + const node = try transCreateNodeArrayAccess(rp.c, container_node); + node.op.ArrayAccess = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getIdx(stmt), .used, .r_value); + node.rtoken = try appendToken(rp.c, .RBrace, "]"); + return maybeSuppressResult(rp, scope, result_used, &node.base); +} + fn transCPtrCast( rp: RestorePoint, loc: ZigClangSourceLocation, @@ -2643,7 +2652,7 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { return &node.base; } -fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp { +fn transCreateNodeContainerInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp { _ = try appendToken(c, .LBrace, "{"); const node = try c.a().create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ @@ -2972,6 +2981,19 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { return &node.base; } +fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp { + _ = try appendToken(c, .LBrace, "["); + const node = try c.a().create(ast.Node.SuffixOp); + node.* = .{ + .lhs = .{ .node = lhs }, + .op = .{ + .ArrayAccess = undefined, + }, + .rtoken = undefined, + }; + return node; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -3869,26 +3891,14 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc .Dot => { const name_tok = it.next().?; if (name_tok.id != .Identifier) - return revertAndWarn( - rp, - error.ParseError, - source_loc, - "unable to translate C expr", - .{}, - ); + return error.ParseError; 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", - .{}, - ); + return error.ParseError; const deref = try transCreateNodePtrDeref(rp.c, node); node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes); @@ -3929,6 +3939,14 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc }; node = &bitshift_node.base; }, + .LBrace => { + const arr_node = try transCreateNodeArrayAccess(rp.c, node); + arr_node.op.ArrayAccess = try parseCPrimaryExpr(rp, it, source_loc, scope); + arr_node.rtoken = try appendToken(rp.c, .RBrace, "]"); + node = &arr_node.base; + if (it.next().?.id != .RBrace) + return error.ParseError; + }, else => { _ = it.prev(); return node; diff --git a/test/translate_c.zig b/test/translate_c.zig index 05f3f1960f..d34bfd9e8a 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1523,6 +1523,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const ARROW = a.*.b; }); + cases.add_2("array access", + \\#define ACCESS array[2] + \\int array[100] = {}; + \\int foo(int index) { + \\ return array[index]; + \\} + , &[_][]const u8{ + \\pub export var array: [100]c_int = .{0} ** 100; + \\pub export fn foo(index: c_int) c_int { + \\ return array[index]; + \\} + , + \\pub const ACCESS = array[2]; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.addAllowWarnings("simple data types", @@ -1731,18 +1746,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("array access", - \\int array[100]; - \\int foo(int index) { - \\ return array[index]; - \\} - , &[_][]const u8{ - \\pub var array: [100]c_int = undefined; - \\pub export fn foo(index: c_int) c_int { - \\ return array[index]; - \\} - }); - cases.addC("sizeof", \\#include \\size_t size_of(void) { @@ -2656,4 +2659,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return foo.*.field; \\} }); + + cases.addC("array access", + \\int array[100]; + \\int foo(int index) { + \\ return array[index]; + \\} + , &[_][]const u8{ + \\pub var array: [100]c_int = undefined; + \\pub export fn foo(index: c_int) c_int { + \\ return array[index]; + \\} + }); }