| author | |
| committer | |
| log | 5cb5f5dbf625f5995a2e34b96985dca181222cea |
| tree | f8214648a6ce5e59e09f55e85786cd403f637be0 |
| parent | eb1542c1027481546d0efdf6a5faac2593b9e8e8 |
4 files changed, 179 insertions(+), 30 deletions(-)
src/analyze.cpp+62-1| ... | @@ -714,6 +714,50 @@ static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context, | ... | @@ -714,6 +714,50 @@ static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context, |
| 714 | } | 714 | } |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { | ||
| 718 | switch (op) { | ||
| 719 | case BinOpTypeAssign: | ||
| 720 | return true; | ||
| 721 | case BinOpTypeAssignTimes: | ||
| 722 | case BinOpTypeAssignDiv: | ||
| 723 | case BinOpTypeAssignMod: | ||
| 724 | case BinOpTypeAssignPlus: | ||
| 725 | case BinOpTypeAssignMinus: | ||
| 726 | return type->id == TypeTableEntryIdInt || type->id == TypeTableEntryIdFloat; | ||
| 727 | case BinOpTypeAssignBitShiftLeft: | ||
| 728 | case BinOpTypeAssignBitShiftRight: | ||
| 729 | case BinOpTypeAssignBitAnd: | ||
| 730 | case BinOpTypeAssignBitXor: | ||
| 731 | case BinOpTypeAssignBitOr: | ||
| 732 | return type->id == TypeTableEntryIdInt; | ||
| 733 | case BinOpTypeAssignBoolAnd: | ||
| 734 | case BinOpTypeAssignBoolOr: | ||
| 735 | return type->id == TypeTableEntryIdBool; | ||
| 736 | |||
| 737 | case BinOpTypeInvalid: | ||
| 738 | case BinOpTypeBoolOr: | ||
| 739 | case BinOpTypeBoolAnd: | ||
| 740 | case BinOpTypeCmpEq: | ||
| 741 | case BinOpTypeCmpNotEq: | ||
| 742 | case BinOpTypeCmpLessThan: | ||
| 743 | case BinOpTypeCmpGreaterThan: | ||
| 744 | case BinOpTypeCmpLessOrEq: | ||
| 745 | case BinOpTypeCmpGreaterOrEq: | ||
| 746 | case BinOpTypeBinOr: | ||
| 747 | case BinOpTypeBinXor: | ||
| 748 | case BinOpTypeBinAnd: | ||
| 749 | case BinOpTypeBitShiftLeft: | ||
| 750 | case BinOpTypeBitShiftRight: | ||
| 751 | case BinOpTypeAdd: | ||
| 752 | case BinOpTypeSub: | ||
| 753 | case BinOpTypeMult: | ||
| 754 | case BinOpTypeDiv: | ||
| 755 | case BinOpTypeMod: | ||
| 756 | zig_unreachable(); | ||
| 757 | } | ||
| 758 | zig_unreachable(); | ||
| 759 | } | ||
| 760 | |||
| 717 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 761 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 718 | TypeTableEntry *expected_type, AstNode *node) | 762 | TypeTableEntry *expected_type, AstNode *node) |
| 719 | { | 763 | { |
| ... | @@ -842,6 +886,18 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -842,6 +886,18 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 842 | { | 886 | { |
| 843 | switch (node->data.bin_op_expr.bin_op) { | 887 | switch (node->data.bin_op_expr.bin_op) { |
| 844 | case BinOpTypeAssign: | 888 | case BinOpTypeAssign: |
| 889 | case BinOpTypeAssignTimes: | ||
| 890 | case BinOpTypeAssignDiv: | ||
| 891 | case BinOpTypeAssignMod: | ||
| 892 | case BinOpTypeAssignPlus: | ||
| 893 | case BinOpTypeAssignMinus: | ||
| 894 | case BinOpTypeAssignBitShiftLeft: | ||
| 895 | case BinOpTypeAssignBitShiftRight: | ||
| 896 | case BinOpTypeAssignBitAnd: | ||
| 897 | case BinOpTypeAssignBitXor: | ||
| 898 | case BinOpTypeAssignBitOr: | ||
| 899 | case BinOpTypeAssignBoolAnd: | ||
| 900 | case BinOpTypeAssignBoolOr: | ||
| 845 | { | 901 | { |
| 846 | AstNode *lhs_node = node->data.bin_op_expr.op1; | 902 | AstNode *lhs_node = node->data.bin_op_expr.op1; |
| 847 | TypeTableEntry *expected_rhs_type = nullptr; | 903 | TypeTableEntry *expected_rhs_type = nullptr; |
| ... | @@ -853,7 +909,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -853,7 +909,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 853 | add_node_error(g, lhs_node, | 909 | add_node_error(g, lhs_node, |
| 854 | buf_sprintf("cannot assign to constant variable")); | 910 | buf_sprintf("cannot assign to constant variable")); |
| 855 | } else { | 911 | } else { |
| 856 | expected_rhs_type = var->type; | 912 | if (!is_op_allowed(var->type, node->data.bin_op_expr.bin_op)) { |
| 913 | add_node_error(g, lhs_node, | ||
| 914 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&var->type->name))); | ||
| 915 | } else { | ||
| 916 | expected_rhs_type = var->type; | ||
| 917 | } | ||
| 857 | } | 918 | } |
| 858 | } else { | 919 | } else { |
| 859 | add_node_error(g, lhs_node, | 920 | add_node_error(g, lhs_node, |
src/codegen.cpp+31-3| ... | @@ -409,6 +409,18 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -409,6 +409,18 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { |
| 409 | case BinOpTypeCmpGreaterOrEq: | 409 | case BinOpTypeCmpGreaterOrEq: |
| 410 | case BinOpTypeInvalid: | 410 | case BinOpTypeInvalid: |
| 411 | case BinOpTypeAssign: | 411 | case BinOpTypeAssign: |
| 412 | case BinOpTypeAssignTimes: | ||
| 413 | case BinOpTypeAssignDiv: | ||
| 414 | case BinOpTypeAssignMod: | ||
| 415 | case BinOpTypeAssignPlus: | ||
| 416 | case BinOpTypeAssignMinus: | ||
| 417 | case BinOpTypeAssignBitShiftLeft: | ||
| 418 | case BinOpTypeAssignBitShiftRight: | ||
| 419 | case BinOpTypeAssignBitAnd: | ||
| 420 | case BinOpTypeAssignBitXor: | ||
| 421 | case BinOpTypeAssignBitOr: | ||
| 422 | case BinOpTypeAssignBoolAnd: | ||
| 423 | case BinOpTypeAssignBoolOr: | ||
| 412 | zig_unreachable(); | 424 | zig_unreachable(); |
| 413 | } | 425 | } |
| 414 | zig_unreachable(); | 426 | zig_unreachable(); |
| ... | @@ -543,6 +555,11 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { | ... | @@ -543,6 +555,11 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 543 | 555 | ||
| 544 | AstNode *lhs_node = node->data.bin_op_expr.op1; | 556 | AstNode *lhs_node = node->data.bin_op_expr.op1; |
| 545 | 557 | ||
| 558 | bool is_read_first = node->data.bin_op_expr.bin_op != BinOpTypeAssign; | ||
| 559 | if (is_read_first) { | ||
| 560 | zig_panic("TODO: implement modify assignment ops"); | ||
| 561 | } | ||
| 562 | |||
| 546 | if (lhs_node->type == NodeTypeSymbol) { | 563 | if (lhs_node->type == NodeTypeSymbol) { |
| 547 | LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context, | 564 | LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context, |
| 548 | &lhs_node->data.symbol); | 565 | &lhs_node->data.symbol); |
| ... | @@ -577,15 +594,26 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { | ... | @@ -577,15 +594,26 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 577 | } else { | 594 | } else { |
| 578 | zig_panic("bad assign target"); | 595 | zig_panic("bad assign target"); |
| 579 | } | 596 | } |
| 580 | |||
| 581 | } | 597 | } |
| 582 | 598 | ||
| 583 | static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { | 599 | static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { |
| 584 | switch (node->data.bin_op_expr.bin_op) { | 600 | switch (node->data.bin_op_expr.bin_op) { |
| 585 | case BinOpTypeAssign: | ||
| 586 | return gen_assign_expr(g, node); | ||
| 587 | case BinOpTypeInvalid: | 601 | case BinOpTypeInvalid: |
| 588 | zig_unreachable(); | 602 | zig_unreachable(); |
| 603 | case BinOpTypeAssign: | ||
| 604 | case BinOpTypeAssignTimes: | ||
| 605 | case BinOpTypeAssignDiv: | ||
| 606 | case BinOpTypeAssignMod: | ||
| 607 | case BinOpTypeAssignPlus: | ||
| 608 | case BinOpTypeAssignMinus: | ||
| 609 | case BinOpTypeAssignBitShiftLeft: | ||
| 610 | case BinOpTypeAssignBitShiftRight: | ||
| 611 | case BinOpTypeAssignBitAnd: | ||
| 612 | case BinOpTypeAssignBitXor: | ||
| 613 | case BinOpTypeAssignBitOr: | ||
| 614 | case BinOpTypeAssignBoolAnd: | ||
| 615 | case BinOpTypeAssignBoolOr: | ||
| 616 | return gen_assign_expr(g, node); | ||
| 589 | case BinOpTypeBoolOr: | 617 | case BinOpTypeBoolOr: |
| 590 | return gen_bool_or_expr(g, node); | 618 | return gen_bool_or_expr(g, node); |
| 591 | case BinOpTypeBoolAnd: | 619 | case BinOpTypeBoolAnd: |
src/parser.cpp+74-26| ... | @@ -14,26 +14,38 @@ | ... | @@ -14,26 +14,38 @@ |
| 14 | 14 | ||
| 15 | static const char *bin_op_str(BinOpType bin_op) { | 15 | static const char *bin_op_str(BinOpType bin_op) { |
| 16 | switch (bin_op) { | 16 | switch (bin_op) { |
| 17 | case BinOpTypeInvalid: return "(invalid)"; | 17 | case BinOpTypeInvalid: return "(invalid)"; |
| 18 | case BinOpTypeBoolOr: return "||"; | 18 | case BinOpTypeBoolOr: return "||"; |
| 19 | case BinOpTypeBoolAnd: return "&&"; | 19 | case BinOpTypeBoolAnd: return "&&"; |
| 20 | case BinOpTypeCmpEq: return "=="; | 20 | case BinOpTypeCmpEq: return "=="; |
| 21 | case BinOpTypeCmpNotEq: return "!="; | 21 | case BinOpTypeCmpNotEq: return "!="; |
| 22 | case BinOpTypeCmpLessThan: return "<"; | 22 | case BinOpTypeCmpLessThan: return "<"; |
| 23 | case BinOpTypeCmpGreaterThan: return ">"; | 23 | case BinOpTypeCmpGreaterThan: return ">"; |
| 24 | case BinOpTypeCmpLessOrEq: return "<="; | 24 | case BinOpTypeCmpLessOrEq: return "<="; |
| 25 | case BinOpTypeCmpGreaterOrEq: return ">="; | 25 | case BinOpTypeCmpGreaterOrEq: return ">="; |
| 26 | case BinOpTypeBinOr: return "|"; | 26 | case BinOpTypeBinOr: return "|"; |
| 27 | case BinOpTypeBinXor: return "^"; | 27 | case BinOpTypeBinXor: return "^"; |
| 28 | case BinOpTypeBinAnd: return "&"; | 28 | case BinOpTypeBinAnd: return "&"; |
| 29 | case BinOpTypeBitShiftLeft: return "<<"; | 29 | case BinOpTypeBitShiftLeft: return "<<"; |
| 30 | case BinOpTypeBitShiftRight: return ">>"; | 30 | case BinOpTypeBitShiftRight: return ">>"; |
| 31 | case BinOpTypeAdd: return "+"; | 31 | case BinOpTypeAdd: return "+"; |
| 32 | case BinOpTypeSub: return "-"; | 32 | case BinOpTypeSub: return "-"; |
| 33 | case BinOpTypeMult: return "*"; | 33 | case BinOpTypeMult: return "*"; |
| 34 | case BinOpTypeDiv: return "/"; | 34 | case BinOpTypeDiv: return "/"; |
| 35 | case BinOpTypeMod: return "%"; | 35 | case BinOpTypeMod: return "%"; |
| 36 | case BinOpTypeAssign: return "="; | 36 | case BinOpTypeAssign: return "="; |
| 37 | case BinOpTypeAssignTimes: return "*="; | ||
| 38 | case BinOpTypeAssignDiv: return "/="; | ||
| 39 | case BinOpTypeAssignMod: return "%="; | ||
| 40 | case BinOpTypeAssignPlus: return "+="; | ||
| 41 | case BinOpTypeAssignMinus: return "-="; | ||
| 42 | case BinOpTypeAssignBitShiftLeft: return "<<="; | ||
| 43 | case BinOpTypeAssignBitShiftRight: return ">>="; | ||
| 44 | case BinOpTypeAssignBitAnd: return "&="; | ||
| 45 | case BinOpTypeAssignBitXor: return "^="; | ||
| 46 | case BinOpTypeAssignBitOr: return "|="; | ||
| 47 | case BinOpTypeAssignBoolAnd: return "&&="; | ||
| 48 | case BinOpTypeAssignBoolOr: return "||="; | ||
| 37 | } | 49 | } |
| 38 | zig_unreachable(); | 50 | zig_unreachable(); |
| 39 | } | 51 | } |
| ... | @@ -103,7 +115,7 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -103,7 +115,7 @@ const char *node_type_str(NodeType node_type) { |
| 103 | case NodeTypeLabel: | 115 | case NodeTypeLabel: |
| 104 | return "Label"; | 116 | return "Label"; |
| 105 | case NodeTypeGoto: | 117 | case NodeTypeGoto: |
| 106 | return "Label"; | 118 | return "Goto"; |
| 107 | case NodeTypeAsmExpr: | 119 | case NodeTypeAsmExpr: |
| 108 | return "AsmExpr"; | 120 | return "AsmExpr"; |
| 109 | case NodeTypeFieldAccessExpr: | 121 | case NodeTypeFieldAccessExpr: |
| ... | @@ -1448,24 +1460,60 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma | ... | @@ -1448,24 +1460,60 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma |
| 1448 | return nullptr; | 1460 | return nullptr; |
| 1449 | } | 1461 | } |
| 1450 | 1462 | ||
| 1463 | static BinOpType tok_to_ass_op(Token *token) { | ||
| 1464 | switch (token->id) { | ||
| 1465 | case TokenIdEq: return BinOpTypeAssign; | ||
| 1466 | case TokenIdTimesEq: return BinOpTypeAssignTimes; | ||
| 1467 | case TokenIdDivEq: return BinOpTypeAssignDiv; | ||
| 1468 | case TokenIdModEq: return BinOpTypeAssignMod; | ||
| 1469 | case TokenIdPlusEq: return BinOpTypeAssignPlus; | ||
| 1470 | case TokenIdMinusEq: return BinOpTypeAssignMinus; | ||
| 1471 | case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft; | ||
| 1472 | case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight; | ||
| 1473 | case TokenIdBitAndEq: return BinOpTypeAssignBitAnd; | ||
| 1474 | case TokenIdBitXorEq: return BinOpTypeAssignBitXor; | ||
| 1475 | case TokenIdBitOrEq: return BinOpTypeAssignBitOr; | ||
| 1476 | case TokenIdBoolAndEq: return BinOpTypeAssignBoolAnd; | ||
| 1477 | case TokenIdBoolOrEq: return BinOpTypeAssignBoolOr; | ||
| 1478 | default: return BinOpTypeInvalid; | ||
| 1479 | } | ||
| 1480 | } | ||
| 1481 | |||
| 1451 | /* | 1482 | /* |
| 1452 | AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression | 1483 | AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq) |
| 1484 | */ | ||
| 1485 | static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 1486 | Token *token = &pc->tokens->at(*token_index); | ||
| 1487 | BinOpType result = tok_to_ass_op(token); | ||
| 1488 | if (result == BinOpTypeInvalid) { | ||
| 1489 | if (mandatory) { | ||
| 1490 | ast_invalid_token_error(pc, token); | ||
| 1491 | } else { | ||
| 1492 | return BinOpTypeInvalid; | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | *token_index += 1; | ||
| 1496 | return result; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | /* | ||
| 1500 | AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | BoolOrExpression | ||
| 1453 | */ | 1501 | */ |
| 1454 | static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1502 | static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1455 | AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory); | 1503 | AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory); |
| 1456 | if (!lhs) | 1504 | if (!lhs) |
| 1457 | return lhs; | 1505 | return nullptr; |
| 1458 | 1506 | ||
| 1459 | Token *token = &pc->tokens->at(*token_index); | 1507 | Token *token = &pc->tokens->at(*token_index); |
| 1460 | if (token->id != TokenIdEq) | 1508 | BinOpType ass_op = ast_parse_ass_op(pc, token_index, false); |
| 1509 | if (ass_op == BinOpTypeInvalid) | ||
| 1461 | return lhs; | 1510 | return lhs; |
| 1462 | *token_index += 1; | ||
| 1463 | 1511 | ||
| 1464 | AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true); | 1512 | AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true); |
| 1465 | 1513 | ||
| 1466 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); | 1514 | AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); |
| 1467 | node->data.bin_op_expr.op1 = lhs; | 1515 | node->data.bin_op_expr.op1 = lhs; |
| 1468 | node->data.bin_op_expr.bin_op = BinOpTypeAssign; | 1516 | node->data.bin_op_expr.bin_op = ass_op; |
| 1469 | node->data.bin_op_expr.op2 = rhs; | 1517 | node->data.bin_op_expr.op2 = rhs; |
| 1470 | 1518 | ||
| 1471 | return node; | 1519 | return node; |
src/parser.hpp+12| ... | @@ -119,6 +119,18 @@ struct AstNodeVariableDeclaration { | ... | @@ -119,6 +119,18 @@ struct AstNodeVariableDeclaration { |
| 119 | enum BinOpType { | 119 | enum BinOpType { |
| 120 | BinOpTypeInvalid, | 120 | BinOpTypeInvalid, |
| 121 | BinOpTypeAssign, | 121 | BinOpTypeAssign, |
| 122 | BinOpTypeAssignTimes, | ||
| 123 | BinOpTypeAssignDiv, | ||
| 124 | BinOpTypeAssignMod, | ||
| 125 | BinOpTypeAssignPlus, | ||
| 126 | BinOpTypeAssignMinus, | ||
| 127 | BinOpTypeAssignBitShiftLeft, | ||
| 128 | BinOpTypeAssignBitShiftRight, | ||
| 129 | BinOpTypeAssignBitAnd, | ||
| 130 | BinOpTypeAssignBitXor, | ||
| 131 | BinOpTypeAssignBitOr, | ||
| 132 | BinOpTypeAssignBoolAnd, | ||
| 133 | BinOpTypeAssignBoolOr, | ||
| 122 | BinOpTypeBoolOr, | 134 | BinOpTypeBoolOr, |
| 123 | BinOpTypeBoolAnd, | 135 | BinOpTypeBoolAnd, |
| 124 | BinOpTypeCmpEq, | 136 | BinOpTypeCmpEq, |