final Arity arity = new Arity(required, optional, methodDetails.getMethodAnnotation().argumentsAsArray());
final List<RubyNode> argumentsNodes = new ArrayList<>();
if (needsSelf) {
RubyNode readSelfNode = new SelfNode(context, sourceSection);
if (methodDetails.getMethodAnnotation().lowerFixnumSelf()) {
readSelfNode = new FixnumLowerNode(readSelfNode);
}
argumentsNodes.add(readSelfNode);
}
if (methodDetails.getMethodAnnotation().argumentsAsArray()) {
argumentsNodes.add(new ReadAllArgumentsNode(context, sourceSection));
} else {
for (int n = 0; n < arity.getRequired() + arity.getOptional(); n++) {
RubyNode readArgumentNode = new ReadPreArgumentNode(context, sourceSection, n, MissingArgumentBehaviour.UNDEFINED);
if (ArrayUtils.contains(methodDetails.getMethodAnnotation().lowerFixnumParameters(), n)) {
readArgumentNode = new FixnumLowerNode(readArgumentNode);
}
argumentsNodes.add(readArgumentNode);
}
}
if (methodDetails.getMethodAnnotation().needsBlock()) {
argumentsNodes.add(new ReadBlockNode(context, sourceSection, UndefinedPlaceholder.INSTANCE));
}
final RubyNode methodNode = methodDetails.getNodeFactory().createNode(context, sourceSection, argumentsNodes.toArray(new RubyNode[argumentsNodes.size()]));
final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity);
final RubyNode block = SequenceNode.sequence(context, sourceSection, checkArity, methodNode);
final ExceptionTranslatingNode exceptionTranslatingNode = new ExceptionTranslatingNode(context, sourceSection, block);
return new RubyRootNode(context, sourceSection, null, sharedMethodInfo, exceptionTranslatingNode);
}