Skip to content

Commit 17ea0ed

Browse files
committed
Add owned AST directives
1 parent c5665f9 commit 17ea0ed

4 files changed

Lines changed: 232 additions & 12 deletions

File tree

rust/ruby-rbs/src/ast/convert.rs

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ use crate::ast::declarations::{
55
Declaration, GlobalDeclaration, InterfaceDeclaration, ModuleAliasDeclaration,
66
ModuleDeclaration, ModuleMember, ModuleSelf, TypeAliasDeclaration,
77
};
8+
use crate::ast::directives::{
9+
Directive, UseClause, UseDirective, UseSingleClause, UseWildcardClause,
10+
};
811
use crate::ast::location::{
912
AliasDeclarationLocation, AliasLocation, AliasMemberLocation, AttributeMemberLocation,
1013
ClassDeclarationLocation, ClassInstanceLocation, ClassSingletonLocation, ClassSuperLocation,
1114
ConstantDeclarationLocation, FunctionParamLocation, GlobalDeclarationLocation,
1215
InterfaceDeclarationLocation, InterfaceLocation, LocationRange, MethodDefinitionLocation,
1316
MethodTypeLocation, MixinMemberLocation, ModuleDeclarationLocation, ModuleSelfLocation,
14-
TypeAliasDeclarationLocation, TypeParamLocation, VariableMemberLocation,
17+
TypeAliasDeclarationLocation, TypeParamLocation, UseDirectiveLocation, UseSingleClauseLocation,
18+
UseWildcardClauseLocation, VariableMemberLocation,
1519
};
1620
use crate::ast::members::{
1721
AliasKind, AliasMember, AttrAccessorMember, AttrReaderMember, AttrWriterMember, AttributeKind,
@@ -38,9 +42,10 @@ use crate::node::{
3842
FunctionTypeNode, GlobalNode, IncludeNode, InstanceVariableNode, InterfaceNode,
3943
InterfaceTypeNode, MethodDefinitionKind as NodeMethodDefinitionKind, MethodDefinitionNode,
4044
MethodDefinitionOverloadNode, MethodDefinitionVisibility as NodeMethodDefinitionVisibility,
41-
MethodTypeNode, ModuleAliasNode, ModuleNode, ModuleSelfNode, Node, PrependNode, PrivateNode,
42-
PublicNode, RBSLocationRange, SymbolNode, TypeAliasNode, TypeNameNode, TypeParamNode,
43-
TypeParamVariance, UntypedFunctionTypeNode,
45+
MethodTypeNode, ModuleAliasNode, ModuleNode, ModuleSelfNode, NamespaceNode, Node, PrependNode,
46+
PrivateNode, PublicNode, RBSLocationRange, SymbolNode, TypeAliasNode, TypeNameNode,
47+
TypeParamNode, TypeParamVariance, UntypedFunctionTypeNode, UseNode, UseSingleClauseNode,
48+
UseWildcardClauseNode,
4449
};
4550
use crate::type_name::TypeNameInterner;
4651

@@ -108,6 +113,13 @@ impl<'a> AstConverter<'a> {
108113
}
109114
}
110115

