Skip to content

Commit 7ee0ac2

Browse files
committed
tree-sitter-extractor: Move final aliases into sibling module
The split between private, non-final Impl classes and public final classes ultimately prevented the facade AST from instrumenting base classes like 'Expr' and have its subclasses actually inherit those members. This commit takes a step towards fixing that by moving the final aliases into a separate module and making the other classes public and stripping their Impl suffix. It is up to each language to avoid leaking the non-final classes (which Ruby and QL4QL don't do anyway).
1 parent 33cd8d2 commit 7ee0ac2

2 files changed

Lines changed: 99 additions & 87 deletions

File tree

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

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,16 @@ pub fn generate(
135135
alias: Some("F"),
136136
}));
137137

138-
for c in ql_gen::create_ast_node_class(
138+
body.push(ql::TopLevel::Class(ql_gen::create_ast_node_class(
139139
&ast_node_name,
140140
&node_location_table_name,
141141
&node_parent_table_name,
142-
) {
143-
body.push(ql::TopLevel::Class(c));
144-
}
142+
)));
145143

146-
for c in ql_gen::create_token_class(&token_name, &tokeninfo_name) {
147-
body.push(ql::TopLevel::Class(c));
148-
}
144+
body.push(ql::TopLevel::Class(ql_gen::create_token_class(
145+
&token_name,
146+
&tokeninfo_name,
147+
)));
149148

150149
if has_trivia_tokens {
151150
body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class(
@@ -179,14 +178,53 @@ pub fn generate(
179178

180179
body.append(&mut ql_gen::convert_nodes(&nodes));
181180
body.push(ql_gen::create_print_ast_module(&nodes));
181+
let mut final_body = vec![
182+
ql::TopLevel::Import(ql::Import {
183+
is_private: true,
184+
module: &facade_import_name,
185+
alias: Some("F"),
186+
}),
187+
ql::TopLevel::Import(ql::Import {
188+
is_private: false,
189+
module: "F",
190+
alias: None,
191+
}),
192+
];
193+
let final_aliases = body
194+
.iter()
195+
.filter_map(|decl| match decl {
196+
ql::TopLevel::Class(c) => Some(ql::TopLevel::Class(ql::Class {
197+
qldoc: None,
198+
name: c.name,
199+
is_abstract: false,
200+
is_final: true,
201+
is_private: false,
202+
supertypes: Set::new(),
203+
characteristic_predicate: None,
204+
predicates: vec![],
205+
alias: Some(format!("F::{}", c.name)),
206+
})),
207+
_ => None,
208+
})
209+
.collect::<Vec<_>>();
210+
final_body.extend(final_aliases);
211+
let final_module_name = format!("{}Final", language.name);
182212
ql::write(
183213
&mut ql_writer,
184-
&[ql::TopLevel::Module(ql::Module {
185-
qldoc: None,
186-
name: &language.name,
187-
body,
188-
overlay: Some(ql::OverlayAnnotation::Local),
189-
})],
214+
&[
215+
ql::TopLevel::Module(ql::Module {
216+
qldoc: None,
217+
name: &language.name,
218+
body,
219+
overlay: Some(ql::OverlayAnnotation::Local),
220+
}),
221+
ql::TopLevel::Module(ql::Module {
222+
qldoc: None,
223+
name: &final_module_name,
224+
body: final_body,
225+
overlay: None,
226+
}),
227+
],
190228
)?;
191229
}
192230
Ok(())

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

Lines changed: 48 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub fn create_ast_node_class<'a>(
88
ast_node: &'a str,
99
node_location_table: &'a str,
1010
node_parent_table: &'a str,
11-
) -> [ql::Class<'a>; 2] {
11+
) -> ql::Class<'a> {
1212
// Default implementation of `toString` calls `this.getAPrimaryQlClass()`
1313
let to_string = ql::Predicate {
1414
qldoc: Some(String::from(
@@ -132,41 +132,28 @@ pub fn create_ast_node_class<'a>(
132132
),
133133
overlay: None,
134134
};
135-
[
136-
ql::Class {
137-
qldoc: Some(String::from("The base class for all AST nodes")),
138-
name: "AstNodeImpl",
139-
is_abstract: false,
140-
is_final: false,
141-
is_private: true,
142-
alias: None,
143-
supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(),
144-
characteristic_predicate: None,
145-
predicates: vec![
146-
to_string,
147-
get_location,
148-
get_parent,
149-
get_parent_index,
150-
get_a_field_or_child,
151-
get_a_primary_ql_class,
152-
get_primary_ql_classes,
153-
],
154-
},
155-
ql::Class {
156-
qldoc: None,
157-
name: "AstNode",
158-
is_abstract: false,
159-
is_final: true,
160-
is_private: false,
161-
alias: Some("AstNodeImpl".to_string()),
162-
supertypes: vec![].into_iter().collect(),
163-
characteristic_predicate: None,
164-
predicates: vec![],
165-
},
166-
]
135+
ql::Class {
136+
qldoc: Some(String::from("The base class for all AST nodes")),
137+
name: "AstNode",
138+
is_abstract: false,
139+
is_final: false,
140+
is_private: false,
141+
alias: None,
142+
supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(),
143+
characteristic_predicate: None,
144+
predicates: vec![
145+
to_string,
146+
get_location,
147+
get_parent,
148+
get_parent_index,
149+
get_a_field_or_child,
150+
get_a_primary_ql_class,
151+
get_primary_ql_classes,
152+
],
153+
}
167154
}
168155

169-
pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::Class<'a>; 2] {
156+
pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Class<'a> {
170157
let tokeninfo_arity = 3; // id, kind, value
171158
let get_value = ql::Predicate {
172159
qldoc: Some(String::from("Gets the value of this token.")),
@@ -199,36 +186,23 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::C
199186
),
200187
overlay: None,
201188
};
202-
[
203-
ql::Class {
204-
qldoc: Some(String::from("A token.")),
205-
name: "TokenImpl",
206-
is_abstract: false,
207-
is_final: false,
208-
is_private: true,
209-
alias: None,
210-
supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNodeImpl")]
211-
.into_iter()
212-
.collect(),
213-
characteristic_predicate: None,
214-
predicates: vec![
215-
get_value,
216-
to_string,
217-
create_get_a_primary_ql_class("Token", false),
218-
],
219-
},
220-
ql::Class {
221-
qldoc: None,
222-
name: "Token",
223-
is_abstract: false,
224-
is_final: true,
225-
is_private: false,
226-
alias: Some("TokenImpl".to_string()),
227-
supertypes: vec![].into_iter().collect(),
228-
characteristic_predicate: None,
229-
predicates: vec![],
230-
},
231-
]
189+
ql::Class {
190+
qldoc: Some(String::from("A token.")),
191+
name: "Token",
192+
is_abstract: false,
193+
is_final: false,
194+
is_private: false,
195+
alias: None,
196+
supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNode")]
197+
.into_iter()
198+
.collect(),
199+
characteristic_predicate: None,
200+
predicates: vec![
201+
get_value,
202+
to_string,
203+
create_get_a_primary_ql_class("Token", false),
204+
],
205+
}
232206
}
233207

