8145486: jjs should support documentation key shortcut in interactive mode

Reviewed-by: mhaupt, hannesw
This commit is contained in:
Athijegannathan Sundararajan 2015-12-16 16:42:03 +05:30
parent d8b6306e43
commit 2cee75db22
12 changed files with 217 additions and 26 deletions

View File

@ -59,6 +59,8 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_C
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SETTER_PREFIX;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_OBJECT;
@ -291,6 +293,13 @@ public class ClassGenerator {
mi.push(memInfo.getArity());
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
}
String doc = memInfo.getDocumentation();
if (doc != null) {
mi.dup();
mi.loadLiteral(memInfo.getDocumentation());
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION, SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
}
}
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {

View File

@ -42,6 +42,8 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_I
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETDOCUMENTATION_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
@ -159,6 +161,13 @@ public class ConstructorGenerator extends ClassGenerator {
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY,
SCRIPTFUNCTION_SETARITY_DESC);
}
final String doc = constructor.getDocumentation();
if (doc != null) {
mi.loadThis();
mi.loadLiteral(doc);
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETDOCUMENTATION,
SCRIPTFUNCTION_SETDOCUMENTATION_DESC);
}
}
mi.returnVoid();
mi.computeMaxs();

View File

@ -85,6 +85,8 @@ public final class MemberInfo implements Cloneable {
private MemberInfo.Kind kind;
// script property name
private String name;
// documentation for this member
private String documentation;
// script property attributes
private int attributes;
// name of the java member
@ -136,6 +138,20 @@ public final class MemberInfo implements Cloneable {
this.name = name;
}
/**
* @return the documentation
*/
public String getDocumentation() {
return documentation;
}
/**
* @param doc the documentation to set
*/
public void setDocumentation(final String doc) {
this.documentation = doc;
}
/**
* Tag something as specialized constructor or not
* @param isSpecializedConstructor boolean, true if specialized constructor

View File

@ -206,6 +206,7 @@ public class ScriptClassInfoCollector extends ClassVisitor {
// These could be "null" if values are not supplied,
// in which case we have to use the default values.
private String name;
private String documentation;
private Integer attributes;
private Integer arity;
private Where where;
@ -221,6 +222,13 @@ public class ScriptClassInfoCollector extends ClassVisitor {
if (name.isEmpty()) {
name = null;
}
break;
case "documentation":
this.documentation = (String)annotationValue;
if (documentation.isEmpty()) {
documentation = null;
}
break;
case "attributes":
this.attributes = (Integer)annotationValue;
@ -270,6 +278,8 @@ public class ScriptClassInfoCollector extends ClassVisitor {
} else {
memInfo.setName(name == null ? methodName : name);
}
memInfo.setDocumentation(documentation);
memInfo.setAttributes(attributes == null ? MemberInfo.DEFAULT_ATTRIBUTES : attributes);
memInfo.setArity((arity == null)? MemberInfo.DEFAULT_ARITY : arity);

View File

@ -118,6 +118,8 @@ public interface StringConstants {
static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName();
static final String SCRIPTFUNCTION_SETARITY = "setArity";
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
static final String SCRIPTFUNCTION_SETDOCUMENTATION = "setDocumentation";
static final String SCRIPTFUNCTION_SETDOCUMENTATION_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING);
static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
static final String SCRIPTFUNCTION_CREATEBUILTIN = "createBuiltin";

View File

@ -25,6 +25,7 @@
package jdk.nashorn.tools.jjs;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -34,21 +35,24 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import jdk.internal.jline.NoInterruptUnixTerminal;
import jdk.internal.jline.Terminal;
import jdk.internal.jline.TerminalFactory;
import jdk.internal.jline.TerminalFactory.Flavor;
import jdk.internal.jline.WindowsTerminal;
import jdk.internal.jline.console.ConsoleReader;
import jdk.internal.jline.console.KeyMap;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.history.FileHistory;
class Console implements AutoCloseable {
private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
private final ConsoleReader in;
private final FileHistory history;
Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
final Completer completer) throws IOException {
final Completer completer, final Function<String, String> docHelper) throws IOException {
TerminalFactory.registerFlavor(Flavor.WINDOWS, isCygwin()? JJSUnixTerminal::new : JJSWindowsTerminal::new);
TerminalFactory.registerFlavor(Flavor.UNIX, JJSUnixTerminal::new);
in = new ConsoleReader(cmdin, cmdout);
@ -58,6 +62,7 @@ class Console implements AutoCloseable {
in.setHistory(history = new FileHistory(historyFile));
in.addCompleter(completer);
Runtime.getRuntime().addShutdownHook(new Thread((Runnable)this::saveHistory));
bind(DOCUMENTATION_SHORTCUT, (ActionListener)evt -> showDocumentation(docHelper));
}
String readLine(final String prompt) throws IOException {
@ -138,4 +143,34 @@ class Console implements AutoCloseable {
private static boolean isCygwin() {
return System.getenv("SHELL") != null;
}
private void bind(String shortcut, Object action) {
KeyMap km = in.getKeys();
for (int i = 0; i < shortcut.length(); i++) {
final Object value = km.getBound(Character.toString(shortcut.charAt(i)));
if (value instanceof KeyMap) {
km = (KeyMap) value;
} else {
km.bind(shortcut.substring(i), action);
}
}
}
private void showDocumentation(final Function<String, String> docHelper) {
final String buffer = in.getCursorBuffer().buffer.toString();
final int cursor = in.getCursorBuffer().cursor;
final String doc = docHelper.apply(buffer.substring(0, cursor));
try {
if (doc != null) {
in.println();
in.println(doc);
in.redrawLine();
in.flush();
} else {
in.beep();
}
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@ -25,6 +25,9 @@
package jdk.nashorn.tools.jjs;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.io.BufferedReader;
import java.io.File;
@ -33,15 +36,21 @@ import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;
import jdk.internal.jline.console.completer.Completer;
import jdk.internal.jline.console.UserInterruptException;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.objects.NativeJava;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.tools.Shell;
@ -109,7 +118,32 @@ public final class Main extends Shell {
final PropertiesHelper propsHelper = new PropertiesHelper(env._classpath);
final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
try (final Console in = new Console(System.in, System.out, HIST_FILE, completer)) {
try (final Console in = new Console(System.in, System.out, HIST_FILE, completer,
str -> {
try {
final Object res = context.eval(global, str, global, "<shell>");
if (res != null && res != UNDEFINED) {
// Special case Java types: show the javadoc for the class.
if (NativeJava.isType(UNDEFINED, res)) {
final String typeName = NativeJava.typeName(UNDEFINED, res).toString();
final String url = typeName.replace('.', '/').replace('$', '.') + ".html";
openBrowserForJavadoc(url);
} else if (res instanceof NativeJavaPackage) {
final String pkgName = ((NativeJavaPackage)res).getName();
final String url = pkgName.replace('.', '/') + "/package-summary.html";
openBrowserForJavadoc(url);
} else if (res instanceof ScriptFunction) {
return ((ScriptFunction)res).getDocumentation();
}
// FIXME: better than toString for other cases?
return JSType.toString(res);
}
} catch (Exception ignored) {
}
return null;
})) {
if (globalChanged) {
Context.setGlobal(global);
}
@ -164,7 +198,7 @@ public final class Main extends Shell {
try {
final Object res = context.eval(global, source, global, "<shell>");
if (res != ScriptRuntime.UNDEFINED) {
if (res != UNDEFINED) {
err.println(toString(res, global));
}
} catch (final Exception exp) {
@ -218,7 +252,7 @@ public final class Main extends Shell {
final PrintWriter err, final boolean doe) {
try {
final Object res = context.eval(global, source, global, "<shell>");
if (res != ScriptRuntime.UNDEFINED) {
if (res != UNDEFINED) {
err.println(JSType.toString(res));
}
} catch (final Exception e) {
@ -228,4 +262,15 @@ public final class Main extends Shell {
}
}
}
// FIXME: needs to be changed to use javase 9 docs later
private static String JAVADOC_BASE = "http://download.java.net/jdk9/docs/api/";
private static void openBrowserForJavadoc(String relativeUrl) {
try {
final URI uri = new URI(JAVADOC_BASE + relativeUrl);
Desktop.getDesktop().browse(uri);
} catch (Exception ignored) {
}
}
}

View File

@ -148,7 +148,8 @@ public final class NativeObject {
* @param buf external buffer - should be a nio ByteBuffer
* @return the 'obj' object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "sets ByteBuffer to hold indexed data (nashorn extension)")
public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) {
Global.checkObject(obj);
final ScriptObject sobj = (ScriptObject)obj;
@ -168,7 +169,8 @@ public final class NativeObject {
* @param obj object to get prototype from
* @return the prototype of an object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "returns the prototype of the specified object")
public static Object getPrototypeOf(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).getProto();
@ -195,7 +197,8 @@ public final class NativeObject {
* @param proto prototype object to be used
* @return object whose prototype is set
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "sets the prototype of the given object (ES6)")
public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
if (obj instanceof ScriptObject) {
((ScriptObject)obj).setPrototypeOf(proto);
@ -216,7 +219,8 @@ public final class NativeObject {
* @param prop property descriptor
* @return property descriptor
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "returns a property descriptor for an own property (not inherited property)")
public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
if (obj instanceof ScriptObject) {
final String key = JSType.toString(prop);
@ -240,7 +244,8 @@ public final class NativeObject {
* @param obj object to query for property names
* @return array of property names
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "returns an array of all properties (enumerable or not) found directly on the given object")
public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
@ -258,7 +263,8 @@ public final class NativeObject {
* @param obj object to query for property names
* @return array of property names
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "returns an array of all symbol properties found directly on the given object (ES6)")
public static ScriptObject getOwnPropertySymbols(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return new NativeArray(((ScriptObject)obj).getOwnSymbols(true));
@ -276,7 +282,8 @@ public final class NativeObject {
* @param props properties to define
* @return object created
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "creates a new object with the specified prototype object and properties")
public static ScriptObject create(final Object self, final Object proto, final Object props) {
if (proto != null) {
Global.checkObject(proto);
@ -302,7 +309,8 @@ public final class NativeObject {
* @param attr attributes for property descriptor
* @return object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "adds an own property and/or update the attributes of an existing own property of an object")
public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
final ScriptObject sobj = Global.checkObject(obj);
sobj.defineOwnProperty(JSType.toPropertyKey(prop), attr, true);
@ -317,7 +325,8 @@ public final class NativeObject {
* @param props properties
* @return object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "defines new or modifies existing properties directly on the given object")
public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) {
final ScriptObject sobj = Global.checkObject(obj);
final Object propsObj = Global.toObject(props);
@ -339,7 +348,8 @@ public final class NativeObject {
* @param obj object to seal
* @return sealed object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "prevents new properties from being added to the given object and marks existing properties as non-configurable")
public static Object seal(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).seal();
@ -358,7 +368,8 @@ public final class NativeObject {
* @param obj object to freeze
* @return frozen object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "prevents new properties from being added to the given object and prevents existing properties from being removed or re-configured")
public static Object freeze(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).freeze();
@ -376,7 +387,8 @@ public final class NativeObject {
* @param obj object, for which to set the internal extensible property to false
* @return object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "prevents new properties from ever being added to the given object")
public static Object preventExtensions(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).preventExtensions();
@ -394,7 +406,8 @@ public final class NativeObject {
* @param obj check whether an object is sealed
* @return true if sealed, false otherwise
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "tells if an object is sealed or not")
public static boolean isSealed(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isSealed();
@ -412,7 +425,8 @@ public final class NativeObject {
* @param obj check whether an object
* @return true if object is frozen, false otherwise
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "tells if an object is fronzen or not")
public static boolean isFrozen(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isFrozen();
@ -430,7 +444,8 @@ public final class NativeObject {
* @param obj check whether an object is extensible
* @return true if object is extensible, false otherwise
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "tells if an object is extensible or not")
public static boolean isExtensible(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).isExtensible();
@ -448,7 +463,8 @@ public final class NativeObject {
* @param obj object from which to extract keys
* @return array of keys in object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "returns an array of the given object's own enumerable properties")
public static ScriptObject keys(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject)obj;
@ -471,7 +487,7 @@ public final class NativeObject {
* @param value value of object to be instantiated
* @return the new NativeObject
*/
@Constructor
@Constructor(documentation = "creates a new script object or converts given value as a script object")
public static Object construct(final boolean newObj, final Object self, final Object value) {
final JSType type = JSType.ofNoFunction(value);
@ -505,7 +521,8 @@ public final class NativeObject {
* @param self self reference
* @return ToString of object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
@Function(attributes = Attribute.NOT_ENUMERABLE,
documentation = "returns a string representing of this object")
public static String toString(final Object self) {
return ScriptRuntime.builtinObjectToString(self);
}
@ -558,7 +575,8 @@ public final class NativeObject {
* @param v property to check for
* @return true if property exists in object
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
@Function(attributes = Attribute.NOT_ENUMERABLE,
documentation = "tells whether this object has the specified property or not")
public static boolean hasOwnProperty(final Object self, final Object v) {
// Convert ScriptObjects to primitive with String.class hint
// but no need to convert other primitives to string.
@ -575,7 +593,8 @@ public final class NativeObject {
* @param v v prototype object to check against
* @return true if object is prototype of v
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
@Function(attributes = Attribute.NOT_ENUMERABLE,
documentation = "tests for this object in another object's prototype chain")
public static boolean isPrototypeOf(final Object self, final Object v) {
if (!(v instanceof ScriptObject)) {
return false;
@ -601,7 +620,8 @@ public final class NativeObject {
* @param v property to check if enumerable
* @return true if property is enumerable
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
@Function(attributes = Attribute.NOT_ENUMERABLE,
documentation = "tells whether the given property is enumerable or not")
public static boolean propertyIsEnumerable(final Object self, final Object v) {
final String str = JSType.toString(v);
final Object obj = Global.toObject(self);
@ -676,7 +696,8 @@ public final class NativeObject {
* @param source the source object whose properties are bound to the target
* @return the target object after property binding
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR,
documentation = "binds the source object's properties to the target object (nashorn extension)")
public static Object bindProperties(final Object self, final Object target, final Object source) {
// target object has to be a ScriptObject
final ScriptObject targetObj = Global.checkObject(target);

View File

@ -48,4 +48,9 @@ public @interface Constructor {
* arity.
*/
public int arity() default -2;
/**
* @return the documentation string for this constructor.
*/
public String documentation() default "";
}

View File

@ -60,4 +60,9 @@ public @interface Function {
* @return where this function lives.
*/
public Where where() default Where.PROTOTYPE;
/**
* @return return the documentation string for this function.
*/
public String documentation() default "";
}

View File

@ -645,6 +645,24 @@ public class ScriptFunction extends ScriptObject {
}
/**
* Get the documentation for this function
*
* @return the documentation
*/
public final String getDocumentation() {
return data.getDocumentation();
}
/**
* Set the documentation for this function
*
* @param doc documentation String for this function
*/
public final void setDocumentation(final String doc) {
data.setDocumentation(doc);
}
/**
* Get the name for this function
*

View File

@ -70,6 +70,9 @@ public abstract class ScriptFunctionData implements Serializable {
// value, the function might still be capable of receiving variable number of arguments, see isVariableArity.
private int arity;
// this may be null, if not available
private String documentation;
/**
* A pair of method handles used for generic invoker and constructor. Field is volatile as it can be initialized by
* multiple threads concurrently, but we still tolerate a race condition in it as all values stored into it are
@ -118,6 +121,10 @@ public abstract class ScriptFunctionData implements Serializable {
return arity;
}
final String getDocumentation() {
return documentation != null? documentation : toSource();
}
final boolean isVariableArity() {
return (flags & IS_VARIABLE_ARITY) != 0;
}
@ -137,6 +144,15 @@ public abstract class ScriptFunctionData implements Serializable {
this.arity = arity;
}
/**
* Used from nasgen generated code.
*
* @param doc documentation for this function
*/
void setDocumentation(final String doc) {
this.documentation = doc;
}
CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);