translate-c-2 macro inline fn
parent
75218d4765
commit
57170f9eb6
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Reference in New Issue