rubydex 0.2.4-aarch64-linux → 0.2.5-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,284 @@
1
+ //! Operations represent the ordered actions extracted from Ruby/RBS source code.
2
+ //!
3
+ //! Unlike definitions (which are unordered and declarative), operations are ordered and imperative.
4
+ //! They model what Ruby actually does at execution time: define a class, define a method, change
5
+ //! visibility, include a module, etc.
6
+ //!
7
+ //! Each operation is self-contained: it carries enough context (`name_id`, etc.) to know what it
8
+ //! defines, while scope context is provided by surrounding Enter/Exit scope operations.
9
+ //!
10
+ //! The builder produces a `Vec<Operation>` for each file. These operations are then applied in order
11
+ //! by the applier to produce definitions and declarations in the graph.
12
+ //!
13
+ //! # Example
14
+ //!
15
+ //! ```ruby
16
+ //! class Foo
17
+ //! def bar; end
18
+ //! private :bar
19
+ //! end
20
+ //! ```
21
+ //!
22
+ //! Produces the operations:
23
+ //! 1. `EnterClass` (name: Foo)
24
+ //! 2. `EnterMethod` (name: bar)
25
+ //! 3. `ExitScope` # exit method bar
26
+ //! 4. `SetMethodVisibility` (name: bar, visibility: private)
27
+ //! 5. `ExitScope` # exit class Foo
28
+
29
+ pub mod applier;
30
+ pub mod printer;
31
+ pub mod ruby_builder;
32
+
33
+ use crate::model::{
34
+ comment::Comment,
35
+ definitions::{DefinitionFlags, Signatures},
36
+ ids::{NameId, StringId, UriId},
37
+ visibility::Visibility,
38
+ };
39
+ use crate::offset::Offset;
40
+
41
+ /// An ordered instruction extracted from Ruby/RBS source code.
42
+ ///
43
+ /// Operations are produced by the builder in the order they appear in the source file.
44
+ /// Scope context is established by Enter/Exit operations rather than carried on each variant.
45
+ #[derive(Debug)]
46
+ pub enum Operation {
47
+ /// Enter a class scope (`class Foo` or `Class.new`).
48
+ EnterClass(EnterClass),
49
+ /// Enter a module scope (`module Foo` or `Module.new`).
50
+ EnterModule(EnterModule),
51
+ /// Enter a singleton class scope (`class << self` or `class << Foo`).
52
+ EnterSingletonClass(EnterSingletonClass),
53
+ /// Enter a method scope (`def foo` or `def self.foo`).
54
+ EnterMethod(EnterMethod),
55
+ /// Exit the current scope (class, module, singleton class, or method).
56
+ ExitScope,
57
+ /// Alias a method (`alias new_name old_name` or `alias_method :new, :old`).
58
+ AliasMethod(AliasMethod),
59
+ /// Change visibility of a specific method (`private :foo`).
60
+ SetMethodVisibility(SetMethodVisibility),
61
+ /// Change the default visibility for subsequent method definitions (`private` with no args).
62
+ SetDefaultVisibility(SetDefaultVisibility),
63
+ /// Define a constant (`FOO = 1`).
64
+ DefineConstant(DefineConstant),
65
+ /// Define a constant alias (`ALIAS = OtherConstant`).
66
+ AliasConstant(AliasConstant),
67
+ /// Change visibility of constants (`private_constant :FOO` or `public_constant :BAR`).
68
+ SetConstantVisibility(SetConstantVisibility),
69
+ /// Include, prepend, or extend a module.
70
+ Mixin(Mixin),
71
+ /// Define an attribute (`attr_accessor :foo`, `attr_reader :bar`, `attr_writer :baz`).
72
+ DefineAttribute(DefineAttribute),
73
+ /// Define a global variable (`$foo = 1`).
74
+ DefineGlobalVariable(DefineGlobalVariable),
75
+ /// Define an instance variable (`@foo = 1`).
76
+ DefineInstanceVariable(DefineInstanceVariable),
77
+ /// Define a class variable (`@@foo = 1`).
78
+ DefineClassVariable(DefineClassVariable),
79
+ /// Alias a global variable (`alias $new $old`).
80
+ AliasGlobalVariable(AliasGlobalVariable),
81
+ /// Record a reference to a constant (for tracking usages).
82
+ ReferenceConstant(ReferenceConstant),
83
+ /// Record a reference to a method (for tracking usages).
84
+ ReferenceMethod(ReferenceMethod),
85
+ }
86
+
87
+ /// A resolved target as it appears in source code.
88
+ ///
89
+ /// Used for method receivers (`def self.foo`), mixin targets (`include Foo`),
90
+ /// constant visibility (`Foo.private_constant`), and method references (`Foo.bar`).
91
+ #[derive(Debug, Clone, Copy)]
92
+ pub enum Target {
93
+ /// Explicit `self` (e.g. `def self.foo`, `extend self`).
94
+ ExplicitSelf,
95
+ /// A constant name (e.g. `def Foo.foo`, `include Foo`).
96
+ Constant(NameId),
97
+ /// An expression we don't resolve (e.g. `def expr.foo`).
98
+ Other,
99
+ }
100
+
101
+ /// The kind of attribute definition.
102
+ #[derive(Debug, Clone, Copy)]
103
+ pub enum AttrKind {
104
+ Accessor,
105
+ Reader,
106
+ Writer,
107
+ }
108
+
109
+ /// The kind of mixin operation.
110
+ #[derive(Debug, Clone, Copy)]
111
+ pub enum MixinKind {
112
+ Include,
113
+ Prepend,
114
+ Extend,
115
+ }
116
+
117
+ #[derive(Debug)]
118
+ pub struct EnterClass {
119
+ pub name_id: NameId,
120
+ pub uri_id: UriId,
121
+ pub offset: Offset,
122
+ pub name_offset: Offset,
123
+ pub comments: Box<[Comment]>,
124
+ pub flags: DefinitionFlags,
125
+ pub superclass_name: Option<NameId>,
126
+ pub is_lexical_scope: bool,
127
+ }
128
+
129
+ #[derive(Debug)]
130
+ pub struct EnterModule {
131
+ pub name_id: NameId,
132
+ pub uri_id: UriId,
133
+ pub offset: Offset,
134
+ pub name_offset: Offset,
135
+ pub comments: Box<[Comment]>,
136
+ pub flags: DefinitionFlags,
137
+ pub is_lexical_scope: bool,
138
+ }
139
+
140
+ #[derive(Debug)]
141
+ pub struct EnterSingletonClass {
142
+ pub name_id: NameId,
143
+ pub uri_id: UriId,
144
+ pub offset: Offset,
145
+ pub name_offset: Offset,
146
+ pub comments: Box<[Comment]>,
147
+ pub flags: DefinitionFlags,
148
+ }
149
+
150
+ #[derive(Debug)]
151
+ pub struct EnterMethod {
152
+ pub str_id: StringId,
153
+ pub uri_id: UriId,
154
+ pub offset: Offset,
155
+ pub comments: Box<[Comment]>,
156
+ pub flags: DefinitionFlags,
157
+ pub signatures: Signatures,
158
+ pub receiver: Option<Target>,
159
+ }
160
+
161
+ #[derive(Debug)]
162
+ pub struct AliasMethod {
163
+ pub new_name_str_id: StringId,
164
+ pub old_name_str_id: StringId,
165
+ pub uri_id: UriId,
166
+ pub offset: Offset,
167
+ pub comments: Box<[Comment]>,
168
+ pub flags: DefinitionFlags,
169
+ pub receiver: Option<Target>,
170
+ }
171
+
172
+ #[derive(Debug)]
173
+ pub struct SetMethodVisibility {
174
+ pub str_id: StringId,
175
+ pub visibility: Visibility,
176
+ pub uri_id: UriId,
177
+ pub offset: Offset,
178
+ pub flags: DefinitionFlags,
179
+ }
180
+
181
+ #[derive(Debug)]
182
+ pub struct SetDefaultVisibility {
183
+ pub visibility: Visibility,
184
+ pub uri_id: UriId,
185
+ pub offset: Offset,
186
+ }
187
+
188
+ #[derive(Debug)]
189
+ pub struct DefineConstant {
190
+ pub name_id: NameId,
191
+ pub uri_id: UriId,
192
+ pub offset: Offset,
193
+ pub comments: Box<[Comment]>,
194
+ pub flags: DefinitionFlags,
195
+ }
196
+
197
+ #[derive(Debug)]
198
+ pub struct AliasConstant {
199
+ pub name_id: NameId,
200
+ pub target_name_id: NameId,
201
+ pub uri_id: UriId,
202
+ pub offset: Offset,
203
+ pub comments: Box<[Comment]>,
204
+ pub flags: DefinitionFlags,
205
+ }
206
+
207
+ #[derive(Debug)]
208
+ pub struct SetConstantVisibility {
209
+ pub receiver: Option<Target>,
210
+ pub target: StringId,
211
+ pub visibility: Visibility,
212
+ pub uri_id: UriId,
213
+ pub offset: Offset,
214
+ pub comments: Box<[Comment]>,
215
+ pub flags: DefinitionFlags,
216
+ }
217
+
218
+ #[derive(Debug)]
219
+ pub struct Mixin {
220
+ pub kind: MixinKind,
221
+ pub target: Target,
222
+ }
223
+
224
+ #[derive(Debug)]
225
+ pub struct DefineAttribute {
226
+ pub kind: AttrKind,
227
+ pub str_id: StringId,
228
+ pub uri_id: UriId,
229
+ pub offset: Offset,
230
+ pub comments: Box<[Comment]>,
231
+ pub flags: DefinitionFlags,
232
+ }
233
+
234
+ #[derive(Debug)]
235
+ pub struct DefineGlobalVariable {
236
+ pub str_id: StringId,
237
+ pub uri_id: UriId,
238
+ pub offset: Offset,
239
+ pub comments: Box<[Comment]>,
240
+ pub flags: DefinitionFlags,
241
+ }
242
+
243
+ #[derive(Debug)]
244
+ pub struct DefineInstanceVariable {
245
+ pub str_id: StringId,
246
+ pub uri_id: UriId,
247
+ pub offset: Offset,
248
+ pub comments: Box<[Comment]>,
249
+ pub flags: DefinitionFlags,
250
+ }
251
+
252
+ #[derive(Debug)]
253
+ pub struct DefineClassVariable {
254
+ pub str_id: StringId,
255
+ pub uri_id: UriId,
256
+ pub offset: Offset,
257
+ pub comments: Box<[Comment]>,
258
+ pub flags: DefinitionFlags,
259
+ }
260
+
261
+ #[derive(Debug)]
262
+ pub struct AliasGlobalVariable {
263
+ pub new_name_str_id: StringId,
264
+ pub old_name_str_id: StringId,
265
+ pub uri_id: UriId,
266
+ pub offset: Offset,
267
+ pub comments: Box<[Comment]>,
268
+ pub flags: DefinitionFlags,
269
+ }
270
+
271
+ #[derive(Debug)]
272
+ pub struct ReferenceConstant {
273
+ pub name_id: NameId,
274
+ pub uri_id: UriId,
275
+ pub offset: Offset,
276
+ }
277
+
278
+ #[derive(Debug)]
279
+ pub struct ReferenceMethod {
280
+ pub str_id: StringId,
281
+ pub uri_id: UriId,
282
+ pub offset: Offset,
283
+ pub receiver: Option<Target>,
284
+ }
@@ -0,0 +1,260 @@
1
+ use std::fmt::Write;
2
+
3
+ use crate::model::{
4
+ identity_maps::IdentityHashMap,
5
+ ids::{NameId, StringId},
6
+ name::NameRef,
7
+ string_ref::StringRef,
8
+ visibility::Visibility,
9
+ };
10
+ use crate::operation::{
11
+ AliasConstant, AliasGlobalVariable, AliasMethod, AttrKind, DefineAttribute, DefineClassVariable, DefineConstant,
12
+ DefineGlobalVariable, DefineInstanceVariable, EnterClass, EnterMethod, EnterModule, EnterSingletonClass, Mixin,
13
+ MixinKind, Operation, ReferenceConstant, ReferenceMethod, SetConstantVisibility, SetDefaultVisibility,
14
+ SetMethodVisibility, Target,
15
+ };
16
+
17
+ struct OperationPrinter<'a> {
18
+ strings: &'a IdentityHashMap<StringId, StringRef>,
19
+ names: &'a IdentityHashMap<NameId, NameRef>,
20
+ out: String,
21
+ depth: usize,
22
+ include_references: bool,
23
+ }
24
+
25
+ impl OperationPrinter<'_> {
26
+ fn name_str(&self, name_id: NameId) -> String {
27
+ let mut parts = Vec::new();
28
+ let mut current = Some(name_id);
29
+ while let Some(id) = current {
30
+ let name = self.names.get(&id).expect("NameId should exist");
31
+ let s = self.strings.get(name.str()).expect("StringId should exist");
32
+ parts.push(s.as_str().to_string());
33
+ current = name.parent_scope().as_ref().copied();
34
+ }
35
+ parts.reverse();
36
+ parts.join("::")
37
+ }
38
+
39
+ fn string_value(&self, str_id: StringId) -> String {
40
+ self.strings
41
+ .get(&str_id)
42
+ .expect("StringId should exist")
43
+ .as_str()
44
+ .to_string()
45
+ }
46
+
47
+ fn receiver_prefix(&self, receiver: Option<&Target>) -> String {
48
+ match receiver {
49
+ Some(Target::ExplicitSelf) => "self.".to_string(),
50
+ Some(Target::Constant(name_id)) => format!("{}.", self.name_str(*name_id)),
51
+ Some(Target::Other) => "<expr>.".to_string(),
52
+ None => String::new(),
53
+ }
54
+ }
55
+
56
+ fn vis(visibility: Visibility) -> &'static str {
57
+ match visibility {
58
+ Visibility::Public => "public",
59
+ Visibility::Protected => "protected",
60
+ Visibility::Private => "private",
61
+ Visibility::ModuleFunction => "module_function",
62
+ }
63
+ }
64
+
65
+ fn indent(&self) -> String {
66
+ " ".repeat(self.depth)
67
+ }
68
+
69
+ fn print_operation(&mut self, op: &Operation) {
70
+ match op {
71
+ Operation::EnterClass(op) => self.print_enter_class(op),
72
+ Operation::EnterModule(op) => self.print_enter_module(op),
73
+ Operation::EnterSingletonClass(op) => self.print_enter_singleton_class(op),
74
+ Operation::EnterMethod(op) => self.print_enter_method(op),
75
+ Operation::ExitScope => {
76
+ self.depth = self.depth.saturating_sub(1);
77
+ let indent = self.indent();
78
+ writeln!(self.out, "{indent}ExitScope").unwrap();
79
+ }
80
+ Operation::AliasMethod(op) => self.print_alias_method(op),
81
+ Operation::SetMethodVisibility(op) => self.print_set_method_visibility(op),
82
+ Operation::SetDefaultVisibility(op) => self.print_set_default_visibility(op),
83
+ Operation::DefineConstant(op) => self.print_define_constant(op),
84
+ Operation::AliasConstant(op) => self.print_alias_constant(op),
85
+ Operation::SetConstantVisibility(op) => self.print_set_constant_visibility(op),
86
+ Operation::Mixin(op) => self.print_mixin(op),
87
+ Operation::DefineAttribute(op) => self.print_define_attribute(op),
88
+ Operation::DefineGlobalVariable(op) => self.print_define_global_variable(op),
89
+ Operation::DefineInstanceVariable(op) => self.print_define_instance_variable(op),
90
+ Operation::DefineClassVariable(op) => self.print_define_class_variable(op),
91
+ Operation::AliasGlobalVariable(op) => self.print_alias_global_variable(op),
92
+ Operation::ReferenceConstant(op) => self.print_reference_constant(op),
93
+ Operation::ReferenceMethod(op) => self.print_reference_method(op),
94
+ }
95
+ }
96
+
97
+ fn print_enter_class(&mut self, op: &EnterClass) {
98
+ let indent = self.indent();
99
+ let name = self.name_str(op.name_id);
100
+ write!(self.out, "{indent}EnterClass({name}").unwrap();
101
+ if let Some(sc_name_id) = op.superclass_name {
102
+ let sc = self.name_str(sc_name_id);
103
+ write!(self.out, ", superclass: {sc}").unwrap();
104
+ }
105
+ writeln!(self.out, ")").unwrap();
106
+ self.depth += 1;
107
+ }
108
+
109
+ fn print_enter_module(&mut self, op: &EnterModule) {
110
+ let indent = self.indent();
111
+ let name = self.name_str(op.name_id);
112
+ writeln!(self.out, "{indent}EnterModule({name})").unwrap();
113
+ self.depth += 1;
114
+ }
115
+
116
+ fn print_enter_singleton_class(&mut self, op: &EnterSingletonClass) {
117
+ let indent = self.indent();
118
+ let name = self.name_str(op.name_id);
119
+ writeln!(self.out, "{indent}EnterSingletonClass({name})").unwrap();
120
+ self.depth += 1;
121
+ }
122
+
123
+ fn print_enter_method(&mut self, op: &EnterMethod) {
124
+ let indent = self.indent();
125
+ let prefix = self.receiver_prefix(op.receiver.as_ref());
126
+ let name = self.string_value(op.str_id);
127
+ writeln!(self.out, "{indent}EnterMethod({prefix}{name})").unwrap();
128
+ self.depth += 1;
129
+ }
130
+
131
+ fn print_alias_method(&mut self, op: &AliasMethod) {
132
+ let indent = self.indent();
133
+ let new_name = self.string_value(op.new_name_str_id);
134
+ let old_name = self.string_value(op.old_name_str_id);
135
+ writeln!(self.out, "{indent}AliasMethod({new_name} -> {old_name})").unwrap();
136
+ }
137
+
138
+ fn print_set_method_visibility(&mut self, op: &SetMethodVisibility) {
139
+ let indent = self.indent();
140
+ let name = self.string_value(op.str_id);
141
+ let v = Self::vis(op.visibility);
142
+ writeln!(self.out, "{indent}SetMethodVisibility({name}, vis: {v})").unwrap();
143
+ }
144
+
145
+ fn print_set_default_visibility(&mut self, op: &SetDefaultVisibility) {
146
+ let indent = self.indent();
147
+ let v = Self::vis(op.visibility);
148
+ writeln!(self.out, "{indent}SetDefaultVisibility({v})").unwrap();
149
+ }
150
+
151
+ fn print_define_constant(&mut self, op: &DefineConstant) {
152
+ let indent = self.indent();
153
+ let name = self.name_str(op.name_id);
154
+ writeln!(self.out, "{indent}DefineConstant({name})").unwrap();
155
+ }
156
+
157
+ fn print_alias_constant(&mut self, op: &AliasConstant) {
158
+ let indent = self.indent();
159
+ let name = self.name_str(op.name_id);
160
+ let target = self.name_str(op.target_name_id);
161
+ writeln!(self.out, "{indent}AliasConstant({name} -> {target})").unwrap();
162
+ }
163
+
164
+ fn print_set_constant_visibility(&mut self, op: &SetConstantVisibility) {
165
+ let indent = self.indent();
166
+ let name = self.string_value(op.target);
167
+ let v = Self::vis(op.visibility);
168
+ writeln!(self.out, "{indent}SetConstantVisibility({name}, vis: {v})").unwrap();
169
+ }
170
+
171
+ fn print_mixin(&mut self, op: &Mixin) {
172
+ let indent = self.indent();
173
+ let kind_str = match op.kind {
174
+ MixinKind::Include => "include",
175
+ MixinKind::Prepend => "prepend",
176
+ MixinKind::Extend => "extend",
177
+ };
178
+ let target_name = match op.target {
179
+ Target::Constant(name_id) => self.name_str(name_id),
180
+ Target::ExplicitSelf => "self".to_string(),
181
+ Target::Other => "<expr>".to_string(),
182
+ };
183
+ writeln!(self.out, "{indent}Mixin({kind_str}, {target_name})").unwrap();
184
+ }
185
+
186
+ fn print_define_attribute(&mut self, op: &DefineAttribute) {
187
+ let indent = self.indent();
188
+ let kind_str = match op.kind {
189
+ AttrKind::Accessor => "accessor",
190
+ AttrKind::Reader => "reader",
191
+ AttrKind::Writer => "writer",
192
+ };
193
+ let name = self.string_value(op.str_id);
194
+ writeln!(self.out, "{indent}DefineAttribute({kind_str} {name})").unwrap();
195
+ }
196
+
197
+ fn print_define_global_variable(&mut self, op: &DefineGlobalVariable) {
198
+ let indent = self.indent();
199
+ let name = self.string_value(op.str_id);
200
+ writeln!(self.out, "{indent}DefineGlobalVariable({name})").unwrap();
201
+ }
202
+
203
+ fn print_define_instance_variable(&mut self, op: &DefineInstanceVariable) {
204
+ let indent = self.indent();
205
+ let name = self.string_value(op.str_id);
206
+ writeln!(self.out, "{indent}DefineInstanceVariable({name})").unwrap();
207
+ }
208
+
209
+ fn print_define_class_variable(&mut self, op: &DefineClassVariable) {
210
+ let indent = self.indent();
211
+ let name = self.string_value(op.str_id);
212
+ writeln!(self.out, "{indent}DefineClassVariable({name})").unwrap();
213
+ }
214
+
215
+ fn print_alias_global_variable(&mut self, op: &AliasGlobalVariable) {
216
+ let indent = self.indent();
217
+ let new_name = self.string_value(op.new_name_str_id);
218
+ let old_name = self.string_value(op.old_name_str_id);
219
+ writeln!(self.out, "{indent}AliasGlobalVariable({new_name} -> {old_name})").unwrap();
220
+ }
221
+
222
+ fn print_reference_constant(&mut self, op: &ReferenceConstant) {
223
+ if self.include_references {
224
+ let indent = self.indent();
225
+ let name = self.name_str(op.name_id);
226
+ writeln!(self.out, "{indent}ReferenceConstant({name})").unwrap();
227
+ }
228
+ }
229
+
230
+ fn print_reference_method(&mut self, op: &ReferenceMethod) {
231
+ if self.include_references {
232
+ let indent = self.indent();
233
+ let name = self.string_value(op.str_id);
234
+ writeln!(self.out, "{indent}ReferenceMethod({name})").unwrap();
235
+ }
236
+ }
237
+ }
238
+
239
+ #[must_use]
240
+ #[allow(clippy::implicit_hasher)]
241
+ pub fn print_operations(
242
+ operations: &[Operation],
243
+ strings: &IdentityHashMap<StringId, StringRef>,
244
+ names: &IdentityHashMap<NameId, NameRef>,
245
+ include_references: bool,
246
+ ) -> String {
247
+ let mut printer = OperationPrinter {
248
+ strings,
249
+ names,
250
+ out: String::new(),
251
+ depth: 0,
252
+ include_references,
253
+ };
254
+
255
+ for op in operations {
256
+ printer.print_operation(op);
257
+ }
258
+
259
+ printer.out.trim_end().to_string()
260
+ }