Merge branch 'master' into actions-ci

This commit is contained in:
Max Brunsfeld 2021-02-05 10:19:05 -08:00
commit 6dbe6a3a90
27 changed files with 932 additions and 460 deletions

View file

@ -24,7 +24,7 @@ include = [
regex = "1"
[build-dependencies]
cc = "1.0"
cc = "^1.0.58"
[lib]
path = "binding_rust/lib.rs"

View file

@ -1147,6 +1147,12 @@ impl<'a> TreeCursor<'a> {
}
}
impl<'a> Clone for TreeCursor<'a> {
fn clone(&self) -> Self {
TreeCursor(unsafe { ffi::ts_tree_cursor_copy(&self.0) }, PhantomData)
}
}
impl<'a> Drop for TreeCursor<'a> {
fn drop(&mut self) {
unsafe { ffi::ts_tree_cursor_delete(&mut self.0) }

View file

@ -7,7 +7,7 @@ WebAssembly bindings to the [Tree-sitter](https://github.com/tree-sitter/tree-si
### 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/tag/0.14.7) and load them using a standalone script:
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:
```html
<script src="/the/path/to/tree-sitter.js"/>

View file

@ -184,6 +184,20 @@ TSTree *ts_parser_parse_wasm(
return ts_parser_parse(self, old_tree, input);
}
/**********************/
/* Section - Language */
/**********************/
int ts_language_type_is_named_wasm(const TSLanguage *self, TSSymbol typeId) {
const TSSymbolType symbolType = ts_language_symbol_type(self, typeId);
return symbolType == TSSymbolTypeRegular;
}
int ts_language_type_is_visible_wasm(const TSLanguage *self, TSSymbol typeId) {
const TSSymbolType symbolType = ts_language_symbol_type(self, typeId);
return symbolType <= TSSymbolTypeAnonymous;
}
/******************/
/* Section - Tree */
/******************/

View file

@ -646,6 +646,32 @@ class Language {
return this.fields[fieldId] || null;
}
idForNodeType(type, named) {
const typeLength = lengthBytesUTF8(type);
const typeAddress = C._malloc(typeLength + 1);
stringToUTF8(type, typeAddress, typeLength + 1);
const result = C._ts_language_symbol_for_name(this[0], typeAddress, typeLength, named);
C._free(typeAddress);
return result || null;
}
get nodeTypeCount() {
return C._ts_language_symbol_count(this[0]);
}
nodeTypeForId(typeId) {
const name = C._ts_language_symbol_name(this[0], typeId);
return name ? UTF8ToString(name) : null;
}
nodeTypeIsNamed(typeId) {
return C._ts_language_type_is_named_wasm(this[0], typeId) ? true : false;
}
nodeTypeIsVisible(typeId) {
return C._ts_language_type_is_visible_wasm(this[0], typeId) ? true : false;
}
query(source) {
const sourceLength = lengthBytesUTF8(source);
const sourceAddress = C._malloc(sourceLength + 1);
@ -856,30 +882,41 @@ class Language {
);
}
static load(url) {
static load(input) {
let bytes;
if (
typeof process !== 'undefined' &&
process.versions &&
process.versions.node
) {
const fs = require('fs');
bytes = Promise.resolve(fs.readFileSync(url));
if (input instanceof Uint8Array) {
bytes = Promise.resolve(input);
} else {
bytes = fetch(url)
.then(response => response.arrayBuffer()
.then(buffer => {
if (response.ok) {
return new Uint8Array(buffer);
} else {
const body = new TextDecoder('utf-8').decode(buffer);
throw new Error(`Language.load failed with status ${response.status}.\n\n${body}`)
}
}));
const url = input;
if (
typeof process !== 'undefined' &&
process.versions &&
process.versions.node
) {
const fs = require('fs');
bytes = Promise.resolve(fs.readFileSync(url));
} else {
bytes = fetch(url)
.then(response => response.arrayBuffer()
.then(buffer => {
if (response.ok) {
return new Uint8Array(buffer);
} else {
const body = new TextDecoder('utf-8').decode(buffer);
throw new Error(`Language.load failed with status ${response.status}.\n\n${body}`)
}
}));
}
}
// emscripten-core/emscripten#12969
const loadModule =
typeof loadSideModule === 'function'
? loadSideModule
: loadWebAssemblyModule;
return bytes
.then(bytes => loadSideModule(bytes, {loadAsync: true}))
.then(bytes => loadModule(bytes, {loadAsync: true}))
.then(mod => {
const symbolNames = Object.keys(mod)
const functionName = symbolNames.find(key =>
@ -1139,3 +1176,4 @@ function marshalEdit(edit) {
}
Parser.Language = Language;
Parser.Parser = Parser;

View file

@ -31,7 +31,10 @@
"_ts_init",
"_ts_language_field_count",
"_ts_language_field_name_for_id",
"_ts_language_type_is_named_wasm",
"_ts_language_type_is_visible_wasm",
"_ts_language_symbol_count",
"_ts_language_symbol_for_name",
"_ts_language_symbol_name",
"_ts_language_symbol_type",
"_ts_language_version",
@ -79,6 +82,7 @@
"_ts_query_predicates_for_pattern",
"_ts_query_string_count",
"_ts_query_string_value_for_id",
"_ts_tree_copy",
"_ts_tree_cursor_current_field_id_wasm",
"_ts_tree_cursor_current_node_id_wasm",
"_ts_tree_cursor_current_node_is_missing_wasm",

View file

@ -1,6 +1,6 @@
{
"name": "web-tree-sitter",
"version": "0.17.1",
"version": "0.18.0",
"description": "Tree-sitter bindings for the web",
"main": "tree-sitter.js",
"types": "tree-sitter-web.d.ts",

View file

@ -0,0 +1,44 @@
const { assert } = require("chai");
let JavaScript;
describe("Language", () => {
before(async () => ({ JavaScript } = await require("./helper")));
describe(".fieldIdForName, .fieldNameForId", () => {
it("converts between the string and integer representations of fields", () => {
const nameId = JavaScript.fieldIdForName("name");
const bodyId = JavaScript.fieldIdForName("body");
assert.isBelow(nameId, JavaScript.fieldCount);
assert.isBelow(bodyId, JavaScript.fieldCount);
assert.equal("name", JavaScript.fieldNameForId(nameId));
assert.equal("body", JavaScript.fieldNameForId(bodyId));
});
it("handles invalid inputs", () => {
assert.equal(null, JavaScript.fieldIdForName("namezzz"));
assert.equal(null, JavaScript.fieldNameForId(-1));
assert.equal(null, JavaScript.fieldNameForId(10000));
});
});
describe(".idForNodeType, .nodeTypeForId, .nodeTypeIsNamed", () => {
it("converts between the string and integer representations of a node type", () => {
const exportStatementId = JavaScript.idForNodeType("export_statement", true);
const starId = JavaScript.idForNodeType("*", false);
assert.isBelow(exportStatementId, JavaScript.nodeTypeCount);
assert.isBelow(starId, JavaScript.nodeTypeCount);
assert.equal(true, JavaScript.nodeTypeIsNamed(exportStatementId))
assert.equal("export_statement", JavaScript.nodeTypeForId(exportStatementId))
assert.equal(false, JavaScript.nodeTypeIsNamed(starId))
assert.equal("*", JavaScript.nodeTypeForId(starId))
});
it("handles invalid inputs", () => {
assert.equal(null, JavaScript.nodeTypeForId(-1));
assert.equal(null, JavaScript.nodeTypeForId(10000));
assert.equal(null, JavaScript.idForNodeType("export_statement", false));
});
});
});

View file

@ -323,6 +323,31 @@ describe("Tree", () => {
assert(!cursor.gotoParent());
})
});
describe(".copy", () => {
it("creates another tree that remains stable if the original tree is edited", () => {
input = 'abc + cde';
tree = parser.parse(input);
assert.equal(
tree.rootNode.toString(),
"(program (expression_statement (binary_expression left: (identifier) right: (identifier))))"
);
const tree2 = tree.copy();
([input, edit] = spliceInput(input, 3, 0, '123'));
assert.equal(input, 'abc123 + cde');
tree.edit(edit);
const leftNode = tree.rootNode.firstChild.firstChild.firstChild;
const leftNode2 = tree2.rootNode.firstChild.firstChild.firstChild;
const rightNode = tree.rootNode.firstChild.firstChild.lastChild;
const rightNode2 = tree2.rootNode.firstChild.firstChild.lastChild;
assert.equal(leftNode.endIndex, 6)
assert.equal(leftNode2.endIndex, 3)
assert.equal(rightNode.startIndex, 9)
assert.equal(rightNode2.startIndex, 6)
});
});
});
function spliceInput(input, startIndex, lengthRemoved, newText) {

View file

@ -127,13 +127,18 @@ declare module 'web-tree-sitter' {
}
class Language {
static load(path: string): Promise<Language>;
static load(input: string | Uint8Array): Promise<Language>;
readonly version: number;
readonly fieldCount: number;
readonly nodeTypeCount: number;
fieldNameForId(fieldId: number): string | null;
fieldIdForName(fieldName: string): number | null;
idForNodeType(type: string, named: boolean): number;
nodeTypeForId(typeId: number): string | null;
nodeTypeIsNamed(typeId: number): boolean;
nodeTypeIsVisible(typeId: number): boolean;
query(source: string): Query;
}

View file

@ -448,6 +448,7 @@ TSTreeCursor ts_tree_cursor_copy(const TSTreeCursor *_cursor) {
TSTreeCursor res = {NULL, NULL, {0, 0}};
TreeCursor *copy = (TreeCursor *)&res;
copy->tree = cursor->tree;
array_init(&copy->stack);
array_push_all(&copy->stack, &cursor->stack);
return res;
}