OR-1 dataflow CPU sketch
at main 916 lines 26 kB view raw
1const binding = typeof process.versions.bun === "string" ? 2 // Statically analyzable enough for `bun build --compile` to embed the tree-sitter.node napi addon 3 require(`./prebuilds/${process.platform}-${process.arch}/tree-sitter.node`) : 4 require('node-gyp-build')(__dirname); 5const {Query, Parser, NodeMethods, Tree, TreeCursor, LookaheadIterator} = binding; 6 7const util = require('util'); 8 9/* 10 * Tree 11 */ 12 13const {rootNode, rootNodeWithOffset, edit} = Tree.prototype; 14 15Object.defineProperty(Tree.prototype, 'rootNode', { 16 get() { 17 /* 18 Due to a race condition arising from Jest's worker pool, "this" 19 has no knowledge of the native extension if the extension has not 20 yet loaded when multiple Jest tests are being run simultaneously. 21 If the extension has correctly loaded, "this" should be an instance 22 of the class whose prototype we are acting on (in this case, Tree). 23 Furthermore, the race condition sometimes results in the function in 24 question being undefined even when the context is correct, so we also 25 perform a null function check. 26 */ 27 if (this instanceof Tree && rootNode) { 28 return unmarshalNode(rootNode.call(this), this); 29 } 30 }, 31 // Jest worker pool may attempt to override property due to race condition, 32 // we don't want to error on this 33 configurable: true 34}); 35 36Tree.prototype.rootNodeWithOffset = function(offset_bytes, offset_extent) { 37 return unmarshalNode(rootNodeWithOffset.call(this, offset_bytes, offset_extent.row, offset_extent.column), this); 38} 39 40Tree.prototype.edit = function(arg) { 41 if (this instanceof Tree && edit) { 42 edit.call( 43 this, 44 arg.startPosition.row, arg.startPosition.column, 45 arg.oldEndPosition.row, arg.oldEndPosition.column, 46 arg.newEndPosition.row, arg.newEndPosition.column, 47 arg.startIndex, 48 arg.oldEndIndex, 49 arg.newEndIndex 50 ); 51 } 52}; 53 54Tree.prototype.walk = function() { 55 return this.rootNode.walk() 56}; 57 58/* 59 * Node 60 */ 61 62class SyntaxNode { 63 constructor(tree) { 64 this.tree = tree; 65 } 66 67 [util.inspect.custom]() { 68 return this.constructor.name + ' {\n' + 69 ' type: ' + this.type + ',\n' + 70 ' startPosition: ' + pointToString(this.startPosition) + ',\n' + 71 ' endPosition: ' + pointToString(this.endPosition) + ',\n' + 72 ' childCount: ' + this.childCount + ',\n' + 73 '}' 74 } 75 76 get id() { 77 marshalNode(this); 78 return NodeMethods.id(this.tree); 79 } 80 81 get typeId() { 82 marshalNode(this); 83 return NodeMethods.typeId(this.tree); 84 } 85 86 get grammarId() { 87 marshalNode(this); 88 return NodeMethods.grammarId(this.tree); 89 } 90 91 get type() { 92 marshalNode(this); 93 return NodeMethods.type(this.tree); 94 } 95 96 get grammarType() { 97 marshalNode(this); 98 return NodeMethods.grammarType(this.tree); 99 } 100 101 get isExtra() { 102 marshalNode(this); 103 return NodeMethods.isExtra(this.tree); 104 } 105 106 get isNamed() { 107 marshalNode(this); 108 return NodeMethods.isNamed(this.tree); 109 } 110 111 get isMissing() { 112 marshalNode(this); 113 return NodeMethods.isMissing(this.tree); 114 } 115 116 get hasChanges() { 117 marshalNode(this); 118 return NodeMethods.hasChanges(this.tree); 119 } 120 121 get hasError() { 122 marshalNode(this); 123 return NodeMethods.hasError(this.tree); 124 } 125 126 get isError() { 127 marshalNode(this); 128 return NodeMethods.isError(this.tree); 129 } 130 131 get text() { 132 return this.tree.getText(this); 133 } 134 135 get startPosition() { 136 marshalNode(this); 137 NodeMethods.startPosition(this.tree); 138 return unmarshalPoint(); 139 } 140 141 get endPosition() { 142 marshalNode(this); 143 NodeMethods.endPosition(this.tree); 144 return unmarshalPoint(); 145 } 146 147 get startIndex() { 148 marshalNode(this); 149 return NodeMethods.startIndex(this.tree); 150 } 151 152 get endIndex() { 153 marshalNode(this); 154 return NodeMethods.endIndex(this.tree); 155 } 156 157 get parent() { 158 marshalNode(this); 159 return unmarshalNode(NodeMethods.parent(this.tree), this.tree); 160 } 161 162 get children() { 163 marshalNode(this); 164 return unmarshalNodes(NodeMethods.children(this.tree), this.tree); 165 } 166 167 get namedChildren() { 168 marshalNode(this); 169 return unmarshalNodes(NodeMethods.namedChildren(this.tree), this.tree); 170 } 171 172 get childCount() { 173 marshalNode(this); 174 return NodeMethods.childCount(this.tree); 175 } 176 177 get namedChildCount() { 178 marshalNode(this); 179 return NodeMethods.namedChildCount(this.tree); 180 } 181 182 get firstChild() { 183 marshalNode(this); 184 return unmarshalNode(NodeMethods.firstChild(this.tree), this.tree); 185 } 186 187 get firstNamedChild() { 188 marshalNode(this); 189 return unmarshalNode(NodeMethods.firstNamedChild(this.tree), this.tree); 190 } 191 192 get lastChild() { 193 marshalNode(this); 194 return unmarshalNode(NodeMethods.lastChild(this.tree), this.tree); 195 } 196 197 get lastNamedChild() { 198 marshalNode(this); 199 return unmarshalNode(NodeMethods.lastNamedChild(this.tree), this.tree); 200 } 201 202 get nextSibling() { 203 marshalNode(this); 204 return unmarshalNode(NodeMethods.nextSibling(this.tree), this.tree); 205 } 206 207 get nextNamedSibling() { 208 marshalNode(this); 209 return unmarshalNode(NodeMethods.nextNamedSibling(this.tree), this.tree); 210 } 211 212 get previousSibling() { 213 marshalNode(this); 214 return unmarshalNode(NodeMethods.previousSibling(this.tree), this.tree); 215 } 216 217 get previousNamedSibling() { 218 marshalNode(this); 219 return unmarshalNode(NodeMethods.previousNamedSibling(this.tree), this.tree); 220 } 221 222 get parseState() { 223 marshalNode(this); 224 return NodeMethods.parseState(this.tree); 225 } 226 227 get nextParseState() { 228 marshalNode(this); 229 return NodeMethods.nextParseState(this.tree); 230 } 231 232 get descendantCount() { 233 marshalNode(this); 234 return NodeMethods.descendantCount(this.tree); 235 } 236 237 toString() { 238 marshalNode(this); 239 return NodeMethods.toString(this.tree); 240 } 241 242 child(index) { 243 marshalNode(this); 244 return unmarshalNode(NodeMethods.child(this.tree, index), this.tree); 245 } 246 247 namedChild(index) { 248 marshalNode(this); 249 return unmarshalNode(NodeMethods.namedChild(this.tree, index), this.tree); 250 } 251 252 childForFieldName(fieldName) { 253 marshalNode(this); 254 return unmarshalNode(NodeMethods.childForFieldName(this.tree, fieldName), this.tree); 255 } 256 257 childForFieldId(fieldId) { 258 marshalNode(this); 259 return unmarshalNode(NodeMethods.childForFieldId(this.tree, fieldId), this.tree); 260 } 261 262 fieldNameForChild(childIndex) { 263 marshalNode(this); 264 return NodeMethods.fieldNameForChild(this.tree, childIndex); 265 } 266 267 fieldNameForNamedChild(namedChildIndex) { 268 marshalNode(this); 269 return NodeMethods.fieldNameForNamedChild(this.tree, namedChildIndex); 270 } 271 272 childrenForFieldName(fieldName) { 273 marshalNode(this); 274 return unmarshalNodes(NodeMethods.childrenForFieldName(this.tree, fieldName), this.tree); 275 } 276 277 childrenForFieldId(fieldId) { 278 marshalNode(this); 279 return unmarshalNodes(NodeMethods.childrenForFieldId(this.tree, fieldId), this.tree); 280 } 281 282 firstChildForIndex(index) { 283 marshalNode(this); 284 return unmarshalNode(NodeMethods.firstChildForIndex(this.tree, index), this.tree); 285 } 286 287 firstNamedChildForIndex(index) { 288 marshalNode(this); 289 return unmarshalNode(NodeMethods.firstNamedChildForIndex(this.tree, index), this.tree); 290 } 291 292 childWithDescendant(descendant) { 293 marshalNodes([this, descendant]); 294 return unmarshalNode(NodeMethods.childWithDescendant(this.tree, descendant.tree), this.tree); 295 } 296 297 namedDescendantForIndex(start, end) { 298 marshalNode(this); 299 if (end == null) end = start; 300 return unmarshalNode(NodeMethods.namedDescendantForIndex(this.tree, start, end), this.tree); 301 } 302 303 descendantForIndex(start, end) { 304 marshalNode(this); 305 if (end == null) end = start; 306 return unmarshalNode(NodeMethods.descendantForIndex(this.tree, start, end), this.tree); 307 } 308 309 descendantsOfType(types, start, end) { 310 marshalNode(this); 311 if (typeof types === 'string') types = [types] 312 return unmarshalNodes(NodeMethods.descendantsOfType(this.tree, types, start, end), this.tree); 313 } 314 315 namedDescendantForPosition(start, end) { 316 marshalNode(this); 317 if (end == null) end = start; 318 return unmarshalNode(NodeMethods.namedDescendantForPosition(this.tree, start, end), this.tree); 319 } 320 321 descendantForPosition(start, end) { 322 marshalNode(this); 323 if (end == null) end = start; 324 return unmarshalNode(NodeMethods.descendantForPosition(this.tree, start, end), this.tree); 325 } 326 327 closest(types) { 328 marshalNode(this); 329 if (typeof types === 'string') types = [types] 330 return unmarshalNode(NodeMethods.closest(this.tree, types), this.tree); 331 } 332 333 walk () { 334 marshalNode(this); 335 const cursor = NodeMethods.walk(this.tree); 336 cursor.tree = this.tree; 337 unmarshalNode(cursor.currentNode, this.tree); 338 return cursor; 339 } 340} 341 342/* 343 * Parser 344 */ 345 346const {parse, setLanguage} = Parser.prototype; 347const languageSymbol = Symbol('parser.language'); 348 349Parser.prototype.setLanguage = function(language) { 350 if (this instanceof Parser && setLanguage) { 351 setLanguage.call(this, language); 352 } 353 this[languageSymbol] = language; 354 if (!language.nodeSubclasses) { 355 initializeLanguageNodeClasses(language) 356 } 357 return this; 358}; 359 360Parser.prototype.getLanguage = function(_language) { 361 return this[languageSymbol] || null; 362}; 363 364Parser.prototype.parse = function(input, oldTree, {bufferSize, includedRanges}={}) { 365 let getText, treeInput = input 366 if (typeof input === 'string') { 367 const inputString = input; 368 input = (offset, _position) => inputString.slice(offset) 369 getText = getTextFromString 370 } else { 371 getText = getTextFromFunction 372 } 373 const tree = this instanceof Parser && parse 374 ? parse.call( 375 this, 376 input, 377 oldTree, 378 bufferSize, 379 includedRanges, 380 ) 381 : undefined; 382 383 if (tree) { 384 tree.input = treeInput 385 tree.getText = getText 386 tree.language = this.getLanguage() 387 } 388 return tree 389}; 390 391/* 392 * TreeCursor 393 */ 394 395const {startPosition, endPosition, currentNode} = TreeCursor.prototype; 396 397Object.defineProperties(TreeCursor.prototype, { 398 currentNode: { 399 get() { 400 if (this instanceof TreeCursor && currentNode) { 401 return unmarshalNode(currentNode.call(this), this.tree); 402 } 403 }, 404 configurable: true 405 }, 406 startPosition: { 407 get() { 408 if (this instanceof TreeCursor && startPosition) { 409 startPosition.call(this); 410 return unmarshalPoint(); 411 } 412 }, 413 configurable: true 414 }, 415 endPosition: { 416 get() { 417 if (this instanceof TreeCursor && endPosition) { 418 endPosition.call(this); 419 return unmarshalPoint(); 420 } 421 }, 422 configurable: true 423 }, 424 nodeText: { 425 get() { 426 return this.tree.getText(this) 427 }, 428 configurable: true 429 } 430}); 431 432/* 433 * Query 434 */ 435 436const {_matches, _captures} = Query.prototype; 437 438const PREDICATE_STEP_TYPE = { 439 DONE: 0, 440 CAPTURE: 1, 441 STRING: 2, 442} 443 444const ZERO_POINT = { row: 0, column: 0 }; 445 446Query.prototype._init = function() { 447 /* 448 * Initialize predicate functions 449 * format: [type1, value1, type2, value2, ...] 450 */ 451 const predicateDescriptions = this._getPredicates(); 452 const patternCount = predicateDescriptions.length; 453 454 const setProperties = new Array(patternCount); 455 const assertedProperties = new Array(patternCount); 456 const refutedProperties = new Array(patternCount); 457 const predicates = new Array(patternCount); 458 459 const FIRST = 0 460 const SECOND = 2 461 const THIRD = 4 462 463 for (let i = 0; i < predicateDescriptions.length; i++) { 464 predicates[i] = []; 465 466 for (let j = 0; j < predicateDescriptions[i].length; j++) { 467 468 const steps = predicateDescriptions[i][j]; 469 const stepsLength = steps.length / 2; 470 471 if (steps[FIRST] !== PREDICATE_STEP_TYPE.STRING) { 472 throw new Error('Predicates must begin with a literal value'); 473 } 474 475 const operator = steps[FIRST + 1]; 476 477 let isPositive = true; 478 let matchAll = true; 479 let captureName; 480 switch (operator) { 481 case 'any-not-eq?': 482 case 'not-eq?': 483 isPositive = false; 484 case 'any-eq?': 485 case 'eq?': 486 if (stepsLength !== 3) throw new Error( 487 `Wrong number of arguments to \`#eq?\` predicate. Expected 2, got ${stepsLength - 1}` 488 ); 489 if (steps[SECOND] !== PREDICATE_STEP_TYPE.CAPTURE) throw new Error( 490 `First argument of \`#eq?\` predicate must be a capture. Got "${steps[SECOND + 1]}"` 491 ); 492 matchAll = !operator.startsWith('any-'); 493 if (steps[THIRD] === PREDICATE_STEP_TYPE.CAPTURE) { 494 const captureName1 = steps[SECOND + 1]; 495 const captureName2 = steps[THIRD + 1]; 496 predicates[i].push(function (captures) { 497 let nodes_1 = []; 498 let nodes_2 = []; 499 for (const c of captures) { 500 if (c.name === captureName1) nodes_1.push(c.node); 501 if (c.name === captureName2) nodes_2.push(c.node); 502 } 503 let compare = (n1, n2, positive) => { 504 return positive ? 505 n1.text === n2.text : 506 n1.text !== n2.text; 507 }; 508 return matchAll 509 ? nodes_1.every(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive))) 510 : nodes_1.some(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive))); 511 }); 512 } else { 513 captureName = steps[SECOND + 1]; 514 const stringValue = steps[THIRD + 1]; 515 let matches = (n) => n.text === stringValue; 516 let doesNotMatch = (n) => n.text !== stringValue; 517 predicates[i].push(function (captures) { 518 let nodes = []; 519 for (const c of captures) { 520 if (c.name === captureName) nodes.push(c.node); 521 } 522 let test = isPositive ? matches : doesNotMatch; 523 return matchAll 524 ? nodes.every(test) 525 : nodes.some(test); 526 }); 527 } 528 break; 529 530 case 'any-not-match?': 531 case 'not-match?': 532 isPositive = false; 533 case 'any-match?': 534 case 'match?': 535 if (stepsLength !== 3) throw new Error( 536 `Wrong number of arguments to \`#match?\` predicate. Expected 2, got ${stepsLength - 1}.` 537 ); 538 if (steps[SECOND] !== PREDICATE_STEP_TYPE.CAPTURE) throw new Error( 539 `First argument of \`#match?\` predicate must be a capture. Got "${steps[SECOND + 1]}".` 540 ); 541 if (steps[THIRD] !== PREDICATE_STEP_TYPE.STRING) throw new Error( 542 `Second argument of \`#match?\` predicate must be a string. Got @${steps[THIRD + 1]}.` 543 ); 544 captureName = steps[SECOND + 1]; 545 const regex = new RegExp(steps[THIRD + 1]); 546 matchAll = !operator.startsWith('any-'); 547 predicates[i].push(function (captures) { 548 const nodes = []; 549 for (const c of captures) { 550 if (c.name === captureName) nodes.push(c.node.text); 551 } 552 let test = (text, positive) => { 553 return positive ? 554 regex.test(text) : 555 !regex.test(text); 556 }; 557 if (nodes.length === 0) return !isPositive; 558 return matchAll 559 ? nodes.every(text => test(text, isPositive)) 560 : nodes.some(text => test(text, isPositive)) 561 }); 562 break; 563 564 case 'set!': 565 if (stepsLength < 2 || stepsLength > 3) throw new Error( 566 `Wrong number of arguments to \`#set!\` predicate. Expected 1 or 2. Got ${stepsLength - 1}.` 567 ); 568 if (steps.some((s, i) => (i % 2 !== 1) && s !== PREDICATE_STEP_TYPE.STRING)) throw new Error( 569 `Arguments to \`#set!\` predicate must be a strings.".` 570 ); 571 if (!setProperties[i]) setProperties[i] = {}; 572 setProperties[i][steps[SECOND + 1]] = steps[THIRD] ? steps[THIRD + 1] : null; 573 break; 574 575 case 'is?': 576 case 'is-not?': 577 if (stepsLength < 2 || stepsLength > 3) throw new Error( 578 `Wrong number of arguments to \`#${operator}\` predicate. Expected 1 or 2. Got ${stepsLength - 1}.` 579 ); 580 if (steps.some((s, i) => (i % 2 !== 1) && s !== PREDICATE_STEP_TYPE.STRING)) throw new Error( 581 `Arguments to \`#${operator}\` predicate must be a strings.".` 582 ); 583 const properties = operator === 'is?' ? assertedProperties : refutedProperties; 584 if (!properties[i]) properties[i] = {}; 585 properties[i][steps[SECOND + 1]] = steps[THIRD] ? steps[THIRD + 1] : null; 586 break; 587 588 case 'not-any-of?': 589 isPositive = false; 590 case 'any-of?': 591 if (stepsLength < 2) throw new Error( 592 `Wrong number of arguments to \`#${operator}\` predicate. Expected at least 1. Got ${stepsLength - 1}.` 593 ); 594 if (steps[SECOND] !== PREDICATE_STEP_TYPE.CAPTURE) throw new Error( 595 `First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".` 596 ); 597 const stringValues = []; 598 for (let k = THIRD; k < 2 * stepsLength; k += 2) { 599 if (steps[k] !== PREDICATE_STEP_TYPE.STRING) throw new Error( 600 `Arguments to \`#${operator}\` predicate must be a strings.".` 601 ); 602 stringValues.push(steps[k + 1]); 603 } 604 captureName = steps[SECOND + 1]; 605 predicates[i].push(function (captures) { 606 const nodes = []; 607 for (const c of captures) { 608 if (c.name === captureName) nodes.push(c.node.text); 609 } 610 if (nodes.length === 0) return !isPositive; 611 return nodes.every(text => stringValues.includes(text)) === isPositive; 612 }); 613 break; 614 615 default: 616 throw new Error(`Unknown query predicate \`#${steps[FIRST + 1]}\``); 617 } 618 } 619 } 620 621 this.predicates = Object.freeze(predicates); 622 this.setProperties = Object.freeze(setProperties); 623 this.assertedProperties = Object.freeze(assertedProperties); 624 this.refutedProperties = Object.freeze(refutedProperties); 625} 626 627Query.prototype.matches = function( 628 node, 629 { 630 startPosition = ZERO_POINT, 631 endPosition = ZERO_POINT, 632 startIndex = 0, 633 endIndex = 0, 634 matchLimit = 0xFFFFFFFF, 635 maxStartDepth = 0xFFFFFFFF, 636 timeoutMicros = 0 637 } = {} 638) { 639 marshalNode(node); 640 const [returnedMatches, returnedNodes] = _matches.call(this, node.tree, 641 startPosition.row, startPosition.column, 642 endPosition.row, endPosition.column, 643 startIndex, endIndex, matchLimit, maxStartDepth, timeoutMicros 644 ); 645 const nodes = unmarshalNodes(returnedNodes, node.tree); 646 const results = []; 647 648 let i = 0 649 let nodeIndex = 0; 650 while (i < returnedMatches.length) { 651 const patternIndex = returnedMatches[i++]; 652 const captures = []; 653 654 while (i < returnedMatches.length && typeof returnedMatches[i] === 'string') { 655 const captureName = returnedMatches[i++]; 656 captures.push({ 657 name: captureName, 658 node: nodes[nodeIndex++], 659 }) 660 } 661 662 if (this.predicates[patternIndex].every(p => p(captures))) { 663 const result = {pattern: patternIndex, captures}; 664 const setProperties = this.setProperties[patternIndex]; 665 const assertedProperties = this.assertedProperties[patternIndex]; 666 const refutedProperties = this.refutedProperties[patternIndex]; 667 if (setProperties) result.setProperties = setProperties; 668 if (assertedProperties) result.assertedProperties = assertedProperties; 669 if (refutedProperties) result.refutedProperties = refutedProperties; 670 results.push(result); 671 } 672 } 673 674 return results; 675} 676 677Query.prototype.captures = function( 678 node, 679 { 680 startPosition = ZERO_POINT, 681 endPosition = ZERO_POINT, 682 startIndex = 0, 683 endIndex = 0, 684 matchLimit = 0xFFFFFFFF, 685 maxStartDepth = 0xFFFFFFFF, 686 timeoutMicros = 0, 687 } = {} 688) { 689 marshalNode(node); 690 const [returnedMatches, returnedNodes] = _captures.call(this, node.tree, 691 startPosition.row, startPosition.column, 692 endPosition.row, endPosition.column, 693 startIndex, endIndex, matchLimit, maxStartDepth, timeoutMicros 694 ); 695 const nodes = unmarshalNodes(returnedNodes, node.tree); 696 const results = []; 697 698 let i = 0 699 let nodeIndex = 0; 700 while (i < returnedMatches.length) { 701 const patternIndex = returnedMatches[i++]; 702 const captureIndex = returnedMatches[i++]; 703 const captures = []; 704 705 while (i < returnedMatches.length && typeof returnedMatches[i] === 'string') { 706 const captureName = returnedMatches[i++]; 707 captures.push({ 708 name: captureName, 709 node: nodes[nodeIndex++], 710 }) 711 } 712 713 if (this.predicates[patternIndex].every(p => p(captures))) { 714 const result = captures[captureIndex]; 715 const setProperties = this.setProperties[patternIndex]; 716 const assertedProperties = this.assertedProperties[patternIndex]; 717 const refutedProperties = this.refutedProperties[patternIndex]; 718 if (setProperties) result.setProperties = setProperties; 719 if (assertedProperties) result.assertedProperties = assertedProperties; 720 if (refutedProperties) result.refutedProperties = refutedProperties; 721 results.push(result); 722 } 723 } 724 725 return results; 726} 727 728/* 729 * LookaheadIterator 730 */ 731 732LookaheadIterator.prototype[Symbol.iterator] = function() { 733 const self = this; 734 return { 735 next() { 736 if (self._next()) { 737 return {done: false, value: self.currentType}; 738 } 739 740 return {done: true, value: ''}; 741 }, 742 }; 743} 744 745/* 746 * Other functions 747 */ 748 749function getTextFromString (node) { 750 return this.input.substring(node.startIndex, node.endIndex); 751} 752 753function getTextFromFunction ({startIndex, endIndex}) { 754 const {input} = this 755 let result = ''; 756 const goalLength = endIndex - startIndex; 757 while (result.length < goalLength) { 758 const text = input(startIndex + result.length); 759 result += text; 760 } 761 return result.slice(0, goalLength); 762} 763 764const {pointTransferArray} = binding; 765 766const NODE_FIELD_COUNT = 6; 767const ERROR_TYPE_ID = 0xFFFF 768 769function getID(buffer, offset) { 770 const low = BigInt(buffer[offset]); 771 const high = BigInt(buffer[offset + 1]); 772 return (high << 32n) + low; 773} 774 775function unmarshalNode(value, tree, offset = 0, cache = null) { 776 /* case 1: node from the tree cache */ 777 if (typeof value === 'object') { 778 const node = value; 779 return node; 780 } 781 782 /* case 2: node being transferred */ 783 const nodeTypeId = value; 784 const NodeClass = nodeTypeId === ERROR_TYPE_ID 785 ? SyntaxNode 786 : tree.language.nodeSubclasses[nodeTypeId]; 787 788 const {nodeTransferArray} = binding; 789 const id = getID(nodeTransferArray, offset) 790 if (id === 0n) { 791 return null 792 } 793 794 let cachedResult; 795 if (cache && (cachedResult = cache.get(id))) 796 return cachedResult; 797 798 const result = new NodeClass(tree); 799 for (let i = 0; i < NODE_FIELD_COUNT; i++) { 800 result[i] = nodeTransferArray[offset + i]; 801 } 802 803 if (cache) 804 cache.set(id, result); 805 else 806 tree._cacheNode(result); 807 808 return result; 809} 810 811function unmarshalNodes(nodes, tree) { 812 const cache = new Map(); 813 814 let offset = 0; 815 for (let i = 0, {length} = nodes; i < length; i++) { 816 const node = unmarshalNode(nodes[i], tree, offset, cache); 817 if (node !== nodes[i]) { 818 nodes[i] = node; 819 offset += NODE_FIELD_COUNT 820 } 821 } 822 823 tree._cacheNodes(Array.from(cache.values())); 824 825 return nodes; 826} 827 828function marshalNode(node, offset = 0) { 829 if (!(node.tree instanceof Tree)) { 830 throw new TypeError("SyntaxNode must belong to a Tree") 831 } 832 const { nodeTransferArray } = binding; 833 for (let i = 0; i < NODE_FIELD_COUNT; i++) { 834 nodeTransferArray[offset * NODE_FIELD_COUNT + i] = node[i]; 835 } 836} 837 838function marshalNodes(nodes) { 839 for (let i = 0, { length } = nodes; i < length; i++) { 840 marshalNode(nodes[i], i); 841 } 842} 843 844function unmarshalPoint() { 845 return {row: pointTransferArray[0], column: pointTransferArray[1]}; 846} 847 848function pointToString(point) { 849 return `{row: ${point.row}, column: ${point.column}}`; 850} 851 852function initializeLanguageNodeClasses(language) { 853 const nodeTypeNamesById = binding.getNodeTypeNamesById(language); 854 const nodeFieldNamesById = binding.getNodeFieldNamesById(language); 855 const nodeTypeInfo = language.nodeTypeInfo || []; 856 857 const nodeSubclasses = []; 858 for (let id = 0, n = nodeTypeNamesById.length; id < n; id++) { 859 nodeSubclasses[id] = SyntaxNode; 860 861 const typeName = nodeTypeNamesById[id]; 862 if (!typeName) continue; 863 864 const typeInfo = nodeTypeInfo.find(info => info.named && info.type === typeName); 865 if (!typeInfo) continue; 866 867 const fieldNames = []; 868 let classBody = '\n'; 869 if (typeInfo.fields) { 870 for (const fieldName in typeInfo.fields) { 871 const fieldId = nodeFieldNamesById.indexOf(fieldName); 872 if (fieldId === -1) continue; 873 if (typeInfo.fields[fieldName].multiple) { 874 const getterName = camelCase(fieldName) + 'Nodes'; 875 fieldNames.push(getterName); 876 classBody += ` 877 get ${getterName}() { 878 marshalNode(this); 879 return unmarshalNodes(NodeMethods.childNodesForFieldId(this.tree, ${fieldId}), this.tree); 880 } 881 `.replace(/\s+/g, ' ') + '\n'; 882 } else { 883 const getterName = camelCase(fieldName, false) + 'Node'; 884 fieldNames.push(getterName); 885 classBody += ` 886 get ${getterName}() { 887 marshalNode(this); 888 return unmarshalNode(NodeMethods.childNodeForFieldId(this.tree, ${fieldId}), this.tree); 889 } 890 `.replace(/\s+/g, ' ') + '\n'; 891 } 892 } 893 } 894 895 const className = camelCase(typeName, true) + 'Node'; 896 const nodeSubclass = eval(`class ${className} extends SyntaxNode {${classBody}}; ${className}`); 897 nodeSubclass.prototype.type = typeName; 898 nodeSubclass.prototype.fields = Object.freeze(fieldNames.sort()) 899 nodeSubclasses[id] = nodeSubclass; 900 } 901 902 language.nodeSubclasses = nodeSubclasses 903} 904 905function camelCase(name, upperCase) { 906 name = name.replace(/_(\w)/g, (_match, letter) => letter.toUpperCase()); 907 if (upperCase) name = name[0].toUpperCase() + name.slice(1); 908 return name; 909} 910 911module.exports = Parser; 912module.exports.Query = Query; 913module.exports.Tree = Tree; 914module.exports.SyntaxNode = SyntaxNode; 915module.exports.TreeCursor = TreeCursor; 916module.exports.LookaheadIterator = LookaheadIterator;