Skip to content

Commit

Permalink
Add support for turning one keyword argument into a trailing optional…
Browse files Browse the repository at this point in the history
… in the DSL
  • Loading branch information
chrisseaton committed Nov 14, 2018
1 parent 47d61e6 commit 1812fdc
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/annotations/java/org/truffleruby/builtins/CoreMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@

int optional() default 0;

String keywordAsOptional() default "";

boolean rest() default false;

boolean needsBlock() default false;
Expand Down
28 changes: 23 additions & 5 deletions src/main/java/org/truffleruby/builtins/CoreMethodNodeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import org.truffleruby.language.RubyRootNode;
import org.truffleruby.language.Visibility;
import org.truffleruby.language.arguments.MissingArgumentBehavior;
import org.truffleruby.language.arguments.NotProvidedNode;
import org.truffleruby.language.arguments.ProfileArgumentNodeGen;
import org.truffleruby.language.arguments.ReadBlockNode;
import org.truffleruby.language.arguments.ReadKeywordArgumentNode;
import org.truffleruby.language.arguments.ReadPreArgumentNode;
import org.truffleruby.language.arguments.ReadRemainingArgumentsNode;
import org.truffleruby.language.arguments.ReadSelfNode;
Expand Down Expand Up @@ -138,18 +140,18 @@ private void addCoreMethod(DynamicObject module, MethodDetails methodDetails) {
verifyUsage(module, methodDetails, method, visibility);

final SharedMethodInfo sharedMethodInfo = makeSharedMethodInfo(context, module,
method.required(), method.optional(), method.rest(), names[0]);
method.required(), method.optional(), method.rest(), method.keywordAsOptional().isEmpty() ? null : method.keywordAsOptional(), names[0]);
final CallTarget callTarget = makeGenericMethod(context, methodDetails.getNodeFactory(), methodDetails.getMethodAnnotation(), sharedMethodInfo);

final boolean onSingleton = method.onSingleton() || method.constructor();
addMethods(module, method.isModuleFunction(), onSingleton, names, visibility, sharedMethodInfo, callTarget);
}

public void addLazyCoreMethod(String nodeFactoryName, String moduleName, Visibility visibility,
boolean isModuleFunction, boolean onSingleton, int required, int optional, boolean rest, String... names) {
boolean isModuleFunction, boolean onSingleton, int required, int optional, boolean rest, String keywordAsOptional, String... names) {
final DynamicObject module = getModule(moduleName);

final SharedMethodInfo sharedMethodInfo = makeSharedMethodInfo(context, module, required, optional, rest, names[0]);
final SharedMethodInfo sharedMethodInfo = makeSharedMethodInfo(context, module, required, optional, rest, keywordAsOptional, names[0]);

final RubyNode methodNode = new LazyRubyNode(() -> {
final NodeFactory<? extends RubyNode> nodeFactory = loadNodeFactory(nodeFactoryName);
Expand Down Expand Up @@ -216,13 +218,21 @@ private static void addMethod(RubyContext context, DynamicObject module, SharedM
}

private static SharedMethodInfo makeSharedMethodInfo(RubyContext context, DynamicObject module,
int required, int optional, boolean rest, String primaryName) {
int required, int optional, boolean rest, String keywordAsOptional, String primaryName) {
final LexicalScope lexicalScope = new LexicalScope(context.getRootLexicalScope(), module);

final Arity arity;

if (keywordAsOptional == null) {
arity = new Arity(required, optional, rest);
} else {
arity = new Arity(required, optional, rest, 0, new String[]{keywordAsOptional}, false);
}

return new SharedMethodInfo(
context.getCoreLibrary().getSourceSection(),
lexicalScope,
new Arity(required, optional, rest),
arity,
module,
primaryName,
0,
Expand Down Expand Up @@ -279,6 +289,14 @@ public static RubyNode createCoreMethodNode(NodeFactory<? extends RubyNode> node
argumentsNodes.add(new ReadBlockNode(NotProvided.INSTANCE));
}

if (!method.keywordAsOptional().isEmpty()) {
if (optional > 0) {
throw new UnsupportedOperationException();
}

argumentsNodes.add(new ReadKeywordArgumentNode(required, method.keywordAsOptional(), new NotProvidedNode()));
}

RubyNode node = createNodeFromFactory(nodeFactory, argumentsNodes);

final RubyNode checkArity = Translator.createCheckArityNode(sharedMethodInfo.getArity());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 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 1.0, or
* GNU General Public License version 2, or
* GNU Lesser General Public License version 2.1.
*/
package org.truffleruby.language.arguments;

import com.oracle.truffle.api.frame.VirtualFrame;
import org.truffleruby.language.NotProvided;
import org.truffleruby.language.RubyNode;

public class NotProvidedNode extends RubyNode {

@Override
public Object execute(VirtualFrame frame) {
return NotProvided.INSTANCE;
}

}
1 change: 1 addition & 0 deletions src/main/java/org/truffleruby/language/methods/Arity.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Arity(int preRequired, int optional, boolean hasRest) {
this(preRequired, optional, hasRest, 0, NO_KEYWORDS, false);
}


public Arity(int preRequired, int optional, boolean hasRest, int postRequired, String[] keywordArguments, boolean hasKeywordsRest) {
this.preRequired = preRequired;
this.optional = optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ private void processCoreMethod(TypeElement element) throws IOException {
method.required() + ", " +
method.optional() + ", " +
method.rest() + ", " +
(method.keywordAsOptional().isEmpty() ? "null" : quote(method.keywordAsOptional())) + ", " +
names + ");");
}

Expand Down

0 comments on commit 1812fdc

Please sign in to comment.