From 9f608435eebdf5cd23a7c4d7a4c7eed416ba1375 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 12 Feb 2019 17:20:12 -0800 Subject: [PATCH] Fix errors in when languages have no fields --- cli/src/tests/node_test.rs | 66 +++++++++++++++++++++++++++++++++----- lib/src/language.c | 4 +-- lib/src/language.h | 7 ++++ lib/src/tree_cursor.c | 8 +++-- 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/cli/src/tests/node_test.rs b/cli/src/tests/node_test.rs index 08080798..098f1262 100644 --- a/cli/src/tests/node_test.rs +++ b/cli/src/tests/node_test.rs @@ -1,6 +1,6 @@ +use super::helpers::edits::{get_random_edit, perform_edit}; use super::helpers::fixtures::{get_language, get_test_language}; use super::helpers::random::Rand; -use super::helpers::edits::{get_random_edit, perform_edit}; use crate::generate::generate_parser_for_grammar; use tree_sitter::{Node, Parser, Point, Tree}; @@ -321,11 +321,7 @@ fn test_node_edit() { let nodes_after = get_all_nodes(&tree2); for (i, node) in nodes_before.into_iter().enumerate() { assert_eq!( - ( - node.kind(), - node.start_byte(), - node.start_position() - ), + (node.kind(), node.start_byte(), node.start_position()), ( nodes_after[i].kind(), nodes_after[i].start_byte(), @@ -415,13 +411,18 @@ fn test_node_field_names() { let language = get_test_language(&parser_name, &parser_code, None); parser.set_language(language).unwrap(); - let tree = parser.parse("child-0 child-1 child-2 child-3 child-4", None).unwrap(); + let tree = parser + .parse("child-0 child-1 child-2 child-3 child-4", None) + .unwrap(); let root_node = tree.root_node(); assert_eq!(root_node.child_by_field_name("field_1"), root_node.child(0)); assert_eq!(root_node.child_by_field_name("field_2"), root_node.child(2)); assert_eq!(root_node.child_by_field_name("field_3"), root_node.child(4)); - assert_eq!(root_node.child(0).unwrap().child_by_field_name("field_1"), None); + assert_eq!( + root_node.child(0).unwrap().child_by_field_name("field_1"), + None + ); assert_eq!(root_node.child_by_field_name("not_a_real_field"), None); let mut cursor = root_node.walk(); @@ -443,6 +444,55 @@ fn test_node_field_names() { assert_eq!(cursor.field_name(), Some("field_3")); } +#[test] +fn test_node_field_calls_in_language_without_fields() { + let (parser_name, parser_code) = generate_parser_for_grammar( + r#" + { + "name": "test_grammar_with_no_fields", + "extras": [ + {"type": "PATTERN", "value": "\\s+"} + ], + "rules": { + "a": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "b" + }, + { + "type": "STRING", + "value": "c" + }, + { + "type": "STRING", + "value": "d" + } + ] + } + } + } + "#, + ) + .unwrap(); + + let mut parser = Parser::new(); + let language = get_test_language(&parser_name, &parser_code, None); + parser.set_language(language).unwrap(); + + let tree = parser.parse("b c d", None).unwrap(); + + let root_node = tree.root_node(); + assert_eq!(root_node.kind(), "a"); + assert_eq!(root_node.child_by_field_name("something"), None); + + let mut cursor = root_node.walk(); + assert_eq!(cursor.field_name(), None); + assert_eq!(cursor.goto_first_child(), true); + assert_eq!(cursor.field_name(), None); +} + fn get_all_nodes(tree: &Tree) -> Vec { let mut result = Vec::new(); let mut visited_children = false; diff --git a/lib/src/language.c b/lib/src/language.c index 74a7b58d..ebb47d06 100644 --- a/lib/src/language.c +++ b/lib/src/language.c @@ -3,8 +3,6 @@ #include "./error_costs.h" #include -#define LANGUAGE_VERSION_WITH_FIELDS 10 - void ts_language_table_entry(const TSLanguage *self, TSStateId state, TSSymbol symbol, TableEntry *result) { if (symbol == ts_builtin_sym_error || symbol == ts_builtin_sym_error_repeat) { @@ -73,7 +71,7 @@ TSSymbolType ts_language_symbol_type(const TSLanguage *language, TSSymbol symbol } uint32_t ts_language_field_count(const TSLanguage *self) { - if (self->version >= LANGUAGE_VERSION_WITH_FIELDS) { + if (self->version >= TREE_SITTER_LANGUAGE_VERSION_WITH_FIELDS) { return self->field_count; } else { return 0; diff --git a/lib/src/language.h b/lib/src/language.h index 84e3fbc4..16e74790 100644 --- a/lib/src/language.h +++ b/lib/src/language.h @@ -9,6 +9,7 @@ extern "C" { #include "tree_sitter/parser.h" #define ts_builtin_sym_error_repeat (ts_builtin_sym_error - 1) +#define TREE_SITTER_LANGUAGE_VERSION_WITH_FIELDS 10 typedef struct { const TSParseAction *actions; @@ -93,6 +94,12 @@ static inline void ts_language_field_map( const TSFieldMapEntry **start, const TSFieldMapEntry **end ) { + if (self->version < TREE_SITTER_LANGUAGE_VERSION_WITH_FIELDS || self->field_count == 0) { + *start = NULL; + *end = NULL; + return; + } + TSFieldMapSlice slice = self->field_map_slices[production_id]; *start = &self->field_map_entries[slice.index]; *end = &self->field_map_entries[slice.index] + slice.length; diff --git a/lib/src/tree_cursor.c b/lib/src/tree_cursor.c index c3ba54c5..35aeebb3 100644 --- a/lib/src/tree_cursor.c +++ b/lib/src/tree_cursor.c @@ -284,6 +284,10 @@ TSFieldId ts_tree_cursor_current_field_id(const TSTreeCursor *_self) { const char *ts_tree_cursor_current_field_name(const TSTreeCursor *_self) { TSFieldId id = ts_tree_cursor_current_field_id(_self); - const TreeCursor *self = (const TreeCursor *)_self; - return self->tree->language->field_names[id]; + if (id) { + const TreeCursor *self = (const TreeCursor *)_self; + return self->tree->language->field_names[id]; + } else { + return NULL; + } }