Skip to content

Commit

Permalink
Move Refinement things to its own RefinementNodes node
Browse files Browse the repository at this point in the history
  • Loading branch information
itarato committed Jun 6, 2023
1 parent 77e1363 commit 0fa5fea
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 78 deletions.
77 changes: 0 additions & 77 deletions src/main/java/org/truffleruby/core/module/ModuleNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleString.ByteIndexOfStringNode;
import org.truffleruby.RubyContext;
import org.truffleruby.RubyLanguage;
import org.truffleruby.annotations.CoreMethod;
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
import org.truffleruby.builtins.CoreMethodNode;
Expand Down Expand Up @@ -2467,73 +2466,6 @@ private RubyModule newRefinementModule(RubyModule namespace, RubyModule moduleTo

}

@Primitive(name = "refinement_import_methods")
public abstract static class ImportMethodsNode extends PrimitiveArrayArgumentsNode {

@TruffleBoundary
@Specialization
protected RubyModule importMethods(RubyModule refinement, RubyModule moduleToImportFrom) {
var firstNonRubyMethod = getFirstNonRubyMethodOrNull(moduleToImportFrom, getLanguage());
if (firstNonRubyMethod != null) {
throw new RaiseException(getContext(),
coreExceptions().argumentError(createErrorMessage(firstNonRubyMethod, moduleToImportFrom),
this));
}

importMethodsFromModuleToRefinement(moduleToImportFrom, refinement);

return refinement;
}

private String createErrorMessage(InternalMethod method, RubyModule module) {
return StringUtils.format("Can't import method which is not defined with Ruby code: %s#%s",
module.getName(), method.getName());
}

private void importMethodsFromModuleToRefinement(RubyModule module, RubyModule refinement) {
var declarationContext = createDeclarationContextWithRefinement(refinement);
for (InternalMethod methodToCopy : module.fields.getMethods()) {
var clonedMethod = cloneMethod(methodToCopy, declarationContext, refinement);
refinement.fields.addMethod(getContext(), this, clonedMethod);
}
}

private InternalMethod getFirstNonRubyMethodOrNull(RubyModule module, RubyLanguage language) {
for (InternalMethod method : module.fields.getMethods()) {
if (!method.isDefinedInRuby(language)) {
return method;
}
}

return null;
}

// Creates a declaration context which contains the refined methods from the given refinement
private DeclarationContext createDeclarationContextWithRefinement(RubyModule refinement) {
final Map<RubyModule, RubyModule[]> refinements = new HashMap<>();
refinements.put(refinement.fields.getRefinedModule(), new RubyModule[]{ refinement });
return new DeclarationContext(
Visibility.PUBLIC,
new FixedDefaultDefinee(refinement),
refinements);
}

private InternalMethod cloneMethod(InternalMethod method, DeclarationContext declarationContext,
RubyModule refinement) {
var clonedCallTarget = cloneCallTarget(method);
return method.withCallTargetAndDeclarationContextAndDeclarationModule(clonedCallTarget, declarationContext,
refinement);
}

private RootCallTarget cloneCallTarget(InternalMethod method) {
var rubyRootNode = (RubyRootNode) method.getCallTarget().getRootNode();
var clonedRootNode = rubyRootNode.cloneUninitialized();

return clonedRootNode.getCallTarget();
}
}


@GenerateUncached
@CoreMethod(names = "using", required = 1, visibility = Visibility.PRIVATE, alwaysInlined = true)
public abstract static class ModuleUsingNode extends UsingNode {
Expand Down Expand Up @@ -2584,13 +2516,4 @@ protected Object doClass(RubyClass rubyClass) {
return rubyClass.isSingleton;
}
}

