Commit 5cb5f5dbf6
Changed files (4)
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,