| ... | ... | @@ -327,6 +327,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 327 | 327 | .while_cont => return whileExpr(mod, scope, tree.whileCont(node)), |
| 328 | 328 | .@"while" => return whileExpr(mod, scope, rl, tree.whileFull(node)), |
| 329 | 329 | |
| 330 | .for_simple => return forExpr(mod, scope, rl, tree.forSimple(node)), |
| 331 | .@"for" => return forExpr(mod, scope, rl, tree.forFull(node)), |
| 332 | |
| 333 | // TODO handling these separately would actually be simpler & have fewer branches |
| 334 | // once we have a ZIR instruction for each of these 3 cases. |
| 335 | .slice_open => return sliceExpr(mod, scope, rl, tree.sliceOpen(node)), |
| 336 | .slice => return sliceExpr(mod, scope, rl, tree.slice(node)), |
| 337 | .slice_sentinel => return sliceExpr(mod, scope, rl, tree.sliceSentinel(node)), |
| 338 | |
| 330 | 339 | .deref => { |
| 331 | 340 | const lhs = try expr(mod, scope, .none, node_datas[node].lhs); |
| 332 | 341 | const src = token_starts[main_tokens[node]]; |
| ... | ... | @@ -402,51 +411,122 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 402 | 411 | const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; |
| 403 | 412 | return blockExpr(mod, scope, rl, node, statements); |
| 404 | 413 | }, |
| 405 | | |
| 406 | | .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)), |
| 407 | | .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)), |
| 408 | | .grouped_expression => return expr(mod, scope, rl, node.expr), |
| 409 | | .array_type => return rvalue(mod, scope, rl, try arrayType(mod, scope, node)), |
| 410 | | .array_type_sentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node)), |
| 411 | | .enum_literal => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node)), |
| 412 | | .char_literal => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node)), |
| 413 | | .slice_type => return rvalue(mod, scope, rl, try sliceType(mod, scope, node)), |
| 414 | | .error_union => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .error_union_type)), |
| 415 | | .merge_error_sets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .merge_error_sets)), |
| 416 | | .anyframe_type => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node)), |
| 417 | | .error_set_decl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node)), |
| 418 | | .error_type => return rvalue(mod, scope, rl, try errorType(mod, scope, node)), |
| 419 | | .@"for" => return forExpr(mod, scope, rl, node), |
| 414 | .enum_literal => { |
| 415 | const ident_token = main_tokens[node]; |
| 416 | const name = try mod.identifierTokenString(scope, ident_token); |
| 417 | const src = token_starts[ident_token]; |
| 418 | const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{}); |
| 419 | return rvalue(mod, scope, rl, result); |
| 420 | }, |
| 421 | .error_union => { |
| 422 | const error_set = try typeExpr(mod, scope, node_datas[node].lhs); |
| 423 | const payload = try typeExpr(mod, scope, node_datas[node].rhs); |
| 424 | const src = token_starts[main_tokens[node]]; |
| 425 | const result = try addZIRBinOp(mod, scope, src, .error_union_type, error_set, payload); |
| 426 | return rvalue(mod, scope, rl, result); |
| 427 | }, |
| 428 | .merge_error_sets => { |
| 429 | const lhs = try typeExpr(mod, scope, node_datas[node].lhs); |
| 430 | const rhs = try typeExpr(mod, scope, node_datas[node].rhs); |
| 431 | const src = token_starts[main_tokens[node]]; |
| 432 | const result = try addZIRBinOp(mod, scope, src, .merge_error_sets, lhs, rhs); |
| 433 | return rvalue(mod, scope, rl, result); |
| 434 | }, |
| 435 | .anyframe_literal => { |
| 436 | const main_token = main_tokens[node]; |
| 437 | const src = token_starts[main_token]; |
| 438 | const result = try addZIRInstConst(mod, scope, src, .{ |
| 439 | .ty = Type.initTag(.type), |
| 440 | .val = Value.initTag(.anyframe_type), |
| 441 | }); |
| 442 | return rvalue(mod, scope, rl, result); |
| 443 | }, |
| 444 | .anyframe_type => { |
| 445 | const src = token_starts[node_datas[node].lhs]; |
| 446 | const return_type = try typeExpr(mod, scope, node_datas[node].rhs); |
| 447 | const result = try addZIRUnOp(mod, scope, src, .anyframe_type, return_type); |
| 448 | return rvalue(mod, scope, rl, result); |
| 449 | }, |
| 450 | .@"catch" => { |
| 451 | const catch_token = main_tokens[node]; |
| 452 | const payload_token: ?TokenIndex = if (token_tags[catch_token + 1] == .pipe) |
| 453 | catch_token + 2 |
| 454 | else |
| 455 | null; |
| 456 | switch (rl) { |
| 457 | .ref => return orelseCatchExpr( |
| 458 | mod, |
| 459 | scope, |
| 460 | rl, |
| 461 | node_datas[node].lhs, |
| 462 | main_tokens[node], |
| 463 | .is_err_ptr, |
| 464 | .err_union_payload_unsafe_ptr, |
| 465 | .err_union_code_ptr, |
| 466 | node_datas[node].rhs, |
| 467 | payload_token, |
| 468 | ), |
| 469 | else => return orelseCatchExpr( |
| 470 | mod, |
| 471 | scope, |
| 472 | rl, |
| 473 | node_datas[node].lhs, |
| 474 | main_tokens[node], |
| 475 | .is_err, |
| 476 | .err_union_payload_unsafe, |
| 477 | .err_union_code, |
| 478 | node_datas[node].rhs, |
| 479 | payload_token, |
| 480 | ), |
| 481 | } |
| 482 | }, |
| 483 | .@"orelse" => switch (rl) { |
| 484 | .ref => return orelseCatchExpr( |
| 485 | mod, |
| 486 | scope, |
| 487 | rl, |
| 488 | node_datas[node].lhs, |
| 489 | main_tokens[node], |
| 490 | .is_null_ptr, |
| 491 | .optional_payload_unsafe_ptr, |
| 492 | undefined, |
| 493 | node_datas[node].rhs, |
| 494 | null, |
| 495 | ), |
| 496 | else => return orelseCatchExpr( |
| 497 | mod, |
| 498 | scope, |
| 499 | rl, |
| 500 | node_datas[node].lhs, |
| 501 | main_tokens[node], |
| 502 | .is_null, |
| 503 | .optional_payload_unsafe, |
| 504 | undefined, |
| 505 | node_datas[node].rhs, |
| 506 | null, |
| 507 | ), |
| 508 | }, |
| 509 | .@"break" => return breakExpr(mod, scope, rl, node), |
| 510 | .@"continue" => return continueExpr(mod, scope, rl, node), |
| 511 | .grouped_expression => return expr(mod, scope, rl, node_datas[node].lhs), |
| 512 | .array_type => return arrayType(mod, scope, rl, node), |
| 513 | .array_type_sentinel => return arrayTypeSentinel(mod, scope, rl, node), |
| 514 | .char_literal => return charLiteral(mod, scope, rl, node), |
| 515 | .error_set_decl => return errorSetDecl(mod, scope, rl, node), |
| 420 | 516 | .array_access => return arrayAccess(mod, scope, rl, node), |
| 421 | | .slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node)), |
| 422 | | .@"catch" => return catchExpr(mod, scope, rl, node), |
| 423 | | .@"comptime" => return comptimeKeyword(mod, scope, rl, node), |
| 424 | | .@"orelse" => return orelseExpr(mod, scope, rl, node), |
| 425 | | .@"switch" => return switchExpr(mod, scope, rl, node), |
| 426 | | .ContainerDecl => return containerDecl(mod, scope, rl, node), |
| 517 | .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs), |
| 518 | .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node), |
| 427 | 519 | |
| 428 | 520 | .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}), |
| 429 | 521 | .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}), |
| 430 | 522 | .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}), |
| 431 | 523 | .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| 432 | | .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), |
| 433 | | .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), |
| 434 | | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), |
| 435 | | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), |
| 436 | 524 | .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}), |
| 437 | 525 | .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}), |
| 438 | | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 439 | 526 | .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}), |
| 440 | 527 | } |
| 441 | 528 | } |
| 442 | 529 | |
| 443 | | fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"comptime") InnerError!*zir.Inst { |
| 444 | | const tracy = trace(@src()); |
| 445 | | defer tracy.end(); |
| 446 | | |
| 447 | | return comptimeExpr(mod, scope, rl, node.expr); |
| 448 | | } |
| 449 | | |
| 450 | 530 | pub fn comptimeExpr( |
| 451 | 531 | mod: *Module, |
| 452 | 532 | parent_scope: *Scope, |
| ... | ... | @@ -493,7 +573,12 @@ pub fn comptimeExpr( |
| 493 | 573 | return &block.base; |
| 494 | 574 | } |
| 495 | 575 | |
| 496 | | fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { |
| 576 | fn breakExpr( |
| 577 | mod: *Module, |
| 578 | parent_scope: *Scope, |
| 579 | rl: ResultLoc, |
| 580 | node: ast.Node.Index, |
| 581 | ) InnerError!*zir.Inst { |
| 497 | 582 | const tree = parent_scope.tree(); |
| 498 | 583 | const node_datas = tree.nodes.items(.data); |
| 499 | 584 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -524,9 +609,10 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro |
| 524 | 609 | }; |
| 525 | 610 | |
| 526 | 611 | if (rhs == 0) { |
| 527 | | return addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 612 | const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 528 | 613 | .block = block_inst, |
| 529 | 614 | }); |
| 615 | return rvalue(mod, parent_scope, rl, result); |
| 530 | 616 | } |
| 531 | 617 | gen_zir.break_count += 1; |
| 532 | 618 | const prev_rvalue_rl_count = gen_zir.rvalue_rl_count; |
| ... | ... | @@ -547,7 +633,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro |
| 547 | 633 | try gen_zir.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst); |
| 548 | 634 | } |
| 549 | 635 | } |
| 550 | | return br; |
| 636 | return rvalue(mod, parent_scope, rl, br); |
| 551 | 637 | }, |
| 552 | 638 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 553 | 639 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| ... | ... | @@ -561,7 +647,12 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerErro |
| 561 | 647 | } |
| 562 | 648 | } |
| 563 | 649 | |
| 564 | | fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { |
| 650 | fn continueExpr( |
| 651 | mod: *Module, |
| 652 | parent_scope: *Scope, |
| 653 | rl: ResultLoc, |
| 654 | node: ast.Node.Index, |
| 655 | ) InnerError!*zir.Inst { |
| 565 | 656 | const tree = parent_scope.tree(); |
| 566 | 657 | const node_datas = tree.nodes.items(.data); |
| 567 | 658 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -590,9 +681,10 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: ast.Node.Index) InnerE |
| 590 | 681 | continue; |
| 591 | 682 | } |
| 592 | 683 | |
| 593 | | return addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 684 | const result = try addZirInstTag(mod, parent_scope, src, .break_void, .{ |
| 594 | 685 | .block = continue_block, |
| 595 | 686 | }); |
| 687 | return rvalue(mod, parent_scope, rl, result); |
| 596 | 688 | }, |
| 597 | 689 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 598 | 690 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| ... | ... | @@ -1083,12 +1175,6 @@ fn negation( |
| 1083 | 1175 | return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); |
| 1084 | 1176 | } |
| 1085 | 1177 | |
| 1086 | | fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.slice_type) InnerError!*zir.Inst { |
| 1087 | | const tree = scope.tree(); |
| 1088 | | const src = token_starts[node.op_token]; |
| 1089 | | return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); |
| 1090 | | } |
| 1091 | | |
| 1092 | 1178 | fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { |
| 1093 | 1179 | const tree = scope.tree(); |
| 1094 | 1180 | const src = token_starts[node.op_token]; |
| ... | ... | @@ -1146,70 +1232,54 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 1146 | 1232 | return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); |
| 1147 | 1233 | } |
| 1148 | 1234 | |
| 1149 | | fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.array_type) !*zir.Inst { |
| 1235 | fn arrayType(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 1150 | 1236 | const tree = scope.tree(); |
| 1151 | | const src = token_starts[node.op_token]; |
| 1237 | const main_tokens = tree.nodes.items(.main_token); |
| 1238 | const node_datas = tree.nodes.items(.data); |
| 1239 | const src = token_starts[main_tokens[node]]; |
| 1152 | 1240 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1153 | 1241 | .ty = Type.initTag(.type), |
| 1154 | 1242 | .val = Value.initTag(.usize_type), |
| 1155 | 1243 | }); |
| 1244 | const len_node = node_datas[node].lhs; |
| 1245 | const elem_node = node_datas[node].rhs; |
| 1246 | if (len_node == 0) { |
| 1247 | const elem_type = try typeExpr(mod, scope, elem_node); |
| 1248 | const result = try addZIRUnOp(mod, scope, src, .mut_slice_type, elem_type); |
| 1249 | return rvalue(mod, scope, rl, result); |
| 1250 | } else { |
| 1251 | // TODO check for [_]T |
| 1252 | const len = try expr(mod, scope, .{ .ty = usize_type }, len_node); |
| 1253 | const elem_type = try typeExpr(mod, scope, elem_node); |
| 1156 | 1254 | |
| 1157 | | // TODO check for [_]T |
| 1158 | | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); |
| 1159 | | const elem_type = try typeExpr(mod, scope, node.rhs); |
| 1160 | | |
| 1161 | | return addZIRBinOp(mod, scope, src, .array_type, len, elem_type); |
| 1255 | const result = try addZIRBinOp(mod, scope, src, .array_type, len, elem_type); |
| 1256 | return rvalue(mod, scope, rl, result); |
| 1257 | } |
| 1162 | 1258 | } |
| 1163 | 1259 | |
| 1164 | | fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.array_type_sentinel) !*zir.Inst { |
| 1260 | fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 1165 | 1261 | const tree = scope.tree(); |
| 1166 | | const src = token_starts[node.op_token]; |
| 1262 | const main_tokens = tree.nodes.items(.main_token); |
| 1263 | const len_node = node_datas[node].lhs; |
| 1264 | const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); |
| 1265 | const src = token_starts[main_tokens[node]]; |
| 1167 | 1266 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1168 | 1267 | .ty = Type.initTag(.type), |
| 1169 | 1268 | .val = Value.initTag(.usize_type), |
| 1170 | 1269 | }); |
| 1171 | 1270 | |
| 1172 | 1271 | // TODO check for [_]T |
| 1173 | | const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr); |
| 1174 | | const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel); |
| 1175 | | const elem_type = try typeExpr(mod, scope, node.rhs); |
| 1272 | const len = try expr(mod, scope, .{ .ty = usize_type }, len_node); |
| 1273 | const sentinel_uncasted = try expr(mod, scope, .none, extra.sentinel); |
| 1274 | const elem_type = try typeExpr(mod, scope, extra.elem_type); |
| 1176 | 1275 | const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted); |
| 1177 | 1276 | |
| 1178 | | return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ |
| 1277 | const result = try addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{ |
| 1179 | 1278 | .len = len, |
| 1180 | 1279 | .sentinel = sentinel, |
| 1181 | 1280 | .elem_type = elem_type, |
| 1182 | 1281 | }, .{}); |
| 1183 | | } |
| 1184 | | |
| 1185 | | fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.anyframe_type) InnerError!*zir.Inst { |
| 1186 | | const tree = scope.tree(); |
| 1187 | | const src = token_starts[node.anyframe_token]; |
| 1188 | | if (node.result) |some| { |
| 1189 | | const return_type = try typeExpr(mod, scope, some.return_type); |
| 1190 | | return addZIRUnOp(mod, scope, src, .anyframe_type, return_type); |
| 1191 | | } else { |
| 1192 | | return addZIRInstConst(mod, scope, src, .{ |
| 1193 | | .ty = Type.initTag(.type), |
| 1194 | | .val = Value.initTag(.anyframe_type), |
| 1195 | | }); |
| 1196 | | } |
| 1197 | | } |
| 1198 | | |
| 1199 | | fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst { |
| 1200 | | const tree = scope.tree(); |
| 1201 | | const src = token_starts[node.op_token]; |
| 1202 | | const error_set = try typeExpr(mod, scope, node.lhs); |
| 1203 | | const payload = try typeExpr(mod, scope, node.rhs); |
| 1204 | | return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload); |
| 1205 | | } |
| 1206 | | |
| 1207 | | fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.enum_literal) !*zir.Inst { |
| 1208 | | const tree = scope.tree(); |
| 1209 | | const src = token_starts[node.name]; |
| 1210 | | const name = try mod.identifierTokenString(scope, node.name); |
| 1211 | | |
| 1212 | | return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{}); |
| 1282 | return rvalue(mod, scope, rl, result); |
| 1213 | 1283 | } |
| 1214 | 1284 | |
| 1215 | 1285 | fn containerField( |
| ... | ... | @@ -1394,85 +1464,50 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con |
| 1394 | 1464 | } |
| 1395 | 1465 | } |
| 1396 | 1466 | |
| 1397 | | fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.error_set_decl) InnerError!*zir.Inst { |
| 1467 | fn errorSetDecl( |
| 1468 | mod: *Module, |
| 1469 | scope: *Scope, |
| 1470 | rl: ResultLoc, |
| 1471 | node: ast.Node.Index, |
| 1472 | ) InnerError!*zir.Inst { |
| 1398 | 1473 | const tree = scope.tree(); |
| 1399 | | const src = token_starts[node.error_token]; |
| 1400 | | const decls = node.decls(); |
| 1401 | | const fields = try scope.arena().alloc([]const u8, decls.len); |
| 1402 | | |
| 1403 | | for (decls) |decl, i| { |
| 1404 | | const tag = decl.castTag(.ErrorTag).?; |
| 1405 | | fields[i] = try mod.identifierTokenString(scope, tag.name_token); |
| 1406 | | } |
| 1407 | | |
| 1408 | | return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); |
| 1409 | | } |
| 1474 | const main_tokens = tree.nodes.items(.main_token); |
| 1475 | const token_tags = tree.tokens.items(.tag); |
| 1410 | 1476 | |
| 1411 | | fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { |
| 1412 | | const tree = scope.tree(); |
| 1413 | | const src = token_starts[node.token]; |
| 1414 | | return addZIRInstConst(mod, scope, src, .{ |
| 1415 | | .ty = Type.initTag(.type), |
| 1416 | | .val = Value.initTag(.anyerror_type), |
| 1417 | | }); |
| 1418 | | } |
| 1477 | // Count how many fields there are. |
| 1478 | const error_token = main_tokens[node]; |
| 1479 | const count: usize = count: { |
| 1480 | var tok_i = error_token + 2; |
| 1481 | var count: usize = 0; |
| 1482 | while (true) : (tok_i += 1) { |
| 1483 | switch (token_tags[tok_i]) { |
| 1484 | .doc_comment, .comma => {}, |
| 1485 | .identifier => count += 1, |
| 1486 | .r_paren => break :count count, |
| 1487 | else => unreachable, |
| 1488 | } |
| 1489 | } else unreachable; // TODO should not need else unreachable here |
| 1490 | }; |
| 1419 | 1491 | |
| 1420 | | fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"catch") InnerError!*zir.Inst { |
| 1421 | | switch (rl) { |
| 1422 | | .ref => return orelseCatchExpr( |
| 1423 | | mod, |
| 1424 | | scope, |
| 1425 | | rl, |
| 1426 | | node.lhs, |
| 1427 | | node.op_token, |
| 1428 | | .is_err_ptr, |
| 1429 | | .err_union_payload_unsafe_ptr, |
| 1430 | | .err_union_code_ptr, |
| 1431 | | node.rhs, |
| 1432 | | node.payload, |
| 1433 | | ), |
| 1434 | | else => return orelseCatchExpr( |
| 1435 | | mod, |
| 1436 | | scope, |
| 1437 | | rl, |
| 1438 | | node.lhs, |
| 1439 | | node.op_token, |
| 1440 | | .is_err, |
| 1441 | | .err_union_payload_unsafe, |
| 1442 | | .err_union_code, |
| 1443 | | node.rhs, |
| 1444 | | node.payload, |
| 1445 | | ), |
| 1446 | | } |
| 1447 | | } |
| 1448 | | |
| 1449 | | fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { |
| 1450 | | switch (rl) { |
| 1451 | | .ref => return orelseCatchExpr( |
| 1452 | | mod, |
| 1453 | | scope, |
| 1454 | | rl, |
| 1455 | | node.lhs, |
| 1456 | | node.op_token, |
| 1457 | | .is_null_ptr, |
| 1458 | | .optional_payload_unsafe_ptr, |
| 1459 | | undefined, |
| 1460 | | node.rhs, |
| 1461 | | null, |
| 1462 | | ), |
| 1463 | | else => return orelseCatchExpr( |
| 1464 | | mod, |
| 1465 | | scope, |
| 1466 | | rl, |
| 1467 | | node.lhs, |
| 1468 | | node.op_token, |
| 1469 | | .is_null, |
| 1470 | | .optional_payload_unsafe, |
| 1471 | | undefined, |
| 1472 | | node.rhs, |
| 1473 | | null, |
| 1474 | | ), |
| 1492 | const fields = try scope.arena().alloc([]const u8, count); |
| 1493 | { |
| 1494 | var tok_i = error_token + 2; |
| 1495 | var field_i: usize = 0; |
| 1496 | while (true) : (tok_i += 1) { |
| 1497 | switch (token_tags[tok_i]) { |
| 1498 | .doc_comment, .comma => {}, |
| 1499 | .identifier => { |
| 1500 | fields[field_i] = try mod.identifierTokenString(scope, tok_i); |
| 1501 | field_i += 1; |
| 1502 | }, |
| 1503 | .r_paren => break, |
| 1504 | else => unreachable, |
| 1505 | } |
| 1506 | } |
| 1475 | 1507 | } |
| 1508 | const src = token_starts[error_token]; |
| 1509 | const result = try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}); |
| 1510 | return rvalue(mod, scope, rl, result); |
| 1476 | 1511 | } |
| 1477 | 1512 | |
| 1478 | 1513 | fn orelseCatchExpr( |
| ... | ... | @@ -1681,55 +1716,78 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) I |
| 1681 | 1716 | } |
| 1682 | 1717 | } |
| 1683 | 1718 | |
| 1684 | | fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.array_access) InnerError!*zir.Inst { |
| 1719 | fn arrayAccess( |
| 1720 | mod: *Module, |
| 1721 | scope: *Scope, |
| 1722 | rl: ResultLoc, |
| 1723 | node: ast.Node.Index, |
| 1724 | ) InnerError!*zir.Inst { |
| 1685 | 1725 | const tree = scope.tree(); |
| 1686 | | const src = token_starts[node.rtoken]; |
| 1726 | const main_tokens = tree.nodes.items(.main_token); |
| 1727 | const token_starts = tree.tokens.items(.start); |
| 1728 | const src = token_starts[main_tokens[node]]; |
| 1687 | 1729 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1688 | 1730 | .ty = Type.initTag(.type), |
| 1689 | 1731 | .val = Value.initTag(.usize_type), |
| 1690 | 1732 | }); |
| 1691 | 1733 | const index_rl: ResultLoc = .{ .ty = usize_type }; |
| 1692 | | |
| 1693 | | if (rl == .ref) { |
| 1694 | | return addZirInstTag(mod, scope, src, .elem_ptr, .{ |
| 1695 | | .array = try expr(mod, scope, .ref, node.lhs), |
| 1696 | | .index = try expr(mod, scope, index_rl, node.index_expr), |
| 1697 | | }); |
| 1734 | switch (rl) { |
| 1735 | .ref => return addZirInstTag(mod, scope, src, .elem_ptr, .{ |
| 1736 | .array = try expr(mod, scope, .ref, node_datas[node].lhs), |
| 1737 | .index = try expr(mod, scope, index_rl, node_datas[node].rhs), |
| 1738 | }), |
| 1739 | else => return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ |
| 1740 | .array = try expr(mod, scope, .none, node_datas[node].lhs), |
| 1741 | .index = try expr(mod, scope, index_rl, node_datas[node].rhs), |
| 1742 | })), |
| 1698 | 1743 | } |
| 1699 | | return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{ |
| 1700 | | .array = try expr(mod, scope, .none, node.lhs), |
| 1701 | | .index = try expr(mod, scope, index_rl, node.index_expr), |
| 1702 | | })); |
| 1703 | 1744 | } |
| 1704 | 1745 | |
| 1705 | | fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.slice) InnerError!*zir.Inst { |
| 1746 | fn sliceExpr( |
| 1747 | mod: *Module, |
| 1748 | scope: *Scope, |
| 1749 | rl: ResultLoc, |
| 1750 | slice: ast.full.Slice, |
| 1751 | ) InnerError!*zir.Inst { |
| 1706 | 1752 | const tree = scope.tree(); |
| 1707 | | const src = token_starts[node.rtoken]; |
| 1753 | const token_starts = tree.tokens.items(.start); |
| 1754 | const src = token_starts[slice.ast.lbracket]; |
| 1708 | 1755 | |
| 1709 | 1756 | const usize_type = try addZIRInstConst(mod, scope, src, .{ |
| 1710 | 1757 | .ty = Type.initTag(.type), |
| 1711 | 1758 | .val = Value.initTag(.usize_type), |
| 1712 | 1759 | }); |
| 1713 | 1760 | |
| 1714 | | const array_ptr = try expr(mod, scope, .ref, node.lhs); |
| 1715 | | const start = try expr(mod, scope, .{ .ty = usize_type }, node.start); |
| 1761 | const array_ptr = try expr(mod, scope, .ref, slice.ast.sliced); |
| 1762 | const start = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.start); |
| 1716 | 1763 | |
| 1717 | | if (node.end == null and node.sentinel == null) { |
| 1718 | | return try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start); |
| 1764 | if (slice.ast.sentinel == 0) { |
| 1765 | if (slice.ast.end == 0) { |
| 1766 | const result = try addZIRBinOp(mod, scope, src, .slice_start, array_ptr, start); |
| 1767 | return rvalue(mod, scope, rl, result); |
| 1768 | } else { |
| 1769 | const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end); |
| 1770 | // TODO a ZIR slice_open instruction |
| 1771 | const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{ |
| 1772 | .array_ptr = array_ptr, |
| 1773 | .start = start, |
| 1774 | }, .{ .end = end }); |
| 1775 | return rvalue(mod, scope, rl, result); |
| 1776 | } |
| 1719 | 1777 | } |
| 1720 | 1778 | |
| 1721 | | const end = if (node.end) |end| try expr(mod, scope, .{ .ty = usize_type }, end) else null; |
| 1722 | | // we could get the child type here, but it is easier to just do it in semantic analysis. |
| 1723 | | const sentinel = if (node.sentinel) |sentinel| try expr(mod, scope, .none, sentinel) else null; |
| 1724 | | |
| 1725 | | return try addZIRInst( |
| 1726 | | mod, |
| 1727 | | scope, |
| 1728 | | src, |
| 1729 | | zir.Inst.Slice, |
| 1730 | | .{ .array_ptr = array_ptr, .start = start }, |
| 1731 | | .{ .end = end, .sentinel = sentinel }, |
| 1732 | | ); |
| 1779 | const end = try expr(mod, scope, .{ .ty = usize_type }, slice.ast.end); |
| 1780 | // TODO pass the proper result loc to this expression using a ZIR instruction |
| 1781 | // "get the child element type for a slice target". |
| 1782 | const sentinel = try expr(mod, scope, .none, slice.ast.sentinel); |
| 1783 | const result = try addZIRInst(mod, scope, src, zir.Inst.Slice, .{ |
| 1784 | .array_ptr = array_ptr, |
| 1785 | .start = start, |
| 1786 | }, .{ |
| 1787 | .end = end, |
| 1788 | .sentinel = sentinel, |
| 1789 | }); |
| 1790 | return rvalue(mod, scope, rl, result); |
| 1733 | 1791 | } |
| 1734 | 1792 | |
| 1735 | 1793 | fn simpleBinOp( |
| ... | ... | @@ -2070,7 +2128,6 @@ fn whileExpr( |
| 2070 | 2128 | }; |
| 2071 | 2129 | defer then_scope.instructions.deinit(mod.gpa); |
| 2072 | 2130 | |
| 2073 | | // declare payload to the then_scope |
| 2074 | 2131 | const then_sub_scope = &then_scope.base; |
| 2075 | 2132 | |
| 2076 | 2133 | loop_scope.break_count += 1; |
| ... | ... | @@ -2101,7 +2158,7 @@ fn whileExpr( |
| 2101 | 2158 | |
| 2102 | 2159 | if (loop_scope.label) |some| { |
| 2103 | 2160 | if (!some.used) { |
| 2104 | | return mod.fail(scope, token_starts[some.token], "unused while label", .{}); |
| 2161 | return mod.fail(scope, token_starts[some.token], "unused while loop label", .{}); |
| 2105 | 2162 | } |
| 2106 | 2163 | } |
| 2107 | 2164 | return finishThenElseBlock( |
| ... | ... | @@ -2126,20 +2183,21 @@ fn forExpr( |
| 2126 | 2183 | mod: *Module, |
| 2127 | 2184 | scope: *Scope, |
| 2128 | 2185 | rl: ResultLoc, |
| 2129 | | for_node: *ast.Node.@"for", |
| 2186 | for_full: ast.full.While, |
| 2130 | 2187 | ) InnerError!*zir.Inst { |
| 2131 | | if (for_node.label) |label| { |
| 2132 | | try checkLabelRedefinition(mod, scope, label); |
| 2188 | if (for_full.label_token) |label_token| { |
| 2189 | try checkLabelRedefinition(mod, scope, label_token); |
| 2133 | 2190 | } |
| 2134 | 2191 | |
| 2135 | | if (for_node.inline_token) |tok| |
| 2136 | | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| 2192 | if (for_full.inline_token) |inline_token| { |
| 2193 | return mod.failTok(scope, inline_token, "TODO inline for", .{}); |
| 2194 | } |
| 2137 | 2195 | |
| 2138 | | // setup variables and constants |
| 2196 | // Set up variables and constants. |
| 2139 | 2197 | const tree = scope.tree(); |
| 2140 | 2198 | const node_datas = tree.nodes.items(.data); |
| 2141 | 2199 | const main_tokens = tree.nodes.items(.main_token); |
| 2142 | | const for_src = token_starts[for_node.for_token]; |
| 2200 | const for_src = token_starts[for_full.ast.while_token]; |
| 2143 | 2201 | const index_ptr = blk: { |
| 2144 | 2202 | const usize_type = try addZIRInstConst(mod, scope, for_src, .{ |
| 2145 | 2203 | .ty = Type.initTag(.type), |
| ... | ... | @@ -2154,8 +2212,8 @@ fn forExpr( |
| 2154 | 2212 | _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero); |
| 2155 | 2213 | break :blk index_ptr; |
| 2156 | 2214 | }; |
| 2157 | | const array_ptr = try expr(mod, scope, .ref, for_node.array_expr); |
| 2158 | | const cond_src = token_starts[for_node.array_expr.firstToken()]; |
| 2215 | const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr); |
| 2216 | const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)]; |
| 2159 | 2217 | const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr); |
| 2160 | 2218 | |
| 2161 | 2219 | var loop_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -2217,15 +2275,15 @@ fn forExpr( |
| 2217 | 2275 | }); |
| 2218 | 2276 | loop_scope.break_block = for_block; |
| 2219 | 2277 | loop_scope.continue_block = cond_block; |
| 2220 | | if (for_node.label) |some| { |
| 2278 | if (for_full.label_token) |label_token| { |
| 2221 | 2279 | loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| 2222 | | .token = some, |
| 2280 | .token = label_token, |
| 2223 | 2281 | .block_inst = for_block, |
| 2224 | 2282 | }); |
| 2225 | 2283 | } |
| 2226 | 2284 | |
| 2227 | 2285 | // while body |
| 2228 | | const then_src = token_starts[for_node.body.lastToken()]; |
| 2286 | const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)]; |
| 2229 | 2287 | var then_scope: Scope.GenZIR = .{ |
| 2230 | 2288 | .parent = &cond_scope.base, |
| 2231 | 2289 | .decl = cond_scope.decl, |
| ... | ... | @@ -2237,23 +2295,27 @@ fn forExpr( |
| 2237 | 2295 | |
| 2238 | 2296 | var index_scope: Scope.LocalPtr = undefined; |
| 2239 | 2297 | const then_sub_scope = blk: { |
| 2240 | | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| 2241 | | const is_ptr = payload.ptr_token != null; |
| 2242 | | const value_name = tree.tokenSlice(payload.value_symbol.firstToken()); |
| 2298 | const payload_token = for_full.payload_token.?; |
| 2299 | const ident = if (token_tags[payload_token] == .asterisk) |
| 2300 | payload_token + 1 |
| 2301 | else |
| 2302 | payload_token; |
| 2303 | const is_ptr = ident != payload_token; |
| 2304 | const value_name = tree.tokenSlice(ident); |
| 2243 | 2305 | if (!mem.eql(u8, value_name, "_")) { |
| 2244 | | return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{}); |
| 2306 | return mod.failNode(&then_scope.base, ident, "TODO implement for loop value payload", .{}); |
| 2245 | 2307 | } else if (is_ptr) { |
| 2246 | | return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| 2308 | return mod.failTok(&then_scope.base, payload_token, "pointer modifier invalid on discard", .{}); |
| 2247 | 2309 | } |
| 2248 | 2310 | |
| 2249 | | const index_symbol_node = payload.index_symbol orelse |
| 2250 | | break :blk &then_scope.base; |
| 2251 | | |
| 2252 | | const index_name = tree.tokenSlice(tree.firstToken(index_symbol_node)); |
| 2253 | | if (mem.eql(u8, index_name, "_")) { |
| 2311 | const index_token = if (token_tags[ident + 1] == .comma) |
| 2312 | ident + 2 |
| 2313 | else |
| 2254 | 2314 | break :blk &then_scope.base; |
| 2315 | if (mem.eql(u8, tree.tokenSlice(index_token), "_")) { |
| 2316 | return mod.failTok(&then_scope.base, index_token, "discard of index capture not allowed; omit it instead", .{}); |
| 2255 | 2317 | } |
| 2256 | | // TODO make this const without an extra copy? |
| 2318 | const index_name = try mod.identifierTokenString(&then_scope.base, index_token); |
| 2257 | 2319 | index_scope = .{ |
| 2258 | 2320 | .parent = &then_scope.base, |
| 2259 | 2321 | .gen_zir = &then_scope, |
| ... | ... | @@ -2264,7 +2326,7 @@ fn forExpr( |
| 2264 | 2326 | }; |
| 2265 | 2327 | |
| 2266 | 2328 | loop_scope.break_count += 1; |
| 2267 | | const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_node.body); |
| 2329 | const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); |
| 2268 | 2330 | |
| 2269 | 2331 | // else branch |
| 2270 | 2332 | var else_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -2276,18 +2338,23 @@ fn forExpr( |
| 2276 | 2338 | }; |
| 2277 | 2339 | defer else_scope.instructions.deinit(mod.gpa); |
| 2278 | 2340 | |
| 2279 | | var else_src: usize = undefined; |
| 2280 | | const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: { |
| 2281 | | else_src = token_starts[else_node.body.lastToken()]; |
| 2341 | const else_node = for_full.ast.else_expr; |
| 2342 | const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: { |
| 2282 | 2343 | loop_scope.break_count += 1; |
| 2283 | | break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body); |
| 2284 | | } else blk: { |
| 2285 | | else_src = token_starts[for_node.lastToken()]; |
| 2286 | | break :blk null; |
| 2287 | | }; |
| 2344 | const sub_scope = &else_scope.base; |
| 2345 | break :blk .{ |
| 2346 | .src = token_starts[tree.lastToken(else_node)], |
| 2347 | .result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node), |
| 2348 | }; |
| 2349 | } else |
| 2350 | .{ |
| 2351 | .src = token_starts[tree.lastToken(then_node)], |
| 2352 | .result = null, |
| 2353 | }; |
| 2354 | |
| 2288 | 2355 | if (loop_scope.label) |some| { |
| 2289 | 2356 | if (!some.used) { |
| 2290 | | return mod.fail(scope, token_starts[some.token], "unused for label", .{}); |
| 2357 | return mod.fail(scope, token_starts[some.token], "unused for loop label", .{}); |
| 2291 | 2358 | } |
| 2292 | 2359 | } |
| 2293 | 2360 | return finishThenElseBlock( |
| ... | ... | @@ -2300,41 +2367,46 @@ fn forExpr( |
| 2300 | 2367 | &condbr.positionals.then_body, |
| 2301 | 2368 | &condbr.positionals.else_body, |
| 2302 | 2369 | then_src, |
| 2303 | | else_src, |
| 2370 | else_info.src, |
| 2304 | 2371 | then_result, |
| 2305 | | else_result, |
| 2372 | else_info.result, |
| 2306 | 2373 | for_block, |
| 2307 | 2374 | cond_block, |
| 2308 | 2375 | ); |
| 2309 | 2376 | } |
| 2310 | 2377 | |
| 2311 | | fn switchCaseUsesRef(node: *ast.Node.@"switch") bool { |
| 2312 | | for (node.cases()) |uncasted_case| { |
| 2313 | | const case = uncasted_case.castTag(.switch_case).?; |
| 2314 | | const uncasted_payload = case.payload orelse continue; |
| 2315 | | const payload = uncasted_payload.castTag(.PointerPayload).?; |
| 2316 | | if (payload.ptr_token) |_| return true; |
| 2317 | | } |
| 2318 | | return false; |
| 2319 | | } |
| 2320 | | |
| 2321 | | fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp { |
| 2322 | | var cur = node; |
| 2378 | fn getRangeNode( |
| 2379 | node_tags: []const ast.Node.Tag, |
| 2380 | node_datas: []const ast.Node.Data, |
| 2381 | start_node: ast.Node.Index, |
| 2382 | ) ?ast.Node.Index { |
| 2383 | var node = start_node; |
| 2323 | 2384 | while (true) { |
| 2324 | | switch (cur.tag) { |
| 2325 | | .range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur), |
| 2326 | | .grouped_expression => cur = @fieldParentPtr(ast.Node.grouped_expression, "base", cur).expr, |
| 2385 | switch (node_tags[node]) { |
| 2386 | .switch_range => return node, |
| 2387 | .grouped_expression => node = node_datas[node].lhs, |
| 2327 | 2388 | else => return null, |
| 2328 | 2389 | } |
| 2329 | 2390 | } |
| 2330 | 2391 | } |
| 2331 | 2392 | |
| 2332 | | fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.@"switch") InnerError!*zir.Inst { |
| 2393 | fn switchExpr( |
| 2394 | mod: *Module, |
| 2395 | scope: *Scope, |
| 2396 | rl: ResultLoc, |
| 2397 | switch_node: ast.Node.Index, |
| 2398 | ) InnerError!*zir.Inst { |
| 2333 | 2399 | const tree = scope.tree(); |
| 2334 | 2400 | const node_datas = tree.nodes.items(.data); |
| 2335 | 2401 | const main_tokens = tree.nodes.items(.main_token); |
| 2336 | | const switch_src = token_starts[switch_node.switch_token]; |
| 2337 | | const use_ref = switchCaseUsesRef(switch_node); |
| 2402 | const token_tags = tree.tokens.items(.tag); |
| 2403 | |
| 2404 | const switch_token = main_tokens[switch_node]; |
| 2405 | const target_node = datas[switch_node].lhs; |
| 2406 | const extra = tree.extraData(datas[switch_node].rhs, ast.switch_node.SubRange); |
| 2407 | const case_nodes = tree.extra_data[extra.start..extra.end]; |
| 2408 | |
| 2409 | const switch_src = token_starts[switch_token]; |
| 2338 | 2410 | |
| 2339 | 2411 | var block_scope: Scope.GenZIR = .{ |
| 2340 | 2412 | .parent = scope, |
| ... | ... | @@ -2349,18 +2421,26 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2349 | 2421 | var items = std.ArrayList(*zir.Inst).init(mod.gpa); |
| 2350 | 2422 | defer items.deinit(); |
| 2351 | 2423 | |
| 2352 | | // first we gather all the switch items and check else/'_' prongs |
| 2424 | // First we gather all the switch items and check else/'_' prongs. |
| 2353 | 2425 | var else_src: ?usize = null; |
| 2354 | 2426 | var underscore_src: ?usize = null; |
| 2355 | 2427 | var first_range: ?*zir.Inst = null; |
| 2356 | 2428 | var simple_case_count: usize = 0; |
| 2357 | | for (switch_node.cases()) |uncasted_case| { |
| 2358 | | const case = uncasted_case.castTag(.switch_case).?; |
| 2359 | | const case_src = token_starts[case.firstToken()]; |
| 2360 | | assert(case.items_len != 0); |
| 2361 | | |
| 2429 | var any_payload_is_ref = false; |
| 2430 | for (case_nodes) |case_node| { |
| 2431 | const case = switch (node_tags[case_node]) { |
| 2432 | .switch_case_one => tree.switchCaseOne(case_node), |
| 2433 | .switch_case => tree.switchCase(case_node), |
| 2434 | else => unreachable, |
| 2435 | }; |
| 2436 | if (case.payload_token) |payload_token| { |
| 2437 | if (token_tags[payload_token] == .asterisk) { |
| 2438 | any_payload_is_ref = true; |
| 2439 | } |
| 2440 | } |
| 2362 | 2441 | // Check for else/_ prong, those are handled last. |
| 2363 | | if (case.items_len == 1 and case.items()[0].tag == .switch_else) { |
| 2442 | if (case.ast.values.len == 0) { |
| 2443 | const case_src = token_starts[case.ast.arrow_token - 1]; |
| 2364 | 2444 | if (else_src) |src| { |
| 2365 | 2445 | const msg = msg: { |
| 2366 | 2446 | const msg = try mod.errMsg( |
| ... | ... | @@ -2377,9 +2457,11 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2377 | 2457 | } |
| 2378 | 2458 | else_src = case_src; |
| 2379 | 2459 | continue; |
| 2380 | | } else if (case.items_len == 1 and case.items()[0].tag == .identifier and |
| 2381 | | mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) |
| 2460 | } else if (case.ast.values.len == 1 and |
| 2461 | node_tags[case.ast.values[0]] == .identifier and |
| 2462 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) |
| 2382 | 2463 | { |
| 2464 | const case_src = token_starts[case.ast.arrow_token - 1]; |
| 2383 | 2465 | if (underscore_src) |src| { |
| 2384 | 2466 | const msg = msg: { |
| 2385 | 2467 | const msg = try mod.errMsg( |
| ... | ... | @@ -2416,14 +2498,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2416 | 2498 | } |
| 2417 | 2499 | } |
| 2418 | 2500 | |
| 2419 | | if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) simple_case_count += 1; |
| 2501 | if (case.ast.values.len == 1 and |
| 2502 | getRangeNode(node_tags, node_datas, case.ast.values[0]) == null) |
| 2503 | { |
| 2504 | simple_case_count += 1; |
| 2505 | } |
| 2420 | 2506 | |
| 2421 | | // generate all the switch items as comptime expressions |
| 2422 | | for (case.items()) |item| { |
| 2423 | | if (getRangeNode(item)) |range| { |
| 2424 | | const start = try comptimeExpr(mod, &block_scope.base, .none, range.lhs); |
| 2425 | | const end = try comptimeExpr(mod, &block_scope.base, .none, range.rhs); |
| 2426 | | const range_src = token_starts[range.op_token]; |
| 2507 | // Generate all the switch items as comptime expressions. |
| 2508 | for (case.ast.values) |item| { |
| 2509 | if (getRangeNode(node_tags, node_datas, item)) |range| { |
| 2510 | const start = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].lhs); |
| 2511 | const end = try comptimeExpr(mod, &block_scope.base, .none, node_datas[range].rhs); |
| 2512 | const range_src = token_starts[main_tokens[range]]; |
| 2427 | 2513 | const range_inst = try addZIRBinOp(mod, &block_scope.base, range_src, .switch_range, start, end); |
| 2428 | 2514 | try items.append(range_inst); |
| 2429 | 2515 | } else { |
| ... | ... | @@ -2438,21 +2524,25 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2438 | 2524 | if (underscore_src != null) special_prong = .underscore; |
| 2439 | 2525 | var cases = try block_scope.arena.alloc(zir.Inst.SwitchBr.Case, simple_case_count); |
| 2440 | 2526 | |
| 2441 | | const target_ptr = if (use_ref) try expr(mod, &block_scope.base, .ref, switch_node.expr) else null; |
| 2442 | | const target = if (target_ptr) |some| |
| 2443 | | try addZIRUnOp(mod, &block_scope.base, some.src, .deref, some) |
| 2527 | const rl_and_tag: struct { rl: ResultLoc, tag: zir.Inst.Tag } = if (any_payload_is_ref) |
| 2528 | .{ |
| 2529 | .rl = .ref, |
| 2530 | .tag = .switchbr_ref, |
| 2531 | } |
| 2444 | 2532 | else |
| 2445 | | try expr(mod, &block_scope.base, .none, switch_node.expr); |
| 2446 | | const switch_inst = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{ |
| 2533 | .{ |
| 2534 | .rl = .none, |
| 2535 | .tag = .switchbr, |
| 2536 | }; |
| 2537 | const target = try expr(mod, &block_scope.base, rl_and_tag.rl, target_node); |
| 2538 | const switch_inst = try addZirInstT(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, rl_and_tag.tag, .{ |
| 2447 | 2539 | .target = target, |
| 2448 | 2540 | .cases = cases, |
| 2449 | 2541 | .items = try block_scope.arena.dupe(*zir.Inst, items.items), |
| 2450 | 2542 | .else_body = undefined, // populated below |
| 2451 | | }, .{ |
| 2452 | 2543 | .range = first_range, |
| 2453 | 2544 | .special_prong = special_prong, |
| 2454 | 2545 | }); |
| 2455 | | |
| 2456 | 2546 | const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{ |
| 2457 | 2547 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 2458 | 2548 | }); |
| ... | ... | @@ -2475,29 +2565,35 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2475 | 2565 | }; |
| 2476 | 2566 | defer else_scope.instructions.deinit(mod.gpa); |
| 2477 | 2567 | |
| 2478 | | // Now generate all but the special cases |
| 2479 | | var special_case: ?*ast.Node.switch_case = null; |
| 2568 | // Now generate all but the special cases. |
| 2569 | var special_case: ?ast.Node.Index = null; |
| 2480 | 2570 | var items_index: usize = 0; |
| 2481 | 2571 | var case_index: usize = 0; |
| 2482 | | for (switch_node.cases()) |uncasted_case| { |
| 2483 | | const case = uncasted_case.castTag(.switch_case).?; |
| 2484 | | const case_src = token_starts[case.firstToken()]; |
| 2485 | | // reset without freeing to reduce allocations. |
| 2486 | | case_scope.instructions.items.len = 0; |
| 2572 | for (case_nodes) |case_node| { |
| 2573 | const case = switch (node_tags[case_node]) { |
| 2574 | .switch_case_one => tree.switchCaseOne(case_node), |
| 2575 | .switch_case => tree.switchCase(case_node), |
| 2576 | else => unreachable, |
| 2577 | }; |
| 2578 | const case_src = token_starts[main_tokens[case_node]]; |
| 2579 | case_scope.instructions.shrinkRetainingCapacity(0); |
| 2487 | 2580 | |
| 2488 | 2581 | // Check for else/_ prong, those are handled last. |
| 2489 | | if (case.items_len == 1 and case.items()[0].tag == .switch_else) { |
| 2582 | if (case.ast.values.len == 0) { |
| 2490 | 2583 | special_case = case; |
| 2491 | 2584 | continue; |
| 2492 | | } else if (case.items_len == 1 and case.items()[0].tag == .identifier and |
| 2493 | | mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) |
| 2585 | } else if (case.ast.values.len == 1 and |
| 2586 | node_tags[case.ast.values[0]] == .identifier and |
| 2587 | mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) |
| 2494 | 2588 | { |
| 2495 | 2589 | special_case = case; |
| 2496 | 2590 | continue; |
| 2497 | 2591 | } |
| 2498 | 2592 | |
| 2499 | 2593 | // If this is a simple one item prong then it is handled by the switchbr. |
| 2500 | | if (case.items_len == 1 and getRangeNode(case.items()[0]) == null) { |
| 2594 | if (case.ast.values.len == 1 and |
| 2595 | getRangeNode(node_tags, node_datas, case.ast.values[0]) == null) |
| 2596 | { |
| 2501 | 2597 | const item = items.items[items_index]; |
| 2502 | 2598 | items_index += 1; |
| 2503 | 2599 | try switchCaseExpr(mod, &case_scope.base, block_scope.break_result_loc, block, case, target, target_ptr); |
| ... | ... | @@ -2510,16 +2606,14 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2510 | 2606 | continue; |
| 2511 | 2607 | } |
| 2512 | 2608 | |
| 2513 | | // TODO if the case has few items and no ranges it might be better |
| 2514 | | // to just handle them as switch prongs. |
| 2515 | | |
| 2516 | 2609 | // Check if the target matches any of the items. |
| 2517 | 2610 | // 1, 2, 3..6 will result in |
| 2518 | 2611 | // target == 1 or target == 2 or (target >= 3 and target <= 6) |
| 2612 | // TODO handle multiple items as switch prongs rather than along with ranges. |
| 2519 | 2613 | var any_ok: ?*zir.Inst = null; |
| 2520 | | for (case.items()) |item| { |
| 2521 | | if (getRangeNode(item)) |range| { |
| 2522 | | const range_src = token_starts[range.op_token]; |
| 2614 | for (case.ast.values) |item| { |
| 2615 | if (getRangeNode(node_tags, node_datas, item)) |range| { |
| 2616 | const range_src = token_starts[main_tokens[range]]; |
| 2523 | 2617 | const range_inst = items.items[items_index].castTag(.switch_range).?; |
| 2524 | 2618 | items_index += 1; |
| 2525 | 2619 | |
| ... | ... | @@ -2580,7 +2674,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 2580 | 2674 | // Not handling all possible cases is a compile error. |
| 2581 | 2675 | _ = try addZIRNoOp(mod, &else_scope.base, switch_src, .unreachable_unsafe); |
| 2582 | 2676 | } |
| 2583 | | switch_inst.castTag(.switchbr).?.positionals.else_body = .{ |
| 2677 | switch_inst.positionals.else_body = .{ |
| 2584 | 2678 | .instructions = try block_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), |
| 2585 | 2679 | }; |
| 2586 | 2680 | |
| ... | ... | @@ -2592,19 +2686,22 @@ fn switchCaseExpr( |
| 2592 | 2686 | scope: *Scope, |
| 2593 | 2687 | rl: ResultLoc, |
| 2594 | 2688 | block: *zir.Inst.Block, |
| 2595 | | case: *ast.Node.switch_case, |
| 2689 | case: ast.full.SwitchCase, |
| 2596 | 2690 | target: *zir.Inst, |
| 2597 | 2691 | target_ptr: ?*zir.Inst, |
| 2598 | 2692 | ) !void { |
| 2599 | 2693 | const tree = scope.tree(); |
| 2600 | 2694 | const node_datas = tree.nodes.items(.data); |
| 2601 | 2695 | const main_tokens = tree.nodes.items(.main_token); |
| 2602 | | const case_src = token_starts[case.firstToken()]; |
| 2696 | const case_src = token_starts[case.ast.arrow_token]; |
| 2603 | 2697 | const sub_scope = blk: { |
| 2604 | | const uncasted_payload = case.payload orelse break :blk scope; |
| 2605 | | const payload = uncasted_payload.castTag(.PointerPayload).?; |
| 2606 | | const is_ptr = payload.ptr_token != null; |
| 2607 | | const value_name = tree.tokenSlice(payload.value_symbol.firstToken()); |
| 2698 | const payload_token = case.payload_token orelse break :blk scope; |
| 2699 | const ident = if (token_tags[payload_token] == .asterisk) |
| 2700 | payload_token + 1 |
| 2701 | else |
| 2702 | payload_token; |
| 2703 | const is_ptr = ident != payload_token; |
| 2704 | const value_name = tree.tokenSlice(ident); |
| 2608 | 2705 | if (mem.eql(u8, value_name, "_")) { |
| 2609 | 2706 | if (is_ptr) { |
| 2610 | 2707 | return mod.failTok(scope, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| ... | ... | @@ -2614,7 +2711,7 @@ fn switchCaseExpr( |
| 2614 | 2711 | return mod.failNode(scope, payload.value_symbol, "TODO implement switch value payload", .{}); |
| 2615 | 2712 | }; |
| 2616 | 2713 | |
| 2617 | | const case_body = try expr(mod, sub_scope, rl, case.expr); |
| 2714 | const case_body = try expr(mod, sub_scope, rl, case.ast.target_expr); |
| 2618 | 2715 | if (!case_body.tag.isNoReturn()) { |
| 2619 | 2716 | _ = try addZIRInst(mod, sub_scope, case_src, zir.Inst.Break, .{ |
| 2620 | 2717 | .block = block, |
| ... | ... | @@ -2820,12 +2917,13 @@ fn multilineStringLiteral( |
| 2820 | 2917 | return rvalue(mod, scope, rl, str_inst); |
| 2821 | 2918 | } |
| 2822 | 2919 | |
| 2823 | | fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst { |
| 2920 | fn charLiteral(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !*zir.Inst { |
| 2824 | 2921 | const tree = scope.tree(); |
| 2825 | 2922 | const node_datas = tree.nodes.items(.data); |
| 2826 | 2923 | const main_tokens = tree.nodes.items(.main_token); |
| 2827 | | const src = token_starts[node.token]; |
| 2828 | | const slice = tree.tokenSlice(node.token); |
| 2924 | const main_token = main_tokens[node]; |
| 2925 | const src = token_starts[main_token]; |
| 2926 | const slice = tree.tokenSlice(main_token); |
| 2829 | 2927 | |
| 2830 | 2928 | var bad_index: usize = undefined; |
| 2831 | 2929 | const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) { |
| ... | ... | @@ -2834,11 +2932,11 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst |
| 2834 | 2932 | return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte}); |
| 2835 | 2933 | }, |
| 2836 | 2934 | }; |
| 2837 | | |
| 2838 | | return addZIRInstConst(mod, scope, src, .{ |
| 2935 | const result = try addZIRInstConst(mod, scope, src, .{ |
| 2839 | 2936 | .ty = Type.initTag(.comptime_int), |
| 2840 | 2937 | .val = try Value.Tag.int_u64.create(scope.arena(), value), |
| 2841 | 2938 | }); |
| 2939 | return rvalue(mod, scope, rl, result); |
| 2842 | 2940 | } |
| 2843 | 2941 | |
| 2844 | 2942 | fn integerLiteral( |
| ... | ... | @@ -3675,6 +3773,29 @@ pub fn addZirInstTag( |
| 3675 | 3773 | return &inst.base; |
| 3676 | 3774 | } |
| 3677 | 3775 | |
| 3776 | pub fn addZirInstT( |
| 3777 | mod: *Module, |
| 3778 | scope: *Scope, |
| 3779 | src: usize, |
| 3780 | comptime T: type, |
| 3781 | tag: zir.Inst.Tag, |
| 3782 | positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type, |
| 3783 | ) !*T { |
| 3784 | const gen_zir = scope.getGenZIR(); |
| 3785 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); |
| 3786 | const inst = try gen_zir.arena.create(T); |
| 3787 | inst.* = .{ |
| 3788 | .base = .{ |
| 3789 | .tag = tag, |
| 3790 | .src = src, |
| 3791 | }, |
| 3792 | .positionals = positionals, |
| 3793 | .kw_args = .{}, |
| 3794 | }; |
| 3795 | gen_zir.instructions.appendAssumeCapacity(&inst.base); |
| 3796 | return inst; |
| 3797 | } |
| 3798 | |
| 3678 | 3799 | pub fn addZIRInstSpecial( |
| 3679 | 3800 | mod: *Module, |
| 3680 | 3801 | scope: *Scope, |