UNPKG

@erml/parser

Version:

Parser implementation of ERML

322 lines (321 loc) 13.7 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.testables = exports.API = exports.Delimiters = void 0; var pipeline_1 = require("./pipeline"); var Delimiters; (function (Delimiters) { Delimiters["OPENING_BRACE"] = "{"; Delimiters["CLOSING_BRACE"] = "}"; Delimiters["OPENING_ANGLE"] = "<"; Delimiters["CLOSING_ANGLE"] = ">"; Delimiters["OPENING_PAREN"] = "("; Delimiters["CLOSING_PAREN"] = ")"; Delimiters["COMMA"] = ","; })(Delimiters = exports.Delimiters || (exports.Delimiters = {})); var API; (function (API) { API["ENTITY"] = "entity"; API["WEAK_ENTITY"] = "weak entity"; API["REL"] = "rel"; API["IDEN_REL"] = "iden rel"; API["SEPARATE"] = "separate"; API["PARTIAL"] = "partial"; API["TOTAL"] = "total"; API["ONE"] = "1"; API["N"] = "N"; API["MIN_MAX"] = "min-max"; API["SIMPLE"] = "simple"; API["ATOMIC"] = "atomic"; API["PRIMARY"] = "primary"; API["DERIVED"] = "derived"; API["MULTIVALUED"] = "multivalued"; API["COMPOSITE"] = "composite"; })(API = exports.API || (exports.API = {})); var Keywords; (function (Keywords) { Keywords["ENTITY"] = "ENTITY"; Keywords["WEAK"] = "WEAK"; Keywords["OWNER"] = "OWNER"; Keywords["REL"] = "REL"; Keywords["IDEN"] = "IDEN"; Keywords["PARTIAL"] = "PARTIAL"; Keywords["TOTAL"] = "TOTAL"; Keywords["ATTRIBUTES"] = "ATTRIBUTES"; Keywords["SIMPLE"] = "SIMPLE"; Keywords["ATOMIC"] = "ATOMIC"; Keywords["PRIMARY"] = "PRIMARY"; Keywords["DERIVED"] = "DERIVED"; Keywords["MULTIVALUED"] = "MULTIVALUED"; Keywords["COMPOSITE"] = "COMPOSITE"; })(Keywords || (Keywords = {})); function parseAttributes(tokens, bodyStart, bodyEnd, allowMultivalued) { if (allowMultivalued === void 0) { allowMultivalued = true; } var attributes = []; var currentAttribute; var allowedTypes = [ Keywords.COMPOSITE, Keywords.SIMPLE, Keywords.ATOMIC, Keywords.PRIMARY, Keywords.PARTIAL, Keywords.DERIVED, ]; if (allowMultivalued) { allowedTypes.push(Keywords.MULTIVALUED); } var compositeTypePipeline = [ function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (bodyStart, bodyEnd) { return (currentAttribute.componentAttributes = parseAttributes(tokens, bodyStart, bodyEnd, false)); }); }, function (token, tokenIndex) { return tokenIndex > bodyEnd ? undefined : (0, pipeline_1.assertToken)(token, [Delimiters.COMMA]); }, ]; var commonPipeline = [ function (token) { return (0, pipeline_1.assertToken)(token, allowedTypes, function (matchedIndex) { return (currentAttribute.type = [ API.COMPOSITE, API.SIMPLE, API.ATOMIC, API.PRIMARY, API.PARTIAL, API.DERIVED, API.MULTIVALUED, ][matchedIndex]); }); }, function (token) { return (0, pipeline_1.processStringLiteral)(token, function (stringValue) { return (currentAttribute.name = stringValue); }); }, function (token, tokenIndex) { if (tokenIndex > bodyEnd || currentAttribute.type === API.COMPOSITE) { return; } (0, pipeline_1.assertToken)(token, [Delimiters.COMMA]); }, ]; for (var currentTokenIndex = bodyStart; currentTokenIndex <= bodyEnd;) { attributes.push((currentAttribute = {})); currentTokenIndex = (0, pipeline_1.walkPipeline)(commonPipeline, tokens, currentTokenIndex); if (currentAttribute.type === API.COMPOSITE) { currentTokenIndex = (0, pipeline_1.walkPipeline)(compositeTypePipeline, tokens, currentTokenIndex - 1); } } return attributes; } function parseRelBody(tokens, bodyStart, bodyEnd) { var partEntities = []; var currentPartEntity; var attributes = []; var common = { comma: function (token) { return (0, pipeline_1.assertToken)(token, [Delimiters.COMMA]); }, possibleComma: function (token, tokenIndex) { return tokenIndex > bodyEnd ? undefined : (0, pipeline_1.assertToken)(token, [Delimiters.COMMA]); }, }; var attributesPipeline = [ function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (attributesBodyStart, attributesBodyEnd) { return (attributes = parseAttributes(tokens, attributesBodyStart, attributesBodyEnd)); }); }, common.possibleComma, ]; var separateNotationPipeline = [ function (token) { return (0, pipeline_1.assertToken)(token, [Keywords.PARTIAL, Keywords.TOTAL], function (matchedIndex) { return (currentPartEntity.structConstraints.partConstraint = [API.PARTIAL, API.TOTAL][matchedIndex]); }); }, common.comma, function (token) { var allowedTokens = [API.ONE, API.N]; (0, pipeline_1.assertToken)(token, allowedTokens, function (matchedIndex) { return (currentPartEntity.structConstraints.cardinalityRatio = allowedTokens[matchedIndex]); }); }, function (token) { return (0, pipeline_1.assertToken)(token, [Delimiters.CLOSING_ANGLE]); }, common.possibleComma, ]; var minmaxNotationPipeline = [ function (token) { return (0, pipeline_1.processNumber)(token, [0, Infinity], function (numberValue) { return (currentPartEntity.structConstraints.partConstraint = numberValue); }); }, common.comma, function (token) { try { (0, pipeline_1.assertToken)(token, [API.N], function () { return (currentPartEntity.structConstraints.cardinalityRatio = API.N); }); } catch (_a) { (0, pipeline_1.processNumber)(token, [ currentPartEntity.structConstraints.partConstraint, Infinity, ], function (numberValue) { return (currentPartEntity.structConstraints.cardinalityRatio = numberValue); }); } }, function (token) { return (0, pipeline_1.assertToken)(token, [Delimiters.CLOSING_PAREN]); }, common.possibleComma, ]; var nextPipeline = []; var initialPipeline = [ function (token) { return (0, pipeline_1.processIdentifier)(token, true, function () { return (currentPartEntity.name = token.value); }); }, function (token) { return (0, pipeline_1.assertToken)(token, [Delimiters.OPENING_ANGLE, Delimiters.OPENING_PAREN], function (matchedIndex) { if (matchedIndex === 0) { currentPartEntity.notation = API.SEPARATE; nextPipeline = separateNotationPipeline; } else { currentPartEntity.notation = API.MIN_MAX; nextPipeline = minmaxNotationPipeline; } }); }, ]; for (var currentTokenIndex = bodyStart; currentTokenIndex <= bodyEnd;) { if (tokens[currentTokenIndex].value === Keywords.ATTRIBUTES) { if (attributes.length) { throw new SyntaxError("Cannot redefine relationship attributes at position " + tokens[currentTokenIndex].position + ", line " + tokens[currentTokenIndex].line + ". All relationship attributes should be defined within the same body"); } currentTokenIndex = (0, pipeline_1.walkPipeline)(attributesPipeline, tokens, ++currentTokenIndex); } else { partEntities.push((currentPartEntity = { structConstraints: {} })); currentTokenIndex = (0, pipeline_1.walkPipeline)(initialPipeline, tokens, currentTokenIndex); currentTokenIndex = (0, pipeline_1.walkPipeline)(nextPipeline, tokens, currentTokenIndex); } } return __assign({ partEntities: partEntities }, (attributes.length && { attributes: attributes })); } function parseEntity(tokens, currentTokenIndex) { var entityNode = { type: API.ENTITY, start: tokens[currentTokenIndex].position, }; var parsingPipeline = [ function (token) { return (0, pipeline_1.processIdentifier)(token, false, function () { return (entityNode.name = token.value); }); }, function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (bodyStart, bodyEnd) { entityNode.attributes = parseAttributes(tokens, bodyStart, bodyEnd); entityNode.end = tokens[bodyEnd + 1].position; }); }, ]; var nextTokenIndex = (0, pipeline_1.walkPipeline)(parsingPipeline, tokens, ++currentTokenIndex); return [nextTokenIndex, entityNode]; } function parseWeakEntity(tokens, currentTokenIndex) { var weakEntityNode = { type: API.WEAK_ENTITY, start: tokens[currentTokenIndex].position, }; var parsingPipeline = [ function (token) { return (0, pipeline_1.assertToken)(token, [Keywords.ENTITY]); }, function (token) { return (0, pipeline_1.processIdentifier)(token, false, function () { return (weakEntityNode.name = token.value); }); }, function (token) { return (0, pipeline_1.assertToken)(token, [Keywords.OWNER]); }, function (token) { return (0, pipeline_1.processIdentifier)(token, true, function () { return (weakEntityNode.owner = token.value); }); }, function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (bodyStart, bodyEnd) { weakEntityNode.attributes = parseAttributes(tokens, bodyStart, bodyEnd); weakEntityNode.end = tokens[bodyEnd + 1].position; }); }, ]; var nextTokenIndex = (0, pipeline_1.walkPipeline)(parsingPipeline, tokens, ++currentTokenIndex); return [nextTokenIndex, weakEntityNode]; } function parseRel(tokens, currentTokenIndex) { var relNode = { type: API.REL, start: tokens[currentTokenIndex].position, }; var parsingPipeline = [ function (token) { return (0, pipeline_1.processIdentifier)(token, false, function () { return (relNode.name = token.value); }); }, function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (bodyStart, bodyEnd) { relNode.body = parseRelBody(tokens, bodyStart, bodyEnd); relNode.end = tokens[bodyEnd + 1].position; }); }, ]; var nextTokenIndex = (0, pipeline_1.walkPipeline)(parsingPipeline, tokens, ++currentTokenIndex); return [nextTokenIndex, relNode]; } function parseIdenRel(tokens, currentTokenIndex) { var idenRelNode = { type: API.IDEN_REL, start: tokens[currentTokenIndex].position, }; var parsingPipeline = [ function (token) { return (0, pipeline_1.assertToken)(token, [Keywords.REL]); }, function (token) { return (0, pipeline_1.processIdentifier)(token, false, function () { return (idenRelNode.name = token.value); }); }, function (_, tokenIndex) { return (0, pipeline_1.processBody)(tokens, tokenIndex, function (bodyStart, bodyEnd) { idenRelNode.body = parseRelBody(tokens, bodyStart, bodyEnd); idenRelNode.end = tokens[bodyEnd + 1].position; }); }, ]; var nextTokenIndex = (0, pipeline_1.walkPipeline)(parsingPipeline, tokens, ++currentTokenIndex); return [nextTokenIndex, idenRelNode]; } function default_1(tokens) { var _a; var AST = []; var parsers = (_a = {}, _a[Keywords.ENTITY] = parseEntity, _a[Keywords.WEAK] = parseWeakEntity, _a[Keywords.REL] = parseRel, _a[Keywords.IDEN] = parseIdenRel, _a); for (var i = 0, l = tokens.length, currentParser = void 0; i < l;) { currentParser = parsers[tokens[i].value]; if (currentParser === undefined) { throw new SyntaxError("Didn't recognize token '" + tokens[i].value + "' at position " + tokens[i].position + ", line " + tokens[i].line); } var _b = currentParser(tokens, i), nextTokenIndex = _b[0], node = _b[1]; AST.push(node); i = nextTokenIndex; } return AST; } exports.default = default_1; exports.testables = { parseAttributes: parseAttributes, parseRelBody: parseRelBody, parseEntity: parseEntity, parseWeakEntity: parseWeakEntity, parseRel: parseRel, parseIdenRel: parseIdenRel, };