116+
pub fn convert_directive(&mut self, node: &Node<'_>) -> Directive {
117+
match node {
118+
Node::Use(node) => Directive::Use(self.convert_use_directive(node)),
119+
_ => panic_expected("directive node while converting directive", node),
120+
}
121+
}
122+
111123
pub fn convert_type(&mut self, node: &Node<'_>) -> Type {
112124
match node {
113125
Node::AliasType(node) => Type::Alias(self.convert_alias_type(node)),
@@ -245,6 +257,53 @@ impl<'a> AstConverter<'a> {
245257
}
246258
}
247259

260+
fn convert_use_directive(&mut self, node: &UseNode<'_>) -> UseDirective {
261+
UseDirective {
262+
clauses: self.convert_use_clauses(node.clauses()),
263+
location: Some(UseDirectiveLocation {
264+
range: convert_range(node.location()),
265+
keyword_range: convert_range(node.keyword_location()),
266+
}),
267+
}
268+
}
269+
270+
fn convert_use_clause(&mut self, node: &Node<'_>) -> UseClause {
271+
match node {
272+
Node::UseSingleClause(node) => UseClause::Single(self.convert_use_single_clause(node)),
273+
Node::UseWildcardClause(node) => {
274+
UseClause::Wildcard(self.convert_use_wildcard_clause(node))
275+
}
276+
_ => panic_expected("use clause node while converting use directive", node),
277+
}
278+
}
279+
280+
fn convert_use_single_clause(&mut self, node: &UseSingleClauseNode<'_>) -> UseSingleClause {
281+
UseSingleClause {
282+
type_name: self.convert_type_name(&node.type_name()),
283+
new_name: node.new_name().map(|name| self.intern_symbol(&name)),
284+
location: Some(UseSingleClauseLocation {
285+
range: convert_range(node.location()),
286+
type_name_range: convert_range(node.type_name_location()),
287+
keyword_range: convert_optional_range(node.keyword_location()),
288+
new_name_range: convert_optional_range(node.new_name_location()),
289+
}),
290+
}
291+
}
292+
293+
fn convert_use_wildcard_clause(
294+
&mut self,
295+
node: &UseWildcardClauseNode<'_>,
296+
) -> UseWildcardClause {
297+
UseWildcardClause {
298+
namespace: self.convert_namespace(&node.namespace()),
299+
location: Some(UseWildcardClauseLocation {
300+
range: convert_range(node.location()),
301+
namespace_range: convert_range(node.namespace_location()),
302+
star_range: convert_range(node.star_location()),
303+
}),
304+
}
305+
}
306+
248307
fn convert_module_declaration(&mut self, node: &ModuleNode<'_>) -> ModuleDeclaration {
249308
ModuleDeclaration {
250309
name: self.convert_type_name(&node.name()),
@@ -757,6 +816,12 @@ impl<'a> AstConverter<'a> {
757816
.collect()
758817
}
759818

819+
fn convert_use_clauses(&mut self, list: crate::node::NodeList<'_>) -> Vec<UseClause> {
820+
list.iter()
821+
.map(|node| self.convert_use_clause(&node))
822+
.collect()
823+
}
824+
760825
fn convert_class_members(&mut self, list: crate::node::NodeList<'_>) -> Vec<ClassMember> {
761826
list.iter()
762827
.map(|node| match node {
@@ -946,9 +1011,14 @@ impl<'a> AstConverter<'a> {
9461011
}
9471012

9481013
fn convert_type_name(&mut self, node: &TypeNameNode<'_>) -> TypeName {
949-
let namespace = node.namespace();
950-
let mut name = self.type_names.root(namespace.absolute());
951-
for segment_node in namespace.path().iter() {
1014+
let name = self.convert_namespace(&node.namespace());
1015+
let final_segment = self.intern_symbol(&node.name());
1016+
self.type_names.append(name, final_segment)
1017+
}
1018+
1019+
fn convert_namespace(&mut self, node: &NamespaceNode<'_>) -> TypeName {
1020+
let mut name = self.type_names.root(node.absolute());
1021+
for segment_node in node.path().iter() {
9521022
match segment_node {
9531023
Node::Symbol(segment) => {
9541024
let segment = self.intern_symbol(&segment);
@@ -960,8 +1030,7 @@ impl<'a> AstConverter<'a> {
9601030
),
9611031
}
9621032
}
963-
let final_segment = self.intern_symbol(&node.name());
964-
self.type_names.append(name, final_segment)
1033+
name
9651034
}
9661035

9671036
fn intern_symbol(&mut self, node: &SymbolNode<'_>) -> SymbolId {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use crate::ast::location::{
2+
ResolveTypeNamesDirectiveLocation, UseDirectiveLocation, UseSingleClauseLocation,
3+
UseWildcardClauseLocation,
4+
};
5+
use crate::ids::{SymbolId, TypeName};
6+
7+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
8+
pub enum Directive {
9+
Use(UseDirective),
10+
ResolveTypeNames(ResolveTypeNamesDirective),
11+
}
12+
13+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
14+
pub struct UseDirective {
15+
pub clauses: Vec<UseClause>,
16+
pub location: Option<UseDirectiveLocation>,
17+
}
18+
19+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
20+
pub enum UseClause {
21+
Single(UseSingleClause),
22+
Wildcard(UseWildcardClause),
23+
}
24+
25+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
26+
pub struct UseSingleClause {
27+
pub type_name: TypeName,
28+
pub new_name: Option<SymbolId>,
29+
pub location: Option<UseSingleClauseLocation>,
30+
}
31+
32+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
33+
pub struct UseWildcardClause {
34+
pub namespace: TypeName,
35+
pub location: Option<UseWildcardClauseLocation>,
36+
}
37+
38+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
39+
pub struct ResolveTypeNamesDirective {
40+
pub value: bool,
41+
pub location: Option<ResolveTypeNamesDirectiveLocation>,
42+
}

rust/ruby-rbs/src/ast/location.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,55 @@ pub struct AliasMemberLocation {
385385
pub new_kind_range: Option<LocationRange>,
386386
pub old_kind_range: Option<LocationRange>,
387387
}
388+
389+
/// ```rbs
390+
/// use Foo
391+
/// ^^^ keyword
392+
/// ```
393+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
394+
pub struct UseDirectiveLocation {
395+
pub range: LocationRange,
396+
pub keyword_range: LocationRange,
397+
}
398+
399+
/// ```rbs
400+
/// Foo::Bar
401+
/// ^^^^^^^^ type_name
402+
///
403+
/// Foo::Bar as X
404+
/// ^^ keyword
405+
/// ^ new_name
406+
/// ```
407+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
408+
pub struct UseSingleClauseLocation {
409+
pub range: LocationRange,
410+
pub type_name_range: LocationRange,
411+
pub keyword_range: Option<LocationRange>,
412+
pub new_name_range: Option<LocationRange>,
413+
}
414+
415+
/// ```rbs
416+
/// Foo::Bar::*
417+
/// ^^^^^^^^^^ namespace
418+
/// ^ star
419+
/// ```
420+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
421+
pub struct UseWildcardClauseLocation {
422+
pub range: LocationRange,
423+
pub namespace_range: LocationRange,
424+
pub star_range: LocationRange,
425+
}
426+
427+
/// ```rbs
428+
/// # resolve-type-names: false
429+
/// ^^^^^^^^^^^^^^^^^^ keyword
430+
/// ^ colon
431+
/// ^^^^^ value
432+
/// ```
433+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
434+
pub struct ResolveTypeNamesDirectiveLocation {
435+
pub range: LocationRange,
436+
pub keyword_range: LocationRange,
437+
pub colon_range: LocationRange,
438+
pub value_range: LocationRange,
439+
}

rust/ruby-rbs/src/ast/mod.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod annotation;
1111
pub mod comment;
1212
pub mod convert;
1313
pub mod declarations;
14+
pub mod directives;
1415
pub mod location;
1516
pub mod members;
1617
pub mod method_type;
@@ -25,13 +26,19 @@ pub use declarations::{
2526
Declaration, GlobalDeclaration, InterfaceDeclaration, ModuleAliasDeclaration,
2627
ModuleDeclaration, ModuleMember, ModuleSelf, TypeAliasDeclaration,
2728
};
29+
pub use directives::{
30+
Directive, ResolveTypeNamesDirective, UseClause, UseDirective, UseSingleClause,
31+
UseWildcardClause,
32+
};
2833
pub use location::{
2934
AliasDeclarationLocation, AliasLocation, AliasMemberLocation, AttributeMemberLocation,
3035
ClassDeclarationLocation, ClassInstanceLocation, ClassSingletonLocation, ClassSuperLocation,
3136
ConstantDeclarationLocation, FunctionParamLocation, GlobalDeclarationLocation,
3237
InterfaceDeclarationLocation, InterfaceLocation, LocationRange, MethodDefinitionLocation,
3338
MethodTypeLocation, MixinMemberLocation, ModuleDeclarationLocation, ModuleSelfLocation,
34-
TypeAliasDeclarationLocation, TypeParamLocation, VariableMemberLocation,
39+
ResolveTypeNamesDirectiveLocation, TypeAliasDeclarationLocation, TypeParamLocation,
40+
UseDirectiveLocation, UseSingleClauseLocation, UseWildcardClauseLocation,
41+
VariableMemberLocation,
3542
};
3643
pub use members::{
3744
AliasKind, AliasMember, AttrAccessorMember, AttrReaderMember, AttrWriterMember, AttributeKind,
@@ -51,8 +58,8 @@ pub use types::{
5158
#[cfg(test)]
5259
mod tests {
5360
use crate::ast::{
54-
AstConverter, BaseType, BaseTypeKind, ClassMember, Declaration, IvarName, Literal, Member,
55-
MethodKind, ModuleMember, RecordKey, Type,
61+
AstConverter, BaseType, BaseTypeKind, ClassMember, Declaration, Directive, IvarName,
62+
Literal, Member, MethodKind, ModuleMember, RecordKey, Type, UseClause,
5663
};
5764
use crate::interner::StringInterner;
5865
use crate::node::{Node, parse};
@@ -267,4 +274,54 @@ mod tests {
267274
};
268275
assert_eq!(type_names.display(module_alias.old_name, &strings), "NewM");
269276
}
277+
278+
#[test]
279+
fn converts_directives_to_owned_ast() {
280+
let signature = parse(
281+
r#"
282+
use Foo, Foo::Bar as FBar, Foo::Baz::*
283+
284+
class Foo
285+
end
286+
"#,
287+
)
288+
.unwrap();
289+
290+
let mut strings = StringInterner::new();
291+
let mut type_names = TypeNameInterner::new();
292+
let mut converter = AstConverter::new(&mut strings, &mut type_names);
293+
let directives = signature
294+
.directives()
295+
.iter()
296+
.map(|node| converter.convert_directive(&node))
297+
.collect::<Vec<_>>();
298+
299+
assert_eq!(directives.len(), 1);
300+
301+
let Directive::Use(use_directive) = &directives[0] else {
302+
panic!("expected use directive");
303+
};
304+
assert_eq!(use_directive.clauses.len(), 3);
305+
assert!(use_directive.location.is_some());
306+
307+
let UseClause::Single(single) = &use_directive.clauses[0] else {
308+
panic!("expected single use clause");
309+
};
310+
assert_eq!(type_names.display(single.type_name, &strings), "Foo");
311+
assert_eq!(single.new_name, None);
312+
313+
let UseClause::Single(aliased) = &use_directive.clauses[1] else {
314+
panic!("expected aliased single use clause");
315+
};
316+
assert_eq!(type_names.display(aliased.type_name, &strings), "Foo::Bar");
317+
assert_eq!(aliased.new_name, Some(strings.intern("FBar")));
318+
assert!(aliased.location.as_ref().unwrap().keyword_range.is_some());
319+
assert!(aliased.location.as_ref().unwrap().new_name_range.is_some());
320+
321+
let UseClause::Wildcard(wildcard) = &use_directive.clauses[2] else {
322+
panic!("expected wildcard use clause");
323+
};
324+
assert_eq!(type_names.display(wildcard.namespace, &strings), "Foo::Baz");
325+
assert!(wildcard.location.is_some());
326+
}
270327
}

0 commit comments

Comments
 (0)