OR-1 dataflow CPU sketch
at main 397 lines 14 kB view raw
1#include "./query.h" 2#include "./language.h" 3#include "./node.h" 4 5#include <napi.h> 6#include <string> 7#include <vector> 8 9using std::vector; 10using namespace Napi; 11 12namespace node_tree_sitter { 13 14/* 15 tstag() { 16 b2sum -l64 <(printf tree-sitter) <(printf "$1") | \ 17 awk '{printf "0x" toupper($1) (NR == 1 ? ", " : "\n")}' 18 } 19 tstag query # => 0x8AF2E5212AD58ABF, 0x7B1FAB666CBD6803 20*/ 21const napi_type_tag QUERY_TYPE_TAG = { 22 0x8AF2E5212AD58ABF, 0x7B1FAB666CBD6803 23}; 24 25const char *query_error_names[] = { 26 "TSQueryErrorNone", 27 "TSQueryErrorSyntax", 28 "TSQueryErrorNodeType", 29 "TSQueryErrorField", 30 "TSQueryErrorCapture", 31 "TSQueryErrorStructure", 32}; 33 34void Query::Init(Napi::Env env, Napi::Object exports) { 35 auto *data = env.GetInstanceData<AddonData>(); 36 data->ts_query_cursor = ts_query_cursor_new(); 37 38 Function ctor = DefineClass(env, "Query", { 39 InstanceAccessor("matchLimit", &Query::MatchLimit, nullptr, napi_default_method), 40 41 InstanceMethod("_matches", &Query::Matches, napi_default_method), 42 InstanceMethod("_captures", &Query::Captures, napi_default_method), 43 InstanceMethod("_getPredicates", &Query::GetPredicates, napi_default_method), 44 InstanceMethod("disableCapture", &Query::DisableCapture, napi_default_method), 45 InstanceMethod("disablePattern", &Query::DisablePattern, napi_default_method), 46 InstanceMethod("isPatternGuaranteedAtStep", &Query::IsPatternGuaranteedAtStep, napi_default_method), 47 InstanceMethod("isPatternRooted", &Query::IsPatternRooted, napi_default_method), 48 InstanceMethod("isPatternNonLocal", &Query::IsPatternNonLocal, napi_default_method), 49 InstanceMethod("startIndexForPattern", &Query::StartIndexForPattern, napi_default_method), 50 InstanceMethod("endIndexForPattern", &Query::EndIndexForPattern, napi_default_method), 51 InstanceMethod("didExceedMatchLimit", &Query::DidExceedMatchLimit, napi_default_method), 52 }); 53 54 data->query_constructor = Napi::Persistent(ctor); 55 exports["Query"] = ctor; 56} 57 58Query::Query(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Query>(info) , query_(nullptr) { 59 Napi::Env env = info.Env(); 60 61 Value().TypeTag(&QUERY_TYPE_TAG); 62 63 const TSLanguage *language = language_methods::UnwrapLanguage(info[0]); 64 const char *source; 65 uint32_t source_len; 66 uint32_t error_offset = 0; 67 TSQueryError error_type = TSQueryErrorNone; 68 69 if (language == nullptr) { 70 throw Error::New(env, "Missing language argument"); 71 } 72 73 if (info[1].IsString()) { 74 auto string = info[1].As<String>(); 75 std::string utf8_string = string.Utf8Value(); 76 source = utf8_string.data(); 77 source_len = utf8_string.length(); 78 query_ = ts_query_new(language, source, source_len, &error_offset, &error_type); 79 } else if (info[1].IsBuffer()) { 80 auto buf = info[1].As<Buffer<char>>(); 81 source = buf.Data(); 82 source_len = buf.Length(); 83 query_ = ts_query_new(language, source, source_len, &error_offset, &error_type); 84 } 85 else { 86 throw Error::New(env, "Missing source argument"); 87 } 88 89 if (error_offset > 0) { 90 const char *error_name = query_error_names[error_type]; 91 std::string message = "Query error of type "; 92 message += error_name; 93 message += " at position "; 94 message += std::to_string(error_offset); 95 throw Error::New(env, message.c_str()); 96 } 97 98 info.This().As<Napi::Object>().Get("_init").As<Napi::Function>().Call(info.This(), {}); 99} 100 101Query::~Query() { 102 ts_query_delete(query_); 103} 104 105Query *Query::UnwrapQuery(const Napi::Value &value) { 106 if (!value.IsObject()) { 107 return nullptr; 108 } 109 auto js_query = value.As<Object>(); 110 if (!js_query.CheckTypeTag(&QUERY_TYPE_TAG)) { 111 return nullptr; 112 } 113 return Query::Unwrap(js_query); 114} 115 116Napi::Value Query::GetPredicates(const Napi::CallbackInfo &info) { 117 Napi::Env env = info.Env(); 118 Query *query = Query::UnwrapQuery(info.This()); 119 auto *ts_query = query->query_; 120 121 auto pattern_len = ts_query_pattern_count(ts_query); 122 123 Array js_predicates = Array::New(env); 124 125 for (size_t pattern_index = 0; pattern_index < pattern_len; pattern_index++) { 126 uint32_t predicates_len; 127 const TSQueryPredicateStep *predicates = ts_query_predicates_for_pattern( 128 ts_query, pattern_index, &predicates_len); 129 130 Array js_pattern_predicates = Array::New(env); 131 132 if (predicates_len > 0) { 133 Array js_predicate = Array::New(env); 134 135 size_t a_index = 0; 136 size_t p_index = 0; 137 for (size_t i = 0; i < predicates_len; i++) { 138 const TSQueryPredicateStep predicate = predicates[i]; 139 uint32_t len; 140 switch (predicate.type) { 141 case TSQueryPredicateStepTypeCapture: 142 js_predicate[p_index++] = Number::New(env, TSQueryPredicateStepTypeCapture); 143 js_predicate[p_index++] = String::New(env, 144 ts_query_capture_name_for_id(ts_query, predicate.value_id, &len) 145 ); 146 break; 147 case TSQueryPredicateStepTypeString: 148 js_predicate[p_index++] = Number::New(env, TSQueryPredicateStepTypeString); 149 js_predicate[p_index++] = String::New(env, 150 ts_query_string_value_for_id(ts_query, predicate.value_id, &len) 151 ); 152 break; 153 case TSQueryPredicateStepTypeDone: 154 js_pattern_predicates[a_index++] = js_predicate; 155 js_predicate = Array::New(env); 156 p_index = 0; 157 break; 158 } 159 } 160 } 161 162 js_predicates[pattern_index] = js_pattern_predicates; 163 } 164 165 return js_predicates; 166} 167 168Napi::Value Query::Matches(const Napi::CallbackInfo &info) { 169 Napi::Env env = info.Env(); 170 auto *data = env.GetInstanceData<AddonData>(); 171 Query *query = Query::UnwrapQuery(info.This()); 172 const Tree *tree = Tree::UnwrapTree(info[0]); 173 174 uint32_t start_row = 0, start_column = 0, end_row = 0, end_column = 0, start_index = 0, end_index = 0, 175 match_limit = UINT32_MAX, max_start_depth = UINT32_MAX, timeout_micros = 0; 176 177 if (info.Length() > 1 && info[1].IsNumber()) { 178 start_row = info[1].As<Number>().Uint32Value(); 179 } 180 if (info.Length() > 2 && info[2].IsNumber()) { 181 start_column = info[2].As<Number>().Uint32Value() << 1; 182 } 183 if (info.Length() > 3 && info[3].IsNumber()) { 184 end_row = info[3].As<Number>().Uint32Value(); 185 } 186 if (info.Length() > 4 && info[4].IsNumber()) { 187 end_column = info[4].As<Number>().Uint32Value() << 1; 188 } 189 if (info.Length() > 5 && info[5].IsNumber()) { 190 start_index = info[5].As<Number>().Uint32Value(); 191 } 192 if (info.Length() > 6 && info[6].IsNumber()) { 193 end_index = info[6].As<Number>().Uint32Value() << 1; 194 } 195 if (info.Length() > 7 && info[7].IsNumber()) { 196 match_limit = info[7].As<Number>().Uint32Value(); 197 } 198 if (info.Length() > 8 && info[8].IsNumber()) { 199 max_start_depth = info[8].As<Number>().Uint32Value(); 200 } 201 if (info.Length() > 9 && info[9].IsNumber()) { 202 timeout_micros = info[9].As<Number>().Uint32Value(); 203 } 204 205 if (query == nullptr) { 206 throw Error::New(env, "Missing argument query"); 207 } 208 209 if (tree == nullptr) { 210 throw Error::New(env, "Missing argument tree"); 211 } 212 213 TSQuery *ts_query = query->query_; 214 TSNode root_node = node_methods::UnmarshalNode(env, tree); 215 TSPoint start_point = {start_row, start_column}; 216 TSPoint end_point = {end_row, end_column}; 217 ts_query_cursor_set_point_range(data->ts_query_cursor, start_point, end_point); 218 ts_query_cursor_set_byte_range(data->ts_query_cursor, start_index, end_index); 219 ts_query_cursor_set_match_limit(data->ts_query_cursor, match_limit); 220 ts_query_cursor_set_max_start_depth(data->ts_query_cursor, max_start_depth); 221 ts_query_cursor_set_timeout_micros(data->ts_query_cursor, timeout_micros); 222 ts_query_cursor_exec(data->ts_query_cursor, ts_query, root_node); 223 224 Array js_matches = Array::New(env); 225 unsigned index = 0; 226 vector<TSNode> nodes; 227 TSQueryMatch match; 228 229 while (ts_query_cursor_next_match(data->ts_query_cursor, &match)) { 230 js_matches[index++] = Number::New(env, match.pattern_index); 231 232 for (uint16_t i = 0; i < match.capture_count; i++) { 233 const TSQueryCapture &capture = match.captures[i]; 234 235 uint32_t capture_name_len = 0; 236 const char *capture_name = ts_query_capture_name_for_id( 237 ts_query, capture.index, &capture_name_len); 238 239 TSNode node = capture.node; 240 nodes.push_back(node); 241 242 String js_capture = String::New(env, capture_name);; 243 js_matches[index++] = js_capture; 244 } 245 } 246 247 auto js_nodes = node_methods::GetMarshalNodes(info, tree, nodes.data(), nodes.size()); 248 249 auto result = Array::New(env); 250 result[0U] = js_matches; 251 result[1] = js_nodes; 252 return result; 253} 254 255Napi::Value Query::Captures(const Napi::CallbackInfo &info) { 256 Napi::Env env = info.Env(); 257 auto *data = env.GetInstanceData<AddonData>(); 258 Query *query = Query::UnwrapQuery(info.This()); 259 const Tree *tree = Tree::UnwrapTree(info[0]); 260 261 uint32_t start_row = 0, start_column = 0, end_row = 0, end_column = 0, start_index = 0, end_index = 0, 262 match_limit = UINT32_MAX, max_start_depth = UINT32_MAX, timeout_micros = 0; 263 264 if (info.Length() > 1 && info[1].IsNumber()) { 265 start_row = info[1].As<Number>().Uint32Value(); 266 } 267 if (info.Length() > 2 && info[2].IsNumber()) { 268 start_column = info[2].As<Number>().Uint32Value() << 1; 269 } 270 if (info.Length() > 3 && info[3].IsNumber()) { 271 end_row = info[3].As<Number>().Uint32Value(); 272 } 273 if (info.Length() > 4 && info[4].IsNumber()) { 274 end_column = info[4].As<Number>().Uint32Value() << 1; 275 } 276 if (info.Length() > 5 && info[5].IsNumber()) { 277 start_index = info[5].As<Number>().Uint32Value(); 278 } 279 if (info.Length() > 6 && info[6].IsNumber()) { 280 end_index = info[6].As<Number>().Uint32Value() << 1; 281 } 282 if (info.Length() > 7 && info[7].IsNumber()) { 283 match_limit = info[7].As<Number>().Uint32Value(); 284 } 285 if (info.Length() > 8 && info[8].IsNumber()) { 286 max_start_depth = info[8].As<Number>().Uint32Value(); 287 } 288 if (info.Length() > 9 && info[9].IsNumber()) { 289 timeout_micros = info[9].As<Number>().Uint32Value(); 290 } 291 292 if (query == nullptr) { 293 throw Error::New(env, "Missing argument query"); 294 } 295 296 if (tree == nullptr) { 297 throw Error::New(env, "Missing argument tree"); 298 } 299 300 TSQuery *ts_query = query->query_; 301 TSNode root_node = node_methods::UnmarshalNode(env, tree); 302 TSPoint start_point = {start_row, start_column}; 303 TSPoint end_point = {end_row, end_column}; 304 ts_query_cursor_set_point_range(data->ts_query_cursor, start_point, end_point); 305 ts_query_cursor_set_byte_range(data->ts_query_cursor, start_index, end_index); 306 ts_query_cursor_set_match_limit(data->ts_query_cursor, match_limit); 307 ts_query_cursor_set_max_start_depth(data->ts_query_cursor, max_start_depth); 308 ts_query_cursor_set_timeout_micros(data->ts_query_cursor, timeout_micros); 309 ts_query_cursor_exec(data->ts_query_cursor, ts_query, root_node); 310 311 Array js_matches = Array::New(env); 312 unsigned index = 0; 313 vector<TSNode> nodes; 314 TSQueryMatch match; 315 uint32_t capture_index; 316 317 while (ts_query_cursor_next_capture( 318 data->ts_query_cursor, 319 &match, 320 &capture_index 321 )) { 322 323 js_matches[index++] = Number::New(env, match.pattern_index); 324 js_matches[index++] = Number::New(env, capture_index); 325 326 for (uint16_t i = 0; i < match.capture_count; i++) { 327 const TSQueryCapture &capture = match.captures[i]; 328 329 uint32_t capture_name_len = 0; 330 const char *capture_name = ts_query_capture_name_for_id( 331 ts_query, capture.index, &capture_name_len); 332 333 TSNode node = capture.node; 334 nodes.push_back(node); 335 336 String js_capture = String::New(env, capture_name);; 337 js_matches[index++] = js_capture; 338 } 339 } 340 341 auto js_nodes = node_methods::GetMarshalNodes(info, tree, nodes.data(), nodes.size()); 342 343 auto result = Array::New(env); 344 result[0U] = js_matches; 345 result[1] = js_nodes; 346 return result; 347} 348 349Napi::Value Query::DisableCapture(const Napi::CallbackInfo &info) { 350 std::string string = info[0].As<String>().Utf8Value(); 351 const char *capture_name = string.c_str(); 352 ts_query_disable_capture(query_, capture_name, string.length()); 353 return info.Env().Undefined(); 354} 355 356Napi::Value Query::DisablePattern(const Napi::CallbackInfo &info) { 357 uint32_t pattern_index = info[0].As<Number>().Uint32Value(); 358 ts_query_disable_pattern(query_, pattern_index); 359 return info.Env().Undefined(); 360} 361 362Napi::Value Query::IsPatternGuaranteedAtStep(const Napi::CallbackInfo &info) { 363 uint32_t byte_offset = info[0].As<Number>().Uint32Value(); 364 return Boolean::New(info.Env(), ts_query_is_pattern_guaranteed_at_step(query_, byte_offset)); 365} 366 367Napi::Value Query::IsPatternRooted(const Napi::CallbackInfo &info) { 368 uint32_t pattern_index = info[0].As<Number>().Uint32Value(); 369 return Boolean::New(info.Env(), ts_query_is_pattern_rooted(query_, pattern_index)); 370} 371 372Napi::Value Query::IsPatternNonLocal(const Napi::CallbackInfo &info) { 373 uint32_t pattern_index = info[0].As<Number>().Uint32Value(); 374 return Boolean::New(info.Env(), ts_query_is_pattern_non_local(query_, pattern_index)); 375} 376 377Napi::Value Query::StartIndexForPattern(const Napi::CallbackInfo &info) { 378 uint32_t pattern_index = info[0].As<Number>().Uint32Value(); 379 return Number::New(info.Env(), ts_query_start_byte_for_pattern(query_, pattern_index)); 380} 381 382Napi::Value Query::EndIndexForPattern(const Napi::CallbackInfo &info) { 383 uint32_t pattern_index = info[0].As<Number>().Uint32Value(); 384 return Number::New(info.Env(), ts_query_end_byte_for_pattern(query_, pattern_index)); 385} 386 387Napi::Value Query::DidExceedMatchLimit(const Napi::CallbackInfo &info) { 388 auto *data = info.Env().GetInstanceData<AddonData>(); 389 return Boolean::New(info.Env(), ts_query_cursor_did_exceed_match_limit(data->ts_query_cursor)); 390} 391 392Napi::Value Query::MatchLimit(const Napi::CallbackInfo &info) { 393 auto *data = info.Env().GetInstanceData<AddonData>(); 394 return Number::New(info.Env(), ts_query_cursor_match_limit(data->ts_query_cursor)); 395} 396 397} // namespace node_tree_sitter