Skip to content

Commit 1345fa9

Browse files
authored
Merge pull request #31 from github/autogenerate-qldoc
Autogenerate QLDoc for `TreeSitter.qll`
2 parents e57f9e9 + 18fc76f commit 1345fa9

3 files changed

Lines changed: 437 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: 45 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),
@@ -419,6 +452,10 @@ fn create_field_getters<'a>(
419452
};
420453
(
421454
ql::Predicate {
455+
qldoc: field
456+
.name
457+
.as_ref()
458+
.map(|name| format!("Gets the node corresponding to the field `{}`.", name)),
422459
name: &field.getter_name,
423460
overridden: false,
424461
return_type,
@@ -456,6 +493,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
456493
supertypes.insert(ql::Type::AtType(&node.dbscheme_name));
457494
supertypes.insert(ql::Type::Normal("Token"));
458495
classes.push(ql::TopLevel::Class(ql::Class {
496+
qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)),
459497
name: &node.ql_class_name,
460498
is_abstract: false,
461499
supertypes,
@@ -468,6 +506,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
468506
// It's a tree-sitter supertype node, so we're wrapping a dbscheme
469507
// union type.
470508
classes.push(ql::TopLevel::Class(ql::Class {
509+
qldoc: None,
471510
name: &node.ql_class_name,
472511
is_abstract: false,
473512
supertypes: vec![
@@ -501,6 +540,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
501540

502541
let main_class_name = &node.ql_class_name;
503542
let mut main_class = ql::Class {
543+
qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)),
504544
name: &main_class_name,
505545
is_abstract: false,
506546
supertypes: vec![
@@ -543,6 +583,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
543583
}
544584

545585
main_class.predicates.push(ql::Predicate {
586+
qldoc: Some(String::from("Gets a field or child node of this node.")),
546587
name: "getAFieldOrChild",
547588
overridden: true,
548589
return_type: Some(ql::Type::Normal("AstNode")),

0 commit comments

Comments
 (0)