@bitloops/bl-transpiler
Version:
The one and only Bitloops Language transpiler
170 lines • 7.86 kB
JavaScript
/**
* Bitloops Language CLI
* Copyright (C) 2022 Bitloops S.A.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* For further information you can contact legal(at)bitloops.com.
*/
import { BitloopsTypesMapping } from '../helpers/mappings.js';
import { ValidationError, } from '../ast/core/types.js';
import { bitloopsIdentifierError, domainRuleIdentifierError, errorIdentifierError, argumentError, readModelIdentifierError, domainServiceEvaluationError, entityIdentifierError, } from './validators/index.js';
import { TypeInferenceValidator } from './type-inference/TypeInferenceValidator.js';
const isIntermediateASTValidationErrors = (value) => {
if (Array.isArray(value)) {
for (const err of value) {
if (!(err instanceof ValidationError)) {
return false;
}
}
return true;
}
return false;
};
export class SemanticAnalyzer {
symbolTableCore;
symbolTableSetup;
errors = [];
typeInference;
constructor() {
this.symbolTableCore = {};
this.symbolTableSetup = {};
this.typeInference = new TypeInferenceValidator();
}
validate(ast) {
this.createSymbolTablesCore(ast.core);
this.validateCore(ast.core);
this.validateSetup(ast.setup);
const validationErrors = [];
validationErrors.push(...this.errors);
const typeInferenceValidation = this.typeInference.validate(ast);
if (isIntermediateASTValidationErrors(typeInferenceValidation)) {
validationErrors.push(...typeInferenceValidation);
}
if (validationErrors.length > 0)
return validationErrors;
}
getSymbolTable(ast) {
const validationResult = this.validate(ast);
const semanticErrors = [];
if (isIntermediateASTValidationErrors(validationResult)) {
semanticErrors.push(...validationResult);
}
return {
symbolTables: this.typeInference.getSymbolTable(ast),
semanticErrors,
};
}
addError(...errors) {
this.errors.push(...errors);
}
createSymbolTablesCore(core) {
for (const [boundedContextName, boundedContext] of Object.entries(core)) {
this.symbolTableCore[boundedContextName] = new Set();
for (const ASTTree of Object.values(boundedContext)) {
const classTypeNodes = ASTTree.getClassTypeNodes();
for (const node of classTypeNodes) {
switch (node.getNodeType()) {
case BitloopsTypesMapping.TProps: {
const identifierNode = node.getPropsIdentifierNode();
this.symbolTableCore[boundedContextName].add(identifierNode.getIdentifierName());
break;
}
case BitloopsTypesMapping.TDomainError: {
const identifierNode = node.getIdentifier();
this.symbolTableCore[boundedContextName].add('DomainErrors.' + identifierNode.getIdentifierName());
break;
}
case BitloopsTypesMapping.TApplicationError: {
const identifierNode = node.getIdentifier();
this.symbolTableCore[boundedContextName].add('ApplicationErrors.' + identifierNode.getIdentifierName());
break;
}
case BitloopsTypesMapping.TPackagePort: {
const identifier = node.identifier;
this.symbolTableCore[boundedContextName].add(identifier);
break;
}
case BitloopsTypesMapping.TIntegrationEvent: {
const identifier = node.getIntegrationEventIdentifier();
this.symbolTableCore[boundedContextName].add(identifier);
break;
}
default: {
const identifierNode = node.getIdentifier();
this.symbolTableCore[boundedContextName].add(identifierNode.getIdentifierName());
break;
}
}
}
}
}
}
validateCore(core) {
for (const [boundedContextName, boundedContext] of Object.entries(core)) {
for (const ASTTree of Object.values(boundedContext)) {
// this.validateNodes(ASTTree, boundedContextName);
this.validateClassTypeNodesCore(ASTTree, boundedContextName);
}
}
}
validateSetup(setup) {
for (const [fileId, ASTTree] of Object.entries(setup)) {
this.validateClassTypeNodesSetup(ASTTree, fileId);
}
}
//isn't being used right now
// private validateNodes(ASTTree: IntermediateASTTree, boundedContextName: string): void {
// ASTTree.traverse(ASTTree.getRootNode(), (node: IntermediateASTNode) => {
// const validationRes = node.validate(this.symbolTableCore[boundedContextName]);
// if (IntermediateASTNode.isIntermediateASTNodeValidationError(validationRes))
// this.addError(validationRes);
// });
// }
validateClassTypeNodesCore(ASTTree, boundedContext) {
ASTTree.traverse(ASTTree.getRootNode(), (node) => {
switch (node.getNodeType()) {
case BitloopsTypesMapping.TBitloopsIdentifier:
this.addError(...bitloopsIdentifierError(node, this.symbolTableCore[boundedContext]));
break;
case BitloopsTypesMapping.TEntityIdentifier:
this.addError(...entityIdentifierError(node, this.symbolTableCore[boundedContext]));
break;
case BitloopsTypesMapping.TReadModelIdentifier:
this.addError(...readModelIdentifierError(node, this.symbolTableCore[boundedContext]));
break;
case BitloopsTypesMapping.TErrorIdentifier:
this.addError(...errorIdentifierError(node, this.symbolTableCore[boundedContext]));
break;
case BitloopsTypesMapping.TDomainRuleIdentifier:
this.addError(...domainRuleIdentifierError(node, this.symbolTableCore[boundedContext]));
break;
case BitloopsTypesMapping.TDomainServiceEvaluation: {
this.addError(...domainServiceEvaluationError(node, this.symbolTableCore[boundedContext]));
break;
}
}
});
}
validateClassTypeNodesSetup(ASTTree, fileId) {
ASTTree.traverse(ASTTree.getRootNode(), (node) => {
switch (node.getNodeType()) {
case BitloopsTypesMapping.TArgument:
this.addError(...argumentError(node, this.symbolTableSetup[fileId]));
break;
}
});
}
}
//# sourceMappingURL=IntermediateASTValidator.js.map