| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview A semantic tree for MathML expressions. | 6 * @fileoverview A semantic tree for MathML expressions. |
| 7 * | 7 * |
| 8 * This file contains functionality to compute a semantic interpretation from a | 8 * This file contains functionality to compute a semantic interpretation from a |
| 9 * given MathML expression. This is a very heuristic approach that assumes a | 9 * given MathML expression. This is a very heuristic approach that assumes a |
| 10 * fairly simple default semantic which is suitable for K-12 and simple UG | 10 * fairly simple default semantic which is suitable for K-12 and simple UG |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 | 43 |
| 44 | 44 |
| 45 /** | 45 /** |
| 46 * @param {number} id Node id. | 46 * @param {number} id Node id. |
| 47 * @constructor | 47 * @constructor |
| 48 */ | 48 */ |
| 49 cvox.SemanticTree.Node = function(id) { | 49 cvox.SemanticTree.Node = function(id) { |
| 50 /** @type {number} */ | 50 /** @type {number} */ |
| 51 this.id = id; | 51 this.id = id; |
| 52 | 52 |
| 53 /** @type {Array.<Element>} */ | 53 /** @type {Array<Element>} */ |
| 54 this.mathml = []; | 54 this.mathml = []; |
| 55 | 55 |
| 56 /** @type {cvox.SemanticTree.Node} */ | 56 /** @type {cvox.SemanticTree.Node} */ |
| 57 this.parent = null; | 57 this.parent = null; |
| 58 | 58 |
| 59 /** @type {cvox.SemanticAttr.Type} */ | 59 /** @type {cvox.SemanticAttr.Type} */ |
| 60 this.type = cvox.SemanticAttr.Type.UNKNOWN; | 60 this.type = cvox.SemanticAttr.Type.UNKNOWN; |
| 61 | 61 |
| 62 /** @type {cvox.SemanticAttr.Role} */ | 62 /** @type {cvox.SemanticAttr.Role} */ |
| 63 this.role = cvox.SemanticAttr.Role.UNKNOWN; | 63 this.role = cvox.SemanticAttr.Role.UNKNOWN; |
| 64 | 64 |
| 65 /** @type {cvox.SemanticAttr.Font} */ | 65 /** @type {cvox.SemanticAttr.Font} */ |
| 66 this.font = cvox.SemanticAttr.Font.UNKNOWN; | 66 this.font = cvox.SemanticAttr.Font.UNKNOWN; |
| 67 | 67 |
| 68 /** @type {!Array.<cvox.SemanticTree.Node>} */ | 68 /** @type {!Array<cvox.SemanticTree.Node>} */ |
| 69 this.childNodes = []; | 69 this.childNodes = []; |
| 70 | 70 |
| 71 /** @type {string} */ | 71 /** @type {string} */ |
| 72 this.textContent = ''; | 72 this.textContent = ''; |
| 73 | 73 |
| 74 /** Branch nodes can store additional nodes that can be useful. | 74 /** Branch nodes can store additional nodes that can be useful. |
| 75 * E.g. a node of type FENCED can have the opening and closing fences here. | 75 * E.g. a node of type FENCED can have the opening and closing fences here. |
| 76 * @type {!Array.<cvox.SemanticTree.Node>} | 76 * @type {!Array<cvox.SemanticTree.Node>} |
| 77 */ | 77 */ |
| 78 this.contentNodes = []; | 78 this.contentNodes = []; |
| 79 }; | 79 }; |
| 80 | 80 |
| 81 | 81 |
| 82 /** | 82 /** |
| 83 * Retrieve all subnodes (including the node itself) that satisfy a given | 83 * Retrieve all subnodes (including the node itself) that satisfy a given |
| 84 * predicate. | 84 * predicate. |
| 85 * @param {function(cvox.SemanticTree.Node): boolean} pred The predicate. | 85 * @param {function(cvox.SemanticTree.Node): boolean} pred The predicate. |
| 86 * @return {!Array.<cvox.SemanticTree.Node>} The nodes in the tree for which the | 86 * @return {!Array<cvox.SemanticTree.Node>} The nodes in the tree for which the |
| 87 * predicate holds. | 87 * predicate holds. |
| 88 */ | 88 */ |
| 89 cvox.SemanticTree.Node.prototype.querySelectorAll = function(pred) { | 89 cvox.SemanticTree.Node.prototype.querySelectorAll = function(pred) { |
| 90 var result = []; | 90 var result = []; |
| 91 for (var i = 0, child; child = this.childNodes[i]; i++) { | 91 for (var i = 0, child; child = this.childNodes[i]; i++) { |
| 92 result = result.concat(child.querySelectorAll(pred)); | 92 result = result.concat(child.querySelectorAll(pred)); |
| 93 } | 93 } |
| 94 if (pred(this)) { | 94 if (pred(this)) { |
| 95 result.unshift(this); | 95 result.unshift(this); |
| 96 } | 96 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 117 /** | 117 /** |
| 118 * An XML tree representation of the current node. | 118 * An XML tree representation of the current node. |
| 119 * @param {Document} xml The XML document. | 119 * @param {Document} xml The XML document. |
| 120 * @param {boolean=} brief If set attributes are omitted. | 120 * @param {boolean=} brief If set attributes are omitted. |
| 121 * @return {Node} The XML representation of the node. | 121 * @return {Node} The XML representation of the node. |
| 122 */ | 122 */ |
| 123 cvox.SemanticTree.Node.prototype.xml = function(xml, brief) { | 123 cvox.SemanticTree.Node.prototype.xml = function(xml, brief) { |
| 124 /** | 124 /** |
| 125 * Translates a list of nodes into XML representation. | 125 * Translates a list of nodes into XML representation. |
| 126 * @param {string} tag Name of the enclosing tag. | 126 * @param {string} tag Name of the enclosing tag. |
| 127 * @param {!Array.<!cvox.SemanticTree.Node>} nodes A list of nodes. | 127 * @param {!Array<!cvox.SemanticTree.Node>} nodes A list of nodes. |
| 128 * @return {Node} An XML representation of the node list. | 128 * @return {Node} An XML representation of the node list. |
| 129 */ | 129 */ |
| 130 var xmlNodeList = function(tag, nodes) { | 130 var xmlNodeList = function(tag, nodes) { |
| 131 var xmlNodes = nodes.map(function(x) {return x.xml(xml, brief);}); | 131 var xmlNodes = nodes.map(function(x) {return x.xml(xml, brief);}); |
| 132 var tagNode = xml.createElement(tag); | 132 var tagNode = xml.createElement(tag); |
| 133 for (var i = 0, child; child = xmlNodes[i]; i++) { | 133 for (var i = 0, child; child = xmlNodes[i]; i++) { |
| 134 tagNode.appendChild(child); | 134 tagNode.appendChild(child); |
| 135 } | 135 } |
| 136 return tagNode; | 136 return tagNode; |
| 137 }; | 137 }; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 this.role = meaning.role; | 276 this.role = meaning.role; |
| 277 this.type = meaning.type; | 277 this.type = meaning.type; |
| 278 this.font = meaning.font; | 278 this.font = meaning.font; |
| 279 }; | 279 }; |
| 280 | 280 |
| 281 | 281 |
| 282 /** | 282 /** |
| 283 * Adds MathML nodes to the node's store of MathML nodes if necessary only, as | 283 * Adds MathML nodes to the node's store of MathML nodes if necessary only, as |
| 284 * we can not necessarily assume that the MathML of the content nodes and | 284 * we can not necessarily assume that the MathML of the content nodes and |
| 285 * children are all disjoint. | 285 * children are all disjoint. |
| 286 * @param {Array.<Node>} mmlNodes List of MathML nodes. | 286 * @param {Array<Node>} mmlNodes List of MathML nodes. |
| 287 * @private | 287 * @private |
| 288 */ | 288 */ |
| 289 cvox.SemanticTree.Node.prototype.addMathmlNodes_ = function(mmlNodes) { | 289 cvox.SemanticTree.Node.prototype.addMathmlNodes_ = function(mmlNodes) { |
| 290 for (var i = 0, mml; mml = mmlNodes[i]; i++) { | 290 for (var i = 0, mml; mml = mmlNodes[i]; i++) { |
| 291 if (this.mathml.indexOf(mml) == -1) { | 291 if (this.mathml.indexOf(mml) == -1) { |
| 292 this.mathml.push(mml); | 292 this.mathml.push(mml); |
| 293 } | 293 } |
| 294 } | 294 } |
| 295 }; | 295 }; |
| 296 | 296 |
| 297 | 297 |
| 298 /** | 298 /** |
| 299 * Removes MathML nodes from the node's store of MathML nodes. | 299 * Removes MathML nodes from the node's store of MathML nodes. |
| 300 * @param {Array.<Node>} mmlNodes List of MathML nodes. | 300 * @param {Array<Node>} mmlNodes List of MathML nodes. |
| 301 * @private | 301 * @private |
| 302 */ | 302 */ |
| 303 cvox.SemanticTree.Node.prototype.removeMathmlNodes_ = function(mmlNodes) { | 303 cvox.SemanticTree.Node.prototype.removeMathmlNodes_ = function(mmlNodes) { |
| 304 var mmlList = this.mathml; | 304 var mmlList = this.mathml; |
| 305 for (var i = 0, mml; mml = mmlNodes[i]; i++) { | 305 for (var i = 0, mml; mml = mmlNodes[i]; i++) { |
| 306 var index = mmlList.indexOf(mml); | 306 var index = mmlList.indexOf(mml); |
| 307 if (index != -1) { | 307 if (index != -1) { |
| 308 mmlList.splice(index, 1); | 308 mmlList.splice(index, 1); |
| 309 } | 309 } |
| 310 } | 310 } |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 // TODO (sorge) Do something useful with error and phantom symbols. | 486 // TODO (sorge) Do something useful with error and phantom symbols. |
| 487 default: | 487 default: |
| 488 // Ordinarilly at this point we should not get any other tag. | 488 // Ordinarilly at this point we should not get any other tag. |
| 489 return this.makeUnprocessed_(mml); | 489 return this.makeUnprocessed_(mml); |
| 490 } | 490 } |
| 491 }; | 491 }; |
| 492 | 492 |
| 493 | 493 |
| 494 /** | 494 /** |
| 495 * Parse a list of MathML nodes into the semantic tree. | 495 * Parse a list of MathML nodes into the semantic tree. |
| 496 * @param {Array.<Element>} mmls A list of MathML nodes. | 496 * @param {Array<Element>} mmls A list of MathML nodes. |
| 497 * @return {!Array.<cvox.SemanticTree.Node>} The list of resulting semantic | 497 * @return {!Array<cvox.SemanticTree.Node>} The list of resulting semantic |
| 498 * node. | 498 * node. |
| 499 * @private | 499 * @private |
| 500 */ | 500 */ |
| 501 cvox.SemanticTree.prototype.parseMathmlChildren_ = function(mmls) { | 501 cvox.SemanticTree.prototype.parseMathmlChildren_ = function(mmls) { |
| 502 var result = []; | 502 var result = []; |
| 503 for (var i = 0, mml; mml = mmls[i]; i++) { | 503 for (var i = 0, mml; mml = mmls[i]; i++) { |
| 504 result.push(this.parseMathml_(mml)); | 504 result.push(this.parseMathml_(mml)); |
| 505 } | 505 } |
| 506 return result; | 506 return result; |
| 507 }; | 507 }; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 node.mathml = [mml]; | 542 node.mathml = [mml]; |
| 543 node.updateContent_(mml.textContent); | 543 node.updateContent_(mml.textContent); |
| 544 node.font = mml.getAttribute('mathvariant') || node.font; | 544 node.font = mml.getAttribute('mathvariant') || node.font; |
| 545 return node; | 545 return node; |
| 546 }; | 546 }; |
| 547 | 547 |
| 548 | 548 |
| 549 /** | 549 /** |
| 550 * Create a branching node. | 550 * Create a branching node. |
| 551 * @param {!cvox.SemanticAttr.Type} type The type of the node. | 551 * @param {!cvox.SemanticAttr.Type} type The type of the node. |
| 552 * @param {!Array.<cvox.SemanticTree.Node>} children The child nodes. | 552 * @param {!Array<cvox.SemanticTree.Node>} children The child nodes. |
| 553 * @param {!Array.<cvox.SemanticTree.Node>} contentNodes The content Nodes. | 553 * @param {!Array<cvox.SemanticTree.Node>} contentNodes The content Nodes. |
| 554 * @param {string=} content Content string if there is any. | 554 * @param {string=} content Content string if there is any. |
| 555 * @return {!cvox.SemanticTree.Node} The new node. | 555 * @return {!cvox.SemanticTree.Node} The new node. |
| 556 * @private | 556 * @private |
| 557 */ | 557 */ |
| 558 cvox.SemanticTree.prototype.makeBranchNode_ = function( | 558 cvox.SemanticTree.prototype.makeBranchNode_ = function( |
| 559 type, children, contentNodes, content) { | 559 type, children, contentNodes, content) { |
| 560 var node = this.createNode_(); | 560 var node = this.createNode_(); |
| 561 if (content) { | 561 if (content) { |
| 562 node.updateContent_(content); | 562 node.updateContent_(content); |
| 563 } | 563 } |
| 564 node.type = type; | 564 node.type = type; |
| 565 node.childNodes = children; | 565 node.childNodes = children; |
| 566 node.contentNodes = contentNodes; | 566 node.contentNodes = contentNodes; |
| 567 children.concat(contentNodes) | 567 children.concat(contentNodes) |
| 568 .forEach( | 568 .forEach( |
| 569 function(x) { | 569 function(x) { |
| 570 x.parent = node; | 570 x.parent = node; |
| 571 node.addMathmlNodes_(x.mathml); | 571 node.addMathmlNodes_(x.mathml); |
| 572 }); | 572 }); |
| 573 return node; | 573 return node; |
| 574 }; | 574 }; |
| 575 | 575 |
| 576 | 576 |
| 577 /** | 577 /** |
| 578 * Create a branching node for an implicit operation, currently assumed to | 578 * Create a branching node for an implicit operation, currently assumed to |
| 579 * be of multiplicative type. | 579 * be of multiplicative type. |
| 580 * @param {!Array.<!cvox.SemanticTree.Node>} nodes The operands. | 580 * @param {!Array<!cvox.SemanticTree.Node>} nodes The operands. |
| 581 * @return {!cvox.SemanticTree.Node} The new branch node. | 581 * @return {!cvox.SemanticTree.Node} The new branch node. |
| 582 * @private | 582 * @private |
| 583 */ | 583 */ |
| 584 cvox.SemanticTree.prototype.makeImplicitNode_ = function(nodes) { | 584 cvox.SemanticTree.prototype.makeImplicitNode_ = function(nodes) { |
| 585 if (nodes.length == 1) { | 585 if (nodes.length == 1) { |
| 586 return nodes[0]; | 586 return nodes[0]; |
| 587 } | 587 } |
| 588 var operator = this.createNode_(); | 588 var operator = this.createNode_(); |
| 589 // For now we assume this is a multiplication using invisible times. | 589 // For now we assume this is a multiplication using invisible times. |
| 590 operator.updateContent_(cvox.SemanticAttr.invisibleTimes()); | 590 operator.updateContent_(cvox.SemanticAttr.invisibleTimes()); |
| 591 var newNode = this.makeInfixNode_(nodes, operator); | 591 var newNode = this.makeInfixNode_(nodes, operator); |
| 592 newNode.role = cvox.SemanticAttr.Role.IMPLICIT; | 592 newNode.role = cvox.SemanticAttr.Role.IMPLICIT; |
| 593 return newNode; | 593 return newNode; |
| 594 }; | 594 }; |
| 595 | 595 |
| 596 | 596 |
| 597 /** | 597 /** |
| 598 * Create a branching node for an infix operation. | 598 * Create a branching node for an infix operation. |
| 599 * @param {!Array.<cvox.SemanticTree.Node>} children The operands. | 599 * @param {!Array<cvox.SemanticTree.Node>} children The operands. |
| 600 * @param {!cvox.SemanticTree.Node} opNode The operator. | 600 * @param {!cvox.SemanticTree.Node} opNode The operator. |
| 601 * @return {!cvox.SemanticTree.Node} The new branch node. | 601 * @return {!cvox.SemanticTree.Node} The new branch node. |
| 602 * @private | 602 * @private |
| 603 */ | 603 */ |
| 604 cvox.SemanticTree.prototype.makeInfixNode_ = function(children, opNode) { | 604 cvox.SemanticTree.prototype.makeInfixNode_ = function(children, opNode) { |
| 605 return this.makeBranchNode_( | 605 return this.makeBranchNode_( |
| 606 cvox.SemanticAttr.Type.INFIXOP, children, [opNode], opNode.textContent); | 606 cvox.SemanticAttr.Type.INFIXOP, children, [opNode], opNode.textContent); |
| 607 }; | 607 }; |
| 608 | 608 |
| 609 | 609 |
| 610 /** | 610 /** |
| 611 * Creates a node of the specified type by collapsing the given node list into | 611 * Creates a node of the specified type by collapsing the given node list into |
| 612 * one content (thereby concatenating the content of each node into a single | 612 * one content (thereby concatenating the content of each node into a single |
| 613 * content string) with the inner node as a child. | 613 * content string) with the inner node as a child. |
| 614 * @param {!cvox.SemanticTree.Node} inner The inner node. | 614 * @param {!cvox.SemanticTree.Node} inner The inner node. |
| 615 * @param {!Array.<cvox.SemanticTree.Node>} nodeList List of nodes. | 615 * @param {!Array<cvox.SemanticTree.Node>} nodeList List of nodes. |
| 616 * @param {!cvox.SemanticAttr.Type} type The new type of the node. | 616 * @param {!cvox.SemanticAttr.Type} type The new type of the node. |
| 617 * @return {!cvox.SemanticTree.Node} The new branch node. | 617 * @return {!cvox.SemanticTree.Node} The new branch node. |
| 618 * @private | 618 * @private |
| 619 */ | 619 */ |
| 620 cvox.SemanticTree.prototype.makeConcatNode_ = function(inner, nodeList, type) { | 620 cvox.SemanticTree.prototype.makeConcatNode_ = function(inner, nodeList, type) { |
| 621 if (nodeList.length == 0) { | 621 if (nodeList.length == 0) { |
| 622 return inner; | 622 return inner; |
| 623 } | 623 } |
| 624 var content = nodeList.map(function(x) {return x.textContent;}).join(' '); | 624 var content = nodeList.map(function(x) {return x.textContent;}).join(' '); |
| 625 var newNode = this.makeBranchNode_(type, [inner], nodeList, content); | 625 var newNode = this.makeBranchNode_(type, [inner], nodeList, content); |
| 626 if (nodeList.length > 0) { | 626 if (nodeList.length > 0) { |
| 627 newNode.role = cvox.SemanticAttr.Role.MULTIOP; | 627 newNode.role = cvox.SemanticAttr.Role.MULTIOP; |
| 628 } | 628 } |
| 629 return newNode; | 629 return newNode; |
| 630 }; | 630 }; |
| 631 | 631 |
| 632 | 632 |
| 633 /** | 633 /** |
| 634 * Wraps a node into prefix operators. | 634 * Wraps a node into prefix operators. |
| 635 * Example: + - a becomes (+ (- (a))) | 635 * Example: + - a becomes (+ (- (a))) |
| 636 * Input: a [+, -] -> Output: content: '+ -', child: a | 636 * Input: a [+, -] -> Output: content: '+ -', child: a |
| 637 * @param {!cvox.SemanticTree.Node} node The inner node. | 637 * @param {!cvox.SemanticTree.Node} node The inner node. |
| 638 * @param {!Array.<cvox.SemanticTree.Node>} prefixes Prefix operators | 638 * @param {!Array<cvox.SemanticTree.Node>} prefixes Prefix operators |
| 639 * from the outermost to the innermost. | 639 * from the outermost to the innermost. |
| 640 * @return {!cvox.SemanticTree.Node} The new branch node. | 640 * @return {!cvox.SemanticTree.Node} The new branch node. |
| 641 * @private | 641 * @private |
| 642 */ | 642 */ |
| 643 cvox.SemanticTree.prototype.makePrefixNode_ = function(node, prefixes) { | 643 cvox.SemanticTree.prototype.makePrefixNode_ = function(node, prefixes) { |
| 644 var negatives = cvox.SemanticTree.partitionNodes_( | 644 var negatives = cvox.SemanticTree.partitionNodes_( |
| 645 prefixes, cvox.SemanticTree.attrPred_('role', 'SUBTRACTION')); | 645 prefixes, cvox.SemanticTree.attrPred_('role', 'SUBTRACTION')); |
| 646 var newNode = this.makeConcatNode_( | 646 var newNode = this.makeConcatNode_( |
| 647 node, negatives.comp.pop(), cvox.SemanticAttr.Type.PREFIXOP); | 647 node, negatives.comp.pop(), cvox.SemanticAttr.Type.PREFIXOP); |
| 648 | 648 |
| 649 while (negatives.rel.length > 0) { | 649 while (negatives.rel.length > 0) { |
| 650 newNode = this.makeConcatNode_( | 650 newNode = this.makeConcatNode_( |
| 651 newNode, [negatives.rel.pop()], cvox.SemanticAttr.Type.PREFIXOP); | 651 newNode, [negatives.rel.pop()], cvox.SemanticAttr.Type.PREFIXOP); |
| 652 newNode.role = cvox.SemanticAttr.Role.NEGATIVE; | 652 newNode.role = cvox.SemanticAttr.Role.NEGATIVE; |
| 653 newNode = this.makeConcatNode_( | 653 newNode = this.makeConcatNode_( |
| 654 newNode, negatives.comp.pop(), cvox.SemanticAttr.Type.PREFIXOP); | 654 newNode, negatives.comp.pop(), cvox.SemanticAttr.Type.PREFIXOP); |
| 655 } | 655 } |
| 656 return newNode; | 656 return newNode; |
| 657 }; | 657 }; |
| 658 | 658 |
| 659 | 659 |
| 660 /** | 660 /** |
| 661 * Wraps a node into postfix operators. | 661 * Wraps a node into postfix operators. |
| 662 * Example: a - + becomes (((a) -) +) | 662 * Example: a - + becomes (((a) -) +) |
| 663 * Input: a [-, +] -> Output: content: '- +', child: a | 663 * Input: a [-, +] -> Output: content: '- +', child: a |
| 664 * @param {!cvox.SemanticTree.Node} node The inner node. | 664 * @param {!cvox.SemanticTree.Node} node The inner node. |
| 665 * @param {!Array.<cvox.SemanticTree.Node>} postfixes Postfix operators from | 665 * @param {!Array<cvox.SemanticTree.Node>} postfixes Postfix operators from |
| 666 * innermost to outermost. | 666 * innermost to outermost. |
| 667 * @return {!cvox.SemanticTree.Node} The new branch node. | 667 * @return {!cvox.SemanticTree.Node} The new branch node. |
| 668 * @private | 668 * @private |
| 669 */ | 669 */ |
| 670 cvox.SemanticTree.prototype.makePostfixNode_ = function(node, postfixes) { | 670 cvox.SemanticTree.prototype.makePostfixNode_ = function(node, postfixes) { |
| 671 return this.makeConcatNode_( | 671 return this.makeConcatNode_( |
| 672 node, postfixes, cvox.SemanticAttr.Type.POSTFIXOP); | 672 node, postfixes, cvox.SemanticAttr.Type.POSTFIXOP); |
| 673 }; | 673 }; |
| 674 | 674 |
| 675 | 675 |
| 676 // TODO (sorge) Separate out interspersed text before the relations in row | 676 // TODO (sorge) Separate out interspersed text before the relations in row |
| 677 // heuristic otherwise we get them as implicit operations! | 677 // heuristic otherwise we get them as implicit operations! |
| 678 // Currently we handle that later in the rules, which is rather messy. | 678 // Currently we handle that later in the rules, which is rather messy. |
| 679 /** | 679 /** |
| 680 * Processes a list of nodes, combining expressions by delimiters, tables, | 680 * Processes a list of nodes, combining expressions by delimiters, tables, |
| 681 * punctuation sequences, function/big operator/integral applications to | 681 * punctuation sequences, function/big operator/integral applications to |
| 682 * generate a syntax tree with relation and operator precedence. | 682 * generate a syntax tree with relation and operator precedence. |
| 683 * | 683 * |
| 684 * This is the main heuristic to rewrite a flat row of terms into a meaningful | 684 * This is the main heuristic to rewrite a flat row of terms into a meaningful |
| 685 * term tree. | 685 * term tree. |
| 686 * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. | 686 * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. |
| 687 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. | 687 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. |
| 688 * @private | 688 * @private |
| 689 */ | 689 */ |
| 690 cvox.SemanticTree.prototype.processRow_ = function(nodes) { | 690 cvox.SemanticTree.prototype.processRow_ = function(nodes) { |
| 691 if (nodes.length == 0) { | 691 if (nodes.length == 0) { |
| 692 return this.makeEmptyNode_(); | 692 return this.makeEmptyNode_(); |
| 693 } | 693 } |
| 694 nodes = this.getFencesInRow_(nodes); | 694 nodes = this.getFencesInRow_(nodes); |
| 695 nodes = this.processTablesInRow_(nodes); | 695 nodes = this.processTablesInRow_(nodes); |
| 696 nodes = this.getPunctuationInRow_(nodes); | 696 nodes = this.getPunctuationInRow_(nodes); |
| 697 nodes = this.getFunctionsInRow_(nodes); | 697 nodes = this.getFunctionsInRow_(nodes); |
| 698 return this.processRelationsInRow_(nodes); | 698 return this.processRelationsInRow_(nodes); |
| 699 }; | 699 }; |
| 700 | 700 |
| 701 | 701 |
| 702 /** | 702 /** |
| 703 * Constructs a syntax tree with relation and operator precedence from a list | 703 * Constructs a syntax tree with relation and operator precedence from a list |
| 704 * of nodes. | 704 * of nodes. |
| 705 * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. | 705 * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. |
| 706 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. | 706 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. |
| 707 * @private | 707 * @private |
| 708 */ | 708 */ |
| 709 cvox.SemanticTree.prototype.processRelationsInRow_ = function(nodes) { | 709 cvox.SemanticTree.prototype.processRelationsInRow_ = function(nodes) { |
| 710 var partition = cvox.SemanticTree.partitionNodes_( | 710 var partition = cvox.SemanticTree.partitionNodes_( |
| 711 nodes, cvox.SemanticTree.attrPred_('type', 'RELATION')); | 711 nodes, cvox.SemanticTree.attrPred_('type', 'RELATION')); |
| 712 var firstRel = partition.rel[0]; | 712 var firstRel = partition.rel[0]; |
| 713 | 713 |
| 714 if (!firstRel) { | 714 if (!firstRel) { |
| 715 return this.processOperationsInRow_(nodes); | 715 return this.processOperationsInRow_(nodes); |
| 716 } | 716 } |
| 717 if (nodes.length == 1) { | 717 if (nodes.length == 1) { |
| 718 return nodes[0]; | 718 return nodes[0]; |
| 719 } | 719 } |
| 720 var children = partition.comp.map( | 720 var children = partition.comp.map( |
| 721 goog.bind(this.processOperationsInRow_, this)); | 721 goog.bind(this.processOperationsInRow_, this)); |
| 722 if (partition.rel.every( | 722 if (partition.rel.every( |
| 723 function(x) {return x.textContent == firstRel.textContent;})) { | 723 function(x) {return x.textContent == firstRel.textContent;})) { |
| 724 return this.makeBranchNode_( | 724 return this.makeBranchNode_( |
| 725 cvox.SemanticAttr.Type.RELSEQ, children, partition.rel, | 725 cvox.SemanticAttr.Type.RELSEQ, children, partition.rel, |
| 726 firstRel.textContent); | 726 firstRel.textContent); |
| 727 } | 727 } |
| 728 return this.makeBranchNode_( | 728 return this.makeBranchNode_( |
| 729 cvox.SemanticAttr.Type.MULTIREL, children, partition.rel); | 729 cvox.SemanticAttr.Type.MULTIREL, children, partition.rel); |
| 730 }; | 730 }; |
| 731 | 731 |
| 732 | 732 |
| 733 /** | 733 /** |
| 734 * Constructs a syntax tree with operator precedence from a list nodes. | 734 * Constructs a syntax tree with operator precedence from a list nodes. |
| 735 * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. | 735 * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. |
| 736 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. | 736 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. |
| 737 * @private | 737 * @private |
| 738 */ | 738 */ |
| 739 cvox.SemanticTree.prototype.processOperationsInRow_ = function(nodes) { | 739 cvox.SemanticTree.prototype.processOperationsInRow_ = function(nodes) { |
| 740 if (nodes.length == 0) { | 740 if (nodes.length == 0) { |
| 741 return this.makeEmptyNode_(); | 741 return this.makeEmptyNode_(); |
| 742 } | 742 } |
| 743 if (nodes.length == 1) { | 743 if (nodes.length == 1) { |
| 744 return nodes[0]; | 744 return nodes[0]; |
| 745 } | 745 } |
| 746 | 746 |
| 747 var prefix = []; | 747 var prefix = []; |
| 748 while (nodes.length > 0 && | 748 while (nodes.length > 0 && |
| 749 nodes[0].type == cvox.SemanticAttr.Type.OPERATOR) { | 749 nodes[0].type == cvox.SemanticAttr.Type.OPERATOR) { |
| 750 prefix.push(nodes.shift()); | 750 prefix.push(nodes.shift()); |
| 751 } | 751 } |
| 752 // Pathological case: only operators in row. | 752 // Pathological case: only operators in row. |
| 753 if (nodes.length == 0) { | 753 if (nodes.length == 0) { |
| 754 return this.makePrefixNode_(prefix.pop(), prefix); | 754 return this.makePrefixNode_(prefix.pop(), prefix); |
| 755 } | 755 } |
| 756 if (nodes.length == 1) { | 756 if (nodes.length == 1) { |
| 757 return this.makePrefixNode_(nodes[0], prefix); | 757 return this.makePrefixNode_(nodes[0], prefix); |
| 758 } | 758 } |
| 759 | 759 |
| 760 var split = cvox.SemanticTree.sliceNodes_( | 760 var split = cvox.SemanticTree.sliceNodes_( |
| 761 nodes, cvox.SemanticTree.attrPred_('type', 'OPERATOR')); | 761 nodes, cvox.SemanticTree.attrPred_('type', 'OPERATOR')); |
| 762 // At this point, we know that split.head is not empty! | 762 // At this point, we know that split.head is not empty! |
| 763 var node = this.makePrefixNode_( | 763 var node = this.makePrefixNode_( |
| 764 this.makeImplicitNode_( | 764 this.makeImplicitNode_( |
| 765 /** @type {!Array.<!cvox.SemanticTree.Node>} */ (split.head)), | 765 /** @type {!Array<!cvox.SemanticTree.Node>} */ (split.head)), |
| 766 prefix); | 766 prefix); |
| 767 if (!split.div) { | 767 if (!split.div) { |
| 768 return node; | 768 return node; |
| 769 } | 769 } |
| 770 return this.makeOperationsTree_(split.tail, node, split.div); | 770 return this.makeOperationsTree_(split.tail, node, split.div); |
| 771 }; | 771 }; |
| 772 | 772 |
| 773 | 773 |
| 774 /** | 774 /** |
| 775 * Recursively constructs syntax tree with operator precedence from a list nodes | 775 * Recursively constructs syntax tree with operator precedence from a list nodes |
| 776 * given a initial root node. | 776 * given a initial root node. |
| 777 * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. | 777 * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. |
| 778 * @param {!cvox.SemanticTree.Node} root Initial tree. | 778 * @param {!cvox.SemanticTree.Node} root Initial tree. |
| 779 * @param {!cvox.SemanticTree.Node} lastop Last operator that has not been | 779 * @param {!cvox.SemanticTree.Node} lastop Last operator that has not been |
| 780 * processed yet. | 780 * processed yet. |
| 781 * @param {Array.<cvox.SemanticTree.Node>=} prefixes Operator nodes that will | 781 * @param {Array<cvox.SemanticTree.Node>=} prefixes Operator nodes that will |
| 782 * become prefix operation (or postfix in case they come after last operand). | 782 * become prefix operation (or postfix in case they come after last operand). |
| 783 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. | 783 * @return {!cvox.SemanticTree.Node} The root node of the syntax tree. |
| 784 * @private | 784 * @private |
| 785 */ | 785 */ |
| 786 cvox.SemanticTree.prototype.makeOperationsTree_ = function( | 786 cvox.SemanticTree.prototype.makeOperationsTree_ = function( |
| 787 nodes, root, lastop, prefixes) { | 787 nodes, root, lastop, prefixes) { |
| 788 prefixes = prefixes || []; | 788 prefixes = prefixes || []; |
| 789 | 789 |
| 790 if (nodes.length == 0) { | 790 if (nodes.length == 0) { |
| 791 // Left over prefixes become postfixes. | 791 // Left over prefixes become postfixes. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 911 * Combines delimited expressions in a list of nodes. | 911 * Combines delimited expressions in a list of nodes. |
| 912 * | 912 * |
| 913 * The basic idea of the heuristic is as follows: | 913 * The basic idea of the heuristic is as follows: |
| 914 * 1. Opening and closing delimiters are matched regardless of the actual shape | 914 * 1. Opening and closing delimiters are matched regardless of the actual shape |
| 915 * of the fence. These are turned into fenced nodes. | 915 * of the fence. These are turned into fenced nodes. |
| 916 * 2. Neutral fences are matched only with neutral fences of the same shape. | 916 * 2. Neutral fences are matched only with neutral fences of the same shape. |
| 917 * 3. For a collection of unmatched neutral fences we try to get a maximum | 917 * 3. For a collection of unmatched neutral fences we try to get a maximum |
| 918 * number of matching fences. E.g. || a|b || would be turned into a fenced | 918 * number of matching fences. E.g. || a|b || would be turned into a fenced |
| 919 * node with fences || and content a|b. | 919 * node with fences || and content a|b. |
| 920 * 4. Any remaining unmatched delimiters are turned into punctuation nodes. | 920 * 4. Any remaining unmatched delimiters are turned into punctuation nodes. |
| 921 * @param {!Array.<!cvox.SemanticTree.Node>} nodes The list of nodes. | 921 * @param {!Array<!cvox.SemanticTree.Node>} nodes The list of nodes. |
| 922 * @return {!Array.<!cvox.SemanticTree.Node>} The new list of nodes. | 922 * @return {!Array<!cvox.SemanticTree.Node>} The new list of nodes. |
| 923 * @private | 923 * @private |
| 924 */ | 924 */ |
| 925 cvox.SemanticTree.prototype.getFencesInRow_ = function(nodes) { | 925 cvox.SemanticTree.prototype.getFencesInRow_ = function(nodes) { |
| 926 var partition = cvox.SemanticTree.partitionNodes_( | 926 var partition = cvox.SemanticTree.partitionNodes_( |
| 927 nodes, cvox.SemanticTree.attrPred_('type', 'FENCE')); | 927 nodes, cvox.SemanticTree.attrPred_('type', 'FENCE')); |
| 928 var felem = partition.comp.shift(); | 928 var felem = partition.comp.shift(); |
| 929 return this.processFences_(partition.rel, partition.comp, [], [felem]); | 929 return this.processFences_(partition.rel, partition.comp, [], [felem]); |
| 930 }; | 930 }; |
| 931 | 931 |
| 932 | 932 |
| 933 /** | 933 /** |
| 934 * Recursively processes a list of nodes and combines all the fenced expressions | 934 * Recursively processes a list of nodes and combines all the fenced expressions |
| 935 * into single nodes. It also processes singular fences, building expressions | 935 * into single nodes. It also processes singular fences, building expressions |
| 936 * that are only fenced left or right. | 936 * that are only fenced left or right. |
| 937 * @param {!Array.<cvox.SemanticTree.Node>} fences FIFO queue of fence nodes. | 937 * @param {!Array<cvox.SemanticTree.Node>} fences FIFO queue of fence nodes. |
| 938 * @param {!Array.<Array.<cvox.SemanticTree.Node>>} content FIFO queue content | 938 * @param {!Array<Array<cvox.SemanticTree.Node>>} content FIFO queue content |
| 939 * between fences. | 939 * between fences. |
| 940 * @param {!Array.<cvox.SemanticTree.Node>} openStack LIFO stack of open fences. | 940 * @param {!Array<cvox.SemanticTree.Node>} openStack LIFO stack of open fences. |
| 941 * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} contentStack LIFO stack of | 941 * @param {!Array<!Array<cvox.SemanticTree.Node>>} contentStack LIFO stack of |
| 942 * content between fences yet to be processed. | 942 * content between fences yet to be processed. |
| 943 * @return {!Array.<cvox.SemanticTree.Node>} A list of nodes with all fenced | 943 * @return {!Array<cvox.SemanticTree.Node>} A list of nodes with all fenced |
| 944 * expressions processed. | 944 * expressions processed. |
| 945 * @private | 945 * @private |
| 946 */ | 946 */ |
| 947 cvox.SemanticTree.prototype.processFences_ = function( | 947 cvox.SemanticTree.prototype.processFences_ = function( |
| 948 fences, content, openStack, contentStack) { | 948 fences, content, openStack, contentStack) { |
| 949 // Base case 1: Everything is used up. | 949 // Base case 1: Everything is used up. |
| 950 if (fences.length == 0 && openStack.length == 0) { | 950 if (fences.length == 0 && openStack.length == 0) { |
| 951 return contentStack[0]; | 951 return contentStack[0]; |
| 952 } | 952 } |
| 953 var openPred = cvox.SemanticTree.attrPred_('role', 'OPEN'); | 953 var openPred = cvox.SemanticTree.attrPred_('role', 'OPEN'); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 var fenced = fences.shift(); | 1050 var fenced = fences.shift(); |
| 1051 cvox.SemanticTree.fenceToPunct_(fenced); | 1051 cvox.SemanticTree.fenceToPunct_(fenced); |
| 1052 contentStack.push(contentStack.pop().concat([fenced], content.shift())); | 1052 contentStack.push(contentStack.pop().concat([fenced], content.shift())); |
| 1053 return this.processFences_(fences, content, openStack, contentStack); | 1053 return this.processFences_(fences, content, openStack, contentStack); |
| 1054 }; | 1054 }; |
| 1055 | 1055 |
| 1056 | 1056 |
| 1057 // TODO (sorge) The following could be done with linear programming. | 1057 // TODO (sorge) The following could be done with linear programming. |
| 1058 /** | 1058 /** |
| 1059 * Trys to combine neutral fences as much as possible. | 1059 * Trys to combine neutral fences as much as possible. |
| 1060 * @param {!Array.<!cvox.SemanticTree.Node>} fences A list of neutral fences. | 1060 * @param {!Array<!cvox.SemanticTree.Node>} fences A list of neutral fences. |
| 1061 * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} content Intermediate | 1061 * @param {!Array<!Array<cvox.SemanticTree.Node>>} content Intermediate |
| 1062 * content. Observe that |content| = |fences| - 1 | 1062 * content. Observe that |content| = |fences| - 1 |
| 1063 * @return {!Array.<cvox.SemanticTree.Node>} List of node with fully fenced | 1063 * @return {!Array<cvox.SemanticTree.Node>} List of node with fully fenced |
| 1064 * nodes. | 1064 * nodes. |
| 1065 * @private | 1065 * @private |
| 1066 */ | 1066 */ |
| 1067 cvox.SemanticTree.prototype.processNeutralFences_ = function(fences, content) { | 1067 cvox.SemanticTree.prototype.processNeutralFences_ = function(fences, content) { |
| 1068 if (fences.length == 0) { | 1068 if (fences.length == 0) { |
| 1069 return fences; | 1069 return fences; |
| 1070 } | 1070 } |
| 1071 if (fences.length == 1) { | 1071 if (fences.length == 1) { |
| 1072 cvox.SemanticTree.fenceToPunct_(fences[0]); | 1072 cvox.SemanticTree.fenceToPunct_(fences[0]); |
| 1073 return fences; | 1073 return fences; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1092 }; | 1092 }; |
| 1093 | 1093 |
| 1094 | 1094 |
| 1095 /** | 1095 /** |
| 1096 * Combines nodes framed by two matching fences using the given content. | 1096 * Combines nodes framed by two matching fences using the given content. |
| 1097 * Example: leftFence: [, rightFence: ], midFences: |, | | 1097 * Example: leftFence: [, rightFence: ], midFences: |, | |
| 1098 * content: c1, c2, c3, c4, ... cn | 1098 * content: c1, c2, c3, c4, ... cn |
| 1099 * return: [c1 | c2 | c3 ], c4, ... cn | 1099 * return: [c1 | c2 | c3 ], c4, ... cn |
| 1100 * @param {!cvox.SemanticTree.Node} leftFence The left fence. | 1100 * @param {!cvox.SemanticTree.Node} leftFence The left fence. |
| 1101 * @param {!cvox.SemanticTree.Node} rightFence The right fence. | 1101 * @param {!cvox.SemanticTree.Node} rightFence The right fence. |
| 1102 * @param {!Array.<cvox.SemanticTree.Node>} midFences A list of intermediate | 1102 * @param {!Array<cvox.SemanticTree.Node>} midFences A list of intermediate |
| 1103 * fences. | 1103 * fences. |
| 1104 * @param {!Array.<!Array.<cvox.SemanticTree.Node>>} content Intermediate | 1104 * @param {!Array<!Array<cvox.SemanticTree.Node>>} content Intermediate |
| 1105 * content. Observe that |content| = |fences| - 1 + k where k >= 0 is the | 1105 * content. Observe that |content| = |fences| - 1 + k where k >= 0 is the |
| 1106 * remainder. | 1106 * remainder. |
| 1107 * @return {!Array.<!Array.<cvox.SemanticTree.Node>>} List of content nodes | 1107 * @return {!Array<!Array<cvox.SemanticTree.Node>>} List of content nodes |
| 1108 * where the first is the fully fenced node wrt. the given left and right | 1108 * where the first is the fully fenced node wrt. the given left and right |
| 1109 * fence. | 1109 * fence. |
| 1110 * @private | 1110 * @private |
| 1111 */ | 1111 */ |
| 1112 cvox.SemanticTree.prototype.combineFencedContent_ = function( | 1112 cvox.SemanticTree.prototype.combineFencedContent_ = function( |
| 1113 leftFence, rightFence, midFences, content) { | 1113 leftFence, rightFence, midFences, content) { |
| 1114 | 1114 |
| 1115 if (midFences.length == 0) { | 1115 if (midFences.length == 0) { |
| 1116 var fenced = this.makeHorizontalFencedNode_( | 1116 var fenced = this.makeHorizontalFencedNode_( |
| 1117 leftFence, rightFence, content.shift()); | 1117 leftFence, rightFence, content.shift()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1156 fence.role = cvox.SemanticAttr.Role.CLOSEFENCE; | 1156 fence.role = cvox.SemanticAttr.Role.CLOSEFENCE; |
| 1157 break; | 1157 break; |
| 1158 } | 1158 } |
| 1159 }; | 1159 }; |
| 1160 | 1160 |
| 1161 | 1161 |
| 1162 /** | 1162 /** |
| 1163 * Create a fenced node. | 1163 * Create a fenced node. |
| 1164 * @param {cvox.SemanticTree.Node} ofence Opening fence. | 1164 * @param {cvox.SemanticTree.Node} ofence Opening fence. |
| 1165 * @param {cvox.SemanticTree.Node} cfence Closing fence. | 1165 * @param {cvox.SemanticTree.Node} cfence Closing fence. |
| 1166 * @param {!Array.<cvox.SemanticTree.Node>} content The content | 1166 * @param {!Array<cvox.SemanticTree.Node>} content The content |
| 1167 * between the fences. | 1167 * between the fences. |
| 1168 * @return {!cvox.SemanticTree.Node} The new node. | 1168 * @return {!cvox.SemanticTree.Node} The new node. |
| 1169 * @private | 1169 * @private |
| 1170 */ | 1170 */ |
| 1171 cvox.SemanticTree.prototype.makeHorizontalFencedNode_ = function( | 1171 cvox.SemanticTree.prototype.makeHorizontalFencedNode_ = function( |
| 1172 ofence, cfence, content) { | 1172 ofence, cfence, content) { |
| 1173 var childNode = this.processRow_(content); | 1173 var childNode = this.processRow_(content); |
| 1174 var newNode = this.makeBranchNode_( | 1174 var newNode = this.makeBranchNode_( |
| 1175 cvox.SemanticAttr.Type.FENCED, [childNode], [ofence, cfence]); | 1175 cvox.SemanticAttr.Type.FENCED, [childNode], [ofence, cfence]); |
| 1176 if (ofence.role == cvox.SemanticAttr.Role.OPEN) { | 1176 if (ofence.role == cvox.SemanticAttr.Role.OPEN) { |
| 1177 newNode.role = cvox.SemanticAttr.Role.LEFTRIGHT; | 1177 newNode.role = cvox.SemanticAttr.Role.LEFTRIGHT; |
| 1178 } else { | 1178 } else { |
| 1179 newNode.role = ofence.role; | 1179 newNode.role = ofence.role; |
| 1180 } | 1180 } |
| 1181 return newNode; | 1181 return newNode; |
| 1182 }; | 1182 }; |
| 1183 | 1183 |
| 1184 | 1184 |
| 1185 /** | 1185 /** |
| 1186 * Combines sequences of punctuated expressions in a list of nodes. | 1186 * Combines sequences of punctuated expressions in a list of nodes. |
| 1187 * @param {!Array.<cvox.SemanticTree.Node>} nodes The list of nodes. | 1187 * @param {!Array<cvox.SemanticTree.Node>} nodes The list of nodes. |
| 1188 * @return {!Array.<cvox.SemanticTree.Node>} The new list of nodes. | 1188 * @return {!Array<cvox.SemanticTree.Node>} The new list of nodes. |
| 1189 * @private | 1189 * @private |
| 1190 */ | 1190 */ |
| 1191 cvox.SemanticTree.prototype.getPunctuationInRow_ = function(nodes) { | 1191 cvox.SemanticTree.prototype.getPunctuationInRow_ = function(nodes) { |
| 1192 // For now we just make a punctuation node with a particular role. This is | 1192 // For now we just make a punctuation node with a particular role. This is |
| 1193 // similar to an mrow. The only exception are ellipses, which we assume to be | 1193 // similar to an mrow. The only exception are ellipses, which we assume to be |
| 1194 // in lieu of identifiers. | 1194 // in lieu of identifiers. |
| 1195 // In addition we keep the single punctuation nodes as content. | 1195 // In addition we keep the single punctuation nodes as content. |
| 1196 var partition = cvox.SemanticTree.partitionNodes_( | 1196 var partition = cvox.SemanticTree.partitionNodes_( |
| 1197 nodes, function(x) { | 1197 nodes, function(x) { |
| 1198 return cvox.SemanticTree.attrPred_('type', 'PUNCTUATION')(x) && | 1198 return cvox.SemanticTree.attrPred_('type', 'PUNCTUATION')(x) && |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1212 if (firstComp.length > 0) { | 1212 if (firstComp.length > 0) { |
| 1213 newNodes.push(this.processRow_(firstComp)); | 1213 newNodes.push(this.processRow_(firstComp)); |
| 1214 } | 1214 } |
| 1215 } | 1215 } |
| 1216 return [this.makePunctuatedNode_(newNodes, partition.rel)]; | 1216 return [this.makePunctuatedNode_(newNodes, partition.rel)]; |
| 1217 }; | 1217 }; |
| 1218 | 1218 |
| 1219 | 1219 |
| 1220 /** | 1220 /** |
| 1221 * Create a punctuated node. | 1221 * Create a punctuated node. |
| 1222 * @param {!Array.<!cvox.SemanticTree.Node>} nodes List of all nodes separated | 1222 * @param {!Array<!cvox.SemanticTree.Node>} nodes List of all nodes separated |
| 1223 * by punctuations. | 1223 * by punctuations. |
| 1224 * @param {!Array.<!cvox.SemanticTree.Node>} punctuations List of all separating | 1224 * @param {!Array<!cvox.SemanticTree.Node>} punctuations List of all separating |
| 1225 * punctations. Observe that punctations is a subset of nodes. | 1225 * punctations. Observe that punctations is a subset of nodes. |
| 1226 * @return {!cvox.SemanticTree.Node} | 1226 * @return {!cvox.SemanticTree.Node} |
| 1227 * @private | 1227 * @private |
| 1228 */ | 1228 */ |
| 1229 cvox.SemanticTree.prototype.makePunctuatedNode_ = function( | 1229 cvox.SemanticTree.prototype.makePunctuatedNode_ = function( |
| 1230 nodes, punctuations) { | 1230 nodes, punctuations) { |
| 1231 var newNode = this.makeBranchNode_( | 1231 var newNode = this.makeBranchNode_( |
| 1232 cvox.SemanticAttr.Type.PUNCTUATED, nodes, punctuations); | 1232 cvox.SemanticAttr.Type.PUNCTUATED, nodes, punctuations); |
| 1233 | 1233 |
| 1234 if (punctuations.length == 1 && | 1234 if (punctuations.length == 1 && |
| 1235 nodes[0].type == cvox.SemanticAttr.Type.PUNCTUATION) { | 1235 nodes[0].type == cvox.SemanticAttr.Type.PUNCTUATION) { |
| 1236 newNode.role = cvox.SemanticAttr.Role.STARTPUNCT; | 1236 newNode.role = cvox.SemanticAttr.Role.STARTPUNCT; |
| 1237 } else if (punctuations.length == 1 && | 1237 } else if (punctuations.length == 1 && |
| 1238 nodes[nodes.length - 1].type == cvox.SemanticAttr.Type.PUNCTUATION) { | 1238 nodes[nodes.length - 1].type == cvox.SemanticAttr.Type.PUNCTUATION) { |
| 1239 newNode.role = cvox.SemanticAttr.Role.ENDPUNCT; | 1239 newNode.role = cvox.SemanticAttr.Role.ENDPUNCT; |
| 1240 } else { | 1240 } else { |
| 1241 newNode.role = cvox.SemanticAttr.Role.SEQUENCE; | 1241 newNode.role = cvox.SemanticAttr.Role.SEQUENCE; |
| 1242 } | 1242 } |
| 1243 return newNode; | 1243 return newNode; |
| 1244 }; | 1244 }; |
| 1245 | 1245 |
| 1246 | 1246 |
| 1247 /** | 1247 /** |
| 1248 * Creates a limit node from a sub/superscript or over/under node if the central | 1248 * Creates a limit node from a sub/superscript or over/under node if the central |
| 1249 * element is a big operator. Otherwise it creates the standard elements. | 1249 * element is a big operator. Otherwise it creates the standard elements. |
| 1250 * @param {string} mmlTag The tag name of the original node. | 1250 * @param {string} mmlTag The tag name of the original node. |
| 1251 * @param {!Array.<!cvox.SemanticTree.Node>} children The children of the | 1251 * @param {!Array<!cvox.SemanticTree.Node>} children The children of the |
| 1252 * original node. | 1252 * original node. |
| 1253 * @return {!cvox.SemanticTree.Node} The newly created limit node. | 1253 * @return {!cvox.SemanticTree.Node} The newly created limit node. |
| 1254 * @private | 1254 * @private |
| 1255 */ | 1255 */ |
| 1256 cvox.SemanticTree.prototype.makeLimitNode_ = function(mmlTag, children) { | 1256 cvox.SemanticTree.prototype.makeLimitNode_ = function(mmlTag, children) { |
| 1257 var center = children[0]; | 1257 var center = children[0]; |
| 1258 var isFunction = cvox.SemanticTree.attrPred_('type', 'FUNCTION')(center); | 1258 var isFunction = cvox.SemanticTree.attrPred_('type', 'FUNCTION')(center); |
| 1259 // TODO (sorge) Put this into a single function. | 1259 // TODO (sorge) Put this into a single function. |
| 1260 var isLimit = cvox.SemanticTree.attrPred_('type', 'LARGEOP')(center) || | 1260 var isLimit = cvox.SemanticTree.attrPred_('type', 'LARGEOP')(center) || |
| 1261 cvox.SemanticTree.attrPred_('type', 'LIMBOTH')(center) || | 1261 cvox.SemanticTree.attrPred_('type', 'LIMBOTH')(center) || |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1324 * as a functional expressions that consists of a prefix and some arguments. | 1324 * as a functional expressions that consists of a prefix and some arguments. |
| 1325 * In particular we distinguish four types of functional expressions: | 1325 * In particular we distinguish four types of functional expressions: |
| 1326 * - integral: Integral expression. | 1326 * - integral: Integral expression. |
| 1327 * - bigop: A big operator expression like a sum. | 1327 * - bigop: A big operator expression like a sum. |
| 1328 * - prefix: A well defined prefix function such as sin, cos or a limit | 1328 * - prefix: A well defined prefix function such as sin, cos or a limit |
| 1329 * functions like lim, max. | 1329 * functions like lim, max. |
| 1330 * - simple: An expression consisting of letters that are potentially a function | 1330 * - simple: An expression consisting of letters that are potentially a function |
| 1331 * symbol. If we have an explicit function application symbol | 1331 * symbol. If we have an explicit function application symbol |
| 1332 * following the expression we turn into a prefix function. Otherwise | 1332 * following the expression we turn into a prefix function. Otherwise |
| 1333 * we decide heuristically if we could have a function application. | 1333 * we decide heuristically if we could have a function application. |
| 1334 * @param {!Array.<cvox.SemanticTree.Node>} restNodes The remainder list of | 1334 * @param {!Array<cvox.SemanticTree.Node>} restNodes The remainder list of |
| 1335 * nodes. | 1335 * nodes. |
| 1336 * @param {!Array.<cvox.SemanticTree.Node>=} result The result node list. | 1336 * @param {!Array<cvox.SemanticTree.Node>=} result The result node list. |
| 1337 * @return {!Array.<!cvox.SemanticTree.Node>} The fully processed list. | 1337 * @return {!Array<!cvox.SemanticTree.Node>} The fully processed list. |
| 1338 * @private | 1338 * @private |
| 1339 */ | 1339 */ |
| 1340 cvox.SemanticTree.prototype.getFunctionsInRow_ = function(restNodes, result) { | 1340 cvox.SemanticTree.prototype.getFunctionsInRow_ = function(restNodes, result) { |
| 1341 result = result || []; | 1341 result = result || []; |
| 1342 // Base case. | 1342 // Base case. |
| 1343 if (restNodes.length == 0) { | 1343 if (restNodes.length == 0) { |
| 1344 return result; | 1344 return result; |
| 1345 } | 1345 } |
| 1346 var firstNode = /** @type {!cvox.SemanticTree.Node} */ (restNodes.shift()); | 1346 var firstNode = /** @type {!cvox.SemanticTree.Node} */ (restNodes.shift()); |
| 1347 var heuristic = cvox.SemanticTree.classifyFunction_(firstNode, restNodes); | 1347 var heuristic = cvox.SemanticTree.classifyFunction_(firstNode, restNodes); |
| 1348 // First node is not a function node. | 1348 // First node is not a function node. |
| 1349 if (!heuristic) { | 1349 if (!heuristic) { |
| 1350 result.push(firstNode); | 1350 result.push(firstNode); |
| 1351 return this.getFunctionsInRow_(restNodes, result); | 1351 return this.getFunctionsInRow_(restNodes, result); |
| 1352 } | 1352 } |
| 1353 // Combine functions in the rest of the row. | 1353 // Combine functions in the rest of the row. |
| 1354 var processedRest = this.getFunctionsInRow_(restNodes, []); | 1354 var processedRest = this.getFunctionsInRow_(restNodes, []); |
| 1355 var newRest = this.getFunctionArgs_(firstNode, processedRest, heuristic); | 1355 var newRest = this.getFunctionArgs_(firstNode, processedRest, heuristic); |
| 1356 return result.concat(newRest); | 1356 return result.concat(newRest); |
| 1357 }; | 1357 }; |
| 1358 | 1358 |
| 1359 | 1359 |
| 1360 /** | 1360 /** |
| 1361 * Classifies a function wrt. the heuristic that should be applied. | 1361 * Classifies a function wrt. the heuristic that should be applied. |
| 1362 * @param {!cvox.SemanticTree.Node} funcNode The node to be classified. | 1362 * @param {!cvox.SemanticTree.Node} funcNode The node to be classified. |
| 1363 * @param {!Array.<cvox.SemanticTree.Node>} restNodes The remainder list of | 1363 * @param {!Array<cvox.SemanticTree.Node>} restNodes The remainder list of |
| 1364 * nodes. They can useful to look ahead if there is an explicit function | 1364 * nodes. They can useful to look ahead if there is an explicit function |
| 1365 * application. If there is one, it will be destructively removed! | 1365 * application. If there is one, it will be destructively removed! |
| 1366 * @return {!string} The string specifying the heuristic. | 1366 * @return {!string} The string specifying the heuristic. |
| 1367 * @private | 1367 * @private |
| 1368 */ | 1368 */ |
| 1369 cvox.SemanticTree.classifyFunction_ = function(funcNode, restNodes) { | 1369 cvox.SemanticTree.classifyFunction_ = function(funcNode, restNodes) { |
| 1370 // We do not allow double function application. This is not lambda calculus! | 1370 // We do not allow double function application. This is not lambda calculus! |
| 1371 if (funcNode.type == cvox.SemanticAttr.Type.APPL || | 1371 if (funcNode.type == cvox.SemanticAttr.Type.APPL || |
| 1372 funcNode.type == cvox.SemanticAttr.Type.BIGOP || | 1372 funcNode.type == cvox.SemanticAttr.Type.BIGOP || |
| 1373 funcNode.type == cvox.SemanticAttr.Type.INTEGRAL) { | 1373 funcNode.type == cvox.SemanticAttr.Type.INTEGRAL) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1415 funcNode.role = cvox.SemanticAttr.Role.PREFIXFUNC; | 1415 funcNode.role = cvox.SemanticAttr.Role.PREFIXFUNC; |
| 1416 cvox.SemanticTree.propagatePrefixFunc_(funcNode.childNodes[0]); | 1416 cvox.SemanticTree.propagatePrefixFunc_(funcNode.childNodes[0]); |
| 1417 } | 1417 } |
| 1418 }; | 1418 }; |
| 1419 | 1419 |
| 1420 | 1420 |
| 1421 /** | 1421 /** |
| 1422 * Computes the arguments for a function from a list of nodes depending on the | 1422 * Computes the arguments for a function from a list of nodes depending on the |
| 1423 * given heuristic. | 1423 * given heuristic. |
| 1424 * @param {!cvox.SemanticTree.Node} func A function node. | 1424 * @param {!cvox.SemanticTree.Node} func A function node. |
| 1425 * @param {!Array.<cvox.SemanticTree.Node>} rest List of nodes to choose | 1425 * @param {!Array<cvox.SemanticTree.Node>} rest List of nodes to choose |
| 1426 * arguments from. | 1426 * arguments from. |
| 1427 * @param {string} heuristic The heuristic to follow. | 1427 * @param {string} heuristic The heuristic to follow. |
| 1428 * @return {!Array.<!cvox.SemanticTree.Node>} The function and the remainder of | 1428 * @return {!Array<!cvox.SemanticTree.Node>} The function and the remainder of |
| 1429 * the rest list. | 1429 * the rest list. |
| 1430 * @private | 1430 * @private |
| 1431 */ | 1431 */ |
| 1432 cvox.SemanticTree.prototype.getFunctionArgs_ = function(func, rest, heuristic) { | 1432 cvox.SemanticTree.prototype.getFunctionArgs_ = function(func, rest, heuristic) { |
| 1433 switch (heuristic) { | 1433 switch (heuristic) { |
| 1434 case 'integral': | 1434 case 'integral': |
| 1435 var components = this.getIntegralArgs_(rest); | 1435 var components = this.getIntegralArgs_(rest); |
| 1436 var integrand = this.processRow_(components.integrand); | 1436 var integrand = this.processRow_(components.integrand); |
| 1437 var funcNode = this.makeIntegralNode_(func, integrand, components.intvar); | 1437 var funcNode = this.makeIntegralNode_(func, integrand, components.intvar); |
| 1438 components.rest.unshift(funcNode); | 1438 components.rest.unshift(funcNode); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1475 } | 1475 } |
| 1476 rest.unshift(func); | 1476 rest.unshift(func); |
| 1477 return rest; | 1477 return rest; |
| 1478 break; | 1478 break; |
| 1479 } | 1479 } |
| 1480 }; | 1480 }; |
| 1481 | 1481 |
| 1482 | 1482 |
| 1483 /** | 1483 /** |
| 1484 * Tail recursive function to obtain integral arguments. | 1484 * Tail recursive function to obtain integral arguments. |
| 1485 * @param {!Array.<cvox.SemanticTree.Node>} nodes List of nodes to take | 1485 * @param {!Array<cvox.SemanticTree.Node>} nodes List of nodes to take |
| 1486 * arguments from. | 1486 * arguments from. |
| 1487 * @param {Array.<cvox.SemanticTree.Node>=} args List of integral arguments. | 1487 * @param {Array<cvox.SemanticTree.Node>=} args List of integral arguments. |
| 1488 * @return {{integrand: !Array.<cvox.SemanticTree.Node>, | 1488 * @return {{integrand: !Array<cvox.SemanticTree.Node>, |
| 1489 * intvar: cvox.SemanticTree.Node, | 1489 * intvar: cvox.SemanticTree.Node, |
| 1490 * rest: !Array.<cvox.SemanticTree.Node>}} | 1490 * rest: !Array<cvox.SemanticTree.Node>}} |
| 1491 * Result split into integrand, integral variable and the remaining | 1491 * Result split into integrand, integral variable and the remaining |
| 1492 * elements. | 1492 * elements. |
| 1493 * @private | 1493 * @private |
| 1494 */ | 1494 */ |
| 1495 cvox.SemanticTree.prototype.getIntegralArgs_ = function(nodes, args) { | 1495 cvox.SemanticTree.prototype.getIntegralArgs_ = function(nodes, args) { |
| 1496 args = args || []; | 1496 args = args || []; |
| 1497 if (nodes.length == 0) { | 1497 if (nodes.length == 0) { |
| 1498 return {integrand: args, intvar: null, rest: nodes}; | 1498 return {integrand: args, intvar: null, rest: nodes}; |
| 1499 } | 1499 } |
| 1500 var firstNode = nodes[0]; | 1500 var firstNode = nodes[0]; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 * @private | 1657 * @private |
| 1658 */ | 1658 */ |
| 1659 cvox.SemanticTree.generalFunctionBoundary_ = function(node) { | 1659 cvox.SemanticTree.generalFunctionBoundary_ = function(node) { |
| 1660 return cvox.SemanticTree.attrPred_('type', 'RELATION')(node) || | 1660 return cvox.SemanticTree.attrPred_('type', 'RELATION')(node) || |
| 1661 cvox.SemanticTree.attrPred_('type', 'PUNCTUATION')(node); | 1661 cvox.SemanticTree.attrPred_('type', 'PUNCTUATION')(node); |
| 1662 }; | 1662 }; |
| 1663 | 1663 |
| 1664 | 1664 |
| 1665 /** | 1665 /** |
| 1666 * Rewrites tables into matrices or case statements in a list of nodes. | 1666 * Rewrites tables into matrices or case statements in a list of nodes. |
| 1667 * @param {!Array.<cvox.SemanticTree.Node>} nodes List of nodes to rewrite. | 1667 * @param {!Array<cvox.SemanticTree.Node>} nodes List of nodes to rewrite. |
| 1668 * @return {!Array.<cvox.SemanticTree.Node>} The new list of nodes. | 1668 * @return {!Array<cvox.SemanticTree.Node>} The new list of nodes. |
| 1669 * @private | 1669 * @private |
| 1670 */ | 1670 */ |
| 1671 cvox.SemanticTree.prototype.processTablesInRow_ = function(nodes) { | 1671 cvox.SemanticTree.prototype.processTablesInRow_ = function(nodes) { |
| 1672 // First we process all matrices: | 1672 // First we process all matrices: |
| 1673 var partition = cvox.SemanticTree.partitionNodes_( | 1673 var partition = cvox.SemanticTree.partitionNodes_( |
| 1674 nodes, cvox.SemanticTree.tableIsMatrixOrVector_); | 1674 nodes, cvox.SemanticTree.tableIsMatrixOrVector_); |
| 1675 var result = []; | 1675 var result = []; |
| 1676 for (var i = 0, matrix; matrix = partition.rel[i]; i++) { | 1676 for (var i = 0, matrix; matrix = partition.rel[i]; i++) { |
| 1677 result = result.concat(partition.comp.shift()); | 1677 result = result.concat(partition.comp.shift()); |
| 1678 result.push(this.tableToMatrixOrVector_(matrix)); | 1678 result.push(this.tableToMatrixOrVector_(matrix)); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 cvox.SemanticTree.assignRoleToRow_(row, cvox.SemanticAttr.Role[type]); | 1738 cvox.SemanticTree.assignRoleToRow_(row, cvox.SemanticAttr.Role[type]); |
| 1739 } | 1739 } |
| 1740 return matrix; | 1740 return matrix; |
| 1741 }; | 1741 }; |
| 1742 | 1742 |
| 1743 | 1743 |
| 1744 /** | 1744 /** |
| 1745 * Heuristic to decide if we have a case statement: An expression with a | 1745 * Heuristic to decide if we have a case statement: An expression with a |
| 1746 * singular open fence before it. | 1746 * singular open fence before it. |
| 1747 * @param {!cvox.SemanticTree.Node} table A table node. | 1747 * @param {!cvox.SemanticTree.Node} table A table node. |
| 1748 * @param {!Array.<cvox.SemanticTree.Node>} prevNodes A list of previous nodes. | 1748 * @param {!Array<cvox.SemanticTree.Node>} prevNodes A list of previous nodes. |
| 1749 * @return {boolean} True if we believe we have a case statement. | 1749 * @return {boolean} True if we believe we have a case statement. |
| 1750 * @private | 1750 * @private |
| 1751 */ | 1751 */ |
| 1752 cvox.SemanticTree.tableIsCases_ = function(table, prevNodes) { | 1752 cvox.SemanticTree.tableIsCases_ = function(table, prevNodes) { |
| 1753 return prevNodes.length > 0 && | 1753 return prevNodes.length > 0 && |
| 1754 cvox.SemanticTree.attrPred_('role', 'OPENFENCE')( | 1754 cvox.SemanticTree.attrPred_('role', 'OPENFENCE')( |
| 1755 prevNodes[prevNodes.length - 1]); | 1755 prevNodes[prevNodes.length - 1]); |
| 1756 }; | 1756 }; |
| 1757 | 1757 |
| 1758 | 1758 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1845 if (cellPred(cell)) { | 1845 if (cellPred(cell)) { |
| 1846 cell.role = role; | 1846 cell.role = role; |
| 1847 } | 1847 } |
| 1848 }); | 1848 }); |
| 1849 } | 1849 } |
| 1850 }; | 1850 }; |
| 1851 | 1851 |
| 1852 | 1852 |
| 1853 /** | 1853 /** |
| 1854 * Splits a list of nodes wrt. to a given predicate. | 1854 * Splits a list of nodes wrt. to a given predicate. |
| 1855 * @param {Array.<cvox.SemanticTree.Node>} nodes A list of nodes. | 1855 * @param {Array<cvox.SemanticTree.Node>} nodes A list of nodes. |
| 1856 * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the | 1856 * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the |
| 1857 * partitioning relation. | 1857 * partitioning relation. |
| 1858 * @param {boolean=} reverse If true slicing is done from the end. | 1858 * @param {boolean=} reverse If true slicing is done from the end. |
| 1859 * @return {{head: !Array.<cvox.SemanticTree.Node>, | 1859 * @return {{head: !Array<cvox.SemanticTree.Node>, |
| 1860 * div: cvox.SemanticTree.Node, | 1860 * div: cvox.SemanticTree.Node, |
| 1861 * tail: !Array.<cvox.SemanticTree.Node>}} The split list. | 1861 * tail: !Array<cvox.SemanticTree.Node>}} The split list. |
| 1862 * @private | 1862 * @private |
| 1863 */ | 1863 */ |
| 1864 cvox.SemanticTree.sliceNodes_ = function(nodes, pred, reverse) { | 1864 cvox.SemanticTree.sliceNodes_ = function(nodes, pred, reverse) { |
| 1865 if (reverse) { | 1865 if (reverse) { |
| 1866 nodes.reverse(); | 1866 nodes.reverse(); |
| 1867 } | 1867 } |
| 1868 var head = []; | 1868 var head = []; |
| 1869 for (var i = 0, node; node = nodes[i]; i++) { | 1869 for (var i = 0, node; node = nodes[i]; i++) { |
| 1870 if (pred(node)) { | 1870 if (pred(node)) { |
| 1871 if (reverse) { | 1871 if (reverse) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1882 if (reverse) { | 1882 if (reverse) { |
| 1883 return {head: [], div: null, tail: head.reverse()}; | 1883 return {head: [], div: null, tail: head.reverse()}; |
| 1884 } | 1884 } |
| 1885 return {head: head, div: null, tail: []}; | 1885 return {head: head, div: null, tail: []}; |
| 1886 }; | 1886 }; |
| 1887 | 1887 |
| 1888 | 1888 |
| 1889 /** | 1889 /** |
| 1890 * Partitions a list of nodes wrt. to a given predicate. Effectively works like | 1890 * Partitions a list of nodes wrt. to a given predicate. Effectively works like |
| 1891 * a PER on the ordered set of nodes. | 1891 * a PER on the ordered set of nodes. |
| 1892 * @param {!Array.<!cvox.SemanticTree.Node>} nodes A list of nodes. | 1892 * @param {!Array<!cvox.SemanticTree.Node>} nodes A list of nodes. |
| 1893 * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the | 1893 * @param {!function(cvox.SemanticTree.Node): boolean} pred Predicate for the |
| 1894 * partitioning relation. | 1894 * partitioning relation. |
| 1895 * @return {{rel: !Array.<cvox.SemanticTree.Node>, | 1895 * @return {{rel: !Array<cvox.SemanticTree.Node>, |
| 1896 * comp: !Array.<!Array.<cvox.SemanticTree.Node>>}} | 1896 * comp: !Array<!Array<cvox.SemanticTree.Node>>}} |
| 1897 * The partitioning given in terms of a collection of elements satisfying | 1897 * The partitioning given in terms of a collection of elements satisfying |
| 1898 * the predicate and a collection of complementary sets lying inbetween the | 1898 * the predicate and a collection of complementary sets lying inbetween the |
| 1899 * related elements. Observe that we always have |comp| = |rel| + 1. | 1899 * related elements. Observe that we always have |comp| = |rel| + 1. |
| 1900 * | 1900 * |
| 1901 * Example: On input [a, r_1, b, c, r_2, d, e, r_3] where P(r_i) holds, we | 1901 * Example: On input [a, r_1, b, c, r_2, d, e, r_3] where P(r_i) holds, we |
| 1902 * get as output: {rel: [r_1, r_2, r_3], comp: [[a], [b, c], [d, e], []]. | 1902 * get as output: {rel: [r_1, r_2, r_3], comp: [[a], [b, c], [d, e], []]. |
| 1903 * @private | 1903 * @private |
| 1904 */ | 1904 */ |
| 1905 cvox.SemanticTree.partitionNodes_ = function(nodes, pred) { | 1905 cvox.SemanticTree.partitionNodes_ = function(nodes, pred) { |
| 1906 var restNodes = nodes; | 1906 var restNodes = nodes; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1930 var getAttr = function(prop) { | 1930 var getAttr = function(prop) { |
| 1931 switch (prop) { | 1931 switch (prop) { |
| 1932 case 'type': return cvox.SemanticAttr.Type[attr]; | 1932 case 'type': return cvox.SemanticAttr.Type[attr]; |
| 1933 case 'role': return cvox.SemanticAttr.Role[attr]; | 1933 case 'role': return cvox.SemanticAttr.Role[attr]; |
| 1934 case 'font': return cvox.SemanticAttr.Font[attr]; | 1934 case 'font': return cvox.SemanticAttr.Font[attr]; |
| 1935 } | 1935 } |
| 1936 }; | 1936 }; |
| 1937 | 1937 |
| 1938 return function(node) {return node[prop] == getAttr(prop);}; | 1938 return function(node) {return node[prop] == getAttr(prop);}; |
| 1939 }; | 1939 }; |
| OLD | NEW |