private void bindPropertiesForAllTables(
      XlsModuleSyntaxNode moduleNode,
      XlsModuleOpenClass module,
      OpenL openl,
      RulesModuleBindingContext bindingContext) {
    ASelector<ISyntaxNode> propertiesSelector = getSelector(XlsNodeTypes.XLS_PROPERTIES);
    ASelector<ISyntaxNode> otherNodesSelector = getSelector(XlsNodeTypes.XLS_OTHER);
    ISelector<ISyntaxNode> notPropertiesAndNotOtherSelector =
        propertiesSelector.not().and(otherNodesSelector.not());

    TableSyntaxNode[] tableSyntaxNodes = selectNodes(moduleNode, notPropertiesAndNotOtherSelector);

    PropertiesLoader propLoader = new PropertiesLoader(openl, bindingContext, module);
    for (TableSyntaxNode tsn : tableSyntaxNodes) {
      try {
        propLoader.loadProperties(tsn);
      } catch (SyntaxNodeException error) {
        processError(error, tsn, bindingContext);
      } catch (CompositeSyntaxNodeException ex) {
        for (SyntaxNodeException error : ex.getErrors()) {
          processError(error, tsn, bindingContext);
        }
      } catch (Throwable t) {
        SyntaxNodeException error = SyntaxNodeExceptionUtils.createError(t, tsn);
        processError(error, tsn, bindingContext);
      }
    }
  }
  /**
   * Common binding cycle.
   *
   * @param moduleNode
   * @param openl
   * @param moduleContext
   * @param moduleOpenClass
   * @param bindingContext
   * @return
   */
  private IBoundNode processBinding(
      XlsModuleSyntaxNode moduleNode,
      OpenL openl,
      RulesModuleBindingContext moduleContext,
      XlsModuleOpenClass moduleOpenClass,
      IBindingContext bindingContext) {

    IVocabulary vocabulary = makeVocabulary(moduleNode);

    if (vocabulary != null) {
      processVocabulary(vocabulary, moduleContext);
    }

    //
    // Selectors
    //
    ASelector<ISyntaxNode> propertiesSelector = getSelector(XlsNodeTypes.XLS_PROPERTIES);
    ASelector<ISyntaxNode> dataTypeSelector = getSelector(XlsNodeTypes.XLS_DATATYPE);

    ISelector<ISyntaxNode> notPropertiesAndNotDatatypeSelector =
        propertiesSelector.not().and(dataTypeSelector.not());

    ISelector<ISyntaxNode> spreadsheetSelector = getSelector(XlsNodeTypes.XLS_SPREADSHEET);
    ISelector<ISyntaxNode> testMethodSelector = getSelector(XlsNodeTypes.XLS_TEST_METHOD);
    ISelector<ISyntaxNode> runMethodSelector = getSelector(XlsNodeTypes.XLS_RUN_METHOD);

    ISelector<ISyntaxNode> commonTablesSelector =
        notPropertiesAndNotDatatypeSelector.and(
            spreadsheetSelector.not().and(testMethodSelector.not().and(runMethodSelector.not())));

    // Bind property node at first.
    //
    TableSyntaxNode[] propertiesNodes = selectNodes(moduleNode, propertiesSelector);
    bindInternal(moduleNode, moduleOpenClass, propertiesNodes, openl, moduleContext);

    bindPropertiesForAllTables(moduleNode, moduleOpenClass, openl, moduleContext);

    IBoundNode topNode = null;

    // Bind datatype nodes.
    TableSyntaxNode[] datatypeNodes = selectNodes(moduleNode, dataTypeSelector);

    /*
     * Processes datatype table nodes before the bind operation. Checks type
     * declarations and finds invalid using of inheritance feature at this
     * step.
     */
    TableSyntaxNode[] processedDatatypeNodes =
        new DatatypesSorter()
            .sort(
                datatypeNodes,
                moduleContext); // Rewrite this sorter with TableSyntaxNodeRelationsUtils

    bindInternal(moduleNode, moduleOpenClass, processedDatatypeNodes, openl, moduleContext);

    // Select nodes excluding Properties, Datatype, Spreadsheet, Test,
    // RunMethod tables
    TableSyntaxNode[] commonTables = selectNodes(moduleNode, commonTablesSelector);

    // Select and sort Spreadsheet tables
    TableSyntaxNode[] spreadsheets = selectSpreadsheetNodes(moduleNode, spreadsheetSelector);
    if (OpenLSystemProperties.isCustomSpreadsheetType(bindingContext.getExternalParams())) {
      try {
        spreadsheets =
            TableSyntaxNodeRelationsUtils.sort(
                spreadsheets, new SpreadsheetTableSyntaxNodeRelationsDeterminer());
      } catch (TableSyntaxNodeCircularDependencyException e) {
        for (TableSyntaxNode tsn : e.getTableSyntaxNodes()) {
          SyntaxNodeException error = SyntaxNodeExceptionUtils.createError(e, tsn);
          processError(error, tsn, moduleContext);
        }
      }
    }

    TableSyntaxNode[] commonAndSpreadsheetTables = ArrayUtils.addAll(commonTables, spreadsheets);
    bindInternal(moduleNode, moduleOpenClass, commonAndSpreadsheetTables, openl, moduleContext);

    // Select Test and RunMethod tables
    TableSyntaxNode[] runTables = selectNodes(moduleNode, runMethodSelector);
    bindInternal(moduleNode, moduleOpenClass, runTables, openl, moduleContext);

    TableSyntaxNode[] testTables = selectNodes(moduleNode, testMethodSelector);
    topNode = bindInternal(moduleNode, moduleOpenClass, testTables, openl, moduleContext);

    if (moduleOpenClass.isUseDescisionTableDispatcher()) {
      DispatcherTablesBuilder dispTableBuilder =
          new DispatcherTablesBuilder((XlsModuleOpenClass) topNode.getType(), moduleContext);
      dispTableBuilder.build();
    }

    ((XlsModuleOpenClass) topNode.getType()).setRulesModuleBindingContext(moduleContext);
    ((XlsModuleOpenClass) topNode.getType()).completeOpenClassBuilding();

    processErrors(moduleOpenClass.getErrors(), bindingContext);

    return topNode;
  }