@Override
  public IBoundNode bindTarget(ISyntaxNode node, IBindingContext bindingContext, IBoundNode target)
      throws Exception {

    int childrenCount = node.getNumberOfChildren();

    if (childrenCount < 1) {
      BindHelper.processError("New node should have at least one subnode", node, bindingContext);

      return new ErrorBoundNode(node);
    }

    ISyntaxNode lastNode = node.getChild(childrenCount - 1);

    String methodName = ((IdentifierNode) lastNode).getIdentifier();

    IBoundNode[] children = bindChildren(node, bindingContext, 0, childrenCount - 1);
    IOpenClass[] types = getTypes(children);

    IMethodCaller methodCaller =
        MethodSearch.getMethodCaller(methodName, types, bindingContext, target.getType());

    if (methodCaller == null) {

      StringBuilder buf = new StringBuilder("Method ");
      MethodUtil.printMethod(methodName, types, buf);
      buf.append(" not found in '").append(target.getType().getName()).append("'");

      BindHelper.processError(buf.toString(), node, bindingContext, false);

      return new ErrorBoundNode(node);
    }

    if (target.isStaticTarget() != methodCaller.getMethod().isStatic()) {

      if (methodCaller.getMethod().isStatic()) {
        BindHelper.processWarn(
            "Access of a static method from non-static object", node, bindingContext);
      } else {
        BindHelper.processError(
            "Access of a non-static method from a static object", node, bindingContext);

        return new ErrorBoundNode(node);
      }
    }

    MethodBoundNode result = new MethodBoundNode(node, children, methodCaller, target);
    result.setTargetNode(target);

    return result;
  }
  /**
   * 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;
  }