method-ray 0.1.8 → 0.1.10
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/README.md +9 -11
- data/{rust → core}/Cargo.toml +1 -1
- data/core/src/analyzer/assignments.rs +219 -0
- data/{rust → core}/src/analyzer/blocks.rs +0 -50
- data/{rust → core}/src/analyzer/calls.rs +3 -32
- data/core/src/analyzer/conditionals.rs +190 -0
- data/core/src/analyzer/definitions.rs +205 -0
- data/core/src/analyzer/dispatch.rs +455 -0
- data/core/src/analyzer/exceptions.rs +168 -0
- data/{rust → core}/src/analyzer/install.rs +16 -1
- data/{rust → core}/src/analyzer/literals.rs +3 -71
- data/core/src/analyzer/loops.rs +94 -0
- data/{rust → core}/src/analyzer/mod.rs +1 -15
- data/core/src/analyzer/operators.rs +79 -0
- data/{rust → core}/src/analyzer/parameters.rs +4 -67
- data/core/src/analyzer/parentheses.rs +25 -0
- data/core/src/analyzer/returns.rs +39 -0
- data/core/src/analyzer/super_calls.rs +74 -0
- data/{rust → core}/src/analyzer/variables.rs +5 -25
- data/{rust → core}/src/checker.rs +0 -13
- data/{rust → core}/src/diagnostics/diagnostic.rs +0 -41
- data/{rust → core}/src/diagnostics/formatter.rs +0 -38
- data/{rust → core}/src/env/box_manager.rs +0 -30
- data/{rust → core}/src/env/global_env.rs +67 -80
- data/core/src/env/local_env.rs +42 -0
- data/core/src/env/method_registry.rs +173 -0
- data/core/src/env/scope.rs +299 -0
- data/{rust → core}/src/env/vertex_manager.rs +0 -73
- data/core/src/graph/box.rs +347 -0
- data/{rust → core}/src/graph/change_set.rs +0 -65
- data/{rust → core}/src/graph/vertex.rs +0 -69
- data/{rust → core}/src/parser.rs +0 -77
- data/{rust → core}/src/types.rs +11 -0
- data/ext/Cargo.toml +2 -2
- data/lib/methodray/binary_locator.rb +2 -2
- data/lib/methodray/commands.rb +1 -1
- data/lib/methodray/version.rb +1 -1
- metadata +58 -56
- data/rust/src/analyzer/assignments.rs +0 -152
- data/rust/src/analyzer/conditionals.rs +0 -538
- data/rust/src/analyzer/definitions.rs +0 -719
- data/rust/src/analyzer/dispatch.rs +0 -1137
- data/rust/src/analyzer/exceptions.rs +0 -521
- data/rust/src/analyzer/loops.rs +0 -176
- data/rust/src/analyzer/operators.rs +0 -284
- data/rust/src/analyzer/parentheses.rs +0 -113
- data/rust/src/analyzer/returns.rs +0 -191
- data/rust/src/env/local_env.rs +0 -92
- data/rust/src/env/method_registry.rs +0 -268
- data/rust/src/env/scope.rs +0 -596
- data/rust/src/graph/box.rs +0 -766
- /data/{rust → core}/src/analyzer/attributes.rs +0 -0
- /data/{rust → core}/src/cache/mod.rs +0 -0
- /data/{rust → core}/src/cache/rbs_cache.rs +0 -0
- /data/{rust → core}/src/cli/args.rs +0 -0
- /data/{rust → core}/src/cli/commands.rs +0 -0
- /data/{rust → core}/src/cli/mod.rs +0 -0
- /data/{rust → core}/src/diagnostics/mod.rs +0 -0
- /data/{rust → core}/src/env/mod.rs +0 -0
- /data/{rust → core}/src/env/type_error.rs +0 -0
- /data/{rust → core}/src/graph/mod.rs +0 -0
- /data/{rust → core}/src/lib.rs +0 -0
- /data/{rust → core}/src/lsp/diagnostics.rs +0 -0
- /data/{rust → core}/src/lsp/main.rs +0 -0
- /data/{rust → core}/src/lsp/mod.rs +0 -0
- /data/{rust → core}/src/lsp/server.rs +0 -0
- /data/{rust → core}/src/main.rs +0 -0
- /data/{rust → core}/src/rbs/converter.rs +0 -0
- /data/{rust → core}/src/rbs/error.rs +0 -0
- /data/{rust → core}/src/rbs/loader.rs +0 -0
- /data/{rust → core}/src/rbs/mod.rs +0 -0
- /data/{rust → core}/src/source_map.rs +0 -0
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
//! Method registration and resolution
|
|
2
|
-
|
|
3
|
-
use std::collections::HashMap;
|
|
4
|
-
|
|
5
|
-
use crate::graph::VertexId;
|
|
6
|
-
use crate::types::Type;
|
|
7
|
-
use smallvec::SmallVec;
|
|
8
|
-
|
|
9
|
-
const OBJECT_CLASS: &str = "Object";
|
|
10
|
-
const KERNEL_MODULE: &str = "Kernel";
|
|
11
|
-
|
|
12
|
-
/// Method information
|
|
13
|
-
#[derive(Debug, Clone)]
|
|
14
|
-
pub struct MethodInfo {
|
|
15
|
-
pub return_type: Type,
|
|
16
|
-
pub block_param_types: Option<Vec<Type>>,
|
|
17
|
-
pub return_vertex: Option<VertexId>,
|
|
18
|
-
pub param_vertices: Option<Vec<VertexId>>,
|
|
19
|
-
pub keyword_param_vertices: Option<HashMap<String, VertexId>>,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/// Registry for method definitions
|
|
23
|
-
#[derive(Debug, Default)]
|
|
24
|
-
pub struct MethodRegistry {
|
|
25
|
-
methods: HashMap<(Type, String), MethodInfo>,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
impl MethodRegistry {
|
|
29
|
-
/// Create a new empty registry
|
|
30
|
-
pub fn new() -> Self {
|
|
31
|
-
Self {
|
|
32
|
-
methods: HashMap::new(),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/// Register a method for a receiver type
|
|
37
|
-
pub fn register(&mut self, recv_ty: Type, method_name: &str, ret_ty: Type) {
|
|
38
|
-
self.register_with_block(recv_ty, method_name, ret_ty, None);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/// Register a method with block parameter types
|
|
42
|
-
pub fn register_with_block(
|
|
43
|
-
&mut self,
|
|
44
|
-
recv_ty: Type,
|
|
45
|
-
method_name: &str,
|
|
46
|
-
ret_ty: Type,
|
|
47
|
-
block_param_types: Option<Vec<Type>>,
|
|
48
|
-
) {
|
|
49
|
-
self.methods.insert(
|
|
50
|
-
(recv_ty, method_name.to_string()),
|
|
51
|
-
MethodInfo {
|
|
52
|
-
return_type: ret_ty,
|
|
53
|
-
block_param_types,
|
|
54
|
-
return_vertex: None,
|
|
55
|
-
param_vertices: None,
|
|
56
|
-
keyword_param_vertices: None,
|
|
57
|
-
},
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/// Register a user-defined method (return type resolved via graph)
|
|
62
|
-
pub fn register_user_method(
|
|
63
|
-
&mut self,
|
|
64
|
-
recv_ty: Type,
|
|
65
|
-
method_name: &str,
|
|
66
|
-
return_vertex: VertexId,
|
|
67
|
-
param_vertices: Vec<VertexId>,
|
|
68
|
-
keyword_param_vertices: Option<HashMap<String, VertexId>>,
|
|
69
|
-
) {
|
|
70
|
-
self.methods.insert(
|
|
71
|
-
(recv_ty, method_name.to_string()),
|
|
72
|
-
MethodInfo {
|
|
73
|
-
return_type: Type::Bot,
|
|
74
|
-
block_param_types: None,
|
|
75
|
-
return_vertex: Some(return_vertex),
|
|
76
|
-
param_vertices: Some(param_vertices),
|
|
77
|
-
keyword_param_vertices,
|
|
78
|
-
},
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/// Build the method resolution order (MRO) fallback chain for a receiver type.
|
|
83
|
-
///
|
|
84
|
-
/// Returns a list of types to search in order:
|
|
85
|
-
/// 1. Exact receiver type
|
|
86
|
-
/// 2. Generic → base class (e.g., Array[Integer] → Array)
|
|
87
|
-
/// 3. Object (for Instance/Generic types only)
|
|
88
|
-
/// 4. Kernel (for Instance/Generic types only)
|
|
89
|
-
fn fallback_chain(recv_ty: &Type) -> SmallVec<[Type; 4]> {
|
|
90
|
-
let mut chain = SmallVec::new();
|
|
91
|
-
chain.push(recv_ty.clone());
|
|
92
|
-
|
|
93
|
-
if let Type::Generic { name, .. } = recv_ty {
|
|
94
|
-
chain.push(Type::Instance { name: name.clone() });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// NOTE: Kernel is a module, not a class. Represented as Type::Instance
|
|
98
|
-
// due to lack of Type::Module variant.
|
|
99
|
-
if matches!(recv_ty, Type::Instance { .. } | Type::Generic { .. }) {
|
|
100
|
-
chain.push(Type::instance(OBJECT_CLASS));
|
|
101
|
-
chain.push(Type::instance(KERNEL_MODULE));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
chain
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/// Resolve a method for a receiver type
|
|
108
|
-
///
|
|
109
|
-
/// Searches the MRO fallback chain: exact type → base class (for generics) → Object → Kernel.
|
|
110
|
-
/// For non-instance types (Singleton, Nil, Union, Bot), only exact match is attempted.
|
|
111
|
-
pub fn resolve(&self, recv_ty: &Type, method_name: &str) -> Option<&MethodInfo> {
|
|
112
|
-
let method_key = method_name.to_string();
|
|
113
|
-
Self::fallback_chain(recv_ty)
|
|
114
|
-
.into_iter()
|
|
115
|
-
.find_map(|ty| self.methods.get(&(ty, method_key.clone())))
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
#[cfg(test)]
|
|
120
|
-
mod tests {
|
|
121
|
-
use super::*;
|
|
122
|
-
|
|
123
|
-
#[test]
|
|
124
|
-
fn test_register_and_resolve() {
|
|
125
|
-
let mut registry = MethodRegistry::new();
|
|
126
|
-
registry.register(Type::string(), "length", Type::integer());
|
|
127
|
-
|
|
128
|
-
let info = registry.resolve(&Type::string(), "length").unwrap();
|
|
129
|
-
assert_eq!(info.return_type.base_class_name(), Some("Integer"));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
#[test]
|
|
133
|
-
fn test_resolve_not_found() {
|
|
134
|
-
let registry = MethodRegistry::new();
|
|
135
|
-
assert!(registry.resolve(&Type::string(), "unknown").is_none());
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
#[test]
|
|
139
|
-
fn test_register_user_method_and_resolve() {
|
|
140
|
-
let mut registry = MethodRegistry::new();
|
|
141
|
-
let return_vtx = VertexId(42);
|
|
142
|
-
registry.register_user_method(Type::instance("User"), "name", return_vtx, vec![], None);
|
|
143
|
-
|
|
144
|
-
let info = registry.resolve(&Type::instance("User"), "name").unwrap();
|
|
145
|
-
assert_eq!(info.return_vertex, Some(VertexId(42)));
|
|
146
|
-
assert_eq!(info.return_type, Type::Bot);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
#[test]
|
|
150
|
-
fn test_register_user_method_with_param_vertices() {
|
|
151
|
-
let mut registry = MethodRegistry::new();
|
|
152
|
-
let return_vtx = VertexId(10);
|
|
153
|
-
let param_vtxs = vec![VertexId(20), VertexId(21)];
|
|
154
|
-
registry.register_user_method(
|
|
155
|
-
Type::instance("Calc"),
|
|
156
|
-
"add",
|
|
157
|
-
return_vtx,
|
|
158
|
-
param_vtxs,
|
|
159
|
-
None,
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
let info = registry.resolve(&Type::instance("Calc"), "add").unwrap();
|
|
163
|
-
assert_eq!(info.return_vertex, Some(VertexId(10)));
|
|
164
|
-
let pvs = info.param_vertices.as_ref().unwrap();
|
|
165
|
-
assert_eq!(pvs.len(), 2);
|
|
166
|
-
assert_eq!(pvs[0], VertexId(20));
|
|
167
|
-
assert_eq!(pvs[1], VertexId(21));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// --- Object/Kernel fallback ---
|
|
171
|
-
|
|
172
|
-
#[test]
|
|
173
|
-
fn test_resolve_falls_back_to_object() {
|
|
174
|
-
let mut registry = MethodRegistry::new();
|
|
175
|
-
registry.register(Type::instance("Object"), "nil?", Type::instance("TrueClass"));
|
|
176
|
-
let info = registry.resolve(&Type::instance("CustomClass"), "nil?").unwrap();
|
|
177
|
-
assert_eq!(info.return_type.base_class_name(), Some("TrueClass"));
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
#[test]
|
|
181
|
-
fn test_resolve_falls_back_to_kernel() {
|
|
182
|
-
let mut registry = MethodRegistry::new();
|
|
183
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
184
|
-
let info = registry.resolve(&Type::instance("MyApp"), "puts").unwrap();
|
|
185
|
-
assert_eq!(info.return_type, Type::Nil);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
#[test]
|
|
189
|
-
fn test_resolve_object_before_kernel() {
|
|
190
|
-
let mut registry = MethodRegistry::new();
|
|
191
|
-
registry.register(Type::instance("Object"), "to_s", Type::string());
|
|
192
|
-
registry.register(Type::instance("Kernel"), "to_s", Type::integer());
|
|
193
|
-
let info = registry.resolve(&Type::instance("Anything"), "to_s").unwrap();
|
|
194
|
-
assert_eq!(info.return_type.base_class_name(), Some("String"));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
#[test]
|
|
198
|
-
fn test_resolve_exact_match_over_fallback() {
|
|
199
|
-
let mut registry = MethodRegistry::new();
|
|
200
|
-
registry.register(Type::string(), "length", Type::integer());
|
|
201
|
-
registry.register(Type::instance("Object"), "length", Type::string());
|
|
202
|
-
let info = registry.resolve(&Type::string(), "length").unwrap();
|
|
203
|
-
assert_eq!(info.return_type.base_class_name(), Some("Integer"));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// --- Types that skip fallback ---
|
|
207
|
-
|
|
208
|
-
#[test]
|
|
209
|
-
fn test_singleton_type_skips_fallback() {
|
|
210
|
-
let mut registry = MethodRegistry::new();
|
|
211
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
212
|
-
assert!(registry.resolve(&Type::singleton("User"), "puts").is_none());
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
#[test]
|
|
216
|
-
fn test_nil_type_skips_fallback() {
|
|
217
|
-
let mut registry = MethodRegistry::new();
|
|
218
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
219
|
-
assert!(registry.resolve(&Type::Nil, "puts").is_none());
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
#[test]
|
|
223
|
-
fn test_union_type_skips_fallback() {
|
|
224
|
-
let mut registry = MethodRegistry::new();
|
|
225
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
226
|
-
let union_ty = Type::Union(vec![Type::string(), Type::integer()]);
|
|
227
|
-
assert!(registry.resolve(&union_ty, "puts").is_none());
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
#[test]
|
|
231
|
-
fn test_bot_type_skips_fallback() {
|
|
232
|
-
let mut registry = MethodRegistry::new();
|
|
233
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
234
|
-
assert!(registry.resolve(&Type::Bot, "puts").is_none());
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// --- Generic type fallback chain ---
|
|
238
|
-
|
|
239
|
-
#[test]
|
|
240
|
-
fn test_resolve_generic_falls_back_to_kernel() {
|
|
241
|
-
let mut registry = MethodRegistry::new();
|
|
242
|
-
registry.register(Type::instance("Kernel"), "puts", Type::Nil);
|
|
243
|
-
let generic_type = Type::array_of(Type::integer());
|
|
244
|
-
let info = registry.resolve(&generic_type, "puts").unwrap();
|
|
245
|
-
assert_eq!(info.return_type, Type::Nil);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
#[test]
|
|
249
|
-
fn test_resolve_generic_full_chain() {
|
|
250
|
-
// Verify the 4-step fallback: Generic[T] → Base → Object → Kernel
|
|
251
|
-
let mut registry = MethodRegistry::new();
|
|
252
|
-
registry.register(Type::instance("Kernel"), "object_id", Type::integer());
|
|
253
|
-
let generic_type = Type::array_of(Type::string());
|
|
254
|
-
// Array[String] → Array (none) → Object (none) → Kernel (exists)
|
|
255
|
-
let info = registry.resolve(&generic_type, "object_id").unwrap();
|
|
256
|
-
assert_eq!(info.return_type.base_class_name(), Some("Integer"));
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// --- Namespaced class fallback ---
|
|
260
|
-
|
|
261
|
-
#[test]
|
|
262
|
-
fn test_resolve_namespaced_class_falls_back_to_object() {
|
|
263
|
-
let mut registry = MethodRegistry::new();
|
|
264
|
-
registry.register(Type::instance("Object"), "class", Type::string());
|
|
265
|
-
let info = registry.resolve(&Type::instance("Api::V1::User"), "class").unwrap();
|
|
266
|
-
assert_eq!(info.return_type.base_class_name(), Some("String"));
|
|
267
|
-
}
|
|
268
|
-
}
|