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 {...@@ -33,8 +33,7 @@ fn addrEql(a: usize, b: usize) bool {
33 return a == b;33 return a == b;
34}34}
3535
36const MacroTable = std.StringHashMap(*ast.Node);36const SymbolTable = std.StringHashMap(*ast.Node);
37const SymbolTable = std.StringHashMap(void);
38const AliasList = std.SegmentedList(struct {37const AliasList = std.SegmentedList(struct {
39 alias: []const u8,38 alias: []const u8,
40 name: []const u8,39 name: []const u8,
...@@ -109,7 +108,7 @@ const Context = struct {...@@ -109,7 +108,7 @@ const Context = struct {
109 decl_table: DeclTable,108 decl_table: DeclTable,
110 alias_list: AliasList,109 alias_list: AliasList,
111 sym_table: SymbolTable,110 sym_table: SymbolTable,
112 macro_table: MacroTable,111 macro_table: SymbolTable,
113 global_scope: *Scope.Root,112 global_scope: *Scope.Root,
114 ptr_params: std.BufSet,113 ptr_params: std.BufSet,
115 clang_context: *ZigClangASTContext,114 clang_context: *ZigClangASTContext,
...@@ -197,7 +196,7 @@ pub fn translate(...@@ -197,7 +196,7 @@ pub fn translate(
197 .decl_table = DeclTable.init(arena),196 .decl_table = DeclTable.init(arena),
198 .alias_list = AliasList.init(arena),197 .alias_list = AliasList.init(arena),
199 .sym_table = SymbolTable.init(arena),198 .sym_table = SymbolTable.init(arena),
200 .macro_table = MacroTable.init(arena),199 .macro_table = SymbolTable.init(arena),
201 .global_scope = try arena.create(Scope.Root),200 .global_scope = try arena.create(Scope.Root),
202 .ptr_params = std.BufSet.init(arena),201 .ptr_params = std.BufSet.init(arena),
203 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,202 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
...@@ -215,11 +214,7 @@ pub fn translate(...@@ -215,11 +214,7 @@ pub fn translate(
215214
216 try transPreprocessorEntities(&context, ast_unit);215 try transPreprocessorEntities(&context, ast_unit);
217216
218 var macro_it = context.macro_table.iterator();217 try addMacros(&context);
219 while (macro_it.next()) |kv| {
220 try addTopLevelDecl(&context, kv.key, kv.value);
221 }
222
223 var it = context.alias_list.iterator(0);218 var it = context.alias_list.iterator(0);
224 while (it.next()) |alias| {219 while (it.next()) |alias| {
225 if (!context.sym_table.contains(alias.alias)) {220 if (!context.sym_table.contains(alias.alias)) {
...@@ -962,12 +957,11 @@ fn transReturnStmt(...@@ -962,12 +957,11 @@ fn transReturnStmt(
962) !TransResult {957) !TransResult {
963 const node = try transCreateNodeReturnExpr(rp.c);958 const node = try transCreateNodeReturnExpr(rp.c);
964 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {959 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
965 const ret_node = node.cast(ast.Node.ControlFlowExpression).?;960 node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
966 ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
967 }961 }
968 _ = try appendToken(rp.c, .Semicolon, ";");962 _ = try appendToken(rp.c, .Semicolon, ";");
969 return TransResult{963 return TransResult{
970 .node = node,964 .node = &node.base,
971 .child_scope = scope,965 .child_scope = scope,
972 .node_scope = scope,966 .node_scope = scope,
973 };967 };
...@@ -1327,7 +1321,7 @@ fn maybeSuppressResult(...@@ -1327,7 +1321,7 @@ fn maybeSuppressResult(
13271321
1328fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {1322fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
1329 try c.tree.root_node.decls.push(decl_node);1323 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);
1331}1325}
13321326
1333fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {1327fn 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 {...@@ -1767,7 +1761,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
1767 _ = try appendToken(c, .LParen, "(");1761 _ = try appendToken(c, .LParen, "(");
1768 const node = try c.a().create(ast.Node.SuffixOp);1762 const node = try c.a().create(ast.Node.SuffixOp);
1769 node.* = ast.Node.SuffixOp{1763 node.* = ast.Node.SuffixOp{
1770 .lhs = fn_expr,1764 .lhs = .{ .node = fn_expr },
1771 .op = ast.Node.SuffixOp.Op{1765 .op = ast.Node.SuffixOp.Op{
1772 .Call = ast.Node.SuffixOp.Op.Call{1766 .Call = ast.Node.SuffixOp.Op.Call{
1773 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),1767 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
...@@ -1881,7 +1875,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {...@@ -1881,7 +1875,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
1881 return &node.base;1875 return &node.base;
1882}1876}
18831877
1884fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {1878fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
1885 const ltoken = try appendToken(c, .Keyword_return, "return");1879 const ltoken = try appendToken(c, .Keyword_return, "return");
1886 const node = try c.a().create(ast.Node.ControlFlowExpression);1880 const node = try c.a().create(ast.Node.ControlFlowExpression);
1887 node.* = ast.Node.ControlFlowExpression{1881 node.* = ast.Node.ControlFlowExpression{
...@@ -1889,7 +1883,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {...@@ -1889,7 +1883,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
1889 .kind = .Return,1883 .kind = .Return,
1890 .rhs = null,1884 .rhs = null,
1891 };1885 };
1892 return &node.base;1886 return node;
1893}1887}
18941888
1895fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {1889fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
...@@ -1959,6 +1953,100 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {...@@ -1959,6 +1953,100 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1959 return &call_node.base;1953 return &call_node.base;
1960}1954}
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
1962const RestorePoint = struct {2050const RestorePoint = struct {
1963 c: *Context,2051 c: *Context,
1964 token_index: ast.TokenIndex,2052 token_index: ast.TokenIndex,
...@@ -1982,28 +2070,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -1982,28 +2070,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
1982 switch (ZigClangType_getTypeClass(ty)) {2070 switch (ZigClangType_getTypeClass(ty)) {
1983 .Builtin => {2071 .Builtin => {
1984 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);2072 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1985 switch (ZigClangBuiltinType_getKind(builtin_ty)) {2073 return transCreateNodeIdentifier(rp.c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1986 .Void => return transCreateNodeIdentifier(rp.c, "c_void"),2074 .Void => "c_void",
1987 .Bool => return transCreateNodeIdentifier(rp.c, "bool"),2075 .Bool => "bool",
1988 .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"),2076 .Char_U, .UChar, .Char_S, .Char8 => "u8",
1989 .SChar => return transCreateNodeIdentifier(rp.c, "i8"),2077 .SChar => "i8",
1990 .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"),2078 .UShort => "c_ushort",
1991 .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"),2079 .UInt => "c_uint",
1992 .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"),2080 .ULong => "c_ulong",
1993 .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"),2081 .ULongLong => "c_ulonglong",
1994 .Short => return transCreateNodeIdentifier(rp.c, "c_short"),2082 .Short => "c_short",
1995 .Int => return transCreateNodeIdentifier(rp.c, "c_int"),2083 .Int => "c_int",
1996 .Long => return transCreateNodeIdentifier(rp.c, "c_long"),2084 .Long => "c_long",
1997 .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"),2085 .LongLong => "c_longlong",
1998 .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"),2086 .UInt128 => "u128",
1999 .Int128 => return transCreateNodeIdentifier(rp.c, "i128"),2087 .Int128 => "i128",
2000 .Float => return transCreateNodeIdentifier(rp.c, "f32"),2088 .Float => "f32",
2001 .Double => return transCreateNodeIdentifier(rp.c, "f64"),2089 .Double => "f64",
2002 .Float128 => return transCreateNodeIdentifier(rp.c, "f128"),2090 .Float128 => "f128",
2003 .Float16 => return transCreateNodeIdentifier(rp.c, "f16"),2091 .Float16 => "f16",
2004 .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"),2092 .LongDouble => "c_longdouble",
2005 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),2093 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2006 }2094 });
2007 },2095 },
2008 .FunctionProto => {2096 .FunctionProto => {
2009 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);2097 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
...@@ -2693,8 +2781,6 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -2693,8 +2781,6 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
2693 node = &access_node.base;2781 node = &access_node.base;
2694 },2782 },
2695 .Shl => {2783 .Shl => {
2696 const rhs_node = try parseCPrimaryExpr(rp, it, source_loc);
2697
2698 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");2784 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
2699 const rhs = try parseCPrimaryExpr(rp, it, source_loc);2785 const rhs = try parseCPrimaryExpr(rp, it, source_loc);
2700 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);2786 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...@@ -2718,9 +2804,64 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
2718 const op_tok = it.next().?;2804 const op_tok = it.next().?;
27192805
2720 switch (op_tok.id) {2806 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 },
2721 else => {2822 else => {
2722 _ = it.prev();2823 _ = it.prev();
2723 return try parseCSuffixOpExpr(rp, it, source_loc);2824 return try parseCSuffixOpExpr(rp, it, source_loc);
2724 },2825 },
2725 }2826 }
2726}2827}
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 {...@@ -339,6 +339,64 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
339 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);339 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
340 });340 });
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
342 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////400 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
343401
344 cases.add_both("typedef of function in struct field",402 cases.add_both("typedef of function in struct field",
...@@ -1844,7 +1902,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1844,7 +1902,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1844 },1902 },
1845 );1903 );
18461904
1847 cases.addC(//todo1905 cases.add_both(
1848 "bitwise not on u-suffixed 0 (zero) in macro definition",1906 "bitwise not on u-suffixed 0 (zero) in macro definition",
1849 "#define NOT_ZERO (~0U)",1907 "#define NOT_ZERO (~0U)",
1850 &[_][]const u8{1908 &[_][]const u8{