VarType TypeCheckerVisitor::getOperationResultType(TokenKind tokenKind, AstNode* left, AstNode* right) { VarType result = VT_INVALID; VarType leftType = getNodeType(left); VarType rightType = getNodeType(right); switch (tokenKind) { case tOR: case tAND: case tEQ: case tNEQ: case tGT: case tGE: case tLT: case tLE: result = VT_INT; break; case tADD: if (leftType == VT_STRING || rightType == VT_STRING) { result = VT_STRING; } else if (leftType == VT_DOUBLE || rightType == VT_DOUBLE) { result = VT_DOUBLE; } else if (leftType == VT_INT && rightType == VT_INT) { result = VT_INT; } break; case tSUB: case tMUL: case tDIV: case tMOD: if (leftType == VT_DOUBLE || rightType == VT_DOUBLE) { result = VT_DOUBLE; } else if (leftType == VT_INT && rightType == VT_INT) { result = VT_INT; } break; case tASSIGN: if (!(isAssignable(leftType, rightType))) { setErrorMessage(right, "bad type"); } result = leftType; break; case tDECRSET: if (!(isAssignable(leftType, rightType)) || (leftType == VT_STRING)) { setErrorMessage(right, "bad type"); } result = leftType; break; case tINCRSET: if (leftType == VT_STRING) { result = VT_STRING; } else if (leftType == VT_DOUBLE) { result = VT_DOUBLE; } else if (leftType == VT_INT && rightType == VT_INT) { result = VT_INT; } break; default: assert(0); } if (leftType == VT_VOID) { setErrorMessage(left, "Should not be of type void"); } if (rightType == VT_VOID) { setErrorMessage(right, "Should not be of type void"); } return result; }
void TypeCheckerVisitor::visitStoreNode(StoreNode* node) { AstNode* value = node->value(); value->visit(this); const AstVar* var = node->var(); if (isAssignable(var->type(), getNodeType(value))) { setNodeType(node, var->type()); } else { setErrorMessage(node, "Bad type"); } }
static void typeAssign(Output& output, Ast::Assign* n, TypeConstraints* constraints) { type(output, n->left, constraints); type(output, n->right, constraints); typeMustEqual(n->right, astType(n->left), constraints, output); if (!isAssignable(n->left) && !constraints) output.error(n->location, "Expression is not assignable"); if (!n->type) n->type = UNION_NEW(Ty, Void, {}); }
static bool isAssignable(Ast* node) { if (UNION_CASE(Ident, n, node)) return n->targets.size == 1 && n->targets[0]->kind == Variable::KindVariable; else if (UNION_CASE(Member, n, node)) return isAssignable(n->expr); else if (UNION_CASE(Index, n, node)) return true; else if (UNION_CASE(Unary, n, node)) return n->op == UnaryOpDeref; else return false; }
void TypeCheckerVisitor::visitCallNode(CallNode* node) { uint32_t params_count = node->parametersNumber(); AstFunction* refFunc = _current_scope->lookupFunction(node->name(), true); bool matchesRefedFunction = (refFunc!= NULL) && (refFunc->parametersNumber() == params_count); for (uint32_t i = 0; i < params_count; i++) { AstNode* param = node->parameterAt(i); param->visit(this); if (matchesRefedFunction && !isAssignable(refFunc->parameterType(i), getNodeType(param))) { setErrorMessage(param, "Wrong type parameter"); } } if (matchesRefedFunction) { setNodeType(node, refFunc->returnType()); } else { setNodeType(node, VT_INVALID); } }
void TypeCheckerVisitor::visitFunctionNode(FunctionNode* node) { node->body()->visit(this); if (!isAssignable(node->returnType(), getNodeType(node->body()))) { setNodeType(node, VT_INVALID); } }