2011-05-10 71 views
8

我已经用Racket(以前称为PLT Scheme)构建了一个相当复杂的应用程序,并且希望为调试目的添加REPL。我试图让它通过TCP流访问:通过TCP的球拍REPL

(define repl-server 
    (thread (lambda() 
      (let ((listener (tcp-listen 8082 5 #t))) 
      (do() (#f) 
       (let-values (((in out) (tcp-accept listener))) 
       (thread (lambda() 
          (let ((port-string (get-port-string in))) 
          (Try "debug-repl" #f 
           (begin 
           (file-stream-buffer-mode out 'line) 
           (display-and-log "Password: " out) 
           (flush-output out) 
           (when (string=? (read-line in) "whatever") 
            (log "Connect to REPL: " port-string)) 
            (current-input-port in) 
            (current-output-port out) 
            (current-error-port out) 
            (read-eval-print-loop)) 
           (close-input-port in) 
           (close-output-port out)))))))))))) 

(Try name result-if-exception form)是提供基本的异常处理的宏,(日志...)和(显示和记录...)?他们什么声音喜欢。

现在,如果我访问REPL,我甚至不能评估常量,因为我不断收到错误compile: unbound identifier (and no #%app syntax transformer is bound) at: #%top-interaction。我怎样才能让这个REPL工作?在启动REPL服务器之前,如何访问值defined?

+4

大问题!你真的应该在球拍邮件列表http://lists.racket-lang.org/users/上提出这个问题。我可以预测以下几点:1)有办法做到这一点。 2)可能会很痛苦。 3)你可能想看看沙箱。 – 2011-05-10 07:23:05

+0

注意自我:下次使用'addlog'或类似的名称作为该功能的名称... – lbruder 2011-05-10 07:57:50

回答

3

您使用的是read-eval-print-loop,与eval基本相同,因此存在同样的问题。有关详细说明,请参见relevant Guide section。最好是完全阅读,但你要找的答案要么是“命名空间”部分描述的内容,要么是“命名空间和模块”部分 - 第一个是如果你想要一个顶级的命名空间,并且第二个是如果你想要一个与代码出现的实际文件相对应的名称空间(第一个通常更好 - 例如,如果你使用第二个,那么repl-server本身可用于REPL用户,这使得它成为一个有问题的功能...)

下面是它会是什么样子:

... 
(thread (lambda() 
      (parameterize ([current-namespace (make-base-namespace)]) 
      ...same code...))) 
... 

和第二个,定义一个锚和使用namespace-anchor->namespace作为页面所显示的最后一个例子。

[BTW,也看到了run-server的事情,这是一个有点老了,但仍然是有用的。]

+0

完美地工作!我实际上使用了第二种情况,因为这应该是普通用户无法访问的调试黑客。完全访问正在运行的程序!我现在正在快乐地跳跃着:) – lbruder 2011-05-10 07:56:48

+1

为了记录,John的评论也非常相关 - “racket/sandbox”库也对制作健壮的repl有用。 (但是,从上述评论来看,显然它向着你想要去的方向是不太可能的。) – 2011-05-10 08:08:51