Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the module context aware #184

Merged
merged 5 commits into from
Feb 22, 2024
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
6 changes: 2 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ on:
- released

env:
NODE_PREBUILD_CMD: npx prebuild -t 10.0.0 -t 12.0.0 -t 14.0.0 -t 16.0.0 -t 18.0.0 -t 20.0.0 --strip -u ${{ secrets.GH_TOKEN }}
ELECTRON_PREBUILD_CMD: npx prebuild -r electron -t 3.0.0 -t 4.0.0 -t 5.0.0 -t 6.0.0 -t 7.0.0 -t 8.0.0 -t 9.0.0 -t 10.0.0 -t 11.0.0 -t 12.0.0 -t 13.0.0 -t 14.0.0 -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0 -t 19.0.0 -t 20.0.0 -t 21.0.0 -t 22.0.0 -t 23.0.0 -t 24.0.0 -t 25.0.0 --strip -u ${{ secrets.GH_TOKEN }}
NODE_PREBUILD_CMD: npx prebuild -t 14.0.0 -t 16.0.0 -t 18.0.0 -t 20.0.0 --strip -u ${{ secrets.GH_TOKEN }}
ELECTRON_PREBUILD_CMD: npx prebuild -r electron -t 12.0.0 -t 13.0.0 -t 14.0.0 -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0 -t 19.0.0 -t 20.0.0 -t 21.0.0 -t 22.0.0 -t 23.0.0 -t 24.0.0 -t 25.0.0 --strip -u ${{ secrets.GH_TOKEN }}

jobs:

Expand All @@ -25,8 +25,6 @@ jobs:
- macos-latest
- ubuntu-20.04
node:
- 10
- 12
- 14
- 16
- 18
Expand Down
59 changes: 59 additions & 0 deletions src/addon_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <nan.h>
#include <cstdlib>
#include <tree_sitter/api.h>

#ifndef NODE_TREE_SITTER_ADDON_DATA_H_
#define NODE_TREE_SITTER_ADDON_DATA_H_

namespace node_tree_sitter {

class AddonData {
public:
explicit AddonData(v8::Isolate* isolate) {
// Ensure this per-addon-instance data is deleted at environment cleanup.
node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this);
}

~AddonData() {
ts_query_cursor_delete(ts_query_cursor);
}

// conversions
Nan::Persistent<v8::String> row_key;
Nan::Persistent<v8::String> column_key;
Nan::Persistent<v8::String> start_index_key;
Nan::Persistent<v8::String> start_position_key;
Nan::Persistent<v8::String> end_index_key;
Nan::Persistent<v8::String> end_position_key;
uint32_t *point_transfer_buffer = nullptr;

// node
uint32_t *transfer_buffer = nullptr;
uint32_t transfer_buffer_length = 0;
Nan::Persistent<v8::Object> module_exports;
TSTreeCursor scratch_cursor = {nullptr, nullptr, {0, 0}};

// parser
Nan::Persistent<v8::Function> parser_constructor;

// query
TSQueryCursor *ts_query_cursor = nullptr;
Nan::Persistent<v8::Function> query_constructor;
Nan::Persistent<v8::FunctionTemplate> query_constructor_template;

// tree_cursor
Nan::Persistent<v8::Function> tree_cursor_constructor;

// tree
Nan::Persistent<v8::Function> tree_constructor;
Nan::Persistent<v8::FunctionTemplate> tree_constructor_template;

private:
static void DeleteInstance(void* data) {
delete static_cast<AddonData*>(data);
}
};

}

