Rizin
unix-like reverse engineering framework and cli tools
stack.c
Go to the documentation of this file.
1 #include "./alloc.h"
2 #include "./language.h"
3 #include "./subtree.h"
4 #include "./array.h"
5 #include "./stack.h"
6 #include "./length.h"
7 #include <assert.h>
8 #include <stdio.h>
9 
10 #define MAX_LINK_COUNT 8
11 #define MAX_NODE_POOL_SIZE 50
12 #define MAX_ITERATOR_COUNT 64
13 
14 #if defined _WIN32 && !defined __GNUC__
15 #define inline __forceinline
16 #else
17 #define inline static inline __attribute__((always_inline))
18 #endif
19 
20 typedef struct StackNode StackNode;
21 
22 typedef struct {
25  bool is_pending;
26 } StackLink;
27 
28 struct StackNode {
32  short unsigned int link_count;
34  unsigned error_cost;
35  unsigned node_count;
37 };
38 
39 typedef struct {
41  SubtreeArray subtrees;
43  bool is_pending;
45 
46 typedef Array(StackNode *) StackNodeArray;
47 
48 typedef enum {
49  StackStatusActive,
50  StackStatusPaused,
51  StackStatusHalted,
53 
54 typedef struct {
56  StackSummary *summary;
61 } StackHead;
62 
63 struct Stack {
64  Array(StackHead) heads;
65  StackSliceArray slices;
66  Array(StackIterator) iterators;
67  StackNodeArray node_pool;
68  StackNode *base_node;
69  SubtreePool *subtree_pool;
70 };
71 
72 typedef unsigned StackAction;
73 enum {
77 };
78 
79 typedef StackAction (*StackCallback)(void *, const StackIterator *);
80 
81 static void stack_node_retain(StackNode *self) {
82  if (!self)
83  return;
84  assert(self->ref_count > 0);
85  self->ref_count++;
86  assert(self->ref_count != 0);
87 }
88 
89 static void stack_node_release(
90  StackNode *self,
91  StackNodeArray *pool,
92  SubtreePool *subtree_pool
93 ) {
94 recur:
95  assert(self->ref_count != 0);
96  self->ref_count--;
97  if (self->ref_count > 0) return;
98 
99  StackNode *first_predecessor = NULL;
100  if (self->link_count > 0) {
101  for (unsigned i = self->link_count - 1; i > 0; i--) {
102  StackLink link = self->links[i];
103  if (link.subtree.ptr) ts_subtree_release(subtree_pool, link.subtree);
104  stack_node_release(link.node, pool, subtree_pool);
105  }
106  StackLink link = self->links[0];
107  if (link.subtree.ptr) ts_subtree_release(subtree_pool, link.subtree);
108  first_predecessor = self->links[0].node;
109  }
110 
111  if (pool->size < MAX_NODE_POOL_SIZE) {
112  array_push(pool, self);
113  } else {
114  ts_free(self);
115  }
116 
117  if (first_predecessor) {
118  self = first_predecessor;
119  goto recur;
120  }
121 }
122 
124  StackNode *previous_node,
125  Subtree subtree,
126  bool is_pending,
128  StackNodeArray *pool
129 ) {
130  StackNode *node = pool->size > 0
131  ? array_pop(pool)
132  : ts_malloc(sizeof(StackNode));
133  *node = (StackNode) {
134  .ref_count = 1,
135  .link_count = 0,
136  .state = state
137  };
138 
139  if (previous_node) {
140  node->link_count = 1;
141  node->links[0] = (StackLink) {
142  .node = previous_node,
143  .subtree = subtree,
144  .is_pending = is_pending,
145  };
146 
147  node->position = previous_node->position;
148  node->error_cost = previous_node->error_cost;
149  node->dynamic_precedence = previous_node->dynamic_precedence;
150  node->node_count = previous_node->node_count;
151 
152  if (subtree.ptr) {
153  node->error_cost += ts_subtree_error_cost(subtree);
154  node->position = length_add(node->position, ts_subtree_total_size(subtree));
155  node->node_count += ts_subtree_node_count(subtree);
157  }
158  } else {
159  node->position = length_zero();
160  node->error_cost = 0;
161  }
162 
163  return node;
164 }
165 
166 static bool stack__subtree_is_equivalent(Subtree left, Subtree right) {
167  if (left.ptr == right.ptr) return true;
168  if (!left.ptr || !right.ptr) return false;
169 
170  // Symbols must match
171  if (ts_subtree_symbol(left) != ts_subtree_symbol(right)) return false;
172 
173  // If both have errors, don't bother keeping both.
174  if (ts_subtree_error_cost(left) > 0 && ts_subtree_error_cost(right) > 0) return true;
175 
176  return (
178  ts_subtree_size(left).bytes == ts_subtree_size(right).bytes &&
180  ts_subtree_extra(left) == ts_subtree_extra(right) &&
182  );
183 }
184 
186  StackNode *self,
187  StackLink link,
188  SubtreePool *subtree_pool
189 ) {
190  if (link.node == self) return;
191 
192  for (int i = 0; i < self->link_count; i++) {
193  StackLink *existing_link = &self->links[i];
194  if (stack__subtree_is_equivalent(existing_link->subtree, link.subtree)) {
195  // In general, we preserve ambiguities until they are removed from the stack
196  // during a pop operation where multiple paths lead to the same node. But in
197  // the special case where two links directly connect the same pair of nodes,
198  // we can safely remove the ambiguity ahead of time without changing behavior.
199  if (existing_link->node == link.node) {
200  if (
202  ts_subtree_dynamic_precedence(existing_link->subtree)
203  ) {
204  ts_subtree_retain(link.subtree);
205  ts_subtree_release(subtree_pool, existing_link->subtree);
206  existing_link->subtree = link.subtree;
207  self->dynamic_precedence =
208  link.node->dynamic_precedence + ts_subtree_dynamic_precedence(link.subtree);
209  }
210  return;
211  }
212 
213  // If the previous nodes are mergeable, merge them recursively.
214  if (
215  existing_link->node->state == link.node->state &&
216  existing_link->node->position.bytes == link.node->position.bytes
217  ) {
218  for (int j = 0; j < link.node->link_count; j++) {
219  stack_node_add_link(existing_link->node, link.node->links[j], subtree_pool);
220  }
221  int32_t dynamic_precedence = link.node->dynamic_precedence;
222  if (link.subtree.ptr) {
223  dynamic_precedence += ts_subtree_dynamic_precedence(link.subtree);
224  }
225  if (dynamic_precedence > self->dynamic_precedence) {
226  self->dynamic_precedence = dynamic_precedence;
227  }
228  return;
229  }
230  }
231  }
232 
233  if (self->link_count == MAX_LINK_COUNT) return;
234 
235  stack_node_retain(link.node);
236  unsigned node_count = link.node->node_count;
237  int dynamic_precedence = link.node->dynamic_precedence;
238  self->links[self->link_count++] = link;
239 
240  if (link.subtree.ptr) {
241  ts_subtree_retain(link.subtree);
242  node_count += ts_subtree_node_count(link.subtree);
243  dynamic_precedence += ts_subtree_dynamic_precedence(link.subtree);
244  }
245 
246  if (node_count > self->node_count) self->node_count = node_count;
247  if (dynamic_precedence > self->dynamic_precedence) self->dynamic_precedence = dynamic_precedence;
248 }
249 
250 static void stack_head_delete(
251  StackHead *self,
252  StackNodeArray *pool,
253  SubtreePool *subtree_pool
254 ) {
255  if (self->node) {
256  if (self->last_external_token.ptr) {
257  ts_subtree_release(subtree_pool, self->last_external_token);
258  }
259  if (self->lookahead_when_paused.ptr) {
260  ts_subtree_release(subtree_pool, self->lookahead_when_paused);
261  }
262  if (self->summary) {
263  array_delete(self->summary);
264  ts_free(self->summary);
265  }
266  stack_node_release(self->node, pool, subtree_pool);
267  }
268 }
269 
271  Stack *self,
272  StackVersion original_version,
273  StackNode *node
274 ) {
275  StackHead head = {
276  .node = node,
277  .node_count_at_last_error = self->heads.contents[original_version].node_count_at_last_error,
278  .last_external_token = self->heads.contents[original_version].last_external_token,
279  .status = StackStatusActive,
280  .lookahead_when_paused = NULL_SUBTREE,
281  };
282  array_push(&self->heads, head);
283  stack_node_retain(node);
284  if (head.last_external_token.ptr) ts_subtree_retain(head.last_external_token);
285  return (StackVersion)(self->heads.size - 1);
286 }
287 
289  Stack *self,
290  StackVersion original_version,
291  StackNode *node,
292  SubtreeArray *subtrees
293 ) {
294  for (uint32_t i = self->slices.size - 1; i + 1 > 0; i--) {
295  StackVersion version = self->slices.contents[i].version;
296  if (self->heads.contents[version].node == node) {
297  StackSlice slice = {*subtrees, version};
298  array_insert(&self->slices, i + 1, slice);
299  return;
300  }
301  }
302 
303  StackVersion version = ts_stack__add_version(self, original_version, node);
304  StackSlice slice = { *subtrees, version };
305  array_push(&self->slices, slice);
306 }
307 
308 inline StackSliceArray stack__iter(
309  Stack *self,
311  StackCallback callback,
312  void *payload,
313  int goal_subtree_count
314 ) {
315  array_clear(&self->slices);
316  array_clear(&self->iterators);
317 
318  StackHead *head = array_get(&self->heads, version);
320  .node = head->node,
321  .subtrees = array_new(),
322  .subtree_count = 0,
323  .is_pending = true,
324  };
325 
326  bool include_subtrees = false;
327  if (goal_subtree_count >= 0) {
328  include_subtrees = true;
329  array_reserve(&iterator.subtrees, ts_subtree_alloc_size(goal_subtree_count) / sizeof(Subtree));
330  }
331 
332  array_push(&self->iterators, iterator);
333 
334  while (self->iterators.size > 0) {
335  for (uint32_t i = 0, size = self->iterators.size; i < size; i++) {
336  StackIterator *iterator = &self->iterators.contents[i];
337  StackNode *node = iterator->node;
338 
339  StackAction action = callback(payload, iterator);
340  bool should_pop = action & StackActionPop;
341  bool should_stop = action & StackActionStop || node->link_count == 0;
342 
343  if (should_pop) {
344  SubtreeArray subtrees = iterator->subtrees;
345  if (!should_stop) {
346  ts_subtree_array_copy(subtrees, &subtrees);
347  }
348  ts_subtree_array_reverse(&subtrees);
350  self,
351  version,
352  node,
353  &subtrees
354  );
355  }
356 
357  if (should_stop) {
358  if (!should_pop) {
359  ts_subtree_array_delete(self->subtree_pool, &iterator->subtrees);
360  }
361  array_erase(&self->iterators, i);
362  i--, size--;
363  continue;
364  }
365 
366  for (uint32_t j = 1; j <= node->link_count; j++) {
367  StackIterator *next_iterator;
368  StackLink link;
369  if (j == node->link_count) {
370  link = node->links[0];
371  next_iterator = &self->iterators.contents[i];
372  } else {
373  if (self->iterators.size >= MAX_ITERATOR_COUNT) continue;
374  link = node->links[j];
375  StackIterator current_iterator = self->iterators.contents[i];
376  array_push(&self->iterators, current_iterator);
377  next_iterator = array_back(&self->iterators);
378  ts_subtree_array_copy(next_iterator->subtrees, &next_iterator->subtrees);
379  }
380 
381  next_iterator->node = link.node;
382  if (link.subtree.ptr) {
383  if (include_subtrees) {
384  array_push(&next_iterator->subtrees, link.subtree);
385  ts_subtree_retain(link.subtree);
386  }
387 
388  if (!ts_subtree_extra(link.subtree)) {
389  next_iterator->subtree_count++;
390  if (!link.is_pending) {
391  next_iterator->is_pending = false;
392  }
393  }
394  } else {
395  next_iterator->subtree_count++;
396  next_iterator->is_pending = false;
397  }
398  }
399  }
400  }
401 
402  return self->slices;
403 }
404 
405 Stack *ts_stack_new(SubtreePool *subtree_pool) {
406  Stack *self = ts_calloc(1, sizeof(Stack));
407 
408  array_init(&self->heads);
409  array_init(&self->slices);
410  array_init(&self->iterators);
411  array_init(&self->node_pool);
412  array_reserve(&self->heads, 4);
413  array_reserve(&self->slices, 4);
414  array_reserve(&self->iterators, 4);
415  array_reserve(&self->node_pool, MAX_NODE_POOL_SIZE);
416 
417  self->subtree_pool = subtree_pool;
418  self->base_node = stack_node_new(NULL, NULL_SUBTREE, false, 1, &self->node_pool);
419  ts_stack_clear(self);
420 
421  return self;
422 }
423 
424 void ts_stack_delete(Stack *self) {
425  if (self->slices.contents)
426  array_delete(&self->slices);
427  if (self->iterators.contents)
428  array_delete(&self->iterators);
429  stack_node_release(self->base_node, &self->node_pool, self->subtree_pool);
430  for (uint32_t i = 0; i < self->heads.size; i++) {
431  stack_head_delete(&self->heads.contents[i], &self->node_pool, self->subtree_pool);
432  }
433  array_clear(&self->heads);
434  if (self->node_pool.contents) {
435  for (uint32_t i = 0; i < self->node_pool.size; i++)
436  ts_free(self->node_pool.contents[i]);
437  array_delete(&self->node_pool);
438  }
439  array_delete(&self->heads);
440  ts_free(self);
441 }
442 
444  return self->heads.size;
445 }
446 
448  return array_get(&self->heads, version)->node->state;
449 }
450 
452  return array_get(&self->heads, version)->node->position;
453 }
454 
456  return array_get(&self->heads, version)->last_external_token;
457 }
458 
460  StackHead *head = array_get(&self->heads, version);
461  if (token.ptr) ts_subtree_retain(token);
462  if (head->last_external_token.ptr) ts_subtree_release(self->subtree_pool, head->last_external_token);
463  head->last_external_token = token;
464 }
465 
467  StackHead *head = array_get(&self->heads, version);
468  unsigned result = head->node->error_cost;
469  if (
470  head->status == StackStatusPaused ||
471  (head->node->state == ERROR_STATE && !head->node->links[0].subtree.ptr)) {
472  result += ERROR_COST_PER_RECOVERY;
473  }
474  return result;
475 }
476 
478  StackHead *head = array_get(&self->heads, version);
479  if (head->node->node_count < head->node_count_at_last_error) {
480  head->node_count_at_last_error = head->node->node_count;
481  }
482  return head->node->node_count - head->node_count_at_last_error;
483 }
484 
486  Stack *self,
488  Subtree subtree,
489  bool pending,
491 ) {
492  StackHead *head = array_get(&self->heads, version);
493  StackNode *new_node = stack_node_new(head->node, subtree, pending, state, &self->node_pool);
494  if (!subtree.ptr) head->node_count_at_last_error = new_node->node_count;
495  head->node = new_node;
496 }
497 
498 inline StackAction pop_count_callback(void *payload, const StackIterator *iterator) {
499  unsigned *goal_subtree_count = payload;
500  if (iterator->subtree_count == *goal_subtree_count) {
502  } else {
503  return StackActionNone;
504  }
505 }
506 
509 }
510 
512  (void)payload;
513  if (iterator->subtree_count >= 1) {
514  if (iterator->is_pending) {
516  } else {
517  return StackActionStop;
518  }
519  } else {
520  return StackActionNone;
521  }
522 }
523 
525  StackSliceArray pop = stack__iter(self, version, pop_pending_callback, NULL, 0);
526  if (pop.size > 0) {
527  ts_stack_renumber_version(self, pop.contents[0].version, version);
528  pop.contents[0].version = version;
529  }
530  return pop;
531 }
532 
533 inline StackAction pop_error_callback(void *payload, const StackIterator *iterator) {
534  if (iterator->subtrees.size > 0) {
535  bool *found_error = payload;
536  if (!*found_error && ts_subtree_is_error(iterator->subtrees.contents[0])) {
537  *found_error = true;
539  } else {
540  return StackActionStop;
541  }
542  } else {
543  return StackActionNone;
544  }
545 }
546 
548  StackNode *node = array_get(&self->heads, version)->node;
549  for (unsigned i = 0; i < node->link_count; i++) {
550  if (node->links[i].subtree.ptr && ts_subtree_is_error(node->links[i].subtree)) {
551  bool found_error = false;
552  StackSliceArray pop = stack__iter(self, version, pop_error_callback, &found_error, 1);
553  if (pop.size > 0) {
554  assert(pop.size == 1);
555  ts_stack_renumber_version(self, pop.contents[0].version, version);
556  return pop.contents[0].subtrees;
557  }
558  break;
559  }
560  }
561  return (SubtreeArray) {.size = 0};
562 }
563 
564 inline StackAction pop_all_callback(void *payload, const StackIterator *iterator) {
565  (void)payload;
566  return iterator->node->link_count == 0 ? StackActionPop : StackActionNone;
567 }
568 
569 StackSliceArray ts_stack_pop_all(Stack *self, StackVersion version) {
570  return stack__iter(self, version, pop_all_callback, NULL, 0);
571 }
572 
573 typedef struct {
574  StackSummary *summary;
575  unsigned max_depth;
577 
579  SummarizeStackSession *session = payload;
580  TSStateId state = iterator->node->state;
581  unsigned depth = iterator->subtree_count;
582  if (depth > session->max_depth) return StackActionStop;
583  for (unsigned i = session->summary->size - 1; i + 1 > 0; i--) {
584  StackSummaryEntry entry = session->summary->contents[i];
585  if (entry.depth < depth) break;
586  if (entry.depth == depth && entry.state == state) return StackActionNone;
587  }
588  array_push(session->summary, ((StackSummaryEntry) {
589  .position = iterator->node->position,
590  .depth = depth,
591  .state = state,
592  }));
593  return StackActionNone;
594 }
595 
596 void ts_stack_record_summary(Stack *self, StackVersion version, unsigned max_depth) {
597  SummarizeStackSession session = {
598  .summary = ts_malloc(sizeof(StackSummary)),
599  .max_depth = max_depth
600  };
601  array_init(session.summary);
602  stack__iter(self, version, summarize_stack_callback, &session, -1);
603  StackHead *head = &self->heads.contents[version];
604  if (head->summary) {
605  array_delete(head->summary);
606  ts_free(head->summary);
607  }
608  head->summary = session.summary;
609 }
610 
612  return array_get(&self->heads, version)->summary;
613 }
614 
616  return array_get(&self->heads, version)->node->dynamic_precedence;
617 }
618 
620  const StackHead *head = array_get(&self->heads, version);
621  const StackNode *node = head->node;
622  if (node->error_cost == 0) return true;
623  while (node) {
624  if (node->link_count > 0) {
625  Subtree subtree = node->links[0].subtree;
626  if (subtree.ptr) {
627  if (ts_subtree_total_bytes(subtree) > 0) {
628  return true;
629  } else if (
630  node->node_count > head->node_count_at_last_error &&
631  ts_subtree_error_cost(subtree) == 0
632  ) {
633  node = node->links[0].node;
634  continue;
635  }
636  }
637  }
638  break;
639  }
640  return false;
641 }
642 
644  stack_head_delete(array_get(&self->heads, version), &self->node_pool, self->subtree_pool);
645  array_erase(&self->heads, version);
646 }
647 
649  if (v1 == v2) return;
650  assert(v2 < v1);
651  assert((uint32_t)v1 < self->heads.size);
652  StackHead *source_head = &self->heads.contents[v1];
653  StackHead *target_head = &self->heads.contents[v2];
654  if (target_head->summary && !source_head->summary) {
655  source_head->summary = target_head->summary;
656  target_head->summary = NULL;
657  }
658  stack_head_delete(target_head, &self->node_pool, self->subtree_pool);
659  *target_head = *source_head;
660  array_erase(&self->heads, v1);
661 }
662 
664  StackHead temporary_head = self->heads.contents[v1];
665  self->heads.contents[v1] = self->heads.contents[v2];
666  self->heads.contents[v2] = temporary_head;
667 }
668 
670  assert(version < self->heads.size);
671  array_push(&self->heads, self->heads.contents[version]);
672  StackHead *head = array_back(&self->heads);
673  stack_node_retain(head->node);
674  if (head->last_external_token.ptr) ts_subtree_retain(head->last_external_token);
675  head->summary = NULL;
676  return self->heads.size - 1;
677 }
678 
679 bool ts_stack_merge(Stack *self, StackVersion version1, StackVersion version2) {
680  if (!ts_stack_can_merge(self, version1, version2)) return false;
681  StackHead *head1 = &self->heads.contents[version1];
682  StackHead *head2 = &self->heads.contents[version2];
683  for (uint32_t i = 0; i < head2->node->link_count; i++) {
684  stack_node_add_link(head1->node, head2->node->links[i], self->subtree_pool);
685  }
686  if (head1->node->state == ERROR_STATE) {
687  head1->node_count_at_last_error = head1->node->node_count;
688  }
689  ts_stack_remove_version(self, version2);
690  return true;
691 }
692 
693 bool ts_stack_can_merge(Stack *self, StackVersion version1, StackVersion version2) {
694  StackHead *head1 = &self->heads.contents[version1];
695  StackHead *head2 = &self->heads.contents[version2];
696  return
697  head1->status == StackStatusActive &&
698  head2->status == StackStatusActive &&
699  head1->node->state == head2->node->state &&
700  head1->node->position.bytes == head2->node->position.bytes &&
701  head1->node->error_cost == head2->node->error_cost &&
703 }
704 
706  array_get(&self->heads, version)->status = StackStatusHalted;
707 }
708 
710  StackHead *head = array_get(&self->heads, version);
711  head->status = StackStatusPaused;
712  head->lookahead_when_paused = lookahead;
713  head->node_count_at_last_error = head->node->node_count;
714 }
715 
717  return array_get(&self->heads, version)->status == StackStatusActive;
718 }
719 
721  return array_get(&self->heads, version)->status == StackStatusHalted;
722 }
723 
725  return array_get(&self->heads, version)->status == StackStatusPaused;
726 }
727 
729  StackHead *head = array_get(&self->heads, version);
730  assert(head->status == StackStatusPaused);
731  Subtree result = head->lookahead_when_paused;
732  head->status = StackStatusActive;
733  head->lookahead_when_paused = NULL_SUBTREE;
734  return result;
735 }
736 
737 void ts_stack_clear(Stack *self) {
738  stack_node_retain(self->base_node);
739  for (uint32_t i = 0; i < self->heads.size; i++) {
740  stack_head_delete(&self->heads.contents[i], &self->node_pool, self->subtree_pool);
741  }
742  array_clear(&self->heads);
743  array_push(&self->heads, ((StackHead) {
744  .node = self->base_node,
745  .status = StackStatusActive,
746  .last_external_token = NULL_SUBTREE,
747  .lookahead_when_paused = NULL_SUBTREE,
748  }));
749 }
750 
751 bool ts_stack_print_dot_graph(Stack *self, const TSLanguage *language, FILE *f) {
752  array_reserve(&self->iterators, 32);
753  if (!f) f = stderr;
754 
755  fprintf(f, "digraph stack {\n");
756  fprintf(f, "rankdir=\"RL\";\n");
757  fprintf(f, "edge [arrowhead=none]\n");
758 
759  Array(StackNode *) visited_nodes = array_new();
760 
761  array_clear(&self->iterators);
762  for (uint32_t i = 0; i < self->heads.size; i++) {
763  StackHead *head = &self->heads.contents[i];
764  if (head->status == StackStatusHalted) continue;
765 
766  fprintf(f, "node_head_%u [shape=none, label=\"\"]\n", i);
767  fprintf(f, "node_head_%u -> node_%p [", i, (void *)head->node);
768 
769  if (head->status == StackStatusPaused) {
770  fprintf(f, "color=red ");
771  }
772  fprintf(f,
773  "label=%u, fontcolor=blue, weight=10000, labeltooltip=\"node_count: %u\nerror_cost: %u",
774  i,
776  ts_stack_error_cost(self, i)
777  );
778 
779  if (head->summary) {
780  fprintf(f, "\nsummary_size: %u", head->summary->size);
781  }
782 
783  if (head->last_external_token.ptr) {
784  const ExternalScannerState *state = &head->last_external_token.ptr->external_scanner_state;
785  const char *data = ts_external_scanner_state_data(state);
786  fprintf(f, "\nexternal_scanner_state:");
787  for (uint32_t j = 0; j < state->length; j++) fprintf(f, " %2X", data[j]);
788  }
789 
790  fprintf(f, "\"]\n");
791  array_push(&self->iterators, ((StackIterator) {
792  .node = head->node
793  }));
794  }
795 
796  bool all_iterators_done = false;
797  while (!all_iterators_done) {
798  all_iterators_done = true;
799 
800  for (uint32_t i = 0; i < self->iterators.size; i++) {
801  StackIterator iterator = self->iterators.contents[i];
802  StackNode *node = iterator.node;
803 
804  for (uint32_t j = 0; j < visited_nodes.size; j++) {
805  if (visited_nodes.contents[j] == node) {
806  node = NULL;
807  break;
808  }
809  }
810 
811  if (!node) continue;
812  all_iterators_done = false;
813 
814  fprintf(f, "node_%p [", (void *)node);
815  if (node->state == ERROR_STATE) {
816  fprintf(f, "label=\"?\"");
817  } else if (
818  node->link_count == 1 &&
819  node->links[0].subtree.ptr &&
820  ts_subtree_extra(node->links[0].subtree)
821  ) {
822  fprintf(f, "shape=point margin=0 label=\"\"");
823  } else {
824  fprintf(f, "label=\"%d\"", node->state);
825  }
826 
827  fprintf(
828  f,
829  " tooltip=\"position: %u,%u\nnode_count:%u\nerror_cost: %u\ndynamic_precedence: %d\"];\n",
830  node->position.extent.row + 1,
831  node->position.extent.column,
832  node->node_count,
833  node->error_cost,
834  node->dynamic_precedence
835  );
836 
837  for (int j = 0; j < node->link_count; j++) {
838  StackLink link = node->links[j];
839  fprintf(f, "node_%p -> node_%p [", (void *)node, (void *)link.node);
840  if (link.is_pending) fprintf(f, "style=dashed ");
841  if (link.subtree.ptr && ts_subtree_extra(link.subtree)) fprintf(f, "fontcolor=gray ");
842 
843  if (!link.subtree.ptr) {
844  fprintf(f, "color=red");
845  } else {
846  fprintf(f, "label=\"");
847  bool quoted = ts_subtree_visible(link.subtree) && !ts_subtree_named(link.subtree);
848  if (quoted) fprintf(f, "'");
849  const char *name = ts_language_symbol_name(language, ts_subtree_symbol(link.subtree));
850  for (const char *c = name; *c; c++) {
851  if (*c == '\"' || *c == '\\') fprintf(f, "\\");
852  fprintf(f, "%c", *c);
853  }
854  if (quoted) fprintf(f, "'");
855  fprintf(f, "\"");
856  fprintf(
857  f,
858  "labeltooltip=\"error_cost: %u\ndynamic_precedence: %u\"",
859  ts_subtree_error_cost(link.subtree),
861  );
862  }
863 
864  fprintf(f, "];\n");
865 
866  StackIterator *next_iterator;
867  if (j == 0) {
868  next_iterator = &self->iterators.contents[i];
869  } else {
870  array_push(&self->iterators, iterator);
871  next_iterator = array_back(&self->iterators);
872  }
873  next_iterator->node = link.node;
874  }
875 
876  array_push(&visited_nodes, node);
877  }
878  }
879 
880  fprintf(f, "}\n");
881 
882  array_delete(&visited_nodes);
883  return true;
884 }
885 
886 #undef inline
const MCPhysReg * iterator
static char * version
Definition: acr.h:4
#define ts_malloc
Definition: alloc.h:21
#define ts_free
Definition: alloc.h:30
#define ts_calloc
Definition: alloc.h:24
lzma_index ** i
Definition: index.h:629
const char * ts_language_symbol_name(const TSLanguage *, TSSymbol)
Definition: language.c:59
#define array_new()
Definition: array.h:25
#define array_init(self)
Definition: array.h:22
#define array_erase(self, index)
Definition: array.h:79
#define array_get(self, index)
Definition: array.h:28
#define array_back(self)
Definition: array.h:33
#define array_push(self, element)
Definition: array.h:43
#define array_pop(self)
Definition: array.h:82
#define array_reserve(self, new_capacity)
Definition: array.h:37
#define array_insert(self, index, element)
Definition: array.h:75
#define array_delete(self)
Definition: array.h:41
#define array_clear(self)
Definition: array.h:35
static ut8 bytes[32]
Definition: asm_arc.c:23
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static static fork const void static count static fd link
Definition: sflib.h:33
#define ERROR_STATE
Definition: error_costs.h:4
#define ERROR_COST_PER_RECOVERY
Definition: error_costs.h:5
voidpf void uLong size
Definition: ioapi.h:138
@ v1
Definition: lanai.h:85
static Length length_zero(void)
Definition: length.h:39
static Length length_add(Length len1, Length len2)
Definition: length.h:25
assert(limit<=UINT32_MAX/2)
string FILE
Definition: benchmark.py:21
uint16_t TSStateId
Definition: parser.h:16
int int32_t
Definition: sftypes.h:33
unsigned int uint32_t
Definition: sftypes.h:29
#define f(i)
Definition: sha256.c:46
#define c(i)
Definition: sha256.c:43
unsigned StackVersion
Definition: stack.h:15
Definition: length.h:9
uint32_t bytes
Definition: length.h:10
TSPoint extent
Definition: length.h:11
Subtree last_external_token
Definition: stack.c:58
StackNode * node
Definition: stack.c:55
StackStatus status
Definition: stack.c:60
Subtree lookahead_when_paused
Definition: stack.c:59
unsigned node_count_at_last_error
Definition: stack.c:57
StackSummary * summary
Definition: stack.c:56
uint32_t subtree_count
Definition: stack.c:42
StackNode * node
Definition: stack.c:40
SubtreeArray subtrees
Definition: stack.c:41
bool is_pending
Definition: stack.c:43
unsigned node_count
Definition: stack.c:35
TSStateId state
Definition: stack.c:29
Length position
Definition: stack.c:30
uint32_t ref_count
Definition: stack.c:33
StackLink links[MAX_LINK_COUNT]
Definition: stack.c:31
int dynamic_precedence
Definition: stack.c:36
unsigned error_cost
Definition: stack.c:34
short unsigned int link_count
Definition: stack.c:32
Definition: stack.c:63
unsigned max_depth
Definition: stack.c:575
StackSummary * summary
Definition: stack.c:574
uint32_t row
Definition: api.h:56
uint32_t column
Definition: api.h:57
Definition: zipcmp.c:77
Definition: z80asm.h:102
Definition: dis.h:43
bool ts_stack_can_merge(Stack *self, StackVersion version1, StackVersion version2)
Definition: stack.c:693
void ts_stack_renumber_version(Stack *self, StackVersion v1, StackVersion v2)
Definition: stack.c:648
static void stack_node_add_link(StackNode *self, StackLink link, SubtreePool *subtree_pool)
Definition: stack.c:185
int ts_stack_dynamic_precedence(Stack *self, StackVersion version)
Definition: stack.c:615
void ts_stack_swap_versions(Stack *self, StackVersion v1, StackVersion v2)
Definition: stack.c:663
void ts_stack_record_summary(Stack *self, StackVersion version, unsigned max_depth)
Definition: stack.c:596
StackSummary * ts_stack_get_summary(Stack *self, StackVersion version)
Definition: stack.c:611
static void stack_node_release(StackNode *self, StackNodeArray *pool, SubtreePool *subtree_pool)
Definition: stack.c:89
#define MAX_ITERATOR_COUNT
Definition: stack.c:12
void ts_stack_halt(Stack *self, StackVersion version)
Definition: stack.c:705
void ts_stack_clear(Stack *self)
Definition: stack.c:737
bool ts_stack_has_advanced_since_error(const Stack *self, StackVersion version)
Definition: stack.c:619
void ts_stack_pause(Stack *self, StackVersion version, Subtree lookahead)
Definition: stack.c:709
StackAction(* StackCallback)(void *, const StackIterator *)
Definition: stack.c:79
static bool stack__subtree_is_equivalent(Subtree left, Subtree right)
Definition: stack.c:166
static void ts_stack__add_slice(Stack *self, StackVersion original_version, StackNode *node, SubtreeArray *subtrees)
Definition: stack.c:288
Subtree ts_stack_resume(Stack *self, StackVersion version)
Definition: stack.c:728
static StackNode * stack_node_new(StackNode *previous_node, Subtree subtree, bool is_pending, TSStateId state, StackNodeArray *pool)
Definition: stack.c:123
uint32_t ts_stack_version_count(const Stack *self)
Definition: stack.c:443
unsigned StackAction
Definition: stack.c:72
StackSliceArray stack__iter(Stack *self, StackVersion version, StackCallback callback, void *payload, int goal_subtree_count)
Definition: stack.c:308
static StackVersion ts_stack__add_version(Stack *self, StackVersion original_version, StackNode *node)
Definition: stack.c:270
bool ts_stack_print_dot_graph(Stack *self, const TSLanguage *language, FILE *f)
Definition: stack.c:751
TSStateId ts_stack_state(const Stack *self, StackVersion version)
Definition: stack.c:447
StackAction pop_all_callback(void *payload, const StackIterator *iterator)
Definition: stack.c:564
bool ts_stack_is_active(const Stack *self, StackVersion version)
Definition: stack.c:716
Length ts_stack_position(const Stack *self, StackVersion version)
Definition: stack.c:451
StackSliceArray ts_stack_pop_count(Stack *self, StackVersion version, uint32_t count)
Definition: stack.c:507
void ts_stack_push(Stack *self, StackVersion version, Subtree subtree, bool pending, TSStateId state)
Definition: stack.c:485
static void stack_head_delete(StackHead *self, StackNodeArray *pool, SubtreePool *subtree_pool)
Definition: stack.c:250
void ts_stack_remove_version(Stack *self, StackVersion version)
Definition: stack.c:643
unsigned ts_stack_node_count_since_error(const Stack *self, StackVersion version)
Definition: stack.c:477
bool ts_stack_merge(Stack *self, StackVersion version1, StackVersion version2)
Definition: stack.c:679
StackAction pop_error_callback(void *payload, const StackIterator *iterator)
Definition: stack.c:533
StackVersion ts_stack_copy_version(Stack *self, StackVersion version)
Definition: stack.c:669
StackSliceArray ts_stack_pop_pending(Stack *self, StackVersion version)
Definition: stack.c:524
StackSliceArray ts_stack_pop_all(Stack *self, StackVersion version)
Definition: stack.c:569
Stack * ts_stack_new(SubtreePool *subtree_pool)
Definition: stack.c:405
void ts_stack_delete(Stack *self)
Definition: stack.c:424
#define MAX_NODE_POOL_SIZE
Definition: stack.c:11
bool ts_stack_is_halted(const Stack *self, StackVersion version)
Definition: stack.c:720
unsigned ts_stack_error_cost(const Stack *self, StackVersion version)
Definition: stack.c:466
typedef Array(StackNode *)
Definition: stack.c:46
#define MAX_LINK_COUNT
Definition: stack.c:10
SubtreeArray ts_stack_pop_error(Stack *self, StackVersion version)
Definition: stack.c:547
StackStatus
Definition: stack.c:52
static void stack_node_retain(StackNode *self)
Definition: stack.c:81
Subtree ts_stack_last_external_token(const Stack *self, StackVersion version)
Definition: stack.c:455
StackAction pop_pending_callback(void *payload, const StackIterator *iterator)
Definition: stack.c:511
StackAction pop_count_callback(void *payload, const StackIterator *iterator)
Definition: stack.c:498
StackAction summarize_stack_callback(void *payload, const StackIterator *iterator)
Definition: stack.c:578
void ts_stack_set_last_external_token(Stack *self, StackVersion version, Subtree token)
Definition: stack.c:459
@ StackActionNone
Definition: stack.c:74
@ StackActionPop
Definition: stack.c:76
@ StackActionStop
Definition: stack.c:75
bool ts_stack_is_paused(const Stack *self, StackVersion version)
Definition: stack.c:724
struct StackNode StackNode
Definition: stack.c:20
void ts_subtree_array_reverse(SubtreeArray *self)
Definition: subtree.c:112
bool ts_subtree_external_scanner_state_eq(Subtree self, Subtree other)
Definition: subtree.c:1027
void ts_subtree_release(SubtreePool *pool, Subtree self)
Definition: subtree.c:584
void ts_subtree_retain(Subtree self)
Definition: subtree.c:577
void ts_subtree_array_delete(SubtreePool *pool, SubtreeArray *self)
Definition: subtree.c:90
const char * ts_external_scanner_state_data(const ExternalScannerState *self)
Definition: subtree.c:53
void ts_subtree_array_copy(SubtreeArray self, SubtreeArray *dest)
Definition: subtree.c:70
static size_t ts_subtree_alloc_size(uint32_t child_count)
Definition: subtree.h:227
static bool ts_subtree_visible(Subtree self)
Definition: subtree.h:214
static Length ts_subtree_total_size(Subtree self)
Definition: subtree.h:274
static uint32_t ts_subtree_total_bytes(Subtree self)
Definition: subtree.h:278
static uint32_t ts_subtree_error_cost(Subtree self)
Definition: subtree.h:302
static int32_t ts_subtree_dynamic_precedence(Subtree self)
Definition: subtree.h:310
static bool ts_subtree_extra(Subtree self)
Definition: subtree.h:216
static bool ts_subtree_is_error(Subtree self)
Definition: subtree.h:342
static Length ts_subtree_size(Subtree self)
Definition: subtree.h:265
static bool ts_subtree_named(Subtree self)
Definition: subtree.h:215
static uint32_t ts_subtree_child_count(Subtree self)
Definition: subtree.h:282
#define NULL_SUBTREE
Definition: subtree.h:19
static Length ts_subtree_padding(Subtree self)
Definition: subtree.h:256
static uint32_t ts_subtree_node_count(Subtree self)
Definition: subtree.h:290
static TSSymbol ts_subtree_symbol(Subtree self)
Definition: subtree.h:213
const SubtreeHeapData * ptr
Definition: subtree.h:158