@Primitive(name = "refined_class")
public abstract static class RefinedClassNode extends PrimitiveArrayArgumentsNode {

@Specialization
protected RubyModule refinedClass(RubyModule refinement) {
return refinement.fields.getRefinedModule();
}
}
}
108 changes: 108 additions & 0 deletions src/main/java/org/truffleruby/core/refinement/RefinementNodes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 2.0, or
* GNU General Public License version 2, or
* GNU Lesser General Public License version 2.1.
*/
package org.truffleruby.core.refinement;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.dsl.Specialization;
import org.truffleruby.RubyLanguage;
import org.truffleruby.annotations.CoreModule;
import org.truffleruby.annotations.Primitive;
import org.truffleruby.annotations.Visibility;
import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
import org.truffleruby.core.module.RubyModule;
import org.truffleruby.core.string.StringUtils;
import org.truffleruby.language.RubyRootNode;
import org.truffleruby.language.control.RaiseException;
import org.truffleruby.language.methods.DeclarationContext;
import org.truffleruby.language.methods.DeclarationContext.FixedDefaultDefinee;
import org.truffleruby.language.methods.InternalMethod;

import java.util.HashMap;
import java.util.Map;

@CoreModule(value = "Refinement", isClass = true)
public abstract class RefinementNodes {

@Primitive(name = "import_methods")
public abstract static class ImportMethodsNode extends PrimitiveArrayArgumentsNode {

@TruffleBoundary
@Specialization
protected RubyModule importMethods(RubyModule refinement, RubyModule moduleToImportFrom) {
var firstNonRubyMethod = getFirstNonRubyMethodOrNull(moduleToImportFrom, getLanguage());
if (firstNonRubyMethod != null) {
throw new RaiseException(getContext(),
coreExceptions().argumentError(createErrorMessage(firstNonRubyMethod, moduleToImportFrom),
this));
}

importMethodsFromModuleToRefinement(moduleToImportFrom, refinement);

return refinement;
}

private String createErrorMessage(InternalMethod method, RubyModule module) {
return StringUtils.format("Can't import method which is not defined with Ruby code: %s#%s",
module.getName(), method.getName());
}

private void importMethodsFromModuleToRefinement(RubyModule module, RubyModule refinement) {
var declarationContext = createDeclarationContextWithRefinement(refinement);
for (InternalMethod methodToCopy : module.fields.getMethods()) {
var clonedMethod = cloneMethod(methodToCopy, declarationContext, refinement);
refinement.fields.addMethod(getContext(), this, clonedMethod);
}
}

private InternalMethod getFirstNonRubyMethodOrNull(RubyModule module, RubyLanguage language) {
for (InternalMethod method : module.fields.getMethods()) {
if (!method.isDefinedInRuby(language)) {
return method;
}
}

return null;
}

// Creates a declaration context which contains the refined methods from the given refinement
private DeclarationContext createDeclarationContextWithRefinement(RubyModule refinement) {
final Map<RubyModule, RubyModule[]> refinements = new HashMap<>();
refinements.put(refinement.fields.getRefinedModule(), new RubyModule[]{ refinement });
return new DeclarationContext(
Visibility.PUBLIC,
new FixedDefaultDefinee(refinement),
refinements);
}

private InternalMethod cloneMethod(InternalMethod method, DeclarationContext declarationContext,
RubyModule refinement) {
var clonedCallTarget = cloneCallTarget(method);
return method.withCallTargetAndDeclarationContextAndDeclarationModule(clonedCallTarget, declarationContext,
refinement);
}

private RootCallTarget cloneCallTarget(InternalMethod method) {
var rubyRootNode = (RubyRootNode) method.getCallTarget().getRootNode();
var clonedRootNode = rubyRootNode.cloneUninitialized();

return clonedRootNode.getCallTarget();
}
}

@Primitive(name = "refined_class")
public abstract static class RefinedClassNode extends PrimitiveArrayArgumentsNode {

@Specialization
protected RubyModule refinedClass(RubyModule refinement) {
return refinement.fields.getRefinedModule();
}
}
}
2 changes: 1 addition & 1 deletion src/main/ruby/truffleruby/core/refinement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def import_methods(*modules)
if mod.ancestors.length > 1
warn("#{mod} has ancestors, but Refinement#import_methods doesn't import their methods", uplevel: 1)
end
Primitive.refinement_import_methods(self, mod)
Primitive.import_methods(self, mod)
end
self
end
Expand Down

0 comments on commit 0fa5fea

Please sign in to comment.