diff --git a/.gitignore b/.gitignore index 7e06102d..4a87b994 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ tree_sitter *.xcodeproj node_modules .vagrant +package-lock.json diff --git a/README.md b/README.md index 51de82fe..14f0ecf6 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/binding.gyp b/binding.gyp index 201de04a..a1107bcd 100644 --- a/binding.gyp +++ b/binding.gyp @@ -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", diff --git a/index.js b/index.js index 0f67a603..523e0c6a 100644 --- a/index.js +++ b/index.js @@ -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; + } + + 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) { @@ -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) @@ -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]}; } diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 237106ab..00000000 --- a/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "tree-sitter", - "version": "0.12.7", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "nan": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", - "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" - } - } -} diff --git a/package.json b/package.json index aae7cec6..9d09527d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/binding.cc b/src/binding.cc index 3eb979e8..28f63785 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1,7 +1,6 @@ #include #include #include "./node.h" -#include "./node_array.h" #include "./parser.h" #include "./tree.h" #include "./tree_cursor.h" @@ -15,7 +14,6 @@ using namespace v8; void InitAll(Local exports) { InitConversions(exports); Node::Init(exports); - NodeArray::Init(exports); InputReader::Init(); Parser::Init(exports); Tree::Init(exports); diff --git a/src/conversions.cc b/src/conversions.cc index 475e0d1d..bd324146 100644 --- a/src/conversions.cc +++ b/src/conversions.cc @@ -75,12 +75,12 @@ Local ByteCountToJS(uint32_t byte_count) { } Nan::Maybe ByteCountFromJS(const v8::Local &arg) { - if (!arg->IsNumber()) { + if (!arg->IsUint32()) { Nan::ThrowTypeError("Character index must be a number"); return Nan::Nothing(); } - return Nan::Just(arg->Int32Value() * BYTES_PER_CHARACTER); + return Nan::Just(arg->Uint32Value() * BYTES_PER_CHARACTER); } } // namespace node_tree_sitter diff --git a/src/node.cc b/src/node.cc index 04cb91e4..b9fda7ee 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2,32 +2,29 @@ #include #include #include -#include "./node_array.h" #include "./util.h" #include "./conversions.h" +#include "./tree.h" namespace node_tree_sitter { using namespace v8; -Nan::Persistent Node::constructor; +static uint32_t *transfer_buffer; void Node::Init(Local exports) { - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Node").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); + Local result = Nan::New(); - GetterPair enum_getters[] = { + FunctionPair methods[] = { {"startIndex", StartIndex}, {"endIndex", EndIndex}, {"type", Type}, {"isNamed", IsNamed}, - }; - - GetterPair non_enum_getters[] = { {"parent", Parent}, - {"children", Children}, - {"namedChildren", NamedChildren}, + {"child", Child}, + {"namedChild", NamedChild}, + {"childCount", ChildCount}, + {"namedChildCount", NamedChildCount}, {"firstChild", FirstChild}, {"lastChild", LastChild}, {"firstNamedChild", FirstNamedChild}, @@ -37,9 +34,6 @@ void Node::Init(Local exports) { {"previousSibling", PreviousSibling}, {"previousNamedSibling", PreviousNamedSibling}, {"id", Id}, - }; - - FunctionPair methods[] = { {"startPosition", StartPosition}, {"endPosition", EndPosition}, {"isMissing", IsMissing}, @@ -54,403 +48,314 @@ void Node::Init(Local exports) { {"hasError", HasError}, }; - for (size_t i = 0; i < length_of_array(enum_getters); i++) - Nan::SetAccessor( - tpl->InstanceTemplate(), - Nan::New(enum_getters[i].name).ToLocalChecked(), - enum_getters[i].callback); - - for (size_t i = 0; i < length_of_array(non_enum_getters); i++) - Nan::SetAccessor( - tpl->InstanceTemplate(), - Nan::New(non_enum_getters[i].name).ToLocalChecked(), - non_enum_getters[i].callback, - 0, Local(), DEFAULT, DontEnum); - - for (size_t i = 0; i < length_of_array(methods); i++) - Nan::SetPrototypeMethod(tpl, methods[i].name, methods[i].callback); - - auto constructor_local = tpl->GetFunction(); - exports->Set(Nan::New("Node").ToLocalChecked(), constructor_local); - - constructor.Reset(Nan::Persistent(constructor_local)); -} - -Node *Node::Unwrap(const Local &object) { - Node *node = Nan::ObjectWrap::Unwrap(object); - if (node && node->node_.id) { - return node; - } else { - return NULL; + for (size_t i = 0; i < length_of_array(methods); i++) { + result->Set( + Nan::New(methods[i].name).ToLocalChecked(), + Nan::New(methods[i].callback)->GetFunction() + ); } -} - -Node::Node(TSNode node) : node_(node) {} -Local Node::NewInstance(TSNode node) { - Local self; - MaybeLocal maybe_self = Nan::New(constructor)->NewInstance(Nan::GetCurrentContext()); - if (maybe_self.ToLocal(&self)) { - (new Node(node))->Wrap(self); - return self; - } else { - return Nan::Null(); + uint32_t transfer_buffer_length = 6; + transfer_buffer = static_cast(malloc(transfer_buffer_length * sizeof(uint32_t))); + auto js_transfer_buffer = ArrayBuffer::New(Isolate::GetCurrent(), transfer_buffer, transfer_buffer_length * sizeof(uint32_t)); + exports->Set( + Nan::New("nodeTransferArray").ToLocalChecked(), + Uint32Array::New(js_transfer_buffer, 0, transfer_buffer_length) + ); + + exports->Set(Nan::New("NodeMethods").ToLocalChecked(), result); +} + +void Node::MarshalNode(TSNode node) { + transfer_buffer[0] = 0; + transfer_buffer[1] = 0; + memcpy(&transfer_buffer[0], &node.id, sizeof(node.id)); + transfer_buffer[2] = node.context[0]; + transfer_buffer[3] = node.context[1]; + transfer_buffer[4] = node.context[2]; + transfer_buffer[5] = node.context[3]; +} + +TSNode Node::UnmarshalNode(const v8::Local &tree) { + TSNode result = {{0, 0, 0, 0}, nullptr, nullptr}; + result.tree = Tree::UnwrapTree(tree); + if (!result.tree) { + Nan::ThrowTypeError("Argument must be a tree"); + return result; } -} -void Node::New(const Nan::FunctionCallbackInfo &info) { - info.GetReturnValue().Set(Nan::Null()); + memcpy(&result.id, &transfer_buffer[0], sizeof(result.id)); + result.context[0] = transfer_buffer[2]; + result.context[1] = transfer_buffer[3]; + result.context[2] = transfer_buffer[4]; + result.context[3] = transfer_buffer[5]; + return result; } void Node::ToString(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - const char *string = ts_node_string(node->node_); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + const char *string = ts_node_string(node); info.GetReturnValue().Set(Nan::New(string).ToLocalChecked()); free((char *)string); } } void Node::IsMissing(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - bool result = ts_node_is_missing(node->node_); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + bool result = ts_node_is_missing(node); info.GetReturnValue().Set(Nan::New(result)); } } void Node::HasChanges(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - bool result = ts_node_has_changes(node->node_); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + bool result = ts_node_has_changes(node); info.GetReturnValue().Set(Nan::New(result)); } } void Node::HasError(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - bool result = ts_node_has_error(node->node_); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + bool result = ts_node_has_error(node); info.GetReturnValue().Set(Nan::New(result)); } } void Node::FirstNamedChildForIndex(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node && info.Length() > 0) { - Nan::Maybe byte = ByteCountFromJS(info[0]); - if (byte.IsNothing()) return; - TSNode result = ts_node_first_named_child_for_byte(node->node_, byte.FromJust()); - if (result.id) { - info.GetReturnValue().Set(Node::NewInstance(result)); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + Nan::Maybe byte = ByteCountFromJS(info[1]); + if (byte.IsJust()) { + MarshalNode(ts_node_first_named_child_for_byte(node, byte.FromJust())); } } } void Node::FirstChildForIndex(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node && info.Length() > 0) { - Nan::Maybe byte = ByteCountFromJS(info[0]); - if (byte.IsNothing()) return; - TSNode result = ts_node_first_child_for_byte(node->node_, byte.FromJust()); - if (result.id) { - info.GetReturnValue().Set(Node::NewInstance(result)); + TSNode node = UnmarshalNode(info[0]); + if (node.id && info.Length() > 1) { + Nan::Maybe byte = ByteCountFromJS(info[1]); + if (byte.IsJust()) { + MarshalNode(ts_node_first_child_for_byte(node, byte.FromJust())); } } } void Node::NamedDescendantForIndex(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - uint32_t min, max; - switch (info.Length()) { - case 1: { - Nan::Maybe maybe_value = ByteCountFromJS(info[0]); - if (maybe_value.IsNothing()) return; - min = max = maybe_value.FromJust(); - break; - } - case 2: { - Nan::Maybe maybe_min = ByteCountFromJS(info[0]); - Nan::Maybe maybe_max = ByteCountFromJS(info[1]); - if (maybe_min.IsNothing()) return; - if (maybe_max.IsNothing()) return; - min = maybe_min.FromJust(); - max = maybe_max.FromJust(); - break; - } - default: - Nan::ThrowTypeError("Must provide 1 or 2 character indices"); - return; + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + Nan::Maybe maybe_min = ByteCountFromJS(info[1]); + Nan::Maybe maybe_max = ByteCountFromJS(info[2]); + if (maybe_min.IsJust() && maybe_max.IsJust()) { + uint32_t min = maybe_min.FromJust(); + uint32_t max = maybe_max.FromJust(); + MarshalNode(ts_node_named_descendant_for_byte_range(node, min, max)); } - - TSNode result = ts_node_named_descendant_for_byte_range(node->node_, min, max); - info.GetReturnValue().Set(Node::NewInstance(result)); } } void Node::DescendantForIndex(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - uint32_t min, max; - switch (info.Length()) { - case 1: { - Nan::Maybe maybe_value = ByteCountFromJS(info[0]); - if (maybe_value.IsNothing()) return; - min = max = maybe_value.FromJust(); - break; - } - case 2: { - Nan::Maybe maybe_min = ByteCountFromJS(info[0]); - Nan::Maybe maybe_max = ByteCountFromJS(info[1]); - if (maybe_min.IsNothing()) return; - if (maybe_max.IsNothing()) return; - min = maybe_min.FromJust(); - max = maybe_max.FromJust(); - break; - } - default: - Nan::ThrowTypeError("Must provide 1 or 2 character indices"); - return; + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + Nan::Maybe maybe_min = ByteCountFromJS(info[1]); + Nan::Maybe maybe_max = ByteCountFromJS(info[2]); + if (maybe_min.IsJust() && maybe_max.IsJust()) { + uint32_t min = maybe_min.FromJust(); + uint32_t max = maybe_max.FromJust(); + MarshalNode(ts_node_descendant_for_byte_range(node, min, max)); } - - TSNode result = ts_node_descendant_for_byte_range(node->node_, min, max); - info.GetReturnValue().Set(Node::NewInstance(result)); } } void Node::NamedDescendantForPosition(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSPoint min, max; - switch (info.Length()) { - case 1: { - Nan::Maybe value = PointFromJS(info[0]); - if (value.IsNothing()) return; - min = max = value.FromJust(); - break; - } - case 2: { - Nan::Maybe maybe_min = PointFromJS(info[0]); - Nan::Maybe maybe_max = PointFromJS(info[1]); - if (maybe_min.IsNothing()) return; - if (maybe_max.IsNothing()) return; - min = maybe_min.FromJust(); - max = maybe_max.FromJust(); - break; - } - default: - Nan::ThrowTypeError("Must provide 1 or 2 points"); - return; + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + Nan::Maybe maybe_min = PointFromJS(info[1]); + Nan::Maybe maybe_max = PointFromJS(info[2]); + if (maybe_min.IsJust() && maybe_max.IsJust()) { + TSPoint min = maybe_min.FromJust(); + TSPoint max = maybe_max.FromJust(); + MarshalNode(ts_node_named_descendant_for_point_range(node, min, max)); } - - TSNode result = ts_node_named_descendant_for_point_range(node->node_, min, max); - info.GetReturnValue().Set(Node::NewInstance(result)); } } void Node::DescendantForPosition(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSPoint min, max; - switch (info.Length()) { - case 1: { - Nan::Maybe value = PointFromJS(info[0]); - if (value.IsNothing()) return; - min = max = value.FromJust(); - break; - } - case 2: { - Nan::Maybe maybe_min = PointFromJS(info[0]); - Nan::Maybe maybe_max = PointFromJS(info[1]); - if (maybe_min.IsNothing()) return; - if (maybe_max.IsNothing()) return; - min = maybe_min.FromJust(); - max = maybe_max.FromJust(); - break; - } - default: - Nan::ThrowTypeError("Must provide 1 or 2 points"); - return; + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + Nan::Maybe maybe_min = PointFromJS(info[1]); + Nan::Maybe maybe_max = PointFromJS(info[2]); + if (maybe_min.IsJust() && maybe_max.IsJust()) { + TSPoint min = maybe_min.FromJust(); + TSPoint max = maybe_max.FromJust(); + MarshalNode(ts_node_descendant_for_point_range(node, min, max)); } - - TSNode result = ts_node_descendant_for_point_range(node->node_, min, max); - info.GetReturnValue().Set(Node::NewInstance(result)); } } -void Node::Type(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - const char *result = ts_node_type(node->node_); +void Node::Type(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + const char *result = ts_node_type(node); info.GetReturnValue().Set(Nan::New(result).ToLocalChecked()); } } -void Node::IsNamed(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - bool result = ts_node_is_named(node->node_); +void Node::IsNamed(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + bool result = ts_node_is_named(node); info.GetReturnValue().Set(Nan::New(result)); } } -void Node::Id(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - uint64_t result = reinterpret_cast(node->node_.id); +void Node::Id(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + uint64_t result = reinterpret_cast(node.id); info.GetReturnValue().Set(Nan::New(result)); } } -void Node::StartIndex(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - int32_t result = ts_node_start_byte(node->node_) / 2; +void Node::StartIndex(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + int32_t result = ts_node_start_byte(node) / 2; info.GetReturnValue().Set(Nan::New(result)); } } -void Node::EndIndex(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - int32_t result = ts_node_end_byte(node->node_) / 2; +void Node::EndIndex(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + int32_t result = ts_node_end_byte(node) / 2; info.GetReturnValue().Set(Nan::New(result)); } } void Node::StartPosition(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) TransferPoint(ts_node_start_point(node->node_)); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + TransferPoint(ts_node_start_point(node)); + } } void Node::EndPosition(const Nan::FunctionCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) TransferPoint(ts_node_end_point(node->node_)); -} - -void Node::Children(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - info.GetReturnValue().Set(NodeArray::NewInstance(node->node_, false)); + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + TransferPoint(ts_node_end_point(node)); } } -void Node::NamedChildren(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - info.GetReturnValue().Set(NodeArray::NewInstance(node->node_, true)); +void Node::Child(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + if (!info[1]->IsUint32()) { + Nan::ThrowTypeError("Second argument must be an integer"); + return; + } + uint32_t index = info[1]->Uint32Value(); + MarshalNode(ts_node_child(node, index)); } } -void Node::FirstChild(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode child = ts_node_child(node->node_, 0); - if (child.id) { - info.GetReturnValue().Set(Node::NewInstance(child)); +void Node::NamedChild(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + if (!info[1]->IsUint32()) { + Nan::ThrowTypeError("Second argument must be an integer"); return; } + uint32_t index = info[1]->Uint32Value(); + MarshalNode(ts_node_named_child(node, index)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::FirstNamedChild(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode child = ts_node_named_child(node->node_, 0); - if (child.id) { - info.GetReturnValue().Set(Node::NewInstance(child)); - return; - } +void Node::ChildCount(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + info.GetReturnValue().Set(Nan::New(ts_node_child_count(node))); + } +} + +void Node::NamedChildCount(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + info.GetReturnValue().Set(Nan::New(ts_node_named_child_count(node))); + } +} + +void Node::FirstChild(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_child(node, 0)); + } +} + +void Node::FirstNamedChild(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_named_child(node, 0)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::LastChild(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - uint32_t child_count = ts_node_child_count(node->node_); +void Node::LastChild(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + uint32_t child_count = ts_node_child_count(node); if (child_count > 0) { - TSNode child = ts_node_child(node->node_, child_count - 1); - info.GetReturnValue().Set(Node::NewInstance(child)); - return; + MarshalNode(ts_node_child(node, child_count - 1)); } } - info.GetReturnValue().Set(Nan::Null()); } -void Node::LastNamedChild(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - uint32_t child_count = ts_node_named_child_count(node->node_); +void Node::LastNamedChild(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + uint32_t child_count = ts_node_named_child_count(node); if (child_count > 0) { - TSNode child = ts_node_named_child(node->node_, child_count - 1); - info.GetReturnValue().Set(Node::NewInstance(child)); - return; + MarshalNode(ts_node_named_child(node, child_count - 1)); } } - info.GetReturnValue().Set(Nan::Null()); } -void Node::Parent(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode parent = ts_node_parent(node->node_); - if (parent.id) { - info.GetReturnValue().Set(Node::NewInstance(parent)); - return; - } +void Node::Parent(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_parent(node)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::NextSibling(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode sibling = ts_node_next_sibling(node->node_); - if (sibling.id) { - info.GetReturnValue().Set(Node::NewInstance(sibling)); - return; - } +void Node::NextSibling(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_next_sibling(node)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::NextNamedSibling(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode sibling = ts_node_next_named_sibling(node->node_); - if (sibling.id) { - info.GetReturnValue().Set(Node::NewInstance(sibling)); - return; - } +void Node::NextNamedSibling(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_next_named_sibling(node)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::PreviousSibling(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode sibling = ts_node_prev_sibling(node->node_); - if (sibling.id) { - info.GetReturnValue().Set(Node::NewInstance(sibling)); - return; - } +void Node::PreviousSibling(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_prev_sibling(node)); } - info.GetReturnValue().Set(Nan::Null()); } -void Node::PreviousNamedSibling(Local property, const Nan::PropertyCallbackInfo &info) { - Node *node = Unwrap(info.This()); - if (node) { - TSNode sibling = ts_node_prev_named_sibling(node->node_); - if (sibling.id) { - info.GetReturnValue().Set(Node::NewInstance(sibling)); - return; - } +void Node::PreviousNamedSibling(const Nan::FunctionCallbackInfo &info) { + TSNode node = UnmarshalNode(info[0]); + if (node.id) { + MarshalNode(ts_node_prev_named_sibling(node)); } - info.GetReturnValue().Set(Nan::Null()); } } // namespace node_tree_sitter diff --git a/src/node.h b/src/node.h index f11b3448..12802c49 100644 --- a/src/node.h +++ b/src/node.h @@ -8,15 +8,13 @@ namespace node_tree_sitter { -class Node : public Nan::ObjectWrap { +class Node { public: static void Init(v8::Local exports); - static v8::Local NewInstance(TSNode); + static void MarshalNode(TSNode); + static TSNode UnmarshalNode(const v8::Local &tree); private: - explicit Node(TSNode); - - static void New(const Nan::FunctionCallbackInfo &); static void ToString(const Nan::FunctionCallbackInfo &); static void FirstChildForIndex(const Nan::FunctionCallbackInfo &); static void FirstNamedChildForIndex(const Nan::FunctionCallbackInfo &); @@ -30,30 +28,25 @@ class Node : public Nan::ObjectWrap { static void StartPosition(const Nan::FunctionCallbackInfo &); static void EndPosition(const Nan::FunctionCallbackInfo &); - static void Type(v8::Local, const Nan::PropertyCallbackInfo &); - static void StartIndex(v8::Local, const Nan::PropertyCallbackInfo &); - static void EndIndex(v8::Local, const Nan::PropertyCallbackInfo &); - static void IsNamed(v8::Local, const Nan::PropertyCallbackInfo &); - static void Id(v8::Local, const Nan::PropertyCallbackInfo &); - - static void Parent(v8::Local, const Nan::PropertyCallbackInfo &); - static void Children(v8::Local, const Nan::PropertyCallbackInfo &); - static void NamedChildren(v8::Local, const Nan::PropertyCallbackInfo &); - static void FirstChild(v8::Local, const Nan::PropertyCallbackInfo &); - static void FirstNamedChild(v8::Local, const Nan::PropertyCallbackInfo &); - static void LastChild(v8::Local, const Nan::PropertyCallbackInfo &); - static void LastNamedChild(v8::Local, const Nan::PropertyCallbackInfo &); - static void NextSibling(v8::Local, const Nan::PropertyCallbackInfo &); - static void NextNamedSibling(v8::Local, const Nan::PropertyCallbackInfo &); - static void PreviousSibling(v8::Local, const Nan::PropertyCallbackInfo &); - static void PreviousNamedSibling(v8::Local, const Nan::PropertyCallbackInfo &); - - static Node *Unwrap(const v8::Local &); - static Node *UnwrapValid(const v8::Local &); - - TSNode node_; - - static Nan::Persistent constructor; + static void Type(const Nan::FunctionCallbackInfo &); + static void StartIndex(const Nan::FunctionCallbackInfo &); + static void EndIndex(const Nan::FunctionCallbackInfo &); + static void IsNamed(const Nan::FunctionCallbackInfo &); + static void Id(const Nan::FunctionCallbackInfo &); + + static void Parent(const Nan::FunctionCallbackInfo &); + static void Child(const Nan::FunctionCallbackInfo &); + static void ChildCount(const Nan::FunctionCallbackInfo &); + static void NamedChild(const Nan::FunctionCallbackInfo &); + static void NamedChildCount(const Nan::FunctionCallbackInfo &); + static void FirstChild(const Nan::FunctionCallbackInfo &); + static void FirstNamedChild(const Nan::FunctionCallbackInfo &); + static void LastChild(const Nan::FunctionCallbackInfo &); + static void LastNamedChild(const Nan::FunctionCallbackInfo &); + static void NextSibling(const Nan::FunctionCallbackInfo &); + static void NextNamedSibling(const Nan::FunctionCallbackInfo &); + static void PreviousSibling(const Nan::FunctionCallbackInfo &); + static void PreviousNamedSibling(const Nan::FunctionCallbackInfo &); }; } // namespace node_tree_sitter diff --git a/src/node_array.cc b/src/node_array.cc deleted file mode 100644 index 590ddee6..00000000 --- a/src/node_array.cc +++ /dev/null @@ -1,103 +0,0 @@ -#include "./node_array.h" -#include -#include -#include -#include -#include -#include "./util.h" -#include "./node.h" - -namespace node_tree_sitter { - -using namespace v8; - -Nan::Persistent NodeArray::constructor; - -void NodeArray::Init(v8::Local exports) { - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("NodeArray").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - Nan::SetIndexedPropertyHandler( - tpl->InstanceTemplate(), - GetIndex, - NULL); - - Nan::SetAccessor( - tpl->InstanceTemplate(), - Nan::New("length").ToLocalChecked(), - Length, NULL); - - Nan::SetAccessor( - tpl->InstanceTemplate(), - Nan::New("isNamed").ToLocalChecked(), - IsNamed); - - const char * array_methods[] = { - "every", - "filter", - "find", - "findIndex", - "forEach", - "indexOf", - "map", - "reduce", - "reduceRight", - "slice", - "some", - }; - - Local constructor_local = tpl->GetFunction(); - Local prototype = Local::Cast(constructor_local->Get(Nan::New("prototype").ToLocalChecked())); - - Local array = Nan::New(); - for (size_t i = 0; i < length_of_array(array_methods); i++) { - Local method_name = Nan::New(array_methods[i]).ToLocalChecked(); - prototype->Set(method_name, array->Get(method_name)); - } - - exports->Set(Nan::New("NodeArray").ToLocalChecked(), constructor_local); - constructor.Reset(Nan::Persistent(constructor_local)); -} - -NodeArray::NodeArray(TSNode node, bool is_named) : parent_node_(node), is_named_(is_named) {} - -Local NodeArray::NewInstance(TSNode node, bool is_named) { - MaybeLocal maybe_self = Nan::New(constructor)->NewInstance(Nan::GetCurrentContext()); - Local self; - if (maybe_self.ToLocal(&self)) { - (new NodeArray(node, is_named))->Wrap(self); - return self; - } else { - return Nan::Null(); - } -} - -void NodeArray::New(const Nan::FunctionCallbackInfo &info) { - info.GetReturnValue().Set(Nan::Null()); -} - -void NodeArray::GetIndex(uint32_t index, const Nan::PropertyCallbackInfo &info) { - NodeArray *array = ObjectWrap::Unwrap(info.This()); - TSNode child = array->is_named_ ? - ts_node_named_child(array->parent_node_, index) : - ts_node_child(array->parent_node_, index); - if (child.id) { - info.GetReturnValue().Set(Node::NewInstance(child)); - } -} - -void NodeArray::Length(Local property, const Nan::PropertyCallbackInfo &info) { - NodeArray *array = ObjectWrap::Unwrap(info.This()); - uint32_t length = array->is_named_ ? - ts_node_named_child_count(array->parent_node_) : - ts_node_child_count(array->parent_node_); - info.GetReturnValue().Set(Nan::New(length)); -} - -void NodeArray::IsNamed(Local property, const Nan::PropertyCallbackInfo &info) { - NodeArray *array = ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(array->is_named_); -} - -} // namespace node_tree_sitter diff --git a/src/node_array.h b/src/node_array.h deleted file mode 100644 index 35b3b55e..00000000 --- a/src/node_array.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef NODE_TREE_SITTER_NODE_ARRAY_H_ -#define NODE_TREE_SITTER_NODE_ARRAY_H_ - -#include -#include -#include -#include - -namespace node_tree_sitter { - -class NodeArray : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static v8::Local NewInstance(TSNode, bool); - - private: - explicit NodeArray(TSNode, bool); - - static void New(const Nan::FunctionCallbackInfo &); - static void Length(v8::Local, const Nan::PropertyCallbackInfo &); - static void GetIndex(uint32_t, const Nan::PropertyCallbackInfo &); - static void IsNamed(v8::Local, const Nan::PropertyCallbackInfo &); - - TSNode parent_node_; - bool is_named_; - - static Nan::Persistent constructor; -}; - -} // namespace node_tree_sitter - -#endif // NODE_TREE_SITTER_NODE_ARRAY_H_ diff --git a/src/tree.cc b/src/tree.cc index f5f96d6f..50938a26 100644 --- a/src/tree.cc +++ b/src/tree.cc @@ -22,14 +22,10 @@ void Tree::Init(Local exports) { Local class_name = Nan::New("Tree").ToLocalChecked(); tpl->SetClassName(class_name); - Nan::SetAccessor( - tpl->InstanceTemplate(), - Nan::New("rootNode").ToLocalChecked(), - RootNode); - FunctionPair methods[] = { {"edit", Edit}, {"walk", Walk}, + {"rootNode", RootNode}, {"printDotGraph", PrintDotGraph}, {"getChangedRanges", GetChangedRanges}, }; @@ -114,14 +110,9 @@ void Tree::Walk(const Nan::FunctionCallbackInfo &info) { info.GetReturnValue().Set(TreeCursor::NewInstance(cursor)); } -void Tree::RootNode(Local property, const Nan::PropertyCallbackInfo &info) { +void Tree::RootNode(const Nan::FunctionCallbackInfo &info) { Tree *tree = ObjectWrap::Unwrap(info.This()); - TSNode node = ts_tree_root_node(tree->tree_); - if (node.id) { - info.GetReturnValue().Set(Node::NewInstance(node)); - } else { - info.GetReturnValue().Set(Nan::Null()); - } + Node::MarshalNode(ts_tree_root_node(tree->tree_)); } void Tree::GetChangedRanges(const Nan::FunctionCallbackInfo &info) { diff --git a/src/tree.h b/src/tree.h index 03982e11..be261531 100644 --- a/src/tree.h +++ b/src/tree.h @@ -21,7 +21,7 @@ class Tree : public Nan::ObjectWrap { static void New(const Nan::FunctionCallbackInfo &); static void Walk(const Nan::FunctionCallbackInfo &); static void Edit(const Nan::FunctionCallbackInfo &); - static void RootNode(v8::Local, const Nan::PropertyCallbackInfo &); + static void RootNode(const Nan::FunctionCallbackInfo &); static void PrintDotGraph(const Nan::FunctionCallbackInfo &); static void GetChangedRanges(const Nan::FunctionCallbackInfo &); diff --git a/src/tree_cursor.cc b/src/tree_cursor.cc index d5e6c084..aaa0bbfd 100644 --- a/src/tree_cursor.cc +++ b/src/tree_cursor.cc @@ -2,7 +2,6 @@ #include #include #include -#include "./node_array.h" #include "./util.h" #include "./conversions.h" diff --git a/tree-sitter.d.ts b/tree-sitter.d.ts index ee60ff65..3fbc2bf5 100644 --- a/tree-sitter.d.ts +++ b/tree-sitter.d.ts @@ -29,58 +29,37 @@ declare module "tree-sitter" { read(): any; }; - export interface Node { - id: number; + export interface SyntaxNode { isNamed: boolean; type: string; startPosition: Point; endPosition: Point; - children: NodeArray; + children: Array; + namedChildren: Array; startIndex: number; endIndex: number; - parent: Node | null; - namedChildren: NodeArray; - firstChild: Node | null; - lastChild: Node | null; - firstNamedChild: Node | null; - lastNamedChild: Node | null; - nextSibling: Node | null; - nextNamedSibling: Node | null; - previousSibling: Node | null; - previousNamedSibling: Node | null; + parent: SyntaxNode | null; + firstChild: SyntaxNode | null; + lastChild: SyntaxNode | null; + firstNamedChild: SyntaxNode | null; + lastNamedChild: SyntaxNode | null; + nextSibling: SyntaxNode | null; + nextNamedSibling: SyntaxNode | null; + previousSibling: SyntaxNode | null; + previousNamedSibling: SyntaxNode | null; isValid(): boolean; hasError(): boolean; hasChanges(): boolean; toString(): string; - descendantForIndex(index: number): Node; - descendantForIndex(startIndex: number, endIndex: number): Node; - namedDescendantForIndex(index: number): Node; - namedDescendantForIndex(startIndex: number, endIndex: number): Node; - descendantForPosition(position: Point): Node; - descendantForPosition(startPosition: Point, endPosition: Point): Node; - namedDescendantForPosition(position: Point): Node; - namedDescendantForPosition(startPosition: Point, endPosition: Point): Node; - }; - - type ArrayCallback = ( - node: TItem, - index?: number, - array?: TArray - ) => TReturn; - - export interface NodeArray extends ArrayLike, Iterable { - map(callback: ArrayCallback, thisArg?: any): T[]; - every(callback: ArrayCallback, thisArg?: any): void; - filter(callback: ArrayCallback, thisArg?: any): Node[]; - find(callback: ArrayCallback, thisArg?: any): Node | undefined, - findIndex(callback: ArrayCallback, thisArg?: any): number; - forEach(callback: ArrayCallback, thisArg?: any): void; - indexOf(searchElement: Node, fromIndex?: number): number; - reduce(callback: (accumulator: T, current: Node, currentIndex?: number, array?: NodeArray) => T, initialValue?: T): T; - reduceRight(callback: (accumulator: T, current: Node, currentIndex?: number, array?: NodeArray) => T, initialValue?: T): T; - slice(begin?: number, end?: number): Node[], - some(callback: ArrayCallback, thisArg?: any): boolean, + descendantForIndex(index: number): SyntaxNode; + descendantForIndex(startIndex: number, endIndex: number): SyntaxNode; + namedDescendantForIndex(index: number): SyntaxNode; + namedDescendantForIndex(startIndex: number, endIndex: number): SyntaxNode; + descendantForPosition(position: Point): SyntaxNode; + descendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode; + namedDescendantForPosition(position: Point): SyntaxNode; + namedDescendantForPosition(startPosition: Point, endPosition: Point): SyntaxNode; }; export interface TreeCursor { @@ -97,7 +76,7 @@ declare module "tree-sitter" { }; export interface Tree { - public readonly rootNode: Node; + public readonly rootNode: SyntaxNode; public edit(delta: Edit): Document; public walk(): TreeCursor; diff --git a/vendor/tree-sitter b/vendor/tree-sitter index 69d8c6f5..f3014cb7 160000 --- a/vendor/tree-sitter +++ b/vendor/tree-sitter @@ -1 +1 @@ -Subproject commit 69d8c6f5e6d1541357d7e829b2b5a248b4ddc3e5 +Subproject commit f3014cb7678bf3b95cbe4140253858295cdaa706