From b5a9adb555bb0db783cd12070dcab392df1cf823 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 21 Sep 2020 12:34:48 -0700 Subject: [PATCH 1/6] Allow queries to match on supertypes Co-authored-by: Ayman Nadeem --- .../build_tables/minimize_parse_table.rs | 1 + cli/src/generate/render.rs | 3 + cli/src/tests/query_test.rs | 40 ++++++++- lib/include/tree_sitter/parser.h | 1 + lib/src/language.c | 2 +- lib/src/query.c | 83 +++++++++++++++---- lib/src/tree_cursor.c | 44 ++++++++++ lib/src/tree_cursor.h | 1 + 8 files changed, 155 insertions(+), 20 deletions(-) diff --git a/cli/src/generate/build_tables/minimize_parse_table.rs b/cli/src/generate/build_tables/minimize_parse_table.rs index aa4801c8..d159a2c4 100644 --- a/cli/src/generate/build_tables/minimize_parse_table.rs +++ b/cli/src/generate/build_tables/minimize_parse_table.rs @@ -68,6 +68,7 @@ impl<'a> Minimizer<'a> { .. } => { if !self.simple_aliases.contains_key(&symbol) + && !self.syntax_grammar.supertype_symbols.contains(&symbol) && !aliased_symbols.contains(&symbol) && self.syntax_grammar.variables[symbol.index].kind != VariableType::Named diff --git a/cli/src/generate/render.rs b/cli/src/generate/render.rs index 2758eb58..f33539d6 100644 --- a/cli/src/generate/render.rs +++ b/cli/src/generate/render.rs @@ -460,6 +460,9 @@ impl Generator { VariableType::Hidden => { add_line!(self, ".visible = false,"); add_line!(self, ".named = true,"); + if self.syntax_grammar.supertype_symbols.contains(symbol) { + add_line!(self, ".supertype = true,"); + } } VariableType::Auxiliary => { add_line!(self, ".visible = false,"); diff --git a/cli/src/tests/query_test.rs b/cli/src/tests/query_test.rs index f3521bb5..900b7be1 100644 --- a/cli/src/tests/query_test.rs +++ b/cli/src/tests/query_test.rs @@ -701,7 +701,6 @@ fn test_query_matches_with_immediate_siblings() { (2, vec![("last-stmt", "g()")]), ], ); - }); } @@ -1395,6 +1394,45 @@ fn test_query_matches_with_anonymous_tokens() { }); } +#[test] +fn test_query_matches_with_supertypes() { + allocations::record(|| { + let language = get_language("python"); + let query = Query::new( + language, + r#" + ((_simple_statement) @before . (_simple_statement) @after) + + (assignment + left: (left_hand_side (identifier) @def)) + + (_primary_expression/identifier) @ref + "#, + ) + .unwrap(); + + assert_query_matches( + language, + &query, + " + a = b + print c + if d: print e.f; print g.h.i + ", + &[ + (1, vec![("def", "a")]), + (2, vec![("ref", "b")]), + (0, vec![("before", "a = b"), ("after", "print c")]), + (2, vec![("ref", "c")]), + (2, vec![("ref", "d")]), + (2, vec![("ref", "e")]), + (0, vec![("before", "print e.f"), ("after", "print g.h.i")]), + (2, vec![("ref", "g")]), + ], + ); + }); +} + #[test] fn test_query_matches_within_byte_range() { allocations::record(|| { diff --git a/lib/include/tree_sitter/parser.h b/lib/include/tree_sitter/parser.h index 84096132..c5a788ff 100644 --- a/lib/include/tree_sitter/parser.h +++ b/lib/include/tree_sitter/parser.h @@ -35,6 +35,7 @@ typedef uint16_t TSStateId; typedef struct { bool visible : 1; bool named : 1; + bool supertype: 1; } TSSymbolMetadata; typedef struct TSLexer TSLexer; diff --git a/lib/src/language.c b/lib/src/language.c index c00c49e3..9ccf2bc3 100644 --- a/lib/src/language.c +++ b/lib/src/language.c @@ -89,7 +89,7 @@ TSSymbol ts_language_symbol_for_name( uint32_t count = ts_language_symbol_count(self); for (TSSymbol i = 0; i < count; i++) { TSSymbolMetadata metadata = ts_language_symbol_metadata(self, i); - if (!metadata.visible || metadata.named != is_named) continue; + if ((!metadata.visible && !metadata.supertype) || metadata.named != is_named) continue; const char *symbol_name = self->symbol_names[i]; if (!strncmp(symbol_name, string, length) && !symbol_name[length]) { if (self->version >= TREE_SITTER_LANGUAGE_VERSION_WITH_SYMBOL_DEDUPING) { diff --git a/lib/src/query.c b/lib/src/query.c index 45aa3877..0ca03782 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -47,6 +47,7 @@ typedef struct { */ typedef struct { TSSymbol symbol; + TSSymbol supertype_symbol; TSFieldId field; uint16_t capture_ids[MAX_STEP_CAPTURE_COUNT]; uint16_t alternative_index; @@ -1626,14 +1627,9 @@ static TSQueryError ts_query__parse_pattern( else { TSSymbol symbol; - // Parse the wildcard symbol - if ( - stream->next == '_' || - - // TODO - remove. - // For temporary backward compatibility, handle '*' as a wildcard. - stream->next == '*' - ) { + // TODO - remove. + // For temporary backward compatibility, handle '*' as a wildcard. + if (stream->next == '*') { symbol = depth > 0 ? NAMED_WILDCARD_SYMBOL : WILDCARD_SYMBOL; stream_advance(stream); } @@ -1651,15 +1647,22 @@ static TSQueryError ts_query__parse_pattern( return ts_query__parse_predicate(self, stream); } - symbol = ts_language_symbol_for_name( - self->language, - node_name, - length, - true - ); - if (!symbol) { - stream_reset(stream, node_name); - return TSQueryErrorNodeType; + // Parse the wildcard symbol + else if (length == 1 && node_name[0] == '_') { + symbol = depth > 0 ? NAMED_WILDCARD_SYMBOL : WILDCARD_SYMBOL; + } + + else { + symbol = ts_language_symbol_for_name( + self->language, + node_name, + length, + true + ); + if (!symbol) { + stream_reset(stream, node_name); + return TSQueryErrorNodeType; + } } } else { return TSQueryErrorSyntax; @@ -1667,9 +1670,38 @@ static TSQueryError ts_query__parse_pattern( // Add a step for the node. array_push(&self->steps, query_step__new(symbol, depth, is_immediate)); + if (ts_language_symbol_metadata(self->language, symbol).supertype) { + QueryStep *step = array_back(&self->steps); + step->supertype_symbol = step->symbol; + step->symbol = WILDCARD_SYMBOL; + } + + stream_skip_whitespace(stream); + + if (stream->next == '/') { + stream_advance(stream); + if (!stream_is_ident_start(stream)) { + return TSQueryErrorSyntax; + } + + const char *node_name = stream->input; + stream_scan_identifier(stream); + uint32_t length = stream->input - node_name; + + QueryStep *step = array_back(&self->steps); + step->symbol = ts_language_symbol_for_name( + self->language, + node_name, + length, + true + ); + if (!step->symbol) { + stream_reset(stream, node_name); + return TSQueryErrorNodeType; + } + } // Parse the child patterns - stream_skip_whitespace(stream); bool child_is_immediate = false; uint16_t child_start_step_index = self->steps.size; for (;;) { @@ -2622,6 +2654,21 @@ static inline bool ts_query_cursor__advance( if (step->is_last_child && has_later_named_siblings) { node_does_match = false; } + if (step->supertype_symbol) { + bool has_supertype = ts_tree_cursor_has_supertype(&self->cursor, step->supertype_symbol); + + if (symbol == 1) { + LOG( + " has supertype %s: %d", + ts_language_symbol_name(self->query->language, step->supertype_symbol), + has_supertype + ); + } + + if (!has_supertype) { + node_does_match = false; + } + } if (step->field) { if (step->field == field_id) { if (!can_have_later_siblings_with_this_field) { diff --git a/lib/src/tree_cursor.c b/lib/src/tree_cursor.c index b193a754..8ef17960 100644 --- a/lib/src/tree_cursor.c +++ b/lib/src/tree_cursor.c @@ -352,6 +352,50 @@ TSFieldId ts_tree_cursor_current_status( return result; } +bool ts_tree_cursor_has_supertype( + const TSTreeCursor *_self, + TSSymbol supertype_symbol +) { + const TreeCursor *self = (const TreeCursor *)_self; + + // Walk up the tree, visiting the current node and its invisible ancestors, + // because fields can refer to nodes through invisible *wrapper* nodes, + for (unsigned i = self->stack.size - 1; i > 0; i--) { + TreeCursorEntry *entry = &self->stack.contents[i]; + TreeCursorEntry *parent_entry = &self->stack.contents[i - 1]; + + const TSSymbol *alias_sequence = ts_language_alias_sequence( + self->tree->language, + parent_entry->subtree->ptr->production_id + ); + + // If the subtree is visible, return its public-facing symbol. + // Otherwise, return zero. + #define subtree_visible_symbol(subtree, structural_child_index) \ + (( \ + !ts_subtree_extra(subtree) && \ + alias_sequence && \ + alias_sequence[structural_child_index] \ + ) ? \ + alias_sequence[structural_child_index] : \ + ts_subtree_visible(subtree) ? \ + ts_subtree_symbol(subtree) : \ + 0) \ + + // Stop walking up when a visible ancestor is found. + if ( + i != self->stack.size - 1 && + subtree_visible_symbol(*entry->subtree, entry->structural_child_index) + ) break; + + if (ts_subtree_symbol(*entry->subtree) == supertype_symbol) { + return true; + } + } + + return false; +} + TSFieldId ts_tree_cursor_current_field_id(const TSTreeCursor *_self) { const TreeCursor *self = (const TreeCursor *)_self; diff --git a/lib/src/tree_cursor.h b/lib/src/tree_cursor.h index 0bb486d7..7829e8b9 100644 --- a/lib/src/tree_cursor.h +++ b/lib/src/tree_cursor.h @@ -17,5 +17,6 @@ typedef struct { void ts_tree_cursor_init(TreeCursor *, TSNode); TSFieldId ts_tree_cursor_current_status(const TSTreeCursor *, bool *, bool *, bool *); +bool ts_tree_cursor_has_supertype(const TSTreeCursor *, TSSymbol); #endif // TREE_SITTER_TREE_CURSOR_H_ From 8835dfda99d838c5985baa4b30234f6249515019 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 21 Sep 2020 13:11:54 -0700 Subject: [PATCH 2/6] Fix test for supertypes in queries --- cli/src/tests/query_test.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/cli/src/tests/query_test.rs b/cli/src/tests/query_test.rs index 900b7be1..b9b28117 100644 --- a/cli/src/tests/query_test.rs +++ b/cli/src/tests/query_test.rs @@ -1401,12 +1401,15 @@ fn test_query_matches_with_supertypes() { let query = Query::new( language, r#" - ((_simple_statement) @before . (_simple_statement) @after) + (argument_list (_expression) @arg) + + (keyword_argument + value: (_expression) @kw_arg) (assignment - left: (left_hand_side (identifier) @def)) + left: (left_hand_side (identifier) @var_def)) - (_primary_expression/identifier) @ref + (_primary_expression/identifier) @var_ref "#, ) .unwrap(); @@ -1415,19 +1418,19 @@ fn test_query_matches_with_supertypes() { language, &query, " - a = b - print c - if d: print e.f; print g.h.i + a = b.c( + [d], + # a comment + e=f + ) ", &[ - (1, vec![("def", "a")]), - (2, vec![("ref", "b")]), - (0, vec![("before", "a = b"), ("after", "print c")]), - (2, vec![("ref", "c")]), - (2, vec![("ref", "d")]), - (2, vec![("ref", "e")]), - (0, vec![("before", "print e.f"), ("after", "print g.h.i")]), - (2, vec![("ref", "g")]), + (2, vec![("var_def", "a")]), + (3, vec![("var_ref", "b")]), + (0, vec![("arg", "[d]")]), + (3, vec![("var_ref", "d")]), + (1, vec![("kw_arg", "f")]), + (3, vec![("var_ref", "f")]), ], ); }); From a8d77001c247fbfc3dddfb24d5eeb13274d2b751 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 21 Sep 2020 13:20:50 -0700 Subject: [PATCH 3/6] Update c error recovery test to reflect behavior change --- test/fixtures/error_corpus/c_errors.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/fixtures/error_corpus/c_errors.txt b/test/fixtures/error_corpus/c_errors.txt index 4d0c8e8b..b8733245 100644 --- a/test/fixtures/error_corpus/c_errors.txt +++ b/test/fixtures/error_corpus/c_errors.txt @@ -158,9 +158,17 @@ int a() { (translation_unit (function_definition (primitive_type) - (function_declarator (identifier) (parameter_list)) + (function_declarator + (identifier) + (parameter_list)) (compound_statement - (struct_specifier (type_identifier)) - (ERROR (number_literal)) - (primitive_type) - (ERROR (number_literal))))) + (declaration + (struct_specifier (type_identifier)) + (init_declarator + (MISSING identifier) + (number_literal))) + (declaration + (primitive_type) + (init_declarator + (MISSING identifier) + (number_literal)))))) From 5003064da71f46e169f45247d67b2813d11f93e5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 23 Sep 2020 09:35:14 -0700 Subject: [PATCH 4/6] Make supertypes automatically hidden, without underscore prefix --- cli/src/generate/node_types.rs | 9 +-------- cli/src/generate/prepare_grammar/intern_symbols.rs | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cli/src/generate/node_types.rs b/cli/src/generate/node_types.rs index 7a5768a5..7962c7f3 100644 --- a/cli/src/generate/node_types.rs +++ b/cli/src/generate/node_types.rs @@ -325,15 +325,8 @@ pub(crate) fn get_variable_info( } for supertype_symbol in &syntax_grammar.supertype_symbols { - let variable = &syntax_grammar.variables[supertype_symbol.index]; - if variable.kind != VariableType::Hidden { - return Err(Error::grammar(&format!( - "Supertype symbols must be hidden, but `{}` is not", - variable.name - ))); - } - if result[supertype_symbol.index].has_multi_step_production { + let variable = &syntax_grammar.variables[supertype_symbol.index]; return Err(Error::grammar(&format!( "Supertype symbols must always have a single visible child, but `{}` can have multiple", variable.name diff --git a/cli/src/generate/prepare_grammar/intern_symbols.rs b/cli/src/generate/prepare_grammar/intern_symbols.rs index 7cd411ef..276f13ff 100644 --- a/cli/src/generate/prepare_grammar/intern_symbols.rs +++ b/cli/src/generate/prepare_grammar/intern_symbols.rs @@ -73,6 +73,12 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> Result ); } + for (i, variable) in variables.iter_mut().enumerate() { + if supertype_symbols.contains(&Symbol::non_terminal(i)) { + variable.kind = VariableType::Hidden; + } + } + Ok(InternedGrammar { variables, external_tokens, From 21c3bbc4b4bca92b1e79c45ebd7845b92c422ab8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 23 Sep 2020 10:55:31 -0700 Subject: [PATCH 5/6] Account for supertypes during query analysis --- cli/src/tests/query_test.rs | 18 ++++++++++++++++++ lib/src/query.c | 12 +++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/cli/src/tests/query_test.rs b/cli/src/tests/query_test.rs index b9b28117..598a9792 100644 --- a/cli/src/tests/query_test.rs +++ b/cli/src/tests/query_test.rs @@ -291,6 +291,24 @@ fn test_query_errors_on_impossible_patterns() { .join("\n") )) ); + + Query::new( + js_lang, + "(if_statement + condition: (parenthesized_expression (_expression) @cond))", + ) + .unwrap(); + assert_eq!( + Query::new(js_lang, "(if_statement condition: (_expression))",), + Err(QueryError::Structure( + 1, + [ + "(if_statement condition: (_expression))", // + " ^", + ] + .join("\n") + )) + ); }); } diff --git a/lib/src/query.c b/lib/src/query.c index 0ca03782..288656ac 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -639,6 +639,13 @@ static inline AnalysisStateEntry *analysis_state__top(AnalysisState *self) { return &self->stack[self->depth - 1]; } +static inline bool analysis_state__has_supertype(AnalysisState *self, TSSymbol symbol) { + for (unsigned i = 0; i < self->depth; i++) { + if (self->stack[i].parent_symbol == symbol) return true; + } + return false; +} + /*********************** * AnalysisSubgraphNode ***********************/ @@ -1134,6 +1141,9 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { if (step->field && step->field != field_id) { does_match = false; } + if (step->supertype_symbol) { + if (!analysis_state__has_supertype(state, step->supertype_symbol)) does_match = false; + } } // If this is a hidden child, then push a new entry to the stack, in order to @@ -1673,7 +1683,7 @@ static TSQueryError ts_query__parse_pattern( if (ts_language_symbol_metadata(self->language, symbol).supertype) { QueryStep *step = array_back(&self->steps); step->supertype_symbol = step->symbol; - step->symbol = WILDCARD_SYMBOL; + step->symbol = NAMED_WILDCARD_SYMBOL; } stream_skip_whitespace(stream); From a544200a6c9f012e4c111c83b46619ccf572523a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 23 Sep 2020 11:47:47 -0700 Subject: [PATCH 6/6] Simplify query code for matching supertypes --- lib/src/query.c | 45 ++++++++-------- lib/src/tree_cursor.c | 120 ++++++++++++++++-------------------------- lib/src/tree_cursor.h | 11 +++- 3 files changed, 77 insertions(+), 99 deletions(-) diff --git a/lib/src/query.c b/lib/src/query.c index 288656ac..8c86badb 100644 --- a/lib/src/query.c +++ b/lib/src/query.c @@ -640,10 +640,10 @@ static inline AnalysisStateEntry *analysis_state__top(AnalysisState *self) { } static inline bool analysis_state__has_supertype(AnalysisState *self, TSSymbol symbol) { - for (unsigned i = 0; i < self->depth; i++) { - if (self->stack[i].parent_symbol == symbol) return true; - } - return false; + for (unsigned i = 0; i < self->depth; i++) { + if (self->stack[i].parent_symbol == symbol) return true; + } + return false; } /*********************** @@ -1141,9 +1141,10 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *error_offset) { if (step->field && step->field != field_id) { does_match = false; } - if (step->supertype_symbol) { - if (!analysis_state__has_supertype(state, step->supertype_symbol)) does_match = false; - } + if ( + step->supertype_symbol && + !analysis_state__has_supertype(state, step->supertype_symbol) + ) does_match = false; } // If this is a hidden child, then push a new entry to the stack, in order to @@ -2594,11 +2595,17 @@ static inline bool ts_query_cursor__advance( bool has_later_siblings; bool has_later_named_siblings; bool can_have_later_siblings_with_this_field; - TSFieldId field_id = ts_tree_cursor_current_status( + TSFieldId field_id = 0; + TSSymbol supertypes[8] = {0}; + unsigned supertype_count = 8; + ts_tree_cursor_current_status( &self->cursor, + &field_id, &has_later_siblings, &has_later_named_siblings, - &can_have_later_siblings_with_this_field + &can_have_later_siblings_with_this_field, + supertypes, + &supertype_count ); LOG( "enter node. type:%s, field:%s, row:%u state_count:%u, finished_state_count:%u\n", @@ -2617,6 +2624,7 @@ static inline bool ts_query_cursor__advance( // If this node matches the first step of the pattern, then add a new // state at the start of this pattern. if (step->field && field_id != step->field) continue; + if (step->supertype_symbol && !supertype_count) continue; ts_query_cursor__add_state(self, pattern); } @@ -2665,19 +2673,14 @@ static inline bool ts_query_cursor__advance( node_does_match = false; } if (step->supertype_symbol) { - bool has_supertype = ts_tree_cursor_has_supertype(&self->cursor, step->supertype_symbol); - - if (symbol == 1) { - LOG( - " has supertype %s: %d", - ts_language_symbol_name(self->query->language, step->supertype_symbol), - has_supertype - ); - } - - if (!has_supertype) { - node_does_match = false; + bool has_supertype = false; + for (unsigned j = 0; j < supertype_count; j++) { + if (supertypes[j] == step->supertype_symbol) { + has_supertype = true; + break; + } } + if (!has_supertype) node_does_match = false; } if (step->field) { if (step->field == field_id) { diff --git a/lib/src/tree_cursor.c b/lib/src/tree_cursor.c index 8ef17960..64e8b414 100644 --- a/lib/src/tree_cursor.c +++ b/lib/src/tree_cursor.c @@ -246,14 +246,19 @@ TSNode ts_tree_cursor_current_node(const TSTreeCursor *_self) { // Private - Get various facts about the current node that are needed // when executing tree queries. -TSFieldId ts_tree_cursor_current_status( +void ts_tree_cursor_current_status( const TSTreeCursor *_self, + TSFieldId *field_id, bool *has_later_siblings, bool *has_later_named_siblings, - bool *can_have_later_siblings_with_this_field + bool *can_have_later_siblings_with_this_field, + TSSymbol *supertypes, + unsigned *supertype_count ) { const TreeCursor *self = (const TreeCursor *)_self; - TSFieldId result = 0; + unsigned max_supertypes = *supertype_count; + *field_id = 0; + *supertype_count = 0; *has_later_siblings = false; *has_later_named_siblings = false; *can_have_later_siblings_with_this_field = false; @@ -269,24 +274,31 @@ TSFieldId ts_tree_cursor_current_status( parent_entry->subtree->ptr->production_id ); - // If the subtree is visible, return its public-facing symbol. - // Otherwise, return zero. - #define subtree_visible_symbol(subtree, structural_child_index) \ - (( \ - !ts_subtree_extra(subtree) && \ - alias_sequence && \ - alias_sequence[structural_child_index] \ - ) ? \ - alias_sequence[structural_child_index] : \ - ts_subtree_visible(subtree) ? \ - ts_subtree_symbol(subtree) : \ - 0) \ + #define subtree_symbol(subtree, structural_child_index) \ + (( \ + !ts_subtree_extra(subtree) && \ + alias_sequence && \ + alias_sequence[structural_child_index] \ + ) ? \ + alias_sequence[structural_child_index] : \ + ts_subtree_symbol(subtree)) // Stop walking up when a visible ancestor is found. - if ( - i != self->stack.size - 1 && - subtree_visible_symbol(*entry->subtree, entry->structural_child_index) - ) break; + TSSymbol entry_symbol = subtree_symbol( + *entry->subtree, + entry->structural_child_index + ); + TSSymbolMetadata entry_metadata = ts_language_symbol_metadata( + self->tree->language, + entry_symbol + ); + if (i != self->stack.size - 1 && entry_metadata.visible) break; + + // Record any supertypes + if (entry_metadata.supertype && *supertype_count < max_supertypes) { + supertypes[*supertype_count] = entry_symbol; + (*supertype_count)++; + } // Determine if the current node has later siblings. if (!*has_later_siblings) { @@ -295,19 +307,21 @@ TSFieldId ts_tree_cursor_current_status( if (!ts_subtree_extra(*entry->subtree)) structural_child_index++; for (unsigned j = entry->child_index + 1; j < sibling_count; j++) { Subtree sibling = parent_entry->subtree->ptr->children[j]; - if (ts_subtree_visible_child_count(sibling) > 0) { + TSSymbolMetadata sibling_metadata = ts_language_symbol_metadata( + self->tree->language, + subtree_symbol(sibling, structural_child_index) + ); + if (sibling_metadata.visible) { *has_later_siblings = true; if (*has_later_named_siblings) break; - if (sibling.ptr->named_child_count > 0) { + if (sibling_metadata.named) { *has_later_named_siblings = true; break; } - } - TSSymbol visible_symbol = subtree_visible_symbol(sibling, structural_child_index); - if (visible_symbol) { + } else if (ts_subtree_visible_child_count(sibling) > 0) { *has_later_siblings = true; if (*has_later_named_siblings) break; - if (ts_language_symbol_metadata(self->tree->language, visible_symbol).named) { + if (sibling.ptr->named_child_count > 0) { *has_later_named_siblings = true; break; } @@ -316,7 +330,7 @@ TSFieldId ts_tree_cursor_current_status( } } - #undef subtree_visible_symbol + #undef subtree_metadata if (!ts_subtree_extra(*entry->subtree)) { const TSFieldMapEntry *field_map, *field_map_end; @@ -327,10 +341,10 @@ TSFieldId ts_tree_cursor_current_status( ); // Look for a field name associated with the current node. - if (!result) { + if (!*field_id) { for (const TSFieldMapEntry *i = field_map; i < field_map_end; i++) { if (!i->inherited && i->child_index == entry->structural_child_index) { - result = i->field_id; + *field_id = i->field_id; *can_have_later_siblings_with_this_field = false; break; } @@ -338,9 +352,9 @@ TSFieldId ts_tree_cursor_current_status( } // Determine if the current node can have later siblings with the same field name. - if (result) { + if (*field_id) { for (const TSFieldMapEntry *i = field_map; i < field_map_end; i++) { - if (i->field_id == result && i->child_index > entry->structural_child_index) { + if (i->field_id == *field_id && i->child_index > entry->structural_child_index) { *can_have_later_siblings_with_this_field = true; break; } @@ -348,52 +362,6 @@ TSFieldId ts_tree_cursor_current_status( } } } - - return result; -} - -bool ts_tree_cursor_has_supertype( - const TSTreeCursor *_self, - TSSymbol supertype_symbol -) { - const TreeCursor *self = (const TreeCursor *)_self; - - // Walk up the tree, visiting the current node and its invisible ancestors, - // because fields can refer to nodes through invisible *wrapper* nodes, - for (unsigned i = self->stack.size - 1; i > 0; i--) { - TreeCursorEntry *entry = &self->stack.contents[i]; - TreeCursorEntry *parent_entry = &self->stack.contents[i - 1]; - - const TSSymbol *alias_sequence = ts_language_alias_sequence( - self->tree->language, - parent_entry->subtree->ptr->production_id - ); - - // If the subtree is visible, return its public-facing symbol. - // Otherwise, return zero. - #define subtree_visible_symbol(subtree, structural_child_index) \ - (( \ - !ts_subtree_extra(subtree) && \ - alias_sequence && \ - alias_sequence[structural_child_index] \ - ) ? \ - alias_sequence[structural_child_index] : \ - ts_subtree_visible(subtree) ? \ - ts_subtree_symbol(subtree) : \ - 0) \ - - // Stop walking up when a visible ancestor is found. - if ( - i != self->stack.size - 1 && - subtree_visible_symbol(*entry->subtree, entry->structural_child_index) - ) break; - - if (ts_subtree_symbol(*entry->subtree) == supertype_symbol) { - return true; - } - } - - return false; } TSFieldId ts_tree_cursor_current_field_id(const TSTreeCursor *_self) { diff --git a/lib/src/tree_cursor.h b/lib/src/tree_cursor.h index 7829e8b9..7c9c05d5 100644 --- a/lib/src/tree_cursor.h +++ b/lib/src/tree_cursor.h @@ -16,7 +16,14 @@ typedef struct { } TreeCursor; void ts_tree_cursor_init(TreeCursor *, TSNode); -TSFieldId ts_tree_cursor_current_status(const TSTreeCursor *, bool *, bool *, bool *); -bool ts_tree_cursor_has_supertype(const TSTreeCursor *, TSSymbol); +void ts_tree_cursor_current_status( + const TSTreeCursor *, + TSFieldId *, + bool *, + bool *, + bool *, + TSSymbol *, + unsigned * +); #endif // TREE_SITTER_TREE_CURSOR_H_