| ... | ... | @@ -110,7 +110,7 @@ pub fn translate( |
| 110 | 110 | return context.err; |
| 111 | 111 | } |
| 112 | 112 | |
| 113 | | try appendToken(&context, .Eof, ""); |
| 113 | _ = try appendToken(&context, .Eof, ""); |
| 114 | 114 | tree.source = source_buffer.toOwnedSlice(); |
| 115 | 115 | return tree; |
| 116 | 116 | } |
| ... | ... | @@ -149,7 +149,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 152 | | const fn_name = c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); |
| 152 | const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); |
| 153 | 153 | |
| 154 | 154 | // TODO The C++ code has this: |
| 155 | 155 | //if (get_global(c, fn_name)) { |
| ... | ... | @@ -160,28 +160,49 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 160 | 160 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); |
| 161 | 161 | const proto_node = transQualType(c, ZigClangFunctionDecl_getType(fn_decl), fn_decl_loc) catch |e| switch (e) { |
| 162 | 162 | error.UnsupportedType => { |
| 163 | | try emitWarning(c, fn_decl_loc, "unable to resolve prototype of function '{}'", fn_name); |
| 163 | try failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); |
| 164 | 164 | return; |
| 165 | 165 | }, |
| 166 | 166 | else => return e, |
| 167 | 167 | }; |
| 168 | const semi_tok = try appendToken(c, .Semicolon, ";"); |
| 168 | 169 | |
| 169 | | try emitWarning(c, fn_decl_loc, "TODO implement translate-c for function decls"); |
| 170 | try emitWarning(c, fn_decl_loc, "TODO implement more translate-c for function decls"); |
| 171 | |
| 172 | try c.tree.root_node.decls.push(proto_node); |
| 170 | 173 | } |
| 171 | 174 | |
| 172 | 175 | fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 173 | 176 | return transType(c, ZigClangQualType_getTypePtr(qt), source_loc); |
| 174 | 177 | } |
| 175 | 178 | |
| 179 | const RestorePoint = struct { |
| 180 | context: *Context, |
| 181 | token_index: ast.TokenIndex, |
| 182 | src_buf_index: usize, |
| 183 | |
| 184 | fn activate(self: RestorePoint) void { |
| 185 | self.context.tree.tokens.shrink(self.token_index); |
| 186 | self.context.source_buffer.shrink(self.src_buf_index); |
| 187 | } |
| 188 | }; |
| 189 | |
| 190 | fn makeRestorePoint(c: *Context) RestorePoint { |
| 191 | return RestorePoint{ |
| 192 | .context = c, |
| 193 | .token_index = c.tree.tokens.len, |
| 194 | .src_buf_index = c.source_buffer.len(), |
| 195 | }; |
| 196 | } |
| 197 | |
| 176 | 198 | fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 199 | const rp = makeRestorePoint(c); |
| 200 | |
| 177 | 201 | switch (ZigClangType_getTypeClass(ty)) { |
| 178 | 202 | .Builtin => { |
| 179 | 203 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 180 | 204 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 181 | | else => { |
| 182 | | try emitWarning(c, source_loc, "unsupported builtin type"); |
| 183 | | return error.UnsupportedType; |
| 184 | | }, |
| 205 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), |
| 185 | 206 | } |
| 186 | 207 | }, |
| 187 | 208 | .FunctionProto => { |
| ... | ... | @@ -189,87 +210,157 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc |
| 189 | 210 | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { |
| 190 | 211 | .C => CallingConvention.c, |
| 191 | 212 | .X86StdCall => CallingConvention.stdcall, |
| 192 | | .X86FastCall => { |
| 193 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 fastcall"); |
| 194 | | return error.UnsupportedType; |
| 195 | | }, |
| 196 | | .X86ThisCall => { |
| 197 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 thiscall"); |
| 198 | | return error.UnsupportedType; |
| 199 | | }, |
| 200 | | .X86VectorCall => { |
| 201 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 vectorcall"); |
| 202 | | return error.UnsupportedType; |
| 203 | | }, |
| 204 | | .X86Pascal => { |
| 205 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 pascal"); |
| 206 | | return error.UnsupportedType; |
| 207 | | }, |
| 208 | | .Win64 => { |
| 209 | | try emitWarning(c, source_loc, "unsupported calling convention: win64"); |
| 210 | | return error.UnsupportedType; |
| 211 | | }, |
| 212 | | .X86_64SysV => { |
| 213 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 64sysv"); |
| 214 | | return error.UnsupportedType; |
| 215 | | }, |
| 216 | | .X86RegCall => { |
| 217 | | try emitWarning(c, source_loc, "unsupported calling convention: x86 reg"); |
| 218 | | return error.UnsupportedType; |
| 219 | | }, |
| 220 | | .AAPCS => { |
| 221 | | try emitWarning(c, source_loc, "unsupported calling convention: aapcs"); |
| 222 | | return error.UnsupportedType; |
| 223 | | }, |
| 224 | | .AAPCS_VFP => { |
| 225 | | try emitWarning(c, source_loc, "unsupported calling convention: aapcs-vfp"); |
| 226 | | return error.UnsupportedType; |
| 227 | | }, |
| 228 | | .IntelOclBicc => { |
| 229 | | try emitWarning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); |
| 230 | | return error.UnsupportedType; |
| 231 | | }, |
| 232 | | .SpirFunction => { |
| 233 | | try emitWarning(c, source_loc, "unsupported calling convention: SPIR function"); |
| 234 | | return error.UnsupportedType; |
| 235 | | }, |
| 236 | | .OpenCLKernel => { |
| 237 | | try emitWarning(c, source_loc, "unsupported calling convention: OpenCLKernel"); |
| 238 | | return error.UnsupportedType; |
| 239 | | }, |
| 240 | | .Swift => { |
| 241 | | try emitWarning(c, source_loc, "unsupported calling convention: Swift"); |
| 242 | | return error.UnsupportedType; |
| 243 | | }, |
| 244 | | .PreserveMost => { |
| 245 | | try emitWarning(c, source_loc, "unsupported calling convention: PreserveMost"); |
| 246 | | return error.UnsupportedType; |
| 247 | | }, |
| 248 | | .PreserveAll => { |
| 249 | | try emitWarning(c, source_loc, "unsupported calling convention: PreserveAll"); |
| 250 | | return error.UnsupportedType; |
| 251 | | }, |
| 252 | | .AArch64VectorCall => { |
| 253 | | try emitWarning(c, source_loc, "unsupported calling convention: AArch64VectorCall"); |
| 254 | | return error.UnsupportedType; |
| 255 | | }, |
| 213 | .X86FastCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 fastcall"), |
| 214 | .X86ThisCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 thiscall"), |
| 215 | .X86VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 vectorcall"), |
| 216 | .X86Pascal => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 pascal"), |
| 217 | .Win64 => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: win64"), |
| 218 | .X86_64SysV => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 64sysv"), |
| 219 | .X86RegCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 reg"), |
| 220 | .AAPCS => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs"), |
| 221 | .AAPCS_VFP => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs-vfp"), |
| 222 | .IntelOclBicc => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: intel_ocl_bicc"), |
| 223 | .SpirFunction => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: SPIR function"), |
| 224 | .OpenCLKernel => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: OpenCLKernel"), |
| 225 | .Swift => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: Swift"), |
| 226 | .PreserveMost => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveMost"), |
| 227 | .PreserveAll => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveAll"), |
| 228 | .AArch64VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: AArch64VectorCall"), |
| 229 | }; |
| 230 | |
| 231 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 232 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 233 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); |
| 234 | var i: usize = 0; |
| 235 | while (i < param_count) : (i += 1) { |
| 236 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); |
| 237 | } |
| 238 | // TODO check for always_inline attribute |
| 239 | // TODO check for align attribute |
| 240 | |
| 241 | // extern fn (...) T |
| 242 | const cc_tok = if (cc == .stdcall) try appendToken(c, .Keyword_stdcallcc, "stdcallcc") else null; |
| 243 | const extern_tok = if (cc == .c) try appendToken(c, .Keyword_extern, "extern") else null; |
| 244 | const fn_tok = try appendToken(c, .Keyword_fn, "fn"); |
| 245 | const lparen_tok = try appendToken(c, .LParen, "("); |
| 246 | const var_args_tok = if (is_var_args) try appendToken(c, .Ellipsis3, "...") else null; |
| 247 | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 248 | |
| 249 | const return_type_node = blk: { |
| 250 | if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { |
| 251 | break :blk try appendIdentifier(c, "noreturn"); |
| 252 | } else { |
| 253 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: non-noreturn FunctionProto return type"); |
| 254 | //proto_node->data.fn_proto.return_type = trans_qual_type(c, |
| 255 | // ZigClangFunctionType_getReturnType(fn_ty), source_loc); |
| 256 | //if (proto_node->data.fn_proto.return_type == nullptr) { |
| 257 | // emit_warning(c, source_loc, "unsupported function proto return type"); |
| 258 | // return nullptr; |
| 259 | //} |
| 260 | //// convert c_void to actual void (only for return type) |
| 261 | //// we do want to look at the AstNode instead of ZigClangQualType, because |
| 262 | //// if they do something like: |
| 263 | //// typedef Foo void; |
| 264 | //// void foo(void) -> Foo; |
| 265 | //// we want to keep the return type AST node. |
| 266 | //if (is_c_void_type(proto_node->data.fn_proto.return_type)) { |
| 267 | // proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void"); |
| 268 | //} |
| 269 | } |
| 270 | }; |
| 271 | |
| 272 | const fn_proto = try c.a().create(ast.Node.FnProto); |
| 273 | fn_proto.* = ast.Node.FnProto{ |
| 274 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 275 | .doc_comments = null, |
| 276 | .visib_token = null, |
| 277 | .fn_token = fn_tok, |
| 278 | .name_token = null, |
| 279 | .params = ast.Node.FnProto.ParamList.init(c.a()), |
| 280 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 281 | .var_args_token = var_args_tok, |
| 282 | .extern_export_inline_token = extern_tok, |
| 283 | .cc_token = cc_tok, |
| 284 | .async_attr = null, |
| 285 | .body_node = null, |
| 286 | .lib_name = null, |
| 287 | .align_expr = null, |
| 288 | .section_expr = null, |
| 256 | 289 | }; |
| 257 | | try emitWarning(c, source_loc, "TODO: implement transType for FunctionProto"); |
| 258 | | return error.UnsupportedType; |
| 290 | return &fn_proto.base; |
| 259 | 291 | }, |
| 292 | |
| 260 | 293 | else => { |
| 261 | 294 | const type_name = c.str(ZigClangType_getTypeClassName(ty)); |
| 262 | | try emitWarning(c, source_loc, "unsupported type: '{}'", type_name); |
| 263 | | return error.UnsupportedType; |
| 295 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name); |
| 264 | 296 | }, |
| 265 | 297 | } |
| 266 | 298 | } |
| 267 | 299 | |
| 300 | fn revertAndWarn( |
| 301 | restore_point: RestorePoint, |
| 302 | err: var, |
| 303 | source_loc: ZigClangSourceLocation, |
| 304 | comptime format: []const u8, |
| 305 | args: ..., |
| 306 | ) (@typeOf(err) || error{OutOfMemory}) { |
| 307 | restore_point.activate(); |
| 308 | try emitWarning(restore_point.context, source_loc, format, args); |
| 309 | return err; |
| 310 | } |
| 311 | |
| 268 | 312 | fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []const u8, args: ...) !void { |
| 269 | | try appendToken(c, .LineComment, "// {}: warning: " ++ format, c.locStr(loc), args); |
| 313 | _ = try appendToken(c, .LineComment, "// {}: warning: " ++ format, c.locStr(loc), args); |
| 314 | } |
| 315 | |
| 316 | fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: ...) !void { |
| 317 | // const name = @compileError(msg); |
| 318 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| 319 | const name_tok = try appendToken(c, .Identifier, "{}", name); |
| 320 | const eq_tok = try appendToken(c, .Equal, "="); |
| 321 | const builtin_tok = try appendToken(c, .Builtin, "@compileError"); |
| 322 | const lparen_tok = try appendToken(c, .LParen, "("); |
| 323 | const msg_tok = try appendToken(c, .StringLiteral, "\"" ++ format ++ "\"", args); |
| 324 | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 325 | const semi_tok = try appendToken(c, .Semicolon, ";"); |
| 326 | |
| 327 | const msg_node = try c.a().create(ast.Node.StringLiteral); |
| 328 | msg_node.* = ast.Node.StringLiteral{ |
| 329 | .base = ast.Node{ .id = ast.Node.Id.StringLiteral }, |
| 330 | .token = msg_tok, |
| 331 | }; |
| 332 | |
| 333 | const call_node = try c.a().create(ast.Node.BuiltinCall); |
| 334 | call_node.* = ast.Node.BuiltinCall{ |
| 335 | .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, |
| 336 | .builtin_token = builtin_tok, |
| 337 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), |
| 338 | .rparen_token = rparen_tok, |
| 339 | }; |
| 340 | try call_node.params.push(&msg_node.base); |
| 341 | |
| 342 | const var_decl_node = try c.a().create(ast.Node.VarDecl); |
| 343 | var_decl_node.* = ast.Node.VarDecl{ |
| 344 | .base = ast.Node{ .id = ast.Node.Id.VarDecl }, |
| 345 | .doc_comments = null, |
| 346 | .visib_token = null, |
| 347 | .thread_local_token = null, |
| 348 | .name_token = name_tok, |
| 349 | .eq_token = eq_tok, |
| 350 | .mut_token = const_tok, |
| 351 | .comptime_token = null, |
| 352 | .extern_export_token = null, |
| 353 | .lib_name = null, |
| 354 | .type_node = null, |
| 355 | .align_node = null, |
| 356 | .section_node = null, |
| 357 | .init_node = &call_node.base, |
| 358 | .semicolon_token = semi_tok, |
| 359 | }; |
| 360 | try c.tree.root_node.decls.push(&var_decl_node.base); |
| 270 | 361 | } |
| 271 | 362 | |
| 272 | | fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, args: ...) !void { |
| 363 | fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, args: ...) !ast.TokenIndex { |
| 273 | 364 | const S = struct { |
| 274 | 365 | fn callback(context: *Context, bytes: []const u8) Error!void { |
| 275 | 366 | return context.source_buffer.append(bytes); |
| ... | ... | @@ -280,8 +371,9 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg |
| 280 | 371 | |
| 281 | 372 | try std.fmt.format(c, Error, S.callback, format, args); |
| 282 | 373 | const end_index = c.source_buffer.len(); |
| 374 | const token_index = c.tree.tokens.len; |
| 283 | 375 | const new_token = try c.tree.tokens.addOne(); |
| 284 | | errdefer c.tree.tokens.shrink(c.tree.tokens.len - 1); |
| 376 | errdefer c.tree.tokens.shrink(token_index); |
| 285 | 377 | |
| 286 | 378 | new_token.* = Token{ |
| 287 | 379 | .id = token_id, |
| ... | ... | @@ -289,6 +381,18 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg |
| 289 | 381 | .end = end_index, |
| 290 | 382 | }; |
| 291 | 383 | try c.source_buffer.appendByte('\n'); |
| 384 | |
| 385 | return token_index; |
| 386 | } |
| 387 | |
| 388 | fn appendIdentifier(c: *Context, name: []const u8) !*ast.Node { |
| 389 | const token_index = try appendToken(c, .Identifier, "{}", name); |
| 390 | const identifier = try c.a().create(ast.Node.Identifier); |
| 391 | identifier.* = ast.Node.Identifier{ |
| 392 | .base = ast.Node{ .id = ast.Node.Id.Identifier }, |
| 393 | .token = token_index, |
| 394 | }; |
| 395 | return &identifier.base; |
| 292 | 396 | } |
| 293 | 397 | |
| 294 | 398 | pub fn freeErrors(errors: []ClangErrMsg) void { |