Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ tree_sitter
*.xcodeproj
node_modules
.vagrant
package-lock.json
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@ console.log(tree.rootNode.toString());
// (member_expression (identifier) (property_identifier))
// (arguments (identifier)))))

const callExpression = tree.rootNode.children[1].firstChild;
const callExpression = tree.rootNode.child(1).firstChild;
console.log(callExpression);

// { type: 'call_expression',
// startPosition: {row: 0, column: 16},
// endPosition: {row: 0, column: 30},
// startIndex: 0,
// endIndex: 30,
// children: { length: 2 } }
// endIndex: 30 }
```

If your source code *changes*, you can update the syntax tree. This will take less time than the first parse.
Expand Down
1 change: 0 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"src/conversions.cc",
"src/input_reader.cc",
"src/logger.cc",
"src/node_array.cc",
"src/node.cc",
"src/parser.cc",
"src/tree.cc",
Expand Down
275 changes: 249 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,216 @@ try {
}
}

const {Parser, Node, NodeArray, TreeCursor, pointTransferArray} = binding;
const {Parser, NodeMethods, Tree, TreeCursor} = binding;

const {rootNode} = Tree.prototype;

Object.defineProperty(Tree.prototype, 'rootNode', {
get() {
if (!this.nodes) this.nodes = {};
rootNode.call(this);
return unmarshalNode(this);
}
})

class SyntaxNode {
constructor(tree) {
this.tree = tree;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class should replace Node in the .d.ts file right? Along with all it's info


get type() {
marshalNode(this);
return NodeMethods.type(this.tree);
}

get isNamed() {
marshalNode(this);
return NodeMethods.isNamed(this.tree);
}

get startPosition() {
marshalNode(this);
NodeMethods.startPosition(this.tree);
return unmarshalPoint();
}

get endPosition() {
marshalNode(this);
NodeMethods.endPosition(this.tree);
return unmarshalPoint();
}

get startIndex() {
marshalNode(this);
return NodeMethods.startIndex(this.tree);
}

get endIndex() {
marshalNode(this);
return NodeMethods.endIndex(this.tree);
}

get parent() {
marshalNode(this);
NodeMethods.parent(this.tree);
return unmarshalNode(this.tree);
}

get children() {
const {childCount} = this;
const result = new Array(childCount);
for (let i = 0; i < childCount; i++) {
result[i] = this.child(i);
}
return result;
}

get namedChildren() {
const {namedChildCount} = this;
const result = new Array(namedChildCount);
for (let i = 0; i < namedChildCount; i++) {
result[i] = this.namedChild(i);
}
return result;
}

get childCount() {
marshalNode(this);
return NodeMethods.childCount(this.tree);
}

get namedChildCount() {
marshalNode(this);
return NodeMethods.namedChildCount(this.tree);
}

get firstChild() {
marshalNode(this);
NodeMethods.firstChild(this.tree);
return unmarshalNode(this.tree);
}

get firstNamedChild() {
marshalNode(this);
NodeMethods.firstNamedChild(this.tree);
return unmarshalNode(this.tree);
}

get lastChild() {
marshalNode(this);
NodeMethods.lastChild(this.tree);
return unmarshalNode(this.tree);
}

get lastNamedChild() {
marshalNode(this);
NodeMethods.lastNamedChild(this.tree);
return unmarshalNode(this.tree);
}

get nextSibling() {
marshalNode(this);
NodeMethods.nextSibling(this.tree);
return unmarshalNode(this.tree);
}

get nextNamedSibling() {
marshalNode(this);
NodeMethods.nextNamedSibling(this.tree);
return unmarshalNode(this.tree);
}

get previousSibling() {
marshalNode(this);
NodeMethods.previousSibling(this.tree);
return unmarshalNode(this.tree);
}

get previousNamedSibling() {
marshalNode(this);
NodeMethods.previousNamedSibling(this.tree);
return unmarshalNode(this.tree);
}

hasError() {
marshalNode(this);
return NodeMethods.hasError(this.tree);
}

isMissing() {
marshalNode(this);
return NodeMethods.isMissing(this.tree);
}

toString() {
marshalNode(this);
return NodeMethods.toString(this.tree);
}

child(index) {
marshalNode(this);
NodeMethods.child(this.tree, index);
return unmarshalNode(this.tree);
}

namedChild(index) {
marshalNode(this);
NodeMethods.namedChild(this.tree, index);
return unmarshalNode(this.tree);
}

firstChildForIndex(index) {
marshalNode(this);
NodeMethods.firstChildForIndex(this.tree, index);
return unmarshalNode(this.tree);
}

firstNamedChildForIndex(index) {
marshalNode(this);
NodeMethods.firstNamedChildForIndex(this.tree, index);
return unmarshalNode(this.tree);
}

namedDescendantForIndex(start, end) {
marshalNode(this);
if (end != null) {
NodeMethods.namedDescendantForIndex(this.tree, start, end);
} else {
NodeMethods.namedDescendantForIndex(this.tree, start, start);
}
return unmarshalNode(this.tree);
}

descendantForIndex(start, end) {
marshalNode(this);
if (end != null) {
NodeMethods.descendantForIndex(this.tree, start, end);
} else {
NodeMethods.descendantForIndex(this.tree, start, start);
}
return unmarshalNode(this.tree);
}

namedDescendantForPosition(start, end) {
marshalNode(this);
if (end != null) {
NodeMethods.namedDescendantForPosition(this.tree, start, end);
} else {
NodeMethods.namedDescendantForPosition(this.tree, start, start);
}
return unmarshalNode(this.tree);
}

descendantForPosition(start, end) {
marshalNode(this);
if (end != null) {
NodeMethods.descendantForPosition(this.tree, start, end);
} else {
NodeMethods.descendantForPosition(this.tree, start, start);
}
return unmarshalNode(this.tree);
}
}

class StringInput {
constructor(string, bufferSize) {
Expand Down Expand Up @@ -54,7 +263,7 @@ Parser.prototype.parseTextBuffer = function(buffer, oldTree, options) {
const snapshot = buffer.getSnapshot();
const syncOperationLimit = options && options.syncOperationLimit;
return new Promise(resolve => {
parseTextBuffer.call(this, (result) => {
parseTextBuffer.call(this, result => {
snapshot.destroy();
resolve(result);
}, snapshot, oldTree, syncOperationLimit)
Expand All @@ -68,37 +277,51 @@ Parser.prototype.parseTextBufferSync = function(buffer, oldTree) {
return tree;
};

NodeArray.prototype[Symbol.iterator] = function*() {
let node = this[0];
const {startPosition, endPosition} = TreeCursor.prototype;

const getNext = this.isNamed ?
(node) => node.nextNamedSibling :
(node) => node.nextSibling;
Object.defineProperty(TreeCursor.prototype, 'startPosition', {
get() {
startPosition.call(this);
return unmarshalPoint();
}
});

while (node) {
yield node;
node = getNext(node);
Object.defineProperty(TreeCursor.prototype, 'endPosition', {
get() {
endPosition.call(this);
return unmarshalPoint();
}
}
});

for (const {prototype} of [Node, TreeCursor]) {
const {startPosition, endPosition} = prototype;
Object.defineProperty(prototype, 'startPosition', {
get() {
startPosition.call(this);
return transferPoint();
}
});
const {pointTransferArray, nodeTransferArray} = binding;

Object.defineProperty(prototype, 'endPosition', {
get() {
endPosition.call(this);
return transferPoint();
}
});
function unmarshalNode(tree) {
const key = `${nodeTransferArray[0]}${nodeTransferArray[1]}`
if (key === '00') return null;
let result = tree.nodes[key];
if (!result) {
result = new SyntaxNode(tree);
result._0 = nodeTransferArray[0];
result._1 = nodeTransferArray[1];
result._2 = nodeTransferArray[2];
result._3 = nodeTransferArray[3];
result._4 = nodeTransferArray[4];
result._5 = nodeTransferArray[5];
tree.nodes[key] = result;
}
return result;
}

function marshalNode(node) {
nodeTransferArray[0] = node._0;
nodeTransferArray[1] = node._1;
nodeTransferArray[2] = node._2;
nodeTransferArray[3] = node._3;
nodeTransferArray[4] = node._4;
nodeTransferArray[5] = node._5;
}

function transferPoint() {
function unmarshalPoint() {
return {row: pointTransferArray[0], column: pointTransferArray[1]};
}

Expand Down
13 changes: 0 additions & 13 deletions package-lock.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tree-sitter",
"version": "0.12.7",
"version": "0.12.8-1",
"description": "Incremental parsers for node",
"author": "Max Brunsfeld",
"license": "MIT",
Expand Down
2 changes: 0 additions & 2 deletions src/binding.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <node.h>
#include <v8.h>
#include "./node.h"
#include "./node_array.h"
#include "./parser.h"
#include "./tree.h"
#include "./tree_cursor.h"
Expand All @@ -15,7 +14,6 @@ using namespace v8;
void InitAll(Local<Object> exports) {
InitConversions(exports);
Node::Init(exports);
NodeArray::Init(exports);
InputReader::Init();
Parser::Init(exports);
Tree::Init(exports);
Expand Down
4 changes: 2 additions & 2 deletions src/conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ Local<Number> ByteCountToJS(uint32_t byte_count) {
}

Nan::Maybe<uint32_t> ByteCountFromJS(const v8::Local<v8::Value> &arg) {
if (!arg->IsNumber()) {
if (!arg->IsUint32()) {
Nan::ThrowTypeError("Character index must be a number");
return Nan::Nothing<uint32_t>();
}

return Nan::Just<uint32_t>(arg->Int32Value() * BYTES_PER_CHARACTER);
return Nan::Just<uint32_t>(arg->Uint32Value() * BYTES_PER_CHARACTER);
}

} // namespace node_tree_sitter
Loading