| ... | ... | @@ -208,14 +208,14 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 208 | 208 | |
| 209 | 209 | fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 210 | 210 | if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice |
| 211 | | |
| 211 | const rp = makeRestorePoint(c); |
| 212 | 212 | const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); |
| 213 | 213 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); |
| 214 | 214 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); |
| 215 | 215 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); |
| 216 | 216 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 217 | 217 | .FunctionProto => transFnProto( |
| 218 | | c, |
| 218 | rp, |
| 219 | 219 | @ptrCast(*const ZigClangFunctionProtoType, fn_type), |
| 220 | 220 | fn_decl_loc, |
| 221 | 221 | fn_decl, |
| ... | ... | @@ -242,32 +242,35 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { |
| 242 | 242 | try c.tree.root_node.decls.push(decl_node); |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | | fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 246 | | return transType(c, ZigClangQualType_getTypePtr(qt), source_loc); |
| 245 | fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) Error!*ast.Node { |
| 246 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); |
| 247 | } |
| 248 | |
| 249 | fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { |
| 250 | const canon = ZigClangQualType_getCanonicalType(qt); |
| 251 | return ZigClangQualType_getTypePtr(canon); |
| 247 | 252 | } |
| 248 | 253 | |
| 249 | 254 | const RestorePoint = struct { |
| 250 | | context: *Context, |
| 255 | c: *Context, |
| 251 | 256 | token_index: ast.TokenIndex, |
| 252 | 257 | src_buf_index: usize, |
| 253 | 258 | |
| 254 | 259 | fn activate(self: RestorePoint) void { |
| 255 | | self.context.tree.tokens.shrink(self.token_index); |
| 256 | | self.context.source_buffer.shrink(self.src_buf_index); |
| 260 | self.c.tree.tokens.shrink(self.token_index); |
| 261 | self.c.source_buffer.shrink(self.src_buf_index); |
| 257 | 262 | } |
| 258 | 263 | }; |
| 259 | 264 | |
| 260 | 265 | fn makeRestorePoint(c: *Context) RestorePoint { |
| 261 | 266 | return RestorePoint{ |
| 262 | | .context = c, |
| 267 | .c = c, |
| 263 | 268 | .token_index = c.tree.tokens.len, |
| 264 | 269 | .src_buf_index = c.source_buffer.len(), |
| 265 | 270 | }; |
| 266 | 271 | } |
| 267 | 272 | |
| 268 | | fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 269 | | const rp = makeRestorePoint(c); |
| 270 | | |
| 273 | fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) Error!*ast.Node { |
| 271 | 274 | switch (ZigClangType_getTypeClass(ty)) { |
| 272 | 275 | .Builtin => { |
| 273 | 276 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| ... | ... | @@ -275,23 +278,26 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc |
| 275 | 278 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), |
| 276 | 279 | } |
| 277 | 280 | }, |
| 278 | | .FunctionProto => return transFnProto(c, @ptrCast(*const ZigClangFunctionType, ty), source_loc, null, false), |
| 281 | .FunctionProto => { |
| 282 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 283 | const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, null); |
| 284 | return &fn_proto.base; |
| 285 | }, |
| 279 | 286 | else => { |
| 280 | | const type_name = c.str(ZigClangType_getTypeClassName(ty)); |
| 287 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 281 | 288 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name); |
| 282 | 289 | }, |
| 283 | 290 | } |
| 284 | 291 | } |
| 285 | 292 | |
| 286 | 293 | fn transFnProto( |
| 287 | | c: *Context, |
| 294 | rp: RestorePoint, |
| 288 | 295 | fn_proto_ty: *const ZigClangFunctionProtoType, |
| 289 | 296 | source_loc: ZigClangSourceLocation, |
| 290 | 297 | opt_fn_decl: ?*const ZigClangFunctionDecl, |
| 291 | 298 | fn_name: ?[]const u8, |
| 292 | 299 | ) !*ast.Node.FnProto { |
| 293 | 300 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); |
| 294 | | const rp = makeRestorePoint(c); |
| 295 | 301 | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { |
| 296 | 302 | .C => CallingConvention.C, |
| 297 | 303 | .X86StdCall => CallingConvention.Stdcall, |
| ... | ... | @@ -323,13 +329,13 @@ fn transFnProto( |
| 323 | 329 | // TODO check for align attribute |
| 324 | 330 | |
| 325 | 331 | // extern fn name(...) T |
| 326 | | const cc_tok = if (cc == .Stdcall) try appendToken(c, .Keyword_stdcallcc, "stdcallcc") else null; |
| 332 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; |
| 327 | 333 | const is_export = exp: { |
| 328 | 334 | const fn_decl = opt_fn_decl orelse break :exp false; |
| 329 | 335 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); |
| 330 | 336 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); |
| 331 | 337 | break :exp switch (storage_class) { |
| 332 | | .None => switch (c.mode) { |
| 338 | .None => switch (rp.c.mode) { |
| 333 | 339 | .import => false, |
| 334 | 340 | .translate => has_body, |
| 335 | 341 | }, |
| ... | ... | @@ -340,48 +346,44 @@ fn transFnProto( |
| 340 | 346 | }; |
| 341 | 347 | }; |
| 342 | 348 | const extern_export_inline_tok = if (is_export) |
| 343 | | try appendToken(c, .Keyword_export, "export") |
| 349 | try appendToken(rp.c, .Keyword_export, "export") |
| 344 | 350 | else if (cc == .C) |
| 345 | | try appendToken(c, .Keyword_extern, "extern") |
| 351 | try appendToken(rp.c, .Keyword_extern, "extern") |
| 346 | 352 | else |
| 347 | 353 | null; |
| 348 | | const fn_tok = try appendToken(c, .Keyword_fn, "fn"); |
| 349 | | const name_tok = if (fn_name) |n| try appendToken(c, .Identifier, "{}", n) else null; |
| 350 | | const lparen_tok = try appendToken(c, .LParen, "("); |
| 351 | | const var_args_tok = if (is_var_args) try appendToken(c, .Ellipsis3, "...") else null; |
| 352 | | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 354 | const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); |
| 355 | const name_tok = if (fn_name) |n| try appendToken(rp.c, .Identifier, "{}", n) else null; |
| 356 | const lparen_tok = try appendToken(rp.c, .LParen, "("); |
| 357 | const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null; |
| 358 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| 353 | 359 | |
| 354 | 360 | const return_type_node = blk: { |
| 355 | 361 | if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { |
| 356 | | break :blk try appendIdentifier(c, "noreturn"); |
| 362 | break :blk try appendIdentifier(rp.c, "noreturn"); |
| 357 | 363 | } else { |
| 358 | | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: non-noreturn FunctionProto return type"); |
| 359 | | //proto_node->data.fn_proto.return_type = trans_qual_type(c, |
| 360 | | // ZigClangFunctionType_getReturnType(fn_ty), source_loc); |
| 361 | | //if (proto_node->data.fn_proto.return_type == nullptr) { |
| 362 | | // emit_warning(c, source_loc, "unsupported function proto return type"); |
| 363 | | // return nullptr; |
| 364 | | //} |
| 365 | | //// convert c_void to actual void (only for return type) |
| 366 | | //// we do want to look at the AstNode instead of ZigClangQualType, because |
| 367 | | //// if they do something like: |
| 368 | | //// typedef Foo void; |
| 369 | | //// void foo(void) -> Foo; |
| 370 | | //// we want to keep the return type AST node. |
| 371 | | //if (is_c_void_type(proto_node->data.fn_proto.return_type)) { |
| 372 | | // proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void"); |
| 373 | | //} |
| 364 | const return_qt = ZigClangFunctionType_getReturnType(fn_ty); |
| 365 | if (ZigClangType_isVoidType(qualTypeCanon(return_qt))) { |
| 366 | break :blk try appendIdentifier(rp.c, "void"); |
| 367 | } else { |
| 368 | break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { |
| 369 | error.UnsupportedType => { |
| 370 | try emitWarning(rp.c, source_loc, "unsupported function proto return type"); |
| 371 | return err; |
| 372 | }, |
| 373 | else => return err, |
| 374 | }; |
| 375 | } |
| 374 | 376 | } |
| 375 | 377 | }; |
| 376 | 378 | |
| 377 | | const fn_proto = try c.a().create(ast.Node.FnProto); |
| 379 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); |
| 378 | 380 | fn_proto.* = ast.Node.FnProto{ |
| 379 | 381 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 380 | 382 | .doc_comments = null, |
| 381 | 383 | .visib_token = null, |
| 382 | 384 | .fn_token = fn_tok, |
| 383 | 385 | .name_token = name_tok, |
| 384 | | .params = ast.Node.FnProto.ParamList.init(c.a()), |
| 386 | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), |
| 385 | 387 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 386 | 388 | .var_args_token = var_args_tok, |
| 387 | 389 | .extern_export_inline_token = extern_export_inline_tok, |
| ... | ... | @@ -396,14 +398,14 @@ fn transFnProto( |
| 396 | 398 | } |
| 397 | 399 | |
| 398 | 400 | fn revertAndWarn( |
| 399 | | restore_point: RestorePoint, |
| 401 | rp: RestorePoint, |
| 400 | 402 | err: var, |
| 401 | 403 | source_loc: ZigClangSourceLocation, |
| 402 | 404 | comptime format: []const u8, |
| 403 | 405 | args: ..., |
| 404 | 406 | ) (@typeOf(err) || error{OutOfMemory}) { |
| 405 | | restore_point.activate(); |
| 406 | | try emitWarning(restore_point.context, source_loc, format, args); |
| 407 | rp.activate(); |
| 408 | try emitWarning(rp.c, source_loc, format, args); |
| 407 | 409 | return err; |
| 408 | 410 | } |
| 409 | 411 | |