Example #1
0
  @CompilerDirectives.TruffleBoundary
  public void include(Node currentNode, DynamicObject module) {
    assert RubyGuards.isRubyModule(module);

    checkFrozen(currentNode);

    // If the module we want to include already includes us, it is cyclic
    if (ModuleOperations.includesModule(module, rubyModuleObject)) {
      throw new RaiseException(
          getContext().getCoreLibrary().argumentError("cyclic include detected", currentNode));
    }

    // We need to include the module ancestors in reverse order for a given inclusionPoint
    ModuleChain inclusionPoint = this;
    Deque<DynamicObject> modulesToInclude = new ArrayDeque<>();
    for (DynamicObject ancestor : Layouts.MODULE.getFields(module).ancestors()) {
      if (ModuleOperations.includesModule(rubyModuleObject, ancestor)) {
        if (isIncludedModuleBeforeSuperClass(ancestor)) {
          // Include the modules at the appropriate inclusionPoint
          performIncludes(inclusionPoint, modulesToInclude);
          assert modulesToInclude.isEmpty();

          // We need to include the others after that module
          inclusionPoint = parentModule;
          while (inclusionPoint.getActualModule() != ancestor) {
            inclusionPoint = inclusionPoint.getParentModule();
          }
        } else {
          // Just ignore this module, as it is included above the superclass
        }
      } else {
        modulesToInclude.push(ancestor);
      }
    }

    performIncludes(inclusionPoint, modulesToInclude);

    newVersion();
  }