| ... | @@ -12,6 +12,8 @@ | ... | @@ -12,6 +12,8 @@ |
| 12 | | 12 | |
| 13 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 13 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 14 | TypeTableEntry *expected_type, AstNode *node); | 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 | static AstNode *first_executing_node(AstNode *node) { | 18 | static AstNode *first_executing_node(AstNode *node) { |
| 17 | switch (node->type) { | 19 | switch (node->type) { |
| ... | @@ -284,6 +286,98 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry | ... | @@ -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 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | 381 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 288 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | 382 | AstNode *node, AstNodeNumberLiteral *out_number_literal) |
| 289 | { | 383 | { |
| ... | @@ -291,9 +385,11 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | ... | @@ -291,9 +385,11 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 291 | case NodeTypeNumberLiteral: | 385 | case NodeTypeNumberLiteral: |
| 292 | *out_number_literal = node->data.number_literal; | 386 | *out_number_literal = node->data.number_literal; |
| 293 | return node->codegen_node->expr_node.type_entry; | 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 | case NodeTypeBinOpExpr: | 391 | case NodeTypeBinOpExpr: |
| 295 | zig_panic("TODO eval_const_expr bin op expr"); | 392 | return eval_const_expr_bin_op(g, context, node, out_number_literal); |
| 296 | break; | | |
| 297 | case NodeTypeCompilerFnType: | 393 | case NodeTypeCompilerFnType: |
| 298 | { | 394 | { |
| 299 | Buf *name = &node->data.compiler_fn_type.name; | 395 | Buf *name = &node->data.compiler_fn_type.name; |
| ... | @@ -1133,8 +1229,12 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { | ... | @@ -1133,8 +1229,12 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 1133 | context->variable_table.init(8); | 1229 | context->variable_table.init(8); |
| 1134 | | 1230 | |
| 1135 | if (parent) { | 1231 | if (parent) { |
| 1136 | context->break_allowed = parent->break_allowed || parent->next_child_break_allowed; | 1232 | if (parent->next_child_parent_loop_node) { |
| 1137 | parent->next_child_break_allowed = false; | 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 | if (node && node->type == NodeTypeFnDef) { | 1240 | if (node && node->type == NodeTypeFnDef) { |
| ... | @@ -1690,20 +1790,45 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp | ... | @@ -1690,20 +1790,45 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1690 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1790 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1691 | TypeTableEntry *expected_type, AstNode *node) | 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; | 1804 | if (condition_type->id == TypeTableEntryIdInvalid) { |
| 1696 | analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body); | 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 | static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1823 | static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1702 | TypeTableEntry *expected_type, AstNode *node) | 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 | add_node_error(g, node, | 1830 | add_node_error(g, node, |
| 1706 | buf_sprintf("'break' expression not in loop")); | 1831 | buf_sprintf("'break' expression outside loop")); |
| 1707 | } | 1832 | } |
| 1708 | return g->builtin_types.entry_unreachable; | 1833 | return g->builtin_types.entry_unreachable; |
| 1709 | } | 1834 | } |
| ... | @@ -1711,9 +1836,9 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1711,9 +1836,9 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, |
| 1711 | static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1836 | static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1712 | TypeTableEntry *expected_type, AstNode *node) | 1837 | TypeTableEntry *expected_type, AstNode *node) |
| 1713 | { | 1838 | { |
| 1714 | if (!context->break_allowed) { | 1839 | if (!context->parent_loop_node) { |
| 1715 | add_node_error(g, node, | 1840 | add_node_error(g, node, |
| 1716 | buf_sprintf("'continue' expression not in loop")); | 1841 | buf_sprintf("'continue' expression outside loop")); |
| 1717 | } | 1842 | } |
| 1718 | return g->builtin_types.entry_unreachable; | 1843 | return g->builtin_types.entry_unreachable; |
| 1719 | } | 1844 | } |