authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-15 16:50:20+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-15 19:28:34+02:00
log57170f9eb662f17f361ebf4cd19f86283a80b74f
tree3876aeb8cc4351d409e93c8cf211123636e68c84
parent75218d4765bdf0dbdf97581b7dd05b45570ab940
signature Commit is signed but in an unrecognized format.

translate-c-2 macro inline fn


2 files changed, 239 insertions(+), 40 deletions(-)

src-self-hosted/translate_c.zig+180-39
......@@ -33,8 +33,7 @@ fn addrEql(a: usize, b: usize) bool {
3333 return a == b;
3434}
3535
36const MacroTable = std.StringHashMap(*ast.Node);
37const SymbolTable = std.StringHashMap(void);
36const SymbolTable = std.StringHashMap(*ast.Node);
3837const AliasList = std.SegmentedList(struct {
3938 alias: []const u8,
4039 name: []const u8,
......@@ -109,7 +108,7 @@ const Context = struct {
109108 decl_table: DeclTable,
110109 alias_list: AliasList,
111110 sym_table: SymbolTable,
112 macro_table: MacroTable,
111 macro_table: SymbolTable,
113112 global_scope: *Scope.Root,
114113 ptr_params: std.BufSet,
115114 clang_context: *ZigClangASTContext,
......@@ -197,7 +196,7 @@ pub fn translate(
197196 .decl_table = DeclTable.init(arena),
198197 .alias_list = AliasList.init(arena),
199198 .sym_table = SymbolTable.init(arena),
200 .macro_table = MacroTable.init(arena),
199 .macro_table = SymbolTable.init(arena),
201200 .global_scope = try arena.create(Scope.Root),
202201 .ptr_params = std.BufSet.init(arena),
203202 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
......@@ -215,11 +214,7 @@ pub fn translate(
215214
216215 try transPreprocessorEntities(&context, ast_unit);
217216
218 var macro_it = context.macro_table.iterator();
219 while (macro_it.next()) |kv| {
220 try addTopLevelDecl(&context, kv.key, kv.value);
221 }
222
217 try addMacros(&context);
223218 var it = context.alias_list.iterator(0);
224219 while (it.next()) |alias| {
225220 if (!context.sym_table.contains(alias.alias)) {
......@@ -962,12 +957,11 @@ fn transReturnStmt(
962957) !TransResult {
963958 const node = try transCreateNodeReturnExpr(rp.c);
964959 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
965 const ret_node = node.cast(ast.Node.ControlFlowExpression).?;
966 ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
960 node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
967961 }
968962 _ = try appendToken(rp.c, .Semicolon, ";");
969963 return TransResult{
970 .node = node,
964 .node = &node.base,
971965 .child_scope = scope,
972966 .node_scope = scope,
973967 };
......@@ -1327,7 +1321,7 @@ fn maybeSuppressResult(
13271321
13281322fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
13291323 try c.tree.root_node.decls.push(decl_node);
1330 _ = try c.sym_table.put(name, {});
1324 _ = try c.sym_table.put(name, decl_node);
13311325}
13321326
13331327fn 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 {
17671761 _ = try appendToken(c, .LParen, "(");
17681762 const node = try c.a().create(ast.Node.SuffixOp);
17691763 node.* = ast.Node.SuffixOp{
1770 .lhs = fn_expr,
1764 .lhs = .{ .node = fn_expr },
17711765 .op = ast.Node.SuffixOp.Op{
17721766 .Call = ast.Node.SuffixOp.Op.Call{
17731767 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
......@@ -1881,7 +1875,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
18811875 return &node.base;
18821876}
18831877
1884fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
1878fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
18851879 const ltoken = try appendToken(c, .Keyword_return, "return");
18861880 const node = try c.a().create(ast.Node.ControlFlowExpression);
18871881 node.* = ast.Node.ControlFlowExpression{
......@@ -1889,7 +1883,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
18891883 .kind = .Return,
18901884 .rhs = null,
18911885 };
1892 return &node.base;
1886 return node;
18931887}
18941888
18951889fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
......@@ -1959,6 +1953,100 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
19591953 return &call_node.base;
19601954}
19611955
1956fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node {
1957 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
1958 const inline_tok = try appendToken(c, .Keyword_inline, "inline");
1959 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
1960 const name_tok = try appendIdentifier(c, name);
1961 _ = try appendToken(c, .LParen, "(");
1962
1963 const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?;
1964
1965 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
1966 var it = proto_alias.params.iterator(0);
1967 while (it.next()) |pn| {
1968 if (it.index != 0) {
1969 _ = try appendToken(c, .Comma, ",");
1970 }
1971 const param = pn.*.cast(ast.Node.ParamDecl).?;
1972
1973 const param_name_tok = param.name_token orelse
1974 try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()});
1975
1976 _ = try appendToken(c, .Colon, ":");
1977
1978 const param_node = try c.a().create(ast.Node.ParamDecl);
1979 param_node.* = .{
1980 .doc_comments = null,
1981 .comptime_token = null,
1982 .noalias_token = param.noalias_token,
1983 .name_token = param_name_tok,
1984 .type_node = param.type_node,
1985 .var_args_token = null,
1986 };
1987 try fn_params.push(&param_node.base);
1988 }
1989
1990 _ = try appendToken(c, .RParen, ")");
1991
1992 const fn_proto = try c.a().create(ast.Node.FnProto);
1993 fn_proto.* = .{
1994 .doc_comments = null,
1995 .visib_token = pub_tok,
1996 .fn_token = fn_tok,
1997 .name_token = name_tok,
1998 .params = fn_params,
1999 .return_type = proto_alias.return_type,
2000 .var_args_token = null,
2001 .extern_export_inline_token = inline_tok,
2002 .cc_token = null,
2003 .body_node = null,
2004 .lib_name = null,
2005 .align_expr = null,
2006 .section_expr = null,
2007 };
2008
2009 const block = try c.a().create(ast.Node.Block);
2010 block.* = .{
2011 .label = null,
2012 .lbrace = try appendToken(c, .LBrace, "{"),
2013 .statements = ast.Node.Block.StatementList.init(c.a()),
2014 .rbrace = undefined,
2015 };
2016
2017 const return_expr = try transCreateNodeReturnExpr(c);
2018 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
2019 const call_expr = try transCreateNodeFnCall(c, unwrap_expr);
2020 it = fn_params.iterator(0);
2021 while (it.next()) |pn| {
2022 if (it.index != 0) {
2023 _ = try appendToken(c, .Comma, ",");
2024 }
2025 const param = pn.*.cast(ast.Node.ParamDecl).?;
2026 try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)));
2027 }
2028 call_expr.rtoken = try appendToken(c, .RParen, ")");
2029 return_expr.rhs = &call_expr.base;
2030 _ = try appendToken(c, .Semicolon, ";");
2031
2032 block.rbrace = try appendToken(c, .RBrace, "}");
2033 try block.statements.push(&return_expr.base);
2034 fn_proto.body_node = &block.base;
2035 return &fn_proto.base;
2036}
2037
2038fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
2039 _ = try appendToken(c, .Period, ".");
2040 const qm = try appendToken(c, .QuestionMark, "?");
2041 const node = try c.a().create(ast.Node.SuffixOp);
2042 node.* = ast.Node.SuffixOp{
2043 .op = .UnwrapOptional,
2044 .lhs = .{ .node = wrapped },
2045 .rtoken = qm,
2046 };
2047 return &node.base;
2048}
2049
19622050const RestorePoint = struct {
19632051 c: *Context,
19642052 token_index: ast.TokenIndex,
......@@ -1982,28 +2070,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
19822070 switch (ZigClangType_getTypeClass(ty)) {
19832071 .Builtin => {
19842072 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1985 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1986 .Void => return transCreateNodeIdentifier(rp.c, "c_void"),
1987 .Bool => return transCreateNodeIdentifier(rp.c, "bool"),
1988 .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"),
1989 .SChar => return transCreateNodeIdentifier(rp.c, "i8"),
1990 .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"),
1991 .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"),
1992 .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"),
1993 .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"),
1994 .Short => return transCreateNodeIdentifier(rp.c, "c_short"),
1995 .Int => return transCreateNodeIdentifier(rp.c, "c_int"),
1996 .Long => return transCreateNodeIdentifier(rp.c, "c_long"),
1997 .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"),
1998 .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"),
1999 .Int128 => return transCreateNodeIdentifier(rp.c, "i128"),
2000 .Float => return transCreateNodeIdentifier(rp.c, "f32"),
2001 .Double => return transCreateNodeIdentifier(rp.c, "f64"),
2002 .Float128 => return transCreateNodeIdentifier(rp.c, "f128"),
2003 .Float16 => return transCreateNodeIdentifier(rp.c, "f16"),
2004 .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"),
2073 return transCreateNodeIdentifier(rp.c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2074 .Void => "c_void",
2075 .Bool => "bool",
2076 .Char_U, .UChar, .Char_S, .Char8 => "u8",
2077 .SChar => "i8",
2078 .UShort => "c_ushort",
2079 .UInt => "c_uint",
2080 .ULong => "c_ulong",
2081 .ULongLong => "c_ulonglong",
2082 .Short => "c_short",
2083 .Int => "c_int",
2084 .Long => "c_long",
2085 .LongLong => "c_longlong",
2086 .UInt128 => "u128",
2087 .Int128 => "i128",
2088 .Float => "f32",
2089 .Double => "f64",
2090 .Float128 => "f128",
2091 .Float16 => "f16",
2092 .LongDouble => "c_longdouble",
20052093 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2006 }
2094 });
20072095 },
20082096 .FunctionProto => {
20092097 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
......@@ -2693,8 +2781,6 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
26932781 node = &access_node.base;
26942782 },
26952783 .Shl => {
2696 const rhs_node = try parseCPrimaryExpr(rp, it, source_loc);
2697
26982784 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
26992785 const rhs = try parseCPrimaryExpr(rp, it, source_loc);
27002786 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
27182804 const op_tok = it.next().?;
27192805
27202806 switch (op_tok.id) {
2807 .Bang => {
2808 const node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
2809 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc);
2810 return &node.base;
2811 },
2812 .Minus => {
2813 const node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
2814 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc);
2815 return &node.base;
2816 },
2817 .Tilde => {
2818 const node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
2819 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc);
2820 return &node.base;
2821 },
27212822 else => {
27222823 _ = it.prev();
27232824 return try parseCSuffixOpExpr(rp, it, source_loc);
27242825 },
27252826 }
27262827}
2828
2829fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 {
2830 const tok = c.tree.tokens.at(token);
2831 return c.source_buffer.toSliceConst()[tok.start..tok.end];
2832}
2833
2834fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {
2835 const init = ref.cast(ast.Node.VarDecl).?.init_node.?;
2836 const name = if (init.cast(ast.Node.Identifier)) |id|
2837 tokenSlice(c, id.token)
2838 else
2839 return null;
2840 // TODO a.b.c
2841 if (c.sym_table.get(name)) |kv| {
2842 if (kv.value.cast(ast.Node.VarDecl)) |val| {
2843 if (val.type_node) |type_node| {
2844 if (type_node.cast(ast.Node.PrefixOp)) |casted| {
2845 if (casted.rhs.id == .FnProto) {
2846 return casted.rhs;
2847 }
2848 }
2849 }
2850 }
2851 }
2852 return null;
2853}
2854
2855fn addMacros(c: *Context) !void {
2856 var macro_it = c.macro_table.iterator();
2857 while (macro_it.next()) |kv| {
2858 if (getFnDecl(c, kv.value)) |proto_node| {
2859 // If a macro aliases a global variable which is a function pointer, we conclude that
2860 // the macro is intended to represent a function that assumes the function pointer
2861 // variable is non-null and calls it.
2862 try addTopLevelDecl(c, kv.key, try transCreateNodeMacroFn(c, kv.key, kv.value, proto_node));
2863 } else {
2864 try addTopLevelDecl(c, kv.key, kv.value);
2865 }
2866 }
2867}
test/translate_c.zig+59-1
......@@ -339,6 +339,64 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
339339 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
340340 });
341341
342 cases.add_2("generate inline func for #define global extern fn",
343 \\extern void (*fn_ptr)(void);
344 \\#define foo fn_ptr
345 \\
346 \\extern char (*fn_ptr2)(int, float);
347 \\#define bar fn_ptr2
348 , &[_][]const u8{
349 \\pub extern var fn_ptr: ?extern fn () void;
350 ,
351 \\pub inline fn foo() void {
352 \\ return fn_ptr.?();
353 \\}
354 ,
355 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
356 ,
357 \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 {
358 \\ return fn_ptr2.?(arg_1, arg_2);
359 \\}
360 });
361
362 cases.add_2("macros with field targets",
363 \\typedef unsigned int GLbitfield;
364 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
365 \\typedef void(*OpenGLProc)(void);
366 \\union OpenGLProcs {
367 \\ OpenGLProc ptr[1];
368 \\ struct {
369 \\ PFNGLCLEARPROC Clear;
370 \\ } gl;
371 \\};
372 \\extern union OpenGLProcs glProcs;
373 \\#define glClearUnion glProcs.gl.Clear
374 \\#define glClearPFN PFNGLCLEARPROC
375 , &[_][]const u8{
376 \\pub const GLbitfield = c_uint;
377 ,
378 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
379 ,
380 \\pub const OpenGLProc = ?extern fn () void;
381 ,
382 \\pub const union_OpenGLProcs = extern union {
383 \\ ptr: [1]OpenGLProc,
384 \\ gl: extern struct {
385 \\ Clear: PFNGLCLEARPROC,
386 \\ },
387 \\};
388 ,
389 \\pub extern var glProcs: union_OpenGLProcs;
390 ,
391 \\pub const glClearPFN = PFNGLCLEARPROC;
392 // , // TODO
393 // \\pub inline fn glClearUnion(arg_1: GLbitfield) void {
394 // \\ return glProcs.gl.Clear.?(arg_1);
395 // \\}
396 ,
397 \\pub const OpenGLProcs = union_OpenGLProcs;
398 });
399
342400 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
343401
344402 cases.add_both("typedef of function in struct field",
......@@ -1844,7 +1902,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18441902 },
18451903 );
18461904
1847 cases.addC(//todo
1905 cases.add_both(
18481906 "bitwise not on u-suffixed 0 (zero) in macro definition",
18491907 "#define NOT_ZERO (~0U)",
18501908 &[_][]const u8{