tree-sitter
Advanced tools
Comparing version 0.16.1 to 0.16.2
296
index.js
@@ -12,6 +12,9 @@ let binding; | ||
const vm = require('vm'); | ||
const util = require('util') | ||
const {Parser, NodeMethods, Tree, TreeCursor} = binding; | ||
const {Query, Parser, NodeMethods, Tree, TreeCursor} = binding; | ||
/* | ||
* Tree | ||
*/ | ||
const {rootNode, edit} = Tree.prototype; | ||
@@ -41,2 +44,6 @@ | ||
/* | ||
* Node | ||
*/ | ||
class SyntaxNode { | ||
@@ -246,2 +253,6 @@ constructor(tree) { | ||
/* | ||
* Parser | ||
*/ | ||
const {parse, parseTextBuffer, parseTextBufferSync, setLanguage} = Parser.prototype; | ||
@@ -331,2 +342,6 @@ const languageSymbol = Symbol('parser.language'); | ||
/* | ||
* TreeCursor | ||
*/ | ||
const {startPosition, endPosition, currentNode, reset} = TreeCursor.prototype; | ||
@@ -364,2 +379,221 @@ | ||
/* | ||
* Query | ||
*/ | ||
const {_matches, _captures} = Query.prototype; | ||
const PREDICATE_STEP_TYPE = { | ||
DONE: 0, | ||
CAPTURE: 1, | ||
STRING: 2, | ||
} | ||
const ZERO_POINT = { row: 0, column: 0 }; | ||
Query.prototype._init = function() { | ||
/* | ||
* Initializa predicate functions | ||
* format: [type1, value1, type2, value2, ...] | ||
*/ | ||
const predicateDescriptions = this._getPredicates(); | ||
const patternCount = predicateDescriptions.length; | ||
const setProperties = new Array(patternCount); | ||
const assertedProperties = new Array(patternCount); | ||
const refutedProperties = new Array(patternCount); | ||
const predicates = new Array(patternCount); | ||
const FIRST = 0 | ||
const SECOND = 2 | ||
const THIRD = 4 | ||
for (let i = 0; i < predicateDescriptions.length; i++) { | ||
predicates[i] = []; | ||
for (let j = 0; j < predicateDescriptions[i].length; j++) { | ||
const steps = predicateDescriptions[i][j]; | ||
const stepsLength = steps.length / 2; | ||
if (steps[FIRST] !== PREDICATE_STEP_TYPE.STRING) { | ||
throw new Error('Predicates must begin with a literal value'); | ||
} | ||
const operator = steps[FIRST + 1]; | ||
let isPositive = true; | ||
switch (operator) { | ||
case 'not-eq?': | ||
isPositive = false; | ||
case 'eq?': | ||
if (stepsLength !== 3) throw new Error( | ||
`Wrong number of arguments to \`#eq?\` predicate. Expected 2, got ${stepsLength - 1}` | ||
); | ||
if (steps[SECOND] !== PREDICATE_STEP_TYPE.CAPTURE) throw new Error( | ||
`First argument of \`#eq?\` predicate must be a capture. Got "${steps[SECOND + 1]}"` | ||
); | ||
if (steps[THIRD] === PREDICATE_STEP_TYPE.CAPTURE) { | ||
const captureName1 = steps[SECOND + 1]; | ||
const captureName2 = steps[THIRD + 1]; | ||
predicates[i].push(function(captures) { | ||
let node1, node2 | ||
for (const c of captures) { | ||
if (c.name === captureName1) node1 = c.node; | ||
if (c.name === captureName2) node2 = c.node; | ||
} | ||
return (node1.text === node2.text) === isPositive; | ||
}); | ||
} else { | ||
const captureName = steps[SECOND + 1]; | ||
const stringValue = steps[THIRD + 1]; | ||
predicates[i].push(function(captures) { | ||
for (const c of captures) { | ||
if (c.name === captureName) { | ||
return (c.node.text === stringValue) === isPositive; | ||
}; | ||
} | ||
return false; | ||
}); | ||
} | ||
break; | ||
case 'match?': | ||
if (stepsLength !== 3) throw new Error( | ||
`Wrong number of arguments to \`#match?\` predicate. Expected 2, got ${stepsLength - 1}.` | ||
); | ||
if (steps[SECOND] !== PREDICATE_STEP_TYPE.CAPTURE) throw new Error( | ||
`First argument of \`#match?\` predicate must be a capture. Got "${steps[SECOND + 1]}".` | ||
); | ||
if (steps[THIRD] !== PREDICATE_STEP_TYPE.STRING) throw new Error( | ||
`Second argument of \`#match?\` predicate must be a string. Got @${steps[THIRD + 1]}.` | ||
); | ||
const captureName = steps[SECOND + 1]; | ||
const regex = new RegExp(steps[THIRD + 1]); | ||
predicates[i].push(function(captures) { | ||
for (const c of captures) { | ||
if (c.name === captureName) return regex.test(c.node.text); | ||
} | ||
return false; | ||
}); | ||
break; | ||
case 'set!': | ||
if (stepsLength < 2 || stepsLength > 3) throw new Error( | ||
`Wrong number of arguments to \`#set!\` predicate. Expected 1 or 2. Got ${stepsLength - 1}.` | ||
); | ||
if (steps.some((s, i) => (i % 2 !== 1) && s !== PREDICATE_STEP_TYPE.STRING)) throw new Error( | ||
`Arguments to \`#set!\` predicate must be a strings.".` | ||
); | ||
if (!setProperties[i]) setProperties[i] = {}; | ||
setProperties[i][steps[SECOND + 1]] = steps[THIRD] ? steps[THIRD + 1] : null; | ||
break; | ||
case 'is?': | ||
case 'is-not?': | ||
if (stepsLength < 2 || stepsLength > 3) throw new Error( | ||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 1 or 2. Got ${stepsLength - 1}.` | ||
); | ||
if (steps.some((s, i) => (i % 2 !== 1) && s !== PREDICATE_STEP_TYPE.STRING)) throw new Error( | ||
`Arguments to \`#${operator}\` predicate must be a strings.".` | ||
); | ||
const properties = operator === 'is?' ? assertedProperties : refutedProperties; | ||
if (!properties[i]) properties[i] = {}; | ||
properties[i][steps[SECOND + 1]] = steps[THIRD] ? steps[THIRD + 1] : null; | ||
break; | ||
default: | ||
throw new Error(`Unknown query predicate \`#${steps[FIRST + 1]}\``); | ||
} | ||
} | ||
} | ||
this.predicates = Object.freeze(predicates); | ||
this.setProperties = Object.freeze(setProperties); | ||
this.assertedProperties = Object.freeze(assertedProperties); | ||
this.refutedProperties = Object.freeze(refutedProperties); | ||
} | ||
Query.prototype.matches = function(rootNode, start = ZERO_POINT, end = ZERO_POINT) { | ||
marshalNode(rootNode); | ||
const [returnedMatches, returnedNodes] = _matches.call(this, rootNode.tree, | ||
start.row, start.column, | ||
end.row, end.column | ||
); | ||
const nodes = unmarshalNodes(returnedNodes, rootNode.tree); | ||
const results = []; | ||
let i = 0 | ||
let nodeIndex = 0; | ||
while (i < returnedMatches.length) { | ||
const patternIndex = returnedMatches[i++]; | ||
const captures = []; | ||
while (i < returnedMatches.length && typeof returnedMatches[i] === 'string') { | ||
const captureName = returnedMatches[i++]; | ||
captures.push({ | ||
name: captureName, | ||
node: nodes[nodeIndex++], | ||
}) | ||
} | ||
if (this.predicates[patternIndex].every(p => p(captures))) { | ||
const result = {pattern: patternIndex, captures}; | ||
const setProperties = this.setProperties[patternIndex]; | ||
const assertedProperties = this.assertedProperties[patternIndex]; | ||
const refutedProperties = this.refutedProperties[patternIndex]; | ||
if (setProperties) result.setProperties = setProperties; | ||
if (assertedProperties) result.assertedProperties = assertedProperties; | ||
if (refutedProperties) result.refutedProperties = refutedProperties; | ||
results.push(result); | ||
} | ||
} | ||
return results; | ||
} | ||
Query.prototype.captures = function(rootNode, start = ZERO_POINT, end = ZERO_POINT) { | ||
marshalNode(rootNode); | ||
const [returnedMatches, returnedNodes] = _captures.call(this, rootNode.tree, | ||
start.row, start.column, | ||
end.row, end.column | ||
); | ||
const nodes = unmarshalNodes(returnedNodes, rootNode.tree); | ||
const results = []; | ||
let i = 0 | ||
let nodeIndex = 0; | ||
while (i < returnedMatches.length) { | ||
const patternIndex = returnedMatches[i++]; | ||
const captureIndex = returnedMatches[i++]; | ||
const captures = []; | ||
while (i < returnedMatches.length && typeof returnedMatches[i] === 'string') { | ||
const captureName = returnedMatches[i++]; | ||
captures.push({ | ||
name: captureName, | ||
node: nodes[nodeIndex++], | ||
}) | ||
} | ||
if (this.predicates[patternIndex].every(p => p(captures))) { | ||
const result = captures[captureIndex]; | ||
const setProperties = this.setProperties[patternIndex]; | ||
const assertedProperties = this.assertedProperties[patternIndex]; | ||
const refutedProperties = this.refutedProperties[patternIndex]; | ||
if (setProperties) result.setProperties = setProperties; | ||
if (assertedProperties) result.assertedProperties = assertedProperties; | ||
if (refutedProperties) result.refutedProperties = refutedProperties; | ||
results.push(result); | ||
} | ||
} | ||
return results; | ||
} | ||
/* | ||
* Other functions | ||
*/ | ||
function getTextFromString (node) { | ||
@@ -389,28 +623,50 @@ return this.input.substring(node.startIndex, node.endIndex); | ||
function unmarshalNode(value, tree, offset = 0) { | ||
function getID(buffer, offset) { | ||
const low = BigInt(buffer[offset]); | ||
const high = BigInt(buffer[offset + 1]); | ||
return (high << 32n) + low; | ||
} | ||
function unmarshalNode(value, tree, offset = 0, cache = null) { | ||
/* case 1: node from the tree cache */ | ||
if (typeof value === 'object') { | ||
const node = value; | ||
return node; | ||
} else { | ||
const nodeTypeId = value; | ||
const NodeClass = nodeTypeId === ERROR_TYPE_ID | ||
? SyntaxNode | ||
: tree.language.nodeSubclasses[nodeTypeId]; | ||
const {nodeTransferArray} = binding; | ||
if (nodeTransferArray[0] || nodeTransferArray[1]) { | ||
const result = new NodeClass(tree); | ||
for (let i = 0; i < NODE_FIELD_COUNT; i++) { | ||
result[i] = nodeTransferArray[offset + i]; | ||
} | ||
tree._cacheNode(result); | ||
return result; | ||
} | ||
} | ||
/* case 2: node being transferred */ | ||
const nodeTypeId = value; | ||
const NodeClass = nodeTypeId === ERROR_TYPE_ID | ||
? SyntaxNode | ||
: tree.language.nodeSubclasses[nodeTypeId]; | ||
const {nodeTransferArray} = binding; | ||
const id = getID(nodeTransferArray, offset) | ||
if (id === 0n) { | ||
return null | ||
} | ||
let cachedResult; | ||
if (cache && (cachedResult = cache.get(id))) | ||
return cachedResult; | ||
const result = new NodeClass(tree); | ||
for (let i = 0; i < NODE_FIELD_COUNT; i++) { | ||
result[i] = nodeTransferArray[offset + i]; | ||
} | ||
if (cache) | ||
cache.set(id, result); | ||
else | ||
tree._cacheNode(result); | ||
return result; | ||
} | ||
function unmarshalNodes(nodes, tree) { | ||
const cache = new Map(); | ||
let offset = 0; | ||
for (let i = 0, {length} = nodes; i < length; i++) { | ||
const node = unmarshalNode(nodes[i], tree, offset); | ||
const node = unmarshalNode(nodes[i], tree, offset, cache); | ||
if (node !== nodes[i]) { | ||
@@ -421,2 +677,5 @@ nodes[i] = node; | ||
} | ||
tree._cacheNodes(Array.from(cache.values())); | ||
return nodes; | ||
@@ -500,4 +759,5 @@ } | ||
module.exports = Parser; | ||
module.exports.Query = Query; | ||
module.exports.Tree = Tree; | ||
module.exports.SyntaxNode = SyntaxNode; | ||
module.exports.TreeCursor = TreeCursor; |
{ | ||
"name": "tree-sitter", | ||
"version": "0.16.1", | ||
"version": "0.16.2", | ||
"description": "Incremental parsers for node", | ||
@@ -25,3 +25,3 @@ "author": "Max Brunsfeld", | ||
"prebuild": "^7.6.0", | ||
"superstring": "^2.4.1", | ||
"superstring": "^2.4.2", | ||
"tree-sitter-javascript": "git://github.com/tree-sitter/tree-sitter-javascript.git#master" | ||
@@ -31,2 +31,3 @@ }, | ||
"install": "prebuild-install || node-gyp rebuild", | ||
"build": "node-gyp build", | ||
"prebuild": "prebuild -r electron -t 3.0.0 -t 4.0.0 -t 4.0.4 -t 5.0.0 --strip && prebuild -t 10.12.0 -t 12.13.0 --strip", | ||
@@ -33,0 +34,0 @@ "prebuild:upload": "prebuild --upload-all", |
declare module "tree-sitter" { | ||
class Parser { | ||
parse(input: string | Parser.Input, previousTree?: Parser.Tree): Parser.Tree; | ||
parse(input: string | Parser.Input, previousTree?: Parser.Tree, options?: {bufferSize?: number, includedRanges?: Parser.Range[]}): Parser.Tree; | ||
getLanguage(): any; | ||
@@ -17,4 +17,6 @@ setLanguage(language: any): void; | ||
export type Range = { | ||
start: Point; | ||
end: Point; | ||
startIndex: number, | ||
endIndex: number, | ||
startPosition: Point, | ||
endPosition: Point | ||
}; | ||
@@ -21,0 +23,0 @@ |
@@ -8,7 +8,12 @@ # tree-sitter | ||
* **General** enough to parse any programming language | ||
* **Fast** enough to parse on every keystroke in a text editor | ||
* **Robust** enough to provide useful results even in the presence of syntax errors | ||
* **Dependency-free** so that the runtime library (which is written in pure C) can be embedded in any application | ||
- **General** enough to parse any programming language | ||
- **Fast** enough to parse on every keystroke in a text editor | ||
- **Robust** enough to provide useful results even in the presence of syntax errors | ||
- **Dependency-free** so that the runtime library (which is written in pure C) can be embedded in any application | ||
[Documentation](https://tree-sitter.github.io/tree-sitter/) | ||
## Links | ||
- [Documentation](https://tree-sitter.github.io) | ||
- [Rust binding](lib/binding_rust/README.md) | ||
- [WASM binding](lib/binding_web/README.md) | ||
- [Command-line interface](cli/README.md) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
544965
71
742
0