From c6df4413f18302759a71601795a7669e87dc5892 Mon Sep 17 00:00:00 2001 From: ecmel Date: Thu, 30 May 2024 13:31:41 +0300 Subject: [PATCH 1/2] update package-lock --- package-lock.json | 4 ++-- package.json | 13 ------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6236a62..f899e7a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kdb", - "version": "1.5.0", + "version": "1.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kdb", - "version": "1.5.0", + "version": "1.5.1", "license": "MIT", "dependencies": { "@types/graceful-fs": "^4.1.9", diff --git a/package.json b/package.json index 11ff6281..5dcf1d5a 100644 --- a/package.json +++ b/package.json @@ -35,20 +35,7 @@ "onCommand:kdb.newConnection.createNewInsightConnection", "onCommand:kdb.newConnection.createNewConnection", "onCommand:kdb.newConnection.createNewBundledConnection", - "onCommand:kdb.removeConnection", - "onCommand:kdb.connect", - "onCommand:kdb.active.connection", - "onCommand:kdb.disconnect", - "onCommand:kdb.addAuthentication", - "onCommand:kdb.enableTLS", - "onCommand:kdb.resultsPanel.update", - "onCommand:kdb.resultsPanel.clear", - "onCommand:kdb.resultsPanel.export.csv", - "onCommand:kdb.datasource.import.ds", - "onView:kdb-servers", - "onView:kdb-query-history", "onView:kdb-datasources-explorer", - "onView:kdb-results", "onTerminalProfile:kdb.q-terminal", "onLanguage:python" ], From 7de4870986263edb8ea9f4c9952a99fc18ff33f9 Mon Sep 17 00:00:00 2001 From: ecmel Date: Tue, 4 Jun 2024 18:36:51 +0300 Subject: [PATCH 2/2] fixes KXI-47774 --- server/src/linter/checks.ts | 9 +++-- server/src/parser/language.ts | 7 +++- server/src/parser/lexer.ts | 4 ++- server/src/parser/parser.ts | 67 +++++++++++++++++++++++++++++++---- server/src/parser/tokens.ts | 7 +++- server/src/parser/utils.ts | 6 ++++ syntaxes/q.tmLanguage.json | 8 +++-- test/suite/parser.test.ts | 20 +++++++++++ 8 files changed, 112 insertions(+), 16 deletions(-) diff --git a/server/src/linter/checks.ts b/server/src/linter/checks.ts index de3c735f..06f5d4ce 100644 --- a/server/src/linter/checks.ts +++ b/server/src/linter/checks.ts @@ -22,6 +22,7 @@ import { inLambda, inParam, ordered, + qualified, } from "../parser"; export function deprecatedDatetime(tokens: Token[]): Token[] { @@ -41,7 +42,6 @@ export function unusedParam(tokens: Token[]): Token[] { !tokens.find( (target) => !assigned(target) && - assignable(target) && inLambda(target) === inLambda(token) && identifier(target) === identifier(token), ), @@ -51,15 +51,15 @@ export function unusedParam(tokens: Token[]): Token[] { export function unusedVar(tokens: Token[]): Token[] { return tokens.filter( (token) => - !amended(token) && !inParam(token) && + !amended(token) && + !qualified(token) && inLambda(token) && assigned(token) && assignable(token) && !tokens.find( (target) => !assigned(target) && - assignable(target) && inLambda(target) === inLambda(token) && identifier(target) === identifier(token), ), @@ -70,8 +70,8 @@ export function declaredAfterUse(tokens: Token[]): Token[] { return tokens .filter( (token) => - !inParam(token) && !amended(token) && + !qualified(token) && assigned(token) && assignable(token), ) @@ -87,7 +87,6 @@ export function declaredAfterUse(tokens: Token[]): Token[] { tokens.find( (target) => !assigned(target) && - assignable(target) && inLambda(target) === inLambda(token) && identifier(target) === identifier(token) && ordered(target, token), diff --git a/server/src/parser/language.ts b/server/src/parser/language.ts index 4b2d81fc..1c0a2e48 100644 --- a/server/src/parser/language.ts +++ b/server/src/parser/language.ts @@ -37,6 +37,7 @@ import { StringEscape, TestBlock, TestLambdaBlock, + Cond, } from "./tokens"; import { TokenType } from "chevrotain"; import { writeFileSync } from "fs"; @@ -208,6 +209,10 @@ const repository = { name: "keyword.other.iterator.q", match: _(Iterator), }, + { + name: "keyword.operator.arithmetic.q", + match: _(Comparator), + }, { name: "punctuation.assignment.q", match: _(DoubleColon), @@ -218,7 +223,7 @@ const repository = { }, { name: "keyword.operator.arithmetic.q", - match: _(Comparator), + match: _(Cond), }, { name: "punctuation.assignment.q", diff --git a/server/src/parser/lexer.ts b/server/src/parser/lexer.ts index 918dcea0..5c9028aa 100644 --- a/server/src/parser/lexer.ts +++ b/server/src/parser/lexer.ts @@ -57,6 +57,7 @@ import { TestBlock, CommentEndOfLine, TestLambdaBlock, + Cond, } from "./tokens"; import { CommentEnd, @@ -89,9 +90,10 @@ const Language = [ Reserved, Identifier, Iterator, + Comparator, DoubleColon, Operator, - Comparator, + Cond, Colon, SemiColon, LParen, diff --git a/server/src/parser/parser.ts b/server/src/parser/parser.ts index fb49b651..ac4bc60f 100644 --- a/server/src/parser/parser.ts +++ b/server/src/parser/parser.ts @@ -31,11 +31,16 @@ import { TestLambdaBlock, Colon, DoubleColon, + Iterator, + Operator, + Cond, } from "./tokens"; import { CommentBegin, CommentEnd, ExitCommentBegin, + StringBegin, + StringEnd, TestBegin, } from "./ranges"; import { CharLiteral, CommentLiteral } from "./literals"; @@ -68,6 +73,7 @@ function peek(tokens: Token[]): Token | undefined { interface State { order: number; + exprs: number; stack: Token[]; } @@ -76,6 +82,7 @@ function assignment(state: State, token: Token) { if (inParam(token)) { token.assignment = [token, token]; + token.order = 1; } else { let top = peek(stack); if (top?.tokenType === Colon || top?.tokenType === DoubleColon) { @@ -88,8 +95,8 @@ function assignment(state: State, token: Token) { } } stack.push(token); + token.order = state.order++; } - token.order = state.order++; } function block(state: State, tokens: Token[], scopped = true) { @@ -162,6 +169,7 @@ function expression(state: State, tokens: Token[]) { case LParen: case LCurly: case Control: + case Cond: case Colon: case DoubleColon: case SemiColon: @@ -193,6 +201,7 @@ export function parse(text: string): Token[] { const state: State = { order: 1, + exprs: 1, stack: [], }; @@ -214,6 +223,7 @@ export function parse(text: string): Token[] { } scope.push(token); cache.push(token); + token.exprs = state.exprs; break; case TestBegin: case TestBlock: @@ -223,6 +233,7 @@ export function parse(text: string): Token[] { case LSql: scope.push(token); cache.push(token); + token.exprs = state.exprs; break; case RParen: case RBracket: @@ -231,14 +242,39 @@ export function parse(text: string): Token[] { next = scope.pop(); if (next) { cache.push(token); + token.exprs = state.exprs; + } + break; + case StringBegin: + scope.push(token); + cache.push(token); + token.exprs = state.exprs; + token.escaped = '\\"'; + break; + case StringEnd: + next = scope.pop(); + if (next) { + cache.push(token); + token.exprs = state.exprs; + token.escaped = '\\"'; } break; case SemiColon: + token.exprs = state.exprs; if (token.scope) { cache.push(token); } else { expression(state, cache); + state.exprs++; + } + break; + case Operator: + case Iterator: + if (token.image.startsWith("\\")) { + token.escaped = `\\${token.image}`; } + cache.push(token); + token.exprs = state.exprs; break; case EndOfLine: next = tokens[i + 1]; @@ -250,7 +286,28 @@ export function parse(text: string): Token[] { } else { expression(state, cache); } + token.escaped = ";"; + token.exprs = state.exprs; + state.exprs++; + } else if (token.scope?.tokenType === StringBegin) { + token.exprs = state.exprs; + } + break; + case StringEscape: + checkEscape(token); + if (token.image === '\\"' || token.image === "\\\\") { + token.escaped = `\\\\${token.image}`; + } + token.exprs = state.exprs; + break; + case CharLiteral: + token.exprs = state.exprs; + break; + case WhiteSpace: + if (token.scope?.tokenType !== StringBegin) { + token.escaped = " "; } + token.exprs = state.exprs; break; case Command: { const [cmd, arg] = token.image.split(/[ \t]+/, 2); @@ -261,16 +318,14 @@ export function parse(text: string): Token[] { } break; } + token.exprs = state.exprs; + token.escaped = `system \\"${token.image.slice(1)}\\"`; break; } - case StringEscape: - checkEscape(token); - break; - case CharLiteral: - break; default: if (isExpression(token)) { cache.push(token); + token.exprs = state.exprs; } break; } diff --git a/server/src/parser/tokens.ts b/server/src/parser/tokens.ts index 1a60b604..05c58ad2 100644 --- a/server/src/parser/tokens.ts +++ b/server/src/parser/tokens.ts @@ -81,7 +81,12 @@ export const Comparator = createToken({ export const Operator = createToken({ name: "Operator", - pattern: /[\\.,'|^$?!#@&_%*+-]/, + pattern: /[\\.,'|^?!#@&_%*+-]/, +}); + +export const Cond = createToken({ + name: "Cond", + pattern: /\$/, }); export const Colon = createToken({ diff --git a/server/src/parser/utils.ts b/server/src/parser/utils.ts index 4ceeb26e..9b78b8cf 100644 --- a/server/src/parser/utils.ts +++ b/server/src/parser/utils.ts @@ -30,6 +30,8 @@ export const enum SyntaxError { export interface Token extends IToken { index?: number; order?: number; + exprs?: number; + escaped?: string; namespace?: string; scope?: Token; tangled?: Token; @@ -137,6 +139,10 @@ export function local(token: Token, tokens: Token[]) { ); } +export function qualified(token: Token) { + return token.image.startsWith("."); +} + export function ordered(token: Token, next: Token) { return (token.order && next.order && next.order > token.order) || false; } diff --git a/syntaxes/q.tmLanguage.json b/syntaxes/q.tmLanguage.json index 4306b64a..4757e320 100644 --- a/syntaxes/q.tmLanguage.json +++ b/syntaxes/q.tmLanguage.json @@ -182,17 +182,21 @@ "name": "keyword.other.iterator.q", "match": "[\\\\'/]:" }, + { + "name": "keyword.operator.arithmetic.q", + "match": "(?:<=|>=|<>|[>=<~])" + }, { "name": "punctuation.assignment.q", "match": "::" }, { "name": "keyword.operator.arithmetic.q", - "match": "[\\\\.,'|^$?!#@&_%*+-]" + "match": "[\\\\.,'|^?!#@&_%*+-]" }, { "name": "keyword.operator.arithmetic.q", - "match": "(?:<=|>=|<>|[>=<~])" + "match": "\\$" }, { "name": "punctuation.assignment.q", diff --git a/test/suite/parser.test.ts b/test/suite/parser.test.ts index 0f19a57a..bfcc631e 100644 --- a/test/suite/parser.test.ts +++ b/test/suite/parser.test.ts @@ -59,6 +59,11 @@ describe("TSQLint", () => { assert.strictEqual(result.length, 1); assert.strictEqual(result[0].code, "UNUSED_PARAM"); }); + it("should not lint unusedParam", () => { + const text = "{[a];([]b:a)}"; + const result = lint(parse(text)); + assert.strictEqual(result.length, 0); + }); it("should lint unusedVar", () => { const text = "{a:1}"; const result = lint(parse(text)); @@ -70,6 +75,16 @@ describe("TSQLint", () => { const result = lint(parse(text)); assert.strictEqual(result.length, 0); }); + it("should not lint unusedVar", () => { + const text = "{a:1;([]b:a)}"; + const result = lint(parse(text)); + assert.strictEqual(result.length, 0); + }); + it("should not lint unusedVar", () => { + const text = "{.foo.a:1}"; + const result = lint(parse(text)); + assert.strictEqual(result.length, 0); + }); it("should lint declaredAfterUse", () => { const text = "a;a:1"; const result = lint(parse(text)); @@ -96,4 +111,9 @@ describe("TSQLint", () => { const result = lint(parse(text)); assert.strictEqual(result.length, 0); }); + it("should not lint declaredAfterUse", () => { + const text = "{[a]a;a:1}"; + const result = lint(parse(text)); + assert.strictEqual(result.length, 0); + }); });