UNPKG

@bitloops/bl-transpiler

Version:
170 lines 7.86 kB
/** * 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