diff --git a/src/server/navigation.ts b/src/server/navigation.ts index 9eb1bb7..6d28927 100644 --- a/src/server/navigation.ts +++ b/src/server/navigation.ts @@ -13,6 +13,7 @@ interface Definition { uri: string; cursor: Node; body: Node; + name: string | undefined; } interface Search { @@ -34,7 +35,6 @@ export function findMostSpecificNodeForPosition( node.end && position.line >= node.start[0] - 1 && position.line <= node.end[0] - 1 && - // position.line == node.start[0] - 1 && (position.line !== node.start[0] - 1 || position.character >= node.start[1]) && (position.line !== node.end[0] - 1 || @@ -46,9 +46,6 @@ export function findMostSpecificNodeForPosition( let nodeLines: number; let nodeChars: number; nodes.forEach((n: Node) => { - // if (ignoredAstNodes.includes(n.name)) { - // return; - // } const nLines = n.end![0] - n.start![0]; const nChars = n.end![1] - n.start![1]; if ( @@ -107,10 +104,12 @@ export function locationFromDefinition(definition: Definition) { return location; } -// TODO: refactor to use `findInPattern()` -function findNameInPattern(search: Search, pat: Node): Node | undefined { +function findNameInPattern( + search: Search, + pat: Node, +): [string, Node] | undefined { return findInPattern(pat, (name, node) => - name === search.name ? node : undefined, + name === search.name ? [name, node] : undefined, ); } @@ -147,7 +146,7 @@ export function findDefinition( if (!node) { return; } - const reference = { uri, node }; + const reference: Reference = { uri, node }; const importDefinition = followImport(context, reference); if (importDefinition) { return importDefinition; @@ -246,8 +245,10 @@ function followImport( return; } // Find the relevant field name - const field = matchNode(reference.node.parent?.parent, 'ObjP', () => - matchNode(reference.node, 'VarP', (name: string) => name), + const field = matchNode( + reference.node.parent?.parent, + 'ObjP', + () => reference.node.parent?.name, ); // Follow the module import return matchNode(importNode, 'ImportE', (path: string) => { @@ -275,18 +276,18 @@ function followImport( console.log('AST:', status.program.export.ast); return; } - const declaration = { - uri, - cursor: exportNode, - body: exportNode, - }; if (field) { return searchObject( - { uri: declaration.uri, node: declaration.body }, + { uri, node: exportNode }, { type: 'variable', name: field }, - ); // || declaration + ); } - return declaration; + return { + uri, + cursor: exportNode, + body: exportNode, + name: undefined, + }; }); } @@ -349,12 +350,13 @@ function searchDeclaration( ): Definition | undefined { return ( matchNode(dec, 'LetD', (pat: Node, body: Node) => { - const varNode = findNameInPattern(search, pat); + const [name, varNode] = findNameInPattern(search, pat) || []; return ( varNode && { uri: reference.uri, cursor: varNode, body, + name, } ); }) || @@ -364,6 +366,7 @@ function searchDeclaration( uri: reference.uri, cursor: dec, // TODO: cursor on variable name body, + name, } : undefined, ) || @@ -373,6 +376,7 @@ function searchDeclaration( uri: reference.uri, cursor: dec, // TODO: cursor on variable name body: dec, + name, } : undefined, ) @@ -391,6 +395,7 @@ function searchTypeBinding( uri: reference.uri, cursor: typ, // TODO: source location from `name` body: typ, + name, } : undefined, ) || @@ -400,6 +405,7 @@ function searchTypeBinding( uri: reference.uri, cursor: dec, // TODO: cursor on variable name body: dec, + name, } : undefined, ) @@ -430,6 +436,7 @@ function searchObject( uri: reference.uri, cursor: arg, body, + name, }, ) || matchNode(arg, 'DecField', (dec: Node) => @@ -458,12 +465,13 @@ function searchObject( }, ); if (!definition) { - const pat = findNameInPattern(search, arg); // Function parameters + const [name, pat] = findNameInPattern(search, arg) || []; // Function parameters if (pat) { definition = { uri: reference.uri, cursor: pat, body: pat, + name, }; } } diff --git a/src/server/server.ts b/src/server/server.ts index 9a2a98d..fd4dbbd 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1063,7 +1063,10 @@ connection.onHover((event) => { } if (docNode.name === 'Prog' && !docNode.doc) { // Get doc comment at top of file - return asNode(docNode.args?.[0])?.doc; + const doc = asNode(docNode.args?.[0])?.doc; + if (doc) { + return doc; + } } return docNode.doc; } @@ -1352,38 +1355,6 @@ connection.onRequest(TEST_FILE_REQUEST, async (event): Promise => { } else { throw new Error(`Invalid test mode: '${mode}'`); } - // else { - // const start = Date.now(); - // const wasiResult = motoko.wasm(virtualPath, 'wasi'); - // console.log('Compile time:', Date.now() - start); - - // const WebAssembly = (global as any).WebAssembly; - // const module = await ( - // WebAssembly.compileStreaming || WebAssembly.compile - // )(wasiResult.wasm); - // const WASI = require('wasi'); - // const wasi = new WASI({}); - // const inst = new WebAssembly.Instance(module, { - // wasi_unstable: wasi.exports, - // }); - // wasi.setMemory(inst.exports.memory); - // inst.exports._start(); - - // // if (exitCode !== 0) { - // // console.log(stdout); - // // console.error(stderr); - // // console.log('Exit code:', exitCode); - // // } - // // return { - // // passed: exitCode === 0, - // // stdout, - // // stderr, - // // }; - - // console.log(Object.keys(inst.exports)); /////// - - // return { passed: true, stdout: '', stderr: '' }; - // } } catch (err) { console.error(err); return { diff --git a/src/server/syntax.spec.ts b/src/server/syntax.spec.ts index d216362..b73d8d0 100644 --- a/src/server/syntax.spec.ts +++ b/src/server/syntax.spec.ts @@ -100,4 +100,11 @@ describe('syntax', () => { expectFields(prog.exportFields, [undefined]); expectWithFields(prog.exportFields[0].exp, ['a', 'b']); }); + test('object pattern with alias', () => { + const prog = parse( + 'module { let { a; b = c } = { a = "a"; b = "b" }; }', + ); + expectFields(prog.exportFields, [undefined]); + expectWithFields(prog.exportFields[0].exp, ['a', 'c']); + }); }); diff --git a/src/server/syntax.ts b/src/server/syntax.ts index 5d8e921..ec645f1 100644 --- a/src/server/syntax.ts +++ b/src/server/syntax.ts @@ -202,14 +202,8 @@ export function findInPattern( matchNode(pat, 'VarP', (name: string) => fn(name, pat)) || matchNode(pat, 'ObjP', (...args: Node[]) => { for (const field of args) { - const aliasNode = field.args![0] as Node; - const alias = matchNode( - aliasNode, - 'VarP', - (alias) => alias, - field.name, - ); - const result = fn(alias, pat); + const fieldPat = field.args![0] as Node; + const result = findInPattern(fieldPat, fn); if (result !== undefined) { return result; } diff --git a/src/server/utils.spec.ts b/src/server/utils.spec.ts index 78e1107..9a91dc9 100644 --- a/src/server/utils.spec.ts +++ b/src/server/utils.spec.ts @@ -2,18 +2,13 @@ import { getAbsoluteUri, getRelativeUri } from './utils'; describe('utils', () => { test('getRelativeUri', () => { - // expect(getRelativeUri('file:a/b/c', 'file:a')).toStrictEqual('..'); - // expect(getRelativeUri('file://a/b/c', 'file://a')).toStrictEqual('..'); expect(getRelativeUri('file:///a/b', 'file:///a')).toStrictEqual('..'); expect(getRelativeUri('mo:a/b', 'mo:a/b/c')).toStrictEqual('c'); expect(getRelativeUri('mo:a/b', 'mo:a/c')).toStrictEqual('c'); }); test('getAbsoluteUri', () => { expect(getAbsoluteUri('mo:a', 'b')).toStrictEqual('mo:a/b'); - // expect(getAbsoluteUri('file:a/b', '..')).toStrictEqual('file:a'); - // expect(getAbsoluteUri('file://a/b', '..')).toStrictEqual('file://a'); expect(getAbsoluteUri('file:///a/b', '..')).toStrictEqual('file:///a'); expect(getAbsoluteUri('mo:a/b', '../c')).toStrictEqual('mo:a/c'); - // expect(getAbsoluteUri('file:///a', 'mo:b')).toStrictEqual('mo:b'); }); });