| ... | @@ -110,7 +110,7 @@ pub fn translate( | ... | @@ -110,7 +110,7 @@ pub fn translate( |
| 110 | return context.err; | 110 | return context.err; |
| 111 | } | 111 | } |
| 112 | | 112 | |
| 113 | try appendToken(&context, .Eof, ""); | 113 | _ = try appendToken(&context, .Eof, ""); |
| 114 | tree.source = source_buffer.toOwnedSlice(); | 114 | tree.source = source_buffer.toOwnedSlice(); |
| 115 | return tree; | 115 | return tree; |
| 116 | } | 116 | } |
| ... | @@ -149,7 +149,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { | ... | @@ -149,7 +149,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 149 | } | 149 | } |
| 150 | | 150 | |
| 151 | fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | 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 | // TODO The C++ code has this: | 154 | // TODO The C++ code has this: |
| 155 | //if (get_global(c, fn_name)) { | 155 | //if (get_global(c, fn_name)) { |
| ... | @@ -160,28 +160,49 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -160,28 +160,49 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 160 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); | 160 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); |
| 161 | const proto_node = transQualType(c, ZigClangFunctionDecl_getType(fn_decl), fn_decl_loc) catch |e| switch (e) { | 161 | const proto_node = transQualType(c, ZigClangFunctionDecl_getType(fn_decl), fn_decl_loc) catch |e| switch (e) { |
| 162 | error.UnsupportedType => { | 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 | return; | 164 | return; |
| 165 | }, | 165 | }, |
| 166 | else => return e, | 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 | fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node { | 175 | fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| 173 | return transType(c, ZigClangQualType_getTypePtr(qt), source_loc); | 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 | fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node { | 198 | fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node { |
| | 199 | const rp = makeRestorePoint(c); |
| | 200 | |
| 177 | switch (ZigClangType_getTypeClass(ty)) { | 201 | switch (ZigClangType_getTypeClass(ty)) { |
| 178 | .Builtin => { | 202 | .Builtin => { |
| 179 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); | 203 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 180 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { | 204 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 181 | else => { | 205 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"), |
| 182 | try emitWarning(c, source_loc, "unsupported builtin type"); | | |
| 183 | return error.UnsupportedType; | | |
| 184 | }, | | |
| 185 | } | 206 | } |
| 186 | }, | 207 | }, |
| 187 | .FunctionProto => { | 208 | .FunctionProto => { |
| ... | @@ -189,87 +210,157 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc | ... | @@ -189,87 +210,157 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc |
| 189 | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { | 210 | const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) { |
| 190 | .C => CallingConvention.c, | 211 | .C => CallingConvention.c, |
| 191 | .X86StdCall => CallingConvention.stdcall, | 212 | .X86StdCall => CallingConvention.stdcall, |
| 192 | .X86FastCall => { | 213 | .X86FastCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 fastcall"), |
| 193 | try emitWarning(c, source_loc, "unsupported calling convention: x86 fastcall"); | 214 | .X86ThisCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 thiscall"), |
| 194 | return error.UnsupportedType; | 215 | .X86VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 vectorcall"), |
| 195 | }, | 216 | .X86Pascal => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 pascal"), |
| 196 | .X86ThisCall => { | 217 | .Win64 => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: win64"), |
| 197 | try emitWarning(c, source_loc, "unsupported calling convention: x86 thiscall"); | 218 | .X86_64SysV => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 64sysv"), |
| 198 | return error.UnsupportedType; | 219 | .X86RegCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: x86 reg"), |
| 199 | }, | 220 | .AAPCS => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs"), |
| 200 | .X86VectorCall => { | 221 | .AAPCS_VFP => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: aapcs-vfp"), |
| 201 | try emitWarning(c, source_loc, "unsupported calling convention: x86 vectorcall"); | 222 | .IntelOclBicc => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: intel_ocl_bicc"), |
| 202 | return error.UnsupportedType; | 223 | .SpirFunction => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: SPIR function"), |
| 203 | }, | 224 | .OpenCLKernel => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: OpenCLKernel"), |
| 204 | .X86Pascal => { | 225 | .Swift => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: Swift"), |
| 205 | try emitWarning(c, source_loc, "unsupported calling convention: x86 pascal"); | 226 | .PreserveMost => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveMost"), |
| 206 | return error.UnsupportedType; | 227 | .PreserveAll => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: PreserveAll"), |
| 207 | }, | 228 | .AArch64VectorCall => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported calling convention: AArch64VectorCall"), |
| 208 | .Win64 => { | 229 | }; |
| 209 | try emitWarning(c, source_loc, "unsupported calling convention: win64"); | 230 | |
| 210 | return error.UnsupportedType; | 231 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 211 | }, | 232 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 212 | .X86_64SysV => { | 233 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); |
| 213 | try emitWarning(c, source_loc, "unsupported calling convention: x86 64sysv"); | 234 | var i: usize = 0; |
| 214 | return error.UnsupportedType; | 235 | while (i < param_count) : (i += 1) { |
| 215 | }, | 236 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); |
| 216 | .X86RegCall => { | 237 | } |
| 217 | try emitWarning(c, source_loc, "unsupported calling convention: x86 reg"); | 238 | // TODO check for always_inline attribute |
| 218 | return error.UnsupportedType; | 239 | // TODO check for align attribute |
| 219 | }, | 240 | |
| 220 | .AAPCS => { | 241 | // extern fn (...) T |
| 221 | try emitWarning(c, source_loc, "unsupported calling convention: aapcs"); | 242 | const cc_tok = if (cc == .stdcall) try appendToken(c, .Keyword_stdcallcc, "stdcallcc") else null; |
| 222 | return error.UnsupportedType; | 243 | const extern_tok = if (cc == .c) try appendToken(c, .Keyword_extern, "extern") else null; |
| 223 | }, | 244 | const fn_tok = try appendToken(c, .Keyword_fn, "fn"); |
| 224 | .AAPCS_VFP => { | 245 | const lparen_tok = try appendToken(c, .LParen, "("); |
| 225 | try emitWarning(c, source_loc, "unsupported calling convention: aapcs-vfp"); | 246 | const var_args_tok = if (is_var_args) try appendToken(c, .Ellipsis3, "...") else null; |
| 226 | return error.UnsupportedType; | 247 | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 227 | }, | 248 | |
| 228 | .IntelOclBicc => { | 249 | const return_type_node = blk: { |
| 229 | try emitWarning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); | 250 | if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { |
| 230 | return error.UnsupportedType; | 251 | break :blk try appendIdentifier(c, "noreturn"); |
| 231 | }, | 252 | } else { |
| 232 | .SpirFunction => { | 253 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: non-noreturn FunctionProto return type"); |
| 233 | try emitWarning(c, source_loc, "unsupported calling convention: SPIR function"); | 254 | //proto_node->data.fn_proto.return_type = trans_qual_type(c, |
| 234 | return error.UnsupportedType; | 255 | // ZigClangFunctionType_getReturnType(fn_ty), source_loc); |
| 235 | }, | 256 | //if (proto_node->data.fn_proto.return_type == nullptr) { |
| 236 | .OpenCLKernel => { | 257 | // emit_warning(c, source_loc, "unsupported function proto return type"); |
| 237 | try emitWarning(c, source_loc, "unsupported calling convention: OpenCLKernel"); | 258 | // return nullptr; |
| 238 | return error.UnsupportedType; | 259 | //} |
| 239 | }, | 260 | //// convert c_void to actual void (only for return type) |
| 240 | .Swift => { | 261 | //// we do want to look at the AstNode instead of ZigClangQualType, because |
| 241 | try emitWarning(c, source_loc, "unsupported calling convention: Swift"); | 262 | //// if they do something like: |
| 242 | return error.UnsupportedType; | 263 | //// typedef Foo void; |
| 243 | }, | 264 | //// void foo(void) -> Foo; |
| 244 | .PreserveMost => { | 265 | //// we want to keep the return type AST node. |
| 245 | try emitWarning(c, source_loc, "unsupported calling convention: PreserveMost"); | 266 | //if (is_c_void_type(proto_node->data.fn_proto.return_type)) { |
| 246 | return error.UnsupportedType; | 267 | // proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void"); |
| 247 | }, | 268 | //} |
| 248 | .PreserveAll => { | 269 | } |
| 249 | try emitWarning(c, source_loc, "unsupported calling convention: PreserveAll"); | 270 | }; |
| 250 | return error.UnsupportedType; | 271 | |
| 251 | }, | 272 | const fn_proto = try c.a().create(ast.Node.FnProto); |
| 252 | .AArch64VectorCall => { | 273 | fn_proto.* = ast.Node.FnProto{ |
| 253 | try emitWarning(c, source_loc, "unsupported calling convention: AArch64VectorCall"); | 274 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, |
| 254 | return error.UnsupportedType; | 275 | .doc_comments = null, |
| 255 | }, | 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"); | 290 | return &fn_proto.base; |
| 258 | return error.UnsupportedType; | | |
| 259 | }, | 291 | }, |
| | 292 | |
| 260 | else => { | 293 | else => { |
| 261 | const type_name = c.str(ZigClangType_getTypeClassName(ty)); | 294 | const type_name = c.str(ZigClangType_getTypeClassName(ty)); |
| 262 | try emitWarning(c, source_loc, "unsupported type: '{}'", type_name); | 295 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name); |
| 263 | return error.UnsupportedType; | | |
| 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 | fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []const u8, args: ...) !void { | 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 | const S = struct { | 364 | const S = struct { |
| 274 | fn callback(context: *Context, bytes: []const u8) Error!void { | 365 | fn callback(context: *Context, bytes: []const u8) Error!void { |
| 275 | return context.source_buffer.append(bytes); | 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,8 +371,9 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg |
| 280 | | 371 | |
| 281 | try std.fmt.format(c, Error, S.callback, format, args); | 372 | try std.fmt.format(c, Error, S.callback, format, args); |
| 282 | const end_index = c.source_buffer.len(); | 373 | const end_index = c.source_buffer.len(); |
| | 374 | const token_index = c.tree.tokens.len; |
| 283 | const new_token = try c.tree.tokens.addOne(); | 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 | new_token.* = Token{ | 378 | new_token.* = Token{ |
| 287 | .id = token_id, | 379 | .id = token_id, |
| ... | @@ -289,6 +381,18 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg | ... | @@ -289,6 +381,18 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg |
| 289 | .end = end_index, | 381 | .end = end_index, |
| 290 | }; | 382 | }; |
| 291 | try c.source_buffer.appendByte('\n'); | 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 | pub fn freeErrors(errors: []ClangErrMsg) void { | 398 | pub fn freeErrors(errors: []ClangErrMsg) void { |