Skip to content

Commit 2ed0598

Browse files
authored
Splits parsing of statements (#171)
1 parent 2bdb081 commit 2ed0598

File tree

13 files changed

+331
-235
lines changed

13 files changed

+331
-235
lines changed

package-lock.json

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { CompletionItem } from 'vscode-languageserver-types';
22

33
import { DbSchema } from '../dbSchema';
4-
import { findLatestStatement } from '../helpers';
54
import { parserWrapper } from '../parserWrapper';
65
import { completionCoreCompletion } from './completionCoreCompletions';
76

87
export function autocomplete(
98
textUntilPosition: string,
109
dbSchema: DbSchema,
10+
// TODO Add caret index here
1111
): CompletionItem[] {
12-
let parsingResult = parserWrapper.parse(textUntilPosition);
12+
const parsingResult = parserWrapper.parse(textUntilPosition);
1313
/* We try to locate the latest statement by finding the latest available `;`
1414
in the query and take from that point to the end of the query
1515
@@ -22,11 +22,10 @@ export function autocomplete(
2222
If there was no ;, we don't want to reparse, so we return undefined
2323
inside findLatestStatement
2424
*/
25-
26-
const lastStatement = findLatestStatement(parsingResult);
27-
if (lastStatement != undefined) {
28-
parsingResult = parserWrapper.parse(lastStatement);
25+
const lastStatement = parsingResult.statementsParsing.at(-1);
26+
if (lastStatement !== undefined) {
27+
return completionCoreCompletion(lastStatement, dbSchema);
2928
}
3029

31-
return completionCoreCompletion(parsingResult, dbSchema);
30+
return [];
3231
}

packages/language-support/src/autocompletion/completionCoreCompletions.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ import {
1717
lexerSymbols,
1818
tokenNames,
1919
} from '../lexerSymbols';
20-
import {
21-
consoleCommandEnabled,
22-
EnrichedParsingResult,
23-
ParsingResult,
24-
} from '../parserWrapper';
20+
21+
import { ParsedStatement } from '../parserWrapper';
22+
23+
import { consoleCommandEnabled } from '../parserWrapper';
2524

2625
const uniq = <T>(arr: T[]) => Array.from(new Set(arr));
2726

@@ -284,7 +283,7 @@ function calculateNamespacePrefix(
284283
}
285284

286285
export function completionCoreCompletion(
287-
parsingResult: EnrichedParsingResult,
286+
parsingResult: ParsedStatement,
288287
dbSchema: DbSchema,
289288
): CompletionItem[] {
290289
const parser = parsingResult.parser;
@@ -482,7 +481,7 @@ export function completionCoreCompletion(
482481
}
483482

484483
type CompletionHelperArgs = {
485-
parsingResult: ParsingResult;
484+
parsingResult: ParsedStatement;
486485
dbSchema: DbSchema;
487486
candidateRule: CandidateRule;
488487
};

packages/language-support/src/helpers.ts

+67-30
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import CypherParser, {
1212
RelationshipPatternContext,
1313
StatementsOrCommandsContext,
1414
} from './generated-parser/CypherCmdParser';
15-
import { ParsingResult } from './parserWrapper';
15+
import { ParsedStatement, ParsingResult } from './parserWrapper';
1616

1717
/* In antlr we have
1818
@@ -92,35 +92,6 @@ type AntlrDefaultExport = {
9292
};
9393
export const antlrUtils = antlrDefaultExport as unknown as AntlrDefaultExport;
9494

95-
export function findLatestStatement(
96-
parsingResult: ParsingResult,
97-
): undefined | string {
98-
const tokens = parsingResult.tokens;
99-
const lastTokenIndex = tokens.length - 1;
100-
101-
let tokenIndex = lastTokenIndex;
102-
let found = false;
103-
let lastStatement: undefined | string = undefined;
104-
105-
// Last token is always EOF
106-
while (tokenIndex > 0 && !found) {
107-
tokenIndex--;
108-
found = tokens[tokenIndex].type == CypherLexer.SEMICOLON;
109-
}
110-
111-
if (found) {
112-
lastStatement = '';
113-
114-
tokenIndex += 1;
115-
while (tokenIndex < lastTokenIndex) {
116-
lastStatement += tokens.at(tokenIndex)?.text ?? '';
117-
tokenIndex++;
118-
}
119-
}
120-
121-
return lastStatement;
122-
}
123-
12495
export function inNodeLabel(stopNode: ParserRuleContext) {
12596
const nodePattern = findParent(
12697
stopNode,
@@ -139,6 +110,72 @@ export function inRelationshipType(stopNode: ParserRuleContext) {
139110
return isDefined(relPattern);
140111
}
141112

113+
export function findCaret(
114+
parsingResult: ParsingResult,
115+
caretPosition: number,
116+
): { statement: ParsedStatement; token: Token } | undefined {
117+
const statements = parsingResult.statementsParsing;
118+
let i = 0;
119+
let result: { statement: ParsedStatement; token: Token } = undefined;
120+
let keepLooking = true;
121+
122+
while (i < statements.length && keepLooking) {
123+
let j = 0;
124+
const statement = statements[i];
125+
const tokens = statement.tokens;
126+
127+
while (j < tokens.length && keepLooking) {
128+
const currentToken = tokens[j];
129+
keepLooking = currentToken.start < caretPosition;
130+
131+
if (currentToken.channel === 0 && keepLooking) {
132+
result = { statement: statement, token: currentToken };
133+
}
134+
135+
j++;
136+
}
137+
i++;
138+
}
139+
140+
return result;
141+
}
142+
143+
export function splitIntoStatements(
144+
tokenStream: CommonTokenStream,
145+
lexer: CypherLexer,
146+
): CommonTokenStream[] {
147+
tokenStream.fill();
148+
const tokens = tokenStream.tokens;
149+
150+
let i = 0;
151+
const result: CommonTokenStream[] = [];
152+
let chunk: Token[] = [];
153+
let offset = 0;
154+
155+
while (i < tokens.length) {
156+
const current = tokens[i].clone();
157+
current.tokenIndex -= offset;
158+
159+
chunk.push(current);
160+
161+
if (
162+
current.type === CypherLexer.SEMICOLON ||
163+
current.type === CypherLexer.EOF
164+
) {
165+
// This does not relex since we are not calling fill on the token stream
166+
const tokenStream = new CommonTokenStream(lexer);
167+
tokenStream.tokens = chunk;
168+
result.push(tokenStream);
169+
offset = i + 1;
170+
chunk = [];
171+
}
172+
173+
i++;
174+
}
175+
176+
return result;
177+
}
178+
142179
export const rulesDefiningVariables = [
143180
CypherParser.RULE_returnItem,
144181
CypherParser.RULE_unwindClause,

0 commit comments

Comments
 (0)