Handle named nodes aliased as anonymous nodes

Fixes #401
This commit is contained in:
Max Brunsfeld 2019-08-29 14:28:44 -07:00
parent b3ab2e07a2
commit 0955c5b3d7
6 changed files with 90 additions and 10 deletions

View file

@ -1,8 +1,9 @@
use super::helpers::edits::get_random_edit;
use super::helpers::fixtures::{get_language, get_test_language};
use super::helpers::fixtures::{fixtures_dir, get_language, get_test_language};
use super::helpers::random::Rand;
use crate::generate::generate_parser_for_grammar;
use crate::parse::perform_edit;
use std::fs;
use tree_sitter::{Node, Parser, Point, Tree};
const JSON_EXAMPLE: &'static str = r#"
@ -595,6 +596,37 @@ fn test_node_field_calls_in_language_without_fields() {
assert_eq!(cursor.field_name(), None);
}
#[test]
fn test_node_is_named_but_aliased_as_anonymous() {
let (parser_name, parser_code) = generate_parser_for_grammar(
&fs::read_to_string(
&fixtures_dir()
.join("test_grammars")
.join("named_rule_aliased_as_anonymous")
.join("grammar.json"),
)
.unwrap(),
)
.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 B", None).unwrap();
let root_node = tree.root_node();
assert!(!root_node.has_error());
assert_eq!(root_node.child_count(), 3);
assert_eq!(root_node.named_child_count(), 2);
let aliased = root_node.child(0).unwrap();
assert!(!aliased.is_named());
assert_eq!(aliased.kind(), "the-alias");
assert_eq!(root_node.named_child(0).unwrap().kind(), "c");
}
fn get_all_nodes(tree: &Tree) -> Vec<Node> {
let mut result = Vec::new();
let mut visited_children = false;

View file

@ -108,11 +108,12 @@ static inline bool ts_node__is_relevant(TSNode self, bool include_anonymous) {
if (include_anonymous) {
return ts_subtree_visible(tree) || ts_node__alias(&self);
} else {
return
(ts_subtree_visible(tree) &&
ts_subtree_named(tree)) ||
(ts_node__alias(&self) &&
ts_language_symbol_metadata(self.tree->language, ts_node__alias(&self)).named);
TSSymbol alias = ts_node__alias(&self);
if (alias) {
return ts_language_symbol_metadata(self.tree->language, alias).named;
} else {
return ts_subtree_visible(tree) && ts_subtree_named(tree);
}
}
}
@ -440,8 +441,9 @@ bool ts_node_is_extra(TSNode self) {
}
bool ts_node_is_named(TSNode self) {
return ts_node__alias(&self)
? ts_language_symbol_metadata(self.tree->language, ts_node__alias(&self)).named
TSSymbol alias = ts_node__alias(&self);
return alias
? ts_language_symbol_metadata(self.tree->language, alias).named
: ts_subtree_named(ts_node__subtree(self));
}

View file

@ -817,9 +817,12 @@ static size_t ts_subtree__write_to_string(
bool is_root = field_name == ROOT_FIELD;
bool is_visible =
include_all ||
alias_is_named ||
ts_subtree_missing(self) ||
(ts_subtree_visible(self) && ts_subtree_named(self));
(
alias_symbol
? alias_is_named
: ts_subtree_visible(self) && ts_subtree_named(self)
);
if (is_visible) {
if (!is_root) {

View file

@ -0,0 +1,9 @@
================================================
Named rules that are aliased as anonymous tokens
================================================
B C B
---
(a (c) (b))

View file

@ -0,0 +1,33 @@
{
"name": "named_rule_aliased_as_anonymous",
"extras": [
{"type": "PATTERN", "value": "\\s"}
],
"rules": {
"a": {
"type": "SEQ",
"members": [
{
"type": "ALIAS",
"value": "the-alias",
"named": false,
"content": {"type": "SYMBOL", "name": "b"}
},
{"type": "SYMBOL", "name": "c"},
{"type": "SYMBOL", "name": "b"}
]
},
"b": {
"type": "STRING",
"value": "B"
},
"c": {
"type": "STRING",
"value": "C"
}
}
}

View file

@ -0,0 +1 @@
This grammar checks that if a named node is aliased as an anonymous node (e.g. `alias($.foo, 'bar')`), then the rule will behave like an anonymous node. In particular, it will not show up in the tree's S-expression representation.