| ... | ... | @@ -19,6 +19,7 @@ const Body = ir.Body; |
| 19 | 19 | const ast = std.zig.ast; |
| 20 | 20 | const trace = @import("tracy.zig").trace; |
| 21 | 21 | const liveness = @import("liveness.zig"); |
| 22 | const astgen = @import("astgen.zig"); |
| 22 | 23 | |
| 23 | 24 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 24 | 25 | gpa: *Allocator, |
| ... | ... | @@ -76,6 +77,8 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{}, |
| 76 | 77 | |
| 77 | 78 | keep_source_files_loaded: bool, |
| 78 | 79 | |
| 80 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 81 | |
| 79 | 82 | const WorkItem = union(enum) { |
| 80 | 83 | /// Write the machine code for a Decl to the output file. |
| 81 | 84 | codegen_decl: *Decl, |
| ... | ... | @@ -944,8 +947,6 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 944 | 947 | }; |
| 945 | 948 | } |
| 946 | 949 | |
| 947 | | const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 948 | | |
| 949 | 950 | pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { |
| 950 | 951 | while (self.work_queue.readItem()) |work_item| switch (work_item) { |
| 951 | 952 | .codegen_decl => |decl| switch (decl.analysis) { |
| ... | ... | @@ -1140,7 +1141,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1140 | 1141 | .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}), |
| 1141 | 1142 | .type_expr => |node| node, |
| 1142 | 1143 | }; |
| 1143 | | param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node); |
| 1144 | param_types[i] = try astgen.expr(self, &fn_type_scope.base, param_type_node); |
| 1144 | 1145 | } |
| 1145 | 1146 | if (fn_proto.getTrailer("var_args_token")) |var_args_token| { |
| 1146 | 1147 | return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{}); |
| ... | ... | @@ -1168,7 +1169,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1168 | 1169 | .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}), |
| 1169 | 1170 | }; |
| 1170 | 1171 | |
| 1171 | | const return_type_inst = try self.astGenExpr(&fn_type_scope.base, return_type_expr); |
| 1172 | const return_type_inst = try astgen.expr(self, &fn_type_scope.base, return_type_expr); |
| 1172 | 1173 | const fn_src = tree.token_locs[fn_proto.fn_token].start; |
| 1173 | 1174 | const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{ |
| 1174 | 1175 | .return_type = return_type_inst, |
| ... | ... | @@ -1209,7 +1210,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1209 | 1210 | |
| 1210 | 1211 | const body_block = body_node.cast(ast.Node.Block).?; |
| 1211 | 1212 | |
| 1212 | | try self.astGenBlock(&gen_scope.base, body_block); |
| 1213 | try astgen.blockExpr(self, &gen_scope.base, body_block); |
| 1213 | 1214 | |
| 1214 | 1215 | if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or |
| 1215 | 1216 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())) |
| ... | ... | @@ -1298,465 +1299,6 @@ fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Mo |
| 1298 | 1299 | unreachable; |
| 1299 | 1300 | } |
| 1300 | 1301 | |
| 1301 | | fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst { |
| 1302 | | switch (ast_node.id) { |
| 1303 | | .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)), |
| 1304 | | .Asm => return self.astGenAsm(scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)), |
| 1305 | | .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)), |
| 1306 | | .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)), |
| 1307 | | .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)), |
| 1308 | | .Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)), |
| 1309 | | .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)), |
| 1310 | | .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)), |
| 1311 | | .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)), |
| 1312 | | .InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)), |
| 1313 | | .BoolNot => return self.astGenBoolNot(scope, @fieldParentPtr(ast.Node.BoolNot, "base", ast_node)), |
| 1314 | | else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}), |
| 1315 | | } |
| 1316 | | } |
| 1317 | | |
| 1318 | | fn astGenBoolNot(self: *Module, scope: *Scope, node: *ast.Node.BoolNot) InnerError!*zir.Inst { |
| 1319 | | const operand = try self.astGenExpr(scope, node.rhs); |
| 1320 | | const tree = scope.tree(); |
| 1321 | | const src = tree.token_locs[node.op_token].start; |
| 1322 | | return self.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{}); |
| 1323 | | } |
| 1324 | | |
| 1325 | | fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst { |
| 1326 | | switch (infix_node.op) { |
| 1327 | | .Assign => { |
| 1328 | | if (infix_node.lhs.id == .Identifier) { |
| 1329 | | const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs); |
| 1330 | | const tree = scope.tree(); |
| 1331 | | const ident_name = tree.tokenSlice(ident.token); |
| 1332 | | if (std.mem.eql(u8, ident_name, "_")) { |
| 1333 | | return self.astGenExpr(scope, infix_node.rhs); |
| 1334 | | } else { |
| 1335 | | return self.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); |
| 1336 | | } |
| 1337 | | } else { |
| 1338 | | return self.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); |
| 1339 | | } |
| 1340 | | }, |
| 1341 | | .Add => { |
| 1342 | | const lhs = try self.astGenExpr(scope, infix_node.lhs); |
| 1343 | | const rhs = try self.astGenExpr(scope, infix_node.rhs); |
| 1344 | | |
| 1345 | | const tree = scope.tree(); |
| 1346 | | const src = tree.token_locs[infix_node.op_token].start; |
| 1347 | | |
| 1348 | | return self.addZIRInst(scope, src, zir.Inst.Add, .{ .lhs = lhs, .rhs = rhs }, .{}); |
| 1349 | | }, |
| 1350 | | .BangEqual, |
| 1351 | | .EqualEqual, |
| 1352 | | .GreaterThan, |
| 1353 | | .GreaterOrEqual, |
| 1354 | | .LessThan, |
| 1355 | | .LessOrEqual, |
| 1356 | | => { |
| 1357 | | const lhs = try self.astGenExpr(scope, infix_node.lhs); |
| 1358 | | const rhs = try self.astGenExpr(scope, infix_node.rhs); |
| 1359 | | |
| 1360 | | const tree = scope.tree(); |
| 1361 | | const src = tree.token_locs[infix_node.op_token].start; |
| 1362 | | |
| 1363 | | const op: std.math.CompareOperator = switch (infix_node.op) { |
| 1364 | | .BangEqual => .neq, |
| 1365 | | .EqualEqual => .eq, |
| 1366 | | .GreaterThan => .gt, |
| 1367 | | .GreaterOrEqual => .gte, |
| 1368 | | .LessThan => .lt, |
| 1369 | | .LessOrEqual => .lte, |
| 1370 | | else => unreachable, |
| 1371 | | }; |
| 1372 | | |
| 1373 | | return self.addZIRInst(scope, src, zir.Inst.Cmp, .{ |
| 1374 | | .lhs = lhs, |
| 1375 | | .op = op, |
| 1376 | | .rhs = rhs, |
| 1377 | | }, .{}); |
| 1378 | | }, |
| 1379 | | else => |op| { |
| 1380 | | return self.failNode(scope, &infix_node.base, "TODO implement infix operator {}", .{op}); |
| 1381 | | }, |
| 1382 | | } |
| 1383 | | } |
| 1384 | | |
| 1385 | | fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst { |
| 1386 | | if (if_node.payload) |payload| { |
| 1387 | | return self.failNode(scope, payload, "TODO implement astGenIf for optionals", .{}); |
| 1388 | | } |
| 1389 | | if (if_node.@"else") |else_node| { |
| 1390 | | if (else_node.payload) |payload| { |
| 1391 | | return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{}); |
| 1392 | | } |
| 1393 | | } |
| 1394 | | var block_scope: Scope.GenZIR = .{ |
| 1395 | | .decl = scope.decl().?, |
| 1396 | | .arena = scope.arena(), |
| 1397 | | .instructions = .{}, |
| 1398 | | }; |
| 1399 | | defer block_scope.instructions.deinit(self.gpa); |
| 1400 | | |
| 1401 | | const cond = try self.astGenExpr(&block_scope.base, if_node.condition); |
| 1402 | | |
| 1403 | | const tree = scope.tree(); |
| 1404 | | const if_src = tree.token_locs[if_node.if_token].start; |
| 1405 | | const condbr = try self.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{ |
| 1406 | | .condition = cond, |
| 1407 | | .true_body = undefined, // populated below |
| 1408 | | .false_body = undefined, // populated below |
| 1409 | | }, .{}); |
| 1410 | | |
| 1411 | | const block = try self.addZIRInstBlock(scope, if_src, .{ |
| 1412 | | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1413 | | }); |
| 1414 | | var then_scope: Scope.GenZIR = .{ |
| 1415 | | .decl = block_scope.decl, |
| 1416 | | .arena = block_scope.arena, |
| 1417 | | .instructions = .{}, |
| 1418 | | }; |
| 1419 | | defer then_scope.instructions.deinit(self.gpa); |
| 1420 | | |
| 1421 | | const then_result = try self.astGenExpr(&then_scope.base, if_node.body); |
| 1422 | | if (!then_result.tag.isNoReturn()) { |
| 1423 | | const then_src = tree.token_locs[if_node.body.lastToken()].start; |
| 1424 | | _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{ |
| 1425 | | .block = block, |
| 1426 | | .operand = then_result, |
| 1427 | | }, .{}); |
| 1428 | | } |
| 1429 | | condbr.positionals.true_body = .{ |
| 1430 | | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), |
| 1431 | | }; |
| 1432 | | |
| 1433 | | var else_scope: Scope.GenZIR = .{ |
| 1434 | | .decl = block_scope.decl, |
| 1435 | | .arena = block_scope.arena, |
| 1436 | | .instructions = .{}, |
| 1437 | | }; |
| 1438 | | defer else_scope.instructions.deinit(self.gpa); |
| 1439 | | |
| 1440 | | if (if_node.@"else") |else_node| { |
| 1441 | | const else_result = try self.astGenExpr(&else_scope.base, else_node.body); |
| 1442 | | if (!else_result.tag.isNoReturn()) { |
| 1443 | | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| 1444 | | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{ |
| 1445 | | .block = block, |
| 1446 | | .operand = else_result, |
| 1447 | | }, .{}); |
| 1448 | | } |
| 1449 | | } else { |
| 1450 | | // TODO Optimization opportunity: we can avoid an allocation and a memcpy here |
| 1451 | | // by directly allocating the body for this one instruction. |
| 1452 | | const else_src = tree.token_locs[if_node.lastToken()].start; |
| 1453 | | _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.BreakVoid, .{ |
| 1454 | | .block = block, |
| 1455 | | }, .{}); |
| 1456 | | } |
| 1457 | | condbr.positionals.false_body = .{ |
| 1458 | | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), |
| 1459 | | }; |
| 1460 | | |
| 1461 | | return &block.base; |
| 1462 | | } |
| 1463 | | |
| 1464 | | fn astGenControlFlowExpression( |
| 1465 | | self: *Module, |
| 1466 | | scope: *Scope, |
| 1467 | | cfe: *ast.Node.ControlFlowExpression, |
| 1468 | | ) InnerError!*zir.Inst { |
| 1469 | | switch (cfe.kind) { |
| 1470 | | .Break => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Break", .{}), |
| 1471 | | .Continue => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Continue", .{}), |
| 1472 | | .Return => {}, |
| 1473 | | } |
| 1474 | | const tree = scope.tree(); |
| 1475 | | const src = tree.token_locs[cfe.ltoken].start; |
| 1476 | | if (cfe.rhs) |rhs_node| { |
| 1477 | | const operand = try self.astGenExpr(scope, rhs_node); |
| 1478 | | return self.addZIRInst(scope, src, zir.Inst.Return, .{ .operand = operand }, .{}); |
| 1479 | | } else { |
| 1480 | | return self.addZIRInst(scope, src, zir.Inst.ReturnVoid, .{}, .{}); |
| 1481 | | } |
| 1482 | | } |
| 1483 | | |
| 1484 | | fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst { |
| 1485 | | const tree = scope.tree(); |
| 1486 | | const ident_name = tree.tokenSlice(ident.token); |
| 1487 | | const src = tree.token_locs[ident.token].start; |
| 1488 | | if (mem.eql(u8, ident_name, "_")) { |
| 1489 | | return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{}); |
| 1490 | | } |
| 1491 | | |
| 1492 | | if (getSimplePrimitiveValue(ident_name)) |typed_value| { |
| 1493 | | return self.addZIRInstConst(scope, src, typed_value); |
| 1494 | | } |
| 1495 | | |
| 1496 | | if (ident_name.len >= 2) integer: { |
| 1497 | | const first_c = ident_name[0]; |
| 1498 | | if (first_c == 'i' or first_c == 'u') { |
| 1499 | | const is_signed = first_c == 'i'; |
| 1500 | | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { |
| 1501 | | error.Overflow => return self.failNode( |
| 1502 | | scope, |
| 1503 | | &ident.base, |
| 1504 | | "primitive integer type '{}' exceeds maximum bit width of 65535", |
| 1505 | | .{ident_name}, |
| 1506 | | ), |
| 1507 | | error.InvalidCharacter => break :integer, |
| 1508 | | }; |
| 1509 | | const val = switch (bit_count) { |
| 1510 | | 8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type), |
| 1511 | | 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type), |
| 1512 | | 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type), |
| 1513 | | 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type), |
| 1514 | | else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}), |
| 1515 | | }; |
| 1516 | | return self.addZIRInstConst(scope, src, .{ |
| 1517 | | .ty = Type.initTag(.type), |
| 1518 | | .val = val, |
| 1519 | | }); |
| 1520 | | } |
| 1521 | | } |
| 1522 | | |
| 1523 | | if (self.lookupDeclName(scope, ident_name)) |decl| { |
| 1524 | | return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}); |
| 1525 | | } |
| 1526 | | |
| 1527 | | // Function parameter |
| 1528 | | if (scope.decl()) |decl| { |
| 1529 | | if (tree.root_node.decls()[decl.src_index].cast(ast.Node.FnProto)) |fn_proto| { |
| 1530 | | for (fn_proto.params()) |param, i| { |
| 1531 | | const param_name = tree.tokenSlice(param.name_token.?); |
| 1532 | | if (mem.eql(u8, param_name, ident_name)) { |
| 1533 | | return try self.addZIRInst(scope, src, zir.Inst.Arg, .{ .index = i }, .{}); |
| 1534 | | } |
| 1535 | | } |
| 1536 | | } |
| 1537 | | } |
| 1538 | | |
| 1539 | | return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{}); |
| 1540 | | } |
| 1541 | | |
| 1542 | | fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst { |
| 1543 | | const tree = scope.tree(); |
| 1544 | | const unparsed_bytes = tree.tokenSlice(str_lit.token); |
| 1545 | | const arena = scope.arena(); |
| 1546 | | |
| 1547 | | var bad_index: usize = undefined; |
| 1548 | | const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) { |
| 1549 | | error.InvalidCharacter => { |
| 1550 | | const bad_byte = unparsed_bytes[bad_index]; |
| 1551 | | const src = tree.token_locs[str_lit.token].start; |
| 1552 | | return self.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte}); |
| 1553 | | }, |
| 1554 | | else => |e| return e, |
| 1555 | | }; |
| 1556 | | |
| 1557 | | const src = tree.token_locs[str_lit.token].start; |
| 1558 | | return self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{}); |
| 1559 | | } |
| 1560 | | |
| 1561 | | fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst { |
| 1562 | | const arena = scope.arena(); |
| 1563 | | const tree = scope.tree(); |
| 1564 | | const prefixed_bytes = tree.tokenSlice(int_lit.token); |
| 1565 | | const base = if (mem.startsWith(u8, prefixed_bytes, "0x")) |
| 1566 | | 16 |
| 1567 | | else if (mem.startsWith(u8, prefixed_bytes, "0o")) |
| 1568 | | 8 |
| 1569 | | else if (mem.startsWith(u8, prefixed_bytes, "0b")) |
| 1570 | | 2 |
| 1571 | | else |
| 1572 | | @as(u8, 10); |
| 1573 | | |
| 1574 | | const bytes = if (base == 10) |
| 1575 | | prefixed_bytes |
| 1576 | | else |
| 1577 | | prefixed_bytes[2..]; |
| 1578 | | |
| 1579 | | if (std.fmt.parseInt(u64, bytes, base)) |small_int| { |
| 1580 | | const int_payload = try arena.create(Value.Payload.Int_u64); |
| 1581 | | int_payload.* = .{ .int = small_int }; |
| 1582 | | const src = tree.token_locs[int_lit.token].start; |
| 1583 | | return self.addZIRInstConst(scope, src, .{ |
| 1584 | | .ty = Type.initTag(.comptime_int), |
| 1585 | | .val = Value.initPayload(&int_payload.base), |
| 1586 | | }); |
| 1587 | | } else |err| { |
| 1588 | | return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{}); |
| 1589 | | } |
| 1590 | | } |
| 1591 | | |
| 1592 | | fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !void { |
| 1593 | | const tracy = trace(@src()); |
| 1594 | | defer tracy.end(); |
| 1595 | | |
| 1596 | | if (block_node.label) |label| { |
| 1597 | | return self.failTok(scope, label, "TODO implement labeled blocks", .{}); |
| 1598 | | } |
| 1599 | | for (block_node.statements()) |statement| { |
| 1600 | | _ = try self.astGenExpr(scope, statement); |
| 1601 | | } |
| 1602 | | } |
| 1603 | | |
| 1604 | | fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst { |
| 1605 | | if (asm_node.outputs.len != 0) { |
| 1606 | | return self.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{}); |
| 1607 | | } |
| 1608 | | const arena = scope.arena(); |
| 1609 | | const tree = scope.tree(); |
| 1610 | | |
| 1611 | | const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len); |
| 1612 | | const args = try arena.alloc(*zir.Inst, asm_node.inputs.len); |
| 1613 | | |
| 1614 | | for (asm_node.inputs) |input, i| { |
| 1615 | | // TODO semantically analyze constraints |
| 1616 | | inputs[i] = try self.astGenExpr(scope, input.constraint); |
| 1617 | | args[i] = try self.astGenExpr(scope, input.expr); |
| 1618 | | } |
| 1619 | | |
| 1620 | | const src = tree.token_locs[asm_node.asm_token].start; |
| 1621 | | const return_type = try self.addZIRInstConst(scope, src, .{ |
| 1622 | | .ty = Type.initTag(.type), |
| 1623 | | .val = Value.initTag(.void_type), |
| 1624 | | }); |
| 1625 | | const asm_inst = try self.addZIRInst(scope, src, zir.Inst.Asm, .{ |
| 1626 | | .asm_source = try self.astGenExpr(scope, asm_node.template), |
| 1627 | | .return_type = return_type, |
| 1628 | | }, .{ |
| 1629 | | .@"volatile" = asm_node.volatile_token != null, |
| 1630 | | //.clobbers = TODO handle clobbers |
| 1631 | | .inputs = inputs, |
| 1632 | | .args = args, |
| 1633 | | }); |
| 1634 | | return asm_inst; |
| 1635 | | } |
| 1636 | | |
| 1637 | | fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 1638 | | const tree = scope.tree(); |
| 1639 | | const builtin_name = tree.tokenSlice(call.builtin_token); |
| 1640 | | const src = tree.token_locs[call.builtin_token].start; |
| 1641 | | |
| 1642 | | inline for (std.meta.declarations(zir.Inst)) |inst| { |
| 1643 | | if (inst.data != .Type) continue; |
| 1644 | | const T = inst.data.Type; |
| 1645 | | if (!@hasDecl(T, "builtin_name")) continue; |
| 1646 | | if (std.mem.eql(u8, builtin_name, T.builtin_name)) { |
| 1647 | | var value: T = undefined; |
| 1648 | | const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct; |
| 1649 | | if (positionals.fields.len == 0) { |
| 1650 | | return self.addZIRInst(scope, src, T, value.positionals, value.kw_args); |
| 1651 | | } |
| 1652 | | const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len; |
| 1653 | | if (arg_count) |some| { |
| 1654 | | if (call.params_len != some) { |
| 1655 | | return self.failTok( |
| 1656 | | scope, |
| 1657 | | call.builtin_token, |
| 1658 | | "expected {} parameter{}, found {}", |
| 1659 | | .{ some, if (some == 1) "" else "s", call.params_len }, |
| 1660 | | ); |
| 1661 | | } |
| 1662 | | const params = call.params(); |
| 1663 | | inline for (positionals.fields) |p, i| { |
| 1664 | | @field(value.positionals, p.name) = try self.astGenExpr(scope, params[i]); |
| 1665 | | } |
| 1666 | | } else { |
| 1667 | | return self.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name}); |
| 1668 | | } |
| 1669 | | |
| 1670 | | return self.addZIRInst(scope, src, T, value.positionals, .{}); |
| 1671 | | } |
| 1672 | | } |
| 1673 | | return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name}); |
| 1674 | | } |
| 1675 | | |
| 1676 | | fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst { |
| 1677 | | const tree = scope.tree(); |
| 1678 | | const lhs = try self.astGenExpr(scope, call.lhs); |
| 1679 | | |
| 1680 | | const param_nodes = call.params(); |
| 1681 | | const args = try scope.cast(Scope.GenZIR).?.arena.alloc(*zir.Inst, param_nodes.len); |
| 1682 | | for (param_nodes) |param_node, i| { |
| 1683 | | args[i] = try self.astGenExpr(scope, param_node); |
| 1684 | | } |
| 1685 | | |
| 1686 | | const src = tree.token_locs[call.lhs.firstToken()].start; |
| 1687 | | return self.addZIRInst(scope, src, zir.Inst.Call, .{ |
| 1688 | | .func = lhs, |
| 1689 | | .args = args, |
| 1690 | | }, .{}); |
| 1691 | | } |
| 1692 | | |
| 1693 | | fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst { |
| 1694 | | const tree = scope.tree(); |
| 1695 | | const src = tree.token_locs[unreach_node.token].start; |
| 1696 | | return self.addZIRInst(scope, src, zir.Inst.Unreachable, .{}, .{}); |
| 1697 | | } |
| 1698 | | |
| 1699 | | fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { |
| 1700 | | const simple_types = std.ComptimeStringMap(Value.Tag, .{ |
| 1701 | | .{ "u8", .u8_type }, |
| 1702 | | .{ "i8", .i8_type }, |
| 1703 | | .{ "isize", .isize_type }, |
| 1704 | | .{ "usize", .usize_type }, |
| 1705 | | .{ "c_short", .c_short_type }, |
| 1706 | | .{ "c_ushort", .c_ushort_type }, |
| 1707 | | .{ "c_int", .c_int_type }, |
| 1708 | | .{ "c_uint", .c_uint_type }, |
| 1709 | | .{ "c_long", .c_long_type }, |
| 1710 | | .{ "c_ulong", .c_ulong_type }, |
| 1711 | | .{ "c_longlong", .c_longlong_type }, |
| 1712 | | .{ "c_ulonglong", .c_ulonglong_type }, |
| 1713 | | .{ "c_longdouble", .c_longdouble_type }, |
| 1714 | | .{ "f16", .f16_type }, |
| 1715 | | .{ "f32", .f32_type }, |
| 1716 | | .{ "f64", .f64_type }, |
| 1717 | | .{ "f128", .f128_type }, |
| 1718 | | .{ "c_void", .c_void_type }, |
| 1719 | | .{ "bool", .bool_type }, |
| 1720 | | .{ "void", .void_type }, |
| 1721 | | .{ "type", .type_type }, |
| 1722 | | .{ "anyerror", .anyerror_type }, |
| 1723 | | .{ "comptime_int", .comptime_int_type }, |
| 1724 | | .{ "comptime_float", .comptime_float_type }, |
| 1725 | | .{ "noreturn", .noreturn_type }, |
| 1726 | | }); |
| 1727 | | if (simple_types.get(name)) |tag| { |
| 1728 | | return TypedValue{ |
| 1729 | | .ty = Type.initTag(.type), |
| 1730 | | .val = Value.initTag(tag), |
| 1731 | | }; |
| 1732 | | } |
| 1733 | | if (mem.eql(u8, name, "null")) { |
| 1734 | | return TypedValue{ |
| 1735 | | .ty = Type.initTag(.@"null"), |
| 1736 | | .val = Value.initTag(.null_value), |
| 1737 | | }; |
| 1738 | | } |
| 1739 | | if (mem.eql(u8, name, "undefined")) { |
| 1740 | | return TypedValue{ |
| 1741 | | .ty = Type.initTag(.@"undefined"), |
| 1742 | | .val = Value.initTag(.undef), |
| 1743 | | }; |
| 1744 | | } |
| 1745 | | if (mem.eql(u8, name, "true")) { |
| 1746 | | return TypedValue{ |
| 1747 | | .ty = Type.initTag(.bool), |
| 1748 | | .val = Value.initTag(.bool_true), |
| 1749 | | }; |
| 1750 | | } |
| 1751 | | if (mem.eql(u8, name, "false")) { |
| 1752 | | return TypedValue{ |
| 1753 | | .ty = Type.initTag(.bool), |
| 1754 | | .val = Value.initTag(.bool_false), |
| 1755 | | }; |
| 1756 | | } |
| 1757 | | return null; |
| 1758 | | } |
| 1759 | | |
| 1760 | 1302 | fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void { |
| 1761 | 1303 | try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1); |
| 1762 | 1304 | try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1); |
| ... | ... | @@ -2368,7 +1910,7 @@ fn newZIRInst( |
| 2368 | 1910 | return inst; |
| 2369 | 1911 | } |
| 2370 | 1912 | |
| 2371 | | fn addZIRInstSpecial( |
| 1913 | pub fn addZIRInstSpecial( |
| 2372 | 1914 | self: *Module, |
| 2373 | 1915 | scope: *Scope, |
| 2374 | 1916 | src: usize, |
| ... | ... | @@ -2383,7 +1925,7 @@ fn addZIRInstSpecial( |
| 2383 | 1925 | return inst; |
| 2384 | 1926 | } |
| 2385 | 1927 | |
| 2386 | | fn addZIRInst( |
| 1928 | pub fn addZIRInst( |
| 2387 | 1929 | self: *Module, |
| 2388 | 1930 | scope: *Scope, |
| 2389 | 1931 | src: usize, |
| ... | ... | @@ -2396,13 +1938,13 @@ fn addZIRInst( |
| 2396 | 1938 | } |
| 2397 | 1939 | |
| 2398 | 1940 | /// TODO The existence of this function is a workaround for a bug in stage1. |
| 2399 | | fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst { |
| 1941 | pub fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst { |
| 2400 | 1942 | const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type; |
| 2401 | 1943 | return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); |
| 2402 | 1944 | } |
| 2403 | 1945 | |
| 2404 | 1946 | /// TODO The existence of this function is a workaround for a bug in stage1. |
| 2405 | | fn addZIRInstBlock(self: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { |
| 1947 | pub fn addZIRInstBlock(self: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { |
| 2406 | 1948 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; |
| 2407 | 1949 | return self.addZIRInstSpecial(scope, src, zir.Inst.Block, P{ .body = body }, .{}); |
| 2408 | 1950 | } |
| ... | ... | @@ -2637,7 +2179,7 @@ fn getNextAnonNameIndex(self: *Module) usize { |
| 2637 | 2179 | return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic); |
| 2638 | 2180 | } |
| 2639 | 2181 | |
| 2640 | | fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl { |
| 2182 | pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl { |
| 2641 | 2183 | const namespace = scope.namespace(); |
| 2642 | 2184 | const name_hash = namespace.fullyQualifiedNameHash(ident_name); |
| 2643 | 2185 | return self.decl_table.get(name_hash); |
| ... | ... | @@ -3646,13 +3188,13 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I |
| 3646 | 3188 | return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{}); |
| 3647 | 3189 | } |
| 3648 | 3190 | |
| 3649 | | fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError { |
| 3191 | pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError { |
| 3650 | 3192 | @setCold(true); |
| 3651 | 3193 | const err_msg = try ErrorMsg.create(self.gpa, src, format, args); |
| 3652 | 3194 | return self.failWithOwnedErrorMsg(scope, src, err_msg); |
| 3653 | 3195 | } |
| 3654 | 3196 | |
| 3655 | | fn failTok( |
| 3197 | pub fn failTok( |
| 3656 | 3198 | self: *Module, |
| 3657 | 3199 | scope: *Scope, |
| 3658 | 3200 | token_index: ast.TokenIndex, |
| ... | ... | @@ -3664,7 +3206,7 @@ fn failTok( |
| 3664 | 3206 | return self.fail(scope, src, format, args); |
| 3665 | 3207 | } |
| 3666 | 3208 | |
| 3667 | | fn failNode( |
| 3209 | pub fn failNode( |
| 3668 | 3210 | self: *Module, |
| 3669 | 3211 | scope: *Scope, |
| 3670 | 3212 | ast_node: *ast.Node, |