OR-1 dataflow CPU sketch
1#include "./conversions.h"
2#include "./addon_data.h"
3#include "tree_sitter/api.h"
4
5#include <cmath>
6#include <napi.h>
7
8using namespace Napi;
9
10namespace node_tree_sitter {
11
12static const unsigned BYTES_PER_CHARACTER = 2;
13
14void InitConversions(Napi::Env env, Napi::Object exports) {
15 auto *data = env.GetInstanceData<AddonData>();
16
17 auto js_point_transfer_buffer = Uint32Array::New(env, 2);
18 data->point_transfer_buffer = js_point_transfer_buffer.Data();
19
20 exports["pointTransferArray"] = js_point_transfer_buffer;
21}
22
23void TransferPoint(Napi::Env env, const TSPoint &point) {
24 auto *data = env.GetInstanceData<AddonData>();
25 data->point_transfer_buffer[0] = point.row;
26 data->point_transfer_buffer[1] = point.column / 2;
27}
28
29Napi::Object RangeToJS(Napi::Env env, const TSRange &range) {
30 Object result = Object::New(env);
31 result.Set("startPosition", PointToJS(env, range.start_point));
32 result.Set("startIndex", ByteCountToJS(env, range.start_byte));
33 result.Set("endPosition", PointToJS(env, range.end_point));
34 result.Set("endIndex", ByteCountToJS(env, range.end_byte));
35 return result;
36}
37
38Napi::Maybe<TSRange> RangeFromJS(const Napi::Value& arg) {
39 Env env = arg.Env();
40 if (!arg.IsObject()) {
41 TypeError::New(env, "Range must be a {startPosition, endPosition, startIndex, endIndex} object").ThrowAsJavaScriptException();
42 return Napi::Nothing<TSRange>();
43 }
44
45 TSRange result;
46
47 auto js_range = arg.As<Object>();
48
49 #define INIT(field, key, Convert) { \
50 auto value = js_range.Get(key); \
51 if (value.IsEmpty()) { \
52 TypeError::New(env, "Range must be a {startPosition, endPosition, startIndex, endIndex} object").ThrowAsJavaScriptException(); \
53 return Napi::Nothing<TSRange>(); \
54 } \
55 auto field = Convert(value); \
56 if (field.IsJust()) { \
57 result.field = field.Unwrap(); \
58 } else { \
59 return Napi::Nothing<TSRange>(); \
60 } \
61 }
62
63 INIT(start_point, "startPosition", PointFromJS);
64 INIT(end_point, "endPosition", PointFromJS);
65 INIT(start_byte, "startIndex", ByteCountFromJS);
66 INIT(end_byte, "endIndex", ByteCountFromJS);
67
68 #undef INIT
69
70 return Napi::Just(result);
71}
72
73Napi::Object PointToJS(Napi::Env env, const TSPoint &point) {
74 Object result = Object::New(env);
75 result["row"] = Number::New(env, point.row);
76 result["column"] = ByteCountToJS(env, point.column);
77 return result;
78}
79
80Napi::Maybe<TSPoint> PointFromJS(const Napi::Value& arg) {
81 Env env = arg.Env();
82
83 if (!arg.IsObject()) {
84 TypeError::New(env, "Point must be a {row, column} object").ThrowAsJavaScriptException();
85 return Napi::Nothing<TSPoint>();
86 }
87 auto js_point = arg.As<Object>();
88
89 auto js_row = js_point.Get("row").As<Number>();
90 if (!js_row.IsNumber()) {
91 TypeError::New(env, "Point must be a {row, column} object").ThrowAsJavaScriptException();
92 return Napi::Nothing<TSPoint>();
93 }
94
95 auto js_column = js_point.Get("column").As<Number>();
96 if (!js_column.IsNumber()) {
97 TypeError::New(env, "Point must be a {row, column} object").ThrowAsJavaScriptException();
98 return Napi::Nothing<TSPoint>();
99 }
100
101 uint32_t row;
102 if (!std::isfinite(js_row.DoubleValue())) {
103 row = UINT32_MAX;
104 } else if (js_row.IsNumber()) {
105 row = js_row.Uint32Value();
106 } else {
107 TypeError::New(env, "Point.row must be a number").ThrowAsJavaScriptException();
108 return Napi::Nothing<TSPoint>();
109 }
110
111 uint32_t column;
112 if (!std::isfinite(js_column.DoubleValue())) {
113 column = UINT32_MAX;
114 } else if (js_column.IsNumber()) {
115 column = js_column.Uint32Value() * BYTES_PER_CHARACTER;
116 } else {
117 TypeError::New(env, "Point.column must be a number").ThrowAsJavaScriptException();
118 return Napi::Nothing<TSPoint>();
119 }
120
121 return Napi::Just<TSPoint>({row, column});
122}
123
124Napi::Number ByteCountToJS(Napi::Env env, uint32_t byte_count) {
125 return Number::New(env, byte_count / BYTES_PER_CHARACTER);
126}
127
128Napi::Maybe<uint32_t> ByteCountFromJS(const Napi::Value &arg) {
129 Napi::Env env = arg.Env();
130
131 if (!arg.IsNumber()) {
132 TypeError::New(env, "Character index must be a number").ThrowAsJavaScriptException();
133 return Napi::Nothing<uint32_t>();
134 }
135 auto result = arg.As<Number>();
136
137 return Napi::Just<uint32_t>(result.Uint32Value() * BYTES_PER_CHARACTER);
138}
139
140} // namespace node_tree_sitter