Merge branch 'master' into wasm-language
This commit is contained in:
commit
f4e2f68f14
161 changed files with 10293 additions and 4253 deletions
|
|
@ -1,16 +1,18 @@
|
|||
Web Tree-sitter
|
||||
===============
|
||||
# Web Tree-sitter
|
||||
|
||||
[](https://travis-ci.org/tree-sitter/tree-sitter)
|
||||
[![npmjs.com badge]][npmjs.com]
|
||||
|
||||
[npmjs.com]: https://www.npmjs.org/package/web-tree-sitter
|
||||
[npmjs.com badge]: https://img.shields.io/npm/v/web-tree-sitter.svg?color=%23BF4A4A
|
||||
|
||||
WebAssembly bindings to the [Tree-sitter](https://github.com/tree-sitter/tree-sitter) parsing library.
|
||||
|
||||
### Setup
|
||||
|
||||
You can download the the `tree-sitter.js` and `tree-sitter.wasm` files from [the latest GitHub release](https://github.com/tree-sitter/tree-sitter/releases/latest) and load them using a standalone script:
|
||||
You can download the `tree-sitter.js` and `tree-sitter.wasm` files from [the latest GitHub release](https://github.com/tree-sitter/tree-sitter/releases/latest) and load them using a standalone script:
|
||||
|
||||
```html
|
||||
<script src="/the/path/to/tree-sitter.js"/>
|
||||
<script src="/the/path/to/tree-sitter.js"></script>
|
||||
|
||||
<script>
|
||||
const Parser = window.TreeSitter;
|
||||
|
|
@ -118,7 +120,7 @@ First install `tree-sitter-cli` and the tree-sitter language for which to genera
|
|||
npm install --save-dev tree-sitter-cli tree-sitter-javascript
|
||||
```
|
||||
|
||||
Then just use tree-sitter cli tool to generate the `.wasm`.
|
||||
Then just use tree-sitter cli tool to generate the `.wasm`.
|
||||
|
||||
```sh
|
||||
npx tree-sitter build-wasm node_modules/tree-sitter-javascript
|
||||
|
|
@ -149,13 +151,13 @@ const Parser = require('web-tree-sitter');
|
|||
|
||||
##### Loading the .wasm file
|
||||
|
||||
`web-tree-sitter` needs to load the `tree-sitter.wasm` file. By default, it assumes that this file is available in the
|
||||
`web-tree-sitter` needs to load the `tree-sitter.wasm` file. By default, it assumes that this file is available in the
|
||||
same path as the JavaScript code. Therefore, if the code is being served from `http://localhost:3000/bundle.js`, then
|
||||
the wasm file should be at `http://localhost:3000/tree-sitter.wasm`.
|
||||
|
||||
For server side frameworks like NextJS, this can be tricky as pages are often served from a path such as
|
||||
For server side frameworks like NextJS, this can be tricky as pages are often served from a path such as
|
||||
`http://localhost:3000/_next/static/chunks/pages/index.js`. The loader will therefore look for the wasm file at
|
||||
`http://localhost:3000/_next/static/chunks/pages/tree-sitter.wasm`. The solution is to pass a `locateFile` function in
|
||||
`http://localhost:3000/_next/static/chunks/pages/tree-sitter.wasm`. The solution is to pass a `locateFile` function in
|
||||
the `moduleOptions` argument to `Parser.init()`:
|
||||
|
||||
```javascript
|
||||
|
|
@ -166,15 +168,15 @@ await Parser.init({
|
|||
});
|
||||
```
|
||||
|
||||
`locateFile` takes in two parameters, `scriptName`, i.e. the wasm file name, and `scriptDirectory`, i.e. the directory
|
||||
`locateFile` takes in two parameters, `scriptName`, i.e. the wasm file name, and `scriptDirectory`, i.e. the directory
|
||||
where the loader expects the script to be. It returns the path where the loader will look for the wasm file. In the NextJS
|
||||
case, we want to return just the `scriptName` so that the loader will look at `http://localhost:3000/tree-sitter.wasm`
|
||||
and not `http://localhost:3000/_next/static/chunks/pages/tree-sitter.wasm`.
|
||||
|
||||
##### `Can't resolve 'fs' in 'node_modules/web-tree-sitter'`
|
||||
|
||||
Most bundlers will notice that the `tree-sitter.js` file is attempting to import `fs`, i.e. node's file system library.
|
||||
Since this doesn't exist in the browser, the bundlers will get confused. For webpack you can fix this by adding the
|
||||
Most bundlers will notice that the `tree-sitter.js` file is attempting to import `fs`, i.e. node's file system library.
|
||||
Since this doesn't exist in the browser, the bundlers will get confused. For webpack you can fix this by adding the
|
||||
following to your webpack config:
|
||||
|
||||
```javascript
|
||||
|
|
|
|||
|
|
@ -243,6 +243,13 @@ void ts_tree_cursor_reset_wasm(const TSTree *tree) {
|
|||
marshal_cursor(&cursor);
|
||||
}
|
||||
|
||||
void ts_tree_cursor_reset_to_wasm(const TSTree *_dst, const TSTree *_src) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, _dst);
|
||||
TSTreeCursor src = unmarshal_cursor(&TRANSFER_BUFFER[3], _src);
|
||||
ts_tree_cursor_reset_to(&cursor, &src);
|
||||
marshal_cursor(&cursor);
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_goto_first_child_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
bool result = ts_tree_cursor_goto_first_child(&cursor);
|
||||
|
|
@ -250,6 +257,13 @@ bool ts_tree_cursor_goto_first_child_wasm(const TSTree *tree) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_goto_last_child_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
bool result = ts_tree_cursor_goto_last_child(&cursor);
|
||||
marshal_cursor(&cursor);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_goto_next_sibling_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
bool result = ts_tree_cursor_goto_next_sibling(&cursor);
|
||||
|
|
@ -257,6 +271,13 @@ bool ts_tree_cursor_goto_next_sibling_wasm(const TSTree *tree) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_goto_previous_sibling_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
bool result = ts_tree_cursor_goto_previous_sibling(&cursor);
|
||||
marshal_cursor(&cursor);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_goto_parent_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
bool result = ts_tree_cursor_goto_parent(&cursor);
|
||||
|
|
@ -270,6 +291,12 @@ uint16_t ts_tree_cursor_current_node_type_id_wasm(const TSTree *tree) {
|
|||
return ts_node_symbol(node);
|
||||
}
|
||||
|
||||
uint16_t ts_tree_cursor_current_node_state_id_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
TSNode node = ts_tree_cursor_current_node(&cursor);
|
||||
return ts_node_parse_state(node);
|
||||
}
|
||||
|
||||
bool ts_tree_cursor_current_node_is_named_wasm(const TSTree *tree) {
|
||||
TSTreeCursor cursor = unmarshal_cursor(TRANSFER_BUFFER, tree);
|
||||
TSNode node = ts_tree_cursor_current_node(&cursor);
|
||||
|
|
@ -334,6 +361,16 @@ uint16_t ts_node_symbol_wasm(const TSTree *tree) {
|
|||
return ts_node_symbol(node);
|
||||
}
|
||||
|
||||
const char *ts_node_field_name_for_child_wasm(const TSTree *tree, uint32_t index) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_field_name_for_child(node, index);
|
||||
}
|
||||
|
||||
uint16_t ts_node_grammar_symbol_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_grammar_symbol(node);
|
||||
}
|
||||
|
||||
uint32_t ts_node_child_count_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_child_count(node);
|
||||
|
|
@ -579,11 +616,26 @@ int ts_node_has_error_wasm(const TSTree *tree) {
|
|||
return ts_node_has_error(node);
|
||||
}
|
||||
|
||||
int ts_node_is_error_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_is_error(node);
|
||||
}
|
||||
|
||||
int ts_node_is_missing_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_is_missing(node);
|
||||
}
|
||||
|
||||
uint16_t ts_node_parse_state_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_parse_state(node);
|
||||
}
|
||||
|
||||
uint16_t ts_node_next_parse_state_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
return ts_node_next_parse_state(node);
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Section - Query */
|
||||
/******************/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const C = Module;
|
||||
const INTERNAL = {};
|
||||
const SIZE_OF_INT = 4;
|
||||
const SIZE_OF_CURSOR = 3 * SIZE_OF_INT;
|
||||
const SIZE_OF_NODE = 5 * SIZE_OF_INT;
|
||||
const SIZE_OF_POINT = 2 * SIZE_OF_INT;
|
||||
const SIZE_OF_RANGE = 2 * SIZE_OF_INT + 2 * SIZE_OF_POINT;
|
||||
|
|
@ -208,10 +209,19 @@ class Node {
|
|||
return C._ts_node_symbol_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
get grammarId() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_grammar_symbol_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this.tree.language.types[this.typeId] || 'ERROR';
|
||||
}
|
||||
|
||||
get grammarType() {
|
||||
return this.tree.language.types[this.grammarId] || 'ERROR';
|
||||
}
|
||||
|
||||
get endPosition() {
|
||||
marshalNode(this);
|
||||
C._ts_node_end_point_wasm(this.tree[0]);
|
||||
|
|
@ -227,6 +237,16 @@ class Node {
|
|||
return getText(this.tree, this.startIndex, this.endIndex);
|
||||
}
|
||||
|
||||
get parseState() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_parse_state_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
get nextParseState() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_next_parse_state_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
isNamed() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_is_named_wasm(this.tree[0]) === 1;
|
||||
|
|
@ -242,6 +262,11 @@ class Node {
|
|||
return C._ts_node_has_changes_wasm(this.tree[0]) === 1;
|
||||
}
|
||||
|
||||
isError() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_is_error_wasm(this.tree[0]) === 1;
|
||||
}
|
||||
|
||||
isMissing() {
|
||||
marshalNode(this);
|
||||
return C._ts_node_is_missing_wasm(this.tree[0]) === 1;
|
||||
|
|
@ -257,6 +282,17 @@ class Node {
|
|||
return unmarshalNode(this.tree);
|
||||
}
|
||||
|
||||
fieldNameForChild(index) {
|
||||
marshalNode(this);
|
||||
const address = C._ts_node_field_name_for_child_wasm(this.tree[0], index);
|
||||
if (!address) {
|
||||
return null;
|
||||
}
|
||||
const result = AsciiToString(address);
|
||||
// must not free, the string memory is owned by the language
|
||||
return result;
|
||||
}
|
||||
|
||||
namedChild(index) {
|
||||
marshalNode(this);
|
||||
C._ts_node_named_child_wasm(this.tree[0], index);
|
||||
|
|
@ -505,6 +541,13 @@ class TreeCursor {
|
|||
unmarshalTreeCursor(this);
|
||||
}
|
||||
|
||||
resetTo(cursor) {
|
||||
marshalTreeCursor(this, TRANSFER_BUFFER);
|
||||
marshalTreeCursor(cursor, TRANSFER_BUFFER + SIZE_OF_CURSOR);
|
||||
C._ts_tree_cursor_reset_to_wasm(this.tree[0], cursor.tree[0]);
|
||||
unmarshalTreeCursor(this);
|
||||
}
|
||||
|
||||
get nodeType() {
|
||||
return this.tree.language.types[this.nodeTypeId] || 'ERROR';
|
||||
}
|
||||
|
|
@ -514,6 +557,11 @@ class TreeCursor {
|
|||
return C._ts_tree_cursor_current_node_type_id_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
get nodeStateId() {
|
||||
marshalTreeCursor(this);
|
||||
return C._ts_tree_cursor_current_node_state_id_wasm(this.tree[0]);
|
||||
}
|
||||
|
||||
get nodeId() {
|
||||
marshalTreeCursor(this);
|
||||
return C._ts_tree_cursor_current_node_id_wasm(this.tree[0]);
|
||||
|
|
@ -580,6 +628,13 @@ class TreeCursor {
|
|||
return result === 1;
|
||||
}
|
||||
|
||||
gotoLastChild() {
|
||||
marshalTreeCursor(this);
|
||||
const result = C._ts_tree_cursor_goto_last_child_wasm(this.tree[0]);
|
||||
unmarshalTreeCursor(this);
|
||||
return result === 1;
|
||||
}
|
||||
|
||||
gotoNextSibling() {
|
||||
marshalTreeCursor(this);
|
||||
const result = C._ts_tree_cursor_goto_next_sibling_wasm(this.tree[0]);
|
||||
|
|
@ -587,6 +642,13 @@ class TreeCursor {
|
|||
return result === 1;
|
||||
}
|
||||
|
||||
gotoPreviousSibling() {
|
||||
marshalTreeCursor(this);
|
||||
const result = C._ts_tree_cursor_goto_previous_sibling_wasm(this.tree[0]);
|
||||
unmarshalTreeCursor(this);
|
||||
return result === 1;
|
||||
}
|
||||
|
||||
gotoParent() {
|
||||
marshalTreeCursor(this);
|
||||
const result = C._ts_tree_cursor_goto_parent_wasm(this.tree[0]);
|
||||
|
|
@ -624,6 +686,10 @@ class Language {
|
|||
return this.fields.length - 1;
|
||||
}
|
||||
|
||||
get stateCount() {
|
||||
return C._ts_language_state_count(this[0]);
|
||||
}
|
||||
|
||||
fieldIdForName(fieldName) {
|
||||
const result = this.fields.indexOf(fieldName);
|
||||
if (result !== -1) {
|
||||
|
|
@ -663,6 +729,15 @@ class Language {
|
|||
return C._ts_language_type_is_visible_wasm(this[0], typeId) ? true : false;
|
||||
}
|
||||
|
||||
nextState(stateId, typeId) {
|
||||
return C._ts_language_next_state(this[0], stateId, typeId);
|
||||
}
|
||||
|
||||
lookaheadIterator(stateId) {
|
||||
const address = C._ts_lookahead_iterator_new(this[0], stateId);
|
||||
if (address) return new LookaheadIterable(INTERNAL, address, this);
|
||||
}
|
||||
|
||||
query(source) {
|
||||
const sourceLength = lengthBytesUTF8(source);
|
||||
const sourceAddress = C._malloc(sourceLength + 1);
|
||||
|
|
@ -766,7 +841,13 @@ class Language {
|
|||
}
|
||||
const operator = steps[0].value;
|
||||
let isPositive = true;
|
||||
let matchAll = true;
|
||||
switch (operator) {
|
||||
case 'any-not-eq?':
|
||||
isPositive = false;
|
||||
matchAll = false;
|
||||
case 'any-eq?':
|
||||
matchAll = false;
|
||||
case 'not-eq?':
|
||||
isPositive = false;
|
||||
case 'eq?':
|
||||
|
|
@ -780,28 +861,36 @@ class Language {
|
|||
const captureName1 = steps[1].name;
|
||||
const captureName2 = steps[2].name;
|
||||
textPredicates[i].push(function(captures) {
|
||||
let node1, node2
|
||||
let nodes_1 = [];
|
||||
let nodes_2 = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName1) node1 = c.node;
|
||||
if (c.name === captureName2) node2 = c.node;
|
||||
if (c.name === captureName1) nodes_1.push(c.node);
|
||||
if (c.name === captureName2) nodes_2.push(c.node);
|
||||
}
|
||||
if(node1 === undefined || node2 === undefined) return true;
|
||||
return (node1.text === node2.text) === isPositive;
|
||||
return matchAll
|
||||
? nodes_1.every(n1 => nodes_2.some(n2 => n1.text === n2.text)) === isPositive
|
||||
: nodes_1.some(n1 => nodes_2.some(n2 => n1.text === n2.text)) === isPositive;
|
||||
});
|
||||
} else {
|
||||
const captureName = steps[1].name;
|
||||
const stringValue = steps[2].value;
|
||||
textPredicates[i].push(function(captures) {
|
||||
let nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) {
|
||||
return (c.node.text === stringValue) === isPositive;
|
||||
};
|
||||
if (c.name === captureName) nodes.push(c.node);
|
||||
}
|
||||
return true;
|
||||
return matchAll
|
||||
? nodes.every(n => n.text === stringValue) === isPositive
|
||||
: nodes.some(n => n.text === stringValue) === isPositive;
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'not-any-match?':
|
||||
isPositive = false;
|
||||
matchAll = false;
|
||||
case 'any-match?':
|
||||
matchAll = false;
|
||||
case 'not-match?':
|
||||
isPositive = false;
|
||||
case 'match?':
|
||||
|
|
@ -817,10 +906,14 @@ class Language {
|
|||
const captureName = steps[1].name;
|
||||
const regex = new RegExp(steps[2].value);
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) return regex.test(c.node.text) === isPositive;
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
}
|
||||
return true;
|
||||
if (nodes.length === 0) return !isPositive;
|
||||
return matchAll
|
||||
? nodes.every(text => regex.test(text)) === isPositive
|
||||
: nodes.some(text => regex.test(text)) === isPositive;
|
||||
});
|
||||
break;
|
||||
|
||||
|
|
@ -848,6 +941,32 @@ class Language {
|
|||
properties[i][steps[1].value] = steps[2] ? steps[2].value : null;
|
||||
break;
|
||||
|
||||
case 'not-any-of?':
|
||||
isPositive = false;
|
||||
case 'any-of?':
|
||||
if (steps.length < 2) throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected at least 1. Got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`
|
||||
);
|
||||
for (let i = 2; i < steps.length; i++) {
|
||||
if (steps[i].type !== 'string') throw new Error(
|
||||
`Arguments to \`#${operator}\` predicate must be a strings.".`
|
||||
);
|
||||
}
|
||||
captureName = steps[1].name;
|
||||
const values = steps.slice(2).map(s => s.value);
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
}
|
||||
if (nodes.length === 0) return !isPositive;
|
||||
return nodes.every(text => values.includes(text)) === isPositive;
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
predicates[i].push({operator, operands: steps.slice(1)});
|
||||
}
|
||||
|
|
@ -918,6 +1037,53 @@ class Language {
|
|||
}
|
||||
}
|
||||
|
||||
class LookaheadIterable {
|
||||
constructor(internal, address, language) {
|
||||
assertInternal(internal);
|
||||
this[0] = address;
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
get currentTypeId() {
|
||||
return C._ts_lookahead_iterator_current_symbol(this[0]);
|
||||
}
|
||||
|
||||
get currentType() {
|
||||
return this.language.types[this.currentTypeId] || 'ERROR'
|
||||
}
|
||||
|
||||
delete() {
|
||||
C._ts_lookahead_iterator_delete(this[0]);
|
||||
this[0] = 0;
|
||||
}
|
||||
|
||||
resetState(stateId) {
|
||||
return C._ts_lookahead_iterator_reset_state(this[0], stateId);
|
||||
}
|
||||
|
||||
reset(language, stateId) {
|
||||
if (C._ts_lookahead_iterator_reset(this[0], language[0], stateId)) {
|
||||
this.language = language;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
const self = this;
|
||||
return {
|
||||
next() {
|
||||
if (C._ts_lookahead_iterator_next(self[0])) {
|
||||
return { done: false, value: self.currentType };
|
||||
}
|
||||
|
||||
return { done: true, value: "" };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Query {
|
||||
constructor(
|
||||
internal, address, captureNames, textPredicates, predicates,
|
||||
|
|
|
|||
|
|
@ -4,22 +4,27 @@
|
|||
"_malloc",
|
||||
"_realloc",
|
||||
|
||||
"__ZNKSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4copyEPcmm",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7reserveEm",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__grow_byEmmmmmm",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9push_backEc",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev",
|
||||
"__ZNSt3__212basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE9push_backEw",
|
||||
"__ZNKSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4copyEPcmm",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE7reserveEm",
|
||||
"__ZNSt3__212basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEE6resizeEmw",
|
||||
"__ZNSt3__212basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev",
|
||||
"__ZNSt3__212basic_stringIwNS_11char_traitsIwEENS_9allocatorIwEEED2Ev",
|
||||
"__ZdlPv",
|
||||
"__Znwm",
|
||||
"___cxa_atexit",
|
||||
"_abort",
|
||||
"_isalpha",
|
||||
"_isspace",
|
||||
"_iswalnum",
|
||||
"_iswalpha",
|
||||
"_iswblank",
|
||||
"_iswdigit",
|
||||
"_iswlower",
|
||||
"_iswupper",
|
||||
"_iswspace",
|
||||
"_memchr",
|
||||
"_memcmp",
|
||||
|
|
@ -27,7 +32,12 @@
|
|||
"_memmove",
|
||||
"_memset",
|
||||
"_strlen",
|
||||
"_strcmp",
|
||||
"_strncpy",
|
||||
"_tolower",
|
||||
"_towlower",
|
||||
"_towupper",
|
||||
"_stderr",
|
||||
|
||||
"_ts_init",
|
||||
"_ts_language_field_count",
|
||||
|
|
@ -35,10 +45,13 @@
|
|||
"_ts_language_type_is_named_wasm",
|
||||
"_ts_language_type_is_visible_wasm",
|
||||
"_ts_language_symbol_count",
|
||||
"_ts_language_state_count",
|
||||
"_ts_language_symbol_for_name",
|
||||
"_ts_language_symbol_name",
|
||||
"_ts_language_symbol_type",
|
||||
"_ts_language_version",
|
||||
"_ts_language_next_state",
|
||||
"_ts_node_field_name_for_child_wasm",
|
||||
"_ts_node_child_by_field_id_wasm",
|
||||
"_ts_node_child_count_wasm",
|
||||
"_ts_node_child_wasm",
|
||||
|
|
@ -50,8 +63,11 @@
|
|||
"_ts_node_end_point_wasm",
|
||||
"_ts_node_has_changes_wasm",
|
||||
"_ts_node_has_error_wasm",
|
||||
"_ts_node_is_error_wasm",
|
||||
"_ts_node_is_missing_wasm",
|
||||
"_ts_node_is_named_wasm",
|
||||
"_ts_node_parse_state_wasm",
|
||||
"_ts_node_next_parse_state_wasm",
|
||||
"_ts_node_named_child_count_wasm",
|
||||
"_ts_node_named_child_wasm",
|
||||
"_ts_node_named_children_wasm",
|
||||
|
|
@ -65,6 +81,7 @@
|
|||
"_ts_node_start_index_wasm",
|
||||
"_ts_node_start_point_wasm",
|
||||
"_ts_node_symbol_wasm",
|
||||
"_ts_node_grammar_symbol_wasm",
|
||||
"_ts_node_to_string_wasm",
|
||||
"_ts_parser_delete",
|
||||
"_ts_parser_enable_logger_wasm",
|
||||
|
|
@ -90,19 +107,29 @@
|
|||
"_ts_tree_cursor_current_node_is_missing_wasm",
|
||||
"_ts_tree_cursor_current_node_is_named_wasm",
|
||||
"_ts_tree_cursor_current_node_type_id_wasm",
|
||||
"_ts_tree_cursor_current_node_state_id_wasm",
|
||||
"_ts_tree_cursor_current_node_wasm",
|
||||
"_ts_tree_cursor_delete_wasm",
|
||||
"_ts_tree_cursor_end_index_wasm",
|
||||
"_ts_tree_cursor_end_position_wasm",
|
||||
"_ts_tree_cursor_goto_first_child_wasm",
|
||||
"_ts_tree_cursor_goto_last_child_wasm",
|
||||
"_ts_tree_cursor_goto_next_sibling_wasm",
|
||||
"_ts_tree_cursor_goto_previous_sibling_wasm",
|
||||
"_ts_tree_cursor_goto_parent_wasm",
|
||||
"_ts_tree_cursor_new_wasm",
|
||||
"_ts_tree_cursor_reset_wasm",
|
||||
"_ts_tree_cursor_reset_to_wasm",
|
||||
"_ts_tree_cursor_start_index_wasm",
|
||||
"_ts_tree_cursor_start_position_wasm",
|
||||
"_ts_tree_delete",
|
||||
"_ts_tree_edit_wasm",
|
||||
"_ts_tree_get_changed_ranges_wasm",
|
||||
"_ts_tree_root_node_wasm"
|
||||
"_ts_tree_root_node_wasm",
|
||||
"_ts_lookahead_iterator_new",
|
||||
"_ts_lookahead_iterator_delete",
|
||||
"_ts_lookahead_iterator_reset_state",
|
||||
"_ts_lookahead_iterator_reset",
|
||||
"_ts_lookahead_iterator_next",
|
||||
"_ts_lookahead_iterator_current_symbol"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "web-tree-sitter",
|
||||
"version": "0.20.7",
|
||||
"version": "0.20.8",
|
||||
"description": "Tree-sitter bindings for the web",
|
||||
"main": "tree-sitter.js",
|
||||
"types": "tree-sitter-web.d.ts",
|
||||
|
|
@ -27,8 +27,8 @@
|
|||
},
|
||||
"homepage": "https://github.com/tree-sitter/tree-sitter/tree/master/lib/binding_web",
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"mocha": "^6.1.4",
|
||||
"terser": "^3.17.0"
|
||||
"chai": "^4.3.7",
|
||||
"mocha": "^10.2.0",
|
||||
"terser": "^5.16.6"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,3 +42,46 @@ describe("Language", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Lookahead iterator", () => {
|
||||
let lookahead;
|
||||
let state;
|
||||
before(async () => {
|
||||
let Parser;
|
||||
({ JavaScript, Parser } = await require("./helper"));
|
||||
const parser = new Parser().setLanguage(JavaScript);
|
||||
const tree = parser.parse("function fn() {}");
|
||||
parser.delete();
|
||||
const cursor = tree.walk();
|
||||
assert(cursor.gotoFirstChild());
|
||||
assert(cursor.gotoFirstChild());
|
||||
state = cursor.currentNode().nextParseState;
|
||||
lookahead = JavaScript.lookaheadIterator(state);
|
||||
assert.exists(lookahead);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
lookahead.delete();
|
||||
});
|
||||
|
||||
const expected = ["identifier", "comment", "(", "*", "formal_parameters"];
|
||||
it("should iterate over valid symbols in the state", () => {
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
assert.lengthOf(symbols, expected.length);
|
||||
});
|
||||
|
||||
it("should reset to the initial state", () => {
|
||||
assert(lookahead.resetState(state));
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
assert.lengthOf(symbols, expected.length);
|
||||
});
|
||||
|
||||
it("should reset", () => {
|
||||
assert(lookahead.reset(JavaScript, state));
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
assert.lengthOf(symbols, expected.length);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -268,6 +268,24 @@ describe("Node", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(".isError()", () => {
|
||||
it("returns true if the node is an error", () => {
|
||||
tree = parser.parse("2 * * 3");
|
||||
const node = tree.rootNode;
|
||||
assert.equal(
|
||||
node.toString(),
|
||||
'(program (expression_statement (binary_expression left: (number) (ERROR) right: (number))))'
|
||||
);
|
||||
|
||||
const multi = node.firstChild.firstChild;
|
||||
assert(multi.hasError());
|
||||
assert(!multi.children[0].isError());
|
||||
assert(!multi.children[1].isError());
|
||||
assert(multi.children[2].isError());
|
||||
assert(!multi.children[3].isError());
|
||||
});
|
||||
});
|
||||
|
||||
describe(".isMissing()", () => {
|
||||
it("returns true if the node is missing from the source and was inserted via error recovery", () => {
|
||||
tree = parser.parse("(2 ||)");
|
||||
|
|
@ -308,6 +326,34 @@ describe("Node", () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe(".parseState, .nextParseState", () => {
|
||||
const text = "10 / 5";
|
||||
|
||||
it("returns node parse state ids", async () => {
|
||||
tree = await parser.parse(text)
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
const [numerator, slash, denominator] = quotientNode.children;
|
||||
|
||||
assert.equal(tree.rootNode.parseState, 0);
|
||||
// parse states will change on any change to the grammar so test that it
|
||||
// returns something instead
|
||||
assert.isAbove(numerator.parseState, 0);
|
||||
assert.isAbove(slash.parseState, 0);
|
||||
assert.isAbove(denominator.parseState, 0);
|
||||
})
|
||||
|
||||
it("returns next parse state equal to the language", async () => {
|
||||
tree = await parser.parse(text);
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
quotientNode.children.forEach(node => {
|
||||
assert.equal(
|
||||
node.nextParseState,
|
||||
JavaScript.nextState(node.parseState, node.grammarId)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.descendantsOfType(type, min, max)', () => {
|
||||
it('finds all of the descendants of the given type in the given range', () => {
|
||||
tree = parser.parse("a + 1 * b * 2 + c + 3");
|
||||
|
|
@ -408,4 +454,20 @@ describe("Node", () => {
|
|||
assert(!node1.equals(node2));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.fieldNameForChild(index)', () => {
|
||||
it('returns the field of a child or null', () => {
|
||||
tree = parser.parse('let a = 5');
|
||||
|
||||
const noField = tree.rootNode.fieldNameForChild(0);
|
||||
const name = tree.rootNode.firstChild.children[1].fieldNameForChild(0);
|
||||
const value = tree.rootNode.firstChild.children[1].fieldNameForChild(2);
|
||||
const overflow = tree.rootNode.firstChild.children[1].fieldNameForChild(3);
|
||||
|
||||
assert.equal(noField, null);
|
||||
assert.equal(name, 'name');
|
||||
assert.equal(value, 'value');
|
||||
assert.equal(overflow, null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -127,19 +127,19 @@ describe("Parser", () => {
|
|||
|
||||
it("can use the bash parser", async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('bash')));
|
||||
tree = parser.parse("FOO=bar echo <<EOF 2> err.txt > hello.txt \nhello\nEOF");
|
||||
tree = parser.parse("FOO=bar echo <<EOF 2> err.txt > hello.txt \nhello${FOO}\nEOF");
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(program (redirected_statement ' +
|
||||
'body: (command ' +
|
||||
'(variable_assignment ' +
|
||||
'name: (variable_name) ' +
|
||||
'value: (word)) ' +
|
||||
'name: (command_name (word))) ' +
|
||||
'redirect: (heredoc_redirect (heredoc_start)) ' +
|
||||
'redirect: (file_redirect descriptor: (file_descriptor) destination: (word)) ' +
|
||||
'redirect: (file_redirect destination: (word))) ' +
|
||||
'(heredoc_body))'
|
||||
'(program ' +
|
||||
'(redirected_statement ' +
|
||||
'body: (command ' +
|
||||
'(variable_assignment name: (variable_name) value: (word)) ' +
|
||||
'name: (command_name (word))) ' +
|
||||
'redirect: (heredoc_redirect (heredoc_start) ' +
|
||||
'redirect: (file_redirect descriptor: (file_descriptor) destination: (word)) ' +
|
||||
'redirect: (file_redirect destination: (word)) ' +
|
||||
'(heredoc_body ' +
|
||||
'(expansion (variable_name)) (heredoc_content)) (heredoc_end))))'
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ describe("Parser", () => {
|
|||
'type: (primitive_type) ' +
|
||||
'declarator: (init_declarator ' +
|
||||
'declarator: (pointer_declarator declarator: (identifier)) ' +
|
||||
'value: (raw_string_literal))))'
|
||||
'value: (raw_string_literal delimiter: (raw_string_delimiter) (raw_string_content) (raw_string_delimiter)))))'
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
|
|
|
|||
|
|
@ -244,6 +244,50 @@ describe("Tree", () => {
|
|||
endIndex: 13
|
||||
});
|
||||
|
||||
{
|
||||
const copy = tree.walk();
|
||||
copy.resetTo(cursor);
|
||||
|
||||
assert(copy.gotoPreviousSibling());
|
||||
assertCursorState(copy, {
|
||||
nodeType: '+',
|
||||
nodeIsNamed: false,
|
||||
startPosition: {row: 0, column: 6},
|
||||
endPosition: {row: 0, column: 7},
|
||||
startIndex: 6,
|
||||
endIndex: 7
|
||||
});
|
||||
|
||||
assert(copy.gotoPreviousSibling());
|
||||
assertCursorState(copy, {
|
||||
nodeType: 'binary_expression',
|
||||
nodeIsNamed: true,
|
||||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 0,
|
||||
endIndex: 5
|
||||
});
|
||||
|
||||
assert(copy.gotoLastChild());
|
||||
assertCursorState(copy, {
|
||||
nodeType: "identifier",
|
||||
nodeIsNamed: true,
|
||||
startPosition: {row: 0, column: 4},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 4,
|
||||
endIndex: 5
|
||||
})
|
||||
|
||||
assert(copy.gotoParent());
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'binary_expression')
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'expression_statement')
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'program')
|
||||
assert(!copy.gotoParent());
|
||||
}
|
||||
|
||||
// const childIndex = cursor.gotoFirstChildForIndex(12);
|
||||
// assertCursorState(cursor, {
|
||||
// nodeType: 'identifier',
|
||||
|
|
|
|||
25
lib/binding_web/tree-sitter-web.d.ts
vendored
25
lib/binding_web/tree-sitter-web.d.ts
vendored
|
|
@ -55,10 +55,14 @@ declare module 'web-tree-sitter' {
|
|||
) => string | null;
|
||||
|
||||
export interface SyntaxNode {
|
||||
id: number;
|
||||
typeId: number;
|
||||
grammarId: number;
|
||||
tree: Tree;
|
||||
type: string;
|
||||
grammarType: string;
|
||||
text: string;
|
||||
parseState: number;
|
||||
nextParseState: number;
|
||||
startPosition: Point;
|
||||
endPosition: Point;
|
||||
startIndex: number;
|
||||
|
|
@ -80,6 +84,7 @@ declare module 'web-tree-sitter' {
|
|||
hasChanges(): boolean;
|
||||
hasError(): boolean;
|
||||
equals(other: SyntaxNode): boolean;
|
||||
isError(): boolean;
|
||||
isMissing(): boolean;
|
||||
isNamed(): boolean;
|
||||
toString(): string;
|
||||
|
|
@ -104,6 +109,7 @@ declare module 'web-tree-sitter' {
|
|||
export interface TreeCursor {
|
||||
nodeType: string;
|
||||
nodeTypeId: number;
|
||||
nodeStateId: number;
|
||||
nodeText: string;
|
||||
nodeId: number;
|
||||
nodeIsNamed: boolean;
|
||||
|
|
@ -114,14 +120,17 @@ declare module 'web-tree-sitter' {
|
|||
endIndex: number;
|
||||
|
||||
reset(node: SyntaxNode): void;
|
||||
resetTo(cursor: TreeCursor): void;
|
||||
delete(): void;
|
||||
currentNode(): SyntaxNode;
|
||||
currentFieldId(): number;
|
||||
currentFieldName(): string;
|
||||
gotoParent(): boolean;
|
||||
gotoFirstChild(): boolean;
|
||||
gotoLastChild(): boolean;
|
||||
gotoFirstChildForIndex(index: number): boolean;
|
||||
gotoNextSibling(): boolean;
|
||||
gotoPreviousSibling(): boolean;
|
||||
}
|
||||
|
||||
export interface Tree {
|
||||
|
|
@ -141,6 +150,7 @@ declare module 'web-tree-sitter' {
|
|||
|
||||
readonly version: number;
|
||||
readonly fieldCount: number;
|
||||
readonly stateCount: number;
|
||||
readonly nodeTypeCount: number;
|
||||
|
||||
fieldNameForId(fieldId: number): string | null;
|
||||
|
|
@ -149,7 +159,20 @@ declare module 'web-tree-sitter' {
|
|||
nodeTypeForId(typeId: number): string | null;
|
||||
nodeTypeIsNamed(typeId: number): boolean;
|
||||
nodeTypeIsVisible(typeId: number): boolean;
|
||||
nextState(stateId: number, typeId: number): number;
|
||||
query(source: string): Query;
|
||||
lookaheadIterator(stateId: number): LookaheadIterable | null;
|
||||
}
|
||||
|
||||
class LookaheadIterable {
|
||||
readonly language: Language;
|
||||
readonly currentTypeId: number;
|
||||
readonly currentType: string;
|
||||
|
||||
delete(): void;
|
||||
resetState(stateId: number): boolean;
|
||||
reset(language: Language, stateId: number): boolean;
|
||||
[Symbol.iterator](): Iterator<string>;
|
||||
}
|
||||
|
||||
interface QueryCapture {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue