2015-12-13 28 views
6

Domanda di carattere generale:Richiamare `racket` in uno script Racket

Posso richiamare la corrente racket eseguibile all'interno di uno script in esecuzione Racket?

Fondamentalmente, mi piacerebbe una sostituzione per nel caso che (find-executable-path "racket") non restituisca un percorso all'eseguibile Racket che sto utilizzando attualmente.

Contesto:

Quello che voglio è quello di provare a compilare alcune espressioni e affermare che alzano errori di compilazione. Questo è per i test unitari.

+1

BTW, so che Typed Racket risolve questo problema, ma non capisco la soluzione. (Cos'è 'dr' [qui] (https://github.com/racket/typed-racket/blob/master/typed-racket-test/main.rkt#L66)?) –

+0

Caro Ben, avresti è piaciuto 'find-console-bin-dir' e' find-exe'. –

risposta

5

Non credo che sia necessario uscire dall'eseguibile qui. Prova questo:

#lang racket 

(require syntax/modread) 

;; define a namespace anchor to attach a namespace to: 
(define-namespace-anchor anchor) 
;; define a namespace for expansion: 
(define target-namespace (namespace-anchor->namespace anchor)) 

(define program-to-compile 
    "#lang racket 
(+ 3 4)") 

;; go ahead and expand 
(with-module-reading-parameterization 
(λ() 
    (parameterize ([current-namespace target-namespace]) 
    (expand 
    (read-syntax 
    "bogus-filename" 
    (open-input-string program-to-compile)))))) 

penso di essere corretto quando dico che Racket è singolarmente pulito nella sua capacità di fornire al compilatore di programmi in esecuzione in modo disciplinato.

+0

FWIW, la risposta di Leif è di livello superiore alla mia e probabilmente più vicina a quello che vuoi! –

4

Se il tuo obiettivo è solo quello di compilare alcune espressioni di racket, puoi farlo solo con compile o compile-syntax. Un file di esempio potrebbe essere:

#lang racket 
(require rackunit) 

(define tests 
    (list #'(+ 1 "3") 
     #'(void void) 
     #'(string-append 4))) 

(for/list ([t (in-list test)]) 
    (check-exn exn:fail? 
    (lambda() (compile t)))) 

Dove exn:fail? è tutto ciò eccezione si stanno cercando.

Inoltre, se si dispone di un contesto di sintassi comune in cui si desidera eseguire il test, è possibile utilizzare #`#,. Così il vostro codice finirebbe qualcosa di simile:

#lang racket 
(require rackunit) 

(define tests 
    (list #'(+ 1 "3") 
     #'(void void) 
     #'(string-append 4))) 

(for/list ([t (in-list test)]) 
    (check-exn exn:fail? 
    (lambda() (compile #`(module anonymous racket 
          #,t))))) 

Infine, se il codice è memorizzato sul computer, è possibile utilizzare la soluzione di Giovanni, durante l'utilizzo file->string per convertire il file in una stringa.

+0

Cosa succede se i miei 'test' sono in file separati? Posso chiamare 'compile' su un nome file o una porta? –

+0

Ho aggiornato la risposta per quello. –

2

Per i test di piccole dimensioni, è anche possibile utilizzare convert-compile-time-error dalla libreria syntax/macro-testing. Trasforma un'espressione che causa un errore in fase di compilazione in un'espressione che solleva un errore di runtime quando viene valutata. L'espressione utilizza l'ambiente in cui si verifica nel modulo, inclusi i binding locali; non devi armeggiare con namespace e eval.

(check-exn #rx"bad syntax" 
      (lambda() (convert-compile-time-error (lambda)))) 

C'è anche convert-syntax-error (nella stessa pagina).