lib/src/zipper.c (120 lines of code) (raw):
//
// zipper.c
// jsitter
//
// Created by Andrey Zaytsev on 12.06.19.
//
#include "tree_sitter/api.h"
#include "./alloc.h"
#include "./language.h"
#include "./tree.h"
typedef struct _TSZipper {
const struct _TSZipper *parent;
const TSSymbol *parent_alias_sequence;
Subtree subtree;
uint32_t byte_offset;
uint32_t child_index;
uint32_t structural_child_index;
} _TSZipper;
bool __is_visible(_TSZipper *zip) {
if (ts_subtree_visible(zip->subtree)) {
return true;
} else {
bool extra = ts_subtree_extra(zip->subtree);
if (!extra && zip->parent_alias_sequence) {
return zip->parent_alias_sequence[zip->structural_child_index];
} else {
return false;
}
}
}
bool __ts_zipper_right(const _TSZipper *zip, _TSZipper *result) {
if (!zip->parent) {
return false;
}
Subtree parent_subtree = zip->parent->subtree;
if (zip->child_index == parent_subtree.ptr->child_count - 1) {
return false;
}
const Subtree sibling = parent_subtree.ptr->children[zip->child_index + 1];
bool extra = ts_subtree_extra(zip->subtree);
uint32_t structural_child_index;
if (!extra && zip->parent_alias_sequence) {
structural_child_index = zip->structural_child_index + 1;
} else {
structural_child_index = zip->structural_child_index;
}
*result = (_TSZipper) {
.parent = zip->parent,
.parent_alias_sequence = zip->parent_alias_sequence,
.subtree = sibling,
.byte_offset = ts_subtree_size(zip->subtree).bytes + ts_subtree_padding(sibling).bytes,
.child_index = zip->child_index + 1,
.structural_child_index = structural_child_index
};
return true;
}
bool _ts_zipper_right(const _TSZipper *zip, _TSZipper *result) {
while (__ts_zipper_right(zip, result)) {
if (__is_visible(result)) {
return true;
}
zip = result;
}
return false;
}
bool _ts_zipper_down(const _TSZipper *zip, _TSZipper *result, TSLanguage *lang) {
if (ts_subtree_child_count(zip->subtree) == 0) {
return false;
} else {
Subtree child = zip->subtree.ptr->children[0];
const TSSymbol *alias_sequence = ts_language_alias_sequence(lang, zip->subtree.ptr->production_id);
*result = (_TSZipper) {
.parent = zip,
.parent_alias_sequence = alias_sequence,
.subtree = child,
.byte_offset = zip->byte_offset,
.child_index = 0,
.structural_child_index = 0
};
if (__is_visible(result)) {
return true;
} else {
uint32_t visible_child_count = ts_subtree_visible_child_count(child);
if (visible_child_count > 0) {
_TSZipper *z = (_TSZipper *)malloc(sizeof(_TSZipper));
*z = *result;
return _ts_zipper_down(z, result, lang);
} else {
return _ts_zipper_right(result, result);
}
}
}
}
void _ts_zipper_new(Subtree tree, _TSZipper *result) {
*result = (_TSZipper) {
.parent = NULL,
.parent_alias_sequence = NULL,
.subtree = tree,
.byte_offset = 0,
.child_index = 0,
.structural_child_index = 0
};
}
void ts_zipper_new(TSTree *tree, TSZipper *result) {
return _ts_zipper_new(tree->root, (_TSZipper *)result);
}
bool ts_zipper_right(const TSZipper *zip, TSZipper *result) {
return _ts_zipper_right((_TSZipper *)zip, (_TSZipper *)result);
}
bool ts_zipper_down(const TSZipper *zip, TSZipper *result, TSLanguage *lang) {
return _ts_zipper_down((_TSZipper *)zip, (_TSZipper *)result, lang);
}
TSSymbol ts_zipper_node_type(const TSZipper *zip) {
_TSZipper *z = (_TSZipper *)zip;
return ts_subtree_symbol(z->subtree);
}
uint32_t ts_zipper_start_byte(const TSZipper *zip) {
return zip->byte_offset;
}
uint32_t ts_zipper_end_byte(const TSZipper *zip) {
_TSZipper *z = (_TSZipper *) zip;
return z->byte_offset + ts_subtree_size(z->subtree).bytes;
}
TSZipper *ts_zipper_up(const TSZipper *zip) {
return (TSZipper *)(((_TSZipper *)zip)->parent);
}