parsing assignment operators
parent
eb1542c102
commit
5cb5f5dbf6
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
100
src/parser.cpp
100
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue