Skip to content

Commit 9c199b6

Browse files
authored
Merge pull request #193 from github/tausbn/autogenerate-qldoc
Autogenerate QLDoc for `TreeSitter.qll`
2 parents 5bafc0c + 53b7492 commit 9c199b6

3 files changed

Lines changed: 607 additions & 4 deletions

File tree

generator/src/ql.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ impl<'a> fmt::Display for TopLevel<'a> {
1717

1818
#[derive(Clone, Eq, PartialEq, Hash)]
1919
pub struct Class<'a> {
20+
pub qldoc: Option<String>,
2021
pub name: &'a str,
2122
pub is_abstract: bool,
2223
pub supertypes: BTreeSet<Type<'a>>,
@@ -26,6 +27,9 @@ pub struct Class<'a> {
2627

2728
impl<'a> fmt::Display for Class<'a> {
2829
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30+
if let Some(qldoc) = &self.qldoc {
31+
write!(f, "/** {} */", qldoc)?;
32+
}
2933
if self.is_abstract {
3034
write!(f, "abstract ")?;
3135
}
@@ -43,6 +47,7 @@ impl<'a> fmt::Display for Class<'a> {
4347
f,
4448
" {}\n",
4549
Predicate {
50+
qldoc: None,
4651
name: self.name.clone(),
4752
overridden: false,
4853
return_type: None,
@@ -176,6 +181,7 @@ impl<'a> fmt::Display for Expression<'a> {
176181

177182
#[derive(Clone, Eq, PartialEq, Hash)]
178183
pub struct Predicate<'a> {
184+
pub qldoc: Option<String>,
179185
pub name: &'a str,
180186
pub overridden: bool,
181187
pub return_type: Option<Type<'a>>,
@@ -185,6 +191,9 @@ pub struct Predicate<'a> {
185191

186192
impl<'a> fmt::Display for Predicate<'a> {
187193
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194+
if let Some(qldoc) = &self.qldoc {
195+
write!(f, "/** {} */", qldoc)?;
196+
}
188197
if self.overridden {
189198
write!(f, "override ")?;
190199
}

generator/src/ql_gen.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ pub fn write(language: &Language, classes: &[ql::TopLevel]) -> std::io::Result<(
2929
fn create_ast_node_class<'a>() -> ql::Class<'a> {
3030
// Default implementation of `toString` calls `this.getAPrimaryQlClass()`
3131
let to_string = ql::Predicate {
32+
qldoc: Some(String::from(
33+
"Gets a string representation of this element.",
34+
)),
3235
name: "toString",
3336
overridden: false,
3437
return_type: Some(ql::Type::String),
@@ -42,11 +45,20 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
4245
)),
4346
),
4447
};
45-
let get_location =
46-
create_none_predicate("getLocation", false, Some(ql::Type::Normal("Location")));
47-
let get_a_field_or_child =
48-
create_none_predicate("getAFieldOrChild", false, Some(ql::Type::Normal("AstNode")));
48+
let get_location = create_none_predicate(
49+
Some(String::from("Gets the location of this element.")),
50+
"getLocation",
51+
false,
52+
Some(ql::Type::Normal("Location")),
53+
);
54+
let get_a_field_or_child = create_none_predicate(
55+
Some(String::from("Gets a field or child node of this node.")),
56+
"getAFieldOrChild",
57+
false,
58+
Some(ql::Type::Normal("AstNode")),
59+
);
4960
let get_parent = ql::Predicate {
61+
qldoc: Some(String::from("Gets the parent of this element.")),
5062
name: "getParent",
5163
overridden: false,
5264
return_type: Some(ql::Type::Normal("AstNode")),
@@ -61,6 +73,9 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
6173
),
6274
};
6375
let get_parent_index = ql::Predicate {
76+
qldoc: Some(String::from(
77+
"Gets the index of this node among the children of its parent.",
78+
)),
6479
name: "getParentIndex",
6580
overridden: false,
6681
return_type: Some(ql::Type::Int),
@@ -75,6 +90,9 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
7590
),
7691
};
7792
let get_a_primary_ql_class = ql::Predicate {
93+
qldoc: Some(String::from(
94+
"Gets the name of the primary QL class for this element.",
95+
)),
7896
name: "getAPrimaryQlClass",
7997
overridden: false,
8098
return_type: Some(ql::Type::String),
@@ -85,6 +103,7 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
85103
),
86104
};
87105
ql::Class {
106+
qldoc: Some(String::from("The base class for all AST nodes")),
88107
name: "AstNode",
89108
is_abstract: false,
90109
supertypes: vec![ql::Type::AtType("ast_node")].into_iter().collect(),
@@ -103,20 +122,25 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
103122
fn create_token_class<'a>() -> ql::Class<'a> {
104123
let tokeninfo_arity = 6;
105124
let get_value = ql::Predicate {
125+
qldoc: Some(String::from("Gets the value of this token.")),
106126
name: "getValue",
107127
overridden: false,
108128
return_type: Some(ql::Type::String),
109129
formal_parameters: vec![],
110130
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 3, tokeninfo_arity),
111131
};
112132
let get_location = ql::Predicate {
133+
qldoc: Some(String::from("Gets the location of this token.")),
113134
name: "getLocation",
114135
overridden: true,
115136
return_type: Some(ql::Type::Normal("Location")),
116137
formal_parameters: vec![],
117138
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 4, tokeninfo_arity),
118139
};
119140
let to_string = ql::Predicate {
141+
qldoc: Some(String::from(
142+
"Gets a string representation of this element.",
143+
)),
120144
name: "toString",
121145
overridden: true,
122146
return_type: Some(ql::Type::String),
@@ -127,6 +151,7 @@ fn create_token_class<'a>() -> ql::Class<'a> {
127151
),
128152
};
129153
ql::Class {
154+
qldoc: Some(String::from("A token.")),
130155
name: "Token",
131156
is_abstract: false,
132157
supertypes: vec![ql::Type::AtType("token"), ql::Type::Normal("AstNode")]
@@ -148,6 +173,7 @@ fn create_reserved_word_class<'a>() -> ql::Class<'a> {
148173
let class_name = "ReservedWord";
149174
let get_a_primary_ql_class = create_get_a_primary_ql_class(&class_name);
150175
ql::Class {
176+
qldoc: Some(String::from("A reserved word.")),
151177
name: class_name,
152178
is_abstract: false,
153179
supertypes: vec![ql::Type::AtType(db_name), ql::Type::Normal("Token")]
@@ -160,11 +186,13 @@ fn create_reserved_word_class<'a>() -> ql::Class<'a> {
160186

161187
/// Creates a predicate whose body is `none()`.
162188
fn create_none_predicate<'a>(
189+
qldoc: Option<String>,
163190
name: &'a str,
164191
overridden: bool,
165192
return_type: Option<ql::Type<'a>>,
166193
) -> ql::Predicate<'a> {
167194
ql::Predicate {
195+
qldoc: qldoc,
168196
name: name,
169197
overridden,
170198
return_type,
@@ -177,6 +205,9 @@ fn create_none_predicate<'a>(
177205
/// name.
178206
fn create_get_a_primary_ql_class<'a>(class_name: &'a str) -> ql::Predicate<'a> {
179207
ql::Predicate {
208+
qldoc: Some(String::from(
209+
"Gets the name of the primary QL class for this element.",
210+
)),
180211
name: "getAPrimaryQlClass",
181212
overridden: true,
182213
return_type: Some(ql::Type::String),
@@ -196,6 +227,7 @@ fn create_get_a_primary_ql_class<'a>(class_name: &'a str) -> ql::Predicate<'a> {
196227
/// `arity` - the total number of columns in the table
197228
fn create_get_location_predicate<'a>(def_table: &'a str, arity: usize) -> ql::Predicate<'a> {
198229
ql::Predicate {
230+
qldoc: Some(String::from("Gets the location of this element.")),
199231
name: "getLocation",
200232
overridden: true,
201233
return_type: Some(ql::Type::Normal("Location")),
@@ -220,6 +252,7 @@ fn create_get_location_predicate<'a>(def_table: &'a str, arity: usize) -> ql::Pr
220252
/// `def_table` - the name of the table that defines the entity and its text.
221253
fn create_get_text_predicate<'a>(def_table: &'a str) -> ql::Predicate<'a> {
222254
ql::Predicate {
255+
qldoc: Some(String::from("Gets the text content of this element.")),
223256
name: "getText",
224257
overridden: false,
225258
return_type: Some(ql::Type::String),
@@ -417,8 +450,21 @@ fn create_field_getters<'a>(
417450
(get_value, Some(get_value_any_index))
418451
}
419452
};
453+
let qldoc = match &field.name {
454+
Some(name) => {
455+
format!("Gets the node corresponding to the field `{}`.", name)
456+
}
457+
None => {
458+
if formal_parameters.len() == 0 {
459+
"Gets the child of this node.".to_owned()
460+
} else {
461+
"Gets the `i`th child of this node.".to_owned()
462+
}
463+
}
464+
};
420465
(
421466
ql::Predicate {
467+
qldoc: Some(qldoc),
422468
name: &field.getter_name,
423469
overridden: false,
424470
return_type,
@@ -456,6 +502,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
456502
supertypes.insert(ql::Type::AtType(&node.dbscheme_name));
457503
supertypes.insert(ql::Type::Normal("Token"));
458504
classes.push(ql::TopLevel::Class(ql::Class {
505+
qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)),
459506
name: &node.ql_class_name,
460507
is_abstract: false,
461508
supertypes,
@@ -468,6 +515,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
468515
// It's a tree-sitter supertype node, so we're wrapping a dbscheme
469516
// union type.
470517
classes.push(ql::TopLevel::Class(ql::Class {
518+
qldoc: None,
471519
name: &node.ql_class_name,
472520
is_abstract: false,
473521
supertypes: vec![
@@ -501,6 +549,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
501549

502550
let main_class_name = &node.ql_class_name;
503551
let mut main_class = ql::Class {
552+
qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)),
504553
name: &main_class_name,
505554
is_abstract: false,
506555
supertypes: vec![
@@ -543,6 +592,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
543592
}
544593

545594
main_class.predicates.push(ql::Predicate {
595+
qldoc: Some(String::from("Gets a field or child node of this node.")),
546596
name: "getAFieldOrChild",
547597
overridden: true,
548598
return_type: Some(ql::Type::Normal("AstNode")),

0 commit comments

Comments
 (0)