@@ -336,67 +336,84 @@ def compile_hash(scope, *args)
336
336
compile_callm ( scope , :Hash , :[] , pairs )
337
337
end
338
338
339
- def compile_case ( scope , *args )
340
- # error(":case not implemented yet", scope, [:case]+args)
341
- # FIXME:
342
- # Implement like this: compile_eval_arg
343
- # save the register, and loop over the "when"'s.
344
- # Compile each of the "when"'s as "if"'s where the value
345
- # is loaded from the stack and compared with the value
346
- # (or values) in the when clause
347
-
348
-
349
- # experimental (need to look into saving to register etc..):
350
- # but makes it compile all the way through for now...
351
-
352
- @e . comment ( "compiling case expression" )
353
- compare_exp = args . first
354
-
355
- @e . comment ( "compare_exp: #{ compare_exp } " )
356
-
357
- test = lambda do |test_exprs |
358
- if test_exprs . is_a? ( Array ) && test_exprs [ 0 ] == :comma
339
+ # FIXME: Compiler @bug: This method was a self-recursive
340
+ # lambda in `#compile_case`
341
+ def compile_case_test ( compare_exp , test_exprs )
342
+ test_value = test_exprs
343
+ xrest = [ ]
344
+ if test_exprs . is_a? ( Array )
345
+ #STDERR.puts test_exprs.inspect
346
+ if test_exprs [ 0 ] == :comma
359
347
test_value = test_exprs [ 1 ]
360
- rest = test_exprs [ 2 ]
361
- else
362
- test_value = test_exprs
363
- rest = [ ]
348
+ xrest = Array ( test_exprs [ 2 ] )
364
349
end
365
- cmp = [ :callm , test_value , :=== , [ compare_exp ] ]
350
+ #STDERR.puts xrest.inspect
351
+ end
352
+ cmp = [ :callm , test_value , :=== , [ compare_exp ] ]
366
353
367
- rest . empty? ? cmp : [ :or , cmp , test . call ( rest ) ]
354
+ if xrest . empty?
355
+ cmp
356
+ else
357
+ [ :or , cmp , compile_case_test ( compare_exp , xrest ) ]
368
358
end
359
+ end
369
360
370
- r = lambda do |whens |
371
- exp = whens . first
361
+ # FIXME: This is unsafe. It only works for the compiler
362
+ # for now because none of the case expressions in the
363
+ # compiler itself have side effects.
364
+ def compile_whens ( compare_exp , whens )
365
+ exp = whens . first
372
366
373
- if exp [ 0 ] == :when
374
- test_values = exp [ 1 ]
367
+ if exp [ 0 ] == :when
368
+ test_values = exp [ 1 ]
375
369
376
- body = exp [ 2 ] # body to be executed, if compare_exp === test_value
370
+ body = exp [ 2 ] # body to be executed, if compare_exp === test_value
377
371
378
- @e . comment ( "test_value: #{ test_values . inspect } " )
379
- @e . comment ( "body: #{ body . inspect } " )
372
+ @e . comment ( "test_value: #{ test_values . inspect } " )
373
+ @e . comment ( "body: #{ body . inspect } " )
380
374
381
- rest = whens . slice ( 1 ..-1 )
382
- if rest . empty?
383
- rest = [ :do ]
384
- else
385
- rest = r . call ( rest )
386
- end
387
- [ :do , [ :if , test . call ( test_values ) , [ :do ] +body , rest ] ]
375
+ xrest = whens . slice ( 1 ..-1 )
376
+ if xrest . empty?
377
+ xrest = [ :do ]
388
378
else
389
- [ :do ] + exp
379
+ xrest = compile_whens ( compare_exp , xrest )
390
380
end
381
+ [ :do , [ :if , compile_case_test ( compare_exp , test_values ) , [ :do ] +body , xrest ] ]
382
+ else
383
+ [ :do ] +exp
391
384
end
385
+ end
386
+
387
+ def compile_case ( scope , *args )
388
+ # FIXME: Compiler @bug:
389
+ # The `xrest`'s below were `rest` but that causes `rest` in the
390
+ # expression `arg.rest` to be misinterpreted during rewrite to
391
+ # method call relative to the contents of the `rest` variable,
392
+ # which needless to say is a total disaster.
393
+ #
394
+ # Further, there is likely another problem here, in that it looks like
395
+ # a single, shared, environment is created for the two lambdas, but that
396
+ # may be unavoidable given Ruby semantics.
392
397
393
- rest = args . rest
394
- exprs = rest [ 0 ]
395
- if rest [ 1 ]
396
- exprs << rest [ 1 ]
398
+ # FIXME:
399
+ # Implement like this: compile_eval_arg
400
+ # save the register, and loop over the "when"'s.
401
+ # Compile each of the "when"'s as "if"'s where the value
402
+ # is loaded from the stack and compared with the value
403
+ # (or values) in the when clause
404
+
405
+ @e . comment ( "compiling case expression" )
406
+ compare_exp = args . first
407
+
408
+ @e . comment ( "compare_exp: #{ compare_exp } " )
409
+
410
+ xrest = args . rest
411
+ exprs = xrest [ 0 ]
412
+ if xrest [ 1 ]
413
+ exprs << xrest [ 1 ]
397
414
end
398
415
399
- exprs = r . call ( exprs )
416
+ exprs = compile_whens ( compare_exp , exprs )
400
417
compile_eval_arg ( scope , exprs )
401
418
402
419
return Value . new ( [ :subexpr ] )
@@ -660,7 +677,9 @@ def compile_exp(scope, exp)
660
677
pos = exp . position
661
678
end
662
679
663
- @e . lineno ( pos ) if pos
680
+ if pos && exp [ 0 ] != :defm
681
+ @e . lineno ( pos ) if pos
682
+ end
664
683
#trace(pos,exp)
665
684
666
685
# check if exp is within predefined keywords list
0 commit comments