@erml/parser
Version:
Parser implementation of ERML
322 lines (321 loc) • 13.7 kB
JavaScript
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,
};
;