| author | |
| committer | |
| log | 272fe1c54c76ddab2dbecc2b302a651929c4b994 |
| tree | 3781d8cd1831d9d4aad16721df8ab898a3fdb64e |
| parent | b09a0cd0727055217742cb178822521733078c27 |
6 files changed, 630 insertions(+), 369 deletions(-)
src/all_types.hpp+19-27| ... | ... | @@ -22,7 +22,6 @@ struct FnTableEntry; |
| 22 | 22 | struct BlockContext; |
| 23 | 23 | struct TypeTableEntry; |
| 24 | 24 | struct VariableTableEntry; |
| 25 | struct Cast; | |
| 26 | 25 | struct BuiltinFnEntry; |
| 27 | 26 | struct LabelTableEntry; |
| 28 | 27 | struct TypeStructField; |
| ... | ... | @@ -41,15 +40,6 @@ enum CodeGenBuildType { |
| 41 | 40 | CodeGenBuildTypeRelease, |
| 42 | 41 | }; |
| 43 | 42 | |
| 44 | enum CastOp { | |
| 45 | CastOpNothing, | |
| 46 | CastOpPtrToInt, | |
| 47 | CastOpIntWidenOrShorten, | |
| 48 | CastOpToUnknownSizeArray, | |
| 49 | CastOpMaybeWrap, | |
| 50 | CastOpPointerReinterpret, | |
| 51 | }; | |
| 52 | ||
| 53 | 43 | struct ConstEnumValue { |
| 54 | 44 | uint64_t tag; |
| 55 | 45 | ConstExprValue *payload; |
| ... | ... | @@ -69,29 +59,15 @@ struct ConstExprValue { |
| 69 | 59 | } data; |
| 70 | 60 | }; |
| 71 | 61 | |
| 72 | struct Cast { | |
| 73 | CastOp op; | |
| 74 | // if op is CastOpArrayToString, this will be a pointer to | |
| 75 | // the string struct on the stack | |
| 76 | LLVMValueRef ptr; | |
| 77 | TypeTableEntry *after_type; | |
| 78 | AstNode *source_node; | |
| 79 | ConstExprValue const_val; | |
| 80 | }; | |
| 81 | ||
| 82 | 62 | struct Expr { |
| 83 | 63 | TypeTableEntry *type_entry; |
| 84 | TypeTableEntry *resolved_type; | |
| 85 | 64 | // the context in which this expression is evaluated. |
| 86 | 65 | // for blocks, this points to the containing scope, not the block's own scope for its children. |
| 87 | 66 | BlockContext *block_context; |
| 88 | 67 | |
| 89 | // may be null for no cast | |
| 90 | Cast implicit_cast; // happens first | |
| 91 | Cast implicit_maybe_cast; // happens second | |
| 92 | ||
| 93 | 68 | LLVMValueRef const_llvm_val; |
| 94 | 69 | ConstExprValue const_val; |
| 70 | bool has_global_const; | |
| 95 | 71 | }; |
| 96 | 72 | |
| 97 | 73 | struct StructValExprCodeGen { |
| ... | ... | @@ -305,6 +281,16 @@ struct AstNodeBinOpExpr { |
| 305 | 281 | Expr resolved_expr; |
| 306 | 282 | }; |
| 307 | 283 | |
| 284 | enum CastOp { | |
| 285 | CastOpNoCast, // signifies the function call expression is not a cast | |
| 286 | CastOpNoop, // fn call expr is a cast, but does nothing | |
| 287 | CastOpPtrToInt, | |
| 288 | CastOpIntWidenOrShorten, | |
| 289 | CastOpToUnknownSizeArray, | |
| 290 | CastOpMaybeWrap, | |
| 291 | CastOpPointerReinterpret, | |
| 292 | }; | |
| 293 | ||
| 308 | 294 | struct AstNodeFnCallExpr { |
| 309 | 295 | AstNode *fn_ref_expr; |
| 310 | 296 | ZigList<AstNode *> params; |
| ... | ... | @@ -313,8 +299,11 @@ struct AstNodeFnCallExpr { |
| 313 | 299 | // populated by semantic analyzer: |
| 314 | 300 | BuiltinFnEntry *builtin_fn; |
| 315 | 301 | Expr resolved_expr; |
| 316 | Cast cast; | |
| 317 | 302 | FnTableEntry *fn_entry; |
| 303 | CastOp cast_op; | |
| 304 | // if cast_op is CastOpArrayToString, this will be a pointer to | |
| 305 | // the string struct on the stack | |
| 306 | LLVMValueRef tmp_ptr; | |
| 318 | 307 | }; |
| 319 | 308 | |
| 320 | 309 | struct AstNodeArrayAccessExpr { |
| ... | ... | @@ -610,6 +599,8 @@ struct AstNodeSymbolExpr { |
| 610 | 599 | Expr resolved_expr; |
| 611 | 600 | VariableTableEntry *variable; |
| 612 | 601 | FnTableEntry *fn_entry; |
| 602 | // set this to instead of analyzing the node, pretend it's a type entry and it's this one. | |
| 603 | TypeTableEntry *override_type_entry; | |
| 613 | 604 | }; |
| 614 | 605 | |
| 615 | 606 | struct AstNodeBoolLiteral { |
| ... | ... | @@ -644,6 +635,7 @@ struct AstNode { |
| 644 | 635 | int column; |
| 645 | 636 | uint32_t create_index; // for determinism purposes |
| 646 | 637 | ImportTableEntry *owner; |
| 638 | AstNode **parent_field; // for AST rewriting | |
| 647 | 639 | union { |
| 648 | 640 | AstNodeRoot root; |
| 649 | 641 | AstNodeRootExportDecl root_export_decl; |
| ... | ... | @@ -997,7 +989,7 @@ struct BlockContext { |
| 997 | 989 | BlockContext *parent; // null when this is the root |
| 998 | 990 | HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table; |
| 999 | 991 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; |
| 1000 | ZigList<Cast *> cast_expr_alloca_list; | |
| 992 | ZigList<AstNode *> cast_alloca_list; | |
| 1001 | 993 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; |
| 1002 | 994 | ZigList<VariableTableEntry *> variable_list; |
| 1003 | 995 | AstNode *parent_loop_node; |
src/analyze.cpp+290-215| ... | ... | @@ -17,6 +17,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE |
| 17 | 17 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 18 | 18 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); |
| 19 | 19 | static TypeTableEntry *unwrapped_node_type(AstNode *node); |
| 20 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 21 | AstNode *node); | |
| 20 | 22 | |
| 21 | 23 | static AstNode *first_executing_node(AstNode *node) { |
| 22 | 24 | switch (node->type) { |
| ... | ... | @@ -369,6 +371,9 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c |
| 369 | 371 | // and returns invalid type. Otherwise, returns the type of the constant expression value. |
| 370 | 372 | // Must be called after analyze_expression on the same node. |
| 371 | 373 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 374 | if (node->type == NodeTypeSymbol && node->data.symbol_expr.override_type_entry) { | |
| 375 | return node->data.symbol_expr.override_type_entry; | |
| 376 | } | |
| 372 | 377 | Expr *expr = get_resolved_expr(node); |
| 373 | 378 | assert(expr->type_entry); |
| 374 | 379 | if (expr->type_entry->id == TypeTableEntryIdInvalid) { |
| ... | ... | @@ -393,8 +398,9 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 393 | 398 | static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 394 | 399 | AstNode *node) |
| 395 | 400 | { |
| 396 | analyze_expression(g, import, context, nullptr, node); | |
| 397 | return resolve_type(g, node); | |
| 401 | AstNode **node_ptr = node->parent_field; | |
| 402 | analyze_expression(g, import, context, nullptr, *node_ptr); | |
| 403 | return resolve_type(g, *node_ptr); | |
| 398 | 404 | } |
| 399 | 405 | |
| 400 | 406 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, |
| ... | ... | @@ -1044,12 +1050,43 @@ static TypeTableEntry *get_return_type(BlockContext *context) { |
| 1044 | 1050 | return unwrapped_node_type(return_type_node); |
| 1045 | 1051 | } |
| 1046 | 1052 | |
| 1053 | static bool type_has_codegen_value(TypeTableEntryId id) { | |
| 1054 | switch (id) { | |
| 1055 | case TypeTableEntryIdInvalid: | |
| 1056 | case TypeTableEntryIdMetaType: | |
| 1057 | case TypeTableEntryIdVoid: | |
| 1058 | case TypeTableEntryIdUnreachable: | |
| 1059 | case TypeTableEntryIdNumLitFloat: | |
| 1060 | case TypeTableEntryIdNumLitInt: | |
| 1061 | return false; | |
| 1062 | ||
| 1063 | case TypeTableEntryIdBool: | |
| 1064 | case TypeTableEntryIdInt: | |
| 1065 | case TypeTableEntryIdFloat: | |
| 1066 | case TypeTableEntryIdPointer: | |
| 1067 | case TypeTableEntryIdArray: | |
| 1068 | case TypeTableEntryIdStruct: | |
| 1069 | case TypeTableEntryIdMaybe: | |
| 1070 | case TypeTableEntryIdError: | |
| 1071 | case TypeTableEntryIdEnum: | |
| 1072 | case TypeTableEntryIdFn: | |
| 1073 | return true; | |
| 1074 | } | |
| 1075 | zig_unreachable(); | |
| 1076 | } | |
| 1077 | ||
| 1078 | static void add_global_const_expr(CodeGen *g, Expr *expr) { | |
| 1079 | if (expr->const_val.ok && type_has_codegen_value(expr->type_entry->id) && !expr->has_global_const) { | |
| 1080 | g->global_const_list.append(expr); | |
| 1081 | expr->has_global_const = true; | |
| 1082 | } | |
| 1083 | } | |
| 1084 | ||
| 1047 | 1085 | static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) { |
| 1048 | 1086 | Expr *expr = get_resolved_expr(literal_node); |
| 1049 | 1087 | ConstExprValue *const_val = &expr->const_val; |
| 1050 | 1088 | assert(const_val->ok); |
| 1051 | 1089 | if (other_type->id == TypeTableEntryIdFloat) { |
| 1052 | expr->resolved_type = other_type; | |
| 1053 | 1090 | return true; |
| 1054 | 1091 | } else if (other_type->id == TypeTableEntryIdInt && |
| 1055 | 1092 | const_val->data.x_bignum.kind == BigNumKindInt) |
| ... | ... | @@ -1057,7 +1094,6 @@ static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTa |
| 1057 | 1094 | if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits, |
| 1058 | 1095 | other_type->data.integral.is_signed)) |
| 1059 | 1096 | { |
| 1060 | expr->resolved_type = other_type; | |
| 1061 | 1097 | return true; |
| 1062 | 1098 | } |
| 1063 | 1099 | } else if (other_type->id == TypeTableEntryIdNumLitFloat || |
| ... | ... | @@ -1145,39 +1181,74 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa |
| 1145 | 1181 | return prev_type; |
| 1146 | 1182 | } |
| 1147 | 1183 | |
| 1148 | static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node, | |
| 1149 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) | |
| 1150 | { | |
| 1151 | if (expected_type == nullptr) | |
| 1152 | return actual_type; // anything will do | |
| 1184 | static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) { | |
| 1153 | 1185 | if (expected_type == actual_type) |
| 1154 | return expected_type; // match | |
| 1155 | if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid) | |
| 1156 | return expected_type; // already complained | |
| 1157 | if (actual_type->id == TypeTableEntryIdUnreachable) | |
| 1158 | return actual_type; // sorry toots; gotta run. good luck with that expected type. | |
| 1186 | return true; | |
| 1187 | ||
| 1188 | // pointer const | |
| 1189 | if (expected_type->id == TypeTableEntryIdPointer && | |
| 1190 | actual_type->id == TypeTableEntryIdPointer && | |
| 1191 | (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const)) | |
| 1192 | { | |
| 1193 | return types_match_const_cast_only(expected_type->data.pointer.child_type, | |
| 1194 | actual_type->data.pointer.child_type); | |
| 1195 | } | |
| 1159 | 1196 | |
| 1197 | // unknown size array const | |
| 1198 | if (expected_type->id == TypeTableEntryIdStruct && | |
| 1199 | actual_type->id == TypeTableEntryIdStruct && | |
| 1200 | expected_type->data.structure.is_unknown_size_array && | |
| 1201 | actual_type->data.structure.is_unknown_size_array && | |
| 1202 | (!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const || | |
| 1203 | expected_type->data.structure.fields[0].type_entry->data.pointer.is_const)) | |
| 1204 | { | |
| 1205 | return types_match_const_cast_only( | |
| 1206 | expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, | |
| 1207 | actual_type->data.structure.fields[0].type_entry->data.pointer.child_type); | |
| 1208 | } | |
| 1209 | ||
| 1210 | // maybe | |
| 1160 | 1211 | if (expected_type->id == TypeTableEntryIdMaybe && |
| 1161 | 1212 | actual_type->id == TypeTableEntryIdMaybe) |
| 1162 | 1213 | { |
| 1163 | TypeTableEntry *expected_child = expected_type->data.maybe.child_type; | |
| 1164 | TypeTableEntry *actual_child = actual_type->data.maybe.child_type; | |
| 1165 | return resolve_type_compatibility(g, context, node, expected_child, actual_child); | |
| 1214 | return types_match_const_cast_only( | |
| 1215 | expected_type->data.maybe.child_type, | |
| 1216 | actual_type->data.maybe.child_type); | |
| 1217 | } | |
| 1218 | ||
| 1219 | // error | |
| 1220 | if (expected_type->id == TypeTableEntryIdError && | |
| 1221 | actual_type->id == TypeTableEntryIdError) | |
| 1222 | { | |
| 1223 | return types_match_const_cast_only( | |
| 1224 | expected_type->data.error.child_type, | |
| 1225 | actual_type->data.error.child_type); | |
| 1226 | } | |
| 1227 | ||
| 1228 | // fn | |
| 1229 | if (expected_type->id == TypeTableEntryIdFn && | |
| 1230 | actual_type->id == TypeTableEntryIdFn) | |
| 1231 | { | |
| 1232 | zig_panic("TODO types_match_const_cast_only for fns"); | |
| 1233 | } | |
| 1234 | ||
| 1235 | ||
| 1236 | return false; | |
| 1237 | } | |
| 1238 | ||
| 1239 | static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_type, | |
| 1240 | TypeTableEntry *actual_type, AstNode *literal_node, bool *reported_err) | |
| 1241 | { | |
| 1242 | if (types_match_const_cast_only(expected_type, actual_type)) { | |
| 1243 | return true; | |
| 1166 | 1244 | } |
| 1167 | 1245 | |
| 1168 | 1246 | // implicit conversion from non maybe type to maybe type |
| 1169 | if (expected_type->id == TypeTableEntryIdMaybe) { | |
| 1170 | TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node, | |
| 1171 | expected_type->data.maybe.child_type, actual_type); | |
| 1172 | if (resolved_type->id == TypeTableEntryIdInvalid) { | |
| 1173 | return resolved_type; | |
| 1174 | } | |
| 1175 | Expr *expr = get_resolved_expr(node); | |
| 1176 | expr->implicit_maybe_cast.op = CastOpMaybeWrap; | |
| 1177 | expr->implicit_maybe_cast.after_type = expected_type; | |
| 1178 | expr->implicit_maybe_cast.source_node = node; | |
| 1179 | context->cast_expr_alloca_list.append(&expr->implicit_maybe_cast); | |
| 1180 | return expected_type; | |
| 1247 | if (expected_type->id == TypeTableEntryIdMaybe && | |
| 1248 | types_match_with_implicit_cast(g, expected_type->data.maybe.child_type, actual_type, | |
| 1249 | literal_node, reported_err)) | |
| 1250 | { | |
| 1251 | return true; | |
| 1181 | 1252 | } |
| 1182 | 1253 | |
| 1183 | 1254 | // implicit widening conversion |
| ... | ... | @@ -1186,78 +1257,94 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1186 | 1257 | expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && |
| 1187 | 1258 | expected_type->size_in_bits >= actual_type->size_in_bits) |
| 1188 | 1259 | { |
| 1189 | Expr *expr = get_resolved_expr(node); | |
| 1190 | expr->implicit_cast.after_type = expected_type; | |
| 1191 | expr->implicit_cast.op = CastOpIntWidenOrShorten; | |
| 1192 | expr->implicit_cast.source_node = node; | |
| 1193 | return expected_type; | |
| 1260 | return true; | |
| 1194 | 1261 | } |
| 1195 | 1262 | |
| 1196 | 1263 | // implicit constant sized array to unknown size array conversion |
| 1197 | 1264 | if (expected_type->id == TypeTableEntryIdStruct && |
| 1198 | 1265 | expected_type->data.structure.is_unknown_size_array && |
| 1199 | 1266 | actual_type->id == TypeTableEntryIdArray && |
| 1200 | actual_type->data.array.child_type == expected_type->data.structure.fields[0].type_entry->data.pointer.child_type) | |
| 1267 | types_match_const_cast_only( | |
| 1268 | expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, | |
| 1269 | actual_type->data.array.child_type)) | |
| 1201 | 1270 | { |
| 1202 | Expr *expr = get_resolved_expr(node); | |
| 1203 | expr->implicit_cast.after_type = expected_type; | |
| 1204 | expr->implicit_cast.op = CastOpToUnknownSizeArray; | |
| 1205 | expr->implicit_cast.source_node = node; | |
| 1206 | context->cast_expr_alloca_list.append(&expr->implicit_cast); | |
| 1207 | return expected_type; | |
| 1208 | } | |
| 1209 | ||
| 1210 | // implicit non-const to const for pointers | |
| 1211 | if (expected_type->id == TypeTableEntryIdPointer && | |
| 1212 | actual_type->id == TypeTableEntryIdPointer && | |
| 1213 | (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const)) | |
| 1214 | { | |
| 1215 | TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node, | |
| 1216 | expected_type->data.pointer.child_type, | |
| 1217 | actual_type->data.pointer.child_type); | |
| 1218 | if (resolved_type->id == TypeTableEntryIdInvalid) { | |
| 1219 | return resolved_type; | |
| 1220 | } | |
| 1221 | return expected_type; | |
| 1222 | } | |
| 1223 | ||
| 1224 | // implicit non-const to const for unknown size arrays | |
| 1225 | if (expected_type->id == TypeTableEntryIdStruct && | |
| 1226 | actual_type->id == TypeTableEntryIdStruct && | |
| 1227 | expected_type->data.structure.is_unknown_size_array && | |
| 1228 | actual_type->data.structure.is_unknown_size_array && | |
| 1229 | (!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const || | |
| 1230 | expected_type->data.structure.fields[0].type_entry->data.pointer.is_const)) | |
| 1231 | { | |
| 1232 | TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node, | |
| 1233 | expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, | |
| 1234 | actual_type->data.structure.fields[0].type_entry->data.pointer.child_type); | |
| 1235 | if (resolved_type->id == TypeTableEntryIdInvalid) { | |
| 1236 | return resolved_type; | |
| 1237 | } | |
| 1238 | return expected_type; | |
| 1271 | return true; | |
| 1239 | 1272 | } |
| 1240 | 1273 | |
| 1274 | // implicit number literal to typed number | |
| 1241 | 1275 | if ((actual_type->id == TypeTableEntryIdNumLitFloat || |
| 1242 | 1276 | actual_type->id == TypeTableEntryIdNumLitInt)) |
| 1243 | 1277 | { |
| 1244 | if (num_lit_fits_in_other_type(g, node, expected_type)) { | |
| 1245 | return expected_type; | |
| 1278 | if (num_lit_fits_in_other_type(g, literal_node, expected_type)) { | |
| 1279 | return true; | |
| 1246 | 1280 | } else { |
| 1247 | return g->builtin_types.entry_invalid; | |
| 1281 | *reported_err = true; | |
| 1248 | 1282 | } |
| 1249 | 1283 | } |
| 1250 | 1284 | |
| 1251 | add_node_error(g, first_executing_node(node), | |
| 1252 | buf_sprintf("expected type '%s', got '%s'", | |
| 1253 | buf_ptr(&expected_type->name), | |
| 1254 | buf_ptr(&actual_type->name))); | |
| 1285 | ||
| 1286 | return false; | |
| 1287 | } | |
| 1288 | ||
| 1289 | static AstNode *create_ast_node(CodeGen *g, ImportTableEntry *import, NodeType kind) { | |
| 1290 | AstNode *node = allocate<AstNode>(1); | |
| 1291 | node->type = kind; | |
| 1292 | node->owner = import; | |
| 1293 | node->create_index = g->next_node_index; | |
| 1294 | g->next_node_index += 1; | |
| 1295 | return node; | |
| 1296 | } | |
| 1297 | ||
| 1298 | static AstNode *create_ast_type_node(CodeGen *g, ImportTableEntry *import, TypeTableEntry *type_entry) { | |
| 1299 | AstNode *node = create_ast_node(g, import, NodeTypeSymbol); | |
| 1300 | node->data.symbol_expr.override_type_entry = type_entry; | |
| 1301 | return node; | |
| 1302 | } | |
| 1303 | ||
| 1304 | static TypeTableEntry *create_and_analyze_cast_node(CodeGen *g, ImportTableEntry *import, | |
| 1305 | BlockContext *context, TypeTableEntry *cast_to_type, AstNode *node) | |
| 1306 | { | |
| 1307 | AstNode *new_parent_node = create_ast_node(g, import, NodeTypeFnCallExpr); | |
| 1308 | *node->parent_field = new_parent_node; | |
| 1309 | new_parent_node->parent_field = node->parent_field; | |
| 1310 | ||
| 1311 | new_parent_node->data.fn_call_expr.fn_ref_expr = create_ast_type_node(g, import, cast_to_type); | |
| 1312 | new_parent_node->data.fn_call_expr.params.append(node); | |
| 1313 | normalize_parent_ptrs(new_parent_node); | |
| 1314 | ||
| 1315 | return analyze_expression(g, import, context, cast_to_type, new_parent_node); | |
| 1316 | } | |
| 1317 | ||
| 1318 | static TypeTableEntry *resolve_type_compatibility(CodeGen *g, ImportTableEntry *import, | |
| 1319 | BlockContext *context, AstNode *node, | |
| 1320 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) | |
| 1321 | { | |
| 1322 | if (expected_type == nullptr) | |
| 1323 | return actual_type; // anything will do | |
| 1324 | if (expected_type == actual_type) | |
| 1325 | return expected_type; // match | |
| 1326 | if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid) | |
| 1327 | return g->builtin_types.entry_invalid; | |
| 1328 | if (actual_type->id == TypeTableEntryIdUnreachable) | |
| 1329 | return actual_type; | |
| 1330 | ||
| 1331 | bool reported_err = false; | |
| 1332 | if (types_match_with_implicit_cast(g, expected_type, actual_type, node, &reported_err)) { | |
| 1333 | return create_and_analyze_cast_node(g, import, context, expected_type, node); | |
| 1334 | } | |
| 1335 | ||
| 1336 | if (!reported_err) { | |
| 1337 | add_node_error(g, first_executing_node(node), | |
| 1338 | buf_sprintf("expected type '%s', got '%s'", | |
| 1339 | buf_ptr(&expected_type->name), | |
| 1340 | buf_ptr(&actual_type->name))); | |
| 1341 | } | |
| 1255 | 1342 | |
| 1256 | 1343 | return g->builtin_types.entry_invalid; |
| 1257 | 1344 | } |
| 1258 | 1345 | |
| 1259 | static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext *block_context, | |
| 1260 | AstNode *parent_source_node, | |
| 1346 | static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import, | |
| 1347 | BlockContext *block_context, AstNode *parent_source_node, | |
| 1261 | 1348 | AstNode **child_nodes, TypeTableEntry **child_types, int child_count) |
| 1262 | 1349 | { |
| 1263 | 1350 | assert(child_count > 0); |
| ... | ... | @@ -1270,7 +1357,14 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext |
| 1270 | 1357 | } |
| 1271 | 1358 | |
| 1272 | 1359 | for (int i = 0; i < child_count; i += 1) { |
| 1273 | resolve_type_compatibility(g, block_context, child_nodes[i], expected_type, child_types[i]); | |
| 1360 | if (!child_nodes[i]) { | |
| 1361 | continue; | |
| 1362 | } | |
| 1363 | Expr *expr = get_resolved_expr(child_nodes[i]); | |
| 1364 | TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, block_context, | |
| 1365 | child_nodes[i], expected_type, child_types[i]); | |
| 1366 | expr->type_entry = resolved_type; | |
| 1367 | add_global_const_expr(g, expr); | |
| 1274 | 1368 | } |
| 1275 | 1369 | |
| 1276 | 1370 | return expected_type; |
| ... | ... | @@ -1667,13 +1761,7 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, |
| 1667 | 1761 | static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) { |
| 1668 | 1762 | Expr *expr = get_resolved_expr(node); |
| 1669 | 1763 | Expr *other_expr = get_resolved_expr(other); |
| 1670 | ConstExprValue *other_const_val; | |
| 1671 | if (other_expr->implicit_maybe_cast.after_type) { | |
| 1672 | other_const_val = &other_expr->implicit_maybe_cast.const_val; | |
| 1673 | } else { | |
| 1674 | other_const_val = &other_expr->const_val; | |
| 1675 | } | |
| 1676 | expr->const_val = *other_const_val; | |
| 1764 | expr->const_val = other_expr->const_val; | |
| 1677 | 1765 | return other_expr->type_entry; |
| 1678 | 1766 | } |
| 1679 | 1767 | |
| ... | ... | @@ -1758,6 +1846,10 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode * |
| 1758 | 1846 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1759 | 1847 | TypeTableEntry *expected_type, AstNode *node) |
| 1760 | 1848 | { |
| 1849 | if (node->data.symbol_expr.override_type_entry) { | |
| 1850 | return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry); | |
| 1851 | } | |
| 1852 | ||
| 1761 | 1853 | Buf *variable_name = &node->data.symbol_expr.symbol; |
| 1762 | 1854 | |
| 1763 | 1855 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); |
| ... | ... | @@ -1772,13 +1864,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1772 | 1864 | AstNode *decl_node = var->decl_node; |
| 1773 | 1865 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| 1774 | 1866 | AstNode *expr_node = decl_node->data.variable_declaration.expr; |
| 1775 | Expr *other_expr = get_resolved_expr(expr_node); | |
| 1776 | ConstExprValue *other_const_val; | |
| 1777 | if (other_expr->implicit_maybe_cast.after_type) { | |
| 1778 | other_const_val = &other_expr->implicit_maybe_cast.const_val; | |
| 1779 | } else { | |
| 1780 | other_const_val = &other_expr->const_val; | |
| 1781 | } | |
| 1867 | ConstExprValue *other_const_val = &get_resolved_expr(expr_node)->const_val; | |
| 1782 | 1868 | if (other_const_val->ok) { |
| 1783 | 1869 | return resolve_expr_const_val_as_other_expr(g, node, expr_node); |
| 1784 | 1870 | } |
| ... | ... | @@ -1955,7 +2041,7 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im |
| 1955 | 2041 | AstNode *op_nodes[] = {op1, op2}; |
| 1956 | 2042 | TypeTableEntry *op_types[] = {op1_type, op2_type}; |
| 1957 | 2043 | |
| 1958 | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node, | |
| 2044 | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node, | |
| 1959 | 2045 | op_nodes, op_types, 2); |
| 1960 | 2046 | |
| 1961 | 2047 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| ... | ... | @@ -2109,7 +2195,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2109 | 2195 | AstNode *op_nodes[] = {op1, op2}; |
| 2110 | 2196 | TypeTableEntry *op_types[] = {lhs_type, rhs_type}; |
| 2111 | 2197 | |
| 2112 | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node, | |
| 2198 | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node, | |
| 2113 | 2199 | op_nodes, op_types, 2); |
| 2114 | 2200 | |
| 2115 | 2201 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| ... | ... | @@ -2162,6 +2248,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2162 | 2248 | add_node_error(g, op1, |
| 2163 | 2249 | buf_sprintf("expected maybe type, got '%s'", |
| 2164 | 2250 | buf_ptr(&lhs_type->name))); |
| 2251 | return g->builtin_types.entry_invalid; | |
| 2165 | 2252 | } |
| 2166 | 2253 | } |
| 2167 | 2254 | case BinOpTypeInvalid: |
| ... | ... | @@ -2502,8 +2589,8 @@ static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import |
| 2502 | 2589 | if (else_node) { |
| 2503 | 2590 | else_type = analyze_expression(g, import, context, expected_type, else_node); |
| 2504 | 2591 | } else { |
| 2505 | else_type = g->builtin_types.entry_void; | |
| 2506 | else_type = resolve_type_compatibility(g, context, parent_node, expected_type, else_type); | |
| 2592 | else_type = resolve_type_compatibility(g, import, context, parent_node, expected_type, | |
| 2593 | g->builtin_types.entry_void); | |
| 2507 | 2594 | } |
| 2508 | 2595 | |
| 2509 | 2596 | |
| ... | ... | @@ -2512,7 +2599,7 @@ static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import |
| 2512 | 2599 | } else { |
| 2513 | 2600 | AstNode *op_nodes[] = {then_block, else_node}; |
| 2514 | 2601 | TypeTableEntry *op_types[] = {then_type, else_type}; |
| 2515 | return resolve_peer_type_compatibility(g, context, parent_node, op_nodes, op_types, 2); | |
| 2602 | return resolve_peer_type_compatibility(g, import, context, parent_node, op_nodes, op_types, 2); | |
| 2516 | 2603 | } |
| 2517 | 2604 | } |
| 2518 | 2605 | |
| ... | ... | @@ -2616,37 +2703,30 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 2616 | 2703 | } |
| 2617 | 2704 | } |
| 2618 | 2705 | |
| 2619 | static void eval_const_expr_implicit_cast(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 2620 | AstNode *node, Cast *cast, AstNode *expr_node) | |
| 2621 | { | |
| 2622 | switch (cast->op) { | |
| 2623 | case CastOpNothing: | |
| 2706 | static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *expr_node) { | |
| 2707 | assert(node->type == NodeTypeFnCallExpr); | |
| 2708 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; | |
| 2709 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | |
| 2710 | if (!other_val->ok) { | |
| 2711 | return; | |
| 2712 | } | |
| 2713 | assert(other_val != const_val); | |
| 2714 | switch (node->data.fn_call_expr.cast_op) { | |
| 2715 | case CastOpNoCast: | |
| 2716 | zig_unreachable(); | |
| 2717 | case CastOpNoop: | |
| 2624 | 2718 | case CastOpPtrToInt: |
| 2625 | 2719 | case CastOpIntWidenOrShorten: |
| 2626 | 2720 | case CastOpPointerReinterpret: |
| 2627 | { | |
| 2628 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; | |
| 2629 | ConstExprValue *const_val = &cast->const_val; | |
| 2630 | assert(const_val != other_val); | |
| 2631 | *const_val = *other_val; | |
| 2632 | break; | |
| 2633 | } | |
| 2721 | *const_val = *other_val; | |
| 2722 | break; | |
| 2634 | 2723 | case CastOpToUnknownSizeArray: |
| 2635 | // TODO eval const expr | |
| 2724 | zig_panic("TODO CastOpToUnknownSizeArray"); | |
| 2636 | 2725 | break; |
| 2637 | 2726 | case CastOpMaybeWrap: |
| 2638 | { | |
| 2639 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; | |
| 2640 | ConstExprValue *const_val = &cast->const_val; | |
| 2641 | if (!other_val->ok) { | |
| 2642 | break; | |
| 2643 | } | |
| 2644 | assert(const_val != other_val); | |
| 2645 | ||
| 2646 | const_val->data.x_maybe = other_val; | |
| 2647 | const_val->ok = true; | |
| 2648 | break; | |
| 2649 | } | |
| 2727 | const_val->data.x_maybe = other_val; | |
| 2728 | const_val->ok = true; | |
| 2729 | break; | |
| 2650 | 2730 | } |
| 2651 | 2731 | } |
| 2652 | 2732 | |
| ... | ... | @@ -2673,51 +2753,91 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2673 | 2753 | return g->builtin_types.entry_invalid; |
| 2674 | 2754 | } |
| 2675 | 2755 | |
| 2676 | Cast *cast = &node->data.fn_call_expr.cast; | |
| 2677 | cast->source_node = node; | |
| 2678 | cast->after_type = wanted_type; | |
| 2756 | // explicit match or non-const to const | |
| 2757 | if (types_match_const_cast_only(wanted_type, actual_type)) { | |
| 2758 | node->data.fn_call_expr.cast_op = CastOpNoop; | |
| 2759 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2760 | return wanted_type; | |
| 2761 | } | |
| 2679 | 2762 | |
| 2763 | // explicit cast from pointer to isize or usize | |
| 2680 | 2764 | if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && |
| 2681 | 2765 | actual_type->id == TypeTableEntryIdPointer) |
| 2682 | 2766 | { |
| 2683 | cast->op = CastOpPtrToInt; | |
| 2684 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); | |
| 2767 | node->data.fn_call_expr.cast_op = CastOpPtrToInt; | |
| 2768 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2685 | 2769 | return wanted_type; |
| 2686 | } else if (wanted_type->id == TypeTableEntryIdInt && | |
| 2687 | actual_type->id == TypeTableEntryIdInt) | |
| 2770 | } | |
| 2771 | ||
| 2772 | // explicit cast from any int to any other int | |
| 2773 | if (wanted_type->id == TypeTableEntryIdInt && | |
| 2774 | actual_type->id == TypeTableEntryIdInt) | |
| 2688 | 2775 | { |
| 2689 | cast->op = CastOpIntWidenOrShorten; | |
| 2690 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); | |
| 2776 | node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten; | |
| 2777 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2691 | 2778 | return wanted_type; |
| 2692 | } else if (wanted_type->id == TypeTableEntryIdStruct && | |
| 2693 | wanted_type->data.structure.is_unknown_size_array && | |
| 2694 | actual_type->id == TypeTableEntryIdArray && | |
| 2695 | actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) | |
| 2779 | } | |
| 2780 | ||
| 2781 | // explicit cast from fixed size array to unknown size array | |
| 2782 | if (wanted_type->id == TypeTableEntryIdStruct && | |
| 2783 | wanted_type->data.structure.is_unknown_size_array && | |
| 2784 | actual_type->id == TypeTableEntryIdArray && | |
| 2785 | types_match_const_cast_only( | |
| 2786 | wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type, | |
| 2787 | actual_type->data.array.child_type)) | |
| 2696 | 2788 | { |
| 2697 | cast->op = CastOpToUnknownSizeArray; | |
| 2698 | context->cast_expr_alloca_list.append(cast); | |
| 2699 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); | |
| 2789 | node->data.fn_call_expr.cast_op = CastOpToUnknownSizeArray; | |
| 2790 | context->cast_alloca_list.append(node); | |
| 2791 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2700 | 2792 | return wanted_type; |
| 2701 | } else if (actual_type->id == TypeTableEntryIdNumLitFloat || | |
| 2702 | actual_type->id == TypeTableEntryIdNumLitInt) | |
| 2793 | } | |
| 2794 | ||
| 2795 | // explicit cast from pointer to another pointer | |
| 2796 | if (actual_type->id == TypeTableEntryIdPointer && | |
| 2797 | wanted_type->id == TypeTableEntryIdPointer) | |
| 2703 | 2798 | { |
| 2704 | num_lit_fits_in_other_type(g, expr_node, wanted_type); | |
| 2705 | cast->op = CastOpNothing; | |
| 2706 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); | |
| 2799 | node->data.fn_call_expr.cast_op = CastOpPointerReinterpret; | |
| 2800 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2707 | 2801 | return wanted_type; |
| 2708 | } else if (actual_type->id == TypeTableEntryIdPointer && | |
| 2709 | wanted_type->id == TypeTableEntryIdPointer) | |
| 2802 | } | |
| 2803 | ||
| 2804 | // explicit cast from child type of maybe type to maybe type | |
| 2805 | if (wanted_type->id == TypeTableEntryIdMaybe) { | |
| 2806 | if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) { | |
| 2807 | node->data.fn_call_expr.cast_op = CastOpMaybeWrap; | |
| 2808 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2809 | return wanted_type; | |
| 2810 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || | |
| 2811 | actual_type->id == TypeTableEntryIdNumLitFloat) | |
| 2812 | { | |
| 2813 | if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.maybe.child_type)) { | |
| 2814 | node->data.fn_call_expr.cast_op = CastOpMaybeWrap; | |
| 2815 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2816 | return wanted_type; | |
| 2817 | } else { | |
| 2818 | return g->builtin_types.entry_invalid; | |
| 2819 | } | |
| 2820 | } | |
| 2821 | } | |
| 2822 | ||
| 2823 | // explicit cast from number literal to another type | |
| 2824 | if (actual_type->id == TypeTableEntryIdNumLitFloat || | |
| 2825 | actual_type->id == TypeTableEntryIdNumLitInt) | |
| 2710 | 2826 | { |
| 2711 | cast->op = CastOpPointerReinterpret; | |
| 2712 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); | |
| 2713 | return wanted_type; | |
| 2714 | } else { | |
| 2715 | add_node_error(g, node, | |
| 2716 | buf_sprintf("invalid cast from type '%s' to '%s'", | |
| 2717 | buf_ptr(&actual_type->name), | |
| 2718 | buf_ptr(&wanted_type->name))); | |
| 2719 | return g->builtin_types.entry_invalid; | |
| 2827 | if (num_lit_fits_in_other_type(g, expr_node, wanted_type)) { | |
| 2828 | node->data.fn_call_expr.cast_op = CastOpNoop; | |
| 2829 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 2830 | return wanted_type; | |
| 2831 | } else { | |
| 2832 | return g->builtin_types.entry_invalid; | |
| 2833 | } | |
| 2720 | 2834 | } |
| 2835 | ||
| 2836 | add_node_error(g, node, | |
| 2837 | buf_sprintf("invalid cast from type '%s' to '%s'", | |
| 2838 | buf_ptr(&actual_type->name), | |
| 2839 | buf_ptr(&wanted_type->name))); | |
| 2840 | return g->builtin_types.entry_invalid; | |
| 2721 | 2841 | } |
| 2722 | 2842 | |
| 2723 | 2843 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | ... | @@ -3281,39 +3401,14 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, |
| 3281 | 3401 | actual_return_type = g->builtin_types.entry_invalid; |
| 3282 | 3402 | } |
| 3283 | 3403 | |
| 3284 | resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type); | |
| 3404 | resolve_type_compatibility(g, import, context, node, expected_return_type, actual_return_type); | |
| 3285 | 3405 | |
| 3286 | 3406 | return g->builtin_types.entry_unreachable; |
| 3287 | 3407 | } |
| 3288 | 3408 | |
| 3289 | static bool type_has_codegen_value(TypeTableEntryId id) { | |
| 3290 | switch (id) { | |
| 3291 | case TypeTableEntryIdInvalid: | |
| 3292 | case TypeTableEntryIdMetaType: | |
| 3293 | case TypeTableEntryIdVoid: | |
| 3294 | case TypeTableEntryIdUnreachable: | |
| 3295 | return false; | |
| 3296 | ||
| 3297 | // TODO make num lits return false when we make implicit casts insert ast nodes | |
| 3298 | case TypeTableEntryIdNumLitFloat: | |
| 3299 | case TypeTableEntryIdNumLitInt: | |
| 3300 | ||
| 3301 | case TypeTableEntryIdBool: | |
| 3302 | case TypeTableEntryIdInt: | |
| 3303 | case TypeTableEntryIdFloat: | |
| 3304 | case TypeTableEntryIdPointer: | |
| 3305 | case TypeTableEntryIdArray: | |
| 3306 | case TypeTableEntryIdStruct: | |
| 3307 | case TypeTableEntryIdMaybe: | |
| 3308 | case TypeTableEntryIdError: | |
| 3309 | case TypeTableEntryIdEnum: | |
| 3310 | case TypeTableEntryIdFn: | |
| 3311 | return true; | |
| 3312 | } | |
| 3313 | zig_unreachable(); | |
| 3314 | } | |
| 3315 | ||
| 3316 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 3409 | // When you call analyze_expression, the node you pass might no longer be the child node | |
| 3410 | // you thought it was due to implicit casting rewriting the AST. | |
| 3411 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 3317 | 3412 | TypeTableEntry *expected_type, AstNode *node) |
| 3318 | 3413 | { |
| 3319 | 3414 | TypeTableEntry *return_type = nullptr; |
| ... | ... | @@ -3494,39 +3589,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3494 | 3589 | zig_unreachable(); |
| 3495 | 3590 | } |
| 3496 | 3591 | assert(return_type); |
| 3497 | resolve_type_compatibility(g, context, node, expected_type, return_type); | |
| 3592 | // resolve_type_compatibility might do implicit cast which means node is now a child | |
| 3593 | // of the actual node that we want to return the type of. | |
| 3594 | //AstNode **field = node->parent_field; | |
| 3595 | TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, context, node, | |
| 3596 | expected_type, return_type); | |
| 3498 | 3597 | |
| 3499 | 3598 | Expr *expr = get_resolved_expr(node); |
| 3500 | if (!expr->resolved_type) { | |
| 3501 | expr->resolved_type = return_type; | |
| 3502 | } | |
| 3503 | expr->type_entry = expr->resolved_type; | |
| 3599 | expr->type_entry = return_type; | |
| 3504 | 3600 | expr->block_context = context; |
| 3505 | 3601 | |
| 3506 | if (expr->const_val.ok && type_has_codegen_value(expr->resolved_type->id)) { | |
| 3507 | g->global_const_list.append(expr); | |
| 3508 | } | |
| 3602 | add_global_const_expr(g, expr); | |
| 3509 | 3603 | |
| 3510 | ||
| 3511 | if (expr->type_entry->id == TypeTableEntryIdUnreachable) { | |
| 3512 | return expr->type_entry; | |
| 3513 | } | |
| 3514 | ||
| 3515 | /* TODO delete this code when we make implicit casts insert ast nodes | |
| 3516 | Cast *cast_node = &expr->implicit_cast; | |
| 3517 | if (cast_node->after_type) { | |
| 3518 | eval_const_expr_implicit_cast(g, import, context, node, cast_node, node); | |
| 3519 | expr->type_entry = cast_node->after_type; | |
| 3520 | } | |
| 3521 | */ | |
| 3522 | ||
| 3523 | Cast *cast_node = &expr->implicit_maybe_cast; | |
| 3524 | if (cast_node->after_type) { | |
| 3525 | eval_const_expr_implicit_cast(g, import, context, node, cast_node, node); | |
| 3526 | expr->type_entry = cast_node->after_type; | |
| 3527 | } | |
| 3528 | ||
| 3529 | return expr->type_entry; | |
| 3604 | return resolved_type; | |
| 3530 | 3605 | } |
| 3531 | 3606 | |
| 3532 | 3607 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
src/codegen.cpp+78-124| ... | ... | @@ -71,8 +71,6 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 71 | 71 | static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, |
| 72 | 72 | LLVMValueRef target_ref, LLVMValueRef value, |
| 73 | 73 | TypeTableEntry *op1_type, TypeTableEntry *op2_type); |
| 74 | static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val, | |
| 75 | TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node); | |
| 76 | 74 | |
| 77 | 75 | static TypeTableEntry *get_type_for_type_node(AstNode *node) { |
| 78 | 76 | Expr *expr = get_resolved_expr(node); |
| ... | ... | @@ -111,17 +109,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { |
| 111 | 109 | } |
| 112 | 110 | |
| 113 | 111 | static TypeTableEntry *get_expr_type(AstNode *node) { |
| 114 | Expr *expr = get_resolved_expr(node); | |
| 115 | if (expr->implicit_maybe_cast.after_type) { | |
| 116 | return expr->implicit_maybe_cast.after_type; | |
| 117 | } | |
| 118 | if (expr->implicit_cast.after_type) { | |
| 119 | return expr->implicit_cast.after_type; | |
| 120 | } | |
| 121 | if (expr->resolved_type) { | |
| 122 | return expr->resolved_type; | |
| 123 | } | |
| 124 | return expr->type_entry; | |
| 112 | return get_resolved_expr(node)->type_entry; | |
| 125 | 113 | } |
| 126 | 114 | |
| 127 | 115 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { |
| ... | ... | @@ -305,18 +293,84 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 305 | 293 | TypeTableEntry *actual_type = get_expr_type(expr_node); |
| 306 | 294 | TypeTableEntry *wanted_type = get_expr_type(node); |
| 307 | 295 | |
| 308 | Cast *cast_node = &node->data.fn_call_expr.cast; | |
| 296 | AstNodeFnCallExpr *cast_expr = &node->data.fn_call_expr; | |
| 297 | ||
| 298 | switch (cast_expr->cast_op) { | |
| 299 | case CastOpNoCast: | |
| 300 | zig_unreachable(); | |
| 301 | case CastOpNoop: | |
| 302 | return expr_val; | |
| 303 | case CastOpMaybeWrap: | |
| 304 | { | |
| 305 | assert(cast_expr->tmp_ptr); | |
| 306 | assert(wanted_type->id == TypeTableEntryIdMaybe); | |
| 307 | assert(actual_type); | |
| 308 | ||
| 309 | add_debug_source_node(g, node); | |
| 310 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); | |
| 311 | gen_assign_raw(g, node, BinOpTypeAssign, | |
| 312 | val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type); | |
| 313 | ||
| 314 | add_debug_source_node(g, node); | |
| 315 | LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); | |
| 316 | LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); | |
| 317 | ||
| 318 | return cast_expr->tmp_ptr; | |
| 319 | } | |
| 320 | case CastOpPtrToInt: | |
| 321 | add_debug_source_node(g, node); | |
| 322 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 323 | case CastOpPointerReinterpret: | |
| 324 | add_debug_source_node(g, node); | |
| 325 | return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 326 | case CastOpIntWidenOrShorten: | |
| 327 | if (actual_type->size_in_bits == wanted_type->size_in_bits) { | |
| 328 | return expr_val; | |
| 329 | } else if (actual_type->size_in_bits < wanted_type->size_in_bits) { | |
| 330 | if (actual_type->data.integral.is_signed) { | |
| 331 | add_debug_source_node(g, node); | |
| 332 | return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 333 | } else { | |
| 334 | add_debug_source_node(g, node); | |
| 335 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 336 | } | |
| 337 | } else { | |
| 338 | assert(actual_type->size_in_bits > wanted_type->size_in_bits); | |
| 339 | add_debug_source_node(g, node); | |
| 340 | return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 341 | } | |
| 342 | case CastOpToUnknownSizeArray: | |
| 343 | { | |
| 344 | assert(cast_expr->tmp_ptr); | |
| 345 | assert(wanted_type->id == TypeTableEntryIdStruct); | |
| 346 | assert(wanted_type->data.structure.is_unknown_size_array); | |
| 347 | ||
| 348 | TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry; | |
| 349 | ||
| 350 | add_debug_source_node(g, node); | |
| 309 | 351 | |
| 310 | return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node); | |
| 352 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); | |
| 353 | LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); | |
| 354 | LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); | |
| 311 | 355 | |
| 356 | LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); | |
| 357 | LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, | |
| 358 | actual_type->data.array.len, false); | |
| 359 | LLVMBuildStore(g->builder, len_val, len_ptr); | |
| 360 | ||
| 361 | return cast_expr->tmp_ptr; | |
| 362 | } | |
| 363 | } | |
| 364 | zig_unreachable(); | |
| 312 | 365 | } |
| 313 | 366 | |
| 367 | ||
| 314 | 368 | static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 315 | 369 | assert(node->type == NodeTypeFnCallExpr); |
| 316 | 370 | |
| 317 | 371 | if (node->data.fn_call_expr.is_builtin) { |
| 318 | 372 | return gen_builtin_fn_call_expr(g, node); |
| 319 | } else if (node->data.fn_call_expr.cast.after_type) { | |
| 373 | } else if (node->data.fn_call_expr.cast_op != CastOpNoCast) { | |
| 320 | 374 | return gen_cast_expr(g, node); |
| 321 | 375 | } |
| 322 | 376 | |
| ... | ... | @@ -752,74 +806,6 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 752 | 806 | zig_unreachable(); |
| 753 | 807 | } |
| 754 | 808 | |
| 755 | static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val, | |
| 756 | TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node) | |
| 757 | { | |
| 758 | switch (cast_node->op) { | |
| 759 | case CastOpNothing: | |
| 760 | return expr_val; | |
| 761 | case CastOpMaybeWrap: | |
| 762 | { | |
| 763 | assert(cast_node->ptr); | |
| 764 | assert(wanted_type->id == TypeTableEntryIdMaybe); | |
| 765 | assert(actual_type); | |
| 766 | ||
| 767 | add_debug_source_node(g, node); | |
| 768 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, ""); | |
| 769 | gen_assign_raw(g, node, BinOpTypeAssign, | |
| 770 | val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type); | |
| 771 | ||
| 772 | add_debug_source_node(g, node); | |
| 773 | LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, ""); | |
| 774 | LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); | |
| 775 | ||
| 776 | return cast_node->ptr; | |
| 777 | } | |
| 778 | case CastOpPtrToInt: | |
| 779 | add_debug_source_node(g, node); | |
| 780 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 781 | case CastOpPointerReinterpret: | |
| 782 | add_debug_source_node(g, node); | |
| 783 | return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 784 | case CastOpIntWidenOrShorten: | |
| 785 | if (actual_type->size_in_bits == wanted_type->size_in_bits) { | |
| 786 | return expr_val; | |
| 787 | } else if (actual_type->size_in_bits < wanted_type->size_in_bits) { | |
| 788 | if (actual_type->data.integral.is_signed) { | |
| 789 | add_debug_source_node(g, node); | |
| 790 | return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 791 | } else { | |
| 792 | add_debug_source_node(g, node); | |
| 793 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 794 | } | |
| 795 | } else { | |
| 796 | assert(actual_type->size_in_bits > wanted_type->size_in_bits); | |
| 797 | add_debug_source_node(g, node); | |
| 798 | return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); | |
| 799 | } | |
| 800 | case CastOpToUnknownSizeArray: | |
| 801 | { | |
| 802 | assert(cast_node->ptr); | |
| 803 | ||
| 804 | TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry; | |
| 805 | ||
| 806 | add_debug_source_node(g, node); | |
| 807 | ||
| 808 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, ""); | |
| 809 | LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); | |
| 810 | LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); | |
| 811 | ||
| 812 | LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, ""); | |
| 813 | LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, | |
| 814 | actual_type->data.array.len, false); | |
| 815 | LLVMBuildStore(g->builder, len_val, len_ptr); | |
| 816 | ||
| 817 | return cast_node->ptr; | |
| 818 | } | |
| 819 | } | |
| 820 | zig_unreachable(); | |
| 821 | } | |
| 822 | ||
| 823 | 809 | static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, |
| 824 | 810 | LLVMValueRef val1, LLVMValueRef val2, |
| 825 | 811 | TypeTableEntry *op1_type, TypeTableEntry *op2_type, |
| ... | ... | @@ -1970,7 +1956,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { |
| 1970 | 1956 | return phi; |
| 1971 | 1957 | } |
| 1972 | 1958 | |
| 1973 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | |
| 1959 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | |
| 1974 | 1960 | Expr *expr = get_resolved_expr(node); |
| 1975 | 1961 | if (expr->const_val.ok) { |
| 1976 | 1962 | assert(expr->const_llvm_val); |
| ... | ... | @@ -2072,33 +2058,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 2072 | 2058 | zig_unreachable(); |
| 2073 | 2059 | } |
| 2074 | 2060 | |
| 2075 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | |
| 2076 | LLVMValueRef val = gen_expr_no_cast(g, node); | |
| 2077 | ||
| 2078 | if (is_node_void_expr(node)) { | |
| 2079 | return val; | |
| 2080 | } | |
| 2081 | ||
| 2082 | Expr *expr = get_resolved_expr(node); | |
| 2083 | ||
| 2084 | TypeTableEntry *before_type = expr->type_entry; | |
| 2085 | if (before_type && before_type->id == TypeTableEntryIdUnreachable) { | |
| 2086 | return val; | |
| 2087 | } | |
| 2088 | Cast *cast_node = &expr->implicit_cast; | |
| 2089 | if (cast_node->after_type) { | |
| 2090 | val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); | |
| 2091 | before_type = cast_node->after_type; | |
| 2092 | } | |
| 2093 | ||
| 2094 | cast_node = &expr->implicit_maybe_cast; | |
| 2095 | if (cast_node->after_type) { | |
| 2096 | val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); | |
| 2097 | } | |
| 2098 | ||
| 2099 | return val; | |
| 2100 | } | |
| 2101 | ||
| 2102 | 2061 | static void build_label_blocks(CodeGen *g, AstNode *block_node) { |
| 2103 | 2062 | assert(block_node->type == NodeTypeBlock); |
| 2104 | 2063 | for (int i = 0; i < block_node->data.block.statements.length; i += 1) { |
| ... | ... | @@ -2180,14 +2139,7 @@ static void gen_const_globals(CodeGen *g) { |
| 2180 | 2139 | Expr *expr = g->global_const_list.at(i); |
| 2181 | 2140 | ConstExprValue *const_val = &expr->const_val; |
| 2182 | 2141 | assert(const_val->ok); |
| 2183 | TypeTableEntry *type_entry = expr->resolved_type; | |
| 2184 | ||
| 2185 | // TODO delete this if when we make implicit casts insert ast nodes | |
| 2186 | if (type_entry->id == TypeTableEntryIdNumLitFloat || | |
| 2187 | type_entry->id == TypeTableEntryIdNumLitInt) | |
| 2188 | { | |
| 2189 | continue; | |
| 2190 | } | |
| 2142 | TypeTableEntry *type_entry = expr->type_entry; | |
| 2191 | 2143 | |
| 2192 | 2144 | if (handle_is_ptr(type_entry)) { |
| 2193 | 2145 | LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, ""); |
| ... | ... | @@ -2330,10 +2282,12 @@ static void do_code_gen(CodeGen *g) { |
| 2330 | 2282 | } |
| 2331 | 2283 | |
| 2332 | 2284 | // allocate structs which are the result of casts |
| 2333 | for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) { | |
| 2334 | Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i); | |
| 2335 | add_debug_source_node(g, cast_node->source_node); | |
| 2336 | cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, ""); | |
| 2285 | for (int cea_i = 0; cea_i < block_context->cast_alloca_list.length; cea_i += 1) { | |
| 2286 | AstNode *fn_call_node = block_context->cast_alloca_list.at(cea_i); | |
| 2287 | add_debug_source_node(g, fn_call_node); | |
| 2288 | Expr *expr = &fn_call_node->data.fn_call_expr.resolved_expr; | |
| 2289 | fn_call_node->data.fn_call_expr.tmp_ptr = LLVMBuildAlloca(g->builder, | |
| 2290 | expr->type_entry->type_ref, ""); | |
| 2337 | 2291 | } |
| 2338 | 2292 | |
| 2339 | 2293 | // allocate structs which are struct value expressions |
src/parser.cpp+240-2| ... | ... | @@ -173,6 +173,7 @@ void ast_print(AstNode *node, int indent) { |
| 173 | 173 | for (int i = 0; i < indent; i += 1) { |
| 174 | 174 | fprintf(stderr, " "); |
| 175 | 175 | } |
| 176 | assert(node->type == NodeTypeRoot || *node->parent_field == node); | |
| 176 | 177 | |
| 177 | 178 | switch (node->type) { |
| 178 | 179 | case NodeTypeRoot: |
| ... | ... | @@ -1008,6 +1009,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) { |
| 1008 | 1009 | *token_index += 1; |
| 1009 | 1010 | ast_expect_token(pc, r_paren, TokenIdRParen); |
| 1010 | 1011 | |
| 1012 | normalize_parent_ptrs(node); | |
| 1011 | 1013 | return node; |
| 1012 | 1014 | } |
| 1013 | 1015 | |
| ... | ... | @@ -1059,6 +1061,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) { |
| 1059 | 1061 | |
| 1060 | 1062 | node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true); |
| 1061 | 1063 | |
| 1064 | normalize_parent_ptrs(node); | |
| 1062 | 1065 | return node; |
| 1063 | 1066 | } |
| 1064 | 1067 | |
| ... | ... | @@ -1175,6 +1178,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo |
| 1175 | 1178 | |
| 1176 | 1179 | node->data.array_type.child_type = ast_parse_prefix_op_expr(pc, token_index, true); |
| 1177 | 1180 | |
| 1181 | normalize_parent_ptrs(node); | |
| 1178 | 1182 | return node; |
| 1179 | 1183 | } |
| 1180 | 1184 | |
| ... | ... | @@ -1358,6 +1362,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand |
| 1358 | 1362 | ast_expect_token(pc, rparen_tok, TokenIdRParen); |
| 1359 | 1363 | *token_index += 1; |
| 1360 | 1364 | |
| 1365 | normalize_parent_ptrs(node); | |
| 1361 | 1366 | return node; |
| 1362 | 1367 | } |
| 1363 | 1368 | |
| ... | ... | @@ -1416,6 +1421,8 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1416 | 1421 | ast_eat_token(pc, token_index, TokenIdLParen); |
| 1417 | 1422 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); |
| 1418 | 1423 | node->data.fn_call_expr.is_builtin = true; |
| 1424 | ||
| 1425 | normalize_parent_ptrs(node); | |
| 1419 | 1426 | return node; |
| 1420 | 1427 | } else if (token->id == TokenIdSymbol) { |
| 1421 | 1428 | *token_index += 1; |
| ... | ... | @@ -1499,6 +1506,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index, |
| 1499 | 1506 | ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name); |
| 1500 | 1507 | field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true); |
| 1501 | 1508 | |
| 1509 | normalize_parent_ptrs(field_node); | |
| 1502 | 1510 | node->data.container_init_expr.entries.append(field_node); |
| 1503 | 1511 | |
| 1504 | 1512 | Token *comma_tok = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1545,6 +1553,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index, |
| 1545 | 1553 | } |
| 1546 | 1554 | } |
| 1547 | 1555 | |
| 1556 | normalize_parent_ptrs(node); | |
| 1548 | 1557 | prefix_op_expr = node; |
| 1549 | 1558 | } else { |
| 1550 | 1559 | return prefix_op_expr; |
| ... | ... | @@ -1575,6 +1584,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1575 | 1584 | node->data.fn_call_expr.fn_ref_expr = primary_expr; |
| 1576 | 1585 | ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); |
| 1577 | 1586 | |
| 1587 | normalize_parent_ptrs(node); | |
| 1578 | 1588 | primary_expr = node; |
| 1579 | 1589 | } else if (first_token->id == TokenIdLBracket) { |
| 1580 | 1590 | *token_index += 1; |
| ... | ... | @@ -1599,6 +1609,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1599 | 1609 | node->data.slice_expr.is_const = true; |
| 1600 | 1610 | } |
| 1601 | 1611 | |
| 1612 | normalize_parent_ptrs(node); | |
| 1602 | 1613 | primary_expr = node; |
| 1603 | 1614 | } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { |
| 1604 | 1615 | *token_index += 1; |
| ... | ... | @@ -1607,6 +1618,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1607 | 1618 | node->data.array_access_expr.array_ref_expr = primary_expr; |
| 1608 | 1619 | node->data.array_access_expr.subscript = expr_node; |
| 1609 | 1620 | |
| 1621 | normalize_parent_ptrs(node); | |
| 1610 | 1622 | primary_expr = node; |
| 1611 | 1623 | } else { |
| 1612 | 1624 | ast_invalid_token_error(pc, first_token); |
| ... | ... | @@ -1620,6 +1632,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 1620 | 1632 | node->data.field_access_expr.struct_expr = primary_expr; |
| 1621 | 1633 | ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name); |
| 1622 | 1634 | |
| 1635 | normalize_parent_ptrs(node); | |
| 1623 | 1636 | primary_expr = node; |
| 1624 | 1637 | } else { |
| 1625 | 1638 | return primary_expr; |
| ... | ... | @@ -1677,6 +1690,8 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo |
| 1677 | 1690 | node->data.prefix_op_expr.primary_expr = prefix_op_expr; |
| 1678 | 1691 | node->data.prefix_op_expr.prefix_op = prefix_op; |
| 1679 | 1692 | |
| 1693 | normalize_parent_ptrs(node); | |
| 1694 | normalize_parent_ptrs(parent_node); | |
| 1680 | 1695 | return parent_node; |
| 1681 | 1696 | } |
| 1682 | 1697 | |
| ... | ... | @@ -1728,6 +1743,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man |
| 1728 | 1743 | node->data.bin_op_expr.bin_op = mult_op; |
| 1729 | 1744 | node->data.bin_op_expr.op2 = operand_2; |
| 1730 | 1745 | |
| 1746 | normalize_parent_ptrs(node); | |
| 1731 | 1747 | operand_1 = node; |
| 1732 | 1748 | } |
| 1733 | 1749 | } |
| ... | ... | @@ -1778,6 +1794,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand |
| 1778 | 1794 | node->data.bin_op_expr.bin_op = add_op; |
| 1779 | 1795 | node->data.bin_op_expr.op2 = operand_2; |
| 1780 | 1796 | |
| 1797 | normalize_parent_ptrs(node); | |
| 1781 | 1798 | operand_1 = node; |
| 1782 | 1799 | } |
| 1783 | 1800 | } |
| ... | ... | @@ -1828,6 +1845,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo |
| 1828 | 1845 | node->data.bin_op_expr.bin_op = bit_shift_op; |
| 1829 | 1846 | node->data.bin_op_expr.op2 = operand_2; |
| 1830 | 1847 | |
| 1848 | normalize_parent_ptrs(node); | |
| 1831 | 1849 | operand_1 = node; |
| 1832 | 1850 | } |
| 1833 | 1851 | } |
| ... | ... | @@ -1854,6 +1872,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool |
| 1854 | 1872 | node->data.bin_op_expr.bin_op = BinOpTypeBinAnd; |
| 1855 | 1873 | node->data.bin_op_expr.op2 = operand_2; |
| 1856 | 1874 | |
| 1875 | normalize_parent_ptrs(node); | |
| 1857 | 1876 | operand_1 = node; |
| 1858 | 1877 | } |
| 1859 | 1878 | } |
| ... | ... | @@ -1879,6 +1898,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool |
| 1879 | 1898 | node->data.bin_op_expr.bin_op = BinOpTypeBinXor; |
| 1880 | 1899 | node->data.bin_op_expr.op2 = operand_2; |
| 1881 | 1900 | |
| 1901 | normalize_parent_ptrs(node); | |
| 1882 | 1902 | operand_1 = node; |
| 1883 | 1903 | } |
| 1884 | 1904 | } |
| ... | ... | @@ -1904,6 +1924,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m |
| 1904 | 1924 | node->data.bin_op_expr.bin_op = BinOpTypeBinOr; |
| 1905 | 1925 | node->data.bin_op_expr.op2 = operand_2; |
| 1906 | 1926 | |
| 1927 | normalize_parent_ptrs(node); | |
| 1907 | 1928 | operand_1 = node; |
| 1908 | 1929 | } |
| 1909 | 1930 | } |
| ... | ... | @@ -1954,6 +1975,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo |
| 1954 | 1975 | node->data.bin_op_expr.bin_op = cmp_op; |
| 1955 | 1976 | node->data.bin_op_expr.op2 = operand_2; |
| 1956 | 1977 | |
| 1978 | normalize_parent_ptrs(node); | |
| 1957 | 1979 | return node; |
| 1958 | 1980 | } |
| 1959 | 1981 | |
| ... | ... | @@ -1978,6 +2000,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool |
| 1978 | 2000 | node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd; |
| 1979 | 2001 | node->data.bin_op_expr.op2 = operand_2; |
| 1980 | 2002 | |
| 2003 | normalize_parent_ptrs(node); | |
| 1981 | 2004 | operand_1 = node; |
| 1982 | 2005 | } |
| 1983 | 2006 | } |
| ... | ... | @@ -2043,6 +2066,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda |
| 2043 | 2066 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2044 | 2067 | node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true); |
| 2045 | 2068 | node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false); |
| 2069 | ||
| 2070 | normalize_parent_ptrs(node); | |
| 2046 | 2071 | return node; |
| 2047 | 2072 | } else { |
| 2048 | 2073 | AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok); |
| ... | ... | @@ -2050,6 +2075,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda |
| 2050 | 2075 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2051 | 2076 | node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true); |
| 2052 | 2077 | node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false); |
| 2078 | ||
| 2079 | normalize_parent_ptrs(node); | |
| 2053 | 2080 | return node; |
| 2054 | 2081 | } |
| 2055 | 2082 | } |
| ... | ... | @@ -2094,6 +2121,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 2094 | 2121 | AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token); |
| 2095 | 2122 | node->data.return_expr.kind = kind; |
| 2096 | 2123 | node->data.return_expr.expr = ast_parse_expression(pc, token_index, false); |
| 2124 | ||
| 2125 | normalize_parent_ptrs(node); | |
| 2097 | 2126 | return node; |
| 2098 | 2127 | } |
| 2099 | 2128 | |
| ... | ... | @@ -2156,6 +2185,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token |
| 2156 | 2185 | *token_index += 1; |
| 2157 | 2186 | if (eq_or_colon->id == TokenIdEq) { |
| 2158 | 2187 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); |
| 2188 | ||
| 2189 | normalize_parent_ptrs(node); | |
| 2159 | 2190 | return node; |
| 2160 | 2191 | } else if (eq_or_colon->id == TokenIdColon) { |
| 2161 | 2192 | node->data.variable_declaration.type = ast_parse_prefix_op_expr(pc, token_index, true); |
| ... | ... | @@ -2165,6 +2196,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token |
| 2165 | 2196 | |
| 2166 | 2197 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); |
| 2167 | 2198 | } |
| 2199 | ||
| 2200 | normalize_parent_ptrs(node); | |
| 2168 | 2201 | return node; |
| 2169 | 2202 | } else { |
| 2170 | 2203 | ast_invalid_token_error(pc, eq_or_colon); |
| ... | ... | @@ -2192,6 +2225,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool |
| 2192 | 2225 | node->data.bin_op_expr.bin_op = BinOpTypeBoolOr; |
| 2193 | 2226 | node->data.bin_op_expr.op2 = operand_2; |
| 2194 | 2227 | |
| 2228 | normalize_parent_ptrs(node); | |
| 2195 | 2229 | operand_1 = node; |
| 2196 | 2230 | } |
| 2197 | 2231 | } |
| ... | ... | @@ -2220,7 +2254,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma |
| 2220 | 2254 | node->data.while_expr.body = ast_parse_expression(pc, token_index, true); |
| 2221 | 2255 | |
| 2222 | 2256 | |
| 2223 | ||
| 2257 | normalize_parent_ptrs(node); | |
| 2224 | 2258 | return node; |
| 2225 | 2259 | } |
| 2226 | 2260 | |
| ... | ... | @@ -2262,6 +2296,8 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand |
| 2262 | 2296 | ast_eat_token(pc, token_index, TokenIdRParen); |
| 2263 | 2297 | |
| 2264 | 2298 | node->data.for_expr.body = ast_parse_expression(pc, token_index, true); |
| 2299 | ||
| 2300 | normalize_parent_ptrs(node); | |
| 2265 | 2301 | return node; |
| 2266 | 2302 | } |
| 2267 | 2303 | |
| ... | ... | @@ -2294,6 +2330,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m |
| 2294 | 2330 | |
| 2295 | 2331 | if (token->id == TokenIdRBrace) { |
| 2296 | 2332 | *token_index += 1; |
| 2333 | ||
| 2334 | normalize_parent_ptrs(node); | |
| 2297 | 2335 | return node; |
| 2298 | 2336 | } |
| 2299 | 2337 | |
| ... | ... | @@ -2313,6 +2351,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m |
| 2313 | 2351 | |
| 2314 | 2352 | range_node->data.switch_range.start = expr1; |
| 2315 | 2353 | range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true); |
| 2354 | ||
| 2355 | normalize_parent_ptrs(range_node); | |
| 2316 | 2356 | } else { |
| 2317 | 2357 | prong_node->data.switch_prong.items.append(expr1); |
| 2318 | 2358 | } |
| ... | ... | @@ -2335,6 +2375,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m |
| 2335 | 2375 | ast_eat_token(pc, token_index, TokenIdFatArrow); |
| 2336 | 2376 | prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true); |
| 2337 | 2377 | ast_eat_token(pc, token_index, TokenIdComma); |
| 2378 | ||
| 2379 | normalize_parent_ptrs(prong_node); | |
| 2338 | 2380 | } |
| 2339 | 2381 | } |
| 2340 | 2382 | |
| ... | ... | @@ -2430,6 +2472,7 @@ static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, |
| 2430 | 2472 | node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe; |
| 2431 | 2473 | node->data.bin_op_expr.op2 = rhs; |
| 2432 | 2474 | |
| 2475 | normalize_parent_ptrs(node); | |
| 2433 | 2476 | return node; |
| 2434 | 2477 | } |
| 2435 | 2478 | |
| ... | ... | @@ -2453,6 +2496,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand |
| 2453 | 2496 | node->data.bin_op_expr.bin_op = ass_op; |
| 2454 | 2497 | node->data.bin_op_expr.op2 = rhs; |
| 2455 | 2498 | |
| 2499 | normalize_parent_ptrs(node); | |
| 2456 | 2500 | return node; |
| 2457 | 2501 | } |
| 2458 | 2502 | |
| ... | ... | @@ -2530,6 +2574,7 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) { |
| 2530 | 2574 | node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token); |
| 2531 | 2575 | node->data.container_init_expr.kind = ContainerInitKindArray; |
| 2532 | 2576 | buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void"); |
| 2577 | normalize_parent_ptrs(node); | |
| 2533 | 2578 | return node; |
| 2534 | 2579 | } |
| 2535 | 2580 | |
| ... | ... | @@ -2581,6 +2626,8 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato |
| 2581 | 2626 | last_token = &pc->tokens->at(*token_index); |
| 2582 | 2627 | if (last_token->id == TokenIdRBrace) { |
| 2583 | 2628 | *token_index += 1; |
| 2629 | ||
| 2630 | normalize_parent_ptrs(node); | |
| 2584 | 2631 | return node; |
| 2585 | 2632 | } else if (!semicolon_expected) { |
| 2586 | 2633 | continue; |
| ... | ... | @@ -2651,6 +2698,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 2651 | 2698 | node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token); |
| 2652 | 2699 | } |
| 2653 | 2700 | |
| 2701 | normalize_parent_ptrs(node); | |
| 2654 | 2702 | return node; |
| 2655 | 2703 | } |
| 2656 | 2704 | |
| ... | ... | @@ -2667,6 +2715,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat |
| 2667 | 2715 | ast_eat_token(pc, token_index, TokenIdFatArrow); |
| 2668 | 2716 | node->data.fn_def.body = ast_parse_block(pc, token_index, true); |
| 2669 | 2717 | |
| 2718 | normalize_parent_ptrs(node); | |
| 2670 | 2719 | return node; |
| 2671 | 2720 | } |
| 2672 | 2721 | |
| ... | ... | @@ -2683,6 +2732,7 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int *token_index) { |
| 2683 | 2732 | *token_index += 1; |
| 2684 | 2733 | ast_expect_token(pc, semicolon, TokenIdSemicolon); |
| 2685 | 2734 | |
| 2735 | normalize_parent_ptrs(node); | |
| 2686 | 2736 | return node; |
| 2687 | 2737 | } |
| 2688 | 2738 | |
| ... | ... | @@ -2725,6 +2775,8 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool |
| 2725 | 2775 | pc->directive_list = nullptr; |
| 2726 | 2776 | |
| 2727 | 2777 | *token_index += 1; |
| 2778 | ||
| 2779 | normalize_parent_ptrs(node); | |
| 2728 | 2780 | return node; |
| 2729 | 2781 | } else { |
| 2730 | 2782 | AstNode *child = ast_parse_fn_decl(pc, token_index); |
| ... | ... | @@ -2768,6 +2820,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b |
| 2768 | 2820 | *token_index += 1; |
| 2769 | 2821 | ast_expect_token(pc, semicolon, TokenIdSemicolon); |
| 2770 | 2822 | |
| 2823 | normalize_parent_ptrs(node); | |
| 2771 | 2824 | return node; |
| 2772 | 2825 | } |
| 2773 | 2826 | |
| ... | ... | @@ -2795,6 +2848,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { |
| 2795 | 2848 | node->data.use.directives = pc->directive_list; |
| 2796 | 2849 | pc->directive_list = nullptr; |
| 2797 | 2850 | |
| 2851 | normalize_parent_ptrs(node); | |
| 2798 | 2852 | return node; |
| 2799 | 2853 | } |
| 2800 | 2854 | |
| ... | ... | @@ -2895,12 +2949,13 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { |
| 2895 | 2949 | } |
| 2896 | 2950 | |
| 2897 | 2951 | node->data.struct_decl.fields.append(field_node); |
| 2952 | normalize_parent_ptrs(field_node); | |
| 2898 | 2953 | } else { |
| 2899 | 2954 | ast_invalid_token_error(pc, token); |
| 2900 | 2955 | } |
| 2901 | 2956 | } |
| 2902 | 2957 | |
| 2903 | ||
| 2958 | normalize_parent_ptrs(node); | |
| 2904 | 2959 | return node; |
| 2905 | 2960 | } |
| 2906 | 2961 | |
| ... | ... | @@ -2948,6 +3003,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b |
| 2948 | 3003 | node->data.error_value_decl.visib_mod = visib_mod; |
| 2949 | 3004 | ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name); |
| 2950 | 3005 | |
| 3006 | normalize_parent_ptrs(node); | |
| 2951 | 3007 | return node; |
| 2952 | 3008 | } |
| 2953 | 3009 | |
| ... | ... | @@ -3026,6 +3082,7 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) { |
| 3026 | 3082 | ast_invalid_token_error(pc, &pc->tokens->at(*token_index)); |
| 3027 | 3083 | } |
| 3028 | 3084 | |
| 3085 | normalize_parent_ptrs(node); | |
| 3029 | 3086 | return node; |
| 3030 | 3087 | } |
| 3031 | 3088 | |
| ... | ... | @@ -3042,3 +3099,184 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, |
| 3042 | 3099 | pc.root = ast_parse_root(&pc, &token_index); |
| 3043 | 3100 | return pc.root; |
| 3044 | 3101 | } |
| 3102 | ||
| 3103 | static void set_field(AstNode **field) { | |
| 3104 | if (*field) { | |
| 3105 | (*field)->parent_field = field; | |
| 3106 | } | |
| 3107 | } | |
| 3108 | ||
| 3109 | static void set_list_fields(ZigList<AstNode*> *list) { | |
| 3110 | for (int i = 0; i < list->length; i += 1) { | |
| 3111 | set_field(&list->at(i)); | |
| 3112 | } | |
| 3113 | } | |
| 3114 | ||
| 3115 | void normalize_parent_ptrs(AstNode *node) { | |
| 3116 | switch (node->type) { | |
| 3117 | case NodeTypeRoot: | |
| 3118 | set_list_fields(&node->data.root.top_level_decls); | |
| 3119 | break; | |
| 3120 | case NodeTypeRootExportDecl: | |
| 3121 | set_list_fields(node->data.root_export_decl.directives); | |
| 3122 | break; | |
| 3123 | case NodeTypeFnProto: | |
| 3124 | set_field(&node->data.fn_proto.return_type); | |
| 3125 | set_list_fields(node->data.fn_proto.directives); | |
| 3126 | set_list_fields(&node->data.fn_proto.params); | |
| 3127 | break; | |
| 3128 | case NodeTypeFnDef: | |
| 3129 | set_field(&node->data.fn_def.fn_proto); | |
| 3130 | set_field(&node->data.fn_def.body); | |
| 3131 | break; | |
| 3132 | case NodeTypeFnDecl: | |
| 3133 | set_field(&node->data.fn_decl.fn_proto); | |
| 3134 | break; | |
| 3135 | case NodeTypeParamDecl: | |
| 3136 | set_field(&node->data.param_decl.type); | |
| 3137 | break; | |
| 3138 | case NodeTypeBlock: | |
| 3139 | set_list_fields(&node->data.block.statements); | |
| 3140 | break; | |
| 3141 | case NodeTypeExternBlock: | |
| 3142 | set_list_fields(node->data.extern_block.directives); | |
| 3143 | set_list_fields(&node->data.extern_block.fn_decls); | |
| 3144 | break; | |
| 3145 | case NodeTypeDirective: | |
| 3146 | // none | |
| 3147 | break; | |
| 3148 | case NodeTypeReturnExpr: | |
| 3149 | set_field(&node->data.return_expr.expr); | |
| 3150 | break; | |
| 3151 | case NodeTypeVariableDeclaration: | |
| 3152 | set_field(&node->data.variable_declaration.type); | |
| 3153 | set_field(&node->data.variable_declaration.expr); | |
| 3154 | break; | |
| 3155 | case NodeTypeErrorValueDecl: | |
| 3156 | // none | |
| 3157 | break; | |
| 3158 | case NodeTypeBinOpExpr: | |
| 3159 | set_field(&node->data.bin_op_expr.op1); | |
| 3160 | set_field(&node->data.bin_op_expr.op2); | |
| 3161 | break; | |
| 3162 | case NodeTypeNumberLiteral: | |
| 3163 | // none | |
| 3164 | break; | |
| 3165 | case NodeTypeStringLiteral: | |
| 3166 | // none | |
| 3167 | break; | |
| 3168 | case NodeTypeCharLiteral: | |
| 3169 | // none | |
| 3170 | break; | |
| 3171 | case NodeTypeErrorLiteral: | |
| 3172 | // none | |
| 3173 | break; | |
| 3174 | case NodeTypeSymbol: | |
| 3175 | // none | |
| 3176 | break; | |
| 3177 | case NodeTypePrefixOpExpr: | |
| 3178 | set_field(&node->data.prefix_op_expr.primary_expr); | |
| 3179 | break; | |
| 3180 | case NodeTypeFnCallExpr: | |
| 3181 | set_field(&node->data.fn_call_expr.fn_ref_expr); | |
| 3182 | set_list_fields(&node->data.fn_call_expr.params); | |
| 3183 | break; | |
| 3184 | case NodeTypeArrayAccessExpr: | |
| 3185 | set_field(&node->data.array_access_expr.array_ref_expr); | |
| 3186 | set_field(&node->data.array_access_expr.subscript); | |
| 3187 | break; | |
| 3188 | case NodeTypeSliceExpr: | |
| 3189 | set_field(&node->data.slice_expr.array_ref_expr); | |
| 3190 | set_field(&node->data.slice_expr.start); | |
| 3191 | set_field(&node->data.slice_expr.end); | |
| 3192 | break; | |
| 3193 | case NodeTypeFieldAccessExpr: | |
| 3194 | set_field(&node->data.field_access_expr.struct_expr); | |
| 3195 | break; | |
| 3196 | case NodeTypeUse: | |
| 3197 | set_list_fields(node->data.use.directives); | |
| 3198 | break; | |
| 3199 | case NodeTypeBoolLiteral: | |
| 3200 | // none | |
| 3201 | break; | |
| 3202 | case NodeTypeNullLiteral: | |
| 3203 | // none | |
| 3204 | break; | |
| 3205 | case NodeTypeIfBoolExpr: | |
| 3206 | set_field(&node->data.if_bool_expr.condition); | |
| 3207 | set_field(&node->data.if_bool_expr.then_block); | |
| 3208 | set_field(&node->data.if_bool_expr.else_node); | |
| 3209 | break; | |
| 3210 | case NodeTypeIfVarExpr: | |
| 3211 | set_field(&node->data.if_var_expr.var_decl.type); | |
| 3212 | set_field(&node->data.if_var_expr.var_decl.expr); | |
| 3213 | set_field(&node->data.if_var_expr.then_block); | |
| 3214 | set_field(&node->data.if_var_expr.else_node); | |
| 3215 | break; | |
| 3216 | case NodeTypeWhileExpr: | |
| 3217 | set_field(&node->data.while_expr.condition); | |
| 3218 | set_field(&node->data.while_expr.body); | |
| 3219 | break; | |
| 3220 | case NodeTypeForExpr: | |
| 3221 | set_field(&node->data.for_expr.elem_node); | |
| 3222 | set_field(&node->data.for_expr.array_expr); | |
| 3223 | set_field(&node->data.for_expr.index_node); | |
| 3224 | set_field(&node->data.for_expr.body); | |
| 3225 | break; | |
| 3226 | case NodeTypeSwitchExpr: | |
| 3227 | set_field(&node->data.switch_expr.expr); | |
| 3228 | set_list_fields(&node->data.switch_expr.prongs); | |
| 3229 | break; | |
| 3230 | case NodeTypeSwitchProng: | |
| 3231 | set_list_fields(&node->data.switch_prong.items); | |
| 3232 | set_field(&node->data.switch_prong.var_symbol); | |
| 3233 | set_field(&node->data.switch_prong.expr); | |
| 3234 | break; | |
| 3235 | case NodeTypeSwitchRange: | |
| 3236 | set_field(&node->data.switch_range.start); | |
| 3237 | set_field(&node->data.switch_range.end); | |
| 3238 | break; | |
| 3239 | case NodeTypeLabel: | |
| 3240 | // none | |
| 3241 | break; | |
| 3242 | case NodeTypeGoto: | |
| 3243 | // none | |
| 3244 | break; | |
| 3245 | case NodeTypeBreak: | |
| 3246 | // none | |
| 3247 | break; | |
| 3248 | case NodeTypeContinue: | |
| 3249 | // none | |
| 3250 | break; | |
| 3251 | case NodeTypeAsmExpr: | |
| 3252 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { | |
| 3253 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); | |
| 3254 | set_field(&asm_input->expr); | |
| 3255 | } | |
| 3256 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { | |
| 3257 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); | |
| 3258 | set_field(&asm_output->return_type); | |
| 3259 | } | |
| 3260 | break; | |
| 3261 | case NodeTypeStructDecl: | |
| 3262 | set_list_fields(&node->data.struct_decl.fields); | |
| 3263 | set_list_fields(&node->data.struct_decl.fns); | |
| 3264 | set_list_fields(node->data.struct_decl.directives); | |
| 3265 | break; | |
| 3266 | case NodeTypeStructField: | |
| 3267 | set_field(&node->data.struct_field.type); | |
| 3268 | set_list_fields(node->data.struct_field.directives); | |
| 3269 | break; | |
| 3270 | case NodeTypeContainerInitExpr: | |
| 3271 | set_field(&node->data.container_init_expr.type); | |
| 3272 | set_list_fields(&node->data.container_init_expr.entries); | |
| 3273 | break; | |
| 3274 | case NodeTypeStructValueField: | |
| 3275 | set_field(&node->data.struct_val_field.expr); | |
| 3276 | break; | |
| 3277 | case NodeTypeArrayType: | |
| 3278 | set_field(&node->data.array_type.size); | |
| 3279 | set_field(&node->data.array_type.child_type); | |
| 3280 | break; | |
| 3281 | } | |
| 3282 | } |
src/parser.hpp+2| ... | ... | @@ -24,4 +24,6 @@ const char *node_type_str(NodeType node_type); |
| 24 | 24 | |
| 25 | 25 | void ast_print(AstNode *node, int indent); |
| 26 | 26 | |
| 27 | void normalize_parent_ptrs(AstNode *node); | |
| 28 | ||
| 27 | 29 | #endif |
test/run_tests.cpp+1-1| ... | ... | @@ -1317,7 +1317,7 @@ fn f() i32 => { |
| 1317 | 1317 | const a = c"a"; |
| 1318 | 1318 | a |
| 1319 | 1319 | } |
| 1320 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'"); | |
| 1320 | )SOURCE", 1, ".tmp_source.zig:4:5: error: expected type 'i32', got '&const u8'"); | |
| 1321 | 1321 | |
| 1322 | 1322 | add_compile_fail_case("if condition is bool, not int", R"SOURCE( |
| 1323 | 1323 | fn f() => { |