egallesio / STklos

STklos Scheme
http://stklos.net
GNU General Public License v2.0
67 stars 17 forks source link

`select-module` inside `let` -- strange behavior #652

Open jpellegrini opened 1 month ago

jpellegrini commented 1 month ago

When select-module is used inside a LET, the result seems a bit confusing...

(define-module x)

(let ((a 1))
  (select-module x)
  a)

==> (#[module stklos])
(define-module x)

(let ((a 1))
  (select-module x)
  (select-module stklos)
  a)

==> (#[module MBE] #[module SRFI-0] #[module REPL] #[module REPL-READLINE] #[module STKLOS-OBJECT] #[module STKLOS-COMPILER] #[module stklos])

I have read the source of select-module, but still can't see why this happens. Is the local scope somehow attached to the module? And when we change the module, the scope is gone?

I have compared the bytecode for (select-module x) to the bytecode for the first expression (above):

stklos> (disassemble-expr ' (select-module x) #t)

000:  PREPARE-CALL        
001:  CONSTANT-PUSH        0
003:  GREF-INVOKE          1 1
006:  SET-CUR-MOD         
007:  IM-VOID             
008:

Constants:
0: x
1: find-module
stklos> (disassemble-expr 
' (let ((a 1))
    (select-module x)
    a) #t)

000:  PREPARE-CALL        
001:  ONE-PUSH            
002:  ENTER-LET            1
004:  PREPARE-CALL        
005:  CONSTANT-PUSH        0
007:  GREF-INVOKE          1 1
010:  SET-CUR-MOD         
011:  IM-VOID             
012:  LOCAL-REF0          
013:  LEAVE-LET           
014:

Constants:
0: x
1: find-module

This second one ends with local-ref0 (before the leave-let), so it "should" have returned the value of a... unless this local-ref0 actually depends on the current module. (?)

jpellegrini commented 1 month ago

I forgot the explain why I used select-module inside a let: I was trying to write a with-module macro, and it didn't work...

(define-macro (with-module mod . body)
  (let ((old-module (gensym 'old-module))
        (res        (gensym 'res)))
    `(let ((,old-module (current-module)))
       (select-module ,mod)
       (let ((,res (begin ,@body)))
         (select-module ,old-module)
         ,res))))

But that didn't work for a couple of reasons (including the fact that I can't seem to guarantee that the current-module symbol has the binding from the SCHEME module)