Skip to content

Commit cfff4db

Browse files
committed
tree-sitter-extractor: Generate plural getters
1 parent c1c41c8 commit cfff4db

2 files changed

Lines changed: 51 additions & 16 deletions

File tree

shared/tree-sitter-extractor/src/generator/ql_gen.rs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,11 @@ fn create_get_field_expr_for_table_storage<'a>(
606606
)
607607
}
608608

609-
/// Creates a pair consisting of a predicate to get the given field, and an
610-
/// optional expression that will get the same field. When the field can occur
611-
/// multiple times, the predicate will take an index argument, while the
612-
/// expression will use the "don't care" expression to hold for all occurrences.
609+
/// Creates a list of predicates to get the given field, and an optional
610+
/// expression that will get the same field. When the field can occur multiple
611+
/// times, this includes an indexed getter and a convenience getter that returns
612+
/// any member; the expression uses the "don't care" expression to hold for all
613+
/// occurrences.
613614
///
614615
/// # Arguments
615616
///
@@ -627,7 +628,7 @@ fn create_field_getters<'a>(
627628
main_table_column_index: &mut usize,
628629
field: &'a node_types::Field,
629630
nodes: &'a node_types::NodeTypeMap,
630-
) -> (ql::Predicate<'a>, Option<ql::Expression<'a>>) {
631+
) -> (Vec<ql::Predicate<'a>>, Option<ql::Expression<'a>>) {
631632
let return_type = match &field.type_info {
632633
node_types::FieldTypeInfo::Single(t) => {
633634
Some(ql::Type::Facade(&nodes.get(t).unwrap().ql_class_name))
@@ -751,20 +752,40 @@ fn create_field_getters<'a>(
751752
}
752753
}
753754
};
754-
(
755-
ql::Predicate {
756-
qldoc: Some(qldoc),
757-
name: &field.getter_name,
755+
let mut predicates = vec![ql::Predicate {
756+
qldoc: Some(qldoc.clone()),
757+
name: &field.getter_name,
758+
overridden: false,
759+
is_private: false,
760+
is_final: true,
761+
return_type: return_type.clone(),
762+
formal_parameters,
763+
body,
764+
overlay: None,
765+
}];
766+
767+
if let Some(any_getter_name) = &field.any_getter_name {
768+
predicates.push(ql::Predicate {
769+
qldoc: Some(qldoc.clone()),
770+
name: any_getter_name,
758771
overridden: false,
759772
is_private: false,
760773
is_final: true,
761774
return_type,
762-
formal_parameters,
763-
body,
775+
formal_parameters: vec![],
776+
body: ql::Expression::Equals(
777+
Box::new(ql::Expression::Var("result")),
778+
Box::new(ql::Expression::Dot(
779+
Box::new(ql::Expression::Var("this")),
780+
&field.getter_name,
781+
vec![ql::Expression::Var("_")],
782+
)),
783+
),
764784
overlay: None,
765-
},
766-
optional_expr,
767-
)
785+
});
786+
}
787+
788+
(predicates, optional_expr)
768789
}
769790

770791
fn compute_direct_supertypes(
@@ -902,14 +923,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
902923
// - predicates to access the fields,
903924
// - the QL expressions to access the fields that will be part of getAFieldOrChild.
904925
for field in fields {
905-
let (get_pred, get_child_expr) = create_field_getters(
926+
let (get_preds, get_child_expr) = create_field_getters(
906927
main_table_name,
907928
main_table_arity,
908929
&mut main_table_column_index,
909930
field,
910931
nodes,
911932
);
912-
main_class.predicates.push(get_pred);
933+
main_class.predicates.extend(get_preds);
913934
if let Some(get_child_expr) = get_child_expr {
914935
get_child_exprs.push(get_child_expr)
915936
}

shared/tree-sitter-extractor/src/node_types.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub struct Field {
5656
pub name: Option<String>,
5757
/// The name of the predicate to get this field.
5858
pub getter_name: String,
59+
/// For plural fields, the name of a convenience getter that returns
60+
/// any member (for example `getAnArgument` for `getArgument(i)`).
61+
pub any_getter_name: Option<String>,
5962
pub storage: Storage,
6063
}
6164

@@ -281,6 +284,16 @@ fn add_field(
281284
"get{}",
282285
dbscheme_name_to_class_name(&escape_name(&name_for_field_or_child(&field_name)))
283286
);
287+
let getter_suffix = getter_name.strip_prefix("get").unwrap_or(&getter_name);
288+
let article = match getter_suffix.chars().next().map(|c| c.to_ascii_lowercase()) {
289+
Some('a' | 'e' | 'i' | 'o' | 'u') => "An",
290+
_ => "A",
291+
};
292+
let any_getter_name = if field_info.multiple {
293+
Some(format!("get{article}{getter_suffix}"))
294+
} else {
295+
None
296+
};
284297
fields.push(Field {
285298
parent: TypeName {
286299
kind: parent_type_name.kind.to_string(),
@@ -289,6 +302,7 @@ fn add_field(
289302
type_info,
290303
name: field_name,
291304
getter_name,
305+
any_getter_name,
292306
storage,
293307
});
294308
}

0 commit comments

Comments
 (0)