{ /* initializer - run before general parser runs */ /** * Deeply flatten an array. * @param {Array} arr - array to flatten * @return {Array} - flattened array */ const flatten = (arr) => Array.isArray(arr) ? arr.reduce((flat, elt) => flat.concat(Array.isArray(elt) ? flatten(elt) : elt), []) : arr function Node( name ){ // an individual node this.name = name; this.children = []; // ordered list of names } function Tree(){ // a tree of nodes this.root = new Node('root'); // start from a root node this.ancestors = []; // ancestors of last added node } Tree.prototype.addNode = function( indent, name, bullet ){ console.log(bullet); this.ancestors.splice( indent ); // trim ancestor tree (if needed) this.current = this.root; // set current pointer to root this.ancestors.forEach(function(e){ // walk current to node ancestor this.current = this.current[e]; }, this); this.current[name] = new Node( name ); // add node to parent this.current.children.push( name ); // add node name to list of kids this.ancestors.push( name ); // add node to list of ancestors } var tree = new Tree(); } start = axis subAxis* { return tree.root; } axis = name:text ( newline / eof ) { tree.addNode( 0, flatten(name).join("") ); } subAxis = i:indent b:bullet? name:text t:times? ( newline / eof ) { tree.addNode( i.length, flatten(name).join(""), b); } indent = i:" "* bullet = b:(">" / "|" / "//" / ">=") " "? times = "(X" [1-9] ")" text = w:(word " "?)+ word = w:[a-zA-Z0-9\']+ newline = "\r\n" / "\n" / "\r"+ eof = !. { console.log(tree) }