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,
|
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||||
TypeTableEntry *expected_type, AstNode *node)
|
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) {
|
switch (node->data.bin_op_expr.bin_op) {
|
||||||
case BinOpTypeAssign:
|
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;
|
AstNode *lhs_node = node->data.bin_op_expr.op1;
|
||||||
TypeTableEntry *expected_rhs_type = nullptr;
|
TypeTableEntry *expected_rhs_type = nullptr;
|
||||||
|
@ -853,7 +909,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||||
add_node_error(g, lhs_node,
|
add_node_error(g, lhs_node,
|
||||||
buf_sprintf("cannot assign to constant variable"));
|
buf_sprintf("cannot assign to constant variable"));
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
add_node_error(g, lhs_node,
|
add_node_error(g, lhs_node,
|
||||||
|
|
|
@ -409,6 +409,18 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||||
case BinOpTypeCmpGreaterOrEq:
|
case BinOpTypeCmpGreaterOrEq:
|
||||||
case BinOpTypeInvalid:
|
case BinOpTypeInvalid:
|
||||||
case BinOpTypeAssign:
|
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();
|
||||||
}
|
}
|
||||||
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;
|
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) {
|
if (lhs_node->type == NodeTypeSymbol) {
|
||||||
LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
|
LocalVariableTableEntry *var = find_local_variable(node->codegen_node->expr_node.block_context,
|
||||||
&lhs_node->data.symbol);
|
&lhs_node->data.symbol);
|
||||||
|
@ -577,15 +594,26 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
|
||||||
} else {
|
} else {
|
||||||
zig_panic("bad assign target");
|
zig_panic("bad assign target");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
|
static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||||
switch (node->data.bin_op_expr.bin_op) {
|
switch (node->data.bin_op_expr.bin_op) {
|
||||||
case BinOpTypeAssign:
|
|
||||||
return gen_assign_expr(g, node);
|
|
||||||
case BinOpTypeInvalid:
|
case BinOpTypeInvalid:
|
||||||
zig_unreachable();
|
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:
|
case BinOpTypeBoolOr:
|
||||||
return gen_bool_or_expr(g, node);
|
return gen_bool_or_expr(g, node);
|
||||||
case BinOpTypeBoolAnd:
|
case BinOpTypeBoolAnd:
|
||||||
|
|
100
src/parser.cpp
100
src/parser.cpp
|
@ -14,26 +14,38 @@
|
||||||
|
|
||||||
static const char *bin_op_str(BinOpType bin_op) {
|
static const char *bin_op_str(BinOpType bin_op) {
|
||||||
switch (bin_op) {
|
switch (bin_op) {
|
||||||
case BinOpTypeInvalid: return "(invalid)";
|
case BinOpTypeInvalid: return "(invalid)";
|
||||||
case BinOpTypeBoolOr: return "||";
|
case BinOpTypeBoolOr: return "||";
|
||||||
case BinOpTypeBoolAnd: return "&&";
|
case BinOpTypeBoolAnd: return "&&";
|
||||||
case BinOpTypeCmpEq: return "==";
|
case BinOpTypeCmpEq: return "==";
|
||||||
case BinOpTypeCmpNotEq: return "!=";
|
case BinOpTypeCmpNotEq: return "!=";
|
||||||
case BinOpTypeCmpLessThan: return "<";
|
case BinOpTypeCmpLessThan: return "<";
|
||||||
case BinOpTypeCmpGreaterThan: return ">";
|
case BinOpTypeCmpGreaterThan: return ">";
|
||||||
case BinOpTypeCmpLessOrEq: return "<=";
|
case BinOpTypeCmpLessOrEq: return "<=";
|
||||||
case BinOpTypeCmpGreaterOrEq: return ">=";
|
case BinOpTypeCmpGreaterOrEq: return ">=";
|
||||||
case BinOpTypeBinOr: return "|";
|
case BinOpTypeBinOr: return "|";
|
||||||
case BinOpTypeBinXor: return "^";
|
case BinOpTypeBinXor: return "^";
|
||||||
case BinOpTypeBinAnd: return "&";
|
case BinOpTypeBinAnd: return "&";
|
||||||
case BinOpTypeBitShiftLeft: return "<<";
|
case BinOpTypeBitShiftLeft: return "<<";
|
||||||
case BinOpTypeBitShiftRight: return ">>";
|
case BinOpTypeBitShiftRight: return ">>";
|
||||||
case BinOpTypeAdd: return "+";
|
case BinOpTypeAdd: return "+";
|
||||||
case BinOpTypeSub: return "-";
|
case BinOpTypeSub: return "-";
|
||||||
case BinOpTypeMult: return "*";
|
case BinOpTypeMult: return "*";
|
||||||
case BinOpTypeDiv: return "/";
|
case BinOpTypeDiv: return "/";
|
||||||
case BinOpTypeMod: return "%";
|
case BinOpTypeMod: return "%";
|
||||||
case BinOpTypeAssign: 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();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +115,7 @@ const char *node_type_str(NodeType node_type) {
|
||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
return "Label";
|
return "Label";
|
||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
return "Label";
|
return "Goto";
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
return "AsmExpr";
|
return "AsmExpr";
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
|
@ -1448,24 +1460,60 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
|
||||||
return nullptr;
|
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) {
|
static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||||
AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
|
AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
|
||||||
if (!lhs)
|
if (!lhs)
|
||||||
return lhs;
|
return nullptr;
|
||||||
|
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
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;
|
return lhs;
|
||||||
*token_index += 1;
|
|
||||||
|
|
||||||
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
|
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
|
||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
|
||||||
node->data.bin_op_expr.op1 = lhs;
|
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;
|
node->data.bin_op_expr.op2 = rhs;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -119,6 +119,18 @@ struct AstNodeVariableDeclaration {
|
||||||
enum BinOpType {
|
enum BinOpType {
|
||||||
BinOpTypeInvalid,
|
BinOpTypeInvalid,
|
||||||
BinOpTypeAssign,
|
BinOpTypeAssign,
|
||||||
|
BinOpTypeAssignTimes,
|
||||||
|
BinOpTypeAssignDiv,
|
||||||
|
BinOpTypeAssignMod,
|
||||||
|
BinOpTypeAssignPlus,
|
||||||
|
BinOpTypeAssignMinus,
|
||||||
|
BinOpTypeAssignBitShiftLeft,
|
||||||
|
BinOpTypeAssignBitShiftRight,
|
||||||
|
BinOpTypeAssignBitAnd,
|
||||||
|
BinOpTypeAssignBitXor,
|
||||||
|
BinOpTypeAssignBitOr,
|
||||||
|
BinOpTypeAssignBoolAnd,
|
||||||
|
BinOpTypeAssignBoolOr,
|
||||||
BinOpTypeBoolOr,
|
BinOpTypeBoolOr,
|
||||||
BinOpTypeBoolAnd,
|
BinOpTypeBoolAnd,
|
||||||
BinOpTypeCmpEq,
|
BinOpTypeCmpEq,
|
||||||
|
|
Loading…
Reference in New Issue