From 5ca4f0c6adec6ae0ca9429221d2b1d48b95f41f3 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 21 Feb 2022 14:35:08 +0100 Subject: [PATCH 1/9] Initial bits for integrating the LSP API. --- README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.ts | 21 ++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/README.md b/README.md index b1378a57..cbe75998 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,71 @@ The low-level API is as follows: For examples how to use them, please refer to the README of the above mentioned solc-js releases. +#### Language Server Mode + +Since version 0.8.11, the solidity compiler natively supports the +language server protocol. With solc-js, you can now use it as follows: + +```javascript +var solc = require('solc'); + +// Callback to be invoked when additional files have to be opened during +// source code analysis stage. +// +// This function behaves similar to the compilation file reader callback. +function fileReadCallback(path) +{ + if ('path' === 'file:///project/lib.sol') { + return { + contents: 'library L { function f() internal returns (uint) { return 7; } }'; + }; + } + else + return { error: 'File not found' }; +} + +// Put solcjs into LSP mode. +// Needs to be called only once before the actual LSP I/O calls. +solc.lspStart(fileReadCallback); + +// Send some LSP JSON-RPC message and optionally receive a reply. +var lspInitializationMessage = { + 'jsonrpc': '2.0', + 'method': 'initialize', + 'params': { + 'rootUri': 'file:///project/', + 'capabilities': { + 'textDocument': { + 'publishDiagnostics': {'relatedInformation': true} + }, + 'workspace': { + 'applyEdit': true, + 'configuration': true, + 'didChangeConfiguration': {'dynamicRegistration': true}, + 'workspaceEdit': {'documentChanges': true}, + 'workspaceFolders': true + } + } + } +}; +solc.lspSendReceive(JSON.stringify(lspInitializationMessage))); +solc.lspSendReceive(JSON.stringify({'jsonrpc': '2.0', 'method': 'initialized'})); + +// Now, with the LSP server, being set up the following +// can be called as often as needed. +function lspRoundtrip(jsonRpcInputObject) +{ + return JSON.parse(solc.lspSendReceive(JSON.stringify(jsonRpcInputObject))); +} +``` + +This is a low level API endpoint for use by language server clients, +such as Visual Studio Code, or any other editor. +In order to know what you can pass in and what can come out, +it is highly recommended to have a look at: + + https://microsoft.github.io/language-server-protocol/specification + ### Using with Electron **Note:** diff --git a/wrapper.ts b/wrapper.ts index 36c18d74..691832df 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -92,6 +92,25 @@ function setupMethods (soljson) { }; }; + let lspStart = null; + if ('_solidity_lsp_start' in soljson) { + const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'int', []); + lspStart = function (callbacks) { + return runWithCallbacks(callbacks, wrappedLspStart, []); + }; + } + + let lspSendReceive = null; + if ('_solidity_lsp_send_receive' in soljson) { + const wrappedLspSendReceive = soljson.cwrap('solidity_lsp_send_receive', 'string', ['string']); + lspSendReceive = function (input: String, callbacks) { + // We are reusing the `runWithCallbacks` function that was supposed to + // only receive _solidity_compile as second parameter. + // I may be wrong, but that should work analogous. + return runWithCallbacks(callbacks, wrappedLspSendReceive, [input]); + }; + } + // This calls compile() with args || cb const runWithCallbacks = function (callbacks, compile, args) { if (callbacks) { @@ -324,6 +343,8 @@ function setupMethods (soljson) { importCallback: compileJSONCallback !== null || compileStandard !== null, nativeStandardJSON: compileStandard !== null }, + lspStart: lspStart, + lspSendReceive: lspSendReceive, compile: compileStandardWrapper, // Loads the compiler of the given version from the github repository // instead of from the local filesystem. From 806856a3e4d34549f276f22ccc3a2ddfb286a1b4 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Wed, 23 Feb 2022 14:30:15 +0100 Subject: [PATCH 2/9] continued WIP-work on LSP bindings --- wrapper.ts | 76 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/wrapper.ts b/wrapper.ts index 691832df..fea86860 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -6,6 +6,15 @@ import * as semver from 'semver'; const Module = module.constructor as any; +interface ReadCallbackReply { + error?: string; + contents?: string +} + +interface Callbacks { + import(path: string): ReadCallbackReply; +} + function setupMethods (soljson) { let version; if ('_solidity_version' in soljson) { @@ -45,6 +54,7 @@ function setupMethods (soljson) { reset = soljson.cwrap('solidity_reset', null, []); } + // Copies the string at @p str to @p ptr. const copyToCString = function (str, ptr) { const length = soljson.lengthBytesUTF8(str); // This is allocating memory using solc's allocator. @@ -60,6 +70,58 @@ function setupMethods (soljson) { soljson.setValue(ptr, buffer, '*'); }; + const createWrappedLspSend = function() { + const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); + return function (input: String) { + let args = []; + args.push(JSON.stringify(input)); + return wrappedLspSend.apply(undefined, args); + }; + }; + + // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. + const createWrappedLspStart = function() { + const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); + return function (callbacks: Callbacks) { + let readCallback = callbacks.import; + assert(typeof readCallback === 'function', 'Invalid callback specified.'); + const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; + + const wrappedReadCallback = function (path: string, contents: string, error: string) { + // Calls the user-supplied file read callback and passes the return values + // accordingly to either @p contents or into @p error on failure. + const result = readCallback(copyFromCString(path)); + if (typeof result.contents === 'string') { + copyToCString(result.contents, contents); + } + if (typeof result.error === 'string') { + copyToCString(result.error, error); + } + }; + + const addFunction = soljson.addFunction || soljson.Runtime.addFunction; + const removeFunction = soljson.removeFunction || soljson.Runtime.removeFunction; + const wrappedFunctionId = addFunction(wrappedReadCallback, 'ii'); + + try { + // call solidity_lsp_start(callbacks) + let args = []; + args.push(wrappedFunctionId); + let output = wrappedLspStart.apply(undefined, args); + removeFunction(wrappedFunctionId); + return output; + } catch (e) { + removeFunction(wrappedFunctionId); + throw e; + } + // NOTE: We MUST NOT reset the compiler here. + // We instead could try to make sure to only release memory that is + // safe to be released. + // Probably by clearly defining semantics and memory lifetimes + // of output strings. + }; + }; + // This is to support multiple versions of Emscripten. // Take a single `ptr` and returns a `str`. const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; @@ -92,23 +154,15 @@ function setupMethods (soljson) { }; }; +// solc.lspStart(myCallbackHere); let lspStart = null; if ('_solidity_lsp_start' in soljson) { - const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'int', []); - lspStart = function (callbacks) { - return runWithCallbacks(callbacks, wrappedLspStart, []); - }; + lspStart = createWrappedLspStart(); } let lspSendReceive = null; if ('_solidity_lsp_send_receive' in soljson) { - const wrappedLspSendReceive = soljson.cwrap('solidity_lsp_send_receive', 'string', ['string']); - lspSendReceive = function (input: String, callbacks) { - // We are reusing the `runWithCallbacks` function that was supposed to - // only receive _solidity_compile as second parameter. - // I may be wrong, but that should work analogous. - return runWithCallbacks(callbacks, wrappedLspSendReceive, [input]); - }; + lspSendReceive = createWrappedLspSend(); } // This calls compile() with args || cb From 0a420229792bc7d2f7d0bbebb64969e723b5e735 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 7 Mar 2022 11:45:14 +0100 Subject: [PATCH 3/9] Restructure setupMethods. --- wrapper.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wrapper.ts b/wrapper.ts index fea86860..6066ff8f 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -397,8 +397,10 @@ function setupMethods (soljson) { importCallback: compileJSONCallback !== null || compileStandard !== null, nativeStandardJSON: compileStandard !== null }, - lspStart: lspStart, - lspSendReceive: lspSendReceive, + lsp: { + start: lspStart, + sendReceive: lspSendReceive + }, compile: compileStandardWrapper, // Loads the compiler of the given version from the github repository // instead of from the local filesystem. From da975f100bf058d305df5714253b9b6032078689 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 7 Mar 2022 11:48:09 +0100 Subject: [PATCH 4/9] README.md: linting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cbe75998..5ca2827b 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ an error, and keep re-running the compiler until all of them are resolved. Example: ```javascript -var solc = require('solc'); +const solc = require('solc'); var input = { language: 'Solidity', From c6d71e0fd48c6a17a422b5ac14f2d0568a3ffe5d Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 7 Mar 2022 12:09:34 +0100 Subject: [PATCH 5/9] some more refactors and review comment adaptions. --- README.md | 15 +++++++-------- common/interfaces.ts | 9 +++++++++ wrapper.ts | 24 ++++++++---------------- 3 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 common/interfaces.ts diff --git a/README.md b/README.md index 5ca2827b..5986fa95 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ Since version 0.8.11, the solidity compiler natively supports the language server protocol. With solc-js, you can now use it as follows: ```javascript -var solc = require('solc'); +const solc = require('solc'); // Callback to be invoked when additional files have to be opened during // source code analysis stage. @@ -223,16 +223,15 @@ function fileReadCallback(path) contents: 'library L { function f() internal returns (uint) { return 7; } }'; }; } - else - return { error: 'File not found' }; + return { error: 'File not found' }; } // Put solcjs into LSP mode. // Needs to be called only once before the actual LSP I/O calls. -solc.lspStart(fileReadCallback); +solc.lsp.start(fileReadCallback); // Send some LSP JSON-RPC message and optionally receive a reply. -var lspInitializationMessage = { +const lspInitializationMessage = { 'jsonrpc': '2.0', 'method': 'initialize', 'params': { @@ -251,14 +250,14 @@ var lspInitializationMessage = { } } }; -solc.lspSendReceive(JSON.stringify(lspInitializationMessage))); -solc.lspSendReceive(JSON.stringify({'jsonrpc': '2.0', 'method': 'initialized'})); +solc.lsp.sendReceive(JSON.stringify(lspInitializationMessage))); +solc.lsp.sendReceive(JSON.stringify({'jsonrpc': '2.0', 'method': 'initialized'})); // Now, with the LSP server, being set up the following // can be called as often as needed. function lspRoundtrip(jsonRpcInputObject) { - return JSON.parse(solc.lspSendReceive(JSON.stringify(jsonRpcInputObject))); + return JSON.parse(solc.lsp.sendReceive(JSON.stringify(jsonRpcInputObject))); } ``` diff --git a/common/interfaces.ts b/common/interfaces.ts new file mode 100644 index 00000000..d0972247 --- /dev/null +++ b/common/interfaces.ts @@ -0,0 +1,9 @@ +export interface ReadCallbackReply { + error?: string; + contents?: string +} + +export interface Callbacks { + import(path: string): ReadCallbackReply; +} + diff --git a/wrapper.ts b/wrapper.ts index 6066ff8f..f0edd36e 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -3,18 +3,10 @@ import { https } from 'follow-redirects'; import MemoryStream from 'memorystream'; import assert from 'assert'; import * as semver from 'semver'; +import { Callbacks } from './common/interfaces'; const Module = module.constructor as any; -interface ReadCallbackReply { - error?: string; - contents?: string -} - -interface Callbacks { - import(path: string): ReadCallbackReply; -} - function setupMethods (soljson) { let version; if ('_solidity_version' in soljson) { @@ -73,7 +65,7 @@ function setupMethods (soljson) { const createWrappedLspSend = function() { const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); return function (input: String) { - let args = []; + const args = []; args.push(JSON.stringify(input)); return wrappedLspSend.apply(undefined, args); }; @@ -81,15 +73,15 @@ function setupMethods (soljson) { // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. const createWrappedLspStart = function() { - const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); - return function (callbacks: Callbacks) { + const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); + return function (callbacks: Callbacks) { let readCallback = callbacks.import; assert(typeof readCallback === 'function', 'Invalid callback specified.'); const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; const wrappedReadCallback = function (path: string, contents: string, error: string) { - // Calls the user-supplied file read callback and passes the return values - // accordingly to either @p contents or into @p error on failure. + // Calls the user-supplied file read callback and passes the return values + // accordingly to either @p contents or into @p error on failure. const result = readCallback(copyFromCString(path)); if (typeof result.contents === 'string') { copyToCString(result.contents, contents); @@ -104,7 +96,7 @@ function setupMethods (soljson) { const wrappedFunctionId = addFunction(wrappedReadCallback, 'ii'); try { - // call solidity_lsp_start(callbacks) + // call solidity_lsp_start(callbacks) let args = []; args.push(wrappedFunctionId); let output = wrappedLspStart.apply(undefined, args); @@ -119,7 +111,7 @@ function setupMethods (soljson) { // safe to be released. // Probably by clearly defining semantics and memory lifetimes // of output strings. - }; + }; }; // This is to support multiple versions of Emscripten. From b482bd5008c28dfcef7a312cd385b98a5ce2718c Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 7 Mar 2022 12:17:45 +0100 Subject: [PATCH 6/9] wrapper.ts: simplify code a bit. --- wrapper.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/wrapper.ts b/wrapper.ts index f0edd36e..7a1b783c 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -63,6 +63,8 @@ function setupMethods (soljson) { }; const createWrappedLspSend = function() { + if (!('_solidity_lsp_send' in soljson)) + return null; const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); return function (input: String) { const args = []; @@ -73,6 +75,8 @@ function setupMethods (soljson) { // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. const createWrappedLspStart = function() { + if (!('_solidity_lsp_start' in soljson)) + return null; const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); return function (callbacks: Callbacks) { let readCallback = callbacks.import; @@ -146,17 +150,6 @@ function setupMethods (soljson) { }; }; -// solc.lspStart(myCallbackHere); - let lspStart = null; - if ('_solidity_lsp_start' in soljson) { - lspStart = createWrappedLspStart(); - } - - let lspSendReceive = null; - if ('_solidity_lsp_send_receive' in soljson) { - lspSendReceive = createWrappedLspSend(); - } - // This calls compile() with args || cb const runWithCallbacks = function (callbacks, compile, args) { if (callbacks) { @@ -390,8 +383,8 @@ function setupMethods (soljson) { nativeStandardJSON: compileStandard !== null }, lsp: { - start: lspStart, - sendReceive: lspSendReceive + start: createWrappedLspStart(), + sendReceive: createWrappedLspSend() }, compile: compileStandardWrapper, // Loads the compiler of the given version from the github repository From aa5463faaf69e4c12ee62809131924d2dced489d Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 7 Mar 2022 13:44:07 +0100 Subject: [PATCH 7/9] wrapper.ts: adds sendReceive() plus some function order changes. --- wrapper.ts | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/wrapper.ts b/wrapper.ts index 7a1b783c..177a83ca 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -62,17 +62,6 @@ function setupMethods (soljson) { soljson.setValue(ptr, buffer, '*'); }; - const createWrappedLspSend = function() { - if (!('_solidity_lsp_send' in soljson)) - return null; - const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); - return function (input: String) { - const args = []; - args.push(JSON.stringify(input)); - return wrappedLspSend.apply(undefined, args); - }; - }; - // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. const createWrappedLspStart = function() { if (!('_solidity_lsp_start' in soljson)) @@ -118,6 +107,36 @@ function setupMethods (soljson) { }; }; + // C signature : int solidity_lsp_send(char const* jsonRpcInputObject); + // TS signature : int send(object jsonRpcInputObject); + const createWrappedLspSend = function() { + if (!('_solidity_lsp_send' in soljson)) + return null; + const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); + return function (input: String) { + const args = []; + args.push(JSON.stringify(input)); + return wrappedLspSend.apply(undefined, args); + }; + }; + + // C signature : char* solidity_lsp_send_receive(char const* jsonRpcInputObject); + // TS signature : object sendReceive(object jsonRpcInputObject); + // + // sendReceive send one message to the LSP server (notification or method call). + // The method call may reply with zero or one message that is going to be returned. + const createWrappedLspSendReceive = function() { + if (!('_solidity_lsp_send_receive' in soljson)) + return null; + const wrappedLspSendReceive = soljson.cwrap('solidity_lsp_send_receive', 'string', ['string']); + return function (input: String) { + const args = []; + args.push(JSON.stringify(input)); + const reply = wrappedLspSendReceive.apply(undefined, args); + return JSON.parse(reply); + }; + }; + // This is to support multiple versions of Emscripten. // Take a single `ptr` and returns a `str`. const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; @@ -384,7 +403,8 @@ function setupMethods (soljson) { }, lsp: { start: createWrappedLspStart(), - sendReceive: createWrappedLspSend() + send: createWrappedLspSend(), + sendReceive: createWrappedLspSendReceive() }, compile: compileStandardWrapper, // Loads the compiler of the given version from the github repository From abaaa955a4b47dfb2a64179df9b1e5a855e2d4aa Mon Sep 17 00:00:00 2001 From: Stephen Lineker-Miller Date: Mon, 14 Mar 2022 12:46:56 +0000 Subject: [PATCH 8/9] simple refactor to resolve linting and legacy variables --- common/interfaces.ts | 5 +- wrapper.ts | 143 ++++++++++++++++++++++--------------------- 2 files changed, 76 insertions(+), 72 deletions(-) diff --git a/common/interfaces.ts b/common/interfaces.ts index d0972247..a22750b3 100644 --- a/common/interfaces.ts +++ b/common/interfaces.ts @@ -1,9 +1,8 @@ export interface ReadCallbackReply { error?: string; - contents?: string + contents?: string; } export interface Callbacks { - import(path: string): ReadCallbackReply; + import (path: string): ReadCallbackReply; } - diff --git a/wrapper.ts b/wrapper.ts index 177a83ca..2eb83946 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -62,79 +62,84 @@ function setupMethods (soljson) { soljson.setValue(ptr, buffer, '*'); }; - // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. - const createWrappedLspStart = function() { - if (!('_solidity_lsp_start' in soljson)) - return null; - const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); - return function (callbacks: Callbacks) { - let readCallback = callbacks.import; - assert(typeof readCallback === 'function', 'Invalid callback specified.'); - const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; - - const wrappedReadCallback = function (path: string, contents: string, error: string) { - // Calls the user-supplied file read callback and passes the return values - // accordingly to either @p contents or into @p error on failure. - const result = readCallback(copyFromCString(path)); - if (typeof result.contents === 'string') { - copyToCString(result.contents, contents); - } - if (typeof result.error === 'string') { - copyToCString(result.error, error); - } - }; - - const addFunction = soljson.addFunction || soljson.Runtime.addFunction; - const removeFunction = soljson.removeFunction || soljson.Runtime.removeFunction; - const wrappedFunctionId = addFunction(wrappedReadCallback, 'ii'); - - try { - // call solidity_lsp_start(callbacks) - let args = []; - args.push(wrappedFunctionId); - let output = wrappedLspStart.apply(undefined, args); - removeFunction(wrappedFunctionId); - return output; - } catch (e) { - removeFunction(wrappedFunctionId); - throw e; - } - // NOTE: We MUST NOT reset the compiler here. - // We instead could try to make sure to only release memory that is - // safe to be released. - // Probably by clearly defining semantics and memory lifetimes - // of output strings. - }; - }; - - // C signature : int solidity_lsp_send(char const* jsonRpcInputObject); - // TS signature : int send(object jsonRpcInputObject); - const createWrappedLspSend = function() { - if (!('_solidity_lsp_send' in soljson)) - return null; - const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); - return function (input: String) { - const args = []; - args.push(JSON.stringify(input)); - return wrappedLspSend.apply(undefined, args); + // Creates a wrapper around `int solidity_lsp_start(callbacks: Callbacks)`. + const createWrappedLspStart = function () { + if (!('_solidity_lsp_start' in soljson)) { + return () => { + throw new Error('lsp is not supported on this version.'); + }; + } + + const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); + + return function (callbacks: Callbacks) { + const readCallback = callbacks.import; + + assert(typeof readCallback === 'function', 'Invalid callback specified.'); + const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; + + const wrappedReadCallback = function (path: string, contents: string, error: string) { + // Calls the user-supplied file read callback and passes the return values + // accordingly to either @p contents or into @p error on failure. + const result = readCallback(copyFromCString(path)); + + if (typeof result.contents === 'string') { + copyToCString(result.contents, contents); + } + + if (typeof result.error === 'string') { + copyToCString(result.error, error); + } + }; + + const addFunction = soljson.addFunction || soljson.Runtime.addFunction; + const removeFunction = soljson.removeFunction || soljson.Runtime.removeFunction; + const wrappedFunctionId = addFunction(wrappedReadCallback, 'ii'); + + try { + // call solidity_lsp_start(callbacks) + const output = wrappedLspStart(wrappedFunctionId); + removeFunction(wrappedFunctionId); + return output; + } catch (e) { + removeFunction(wrappedFunctionId); + throw e; + } + + // NOTE: We MUST NOT reset the compiler here. + // We instead could try to make sure to only release memory that is safe + // to be released. Probably by clearly defining semantics and memory + // lifetimes of output strings. }; }; - // C signature : char* solidity_lsp_send_receive(char const* jsonRpcInputObject); - // TS signature : object sendReceive(object jsonRpcInputObject); - // - // sendReceive send one message to the LSP server (notification or method call). - // The method call may reply with zero or one message that is going to be returned. - const createWrappedLspSendReceive = function() { - if (!('_solidity_lsp_send_receive' in soljson)) - return null; + // C signature : int solidity_lsp_send(char const* jsonRpcInputObject); + // TS signature : int send(object jsonRpcInputObject); + const createWrappedLspSend = function () { + if (!('_solidity_lsp_send' in soljson)) { + return () => { + throw new Error('lsp is not supported on this version.'); + }; + } + + const wrappedLspSend = soljson.cwrap('solidity_lsp_send', 'number', ['string']); + return (input: string) => wrappedLspSend(JSON.stringify(input)); + }; + + // C signature : char* solidity_lsp_send_receive(char const* jsonRpcInputObject); + // TS signature : object sendReceive(object jsonRpcInputObject); + // + // sendReceive send one message to the LSP server (notification or method call). + // The method call may reply with zero or one message that is going to be returned. + const createWrappedLspSendReceive = function () { + if (!('_solidity_lsp_send_receive' in soljson)) { + return () => { + throw new Error('lsp is not supported on this version.'); + }; + } + const wrappedLspSendReceive = soljson.cwrap('solidity_lsp_send_receive', 'string', ['string']); - return function (input: String) { - const args = []; - args.push(JSON.stringify(input)); - const reply = wrappedLspSendReceive.apply(undefined, args); - return JSON.parse(reply); - }; + return (input: string) => JSON.parse(wrappedLspSendReceive(JSON.stringify(input))); }; // This is to support multiple versions of Emscripten. From 85a853e1516ccd77541938b166a9c82eabf064b6 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 14 Mar 2022 16:40:51 +0100 Subject: [PATCH 9/9] wrapper.ts: some QA updates. --- wrapper.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wrapper.ts b/wrapper.ts index 2eb83946..df47c21e 100755 --- a/wrapper.ts +++ b/wrapper.ts @@ -70,7 +70,7 @@ function setupMethods (soljson) { }; } - const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', []); + const wrappedLspStart = soljson.cwrap('solidity_lsp_start', 'number', ['number']); return function (callbacks: Callbacks) { const readCallback = callbacks.import; @@ -79,6 +79,8 @@ function setupMethods (soljson) { const copyFromCString = soljson.UTF8ToString || soljson.Pointer_stringify; const wrappedReadCallback = function (path: string, contents: string, error: string) { + console.log("wrappedReadCallback: \"" + path + "\""); + // Calls the user-supplied file read callback and passes the return values // accordingly to either @p contents or into @p error on failure. const result = readCallback(copyFromCString(path)); @@ -94,15 +96,15 @@ function setupMethods (soljson) { const addFunction = soljson.addFunction || soljson.Runtime.addFunction; const removeFunction = soljson.removeFunction || soljson.Runtime.removeFunction; - const wrappedFunctionId = addFunction(wrappedReadCallback, 'ii'); + const wrappedReadCallbackId = addFunction(wrappedReadCallback, 'ii'); try { // call solidity_lsp_start(callbacks) - const output = wrappedLspStart(wrappedFunctionId); - removeFunction(wrappedFunctionId); + const output = wrappedLspStart(wrappedReadCallbackId); + removeFunction(wrappedReadCallbackId); return output; } catch (e) { - removeFunction(wrappedFunctionId); + removeFunction(wrappedReadCallbackId); throw e; }