| ... | ... | @@ -12,6 +12,8 @@ |
| 12 | 12 | |
| 13 | 13 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 14 | 14 | TypeTableEntry *expected_type, AstNode *node); |
| 15 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 16 | AstNode *node, AstNodeNumberLiteral *out_number_literal); |
| 15 | 17 | |
| 16 | 18 | static AstNode *first_executing_node(AstNode *node) { |
| 17 | 19 | switch (node->type) { |
| ... | ... | @@ -284,6 +286,98 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry |
| 284 | 286 | } |
| 285 | 287 | } |
| 286 | 288 | |
| 289 | static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 290 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 291 | { |
| 292 | AstNodeNumberLiteral op1_lit; |
| 293 | AstNodeNumberLiteral op2_lit; |
| 294 | TypeTableEntry *op1_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op1_lit); |
| 295 | TypeTableEntry *op2_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op2_lit); |
| 296 | |
| 297 | if (op1_type->id == TypeTableEntryIdInvalid || |
| 298 | op2_type->id == TypeTableEntryIdInvalid) |
| 299 | { |
| 300 | return g->builtin_types.entry_invalid; |
| 301 | } |
| 302 | |
| 303 | // TODO complete more of this function instead of returning invalid |
| 304 | // returning invalid makes the "unable to evaluate constant expression" error |
| 305 | |
| 306 | switch (node->data.bin_op_expr.bin_op) { |
| 307 | case BinOpTypeCmpNotEq: |
| 308 | { |
| 309 | if (is_num_lit_unsigned(op1_lit.kind) && |
| 310 | is_num_lit_unsigned(op2_lit.kind)) |
| 311 | { |
| 312 | out_number_literal->kind = NumLitU8; |
| 313 | out_number_literal->overflow = false; |
| 314 | out_number_literal->data.x_uint = (op1_lit.data.x_uint != op2_lit.data.x_uint); |
| 315 | return node->codegen_node->expr_node.type_entry; |
| 316 | } else { |
| 317 | return g->builtin_types.entry_invalid; |
| 318 | } |
| 319 | } |
| 320 | case BinOpTypeCmpLessThan: |
| 321 | { |
| 322 | if (is_num_lit_unsigned(op1_lit.kind) && |
| 323 | is_num_lit_unsigned(op2_lit.kind)) |
| 324 | { |
| 325 | out_number_literal->kind = NumLitU8; |
| 326 | out_number_literal->overflow = false; |
| 327 | out_number_literal->data.x_uint = (op1_lit.data.x_uint < op2_lit.data.x_uint); |
| 328 | return node->codegen_node->expr_node.type_entry; |
| 329 | } else { |
| 330 | return g->builtin_types.entry_invalid; |
| 331 | } |
| 332 | } |
| 333 | case BinOpTypeMod: |
| 334 | { |
| 335 | if (is_num_lit_unsigned(op1_lit.kind) && |
| 336 | is_num_lit_unsigned(op2_lit.kind)) |
| 337 | { |
| 338 | out_number_literal->kind = NumLitU64; |
| 339 | out_number_literal->overflow = false; |
| 340 | out_number_literal->data.x_uint = (op1_lit.data.x_uint % op2_lit.data.x_uint); |
| 341 | return node->codegen_node->expr_node.type_entry; |
| 342 | } else { |
| 343 | return g->builtin_types.entry_invalid; |
| 344 | } |
| 345 | } |
| 346 | case BinOpTypeBoolOr: |
| 347 | case BinOpTypeBoolAnd: |
| 348 | case BinOpTypeCmpEq: |
| 349 | case BinOpTypeCmpGreaterThan: |
| 350 | case BinOpTypeCmpLessOrEq: |
| 351 | case BinOpTypeCmpGreaterOrEq: |
| 352 | case BinOpTypeBinOr: |
| 353 | case BinOpTypeBinXor: |
| 354 | case BinOpTypeBinAnd: |
| 355 | case BinOpTypeBitShiftLeft: |
| 356 | case BinOpTypeBitShiftRight: |
| 357 | case BinOpTypeAdd: |
| 358 | case BinOpTypeSub: |
| 359 | case BinOpTypeMult: |
| 360 | case BinOpTypeDiv: |
| 361 | return g->builtin_types.entry_invalid; |
| 362 | case BinOpTypeInvalid: |
| 363 | case BinOpTypeAssign: |
| 364 | case BinOpTypeAssignTimes: |
| 365 | case BinOpTypeAssignDiv: |
| 366 | case BinOpTypeAssignMod: |
| 367 | case BinOpTypeAssignPlus: |
| 368 | case BinOpTypeAssignMinus: |
| 369 | case BinOpTypeAssignBitShiftLeft: |
| 370 | case BinOpTypeAssignBitShiftRight: |
| 371 | case BinOpTypeAssignBitAnd: |
| 372 | case BinOpTypeAssignBitXor: |
| 373 | case BinOpTypeAssignBitOr: |
| 374 | case BinOpTypeAssignBoolAnd: |
| 375 | case BinOpTypeAssignBoolOr: |
| 376 | zig_unreachable(); |
| 377 | } |
| 378 | zig_unreachable(); |
| 379 | } |
| 380 | |
| 287 | 381 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 288 | 382 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 289 | 383 | { |
| ... | ... | @@ -291,9 +385,11 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 291 | 385 | case NodeTypeNumberLiteral: |
| 292 | 386 | *out_number_literal = node->data.number_literal; |
| 293 | 387 | return node->codegen_node->expr_node.type_entry; |
| 388 | case NodeTypeBoolLiteral: |
| 389 | out_number_literal->data.x_uint = node->data.bool_literal ? 1 : 0; |
| 390 | return node->codegen_node->expr_node.type_entry; |
| 294 | 391 | case NodeTypeBinOpExpr: |
| 295 | | zig_panic("TODO eval_const_expr bin op expr"); |
| 296 | | break; |
| 392 | return eval_const_expr_bin_op(g, context, node, out_number_literal); |
| 297 | 393 | case NodeTypeCompilerFnType: |
| 298 | 394 | { |
| 299 | 395 | Buf *name = &node->data.compiler_fn_type.name; |
| ... | ... | @@ -1133,8 +1229,12 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 1133 | 1229 | context->variable_table.init(8); |
| 1134 | 1230 | |
| 1135 | 1231 | if (parent) { |
| 1136 | | context->break_allowed = parent->break_allowed || parent->next_child_break_allowed; |
| 1137 | | parent->next_child_break_allowed = false; |
| 1232 | if (parent->next_child_parent_loop_node) { |
| 1233 | context->parent_loop_node = parent->next_child_parent_loop_node; |
| 1234 | parent->next_child_parent_loop_node = nullptr; |
| 1235 | } else { |
| 1236 | context->parent_loop_node = parent->parent_loop_node; |
| 1237 | } |
| 1138 | 1238 | } |
| 1139 | 1239 | |
| 1140 | 1240 | if (node && node->type == NodeTypeFnDef) { |
| ... | ... | @@ -1690,20 +1790,45 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1690 | 1790 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1691 | 1791 | TypeTableEntry *expected_type, AstNode *node) |
| 1692 | 1792 | { |
| 1693 | | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition); |
| 1793 | AstNode *condition_node = node->data.while_expr.condition; |
| 1794 | AstNode *while_body_node = node->data.while_expr.body; |
| 1795 | TypeTableEntry *condition_type = analyze_expression(g, import, context, |
| 1796 | g->builtin_types.entry_bool, condition_node); |
| 1797 | |
| 1798 | context->next_child_parent_loop_node = node; |
| 1799 | analyze_expression(g, import, context, g->builtin_types.entry_void, while_body_node); |
| 1800 | |
| 1801 | |
| 1802 | TypeTableEntry *expr_return_type = g->builtin_types.entry_void; |
| 1694 | 1803 | |
| 1695 | | context->next_child_break_allowed = true; |
| 1696 | | analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body); |
| 1804 | if (condition_type->id == TypeTableEntryIdInvalid) { |
| 1805 | expr_return_type = g->builtin_types.entry_invalid; |
| 1806 | } else { |
| 1807 | // if the condition is a simple constant expression and there are no break statements |
| 1808 | // then the return type is unreachable |
| 1809 | AstNodeNumberLiteral number_literal; |
| 1810 | TypeTableEntry *resolved_type = eval_const_expr(g, context, condition_node, &number_literal); |
| 1811 | if (resolved_type->id != TypeTableEntryIdInvalid) { |
| 1812 | assert(resolved_type->id == TypeTableEntryIdBool); |
| 1813 | bool constant_cond_value = number_literal.data.x_uint; |
| 1814 | if (constant_cond_value && !node->codegen_node->data.while_node.contains_break) { |
| 1815 | expr_return_type = g->builtin_types.entry_unreachable; |
| 1816 | } |
| 1817 | } |
| 1818 | } |
| 1697 | 1819 | |
| 1698 | | return g->builtin_types.entry_void; |
| 1820 | return expr_return_type; |
| 1699 | 1821 | } |
| 1700 | 1822 | |
| 1701 | 1823 | static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1702 | 1824 | TypeTableEntry *expected_type, AstNode *node) |
| 1703 | 1825 | { |
| 1704 | | if (!context->break_allowed) { |
| 1826 | AstNode *loop_node = context->parent_loop_node; |
| 1827 | if (loop_node) { |
| 1828 | loop_node->codegen_node->data.while_node.contains_break = true; |
| 1829 | } else { |
| 1705 | 1830 | add_node_error(g, node, |
| 1706 | | buf_sprintf("'break' expression not in loop")); |
| 1831 | buf_sprintf("'break' expression outside loop")); |
| 1707 | 1832 | } |
| 1708 | 1833 | return g->builtin_types.entry_unreachable; |
| 1709 | 1834 | } |
| ... | ... | @@ -1711,9 +1836,9 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, |
| 1711 | 1836 | static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1712 | 1837 | TypeTableEntry *expected_type, AstNode *node) |
| 1713 | 1838 | { |
| 1714 | | if (!context->break_allowed) { |
| 1839 | if (!context->parent_loop_node) { |
| 1715 | 1840 | add_node_error(g, node, |
| 1716 | | buf_sprintf("'continue' expression not in loop")); |
| 1841 | buf_sprintf("'continue' expression outside loop")); |
| 1717 | 1842 | } |
| 1718 | 1843 | return g->builtin_types.entry_unreachable; |
| 1719 | 1844 | } |