diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index d14ee86..76e64e2 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -29,12 +29,10 @@ jobs: - run: npm ci # For some reason, antlr4ng writes to a different location on the VM # than it does locally, preventing compile. Command added to move the generated files. - - run: npm run textMate - - name: npm run antlr + - name: npm run generate run: | - npm run antlr4ng - npm run antlr4ngPre - npm run antlr4ngFmt + npm run antlr + npm run build:textMate mv ./server/src/antlr/out/server/src/antlr/* ./server/src/antlr/out - run: npm run build - run: xvfb-run -a npm test diff --git a/contributing.md b/contributing.md index 9ab0689..a418c07 100644 --- a/contributing.md +++ b/contributing.md @@ -1,21 +1,19 @@ # Contributing -**Signed commits are turned on for this repo.** +This repository is under active development. Please ensure your contributions do not cause merge conflicts with the dev branch. ## Setup 1. Fork this repo -1. Install VS Code Extension [esBuild Problem Matchers](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers). -2. Install [Java](https://www.oracle.com/au/java/technologies/downloads/) >= 11 -3. Install [NPM](https://github.com/coreybutler/nvm-windows) -4. `npm install` to install dependencies. -5. `npm run textMate` first time and every time grammar is changed. -6. `npm run antlr` first time and every time grammar is changed. +2. Install VS Code Extension [esBuild Problem Matchers](https://marketplace.visualstudio.com/items?itemName=connor4312.esbuild-problem-matchers). +3. Install [Java](https://www.oracle.com/au/java/technologies/downloads/) >= 11 +4. Install [NPM](https://github.com/coreybutler/nvm-windows) +5. `npm install` to install dependencies. +6. `npm run test` to build and unit test. 7. Create a `.\sample` directory as a default workspace for client debugging (or update .\\.vscode\\launch.json as preferred). -7. (Optional) Install [ANTLR4 grammar syntax support](https://marketplace.visualstudio.com/items?itemName=mike-lischke.vscode-antlr4) VS Code extension. +8. (Optional) Install [ANTLR4 grammar syntax support](https://marketplace.visualstudio.com/items?itemName=mike-lischke.vscode-antlr4) VS Code extension. Note: to debug a grammar, you'll first need to activate the extension by opening one of the *.g4 files. To contribute, you'll need to [create a pull request from a fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). -**Signed commits are turned on for this repo.** ## Debugging Language Server @@ -41,10 +39,10 @@ Note the grammar file for this project can be found at /server/src/antlr/vba.g4 The grammar call graph is interesting, but not particularly useful. Generating "valid" input generates garbage. -### Run unit tests for TextMate grammar +## TextMate Snapshots -To verify that your changes haven't broken existing syntax or tests, and to ensure any new tests pass, run the following command: +Your edits to the TextMate grammar may cause changes to the snapshot. If these changes are expected and unit tested, update the snapshot. ``` -npm run tmUnitTest -``` \ No newline at end of file +npm run tmSnapUpdate +``` diff --git a/package.json b/package.json index 3d929c6..efadc8a 100644 --- a/package.json +++ b/package.json @@ -144,28 +144,26 @@ }, "scripts": { "vscode:prepublish": "npm run package", - "build": "npm run check-types && node esbuild.js", - "fullBuild": "npm run textMate && npm run antlr", - "build-test": "node esbuild.js --test", + "build": "npm-run-all -p build:* && npm run check-types && node esbuild.js", + "package": "npm-run-all -p build:* && npm run check-types && node esbuild.js --production", "check-types": "tsc --noEmit", "watch": "npm-run-all -p watch:*", "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", - "package": "npm run textMate && npm run antlr && npm run check-types && node esbuild.js --production", "lint": "eslint ./client/src ./server/src --ext .ts,.tsx", "postinstall": "cd client && npm install && cd ../server && npm install && cd ..", - "textMate": "npx js-yaml client/syntaxes/vba.tmLanguage.yaml > client/syntaxes/vba.tmLanguage.json && npm run tmSnapTest", - "antlr": "npm run antlr4ngPre && npm run antlr4ng && npm run antlr4ngFmt && npm run build", - "antlr4ng": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vba.g4 -o ./server/src/antlr/out/", - "antlr4ngPre": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vbapre.g4 -o ./server/src/antlr/out/", - "antlr4ngFmt": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vbafmt.g4 -o ./server/src/antlr/out/", - "test": "npm run tmSnapTest && npm run tmUnitTest && npm run vsctest", - "testsh": "sh ./scripts/e2e.sh", - "testps": "powershell ./scripts/e2e.ps1", - "tmUnitTest": "vscode-tmgrammar-test ./test/textmate/**/*.vba", - "tmSnapTest": "vscode-tmgrammar-snap ./test/textmate/snapshot/*.??s", + "build:textMate": "npx js-yaml client/syntaxes/vba.tmLanguage.yaml > client/syntaxes/vba.tmLanguage.json", + "antlr": "npm-run-all -p build:antlr*", + "build:antlr": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vba.g4 -o ./server/src/antlr/out/", + "build:antlrPre": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vbapre.g4 -o ./server/src/antlr/out/", + "build:antlrFmt": "antlr4ng -Dlanguage=TypeScript -visitor ./server/src/antlr/vbafmt.g4 -o ./server/src/antlr/out/", "tmSnapUpdate": "vscode-tmgrammar-snap --updateSnapshot ./test/textmate/snapshot/*.??s", - "vsctest": "npm run build-test && vscode-test" + "test": "npm run build && npm-run-all -p test:*:*", + "test:textMate:unit": "vscode-tmgrammar-test ./test/textmate/**/*.vba", + "test:textMate:snap": "vscode-tmgrammar-snap ./test/textmate/snapshot/*.??s", + "test:vsc:unit": "vscode-test", + "testsh": "sh ./scripts/e2e.sh", + "testps": "powershell ./scripts/e2e.ps1" }, "dependencies": { "antlr4ng": "^3.0.16", @@ -189,4 +187,4 @@ "typescript": "^5.8.3", "vscode-tmgrammar-test": "^0.1.3" } -} +} \ No newline at end of file diff --git a/server/src/antlr/vbapre.g4 b/server/src/antlr/vbapre.g4 index 760b037..60e92a3 100644 --- a/server/src/antlr/vbapre.g4 +++ b/server/src/antlr/vbapre.g4 @@ -11,13 +11,78 @@ startRule ; document - : (documentLines | compilerIfBlock)* + : (documentLines | compilerIfBlock | constDirectiveStatement)* ; documentLines : (anyOtherLine | endOfLine)+ ; +constDirectiveName + : ANYCHARS + ; + +directiveParenthesizedExpression + : '(' WS? directiveExpression WS? ')' + ; + +directiveLiteralExpression + : LITDATE + | LITFLOAT + | LITINTEGER + | LITSTRING + | literalIdentifier + ; + +literalIdentifier + : booleanLiteralIdentifier + | objectLiteralIdentifier + | variantLiteralIdentifier + ; + +booleanLiteralIdentifier + : TRUE + | FALSE + ; + +objectLiteralIdentifier + : NOTHING + ; + +variantLiteralIdentifier + : EMPTY_X + | NULL_ + ; + +// Operators +orderOfOps1: DIVD | MULT; +orderOfOps2: MOD; +orderOfOps3: PLUS | SUBT; +orderOfOps4: AMP; +orderOfOps5: LIKE | (LT | GT)? (LT | GT | EQ) | EQ; +orderOfOps6: AND | OR | XOR | EQV | IMP; + + +directiveExpression + : directiveLiteralExpression + | directiveParenthesizedExpression + | directiveExpression WS? orderOfOps1 WS? directiveExpression + | directiveExpression WS? orderOfOps2 WS? directiveExpression + | directiveExpression WS? orderOfOps3 WS? directiveExpression + | directiveExpression WS? orderOfOps4 WS? directiveExpression + | directiveExpression WS? orderOfOps5 WS? directiveExpression + | notDirectiveExpression + | directiveExpression WS? orderOfOps6 WS? directiveExpression + | unreservedWord + ; + +notDirectiveExpression + : NOT WS directiveExpression; + +constDirectiveStatement + : CONST WS constDirectiveName WS? EQ WS? directiveExpression endOfStatement + ; + compilerIfBlock : compilerConditionalBlock+ compilerDefaultBlock? @@ -64,7 +129,7 @@ booleanExpression ; booleanPart - : WS? (AND | OR | XOR | EQV | IMP)? WS? NOT? WS? (compilerConstant | anyWord) + : WS? (AND | OR | XOR | EQV | IMP)? WS? NOT? WS? (compilerConstant | unreservedWord) ; compilerConstant @@ -76,10 +141,35 @@ compilerConstant | MAC ; -anyWord - : ANYCHARS+ +reservedWord + : AMP + | AND + | AS + | DIVD + | EMPTY_X + | EQ + | MOD + | MULT + | PLUS + | SUBT + | THEN + | compilerConstant ; +unreservedWord + : ANYCHARS + | FALSE + | LITDATE + | LITINTEGER + | LITSTRING + | LITFLOAT + | NOTHING + | NULL_ + | TRUE + ; + +anyWord: ( unreservedWord | reservedWord)+; + anyOtherLine : (WS* anyWord)+ ; @@ -99,7 +189,7 @@ endOfStatement commentBody: COMMENT; remStatement: REMCOMMENT; -// wsc: (WS | LINE_CONTINUATION)+; +// WS: (WS | LINE_CONTINUATION)+; @@ -112,12 +202,20 @@ NEWLINE : ([\r\n\u2028\u2029]) (WS* ([\r\n\u2028\u2029]))* ; +AS + : 'AS' + ; + +CONST + : '#CONST' + ; + ELSE : '#ELSE' ; ELSEIF - : '#ELSE IF' + : '#ELSEIF' ; ENDIF @@ -156,6 +254,19 @@ MAC : 'MAC' ; +MULT: '*'; +DIVD: INTDIV | DBLDIV; +MOD: 'MOD'; +PLUS: '+'; +SUBT: '-'; +AMP: '&'; +LIKE: 'LIKE'; +LT: '<'; +GT: '>'; + +fragment INTDIV: '\\'; +fragment DBLDIV: '/'; + REMCOMMENT : COLON? REM WS (LINE_CONTINUATION | ~[\r\n\u2028\u2029])* ; @@ -188,6 +299,10 @@ SINGLEQUOTE : '\'' ; +EQ + : '=' + ; + REM : 'REM' ; @@ -216,6 +331,121 @@ NOT : 'NOT' ; +NOTHING + : 'NOTHING' + ; + +NULL_ + : 'NULL' + ; + +TRUE + : 'TRUE' + ; + +FALSE + : 'FALSE' + ; + +EMPTY_X + : 'EMPTY' + ; + +LITSTRING + : '"' (~["\r\n] | '""')* '"' + ; + +LITINTEGER + : '-'? (DIGIT DIGIT* | '&H' [0-9A-F]+ | '&' [O]? [0-7]+) [%&^]? + ; + +LITFLOAT + : '-'? FLOATINGPOINTLITERAL [!#@]? + | '-'? DECIMALLITERAL [!#@] + ; + +fragment FLOATINGPOINTLITERAL + : DECIMALLITERAL [DE] [+-]? DECIMALLITERAL + | DECIMALLITERAL '.' DECIMALLITERAL? ([DE] [+-]? DECIMALLITERAL)? + | '.' DECIMALLITERAL ([DE] [+-]? DECIMALLITERAL)? + ; + +fragment DECIMALLITERAL + : DIGIT DIGIT* + ; + +LITDATE + : '#' DATEORTIME '#' + ; + +fragment DATEORTIME + : DATEVALUE WS+ TIMEVALUE + | DATEVALUE + | TIMEVALUE + ; + +fragment DATEVALUE + : DATEVALUEPART DATESEPARATOR DATEVALUEPART (DATESEPARATOR DATEVALUEPART)? + ; + +fragment DATEVALUEPART + : DIGIT+ + | MONTHNAME + ; + +fragment DATESEPARATOR + : WS+ + | WS? [/,-] WS? + ; + +fragment MONTHNAME + : ENGLISHMONTHNAME + | ENGLISHMONTHABBREVIATION + ; + +fragment ENGLISHMONTHNAME + : 'JANUARY' + | 'FEBRUARY' + | 'MARCH' + | 'APRIL' + | 'MAY' + | 'JUNE' + | 'JULY' + | 'AUGUST' + | 'SEPTEMBER' + | 'OCTOBER' + | 'NOVEMBER' + | 'DECEMBER' + ; + +// May has intentionally been left out +fragment ENGLISHMONTHABBREVIATION + : 'JAN' + | 'FEB' + | 'MAR' + | 'APR' + | 'JUN' + | 'JUL' + | 'AUG' + | 'SEP' + | 'OCT' + | 'NOV' + | 'DEC' + ; + +fragment TIMEVALUE + : DIGIT+ AMPM + | DIGIT+ TIMESEPARATOR DIGIT+ (TIMESEPARATOR DIGIT+)? AMPM? + ; + +fragment TIMESEPARATOR + : WS? (':' | '.') WS? + ; + +fragment AMPM + : WS? ('AM' | 'PM' | 'A' | 'P') + ; + // Any non-whitespace or new line characters. ANYCHARS @@ -224,4 +454,8 @@ ANYCHARS fragment ANYCHAR : ~[\r\n\u2028\u2029 \t\u0019\u3000] + ; + +fragment DIGIT + : [0-9] ; \ No newline at end of file diff --git a/server/src/capabilities/capabilities.ts b/server/src/capabilities/capabilities.ts index dea7f41..238a3b5 100644 --- a/server/src/capabilities/capabilities.ts +++ b/server/src/capabilities/capabilities.ts @@ -281,12 +281,16 @@ export class ScopeItemCapability { public parent?: ScopeItemCapability, ) { } + clean(): void { + this.deleteInvalidatedScopes(); + this.cleanInvalidatedLinks(); + } + /** * Recursively build from this node down. */ build(): void { - this.deleteInvalidatedScopes(); - this.cleanInvalidatedLinks(); + this.clean(); // Don't build self if invalidated. if (this.isInvalidated) { @@ -800,7 +804,7 @@ export class ScopeItemCapability { } // Add implicitly accessible names to the project scope. - if (item.isPublicScope && this.project) { + if (item.isPublicScope && this.project && this !== this.project) { this.project.implicitDeclarations ??= new Map(); this.addItem(this.project.implicitDeclarations, item, item.name); } diff --git a/server/src/extensions/antlrVbaPreParserExtensions.ts b/server/src/extensions/antlrVbaPreParserExtensions.ts index 992afbb..aa2b513 100644 --- a/server/src/extensions/antlrVbaPreParserExtensions.ts +++ b/server/src/extensions/antlrVbaPreParserExtensions.ts @@ -1,11 +1,15 @@ // Project -import { CompilerConditionalStatementContext } from '../antlr/out/vbapreParser'; +import { CompilerConditionalStatementContext, DirectiveExpressionContext } from '../antlr/out/vbapreParser'; declare module '../antlr/out/vbapreParser' { interface CompilerConditionalStatementContext { vbaExpression(): string; } + + interface DirectiveExpressionContext { + vbaExpression(): string; + } } @@ -15,3 +19,7 @@ CompilerConditionalStatementContext.prototype.vbaExpression = function (): strin .getText() .toLowerCase(); }; + +DirectiveExpressionContext.prototype.vbaExpression = function (): string { + return this.getText().toLowerCase(); +}; \ No newline at end of file diff --git a/server/src/project/document.ts b/server/src/project/document.ts index fb6a941..896c62c 100644 --- a/server/src/project/document.ts +++ b/server/src/project/document.ts @@ -167,6 +167,7 @@ export abstract class BaseProjectDocument { await (new SyntaxParser(Services.logger)).parse(token, this); const projectScope = this.currentScope.project; const buildScope = projectScope?.isDirty ? projectScope : this.currentScope; + projectScope?.clean(); buildScope.build(); buildScope.resolveUnused(); diff --git a/server/src/project/elements/precompiled.ts b/server/src/project/elements/precompiled.ts index 04a64d6..1a7e3e0 100644 --- a/server/src/project/elements/precompiled.ts +++ b/server/src/project/elements/precompiled.ts @@ -2,19 +2,52 @@ import { TextDocument } from 'vscode-languageserver-textdocument'; // Antlr -import { CompilerConditionalBlockContext, CompilerDefaultBlockContext, CompilerIfBlockContext } from '../../antlr/out/vbapreParser'; +import { CompilerConditionalBlockContext, CompilerDefaultBlockContext, CompilerIfBlockContext, ConstDirectiveStatementContext } from '../../antlr/out/vbapreParser'; // Project -import { DiagnosticCapability, FoldingRangeCapability } from '../../capabilities/capabilities'; +import { DiagnosticCapability, FoldingRangeCapability, IdentifierCapability } from '../../capabilities/capabilities'; import { BaseRuleSyntaxElement } from '../elements/base'; import { UnreachableCodeDiagnostic } from '../../capabilities/diagnostics'; +type DocumentSettings = { environment: { os: string, version: string } }; + +export class CompilerDirectiveElement extends BaseRuleSyntaxElement { + identifierCapability: IdentifierCapability; + + constructor(ctx: ConstDirectiveStatementContext, + doc: TextDocument, + private readonly documentSettings: DocumentSettings, + private readonly directiveConstants: Map) { + super(ctx, doc); + + const getNameCtx = () => ctx.constDirectiveName(); + this.identifierCapability = new IdentifierCapability(this, getNameCtx); + } + + evaluate(): string { + const vbaExpression = this.context.rule.directiveExpression().vbaExpression(); + try { + const tsExpression = transpileVbaToTypescript(vbaExpression, this.documentSettings, this.directiveConstants); + const getExpressionResult = Function('"use strict"; return (' + tsExpression + ')'); + return getExpressionResult().toString(); + } catch (e) { + // FIXME Add a diagnostic for if this fails. + return '0'; + } + } +} + + export class CompilerLogicalBlock extends BaseRuleSyntaxElement { conditionalBlocks: CompilerConditionBlock[] = []; inactiveBlocks: CompilerConditionBlock[] = []; - constructor(ctx: CompilerIfBlockContext, doc: TextDocument, env: { environment: { os: string, version: string } }) { + constructor( + ctx: CompilerIfBlockContext, + doc: TextDocument, + documentSettings: DocumentSettings, + directiveConstants: Map) { super(ctx, doc); this.foldingRangeCapability = new FoldingRangeCapability(this); this.foldingRangeCapability.openWord = '#If'; @@ -22,7 +55,11 @@ export class CompilerLogicalBlock extends BaseRuleSyntaxElement { if (x) this.conditionalBlocks.push(new CompilerConditionBlock(x, doc, env)); }); + blocks.map(x => { + if (x) this.conditionalBlocks.push( + new CompilerConditionBlock(x, doc, documentSettings, directiveConstants) + ); + }); // Create the comment elements. let resolved = false; @@ -31,7 +68,7 @@ export class CompilerLogicalBlock extends BaseRuleSyntaxElement { - readonly documentSettings: { environment: { os: string, version: string } }; - - constructor(ctx: CompilerConditionalBlockContext | CompilerDefaultBlockContext, doc: TextDocument, env: { environment: { os: string, version: string } }) { + constructor( + ctx: CompilerConditionalBlockContext | CompilerDefaultBlockContext, + doc: TextDocument, + private readonly documentSettings: DocumentSettings, + private readonly directiveConstants: Map) { super(ctx, doc); - this.documentSettings = env; } get blockLines(): string[] { @@ -56,7 +94,7 @@ class CompilerConditionBlock extends BaseRuleSyntaxElement 'compilerElseStatement' in o)(ctx)) return true; const vbaExpression = ctx.compilerConditionalStatement().vbaExpression(); - const tsExpression = this.transpileVbaToTypescript(vbaExpression); + const tsExpression = transpileVbaToTypescript(vbaExpression, this.documentSettings, this.directiveConstants); // Evaluate the expression and return the result. const result: boolean = Function('"use strict"; return (' + tsExpression + ')')(); @@ -68,36 +106,46 @@ class CompilerConditionBlock extends BaseRuleSyntaxElement { - const isOs = this.documentSettings.environment.os.toLowerCase() == opt; - const isVer = this.documentSettings.environment.version.toLowerCase() == opt; - return isOs || isVer ? 'true' : 'false'; - }; - - // Set up text replacements map. - const constants = ['vba6', 'vba7', 'mac', 'win16', 'win32', 'win64']; - const replacements = new Map(constants.map(x => [x, envToBooleanText(x)])); - replacements.set('or', '||'); - replacements.set('and', '&&'); - replacements.set('not ', '!'); - - // Perform text replacements. - let result = exp; - replacements.forEach((v, k) => { - const regexp = RegExp(`${k}`, 'i'); - if (regexp.test(result)) { - result = result.replace(regexp, v); - } - }); +function transpileVbaToTypescript(exp: string, settings: DocumentSettings, directives: Map): string { + // Convert the environment constant to boolean. + const envToBooleanText = (opt: string) => { + const isOs = settings.environment.os.toLowerCase() == opt; + const isVer = settings.environment.version.toLowerCase() == opt; + return isOs || isVer ? 'true' : 'false'; + }; + + // Set up text replacements map. + const constants = ['vba6', 'vba7', 'mac', 'win16', 'win32', 'win64']; + const replacements = new Map(constants.map(x => [x, envToBooleanText(x)])); + replacements.set('or', '||'); + replacements.set('and', '&&'); + replacements.set('not ', '!'); + + // Perform language text replacements. + let result = exp; + replacements.forEach((v, k) => { + const regexp = RegExp(`\\b${k}\\b`, 'i'); + if (regexp.test(result)) { + result = result.replace(regexp, v); + } + }); - return result; - } -} + // Perform user directives text replacements. + directives.forEach((v, k) => { + const regexp = RegExp(`\\b${k}\\b`, 'i'); + if (regexp.test(result)) { + result = result.replace(regexp, v); + } + }); + + return result; +} \ No newline at end of file diff --git a/server/src/project/parser/vbaListener.ts b/server/src/project/parser/vbaListener.ts index 479e4a4..c957d09 100644 --- a/server/src/project/parser/vbaListener.ts +++ b/server/src/project/parser/vbaListener.ts @@ -6,7 +6,7 @@ import { ErrorNode, ParserRuleContext } from 'antlr4ng'; import { vbaListener } from '../../antlr/out/vbaListener'; import { vbapreListener } from '../../antlr/out/vbapreListener'; import { vbafmtListener } from '../../antlr/out/vbafmtListener'; -import { CompilerIfBlockContext } from '../../antlr/out/vbapreParser'; +import { CompilerIfBlockContext, ConstDirectiveStatementContext} from '../../antlr/out/vbapreParser'; import { AmbiguousIdentifierContext, AnyOperatorContext, @@ -67,7 +67,7 @@ import { import { Services } from '../../injection/services'; import { ExtensionConfiguration } from '../workspace'; import { ErrorRuleElement } from '../elements/generic'; -import { CompilerLogicalBlock } from '../elements/precompiled'; +import { CompilerDirectiveElement, CompilerLogicalBlock } from '../elements/precompiled'; import { UnexpectedEndOfLineElement } from '../elements/utils'; import { VbaClassDocument, VbaModuleDocument } from '../document'; import { DuplicateOperatorElement, IfElseBlockElement, WhileLoopElement } from '../elements/flow'; @@ -489,6 +489,7 @@ export class VbaListener extends vbaListener { export class VbaPreListener extends vbapreListener { common: CommonParserCapability; + directives: Map = new Map(); get text(): string { return this.common.document.redactedText; @@ -505,10 +506,27 @@ export class VbaPreListener extends vbapreListener { return result; } + enterConstDirectiveStatement = (ctx: ConstDirectiveStatementContext) => { + const doc = this.common.document; + const element = new CompilerDirectiveElement( + ctx, + doc.textDocument, + this.common.documentSettings, + this.directives + ); + this.directives.set(element.identifierCapability.name, element.evaluate()); + doc.registerElement(element) + .registerSubtractElement(element); + }; + enterCompilerIfBlock = (ctx: CompilerIfBlockContext) => { const doc = this.common.document; - const docprops = this.common.documentSettings; - const element = new CompilerLogicalBlock(ctx, doc.textDocument, docprops); + const element = new CompilerLogicalBlock( + ctx, + doc.textDocument, + this.common.documentSettings, + this.directives + ); element.inactiveBlocks.forEach( b => doc.registerElement(b) .registerSubtractElement(b) diff --git a/server/src/project/workspace.ts b/server/src/project/workspace.ts index 45fe2fe..35bab38 100644 --- a/server/src/project/workspace.ts +++ b/server/src/project/workspace.ts @@ -191,9 +191,10 @@ export class Workspace implements IWorkspace { openDocument(document: TextDocument): void { const normalisedUri = document.uri.toFilePath().toFileUri(); const projectDocument = this.projectDocuments.get(normalisedUri); + Services.logger.debug(`existing: ${projectDocument?.version ?? 'None'}`, 1); if (projectDocument) { projectDocument.open(); - if (document.version > projectDocument?.version) { + if (document.version > projectDocument.version) { this.parseDocument(projectDocument); } this.connection.sendDiagnostics(projectDocument.languageServerDiagnostics());