Merge pull request #31 from github/autogenerate-qldoc

Autogenerate QLDoc for `TreeSitter.qll`
This commit is contained in:
Taus
2021-05-29 16:08:22 +02:00
committed by GitHub
3 changed files with 437 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ impl<'a> fmt::Display for TopLevel<'a> {
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Class<'a> {
pub qldoc: Option<String>,
pub name: &'a str,
pub is_abstract: bool,
pub supertypes: BTreeSet<Type<'a>>,
@@ -26,6 +27,9 @@ pub struct Class<'a> {
impl<'a> fmt::Display for Class<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(qldoc) = &self.qldoc {
write!(f, "/** {} */", qldoc)?;
}
if self.is_abstract {
write!(f, "abstract ")?;
}
@@ -43,6 +47,7 @@ impl<'a> fmt::Display for Class<'a> {
f,
" {}\n",
Predicate {
qldoc: None,
name: self.name.clone(),
overridden: false,
return_type: None,
@@ -176,6 +181,7 @@ impl<'a> fmt::Display for Expression<'a> {
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Predicate<'a> {
pub qldoc: Option<String>,
pub name: &'a str,
pub overridden: bool,
pub return_type: Option<Type<'a>>,
@@ -185,6 +191,9 @@ pub struct Predicate<'a> {
impl<'a> fmt::Display for Predicate<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(qldoc) = &self.qldoc {
write!(f, "/** {} */", qldoc)?;
}
if self.overridden {
write!(f, "override ")?;
}

View File

@@ -29,6 +29,9 @@ pub fn write(language: &Language, classes: &[ql::TopLevel]) -> std::io::Result<(
fn create_ast_node_class<'a>() -> ql::Class<'a> {
// Default implementation of `toString` calls `this.getAPrimaryQlClass()`
let to_string = ql::Predicate {
qldoc: Some(String::from(
"Gets a string representation of this element.",
)),
name: "toString",
overridden: false,
return_type: Some(ql::Type::String),
@@ -42,11 +45,20 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
)),
),
};
let get_location =
create_none_predicate("getLocation", false, Some(ql::Type::Normal("Location")));
let get_a_field_or_child =
create_none_predicate("getAFieldOrChild", false, Some(ql::Type::Normal("AstNode")));
let get_location = create_none_predicate(
Some(String::from("Gets the location of this element.")),
"getLocation",
false,
Some(ql::Type::Normal("Location")),
);
let get_a_field_or_child = create_none_predicate(
Some(String::from("Gets a field or child node of this node.")),
"getAFieldOrChild",
false,
Some(ql::Type::Normal("AstNode")),
);
let get_parent = ql::Predicate {
qldoc: Some(String::from("Gets the parent of this element.")),
name: "getParent",
overridden: false,
return_type: Some(ql::Type::Normal("AstNode")),
@@ -61,6 +73,9 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
),
};
let get_parent_index = ql::Predicate {
qldoc: Some(String::from(
"Gets the index of this node among the children of its parent.",
)),
name: "getParentIndex",
overridden: false,
return_type: Some(ql::Type::Int),
@@ -75,6 +90,9 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
),
};
let get_a_primary_ql_class = ql::Predicate {
qldoc: Some(String::from(
"Gets the name of the primary QL class for this element.",
)),
name: "getAPrimaryQlClass",
overridden: false,
return_type: Some(ql::Type::String),
@@ -85,6 +103,7 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
),
};
ql::Class {
qldoc: Some(String::from("The base class for all AST nodes")),
name: "AstNode",
is_abstract: false,
supertypes: vec![ql::Type::AtType("ast_node")].into_iter().collect(),
@@ -103,6 +122,7 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> {
fn create_token_class<'a>() -> ql::Class<'a> {
let tokeninfo_arity = 6;
let get_value = ql::Predicate {
qldoc: Some(String::from("Gets the value of this token.")),
name: "getValue",
overridden: false,
return_type: Some(ql::Type::String),
@@ -110,6 +130,7 @@ fn create_token_class<'a>() -> ql::Class<'a> {
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 3, tokeninfo_arity),
};
let get_location = ql::Predicate {
qldoc: Some(String::from("Gets the location of this token.")),
name: "getLocation",
overridden: true,
return_type: Some(ql::Type::Normal("Location")),
@@ -117,6 +138,9 @@ fn create_token_class<'a>() -> ql::Class<'a> {
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 4, tokeninfo_arity),
};
let to_string = ql::Predicate {
qldoc: Some(String::from(
"Gets a string representation of this element.",
)),
name: "toString",
overridden: true,
return_type: Some(ql::Type::String),
@@ -127,6 +151,7 @@ fn create_token_class<'a>() -> ql::Class<'a> {
),
};
ql::Class {
qldoc: Some(String::from("A token.")),
name: "Token",
is_abstract: false,
supertypes: vec![ql::Type::AtType("token"), ql::Type::Normal("AstNode")]
@@ -148,6 +173,7 @@ fn create_reserved_word_class<'a>() -> ql::Class<'a> {
let class_name = "ReservedWord";
let get_a_primary_ql_class = create_get_a_primary_ql_class(&class_name);
ql::Class {
qldoc: Some(String::from("A reserved word.")),
name: class_name,
is_abstract: false,
supertypes: vec![ql::Type::AtType(db_name), ql::Type::Normal("Token")]
@@ -160,11 +186,13 @@ fn create_reserved_word_class<'a>() -> ql::Class<'a> {
/// Creates a predicate whose body is `none()`.
fn create_none_predicate<'a>(
qldoc: Option<String>,
name: &'a str,
overridden: bool,
return_type: Option<ql::Type<'a>>,
) -> ql::Predicate<'a> {
ql::Predicate {
qldoc: qldoc,
name: name,
overridden,
return_type,
@@ -177,6 +205,9 @@ fn create_none_predicate<'a>(
/// name.
fn create_get_a_primary_ql_class<'a>(class_name: &'a str) -> ql::Predicate<'a> {
ql::Predicate {
qldoc: Some(String::from(
"Gets the name of the primary QL class for this element.",
)),
name: "getAPrimaryQlClass",
overridden: true,
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> {
/// `arity` - the total number of columns in the table
fn create_get_location_predicate<'a>(def_table: &'a str, arity: usize) -> ql::Predicate<'a> {
ql::Predicate {
qldoc: Some(String::from("Gets the location of this element.")),
name: "getLocation",
overridden: true,
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
/// `def_table` - the name of the table that defines the entity and its text.
fn create_get_text_predicate<'a>(def_table: &'a str) -> ql::Predicate<'a> {
ql::Predicate {
qldoc: Some(String::from("Gets the text content of this element.")),
name: "getText",
overridden: false,
return_type: Some(ql::Type::String),
@@ -419,6 +452,10 @@ fn create_field_getters<'a>(
};
(
ql::Predicate {
qldoc: field
.name
.as_ref()
.map(|name| format!("Gets the node corresponding to the field `{}`.", name)),
name: &field.getter_name,
overridden: false,
return_type,
@@ -456,6 +493,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
supertypes.insert(ql::Type::AtType(&node.dbscheme_name));
supertypes.insert(ql::Type::Normal("Token"));
classes.push(ql::TopLevel::Class(ql::Class {
qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)),
name: &node.ql_class_name,
is_abstract: false,
supertypes,
@@ -468,6 +506,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
// It's a tree-sitter supertype node, so we're wrapping a dbscheme
// union type.
classes.push(ql::TopLevel::Class(ql::Class {
qldoc: None,
name: &node.ql_class_name,
is_abstract: false,
supertypes: vec![
@@ -501,6 +540,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
let main_class_name = &node.ql_class_name;
let mut main_class = ql::Class {
qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)),
name: &main_class_name,
is_abstract: false,
supertypes: vec![
@@ -543,6 +583,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
}
main_class.predicates.push(ql::Predicate {
qldoc: Some(String::from("Gets a field or child node of this node.")),
name: "getAFieldOrChild",
overridden: true,
return_type: Some(ql::Type::Normal("AstNode")),

File diff suppressed because it is too large Load Diff