method-ray 0.1.9 → 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 +20 -0
- data/README.md +9 -11
- data/core/Cargo.toml +1 -1
- data/core/src/analyzer/assignments.rs +0 -280
- data/core/src/analyzer/blocks.rs +0 -190
- data/core/src/analyzer/calls.rs +3 -32
- data/core/src/analyzer/conditionals.rs +0 -348
- data/core/src/analyzer/definitions.rs +11 -526
- data/core/src/analyzer/dispatch.rs +54 -1000
- data/core/src/analyzer/exceptions.rs +0 -454
- data/core/src/analyzer/literals.rs +0 -54
- data/core/src/analyzer/loops.rs +0 -207
- data/core/src/analyzer/mod.rs +0 -15
- data/core/src/analyzer/operators.rs +0 -205
- data/core/src/analyzer/parameters.rs +4 -227
- data/core/src/analyzer/parentheses.rs +0 -88
- data/core/src/analyzer/returns.rs +0 -152
- data/core/src/analyzer/super_calls.rs +1 -212
- data/core/src/analyzer/variables.rs +5 -25
- data/core/src/checker.rs +0 -13
- data/core/src/diagnostics/diagnostic.rs +0 -41
- data/core/src/diagnostics/formatter.rs +0 -38
- data/core/src/env/box_manager.rs +0 -30
- data/core/src/env/global_env.rs +52 -79
- data/core/src/env/local_env.rs +0 -50
- data/core/src/env/method_registry.rs +52 -233
- data/core/src/env/scope.rs +0 -375
- data/core/src/env/vertex_manager.rs +0 -73
- data/core/src/graph/box.rs +20 -439
- data/core/src/graph/change_set.rs +0 -65
- data/core/src/graph/vertex.rs +0 -69
- data/core/src/parser.rs +0 -77
- data/ext/Cargo.toml +1 -1
- data/lib/methodray/version.rb +1 -1
- metadata +5 -4
|
@@ -166,457 +166,3 @@ pub(crate) fn process_rescue_modifier_node(
|
|
|
166
166
|
|
|
167
167
|
Some(result_vtx)
|
|
168
168
|
}
|
|
169
|
-
|
|
170
|
-
#[cfg(test)]
|
|
171
|
-
mod tests {
|
|
172
|
-
use crate::analyzer::install::AstInstaller;
|
|
173
|
-
use crate::env::{GlobalEnv, LocalEnv};
|
|
174
|
-
use crate::graph::VertexId;
|
|
175
|
-
use crate::parser::ParseSession;
|
|
176
|
-
use crate::types::Type;
|
|
177
|
-
|
|
178
|
-
/// Helper: parse Ruby source, process with AstInstaller, and return GlobalEnv
|
|
179
|
-
fn analyze(source: &str) -> GlobalEnv {
|
|
180
|
-
let session = ParseSession::new();
|
|
181
|
-
let parse_result = session.parse_source(source, "test.rb").unwrap();
|
|
182
|
-
let root = parse_result.node();
|
|
183
|
-
let program = root.as_program_node().unwrap();
|
|
184
|
-
|
|
185
|
-
let mut genv = GlobalEnv::new();
|
|
186
|
-
let mut lenv = LocalEnv::new();
|
|
187
|
-
|
|
188
|
-
let mut installer = AstInstaller::new(&mut genv, &mut lenv, source);
|
|
189
|
-
for stmt in &program.statements().body() {
|
|
190
|
-
installer.install_node(&stmt);
|
|
191
|
-
}
|
|
192
|
-
installer.finish();
|
|
193
|
-
|
|
194
|
-
genv
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/// Helper: get the type string for a vertex ID (checks both Vertex and Source)
|
|
198
|
-
fn get_type_show(genv: &GlobalEnv, vtx: VertexId) -> String {
|
|
199
|
-
if let Some(vertex) = genv.get_vertex(vtx) {
|
|
200
|
-
vertex.show()
|
|
201
|
-
} else if let Some(source) = genv.get_source(vtx) {
|
|
202
|
-
source.ty.show()
|
|
203
|
-
} else {
|
|
204
|
-
panic!("vertex {:?} not found as either Vertex or Source", vtx);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
#[test]
|
|
209
|
-
fn test_begin_rescue_basic() {
|
|
210
|
-
let source = r#"
|
|
211
|
-
class Foo
|
|
212
|
-
def bar
|
|
213
|
-
begin
|
|
214
|
-
"hello"
|
|
215
|
-
rescue
|
|
216
|
-
42
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
"#;
|
|
221
|
-
let genv = analyze(source);
|
|
222
|
-
let info = genv
|
|
223
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
224
|
-
.expect("Foo#bar should be registered");
|
|
225
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
226
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String)");
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
#[test]
|
|
230
|
-
fn test_begin_rescue_else() {
|
|
231
|
-
let source = r#"
|
|
232
|
-
class Foo
|
|
233
|
-
def bar
|
|
234
|
-
begin
|
|
235
|
-
"hello"
|
|
236
|
-
rescue
|
|
237
|
-
42
|
|
238
|
-
else
|
|
239
|
-
:ok
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
"#;
|
|
244
|
-
let genv = analyze(source);
|
|
245
|
-
let info = genv
|
|
246
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
247
|
-
.expect("Foo#bar should be registered");
|
|
248
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
249
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
250
|
-
// else present: begin body excluded, else + rescue types
|
|
251
|
-
assert!(type_str.contains("Symbol"), "should contain Symbol: {}", type_str);
|
|
252
|
-
assert!(type_str.contains("Integer"), "should contain Integer: {}", type_str);
|
|
253
|
-
assert!(!type_str.contains("String"), "should NOT contain String: {}", type_str);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
#[test]
|
|
257
|
-
fn test_begin_ensure_only() {
|
|
258
|
-
let source = r#"
|
|
259
|
-
class Foo
|
|
260
|
-
def bar
|
|
261
|
-
begin
|
|
262
|
-
"hello"
|
|
263
|
-
ensure
|
|
264
|
-
puts "cleanup"
|
|
265
|
-
end
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
"#;
|
|
269
|
-
let genv = analyze(source);
|
|
270
|
-
let info = genv
|
|
271
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
272
|
-
.expect("Foo#bar should be registered");
|
|
273
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
274
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "String");
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
#[test]
|
|
278
|
-
fn test_begin_rescue_ensure() {
|
|
279
|
-
let source = r#"
|
|
280
|
-
class Foo
|
|
281
|
-
def bar
|
|
282
|
-
begin
|
|
283
|
-
"hello"
|
|
284
|
-
rescue
|
|
285
|
-
42
|
|
286
|
-
ensure
|
|
287
|
-
:cleanup
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
end
|
|
291
|
-
"#;
|
|
292
|
-
let genv = analyze(source);
|
|
293
|
-
let info = genv
|
|
294
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
295
|
-
.expect("Foo#bar should be registered");
|
|
296
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
297
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
298
|
-
// ensure does not affect return type
|
|
299
|
-
assert_eq!(type_str, "(Integer | String)");
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
#[test]
|
|
303
|
-
fn test_rescue_variable_type() {
|
|
304
|
-
let source = r#"
|
|
305
|
-
class Foo
|
|
306
|
-
def bar
|
|
307
|
-
begin
|
|
308
|
-
"hello"
|
|
309
|
-
rescue => e
|
|
310
|
-
e
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
"#;
|
|
315
|
-
let genv = analyze(source);
|
|
316
|
-
let info = genv
|
|
317
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
318
|
-
.expect("Foo#bar should be registered");
|
|
319
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
320
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
321
|
-
assert!(
|
|
322
|
-
type_str.contains("StandardError"),
|
|
323
|
-
"should contain StandardError: {}",
|
|
324
|
-
type_str
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
#[test]
|
|
329
|
-
fn test_multiple_rescue_clauses() {
|
|
330
|
-
let source = r#"
|
|
331
|
-
class Foo
|
|
332
|
-
def bar
|
|
333
|
-
begin
|
|
334
|
-
"hello"
|
|
335
|
-
rescue ArgumentError
|
|
336
|
-
42
|
|
337
|
-
rescue RuntimeError
|
|
338
|
-
:error
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
"#;
|
|
343
|
-
let genv = analyze(source);
|
|
344
|
-
let info = genv
|
|
345
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
346
|
-
.expect("Foo#bar should be registered");
|
|
347
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
348
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
349
|
-
assert!(type_str.contains("String"), "should contain String: {}", type_str);
|
|
350
|
-
assert!(type_str.contains("Integer"), "should contain Integer: {}", type_str);
|
|
351
|
-
assert!(type_str.contains("Symbol"), "should contain Symbol: {}", type_str);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
#[test]
|
|
355
|
-
fn test_rescue_modifier_basic() {
|
|
356
|
-
let source = r#"
|
|
357
|
-
class Foo
|
|
358
|
-
def bar
|
|
359
|
-
"hello" rescue 42
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
"#;
|
|
363
|
-
let genv = analyze(source);
|
|
364
|
-
let info = genv
|
|
365
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
366
|
-
.expect("Foo#bar should be registered");
|
|
367
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
368
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String)");
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
#[test]
|
|
372
|
-
fn test_rescue_modifier_same_type() {
|
|
373
|
-
let source = r#"
|
|
374
|
-
class Foo
|
|
375
|
-
def bar
|
|
376
|
-
"hello" rescue "world"
|
|
377
|
-
end
|
|
378
|
-
end
|
|
379
|
-
"#;
|
|
380
|
-
let genv = analyze(source);
|
|
381
|
-
let info = genv
|
|
382
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
383
|
-
.expect("Foo#bar should be registered");
|
|
384
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
385
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "String");
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
#[test]
|
|
389
|
-
fn test_nested_begin_rescue() {
|
|
390
|
-
let source = r#"
|
|
391
|
-
class Foo
|
|
392
|
-
def bar
|
|
393
|
-
begin
|
|
394
|
-
begin
|
|
395
|
-
"inner"
|
|
396
|
-
rescue
|
|
397
|
-
42
|
|
398
|
-
end
|
|
399
|
-
rescue
|
|
400
|
-
:outer
|
|
401
|
-
end
|
|
402
|
-
end
|
|
403
|
-
end
|
|
404
|
-
"#;
|
|
405
|
-
let genv = analyze(source);
|
|
406
|
-
let info = genv
|
|
407
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
408
|
-
.expect("Foo#bar should be registered");
|
|
409
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
410
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
411
|
-
// Outer: Union(inner_begin_rescue | :outer) = (Integer | String | Symbol)
|
|
412
|
-
assert!(type_str.contains("Integer"), "should contain Integer: {}", type_str);
|
|
413
|
-
assert!(type_str.contains("String"), "should contain String: {}", type_str);
|
|
414
|
-
assert!(type_str.contains("Symbol"), "should contain Symbol: {}", type_str);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
#[test]
|
|
418
|
-
fn test_begin_rescue_in_method() {
|
|
419
|
-
let source = r#"
|
|
420
|
-
class Foo
|
|
421
|
-
def bar
|
|
422
|
-
x = begin
|
|
423
|
-
"hello"
|
|
424
|
-
rescue
|
|
425
|
-
42
|
|
426
|
-
end
|
|
427
|
-
x
|
|
428
|
-
end
|
|
429
|
-
end
|
|
430
|
-
"#;
|
|
431
|
-
let genv = analyze(source);
|
|
432
|
-
let info = genv
|
|
433
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
434
|
-
.expect("Foo#bar should be registered");
|
|
435
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
436
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String)");
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
#[test]
|
|
440
|
-
fn test_ensure_side_effects() {
|
|
441
|
-
// ensure body should be processed (no panic) but not affect return type
|
|
442
|
-
let source = r#"
|
|
443
|
-
class Foo
|
|
444
|
-
def bar
|
|
445
|
-
begin
|
|
446
|
-
"hello"
|
|
447
|
-
rescue
|
|
448
|
-
42
|
|
449
|
-
ensure
|
|
450
|
-
x = "side_effect"
|
|
451
|
-
end
|
|
452
|
-
end
|
|
453
|
-
end
|
|
454
|
-
"#;
|
|
455
|
-
let genv = analyze(source);
|
|
456
|
-
let info = genv
|
|
457
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
458
|
-
.expect("Foo#bar should be registered");
|
|
459
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
460
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String)");
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
#[test]
|
|
464
|
-
fn test_rescue_variable_scope_restore() {
|
|
465
|
-
// Rescue variable should not destroy outer binding
|
|
466
|
-
let source = r#"
|
|
467
|
-
class Foo
|
|
468
|
-
def bar
|
|
469
|
-
e = "outer"
|
|
470
|
-
begin
|
|
471
|
-
"hello"
|
|
472
|
-
rescue => e
|
|
473
|
-
e
|
|
474
|
-
end
|
|
475
|
-
e
|
|
476
|
-
end
|
|
477
|
-
end
|
|
478
|
-
"#;
|
|
479
|
-
let genv = analyze(source);
|
|
480
|
-
let info = genv
|
|
481
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
482
|
-
.expect("Foo#bar should be registered");
|
|
483
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
484
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
485
|
-
// After rescue block, e should be restored to outer binding (String)
|
|
486
|
-
assert!(type_str.contains("String"), "should contain String: {}", type_str);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
#[test]
|
|
490
|
-
fn test_rescue_variable_scope_removal() {
|
|
491
|
-
// When rescue variable has no prior binding, it should be removed after rescue block
|
|
492
|
-
let source = r#"
|
|
493
|
-
class Foo
|
|
494
|
-
def bar
|
|
495
|
-
begin
|
|
496
|
-
"hello"
|
|
497
|
-
rescue => e
|
|
498
|
-
e
|
|
499
|
-
end
|
|
500
|
-
end
|
|
501
|
-
end
|
|
502
|
-
"#;
|
|
503
|
-
let genv = analyze(source);
|
|
504
|
-
let info = genv
|
|
505
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
506
|
-
.expect("Foo#bar should be registered");
|
|
507
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
508
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
509
|
-
// begin body (String) + rescue body where e = StandardError
|
|
510
|
-
assert!(type_str.contains("String"), "should contain String: {}", type_str);
|
|
511
|
-
assert!(
|
|
512
|
-
type_str.contains("StandardError"),
|
|
513
|
-
"should contain StandardError: {}",
|
|
514
|
-
type_str
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
#[test]
|
|
519
|
-
fn test_rescue_specific_exception_class() {
|
|
520
|
-
let source = r#"
|
|
521
|
-
class Foo
|
|
522
|
-
def bar
|
|
523
|
-
begin
|
|
524
|
-
"hello"
|
|
525
|
-
rescue ArgumentError => e
|
|
526
|
-
e
|
|
527
|
-
end
|
|
528
|
-
end
|
|
529
|
-
end
|
|
530
|
-
"#;
|
|
531
|
-
let genv = analyze(source);
|
|
532
|
-
let info = genv
|
|
533
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
534
|
-
.expect("Foo#bar should be registered");
|
|
535
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
536
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
537
|
-
assert!(
|
|
538
|
-
type_str.contains("ArgumentError"),
|
|
539
|
-
"should contain ArgumentError: {}",
|
|
540
|
-
type_str
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
#[test]
|
|
545
|
-
fn test_rescue_multiple_exception_classes() {
|
|
546
|
-
let source = r#"
|
|
547
|
-
class Foo
|
|
548
|
-
def bar
|
|
549
|
-
begin
|
|
550
|
-
"hello"
|
|
551
|
-
rescue TypeError, NameError => e
|
|
552
|
-
e
|
|
553
|
-
end
|
|
554
|
-
end
|
|
555
|
-
end
|
|
556
|
-
"#;
|
|
557
|
-
let genv = analyze(source);
|
|
558
|
-
let info = genv
|
|
559
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
560
|
-
.expect("Foo#bar should be registered");
|
|
561
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
562
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
563
|
-
assert!(
|
|
564
|
-
type_str.contains("TypeError"),
|
|
565
|
-
"should contain TypeError: {}",
|
|
566
|
-
type_str
|
|
567
|
-
);
|
|
568
|
-
assert!(
|
|
569
|
-
type_str.contains("NameError"),
|
|
570
|
-
"should contain NameError: {}",
|
|
571
|
-
type_str
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
#[test]
|
|
576
|
-
fn test_rescue_qualified_exception_class() {
|
|
577
|
-
let source = r#"
|
|
578
|
-
class Foo
|
|
579
|
-
def bar
|
|
580
|
-
begin
|
|
581
|
-
"hello"
|
|
582
|
-
rescue Net::HTTPError => e
|
|
583
|
-
e
|
|
584
|
-
end
|
|
585
|
-
end
|
|
586
|
-
end
|
|
587
|
-
"#;
|
|
588
|
-
let genv = analyze(source);
|
|
589
|
-
let info = genv
|
|
590
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
591
|
-
.expect("Foo#bar should be registered");
|
|
592
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
593
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
594
|
-
assert!(
|
|
595
|
-
type_str.contains("Net::HTTPError"),
|
|
596
|
-
"should contain Net::HTTPError: {}",
|
|
597
|
-
type_str
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
#[test]
|
|
602
|
-
fn test_empty_rescue_body_is_nil() {
|
|
603
|
-
let source = r#"
|
|
604
|
-
class Foo
|
|
605
|
-
def bar
|
|
606
|
-
begin
|
|
607
|
-
"hello"
|
|
608
|
-
rescue
|
|
609
|
-
end
|
|
610
|
-
end
|
|
611
|
-
end
|
|
612
|
-
"#;
|
|
613
|
-
let genv = analyze(source);
|
|
614
|
-
let info = genv
|
|
615
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
616
|
-
.expect("Foo#bar should be registered");
|
|
617
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
618
|
-
let type_str = get_type_show(&genv, ret_vtx);
|
|
619
|
-
assert!(type_str.contains("String"), "should contain String: {}", type_str);
|
|
620
|
-
assert!(type_str.contains("nil"), "should contain nil: {}", type_str);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
@@ -224,57 +224,3 @@ fn infer_range_element_type(
|
|
|
224
224
|
}
|
|
225
225
|
None
|
|
226
226
|
}
|
|
227
|
-
|
|
228
|
-
#[cfg(test)]
|
|
229
|
-
mod tests {
|
|
230
|
-
use super::*;
|
|
231
|
-
|
|
232
|
-
#[test]
|
|
233
|
-
fn test_install_string_literal() {
|
|
234
|
-
let mut genv = GlobalEnv::new();
|
|
235
|
-
let vtx = genv.new_source(Type::string());
|
|
236
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "String");
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
#[test]
|
|
240
|
-
fn test_install_integer_literal() {
|
|
241
|
-
let mut genv = GlobalEnv::new();
|
|
242
|
-
let vtx = genv.new_source(Type::integer());
|
|
243
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Integer");
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
#[test]
|
|
247
|
-
fn test_install_float_literal() {
|
|
248
|
-
let mut genv = GlobalEnv::new();
|
|
249
|
-
let vtx = genv.new_source(Type::float());
|
|
250
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Float");
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
#[test]
|
|
254
|
-
fn test_install_regexp_literal() {
|
|
255
|
-
let mut genv = GlobalEnv::new();
|
|
256
|
-
let vtx = genv.new_source(Type::regexp());
|
|
257
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Regexp");
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
#[test]
|
|
261
|
-
fn test_install_interpolated_string_literal() {
|
|
262
|
-
let mut genv = GlobalEnv::new();
|
|
263
|
-
let vtx = genv.new_source(Type::string());
|
|
264
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "String");
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
#[test]
|
|
268
|
-
fn test_install_interpolated_symbol_literal() {
|
|
269
|
-
let mut genv = GlobalEnv::new();
|
|
270
|
-
let vtx = genv.new_source(Type::symbol());
|
|
271
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Symbol");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
#[test]
|
|
275
|
-
fn test_install_interpolated_regexp_literal() {
|
|
276
|
-
let mut genv = GlobalEnv::new();
|
|
277
|
-
let vtx = genv.new_source(Type::regexp());
|
|
278
|
-
assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Regexp");
|
|
279
|
-
}
|
|
280
|
-
}
|
data/core/src/analyzer/loops.rs
CHANGED
|
@@ -92,210 +92,3 @@ pub(crate) fn process_for_node(
|
|
|
92
92
|
|
|
93
93
|
Some(genv.new_source(Type::Nil))
|
|
94
94
|
}
|
|
95
|
-
|
|
96
|
-
#[cfg(test)]
|
|
97
|
-
mod tests {
|
|
98
|
-
use crate::analyzer::install::AstInstaller;
|
|
99
|
-
use crate::env::{GlobalEnv, LocalEnv};
|
|
100
|
-
use crate::graph::VertexId;
|
|
101
|
-
use crate::parser::ParseSession;
|
|
102
|
-
use crate::types::Type;
|
|
103
|
-
|
|
104
|
-
/// Helper: parse Ruby source, process with AstInstaller, and return GlobalEnv
|
|
105
|
-
fn analyze(source: &str) -> GlobalEnv {
|
|
106
|
-
let session = ParseSession::new();
|
|
107
|
-
let parse_result = session.parse_source(source, "test.rb").unwrap();
|
|
108
|
-
let root = parse_result.node();
|
|
109
|
-
let program = root.as_program_node().unwrap();
|
|
110
|
-
|
|
111
|
-
let mut genv = GlobalEnv::new();
|
|
112
|
-
let mut lenv = LocalEnv::new();
|
|
113
|
-
|
|
114
|
-
let mut installer = AstInstaller::new(&mut genv, &mut lenv, source);
|
|
115
|
-
for stmt in &program.statements().body() {
|
|
116
|
-
installer.install_node(&stmt);
|
|
117
|
-
}
|
|
118
|
-
installer.finish();
|
|
119
|
-
|
|
120
|
-
genv
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/// Helper: get the type string for a vertex ID (checks both Vertex and Source)
|
|
124
|
-
fn get_type_show(genv: &GlobalEnv, vtx: VertexId) -> String {
|
|
125
|
-
if let Some(vertex) = genv.get_vertex(vtx) {
|
|
126
|
-
vertex.show()
|
|
127
|
-
} else if let Some(source) = genv.get_source(vtx) {
|
|
128
|
-
source.ty.show()
|
|
129
|
-
} else {
|
|
130
|
-
panic!("vertex {:?} not found as either Vertex or Source", vtx);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
#[test]
|
|
135
|
-
fn test_while_returns_nil() {
|
|
136
|
-
let source = r#"
|
|
137
|
-
class Foo
|
|
138
|
-
def bar
|
|
139
|
-
while true
|
|
140
|
-
"hello"
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
"#;
|
|
145
|
-
let genv = analyze(source);
|
|
146
|
-
let info = genv
|
|
147
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
148
|
-
.expect("Foo#bar should be registered");
|
|
149
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
150
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
#[test]
|
|
154
|
-
fn test_until_returns_nil() {
|
|
155
|
-
let source = r#"
|
|
156
|
-
class Foo
|
|
157
|
-
def bar
|
|
158
|
-
until false
|
|
159
|
-
"hello"
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
"#;
|
|
164
|
-
let genv = analyze(source);
|
|
165
|
-
let info = genv
|
|
166
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
167
|
-
.expect("Foo#bar should be registered");
|
|
168
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
169
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
#[test]
|
|
173
|
-
fn test_while_variable_assignment_in_body() {
|
|
174
|
-
// Should not panic — variable assignment inside loop is processed
|
|
175
|
-
let source = r#"
|
|
176
|
-
x = "initial"
|
|
177
|
-
while true
|
|
178
|
-
x = "hello"
|
|
179
|
-
end
|
|
180
|
-
"#;
|
|
181
|
-
analyze(source);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
#[test]
|
|
185
|
-
fn test_while_modifier_form() {
|
|
186
|
-
let source = r#"
|
|
187
|
-
class Foo
|
|
188
|
-
def bar
|
|
189
|
-
x = "hello" while false
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
"#;
|
|
193
|
-
let genv = analyze(source);
|
|
194
|
-
let info = genv
|
|
195
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
196
|
-
.expect("Foo#bar should be registered");
|
|
197
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
198
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
#[test]
|
|
202
|
-
fn test_begin_end_while() {
|
|
203
|
-
let source = r#"
|
|
204
|
-
class Foo
|
|
205
|
-
def bar
|
|
206
|
-
begin
|
|
207
|
-
"hello"
|
|
208
|
-
end while false
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
"#;
|
|
212
|
-
let genv = analyze(source);
|
|
213
|
-
let info = genv
|
|
214
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
215
|
-
.expect("Foo#bar should be registered");
|
|
216
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
217
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// --- for loop tests ---
|
|
221
|
-
|
|
222
|
-
#[test]
|
|
223
|
-
fn test_for_returns_nil() {
|
|
224
|
-
let source = r#"
|
|
225
|
-
class Foo
|
|
226
|
-
def bar
|
|
227
|
-
for x in [1, 2, 3]
|
|
228
|
-
x
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
"#;
|
|
233
|
-
let genv = analyze(source);
|
|
234
|
-
let info = genv
|
|
235
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
236
|
-
.expect("Foo#bar should be registered");
|
|
237
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
238
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
#[test]
|
|
242
|
-
fn test_for_variable_type_from_array() {
|
|
243
|
-
let source = r#"
|
|
244
|
-
for item in [1, 2, 3]
|
|
245
|
-
item
|
|
246
|
-
end
|
|
247
|
-
"#;
|
|
248
|
-
// Should not panic; loop variable is registered
|
|
249
|
-
analyze(source);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
#[test]
|
|
253
|
-
fn test_for_variable_persists_after_loop() {
|
|
254
|
-
// for does NOT create a new scope — variable persists
|
|
255
|
-
let source = r#"
|
|
256
|
-
class Foo
|
|
257
|
-
def bar
|
|
258
|
-
for x in [1, 2, 3]
|
|
259
|
-
end
|
|
260
|
-
x
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
"#;
|
|
264
|
-
// Should not panic — x is accessible after the loop
|
|
265
|
-
analyze(source);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
#[test]
|
|
269
|
-
fn test_for_empty_body() {
|
|
270
|
-
let source = r#"
|
|
271
|
-
class Foo
|
|
272
|
-
def bar
|
|
273
|
-
for x in [1, 2, 3]
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
end
|
|
277
|
-
"#;
|
|
278
|
-
let genv = analyze(source);
|
|
279
|
-
let info = genv
|
|
280
|
-
.resolve_method(&Type::instance("Foo"), "bar")
|
|
281
|
-
.expect("Foo#bar should be registered");
|
|
282
|
-
let ret_vtx = info.return_vertex.unwrap();
|
|
283
|
-
assert_eq!(get_type_show(&genv, ret_vtx), "nil");
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
#[test]
|
|
287
|
-
fn test_for_with_method_call_in_body() {
|
|
288
|
-
// Should not panic — method call on loop variable is processed
|
|
289
|
-
// (type error check requires RBS, covered by Ruby integration test)
|
|
290
|
-
let source = r#"
|
|
291
|
-
class Foo
|
|
292
|
-
def bar
|
|
293
|
-
for item in ["hello", "world"]
|
|
294
|
-
item.upcase
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
"#;
|
|
299
|
-
analyze(source);
|
|
300
|
-
}
|
|
301
|
-
}
|