Start work on new ref API, for giving names to nodes' children

Co-Authored-By: Ayman Nadeem <aymannadeem@gmail.com>
This commit is contained in:
Max Brunsfeld 2019-01-22 12:02:17 -08:00
parent dac13af206
commit bf4e1304f8
7 changed files with 85 additions and 1 deletions

View file

@ -26,6 +26,10 @@ enum RuleJSON {
CHOICE {
members: Vec<RuleJSON>,
},
REF {
value: String,
content: Box<RuleJSON>,
},
SEQ {
members: Vec<RuleJSON>,
},
@ -120,6 +124,7 @@ fn parse_rule(json: RuleJSON) -> Rule {
RuleJSON::PATTERN { value } => Rule::Pattern(value),
RuleJSON::SYMBOL { name } => Rule::NamedSymbol(name),
RuleJSON::CHOICE { members } => Rule::choice(members.into_iter().map(parse_rule).collect()),
RuleJSON::REF { content, value } => parse_rule(*content),
RuleJSON::SEQ { members } => Rule::seq(members.into_iter().map(parse_rule).collect()),
RuleJSON::REPEAT1 { content } => Rule::repeat(parse_rule(*content)),
RuleJSON::REPEAT { content } => {

View file

@ -1,5 +1,6 @@
mod corpus_test;
mod helpers;
mod node_refs;
mod node_test;
mod parser_test;
mod properties_test;

View file

@ -0,0 +1,62 @@
use super::helpers::fixtures::get_test_language;
use crate::generate::generate_parser_for_grammar;
use tree_sitter::Parser;
#[test]
fn test_basic_node_refs() {
let (parser_name, parser_code) = generate_parser_for_grammar(
r#"
{
"name": "test_grammar_with_refs",
"extras": [
{"type": "PATTERN", "value": "\\s+"}
],
"rules": {
"rule_a": {
"type": "SEQ",
"members": [
{
"type": "REF",
"value": "ref_1",
"content": {
"type": "STRING",
"value": "child-1"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "child-2"
},
{
"type": "BLANK"
}
]
},
{
"type": "REF",
"value": "ref_2",
"content": {
"type": "STRING",
"value": "child-3"
}
}
]
}
}
}
"#,
)
.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("child-1 child-2 child-3", None).unwrap();
let root_node = tree.root_node();
assert_eq!(root_node.child_by_ref("ref_1"), root_node.child(0));
assert_eq!(root_node.child_by_ref("ref_2"), root_node.child(2));
}

View file

@ -227,6 +227,9 @@ extern "C" {
extern "C" {
pub fn ts_node_child(arg1: TSNode, arg2: u32) -> TSNode;
}
extern "C" {
pub fn ts_node_child_by_ref(arg1: TSNode, arg2: *const ::std::os::raw::c_char) -> TSNode;
}
extern "C" {
pub fn ts_node_named_child(arg1: TSNode, arg2: u32) -> TSNode;
}

View file

@ -12,7 +12,7 @@ use std::os::unix::io::AsRawFd;
use regex::Regex;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_void};
@ -463,6 +463,14 @@ impl<'tree> Node<'tree> {
Self::new(unsafe { ffi::ts_node_child(self.0, i as u32) })
}
pub fn child_by_ref(&self, ref_name: &str) -> Option<Self> {
if let Ok(c_ref_name) = CString::new(ref_name) {
Self::new(unsafe { ffi::ts_node_child_by_ref(self.0, c_ref_name.as_ptr()) })
} else {
None
}
}
pub fn child_count(&self) -> usize {
unsafe { ffi::ts_node_child_count(self.0) as usize }
}

View file

@ -119,6 +119,7 @@ bool ts_node_has_changes(TSNode);
bool ts_node_has_error(TSNode);
TSNode ts_node_parent(TSNode);
TSNode ts_node_child(TSNode, uint32_t);
TSNode ts_node_child_by_ref(TSNode, const char *);
TSNode ts_node_named_child(TSNode, uint32_t);
uint32_t ts_node_child_count(TSNode);
uint32_t ts_node_named_child_count(TSNode);

View file

@ -453,6 +453,10 @@ TSNode ts_node_named_child(TSNode self, uint32_t child_index) {
return ts_node__child(self, child_index, false);
}
TSNode ts_node_child_by_ref(TSNode self, const char *ref_name) {
return ts_node__null();
}
uint32_t ts_node_child_count(TSNode self) {
Subtree tree = ts_node__subtree(self);
if (ts_subtree_child_count(tree) > 0) {