void processExprRelatedNode(AST_NODE* exprRelatedNode)
{
  switch(exprRelatedNode->nodeType){
    case IDENTIFIER_NODE:
    {
      checkIDNode(exprRelatedNode);
      break;
    }
    case EXPR_NODE:
    {
      processExprNode(exprRelatedNode);
      break;
    }
    case STMT_NODE:
    {
      checkFunctionCall(exprRelatedNode);
      break;
    }
    case CONST_VALUE_NODE:
    {
      processConstValueNode(exprRelatedNode);
      break;
    }
    default: 
    {
      assert(0);
    }
  }
}
void checkParameterPassing(Parameter* formalParameter, AST_NODE* actualParameter)
{
  while (formalParameter && actualParameter) {
    if (actualParameter->nodeType == EXPR_NODE) {
      processExprNode(actualParameter);
      if (formalParameter->type->kind == ARRAY_TYPE_DESCRIPTOR) {
        printErrorMsg(actualParameter, PASS_SCALAR_TO_ARRAY);
      }
    } else if (actualParameter->nodeType == CONST_VALUE_NODE) {
    } else if (actualParameter->nodeType == STMT_NODE) {
      checkFunctionCall(actualParameter);
      SymbolTableEntry *entry = retrieveSymbol(actualParameter->semantic_value.identifierSemanticValue.identifierName);
      if (entry != NULL) {
        if (formalParameter->type->kind == ARRAY_TYPE_DESCRIPTOR ) {
          printErrorMsg(actualParameter, PASS_SCALAR_TO_ARRAY);
        } else {
          if (getDataType(formalParameter->type) != getDataType(entry->attribute->attr.typeDescriptor)) {
            printErrorMsgSpecial(actualParameter, formalParameter->parameterName, PARAMETER_TYPE_UNMATCH);
          }
        }
      }
    } else if (actualParameter->nodeType == IDENTIFIER_NODE) {
      checkParameterIdentifier(formalParameter, actualParameter);
    }

    formalParameter = formalParameter->next;
    actualParameter = actualParameter->rightSibling;
  }
}
std::shared_ptr<inter::LogicalExpression> SemanticChecker::checkLogicalExpression(inter::ScopePrototype & scopePrototype, syntax::LogicalExpression & condition)
{
    CHECK_FAIL(nullptr);

    std::shared_ptr<inter::LogicalExpression> obj = std::make_shared<inter::LogicalExpression>();

    obj->operation = condition._operation;
    obj->negated = condition._isNegated;

    for (auto & operand : condition._operands)
    {
        if (operand->getType() == syntax::Node::Type::LogicalExpression)
        {
            obj->operands.push_back(checkLogicalExpression(scopePrototype, *(static_cast<syntax::LogicalExpression*>(operand.get()))));
        }
        else if (operand->getType() == syntax::Node::Type::Variable)
        {
            obj->operands.push_back(checkVariable(scopePrototype, *(static_cast<syntax::Variable*>(operand.get()))));
        }
        else if (operand->getType() == syntax::Node::Type::Call)
        {
            obj->operands.push_back(checkFunctionCall(scopePrototype, *(static_cast<syntax::Call*>(operand.get()))));
        }
        else if (operand->getType() == syntax::Node::Type::ArithmeticExpression)
        {
            obj->operands.push_back(checkArithmeticExpression(scopePrototype, *(static_cast<syntax::ArithmeticExpression*>(operand.get()))));
        }
        else
        {
            typedef syntax::Node::Type Type;
            Type nodeType = operand->getType();
            if (nodeType == Type::Number)
                obj->operands.push_back(this->checkLiteral(scopePrototype, *(static_cast<syntax::Literal*>(operand.get())), "float"));
            else if (nodeType == Type::Bool)
                obj->operands.push_back(this->checkLiteral(scopePrototype, *(static_cast<syntax::Literal*>(operand.get())), "bool"));
            else
            {
                MessageHandler::error(std::string("Invalid logical expression operand!"));
                FAIL;
                return nullptr;
            }
        }
    }

    return obj;
}
void processStmtNode(AST_NODE* stmtNode)
{
  switch(stmtNode->semantic_value.stmtSemanticValue.kind){
    case WHILE_STMT:
    {
      checkWhileStmt(stmtNode);
      break;
    }
    case FOR_STMT:
    {
      checkForStmt(stmtNode);
      break;
    }
    case IF_STMT:
    {
      checkIfStmt(stmtNode);
      break;
    }
    case ASSIGN_STMT:
    {
      checkAssignmentStmt(stmtNode);
      break;
    }
    case FUNCTION_CALL_STMT:
    {
      checkFunctionCall(stmtNode);
      break;
    }
    case RETURN_STMT:
    {
      checkReturnStmt(stmtNode);
      break;
    }
    default: 
    {
      assert(0);
    }
  }
}