Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to the "bitloops-language" extension will be documented in t

Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

### 0.2.0

Added validator for semantic and syntactic errors

### 0.1.1

Added transpiler package dependency
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"icon": "assets/images/bitloops-language-logo-256x256.png",
"license": "MIT",
"version": "0.1.1",
"version": "0.2.0",
"scripts": {
"vs:package": "vsce package",
"vs:publish": "vsce publish",
Expand Down
4 changes: 2 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bitloops-lsp-server",
"description": "BitLoops Language Server",
"version": "1.0.1",
"version": "0.2.0",
"publisher": "Bitloops",
"license": "MIT",
"engines": {
Expand All @@ -10,7 +10,7 @@
"type": "module",
"scripts": {},
"dependencies": {
"@bitloops/bl-transpiler": "^0.1.0",
"@bitloops/bl-transpiler": "^0.2.0",
"vscode-languageserver": "^7.0.0",
"vscode-languageserver-textdocument": "^1.0.4"
},
Expand Down
13 changes: 8 additions & 5 deletions server/src/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ export interface IAnalyzer {
/**
* It analyzes the document and returns a list of diagnostics.
*/
analyze(document: TextDocument): Diagnostic[];
analyze(document: TextDocument): Record<string, Diagnostic[]>;
}

let problems = 0;

export class RegexAnalyzer implements IAnalyzer {
public analyze(textDocument: TextDocument): Diagnostic[] {
let diagnostics: Diagnostic[] = [];
diagnostics = diagnostics.concat(this.validateComponents(textDocument));
public analyze(textDocument: TextDocument): Record<string, Diagnostic[]> {
let diagnostics: Record<string, Diagnostic[]> = {};
diagnostics[textDocument.uri] = [];
diagnostics[textDocument.uri] = diagnostics[textDocument.uri].concat(
this.validateComponents(textDocument),
);
// connection.console.log(`[validate] ${textDocument.uri} has ${diagnostics.length} for ${text}`);
problems = diagnostics.length;
problems = diagnostics[textDocument.uri].length;
return diagnostics;
}

Expand Down
3 changes: 2 additions & 1 deletion server/src/diagnostic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class DiagnosticFactory {
severity: LogLevel,
range: Range,
message: string,
uri?: string,
addRelatedInformation?: string[],
): Diagnostic {
message = this.prefixMessage(message, severity);
Expand All @@ -27,7 +28,7 @@ export class DiagnosticFactory {
diagnostic.relatedInformation.push({
location: {
// TODO? add TextDocument uri?
uri: '',
uri: uri,
range: range,
},
message: related,
Expand Down
131 changes: 95 additions & 36 deletions server/src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,128 @@ import {
OriginalParserError,
TParserInputData,
isParserErrors,
isIntermediateASTValidationErrors,
transpiler,
OriginalValidatorError,
} from '@bitloops/bl-transpiler';
import { Diagnostic } from 'vscode-languageserver/node.js';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { IAnalyzer } from '../analyzer.js';
import { DiagnosticFactory } from '../diagnostic.js';
import { TParserCoreInputData, TParserSetupInputData } from '../types.js';

export class BitloopsAnalyzer implements IAnalyzer {
static diagnostics: Diagnostic[] = [];
analyze(document: TextDocument): Diagnostic[] {
private diagnostics: Record<string, Diagnostic[]> = {};
private res: Partial<TParserInputData> = {};
private setup: Record<string, TParserSetupInputData> = {};
private core: Record<string, TParserCoreInputData> = {};
analyze(document: TextDocument): Record<string, Diagnostic[]> {
try {
const transpileInputData = this.documentToParserInputData(document);
const intermediateModel = transpiler.bitloopsCodeToIntermediateModel(transpileInputData);
if (isParserErrors(intermediateModel)) {
const diagnostics = this.mapParserErrorsToLSPDiagnostics(intermediateModel, document);
return diagnostics;
this.mapParserErrorsToLSPDiagnostics(intermediateModel, document);
return this.diagnostics;
}
return [];
if (isIntermediateASTValidationErrors(intermediateModel)) {
this.mapValidatorErrorsToLSPDiagnostics(intermediateModel, document);
return this.diagnostics;
}
return this.diagnostics;
} catch (e) {
console.log('error', e);
return [];
return {};
}
}

private documentToParserInputData(document: TextDocument): TParserInputData {
const res: Partial<TParserInputData> = {};

if (document.uri.endsWith('setup.bl')) {
res.setup = [
//giving file id as uri for now
if (!(document.uri in this.diagnostics)) this.diagnostics[document.uri] = [];
if (document.uri.endsWith('setup.bl'))
this.setup[document.uri] = [
{
fileId: document.uri.split('/').slice(-1)[0],
// fileId: document.uri.split('/').slice(-1)[0],
fileId: document.uri,
fileContents: document.getText(),
},
];
return res as TParserInputData;
}
// Handle possibly unknown bounded context and module
const boundedContext = document.uri.split('/')?.slice(-3)?.[0] ?? 'unknown';
const module = document.uri.split('/')?.slice(-2)?.[0] ?? 'unknown';
res.core = [
{
boundedContext,
module,
fileId: document.uri.split('/').slice(-1)[0],
fileContents: document.getText(),
},
];
return res as TParserInputData;
}

mapParserErrorsToLSPDiagnostics(
parserErrors: OriginalParserError,
document: TextDocument,
): Diagnostic[] {
return parserErrors.map((e) =>
DiagnosticFactory.create(
1,
else if (document.uri.endsWith('.bl')) {
const boundedContext = document.uri.split('/')?.slice(-3)?.[0] ?? 'unknown';
const module = document.uri.split('/')?.slice(-2)?.[0] ?? 'unknown';
this.core[document.uri] = [
{
start: document.positionAt(e.start),
end: document.positionAt(e.stop),
boundedContext,
module,
// fileId: document.uri.split('/').slice(-1)[0],
fileId: document.uri,
fileContents: document.getText(),
},
`line: ${e.line}:${e.column}, offendingSymbol: ${e.offendingToken.text}, msg: ${e.message}`,
];
}
this.res.core = [];
this.res.setup = [];
for (const core of Object.values(this.core)) {
this.res.core.push(...core);
}
for (const setup of Object.values(this.setup)) {
this.res.setup.push(...setup);
}
for (const key in this.diagnostics) {
this.diagnostics[key] = [];
}
return this.res as TParserInputData;
}
mapParserErrorsToLSPDiagnostics(parserErrors: OriginalParserError, document: TextDocument): void {
parserErrors.forEach((e) => {
this.diagnostics[e.fileId] = [];
});
for (const key in this.diagnostics) {
this.diagnostics[key] = [];
}
parserErrors.map((e) =>
this.diagnostics[e.fileId].push(
DiagnosticFactory.create(
1,
{
start: document.positionAt(e.start),
end: document.positionAt(e.stop),
},
`line: ${e.line}:${e.column}, offendingSymbol: ${e.offendingToken.text}, msg: ${e.message}`,
e.fileId,
),
),
);
}

mapValidatorErrorsToLSPDiagnostics(
validatorErrors: OriginalValidatorError,
document: TextDocument,
): void {
validatorErrors.forEach((e) => {
this.diagnostics[e.metadata.fileId] = [];
});
for (const key in this.diagnostics) {
this.diagnostics[key] = [];
}
validatorErrors.map((e) => {
this.diagnostics[e.metadata.fileId].push(
DiagnosticFactory.create(
1,
{
start: {
line: e.metadata.start.line - 1,
character: e.metadata.start.column - 1,
},
end: {
line: e.metadata.end.line - 1,
character: e.metadata.end.column - 1,
},
},
`line: ${e.metadata.start.line}:${e.metadata.start.column} , msg: ${e.message}`,
e.metadata.fileId,
),
);
});
}
}
29 changes: 20 additions & 9 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
InitializeResult,
TextDocumentSyncKind,
DidChangeConfigurationNotification,
Diagnostic,
} from 'vscode-languageserver/node.js';

import { TextDocument } from 'vscode-languageserver-textdocument';
Expand Down Expand Up @@ -41,17 +42,13 @@ export class BitloopsServer {
}

public async onDidChangeContent(change: TextDocumentChangeEvent<TextDocument>): Promise<void> {
const settings = await this.settingsManger.getDocumentSettings(
change.document.uri,
this.hasConfigurationCapability,
this.connection,
);
// We could use retrieved settings here to change the way we parse the document

const diagnostics = this.analyzer.analyze(change.document);
this.lspClient.publishDiagnostics({ uri: change.document.uri, diagnostics });
this.createDiagnostics(change.document);
}

// public async onDidOpen(change: TextDocumentChangeEvent<TextDocument>): Promise<void> {
// this.createDiagnostics(change.document);
// }

public onInitialize(params: InitializeParams): InitializeResult {
const capabilities = params.capabilities;
this.hasConfigurationCapability = !!(
Expand Down Expand Up @@ -98,4 +95,18 @@ export class BitloopsServer {

public completion = CompletionItemProvider.onCompletion;
public completionResolve = CompletionItemProvider.onCompletionResolve;

private async createDiagnostics(document: TextDocument): Promise<void> {
const settings = await this.settingsManger.getDocumentSettings(
document.uri,
this.hasConfigurationCapability,
this.connection,
);
// We could use retrieved settings here to change the way we parse the document

const diagnostics = this.analyzer.analyze(document);
for (const [uri, diagnostic] of Object.entries(diagnostics)) {
this.lspClient.publishDiagnostics({ uri: uri, diagnostics: diagnostic });
}
}
}
20 changes: 18 additions & 2 deletions server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export type TParserCoreInputData = {
fileContents: TFileContents;
}[];

export type TParserSetupInputData = {
fileId: TFileId;
fileContents: TFileContents;
}[];

export type TASTCoreInputData = {
boundedContext: string;
classes: Record<TClassType, Record<TClassName, TClassInformation>>;
Expand Down Expand Up @@ -126,7 +131,14 @@ export type TBitloopsTargetGeneratorParams = {
sourceDirPath?: string; // TODO remove this after making the package files injectable in the setup
};

export type TBitloopsClasses = TProps | TValueObjects | TRESTController | TUseCase | TDomainErrors | TDTO | TStructs;
export type TBitloopsClasses =
| TProps
| TValueObjects
| TRESTController
| TUseCase
| TDomainErrors
| TDTO
| TStructs;

export type TModuleName = string;
export type TBoundedContext = Record<TModuleName, TModule>;
Expand Down Expand Up @@ -932,7 +944,11 @@ export type TIdentifierExpression = {
};

export type TLogicalSingleExpression = {
logicalExpression: TNotSingleExpression | TAndSingleExpression | TOrSingleExpression | TXorSingleExpression;
logicalExpression:
| TNotSingleExpression
| TAndSingleExpression
| TOrSingleExpression
| TXorSingleExpression;
};

export type TNotSingleExpression = {
Expand Down
8 changes: 4 additions & 4 deletions server/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# yarn lockfile v1


"@bitloops/bl-transpiler@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@bitloops/bl-transpiler/-/bl-transpiler-0.1.0.tgz#babf5f8ab4c02b23c75c1dca53ebb94d02f33d57"
integrity sha512-HMsU+6ggV/+sRQRbDbzpgZhm7fE06YORfW207ayJYlotVuGhvefyWRqtWjE2da5W37Ora+a+kQwdGW9ArP05ow==
"@bitloops/bl-transpiler@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@bitloops/bl-transpiler/-/bl-transpiler-0.2.0.tgz#0829384701af3086737e9c30ac724c19dd624e74"
integrity sha512-PYcg08m0YCwWzLkufgB3ULgFncSW1BE50qdp5DiMFyRT/5mioDT9hiFcl0cRZJDY8s5hMeWkDRogSI17SOSCtw==
dependencies:
antlr4 "^4.11.0"
lodash "^4.17.21"
Expand Down
2 changes: 1 addition & 1 deletion vsc-extension-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

## Get up and running straight away

- `npm install`
- `yarn`
- `npm run compile`
- Make sure the language configuration settings in `language-configuration.json` are accurate.
- Press `F5` to open a new window with your extension loaded.
Expand Down