Skip to content

Commit 783ee1e

Browse files
committed
Add owned Rust AST types
1 parent d1bcab9 commit 783ee1e

10 files changed

Lines changed: 971 additions & 0 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use crate::ast::location::LocationRange;
2+
use crate::ids::SymbolId;
3+
4+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
5+
pub struct Annotation {
6+
pub string: SymbolId,
7+
pub location: Option<LocationRange>,
8+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use crate::ast::location::LocationRange;
2+
use crate::ids::SymbolId;
3+
4+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
5+
pub struct Comment {
6+
pub string: SymbolId,
7+
pub location: Option<LocationRange>,
8+
}

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

Lines changed: 485 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/// A byte and character range in the source buffer.
2+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
3+
pub struct LocationRange {
4+
pub start_char: u32,
5+
pub start_byte: u32,
6+
pub end_char: u32,
7+
pub end_byte: u32,
8+
}
9+
10+
impl LocationRange {
11+
#[must_use]
12+
pub fn new(start_char: u32, start_byte: u32, end_char: u32, end_byte: u32) -> Self {
13+
Self {
14+
start_char,
15+
start_byte,
16+
end_char,
17+
end_byte,
18+
}
19+
}
20+
}
21+
22+
/// ```rbs
23+
/// foo
24+
/// ^^^ name
25+
///
26+
/// foo[bar, baz]
27+
/// ^^^ name
28+
/// ^^^^^^^^^^ args
29+
/// ```
30+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
31+
pub struct AliasLocation {
32+
pub range: LocationRange,
33+
pub name_range: LocationRange,
34+
pub args_range: Option<LocationRange>,
35+
}
36+
37+
/// ```rbs
38+
/// Foo
39+
/// ^^^ name
40+
///
41+
/// Foo[Bar, Baz]
42+
/// ^^^ name
43+
/// ^^^^^^^^^^ args
44+
/// ```
45+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
46+
pub struct ClassInstanceLocation {
47+
pub range: LocationRange,
48+
pub name_range: LocationRange,
49+
pub args_range: Option<LocationRange>,
50+
}
51+
52+
/// ```rbs
53+
/// singleton(::Foo)
54+
/// ^^^^^ name
55+
/// ```
56+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
57+
pub struct ClassSingletonLocation {
58+
pub range: LocationRange,
59+
pub name_range: LocationRange,
60+
pub args_range: Option<LocationRange>,
61+
}
62+
63+
/// ```rbs
64+
/// String name
65+
/// ^^^^ name
66+
/// ```
67+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
68+
pub struct FunctionParamLocation {
69+
pub range: LocationRange,
70+
pub name_range: Option<LocationRange>,
71+
}
72+
73+
/// ```rbs
74+
/// _Foo
75+
/// ^^^^ name
76+
///
77+
/// _Foo[Bar, Baz]
78+
/// ^^^^ name
79+
/// ^^^^^^^^^^ args
80+
/// ```
81+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
82+
pub struct InterfaceLocation {
83+
pub range: LocationRange,
84+
pub name_range: LocationRange,
85+
pub args_range: Option<LocationRange>,
86+
}
87+
88+
/// ```rbs
89+
/// () -> void
90+
/// ^^^^^^^^^^ type
91+
///
92+
/// [A] () { () -> A } -> A
93+
/// ^^^ type_params
94+
/// ^^^^^^^^^^^^^^^^^^^ type
95+
/// ```
96+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
97+
pub struct MethodTypeLocation {
98+
pub range: LocationRange,
99+
pub type_range: LocationRange,
100+
pub type_params_range: Option<LocationRange>,
101+
}
102+
103+
/// ```rbs
104+
/// Key
105+
/// ^^^ name
106+
///
107+
/// unchecked out Elem < _ToJson > bot = untyped
108+
/// ^^^^^^^^^ unchecked
109+
/// ^^^ variance
110+
/// ^^^^ name
111+
/// ^^^^^^^^^ upper_bound
112+
/// ^^^^^ lower_bound
113+
/// ^^^^^^^^ default
114+
/// ```
115+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
116+
pub struct TypeParamLocation {
117+
pub range: LocationRange,
118+
pub name_range: LocationRange,
119+
pub variance_range: Option<LocationRange>,
120+
pub unchecked_range: Option<LocationRange>,
121+
pub upper_bound_range: Option<LocationRange>,
122+
pub lower_bound_range: Option<LocationRange>,
123+
pub default_range: Option<LocationRange>,
124+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use crate::ast::location::MethodTypeLocation;
2+
use crate::ast::type_param::TypeParam;
3+
use crate::ast::types::{BlockType, Function};
4+
5+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6+
pub struct MethodType {
7+
pub type_params: Vec<TypeParam>,
8+
pub function: Function,
9+
pub block: Option<BlockType>,
10+
pub location: Option<MethodTypeLocation>,
11+
}

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

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! Owned pure-Rust AST data structures.
2+
//!
3+
//! The [`node`] module exposes borrowed wrappers over the C parser AST. This
4+
//! module is the Rust-owned representation that can be built from parser nodes,
5+
//! generated directly, or transformed without keeping the parser allocation
6+
//! alive.
7+
//!
8+
//! [`node`]: crate::node
9+
10+
pub mod annotation;
11+
pub mod comment;
12+
pub mod convert;
13+
pub mod location;
14+
pub mod method_type;
15+
pub mod type_param;
16+
pub mod types;
17+
18+
pub use annotation::Annotation;
19+
pub use comment::Comment;
20+
pub use convert::AstConverter;
21+
pub use location::{
22+
AliasLocation, ClassInstanceLocation, ClassSingletonLocation, FunctionParamLocation,
23+
InterfaceLocation, LocationRange, MethodTypeLocation, TypeParamLocation,
24+
};
25+
pub use method_type::MethodType;
26+
pub use type_param::{TypeParam, Variance};
27+
pub use types::{
28+
AliasType, BaseType, BaseTypeKind, BlockType, ClassInstanceType, ClassSingletonType, Function,
29+
FunctionParam, FunctionType, InterfaceType, IntersectionType, KeywordParam, Literal,
30+
LiteralType, OptionalType, ProcType, RecordField, RecordKey, RecordType, TupleType, Type,
31+
UnionType, UntypedFunctionType, VariableType,
32+
};
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use crate::ast::{AstConverter, BaseType, BaseTypeKind, Literal, RecordKey, Type};
37+
use crate::interner::StringInterner;
38+
use crate::node::{Node, parse};
39+
use crate::type_name::TypeNameInterner;
40+
41+
#[test]
42+
fn builds_owned_type_ast() {
43+
let ty = Type::Base(BaseType {
44+
kind: BaseTypeKind::Any { todo: false },
45+
location: None,
46+
});
47+
48+
assert_eq!(
49+
ty,
50+
Type::Base(BaseType {
51+
kind: BaseTypeKind::Any { todo: false },
52+
location: None,
53+
})
54+
);
55+
}
56+
57+
#[test]
58+
fn converts_type_node_to_owned_ast() {
59+
let signature = parse(
60+
r#"type foo = {
61+
name: String,
62+
?age: Integer,
63+
active: true,
64+
tags: Array[String | Symbol]
65+
}"#,
66+
)
67+
.unwrap();
68+
69+
let Node::TypeAlias(alias) = signature.declarations().iter().next().unwrap() else {
70+
panic!("expected type alias");
71+
};
72+
73+
let mut strings = StringInterner::new();
74+
let mut type_names = TypeNameInterner::new();
75+
let mut converter = AstConverter::new(&mut strings, &mut type_names);
76+
let ty = converter.convert_type(&alias.type_());
77+
78+
let Type::Record(record) = ty else {
79+
panic!("expected record type");
80+
};
81+
82+
assert_eq!(record.fields.len(), 4);
83+
assert_eq!(
84+
record.fields[0].key,
85+
RecordKey::Symbol(strings.intern("name"))
86+
);
87+
assert!(record.fields[0].required);
88+
assert_eq!(
89+
record.fields[1].key,
90+
RecordKey::Symbol(strings.intern("age"))
91+
);
92+
assert!(!record.fields[1].required);
93+
94+
let Type::Literal(literal) = &record.fields[2].ty else {
95+
panic!("expected literal type");
96+
};
97+
assert_eq!(literal.literal, Literal::Bool(true));
98+
99+
let Type::ClassInstance(array) = &record.fields[3].ty else {
100+
panic!("expected Array class instance");
101+
};
102+
assert_eq!(type_names.display(array.name, &strings), "Array");
103+
assert_eq!(array.args.len(), 1);
104+
}
105+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use crate::ast::location::TypeParamLocation;
2+
use crate::ast::types::Type;
3+
use crate::ids::SymbolId;
4+
5+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
6+
pub enum Variance {
7+
Invariant,
8+
Covariant,
9+
Contravariant,
10+
}
11+
12+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
13+
pub struct TypeParam {
14+
pub name: SymbolId,
15+
pub variance: Variance,
16+
pub upper_bound: Option<Type>,
17+
pub lower_bound: Option<Type>,
18+
pub default_type: Option<Type>,
19+
pub unchecked: bool,
20+
pub location: Option<TypeParamLocation>,
21+
}

0 commit comments

Comments
 (0)