d3-dot-graph/grammar/dot.pegjs
2017-09-01 14:54:55 +02:00

173 lines
3.9 KiB
JavaScript

// Simplified DOT grammar
//
// Not supported (yet):
//
// * HTML IDs
{
function merge(a, b, key) {
function x(a) {
a.forEach(function (b) {
if (!(b[key] in obj)) {
obj[b[key]] = obj[b[key]] || {};
array.push(obj[b[key]]);
}
Object.keys(b).forEach(function (k) {
obj[b[key]][k] = b[k];
});
});
}
var array = [],
obj = {};
x(a);
x(b);
return array;
}
var directed;
}
start
= graphStmt+
graphStmt
= _* strict:(strict _)? type:graphType _* id:(id)? _* '{' _* stmts:stmtList? _* '}' _* {
return {type: type, id: id, strict: strict !== null, stmts: stmts};
}
stmtList
= first:stmt _* ';'? rest:(_* inner:stmt _* ';'?)* {
var result = [first];
for (var i = 0; i < rest.length; ++i) {
result.push(rest[i][1]);
}
return result;
}
stmt
= attrStmt
/ edgeStmt
/ subgraphStmt
/ inlineAttrStmt
/ nodeStmt
attrStmt
= type:(graph / node /edge) _* attrs:attrList {
return { type: "attr", attrType: type, attrs: attrs || {}};
}
inlineAttrStmt
= k:id _* '=' _* v:id {
var attrs = {};
attrs[k] = v;
return { type: "inlineAttr", attrs: attrs };
}
nodeStmt
= id:nodeId _* attrs:attrList? { return {type: "node", id: id, attrs: attrs || {}}; }
edgeStmt
= lhs:(nodeIdOrSubgraph) _* rhs:edgeRHS _* attrs:attrList? {
var elems = [lhs];
for (var i = 0; i < rhs.length; ++i) {
elems.push(rhs[i]);
}
return { type: "edge", elems: elems, attrs: attrs || {} };
}
subgraphStmt
= id:(subgraph _* (id _*)?)? '{' _* stmts:stmtList? _* '}' {
id = (id && id[2]) || [];
return { type: "subgraph", id: id[0], stmts: stmts };
}
attrList
= first:attrListBlock rest:(_* attrListBlock)* {
var result = first;
for (var i = 0; i < rest.length; ++i) {
merge(result, rest[i][1]);
}
return result;
}
attrListBlock
= '[' _* aList:aList? _* ']' { return aList; }
aList
= first:idDef rest:(_* ','? _* idDef)* {
var result = first;
for (var i = 0; i < rest.length; ++i) {
_.merge(result, rest[i][3]);
}
return result;
}
edgeRHS
= ("--" !{ return directed; } / "->" &{ return directed; }) _* rhs:(nodeIdOrSubgraph) _* rest:edgeRHS? {
var result = [rhs];
if (rest) {
for (var i = 0; i < rest.length; ++i) {
result.push(rest[i]);
}
}
return result;
}
idDef
= k:id v:(_* '=' _* id)? {
var result = {};
result[k] = v[3];
return result;
}
nodeIdOrSubgraph
= subgraphStmt
/ id:nodeId { return { type: "node", id: id, attrs: {} }; }
nodeId
= id:id _* port? { return id; }
port
= ':' _* id _* (':' _* compassPt)?
compassPt
= "ne" / "se" / "sw" / "nw" / "n" / "e" / "s" / "w" / "c" / "_"
id "identifier"
= fst:[a-zA-Z\u0200-\u0377_] rest:[a-zA-Z\u0200-\u0377_0-9]* { return fst + rest.join(""); }
/ sign:'-'? dot:'.' after:[0-9]+ {
return (sign || "") + dot + after.join("");
}
/ sign:'-'? before:[0-9]+ after:('.' [0-9]*)? {
return (sign || "") + before.join("") + (after ? after[0] : "") + (after ? after[1].join("") : "");
}
/ '"' id:("\\\"" { return '"'; } / "\\" ch:[^"] { return "\\" + ch; } / [^"])* '"' {
return id.join("");
}
node = k:"node"i { return k.toLowerCase(); }
edge = k:"edge"i { return k.toLowerCase(); }
graph = k:"graph"i { return k.toLowerCase(); }
digraph = k:"digraph"i { return k.toLowerCase(); }
subgraph = k:"subgraph"i { return k.toLowerCase(); }
strict = k:"strict"i { return k.toLowerCase(); }
graphType
= graph:graph / graph:digraph {
directed = graph === "digraph";
return graph;
}
whitespace "whitespace"
= [ \t\r\n]+
comment "comment"
= "//" ([^\n])*
/ "/*" (!"*/" .)* "*/"
_
= whitespace
/ comment