pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/jruby/jruby/pull/9220/files

href="https://github.githubassets.com/assets/primer-primitives-10bf9dd67e3d70bd.css" /> Expand Signature to represent all metadata by headius · Pull Request #9220 · jruby/jruby · GitHub
Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 107 additions & 50 deletions core/src/main/java/org/jruby/runtime/Signature.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
package org.jruby.runtime;

import org.jruby.Ruby;
import org.jruby.RubySymbol;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.AssignableNode;
import org.jruby.ast.ForNode;
import org.jruby.ast.IterNode;
import org.jruby.ast.KeywordArgNode;
import org.jruby.ast.KeywordRestArgNode;
import org.jruby.ast.MultipleAsgnNode;
import org.jruby.ast.Node;
import org.jruby.ast.PostExeNode;
import org.jruby.ast.PreExeNode;
import org.jruby.ast.StarNode;
import org.jruby.ast.UnnamedRestArgNode;
import org.jruby.ast.types.INameNode;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.TypeConverter;

import java.util.ArrayList;

import static org.jruby.api.Error.argumentError;
import static org.jruby.runtime.Arity.UNLIMITED_ARGUMENTS;

/**
* A representation of a Ruby method signature (argument layout, min/max, keyword layout, rest args).
*/
public class Signature {
public record Signature(
short pre,
short opt,
short post,
Rest rest,
short kwargs,
short requiredKwargs,
int keyRest,
KeywordArgument[] keywordArguments,
int arityValue) {

public enum Rest {
NONE, NORM, ANON, STAR;

Expand All @@ -34,6 +51,11 @@ public static Rest fromOrdinal(int ordinal) {
}
}

public record KeywordArgument(String id, Type type) {
public static final KeywordArgument[] EMPTY_ARRAY = {};
public enum Type { OPTIONAL, REQUIRED, REST }
}

public static final Signature NO_ARGUMENTS = new Signature(0, 0, 0, Rest.NONE, 0, 0, -1);
public static final Signature ONE_ARGUMENT = new Signature(1, 0, 0, Rest.NONE, 0, 0, -1);
public static final Signature TWO_ARGUMENTS = new Signature(2, 0, 0, Rest.NONE, 0, 0, -1);
Expand All @@ -46,24 +68,20 @@ public static Rest fromOrdinal(int ordinal) {
public static final Signature FOUR_REQUIRED = new Signature(4, 0, 0, Rest.NORM, 0, 0, -1);
public static final Signature ONE_OPT_ARGUMENT = new Signature(0, 1, 0, Rest.NONE, 0, 0, -1);

private final short pre;
private final short opt;
private final Rest rest;
private final short post;
private final short kwargs;
private final short requiredKwargs;
private final int arityValue;
private final int keyRest;
public Signature(short pre, short opt, short post, Rest rest, short kwargs, short requiredKwargs, int keyRest, KeywordArgument[] keywordArguments) {
this(pre, opt, post, rest, kwargs, requiredKwargs, keyRest, keywordArguments, calculateArity(pre, opt, rest, post, kwargs, requiredKwargs, keyRest));
}

public Signature(short pre, short opt, short post, Rest rest, short kwargs, short requiredKwargs, int keyRest) {
this(pre, opt, post, rest, kwargs, requiredKwargs, keyRest, KeywordArgument.EMPTY_ARRAY);
}

public Signature(int pre, int opt, int post, Rest rest, int kwargs, int requiredKwargs, int keyRest) {
this.pre = (short) pre;
this.opt = (short) opt;
this.post = (short) post;
this.rest = rest;
this.kwargs = (short) kwargs;
this.requiredKwargs = (short) requiredKwargs;
this.keyRest = keyRest;
this.arityValue = calculateArityValue();
this((short) pre, (short) opt, (short) post, rest, (short) kwargs, (short) requiredKwargs, keyRest);
}

public Signature(int pre, int opt, int post, Rest rest, int kwargs, int requiredKwargs, int keyRest, KeywordArgument[] keywordArguments) {
this((short) pre, (short) opt, (short) post, rest, (short) kwargs, (short) requiredKwargs, keyRest, keywordArguments);
}

public int getRequiredKeywordForArityCount() {
Expand All @@ -74,13 +92,8 @@ public boolean restKwargs() {
return keyRest != -1;
}

public int pre() { return pre; }
public int opt() { return opt; }
public Rest rest() { return rest; }
public int post() { return post; }
public boolean hasKwargs() { return kwargs > 0 || restKwargs(); }
public boolean hasRest() { return rest != Rest.NONE; }
public int keyRest() { return keyRest; }

/**
* The minimum number of parameters supplied which can fulfill a call to this signature. This
Expand All @@ -103,14 +116,6 @@ public int max() {
-1 : required() + opt() + (kwargs() > 0 || restKwargs() ? 1 : 0);
}

/**
* Total number of keyword argument parameters.
* @return the number of kwarg parameters
*/
public int kwargs() {
return kwargs;
}

/**
* Are there an exact (fixed) number of parameters to this signature?
*/
Expand Down Expand Up @@ -155,29 +160,30 @@ public Arity arity() {
}
}

@Deprecated
public int calculateArityValue() {
return calculateArity(pre, opt, rest, post, kwargs, requiredKwargs, keyRest);
}

/**
* Best attempt at breaking the code of arity values! We figure out how many fixed/required parameters
* must be supplied. Then we figure out if we need to mark the value as optional. Optional is indicated
* by multiplying -1 * (fixed + 1). Keyword args optional and rest values can indicate this optional
* condition but only if no required keyword arguments are present.
*/
public int calculateArityValue() {
private static int calculateArity(short pre, short opt, Rest rest, short post, short kwargs, short requiredKwargs, int keyRest) {
int oneForKeywords = requiredKwargs > 0 ? 1 : 0;
int fixedValue = pre() + post() + oneForKeywords;
int fixedValue = pre + post + oneForKeywords;
boolean hasOptionalKeywords = kwargs - requiredKwargs > 0;
boolean optionalFromRest = rest() != Rest.NONE && rest != Rest.ANON;
boolean optionalFromRest = rest != Rest.NONE && rest != Rest.ANON;

if (opt() > 0 || optionalFromRest || fixedValue == 0 && (hasOptionalKeywords || restKwargs())) {
if (opt > 0 || optionalFromRest || fixedValue == 0 && (hasOptionalKeywords || keyRest != -1)) {
return -1 * (fixedValue + 1);
}

return fixedValue;
}

public int arityValue() {
return arityValue;
}

/**
* If we are yield'ing to this signature should we spread/destructure a Ruby Array?
*
Expand Down Expand Up @@ -225,7 +231,19 @@ public static Signature from(Arity arity) {
}

public static Signature from(int pre, int opt, int post, int kwargs, int requiredKwargs, Rest rest, int keyRest) {
if (opt == 0 && post == 0 && kwargs == 0 && keyRest == -1) {
return from(pre, opt, rest, post, kwargs, requiredKwargs, keyRest, KeywordArgument.EMPTY_ARRAY);
}

public static Signature from(int pre, int opt, Rest rest, int post, int kwargs, int requiredKwargs, int keyRest, KeywordArgument[] keywordArguments) {
if (kwargs == 0 && keyRest == -1) {
return positionalOnly(pre, opt, rest, post, kwargs, requiredKwargs, keyRest);
}

return new Signature(pre, opt, post, rest, kwargs, requiredKwargs, keyRest, keywordArguments);
}

private static Signature positionalOnly(int pre, int opt, Rest rest, int post, int kwargs, int requiredKwargs, int keyRest) {
if (opt == 0 && post == 0) {
switch (pre) {
case 0:
switch (rest) {
Expand Down Expand Up @@ -268,18 +286,29 @@ public static Signature from(int pre, int opt, int post, int kwargs, int require
}
break;
}
} else if (opt == 1 && pre == 0 && rest == Rest.NONE && post == 0 && kwargs == 0 && keyRest == -1) {
} else if (opt == 1 && pre == 0 && rest == Rest.NONE && post == 0) {
return Signature.ONE_OPT_ARGUMENT;
}

return new Signature(pre, opt, post, rest, kwargs, requiredKwargs, keyRest);
}

public static Signature from(ArgsNode args) {
ArgumentNode restArg = args.getRestArgNode();
Rest rest = restArg != null ? restFromArg(restArg) : Rest.NONE;

return Signature.from(args.getPreCount(), args.getOptionalArgsCount(), args.getPostCount(),
args.getKeywordCount(), args.getRequiredKeywordCount(),rest,args.hasKeyRest() ? args.getKeyRest().getIndex() : -1);
int keywordCount = args.getKeywordCount();
KeywordArgument[] keywordArguments = keywordArgumentsFromArgs(args);

return Signature.from(
args.getPreCount(),
args.getOptionalArgsCount(),
rest,
args.getPostCount(),
keywordCount,
args.getRequiredKeywordCount(),
args.hasKeyRest() ? args.getKeyRest().getIndex() : -1,
keywordArguments);
}

public static Signature from(IterNode iter) {
Expand All @@ -291,20 +320,48 @@ public static Signature from(IterNode iter) {
}

private static Rest restFromArg(Node restArg) {
Rest rest;
if (restArg instanceof UnnamedRestArgNode) {
UnnamedRestArgNode anonRest = (UnnamedRestArgNode) restArg;
if (restArg == null) return Rest.NONE;

if (restArg instanceof UnnamedRestArgNode anonRest) {
if (anonRest.isStar()) {
rest = Rest.STAR;
return Rest.STAR;
} else {
rest = Rest.ANON;
return Rest.ANON;
}
} else if (restArg instanceof StarNode) {
rest = Rest.STAR;
return Rest.STAR;
} else {
rest = Rest.NORM;
return Rest.NORM;
}
return rest;
}

private static KeywordArgument[] keywordArgumentsFromArgs(ArgsNode args) {
int kwargs = args.getKeywordCount();
if (kwargs == 0) return KeywordArgument.EMPTY_ARRAY;

var keywordArguments = new ArrayList<KeywordArgument>();
for (Node keywordArg : args.getKeywords()) {
if (keywordArg instanceof KeywordArgNode kwargNode) {
AssignableNode assignable = kwargNode.getAssignable();
RubySymbol name;
if (!(assignable instanceof INameNode namedAssign)) {
throw new RuntimeException("unexpected unnamed assignable");
}
name = namedAssign.getName();

if (assignable.getValueNode() != null) {
keywordArguments.add(new KeywordArgument(name.idString(), KeywordArgument.Type.OPTIONAL));
} else {
keywordArguments.add(new KeywordArgument(name.idString(), KeywordArgument.Type.REQUIRED));
}
}
}

if (args.getKeyRest() instanceof KeywordRestArgNode kwrestArg) {
keywordArguments.add(new KeywordArgument(kwrestArg.getName().idString(), KeywordArgument.Type.REST));
}

return keywordArguments.toArray(KeywordArgument[]::new);
}

public static Signature from(ForNode iter) {
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy