| ... | @@ -272,7 +272,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -272,7 +272,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 272 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { | 272 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 273 | .FunctionProto => blk: { | 273 | .FunctionProto => blk: { |
| 274 | const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); | 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 | error.UnsupportedType => { | 276 | error.UnsupportedType => { |
| 277 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{}); | 277 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{}); |
| 278 | }, | 278 | }, |
| ... | @@ -338,6 +338,7 @@ fn transStmt( | ... | @@ -338,6 +338,7 @@ fn transStmt( |
| 338 | .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), | 338 | .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), |
| 339 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), | 339 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), |
| 340 | .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), | 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 | else => { | 342 | else => { |
| 342 | return revertAndWarn( | 343 | return revertAndWarn( |
| 343 | rp, | 344 | rp, |
| ... | @@ -393,9 +394,67 @@ fn transBinaryOperator( | ... | @@ -393,9 +394,67 @@ fn transBinaryOperator( |
| 393 | .node_scope = scope, | 394 | .node_scope = scope, |
| 394 | }); | 395 | }); |
| 395 | }, | 396 | }, |
| 396 | .Mul, | 397 | .Mul => { |
| 397 | .Div, | 398 | const node = if (cIsUnsignedInteger(qt)) |
| 398 | .Rem, | 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 | .Shl, | 458 | .Shl, |
| 400 | .Shr, | 459 | .Shr, |
| 401 | .LT, | 460 | .LT, |
| ... | @@ -1119,11 +1178,11 @@ fn transCreateNodePtrType( | ... | @@ -1119,11 +1178,11 @@ fn transCreateNodePtrType( |
| 1119 | break :blk lbracket; | 1178 | break :blk lbracket; |
| 1120 | }, | 1179 | }, |
| 1121 | .Identifier => blk: { | 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 | _ = try appendToken(c, .Asterisk, "*"); | 1182 | _ = try appendToken(c, .Asterisk, "*"); |
| 1124 | const c_ident = try appendToken(c, .Identifier, "c"); | 1183 | _ = try appendToken(c, .Identifier, "c"); |
| 1125 | _ = try appendToken(c, .RBracket, "]"); | 1184 | _ = try appendToken(c, .RBracket, "]"); |
| 1126 | break :blk c_ident; | 1185 | break :blk lbracket; |
| 1127 | }, | 1186 | }, |
| 1128 | .Asterisk => try appendToken(c, .Asterisk, "*"), | 1187 | .Asterisk => try appendToken(c, .Asterisk, "*"), |
| 1129 | else => unreachable, | 1188 | else => unreachable, |
| ... | @@ -1222,7 +1281,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -1222,7 +1281,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 1222 | }, | 1281 | }, |
| 1223 | .FunctionProto => { | 1282 | .FunctionProto => { |
| 1224 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); | 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 | return &fn_proto.base; | 1285 | return &fn_proto.base; |
| 1227 | }, | 1286 | }, |
| 1228 | .Paren => { | 1287 | .Paren => { |
| ... | @@ -1293,6 +1352,7 @@ fn transCC( | ... | @@ -1293,6 +1352,7 @@ fn transCC( |
| 1293 | | 1352 | |
| 1294 | fn transFnProto( | 1353 | fn transFnProto( |
| 1295 | rp: RestorePoint, | 1354 | rp: RestorePoint, |
| | 1355 | fn_decl: ?*const ZigClangFunctionDecl, |
| 1296 | fn_proto_ty: *const ZigClangFunctionProtoType, | 1356 | fn_proto_ty: *const ZigClangFunctionProtoType, |
| 1297 | source_loc: ZigClangSourceLocation, | 1357 | source_loc: ZigClangSourceLocation, |
| 1298 | fn_decl_context: ?FnDeclContext, | 1358 | fn_decl_context: ?FnDeclContext, |
| ... | @@ -1301,19 +1361,7 @@ fn transFnProto( | ... | @@ -1301,19 +1361,7 @@ fn transFnProto( |
| 1301 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); | 1361 | const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); |
| 1302 | const cc = try transCC(rp, fn_ty, source_loc); | 1362 | const cc = try transCC(rp, fn_ty, source_loc); |
| 1303 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); | 1363 | const is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); |
| 1304 | const param_count: usize = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); | 1364 | return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 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); | | |
| 1317 | } | 1365 | } |
| 1318 | | 1366 | |
| 1319 | fn transFnNoProto( | 1367 | fn transFnNoProto( |
| ... | @@ -1325,11 +1373,13 @@ fn transFnNoProto( | ... | @@ -1325,11 +1373,13 @@ fn transFnNoProto( |
| 1325 | ) !*ast.Node.FnProto { | 1373 | ) !*ast.Node.FnProto { |
| 1326 | const cc = try transCC(rp, fn_ty, source_loc); | 1374 | const cc = try transCC(rp, fn_ty, source_loc); |
| 1327 | const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true; | 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 | fn finishTransFnProto( | 1379 | fn finishTransFnProto( |
| 1332 | rp: RestorePoint, | 1380 | rp: RestorePoint, |
| | 1381 | fn_decl: ?*const ZigClangFunctionDecl, |
| | 1382 | fn_proto_ty: ?*const ZigClangFunctionProtoType, |
| 1333 | fn_ty: *const ZigClangFunctionType, | 1383 | fn_ty: *const ZigClangFunctionType, |
| 1334 | source_loc: ZigClangSourceLocation, | 1384 | source_loc: ZigClangSourceLocation, |
| 1335 | fn_decl_context: ?FnDeclContext, | 1385 | fn_decl_context: ?FnDeclContext, |
| ... | @@ -1355,7 +1405,67 @@ fn finishTransFnProto( | ... | @@ -1355,7 +1405,67 @@ fn finishTransFnProto( |
| 1355 | const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); | 1405 | const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); |
| 1356 | const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null; | 1406 | const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null; |
| 1357 | const lparen_tok = try appendToken(rp.c, .LParen, "("); | 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 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); | 1469 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| 1360 | | 1470 | |
| 1361 | const return_type_node = blk: { | 1471 | const return_type_node = blk: { |
| ... | @@ -1384,7 +1494,7 @@ fn finishTransFnProto( | ... | @@ -1384,7 +1494,7 @@ fn finishTransFnProto( |
| 1384 | .visib_token = pub_tok, | 1494 | .visib_token = pub_tok, |
| 1385 | .fn_token = fn_tok, | 1495 | .fn_token = fn_tok, |
| 1386 | .name_token = name_tok, | 1496 | .name_token = name_tok, |
| 1387 | .params = ast.Node.FnProto.ParamList.init(rp.c.a()), | 1497 | .params = fn_params, |
| 1388 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, | 1498 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, |
| 1389 | .var_args_token = null, // TODO this field is broken in the AST data model | 1499 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 1390 | .extern_export_inline_token = extern_export_inline_tok, | 1500 | .extern_export_inline_token = extern_export_inline_tok, |
| ... | @@ -1394,19 +1504,6 @@ fn finishTransFnProto( | ... | @@ -1394,19 +1504,6 @@ fn finishTransFnProto( |
| 1394 | .align_expr = null, | 1504 | .align_expr = null, |
| 1395 | .section_expr = null, | 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 | return fn_proto; | 1507 | return fn_proto; |
| 1411 | } | 1508 | } |
| 1412 | | 1509 | |