#endif // NODE_TREE_SITTER_ADDON_DATA_H_
23 changes: 15 additions & 8 deletions src/binding.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <node.h>
#include <v8.h>
#include "./addon_data.h"
#include "./language.h"
#include "./node.h"
#include "./parser.h"
Expand All @@ -12,16 +13,22 @@ namespace node_tree_sitter {

using namespace v8;

void InitAll(Local<Object> exports, Local<Value> m_, void* v_) {
InitConversions(exports);
node_methods::Init(exports);
void InitAll(Local<Object> exports, Local<Value> m_, Local<Context> context) {
Isolate* isolate = context->GetIsolate();

AddonData* data = new AddonData(isolate);

Local<External> data_ext = External::New(isolate, data);

InitConversions(exports, data_ext);
node_methods::Init(exports, data_ext);
language_methods::Init(exports);
Parser::Init(exports);
Query::Init(exports);
Tree::Init(exports);
TreeCursor::Init(exports);
Parser::Init(exports, data_ext);
Query::Init(exports, data_ext);
Tree::Init(exports, data_ext);
TreeCursor::Init(exports, data_ext);
}

NODE_MODULE(tree_sitter_runtime_binding, InitAll)
NODE_MODULE_CONTEXT_AWARE(tree_sitter_runtime_binding, InitAll)

} // namespace node_tree_sitter
92 changes: 39 additions & 53 deletions src/conversions.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "./node.h"
#include "./addon_data.h"
#include <nan.h>
#include <tree_sitter/api.h>
#include <v8.h>
Expand All @@ -9,54 +10,39 @@ namespace node_tree_sitter {

using namespace v8;

Nan::Persistent<String> row_key;
Nan::Persistent<String> column_key;
Nan::Persistent<String> start_index_key;
Nan::Persistent<String> start_position_key;
Nan::Persistent<String> end_index_key;
Nan::Persistent<String> end_position_key;

static unsigned BYTES_PER_CHARACTER = 2;
static uint32_t *point_transfer_buffer;

void InitConversions(Local<Object> exports) {
row_key.Reset(Nan::Persistent<String>(Nan::New("row").ToLocalChecked()));
column_key.Reset(Nan::Persistent<String>(Nan::New("column").ToLocalChecked()));
start_index_key.Reset(Nan::Persistent<String>(Nan::New("startIndex").ToLocalChecked()));
start_position_key.Reset(Nan::Persistent<String>(Nan::New("startPosition").ToLocalChecked()));
end_index_key.Reset(Nan::Persistent<String>(Nan::New("endIndex").ToLocalChecked()));
end_position_key.Reset(Nan::Persistent<String>(Nan::New("endPosition").ToLocalChecked()));

#if defined(_MSC_VER) && NODE_RUNTIME_ELECTRON && NODE_MODULE_VERSION >= 89
auto js_point_transfer_buffer = ArrayBuffer::New(Isolate::GetCurrent(), 2 * sizeof(uint32_t));
point_transfer_buffer = (uint32_t *)(js_point_transfer_buffer->Data());
#elif V8_MAJOR_VERSION < 8 || (V8_MAJOR_VERSION == 8 && V8_MINOR_VERSION < 4) || (defined(_MSC_VER) && NODE_RUNTIME_ELECTRON)
point_transfer_buffer = static_cast<uint32_t *>(malloc(2 * sizeof(uint32_t)));
auto js_point_transfer_buffer = ArrayBuffer::New(Isolate::GetCurrent(), point_transfer_buffer, 2 * sizeof(uint32_t));
#else
point_transfer_buffer = static_cast<uint32_t *>(malloc(2 * sizeof(uint32_t)));
auto backing_store = ArrayBuffer::NewBackingStore(point_transfer_buffer, 2 * sizeof(uint32_t), BackingStore::EmptyDeleter, nullptr);
auto js_point_transfer_buffer = ArrayBuffer::New(Isolate::GetCurrent(), std::move(backing_store));
#endif

Nan::Set(exports, Nan::New("pointTransferArray").ToLocalChecked(), Uint32Array::New(js_point_transfer_buffer, 0, 2));
static const unsigned BYTES_PER_CHARACTER = 2;

void InitConversions(Local<Object> exports, Local<External> data_ext) {
AddonData* data = static_cast<AddonData*>(data_ext->Value());

data->row_key.Reset(Nan::Persistent<String>(Nan::New("row").ToLocalChecked()));
data->column_key.Reset(Nan::Persistent<String>(Nan::New("column").ToLocalChecked()));
data->start_index_key.Reset(Nan::Persistent<String>(Nan::New("startIndex").ToLocalChecked()));
data->start_position_key.Reset(Nan::Persistent<String>(Nan::New("startPosition").ToLocalChecked()));
data->end_index_key.Reset(Nan::Persistent<String>(Nan::New("endIndex").ToLocalChecked()));
data->end_position_key.Reset(Nan::Persistent<String>(Nan::New("endPosition").ToLocalChecked()));

auto js_point_transfer_buffer = Nan::NewBuffer(2 * sizeof(uint32_t)).ToLocalChecked();
data->point_transfer_buffer = reinterpret_cast<uint32_t*>(node::Buffer::Data(js_point_transfer_buffer));

Nan::Set(exports, Nan::New("pointTransferArray").ToLocalChecked(), Uint32Array::New(js_point_transfer_buffer.As<Uint8Array>()->Buffer(), 0, 2));
}

void TransferPoint(const TSPoint &point) {
point_transfer_buffer[0] = point.row;
point_transfer_buffer[1] = point.column / 2;
void TransferPoint(AddonData* data, const TSPoint &point) {
data->point_transfer_buffer[0] = point.row;
data->point_transfer_buffer[1] = point.column / 2;
}

Local<Object> RangeToJS(const TSRange &range) {
Local<Object> RangeToJS(AddonData* data, const TSRange &range) {
Local<Object> result = Nan::New<Object>();
Nan::Set(result, Nan::New(start_position_key), PointToJS(range.start_point));
Nan::Set(result, Nan::New(start_index_key), ByteCountToJS(range.start_byte));
Nan::Set(result, Nan::New(end_position_key), PointToJS(range.end_point));
Nan::Set(result, Nan::New(end_index_key), ByteCountToJS(range.end_byte));
Nan::Set(result, Nan::New(data->start_position_key), PointToJS(data, range.start_point));
Nan::Set(result, Nan::New(data->start_index_key), ByteCountToJS(data, range.start_byte));
Nan::Set(result, Nan::New(data->end_position_key), PointToJS(data, range.end_point));
Nan::Set(result, Nan::New(data->end_index_key), ByteCountToJS(data, range.end_byte));
return result;
}

Nan::Maybe<TSRange> RangeFromJS(const Local<Value> &arg) {
Nan::Maybe<TSRange> RangeFromJS(AddonData* data, const Local<Value> &arg) {
if (!arg->IsObject()) {
Nan::ThrowTypeError("Range must be a {startPosition, endPosition, startIndex, endIndex} object");
return Nan::Nothing<TSRange>();
Expand All @@ -72,46 +58,46 @@ Nan::Maybe<TSRange> RangeFromJS(const Local<Value> &arg) {
Nan::ThrowTypeError("Range must be a {startPosition, endPosition, startIndex, endIndex} object"); \
return Nan::Nothing<TSRange>(); \
} \
auto field = Convert(value.ToLocalChecked()); \
auto field = Convert(data, value.ToLocalChecked()); \
if (field.IsJust()) { \
result.field = field.FromJust(); \
} else { \
return Nan::Nothing<TSRange>(); \
} \
}

INIT(start_point, start_position_key, PointFromJS);
INIT(end_point, end_position_key, PointFromJS);
INIT(start_byte, start_index_key, ByteCountFromJS);
INIT(end_byte, end_index_key, ByteCountFromJS);
INIT(start_point, data->start_position_key, PointFromJS);
INIT(end_point, data->end_position_key, PointFromJS);
INIT(start_byte, data->start_index_key, ByteCountFromJS);
INIT(end_byte, data->end_index_key, ByteCountFromJS);

#undef INIT

return Nan::Just(result);
}

Local<Object> PointToJS(const TSPoint &point) {
Local<Object> PointToJS(AddonData* data, const TSPoint &point) {
Local<Object> result = Nan::New<Object>();
Nan::Set(result, Nan::New(row_key), Nan::New<Number>(point.row));
Nan::Set(result, Nan::New(column_key), ByteCountToJS(point.column));
Nan::Set(result, Nan::New(data->row_key), Nan::New<Number>(point.row));
Nan::Set(result, Nan::New(data->column_key), ByteCountToJS(data, point.column));
return result;
}

Nan::Maybe<TSPoint> PointFromJS(const Local<Value> &arg) {
Nan::Maybe<TSPoint> PointFromJS(AddonData* data, const Local<Value> &arg) {
Local<Object> js_point;
if (!arg->IsObject() || !Nan::To<Object>(arg).ToLocal(&js_point)) {
Nan::ThrowTypeError("Point must be a {row, column} object");
return Nan::Nothing<TSPoint>();
}

Local<Value> js_row;
if (!Nan::Get(js_point, Nan::New(row_key)).ToLocal(&js_row)) {
if (!Nan::Get(js_point, Nan::New(data->row_key)).ToLocal(&js_row)) {
Nan::ThrowTypeError("Point must be a {row, column} object");
return Nan::Nothing<TSPoint>();
}

Local<Value> js_column;
if (!Nan::Get(js_point, Nan::New(column_key)).ToLocal(&js_column)) {
if (!Nan::Get(js_point, Nan::New(data->column_key)).ToLocal(&js_column)) {
Nan::ThrowTypeError("Point must be a {row, column} object");
return Nan::Nothing<TSPoint>();
}
Expand Down Expand Up @@ -139,11 +125,11 @@ Nan::Maybe<TSPoint> PointFromJS(const Local<Value> &arg) {
return Nan::Just<TSPoint>({row, column});
}

Local<Number> ByteCountToJS(uint32_t byte_count) {
Local<Number> ByteCountToJS(AddonData* data, uint32_t byte_count) {
return Nan::New<Number>(byte_count / BYTES_PER_CHARACTER);
}

Nan::Maybe<uint32_t> ByteCountFromJS(const v8::Local<v8::Value> &arg) {
Nan::Maybe<uint32_t> ByteCountFromJS(AddonData* data, const v8::Local<v8::Value> &arg) {
auto result = Nan::To<uint32_t>(arg);
if (!arg->IsNumber()) {
Nan::ThrowTypeError("Character index must be a number");
Expand Down
22 changes: 9 additions & 13 deletions src/conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,18 @@
#include <nan.h>
#include <v8.h>
#include <tree_sitter/api.h>
#include "./addon_data.h"

namespace node_tree_sitter {

void InitConversions(v8::Local<v8::Object> exports);
v8::Local<v8::Object> RangeToJS(const TSRange &);
v8::Local<v8::Object> PointToJS(const TSPoint &);
void TransferPoint(const TSPoint &);
v8::Local<v8::Number> ByteCountToJS(uint32_t);
Nan::Maybe<TSPoint> PointFromJS(const v8::Local<v8::Value> &);
Nan::Maybe<uint32_t> ByteCountFromJS(const v8::Local<v8::Value> &);
Nan::Maybe<TSRange> RangeFromJS(const v8::Local<v8::Value> &);

extern Nan::Persistent<v8::String> row_key;
extern Nan::Persistent<v8::String> column_key;
extern Nan::Persistent<v8::String> start_key;
extern Nan::Persistent<v8::String> end_key;
void InitConversions(v8::Local<v8::Object> exports, v8::Local<v8::External> data_ext);
v8::Local<v8::Object> RangeToJS(AddonData* data, const TSRange &);
v8::Local<v8::Object> PointToJS(AddonData* data, const TSPoint &);
void TransferPoint(AddonData* data, const TSPoint &);
v8::Local<v8::Number> ByteCountToJS(AddonData* data, uint32_t);
Nan::Maybe<TSPoint> PointFromJS(AddonData* data, const v8::Local<v8::Value> &);
Nan::Maybe<uint32_t> ByteCountFromJS(AddonData* data, const v8::Local<v8::Value> &);
Nan::Maybe<TSRange> RangeFromJS(AddonData* data, const v8::Local<v8::Value> &);

} // namespace node_tree_sitter

Expand Down
Loading
Loading