@grammar/xml
Version:
XML 1.1 grammar.
273 lines • 12.4 kB
JavaScript
import $ from './spellu-engine.mjs';
/**
* XML 1.1
*/
var grammar$xml;
(function (grammar$xml) {
function createRecipe() {
return {
name: 'xml',
rules: {
root: {
parser: '&', argument: [
{ parser: 'xml-declaration' },
{ parser: 'document-type', optional: true },
{ parser: 'node-list' },
],
},
// <?xml ...?>
// <?xml-stylesheet ...?>
'xml-declaration': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "token.xml.XmlDeclaration.L" /* XmlDeclarationOpenToken */, pattern: '<?xml' } },
{ parser: '?', argument: { syntax: "xml.TextSection" /* TextSection */, pattern: /[^\?]+/ } },
{ parser: '?', argument: { syntax: "token.xml.XmlDeclaration.R" /* XmlDeclarationCloseToken */, pattern: '?>' } },
],
},
// <!doctype ...>
// <!...>
'document-type': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "token.xml.MarkupDeclaration.L" /* MarkupDeclarationOpenToken */, pattern: '<!' } },
{ parser: '?', argument: { syntax: "xml.DoctypeDeclaration" /* DoctypeDeclaration */, pattern: /(?:doctype|DOCTYPE)\s+([0-9a-zA-Z:_\-]+)\s*/, capture: 1 } },
{ parser: '?', argument: { syntax: "token.xml.MarkupDeclaration.R" /* MarkupDeclarationCloseToken */, pattern: '>' } },
],
},
'node-list': {
parser: '|', argument: [
{ parser: 'comment' },
{ parser: 'tag-open' },
{ parser: 'tag-close' },
{ parser: 'cdata' },
{ parser: 'text' },
],
multiplicity: 0,
},
'comment': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "xml.CommentSection" /* CommentSection */, pattern: '<!--' } },
{
parser: '#', argument: [
{ syntax: 'xml.comment.content', pattern: /.+(?=-->)/ },
]
},
{ parser: '#', argument: { syntax: "xml.CommentSection" /* CommentSection */, pattern: '-->' } },
],
},
'tag-open': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "token.xml.<" /* TagOpenToken */, pattern: '<' } },
{ parser: '#', argument: { syntax: "xml.TagName" /* TagName */, pattern: /[0-9a-zA-Z:_\-]+/ } },
{ parser: 'attribute', multiplicity: 0 },
{ parser: '?', argument: { syntax: "token.xml./" /* SlashToken */, pattern: '/' }, optional: true },
{ parser: '?', argument: { syntax: "token.xml.>" /* TagCloseToken */, pattern: '>' } },
],
},
'tag-close': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "token.xml.<" /* TagOpenToken */, pattern: '<' } },
{ parser: '#', argument: { syntax: "token.xml./" /* SlashToken */, pattern: '/' } },
{ parser: '#', argument: { syntax: "xml.TagName" /* TagName */, pattern: /[0-9a-zA-Z:_\-]+/ } },
{ parser: '?', argument: { syntax: "token.xml.>" /* TagCloseToken */, pattern: '>' } },
],
},
'attribute': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "xml.AttributeName" /* AttributeName */, pattern: /[0-9a-zA-Z:_\-]+/ } },
{ parser: '?', argument: { syntax: "token.xml.=" /* EqualToken */, pattern: '=' } },
{ parser: 'string-literal' },
],
},
'cdata': {
parser: '&', argument: [
// FIXME: Syntax
{ parser: '?', argument: { syntax: "token.xml.<" /* TagOpenToken */, pattern: '<![CDATA[' } },
{ parser: '#', argument: { syntax: "xml.Text" /* Text */, pattern: /.*?(?=\]\]>)/ms } },
{ parser: '#', argument: { syntax: "token.xml.>" /* TagCloseToken */, pattern: ']]>' } },
],
},
'text': { parser: '?', argument: { syntax: "xml.Text" /* Text */, pattern: /.+?(?=<)|.+/ms } },
'string-literal': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: 'token.xml.doublequote', pattern: '"' } },
{ parser: '#', argument: { syntax: 'token.xml.content', pattern: /[^"]*/ } },
{ parser: '#', argument: { syntax: 'token.xml.doublequote', pattern: '"' } },
],
},
},
};
}
grammar$xml.createRecipe = createRecipe;
})(grammar$xml || (grammar$xml = {}));
(function (grammar$xml) {
var processors;
(function (processors) {
processors.cst = {
recipe: grammar$xml.createRecipe(),
parts: {},
};
})(processors = grammar$xml.processors || (grammar$xml.processors = {}));
})(grammar$xml || (grammar$xml = {}));
(function (grammar$xml) {
var processors;
(function (processors) {
processors.ast = {
recipe: grammar$xml.createRecipe(),
parts: {
'root'(_) {
return $.createNode(_, "xml.Document" /* XmlDocument */, {
xmlDeclaration: _[0],
doctype: _[1],
nodeList: _[2],
});
},
'xml-declaration'(_) {
return $.createNode(_, "xml.XmlDeclaration" /* XmlDeclaration */, {
attributeList: [],
});
},
'document-type'(_) {
return $.createNode(_, "xml.DoctypeDeclaration" /* DoctypeDeclaration */, {
string: _[1],
});
},
'comment'(_) {
return $.createNode(_, "xml.CommentSection" /* CommentSection */, {
text: _.value,
});
},
'tag-open'(_) {
return $.createNode(_, "xml.TagSection" /* TagSection */, {
isOpen: true,
isClose: _[3] ? true : false,
tagName: _[1],
attributeList: _[2],
});
},
'tag-close'(_) {
return $.createNode(_, "xml.TagSection" /* TagSection */, {
isOpen: false,
isClose: true,
tagName: _[2],
attributeList: [],
});
},
'attribute'(_) {
return $.createNode(_, "xml.Attribute" /* Attribute */, {
name: _[0],
value: _[2],
});
},
'cdata'(_) {
return $.createNode(_, "xml.CDataSection" /* CDataSection */, {
text: _[1],
});
},
'text'(_) {
return $.createNode(_, "xml.TextSection" /* TextSection */, {
text: _,
});
},
'string-literal'(_) {
return _[1];
},
},
};
})(processors = grammar$xml.processors || (grammar$xml.processors = {}));
})(grammar$xml || (grammar$xml = {}));
(function (grammar$xml) {
let ProcessorSuite;
(function (ProcessorSuite) {
ProcessorSuite["CST"] = "cst";
ProcessorSuite["AST"] = "ast";
})(ProcessorSuite = grammar$xml.ProcessorSuite || (grammar$xml.ProcessorSuite = {}));
function selectProcessorSuite(suite) {
return [grammar$xml.processors[suite]];
}
grammar$xml.selectProcessorSuite = selectProcessorSuite;
function scan(source, suite = ProcessorSuite.AST, rule, options = {}) {
const processors = selectProcessorSuite(suite);
return $.scan($.createSource(source), rule ?? processors[0]?.recipe.name, {
...options,
processors: processors
});
}
grammar$xml.scan = scan;
function tokens(source, options = {}) {
return $.flatten(scan(source, ProcessorSuite.CST, undefined, options));
}
grammar$xml.tokens = tokens;
})(grammar$xml || (grammar$xml = {}));
(function (grammar$xml) {
function assemble(source) {
return new NodeTreeAssembler().assemble(source);
}
grammar$xml.assemble = assemble;
class NodeTreeAssembler {
nodeStack = [];
tagStack = [];
assemble(source) {
this.nodeStack = [...source.nodeList];
this.tagStack = [];
return $.createNode(source, "xml.Document" /* XmlDocument */, {
xmlDeclaration: source.xmlDeclaration,
doctype: source.doctype,
nodeList: this.assembleNodes(),
});
}
assembleNodes() {
const semanticNodeList = [];
while (this.nodeStack.length > 0) {
let node = this.nodeStack.shift();
if (node.syntax === "xml.TagSection" /* TagSection */) {
const nodeTag = node;
if (nodeTag.isOpen) {
// self closing tag
if (nodeTag.isClose) {
const element = $.createNode(nodeTag, "xml.ElementDeclaration" /* ElementDeclaration */, {
tagName: nodeTag.tagName,
attributeList: nodeTag.attributeList,
nodeList: [],
});
semanticNodeList.push(element);
}
// open tag
else {
this.tagStack.push(nodeTag);
const element = $.createNode(nodeTag, "xml.ElementDeclaration" /* ElementDeclaration */, {
tagName: nodeTag.tagName,
attributeList: nodeTag.attributeList,
nodeList: this.assembleNodes(),
});
semanticNodeList.push(element);
}
}
// close tag
else {
if (this.tagStack.length > 0) {
const openNode = this.tagStack.pop();
const closeNode = nodeTag;
if (openNode.tagName.value === closeNode.tagName.value) {
return semanticNodeList;
}
else {
// Error: close tag is not matched
console.error('Ca1');
}
}
else {
// Error: close tag is not matched
console.error('Ca2');
}
}
}
else {
semanticNodeList.push(node);
}
}
return semanticNodeList;
}
}
})(grammar$xml || (grammar$xml = {}));
export default grammar$xml;
//# sourceMappingURL=grammar-xml.mjs.map