/*
 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package org.graalvm.tools.api.lsp;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.GenerateLibrary;
import com.oracle.truffle.api.library.GenerateLibrary.Abstract;
import com.oracle.truffle.api.library.Library;
import com.oracle.truffle.api.library.LibraryFactory;

LSP-specific message library.
Since:1.0
/** * LSP-specific message library. * * @since 1.0 */
@GenerateLibrary(receiverType = TruffleObject.class, assertions = LSPLibrary.Asserts.class) public abstract class LSPLibrary extends Library { static final LibraryFactory<LSPLibrary> FACTORY = LibraryFactory.resolve(LSPLibrary.class);
Get the documentation information about an object. The returned object is either a String, or an object providing MarkupContent protocol interface, with two members kind and value. The kind is a String literal of the markup kind, either plaintext, or markdown. The value is the documentation String. If the kind is markdown, then the value can contain fenced code blocks like in GitHub issues. When just a String is returned, plaintext kind is assumed.
/** * Get the documentation information about an object. The returned object is either a String, or * an object providing <code>MarkupContent</code> protocol interface, with two members * <code>kind</code> and <code>value</code>. The <code>kind</code> is a String literal of the * markup kind, either <code>plaintext</code>, or <code>markdown</code>. The <code>value</code> * is the documentation String. If the kind is <code>markdown</code>, then the value can contain * fenced code blocks like in GitHub issues. When just a String is returned, * <code>plaintext</code> kind is assumed. */
@Abstract @SuppressWarnings("unused") public Object getDocumentation(Object object) throws UnsupportedMessageException { CompilerDirectives.transferToInterpreter(); throw UnsupportedMessageException.create(); }
Get the signature information about object representing a callable. The returned object has a structure that corresponds to SignatureInformation protocol interface. The TruffleLanguage.toString(Object, Object) should provide the String representation of the signature, displayed as a label.

Description of properties of the returned object:

  • documentation - Either a String providing the callable documentation, or an object providing MarkupContent, see getDocumentation(Object) for details.
  • parameters - An array of objects representing the ParameterInformation protocol interface describing parameters of the callable signature. Every ParameterInformation object has following properties:
    • label - String label of this parameter (a substring of its containing signature label), or an integer array of size 2 providing inclusive start and exclusive end offsets within its containing signature label. The intended use case is to highlight the parameter label part in the signature label.
    • documentation - Either a String providing the parameter documentation, or an object providing MarkupContent, see getDocumentation(Object) for details.
/** * Get the signature information about object representing a callable. The returned object has a * structure that corresponds to <code>SignatureInformation<code> protocol interface. The * <code>TruffleLanguage.toString(Object, Object)</code> should provide the String * representation of the signature, displayed as a label. * <p> * Description of properties of the returned object: * <ul> * <li><b><code>documentation</code></b> - Either a String providing the callable documentation, * or an object providing <code>MarkupContent</code>, see {@link #getDocumentation(Object)} for * details.</li> * <li><b><code>parameters</code></b> - An array of objects representing the * <code>ParameterInformation</code> protocol interface describing parameters of the callable * signature. Every <code>ParameterInformation</code> object has following properties: * <ul> * <li><b><code>label</code></b> - String label of this parameter (a substring of its containing * signature label), or an integer array of size 2 providing inclusive start and exclusive end * offsets within its containing signature label. The intended use case is to highlight the * parameter label part in the signature label.</li> * <li><b><code>documentation</code></b> - Either a String providing the parameter * documentation, or an object providing <code>MarkupContent</code>, see * {@link #getDocumentation(Object)} for details.</li> * </ul> * </ul> */
@Abstract @SuppressWarnings("unused") public Object getSignature(Object object) throws UnsupportedMessageException { CompilerDirectives.transferToInterpreter(); throw UnsupportedMessageException.create(); } LSPLibrary() { } public static LibraryFactory<LSPLibrary> getFactory() { return FACTORY; } static class Asserts extends LSPLibrary { @Child private LSPLibrary delegate; Asserts(LSPLibrary delegate) { this.delegate = delegate; } @Override public boolean accepts(Object receiver) { assert receiver != null; return delegate.accepts(receiver); } @Override public Object getDocumentation(Object object) throws UnsupportedMessageException { assert object != null; Object doc = delegate.getDocumentation(object); assert isDocumentation(doc) : "Wrong documentation of " + object + " : " + doc; return doc; } @Override public Object getSignature(Object object) throws UnsupportedMessageException { assert InteropLibrary.getFactory().getUncached().isExecutable(object) : "Expecting an executable, got " + object; Object signature = delegate.getSignature(object); assert isSignature(signature) : "Wrong signature of " + object + " : " + signature; return signature; } private static boolean isDocumentation(Object doc) { if (doc instanceof String) { return true; } InteropLibrary interop = InteropLibrary.getFactory().getUncached(); assert doc instanceof TruffleObject; return interop.isMemberInvocable(doc, "markdown") || interop.isMemberInvocable(doc, "plaintext"); } @CompilerDirectives.TruffleBoundary private static boolean isSignature(Object signature) { InteropLibrary interop = InteropLibrary.getFactory().getUncached(); assert signature instanceof TruffleObject; try { if (interop.isMemberReadable(signature, "documentation")) { if (!isDocumentation(interop.readMember(signature, "documentation"))) { assert false : "Wrong documentation of signature " + signature; return false; } } if (interop.isMemberReadable(signature, "parameters")) { Object parameters = interop.readMember(signature, "parameters"); assert interop.hasArrayElements(parameters) : "Parameters of " + signature + " is not an array"; long size = interop.getArraySize(parameters); for (long i = 0; i < size; i++) { assert interop.isArrayElementReadable(parameters, i); Object param = interop.readArrayElement(parameters, i); assert interop.isMemberReadable(param, "label"); Object label = interop.readMember(param, "label"); assert label instanceof String || interop.hasArrayElements(label); if (interop.hasArrayElements(label)) { long rangeSize = interop.getArraySize(label); assert 2 == rangeSize : "Label range must be an array of size 2, but was " + rangeSize; Object l1 = interop.readArrayElement(label, 0); Object l2 = interop.readArrayElement(label, 1); assert interop.fitsInInt(l1) && interop.fitsInInt(l2); // int i1 = interop.asInt(l1); // int i2 = interop.asInt(l2); // assert 0 <= i1 && i1 <= i2 && i2 <= signatureLabel.length(); } if (interop.isMemberReadable(param, "documentation")) { if (!isDocumentation(interop.readMember(signature, "documentation"))) { assert false : "Wrong documentation of parameter " + param + " of signature " + signature; return false; } } } } } catch (InteropException ex) { throw new AssertionError("Checking signature " + signature, ex); } return true; } } }