| ... | ... | @@ -272,7 +272,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 272 | 272 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 273 | 273 | .FunctionProto => blk: { |
| 274 | 274 | const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); |
| 275 | | break :blk transFnProto(rp, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 275 | break :blk transFnProto(rp, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 276 | 276 | error.UnsupportedType => { |
| 277 | 277 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{}); |
| 278 | 278 | }, |
| ... | ... | @@ -338,6 +338,7 @@ fn transStmt( |
| 338 | 338 | .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), |
| 339 | 339 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), |
| 340 | 340 | .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), |
| 341 | .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue), |
| 341 | 342 | else => { |
| 342 | 343 | return revertAndWarn( |
| 343 | 344 | rp, |
| ... | ... | @@ -393,9 +394,67 @@ fn transBinaryOperator( |
| 393 | 394 | .node_scope = scope, |
| 394 | 395 | }); |
| 395 | 396 | }, |
| 396 | | .Mul, |
| 397 | | .Div, |
| 398 | | .Rem, |
| 397 | .Mul => { |
| 398 | const node = if (cIsUnsignedInteger(qt)) |
| 399 | try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true) |
| 400 | else |
| 401 | try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true); |
| 402 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 403 | .node = node, |
| 404 | .child_scope = scope, |
| 405 | .node_scope = scope, |
| 406 | }); |
| 407 | }, |
| 408 | .Div => { |
| 409 | if (!cIsUnsignedInteger(qt)) { |
| 410 | // signed integer division uses @divTrunc |
| 411 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); |
| 412 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); |
| 413 | try div_trunc_node.params.push(lhs.node); |
| 414 | _ = try appendToken(rp.c, .Comma, ","); |
| 415 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 416 | try div_trunc_node.params.push(rhs.node); |
| 417 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 418 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 419 | .node = &div_trunc_node.base, |
| 420 | .child_scope = scope, |
| 421 | .node_scope = scope, |
| 422 | }); |
| 423 | } else { |
| 424 | // unsigned/float division uses the operator |
| 425 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true); |
| 426 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 427 | .node = node, |
| 428 | .child_scope = scope, |
| 429 | .node_scope = scope, |
| 430 | }); |
| 431 | } |
| 432 | }, |
| 433 | .Rem => { |
| 434 | if (!cIsUnsignedInteger(qt)) { |
| 435 | // signed integer division uses @rem |
| 436 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); |
| 437 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); |
| 438 | try rem_node.params.push(lhs.node); |
| 439 | _ = try appendToken(rp.c, .Comma, ","); |
| 440 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 441 | try rem_node.params.push(rhs.node); |
| 442 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 443 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 444 | .node = &rem_node.base, |
| 445 | .child_scope = scope, |
| 446 | .node_scope = scope, |
| 447 | }); |
| 448 | } else { |
| 449 | // unsigned/float division uses the operator |
| 450 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true); |
| 451 | return maybeSuppressResult(rp, scope, result_used, TransResult{ |
| 452 | .node = node, |
| 453 | .child_scope = scope, |
| 454 | .node_scope = scope, |
| 455 | }); |
| 456 | } |
| 457 | }, |
| 399 | 458 | .Shl, |
| 400 | 459 | .Shr, |
| 401 | 460 | .LT, |
| ... | ... | @@ -1119,11 +1178,11 @@ fn transCreateNodePtrType( |
| 1119 | 1178 | break :blk lbracket; |
| 1120 | 1179 | }, |
| 1121 | 1180 | .Identifier => blk: { |
| 1122 | | _ = try appendToken(c, .LBracket, "["); |
| 1181 | const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token |
| 1123 | 1182 | _ = try appendToken(c, .Asterisk, "*"); |
| 1124 | | const c_ident = try appendToken(c, .Identifier, "c"); |
| 1183 | _ = try appendToken(c, .Identifier, "c"); |
| 1125 | 1184 | _ = try appendToken(c, .RBracket, "]"); |
| 1126 | | break :blk c_ident; |
| 1185 | break :blk lbracket; |
| 1127 | 1186 | }, |
| 1128 | 1187 | .Asterisk => try appendToken(c, .Asterisk, "*"), |
| 1129 | 1188 | else => unreachable, |
| ... | ... | @@ -1222,7 +1281,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 1222 | 1281 | }, |
| 1223 | 1282 | .FunctionProto => { |
| 1224 | 1283 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 1225 | | const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, false); |
| 1284 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); |
| 1226 | 1285 | return &fn_proto.base; |
| 1227 | 1286 | }, |
| 1228 | 1287 | .Paren => { |
| ... | ... | @@ -1293,6 +1352,7 @@ fn transCC( |
| 1293 | 1352 | |
| 1294 | 1353 | fn transFnProto( |
| 1295 | 1354 | rp: RestorePoint, |
| 1355 | fn_decl: ?*const ZigClangFunctionDecl, |
| 1296 | 1356 | fn_proto_ty: *const ZigClangFunctionProtoType, |
| 1297 | 1357 | source_loc: ZigClangSourceLocation, |
| 1298 | 1358 | fn_decl_context: ?FnDeclContext, |
| ... | ... | @@ -1301,19 +1361,7 @@ fn transFnProto( |
| 1301 | 1361 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); |
| 1302 | 1362 | const cc = try transCC(rp, fn_ty, source_loc); |
| 1303 | 1363 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 1304 | | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); |
| 1305 | | var i: usize = 0; |
| 1306 | | while (i < param_count) : (i += 1) { |
| 1307 | | return revertAndWarn( |
| 1308 | | rp, |
| 1309 | | error.UnsupportedType, |
| 1310 | | source_loc, |
| 1311 | | "TODO: implement parameters for FunctionProto in transType", |
| 1312 | | .{}, |
| 1313 | | ); |
| 1314 | | } |
| 1315 | | |
| 1316 | | return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 1364 | return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 1317 | 1365 | } |
| 1318 | 1366 | |
| 1319 | 1367 | fn transFnNoProto( |
| ... | ... | @@ -1325,11 +1373,13 @@ fn transFnNoProto( |
| 1325 | 1373 | ) !*ast.Node.FnProto { |
| 1326 | 1374 | const cc = try transCC(rp, fn_ty, source_loc); |
| 1327 | 1375 | const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true; |
| 1328 | | return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 1376 | return finishTransFnProto(rp, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 1329 | 1377 | } |
| 1330 | 1378 | |
| 1331 | 1379 | fn finishTransFnProto( |
| 1332 | 1380 | rp: RestorePoint, |
| 1381 | fn_decl: ?*const ZigClangFunctionDecl, |
| 1382 | fn_proto_ty: ?*const ZigClangFunctionProtoType, |
| 1333 | 1383 | fn_ty: *const ZigClangFunctionType, |
| 1334 | 1384 | source_loc: ZigClangSourceLocation, |
| 1335 | 1385 | fn_decl_context: ?FnDeclContext, |
| ... | ... | @@ -1355,7 +1405,67 @@ fn finishTransFnProto( |
| 1355 | 1405 | const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); |
| 1356 | 1406 | const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null; |
| 1357 | 1407 | const lparen_tok = try appendToken(rp.c, .LParen, "("); |
| 1358 | | const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null; |
| 1408 | |
| 1409 | var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a()); |
| 1410 | const param_count: usize = if (fn_proto_ty != null) ZigClangFunctionProtoType_getNumParams(fn_proto_ty.?) else 0; |
| 1411 | |
| 1412 | var i: usize = 0; |
| 1413 | while (i < param_count) : (i += 1) { |
| 1414 | const param_qt = ZigClangFunctionProtoType_getParamType(fn_proto_ty.?, @intCast(c_uint, i)); |
| 1415 | |
| 1416 | const noalias_tok = if (ZigClangQualType_isRestrictQualified(param_qt)) try appendToken(rp.c, .Keyword_noalias, "noalias") else null; |
| 1417 | |
| 1418 | const param_name_tok: ?ast.TokenIndex = blk: { |
| 1419 | if (fn_decl != null) { |
| 1420 | const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i)); |
| 1421 | const param_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); |
| 1422 | if (param_name.len > 0) { |
| 1423 | // TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank? |
| 1424 | const result = try appendToken(rp.c, .Identifier, param_name); |
| 1425 | _ = try appendToken(rp.c, .Colon, ":"); |
| 1426 | break :blk result; |
| 1427 | } |
| 1428 | } |
| 1429 | break :blk null; |
| 1430 | }; |
| 1431 | |
| 1432 | const type_node = try transQualType(rp, param_qt, source_loc); |
| 1433 | |
| 1434 | const param_node = try rp.c.a().create(ast.Node.ParamDecl); |
| 1435 | param_node.* = ast.Node.ParamDecl{ |
| 1436 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| 1437 | .doc_comments = null, |
| 1438 | .comptime_token = null, |
| 1439 | .noalias_token = noalias_tok, |
| 1440 | .name_token = param_name_tok, |
| 1441 | .type_node = type_node, |
| 1442 | .var_args_token = null, |
| 1443 | }; |
| 1444 | try fn_params.push(&param_node.base); |
| 1445 | |
| 1446 | if (i + 1 < param_count) { |
| 1447 | _ = try appendToken(rp.c, .Comma, ","); |
| 1448 | } |
| 1449 | } |
| 1450 | |
| 1451 | if (is_var_args) { |
| 1452 | if (param_count > 0) { |
| 1453 | _ = try appendToken(rp.c, .Comma, ","); |
| 1454 | } |
| 1455 | |
| 1456 | const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl); |
| 1457 | var_arg_node.* = ast.Node.ParamDecl{ |
| 1458 | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| 1459 | .doc_comments = null, |
| 1460 | .comptime_token = null, |
| 1461 | .noalias_token = null, |
| 1462 | .name_token = null, |
| 1463 | .type_node = undefined, // Note: Accessing this causes an access violation. Need to check .var_args_token first before trying this field |
| 1464 | .var_args_token = try appendToken(rp.c, .Ellipsis3, "..."), |
| 1465 | }; |
| 1466 | try fn_params.push(&var_arg_node.base); |
| 1467 | } |
| 1468 | |
| 1359 | 1469 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| 1360 | 1470 | |
| 1361 | 1471 | const return_type_node = blk: { |
| ... | ... | @@ -1384,7 +1494,7 @@ fn finishTransFnProto( |
| 1384 | 1494 | .visib_token = pub_tok, |
| 1385 | 1495 | .fn_token = fn_tok, |
| 1386 | 1496 | .name_token = name_tok, |
| 1387 | | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), |
| 1497 | .params = fn_params, |
| 1388 | 1498 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 1389 | 1499 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 1390 | 1500 | .extern_export_inline_token = extern_export_inline_tok, |
| ... | ... | @@ -1394,19 +1504,6 @@ fn finishTransFnProto( |
| 1394 | 1504 | .align_expr = null, |
| 1395 | 1505 | .section_expr = null, |
| 1396 | 1506 | }; |
| 1397 | | if (is_var_args) { |
| 1398 | | const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl); |
| 1399 | | var_arg_node.* = ast.Node.ParamDecl{ |
| 1400 | | .base = ast.Node{ .id = ast.Node.Id.ParamDecl }, |
| 1401 | | .doc_comments = null, |
| 1402 | | .comptime_token = null, |
| 1403 | | .noalias_token = null, |
| 1404 | | .name_token = null, |
| 1405 | | .type_node = undefined, |
| 1406 | | .var_args_token = var_args_tok, |
| 1407 | | }; |
| 1408 | | try fn_proto.params.push(&var_arg_node.base); |
| 1409 | | } |
| 1410 | 1507 | return fn_proto; |
| 1411 | 1508 | } |
| 1412 | 1509 | |