234208
/// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are
@@ -283,12 +257,12 @@ pub fn create_trivia_token_class<'a>(
283257
)),
284258
name: "TriviaToken",
285259
is_abstract: false,
286-
is_final: true,
260+
is_final: false,
287261
is_private: false,
288262
alias: None,
289263
supertypes: vec![
290264
ql::Type::At(trivia_token_type),
291-
ql::Type::Normal("AstNodeImpl"),
265+
ql::Type::Normal("AstNode"),
292266
]
293267
.into_iter()
294268
.collect(),
@@ -309,10 +283,10 @@ pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> {
309283
qldoc: Some(String::from("A reserved word.")),
310284
name: class_name,
311285
is_abstract: false,
312-
is_final: true,
286+
is_final: false,
313287
is_private: false,
314288
alias: None,
315-
supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("TokenImpl")]
289+
supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("Token")]
316290
.into_iter()
317291
.collect(),
318292
characteristic_predicate: None,
@@ -816,12 +790,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
816790
create_get_a_primary_ql_class(&node.ql_class_name, true);
817791
let mut supertypes: BTreeSet<ql::Type> = BTreeSet::new();
818792
supertypes.insert(ql::Type::At(&node.dbscheme_name));
819-
supertypes.insert(ql::Type::Normal("TokenImpl"));
793+
supertypes.insert(ql::Type::Normal("Token"));
820794
classes.push(ql::TopLevel::Class(ql::Class {
821795
qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)),
822796
name: &node.ql_class_name,
823797
is_abstract: false,
824-
is_final: true,
798+
is_final: false,
825799
is_private: false,
826800
alias: None,
827801
supertypes,
@@ -837,12 +811,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
837811
qldoc: None,
838812
name: &node.ql_class_name,
839813
is_abstract: false,
840-
is_final: true,
814+
is_final: false,
841815
is_private: false,
842816
alias: None,
843817
supertypes: vec![
844818
ql::Type::At(&node.dbscheme_name),
845-
ql::Type::Normal("AstNodeImpl"),
819+
ql::Type::Normal("AstNode"),
846820
]
847821
.into_iter()
848822
.collect(),
@@ -871,12 +845,12 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec<ql::TopLevel<'_>> {
871845
qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)),
872846
name: main_class_name,
873847
is_abstract: false,
874-
is_final: true,
848+
is_final: false,
875849
is_private: false,
876850
alias: None,
877851
supertypes: vec![
878852
ql::Type::At(&node.dbscheme_name),
879-
ql::Type::Normal("AstNodeImpl"),
853+
ql::Type::Normal("AstNode"),
880854
]
881855
.into_iter()
882856
.collect(),

0 commit comments

Comments
 (0)