public void relationalOperator() {
    ModuleEnvironment rightOperandType = _typeCheckingStack.pop();
    ModuleEnvironment leftOperandType = _typeCheckingStack.pop();
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (haveSameType(rightOperandType, leftOperandType, intType)) _typeCheckingStack.push(boolType);
    else throw new TypesOfRelationalOperatorsMustBeIntException();
  }
  private boolean isSubTypeOfBaseTypes() {
    ModuleEnvironment variableType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");
    ModuleEnvironment stringType = ApplicationMainSymbolTable.getModuleByName("string");

    return variableType.isSubtypeOf(boolType)
        || variableType.isSubtypeOf(intType)
        || variableType.isSubtypeOf(stringType);
  }
  public void equalityRelationOperators() {
    ModuleEnvironment rightOperandType = _typeCheckingStack.pop();
    ModuleEnvironment leftOperandType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");
    ModuleEnvironment stringType = ApplicationMainSymbolTable.getModuleByName("string");

    if (haveSameType(rightOperandType, leftOperandType, boolType)
        || haveSameType(rightOperandType, leftOperandType, intType)
        || haveSameType(rightOperandType, leftOperandType, stringType))
      _typeCheckingStack.push(boolType);
    else throw new TypesOfEqualityRelationOperatorsMustBeSameBaseTypesException();
  }
  public void conditionExpressionShouldBeBoolean() {
    ModuleEnvironment conditionExpressionType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (conditionExpressionType.isSubtypeOf(boolType) == false)
      throw new ConditionExpressionMustBeBooleanException();
  }
  public void unaryMinusOperator() {
    ModuleEnvironment unaryMinusOperandType = _typeCheckingStack.pop();
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");

    if (unaryMinusOperandType.isSubtypeOf(intType)) _typeCheckingStack.push(intType);
    else throw new TypeOfUnaryMinusOperatorMustBeIntException();
  }
  public void notOperator() {
    ModuleEnvironment operandType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (operandType.isSubtypeOf(boolType)) _typeCheckingStack.push(boolType);
    else throw new TypesOfBooleanOperatorsMustBeBooleanException();
  }
  public ArrayList<ModuleEnvironment> getAllChildren() {
    Collection<ModuleEnvironment> allModules = ApplicationMainSymbolTable.getAllModules().values();
    ArrayList<ModuleEnvironment> children = new ArrayList<ModuleEnvironment>();
    for (ModuleEnvironment module : allModules)
      if (module.getParentName().equals(getName())) children.add(module);

    return children;
  }
  public void checkArrayIndexType() {
    ModuleEnvironment arrayIndexType = _typeCheckingStack.pop();
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");

    if (arrayIndexType.isSubtypeOf(intType) == false) {
      _typeCheckingStack.pop();
      throw new ArrayIndexTypeMustBeIntException();
    }
  }
  private void binaryBooleanOperator() {
    ModuleEnvironment rightOperandType = _typeCheckingStack.pop();
    ModuleEnvironment leftOperandType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (rightOperandType.isSubtypeOf(boolType) && leftOperandType.isSubtypeOf(boolType))
      _typeCheckingStack.push(boolType);
    else throw new TypesOfBooleanOperatorsMustBeBooleanException();
  }
  public void endMethodCall() {
    ArrayList<ModuleEnvironment> parameterTypes = new ArrayList<ModuleEnvironment>();
    String calledMethodName = fetchParameteresAndMethodName(parameterTypes);

    Signature calledMethodSignature = fetchCalledMethodSignature(parameterTypes, calledMethodName);

    ModuleEnvironment methodReturnType =
        ApplicationMainSymbolTable.getModuleByName(calledMethodSignature.getReturnType());
    _typeCheckingStack.push(methodReturnType);
  }
  public void checkReturnType(Environment environment) {
    environment = getContainerMethodEnvironment(environment);

    ModuleEnvironment returnTypeStatement = getReturnTypeStatement();
    MethodEnvironment currentMethod = (MethodEnvironment) environment;
    ModuleEnvironment methodReturnType =
        ApplicationMainSymbolTable.getModuleByName(currentMethod.getReturnTypeName());

    if (returnTypeStatement.isSubtypeOf(methodReturnType) == false)
      throw new ReturnTypeMustBeSubTypeOfMethodReturnType();
  }
 public void setConstIntInput() {
   _typeCheckingStack.push(ApplicationMainSymbolTable.getModuleByName("int"));
 }
  private ModuleEnvironment getReturnTypeStatement() {
    if (_typeCheckingStack.size() == 0) return ApplicationMainSymbolTable.getModuleByName("void");

    return _typeCheckingStack.pop();
  }