Commit 5cb5f5dbf6

Josh Wolfe <thejoshwolfe@gmail.com>
2015-12-13 03:07:29
parsing assignment operators
1 parent eb1542c
src/analyze.cpp
@@ -714,6 +714,50 @@ static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context,
     }
 }
 
+static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
+    switch (op) {
+        case BinOpTypeAssign:
+            return true;
+        case BinOpTypeAssignTimes:
+        case BinOpTypeAssignDiv:
+        case BinOpTypeAssignMod:
+        case BinOpTypeAssignPlus:
+        case BinOpTypeAssignMinus:
+            return type->id == TypeTableEntryIdInt || type->id == TypeTableEntryIdFloat;
+        case BinOpTypeAssignBitShiftLeft:
+        case BinOpTypeAssignBitShiftRight:
+        case BinOpTypeAssignBitAnd:
+        case BinOpTypeAssignBitXor:
+        case BinOpTypeAssignBitOr:
+            return type->id == TypeTableEntryIdInt;
+        case BinOpTypeAssignBoolAnd:
+        case BinOpTypeAssignBoolOr:
+            return type->id == TypeTableEntryIdBool;
+
+        case BinOpTypeInvalid:
+        case BinOpTypeBoolOr:
+        case BinOpTypeBoolAnd:
+        case BinOpTypeCmpEq:
+        case BinOpTypeCmpNotEq:
+        case BinOpTypeCmpLessThan:
+        case BinOpTypeCmpGreaterThan:
+        case BinOpTypeCmpLessOrEq:
+        case BinOpTypeCmpGreaterOrEq:
+        case BinOpTypeBinOr:
+        case BinOpTypeBinXor:
+        case BinOpTypeBinAnd:
+        case BinOpTypeBitShiftLeft:
+        case BinOpTypeBitShiftRight:
+        case BinOpTypeAdd:
+        case BinOpTypeSub:
+        case BinOpTypeMult:
+        case BinOpTypeDiv:
+        case BinOpTypeMod:
+            zig_unreachable();
+    }
+    zig_unreachable();
+}
+
 static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node)
 {
@@ -842,6 +886,18 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
             {
                 switch (node->data.bin_op_expr.bin_op) {
                     case BinOpTypeAssign:
+                    case BinOpTypeAssignTimes:
+                    case BinOpTypeAssignDiv:
+                    case BinOpTypeAssignMod:
+                    case BinOpTypeAssignPlus:
+                    case BinOpTypeAssignMinus:
+                    case BinOpTypeAssignBitShiftLeft:
+                    case BinOpTypeAssignBitShiftRight:
+                    case BinOpTypeAssignBitAnd:
+                    case BinOpTypeAssignBitXor:
+                    case BinOpTypeAssignBitOr:
+                    case BinOpTypeAssignBoolAnd:
+                    case BinOpTypeAssignBoolOr:
                         {
                             AstNode *lhs_node = node->data.bin_op_expr.op1;
                             TypeTableEntry *expected_rhs_type = nullptr;
@@ -853,7 +909,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
                                         add_node_error(g, lhs_node,
                                             buf_sprintf("cannot assign to constant variable"));
                                     } else {
-                                        expected_rhs_type = var->type;
+                                        if (!is_op_allowed(var->type, node->data.bin_op_expr.bin_op)) {
+                                            add_node_error(g, lhs_node,
+                                                buf_sprintf("operator not allowed for type '%s'", buf_ptr(&var->type->name)));
+                                        } else {
+                                            expected_rhs_type = var->type;
+                                        }
                                     }
                                 } else {
                                     add_node_error(g, lhs_node,
src/codegen.cpp
@@ -409,6 +409,18 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
         case BinOpTypeCmpGreaterOrEq:
         case BinOpTypeInvalid:
         case BinOpTypeAssign:
+        case BinOpTypeAssignTimes:
+        case BinOpTypeAssignDiv:
+        case BinOpTypeAssignMod:
+        case BinOpTypeAssignPlus:
+        case BinOpTypeAssignMinus:
+        case BinOpTypeAssignBitShiftLeft:
+        case BinOpTypeAssignBitShiftRight:
+        case BinOpTypeAssignBitAnd:
+        case BinOpTypeAssignBitXor:
+        case BinOpTypeAssignBitOr:
+        case BinOpTypeAssignBoolAnd:
+        case BinOpTypeAssignBoolOr:
             zig_unreachable();
     }
     zig_unreachable();
@@ -543,6 +555,11 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
 
     AstNode *lhs_node = node->data.bin_op_expr.op1;
 
+    bool is_read_first = node->data.bin_op_expr.bin_op != BinOpTypeAssign;
+    if (is_read_first) {
+        zig_panic("TODO: implement modify assignment ops");
+    }
+
     if (lhs_node->type == NodeTypeSymbol) {
         LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
                 &lhs_node->data.symbol);
@@ -577,15 +594,26 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
     } else {
         zig_panic("bad assign target");
     }
-
 }
 
 static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
     switch (node->data.bin_op_expr.bin_op) {
-        case BinOpTypeAssign:
-            return gen_assign_expr(g, node);
         case BinOpTypeInvalid:
             zig_unreachable();
+        case BinOpTypeAssign:
+        case BinOpTypeAssignTimes:
+        case BinOpTypeAssignDiv:
+        case BinOpTypeAssignMod:
+        case BinOpTypeAssignPlus:
+        case BinOpTypeAssignMinus:
+        case BinOpTypeAssignBitShiftLeft:
+        case BinOpTypeAssignBitShiftRight:
+        case BinOpTypeAssignBitAnd:
+        case BinOpTypeAssignBitXor:
+        case BinOpTypeAssignBitOr:
+        case BinOpTypeAssignBoolAnd:
+        case BinOpTypeAssignBoolOr:
+            return gen_assign_expr(g, node);
         case BinOpTypeBoolOr:
             return gen_bool_or_expr(g, node);
         case BinOpTypeBoolAnd:
src/parser.cpp
@@ -14,26 +14,38 @@
 
 static const char *bin_op_str(BinOpType bin_op) {
     switch (bin_op) {
-        case BinOpTypeInvalid:        return "(invalid)";
-        case BinOpTypeBoolOr:         return "||";
-        case BinOpTypeBoolAnd:        return "&&";
-        case BinOpTypeCmpEq:          return "==";
-        case BinOpTypeCmpNotEq:       return "!=";
-        case BinOpTypeCmpLessThan:    return "<";
-        case BinOpTypeCmpGreaterThan: return ">";
-        case BinOpTypeCmpLessOrEq:    return "<=";
-        case BinOpTypeCmpGreaterOrEq: return ">=";
-        case BinOpTypeBinOr:          return "|";
-        case BinOpTypeBinXor:         return "^";
-        case BinOpTypeBinAnd:         return "&";
-        case BinOpTypeBitShiftLeft:   return "<<";
-        case BinOpTypeBitShiftRight:  return ">>";
-        case BinOpTypeAdd:            return "+";
-        case BinOpTypeSub:            return "-";
-        case BinOpTypeMult:           return "*";
-        case BinOpTypeDiv:            return "/";
-        case BinOpTypeMod:            return "%";
-        case BinOpTypeAssign:         return "=";
+        case BinOpTypeInvalid:             return "(invalid)";
+        case BinOpTypeBoolOr:              return "||";
+        case BinOpTypeBoolAnd:             return "&&";
+        case BinOpTypeCmpEq:               return "==";
+        case BinOpTypeCmpNotEq:            return "!=";
+        case BinOpTypeCmpLessThan:         return "<";
+        case BinOpTypeCmpGreaterThan:      return ">";
+        case BinOpTypeCmpLessOrEq:         return "<=";
+        case BinOpTypeCmpGreaterOrEq:      return ">=";
+        case BinOpTypeBinOr:               return "|";
+        case BinOpTypeBinXor:              return "^";
+        case BinOpTypeBinAnd:              return "&";
+        case BinOpTypeBitShiftLeft:        return "<<";
+        case BinOpTypeBitShiftRight:       return ">>";
+        case BinOpTypeAdd:                 return "+";
+        case BinOpTypeSub:                 return "-";
+        case BinOpTypeMult:                return "*";
+        case BinOpTypeDiv:                 return "/";
+        case BinOpTypeMod:                 return "%";
+        case BinOpTypeAssign:              return "=";
+        case BinOpTypeAssignTimes:         return "*=";
+        case BinOpTypeAssignDiv:           return "/=";
+        case BinOpTypeAssignMod:           return "%=";
+        case BinOpTypeAssignPlus:          return "+=";
+        case BinOpTypeAssignMinus:         return "-=";
+        case BinOpTypeAssignBitShiftLeft:  return "<<=";
+        case BinOpTypeAssignBitShiftRight: return ">>=";
+        case BinOpTypeAssignBitAnd:        return "&=";
+        case BinOpTypeAssignBitXor:        return "^=";
+        case BinOpTypeAssignBitOr:         return "|=";
+        case BinOpTypeAssignBoolAnd:       return "&&=";
+        case BinOpTypeAssignBoolOr:        return "||=";
     }
     zig_unreachable();
 }
@@ -103,7 +115,7 @@ const char *node_type_str(NodeType node_type) {
         case NodeTypeLabel:
             return "Label";
         case NodeTypeGoto:
-            return "Label";
+            return "Goto";
         case NodeTypeAsmExpr:
             return "AsmExpr";
         case NodeTypeFieldAccessExpr:
@@ -1448,24 +1460,60 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
     return nullptr;
 }
 
+static BinOpType tok_to_ass_op(Token *token) {
+    switch (token->id) {
+        case TokenIdEq: return BinOpTypeAssign;
+        case TokenIdTimesEq: return BinOpTypeAssignTimes;
+        case TokenIdDivEq: return BinOpTypeAssignDiv;
+        case TokenIdModEq: return BinOpTypeAssignMod;
+        case TokenIdPlusEq: return BinOpTypeAssignPlus;
+        case TokenIdMinusEq: return BinOpTypeAssignMinus;
+        case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
+        case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
+        case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
+        case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
+        case TokenIdBitOrEq: return BinOpTypeAssignBitOr;
+        case TokenIdBoolAndEq: return BinOpTypeAssignBoolAnd;
+        case TokenIdBoolOrEq: return BinOpTypeAssignBoolOr;
+        default: return BinOpTypeInvalid;
+    }
+}
+
 /*
-AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression
+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)
+*/
+static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool mandatory) {
+    Token *token = &pc->tokens->at(*token_index);
+    BinOpType result = tok_to_ass_op(token);
+    if (result == BinOpTypeInvalid) {
+        if (mandatory) {
+            ast_invalid_token_error(pc, token);
+        } else {
+            return BinOpTypeInvalid;
+        }
+    }
+    *token_index += 1;
+    return result;
+}
+
+/*
+AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | BoolOrExpression
 */
 static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
     AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
     if (!lhs)
-        return lhs;
+        return nullptr;
 
     Token *token = &pc->tokens->at(*token_index);
-    if (token->id != TokenIdEq)
+    BinOpType ass_op = ast_parse_ass_op(pc, token_index, false);
+    if (ass_op == BinOpTypeInvalid)
         return lhs;
-    *token_index += 1;
 
     AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
 
     AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
     node->data.bin_op_expr.op1 = lhs;
-    node->data.bin_op_expr.bin_op = BinOpTypeAssign;
+    node->data.bin_op_expr.bin_op = ass_op;
     node->data.bin_op_expr.op2 = rhs;
 
     return node;
src/parser.hpp
@@ -119,6 +119,18 @@ struct AstNodeVariableDeclaration {
 enum BinOpType {
     BinOpTypeInvalid,
     BinOpTypeAssign,
+    BinOpTypeAssignTimes,
+    BinOpTypeAssignDiv,
+    BinOpTypeAssignMod,
+    BinOpTypeAssignPlus,
+    BinOpTypeAssignMinus,
+    BinOpTypeAssignBitShiftLeft,
+    BinOpTypeAssignBitShiftRight,
+    BinOpTypeAssignBitAnd,
+    BinOpTypeAssignBitXor,
+    BinOpTypeAssignBitOr,
+    BinOpTypeAssignBoolAnd,
+    BinOpTypeAssignBoolOr,
     BinOpTypeBoolOr,
     BinOpTypeBoolAnd,
     BinOpTypeCmpEq,