General question:
Can I invoke the current racket executable from within a running Racket script?
Basically, I'd like a replacement for (system "racket ...") in the case that (find-executable-path "racket") does not return a path to the Racket executable I'm currently using.
Context:
What I really want is to try compiling a few expressions and assert that they raise compilation errors. This is for unit testing.
I don't believe you need to step outside of the executable here. Try this:
#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))))))
I think I'm correct when I say that Racket is singularly clean in its ability to provide the compiler to running programs in a disciplined way.
If your goal is just to compile some racket expressions, you can do that just with either compile or compile-syntax. An example file would be:
#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))))
Where exn:fail? is whatever exception you are looking for.
Furthermore, if you have some common syntax context you want to run your test in, you can use #` #,. So your code would end up something like this:
#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)))))
Finally, if your code is stored on your computer, you can use John's solution, while using file->string to convert the file into a string.
For small tests, you can also use convert-compile-time-error from the syntax/macro-testing library. It turns an expression that causes a compile-time error into an expression that raises a run-time error when evaluated. The expression uses the environment where it occurs in the module, including local bindings; you don't have to fiddle with namespaces and eval.
(check-exn #rx"bad syntax"
(lambda () (convert-compile-time-error (lambda))))
There's also convert-syntax-error (on the same page).
Related
I was asked to write a program in racket in order to change the behaviours of arithmetic operators from prefix to postfix. More precisely:
I want this code: (a b +) to behave like: (+ a b)
I wanted to use define-syntax-rule in order to change the behaviour of the + operator, but I have one problem, while using define-syntax-rule we write at first the name of our macro, and after that we write the arguments.
My question: Is there any way to write the arguments at the beginning and the name at last in racket functions?
The easiest way to accomplish this is to create your own #%app macro. Since you are essentially creating a new language here, you'll want two modules: a 'lang' module that defines your language, and a 'use' module, for the program you want to write in that language. This could be done with two files, or one file using submodules.
Here, I'll show it to you using two files:
lang.rkt
#lang racket
(provide (except-out (all-from-out racket)
#%app)
(rename-out [-app #%app]))
(require syntax/parse/define)
(define-syntax-parse-rule (-app args ... proc)
(#%app proc args ...))
use.rkt
#lang s-exp "lang.rkt"
(3 2 +) ; => 5
Note though that this only changes function calls, not other forms. So:
use2.rkt
#lang s-exp "lang.rkt"
(define x 42)
(2 x *) ; => 84
Edit:
To explain what's happening in lang.rkt. It's taking the racket language, and re-exporting all of it, except the #%app macro. (For reference, all function applications in racket (f args ...) get expanded to (#%app f args ...).)
For the #%app macro, we define another macro -app, which moves the function call from the end to the start, and the uses Racket's #%app macro. We then rename -app to #%app on export.
Section 5.1 of this paper gives you an outline of the same thing, but to turn Racket into a lazy language.
If I want to optionally require a module at runtime, I can use [dynamic-require'1. This works great if I want to require a package that has been installed, for example:
(dynamic-require 'racket/match 'match)
This will (provided I have racket/match installed), require racket/match and evaluate to the match binding in that library.
However, I run into trouble when I want to require a local, non installed module. Let's say I have some module called eat.rkt, which provides one function: bite:
#lang racket ;; eat.rkt
(provide bite)
(define (bite) "Nom nom")
Now lets say we want to make a lunch.rkt module that requires eat.rkt, and calls the function. Furthermore, lets suppose I put them in the same directory:
#lang racket ;; lunch.rkt
(require "eat.rkt")
(bite) ; => Nom Nom
This is fine because I used static require, but this falls apart when I want to do a dynamic-require:
#lang racket ;; lunch2.rkt
(define bite (dynamic-require "eat.rkt" 'bite)
(bite) ; => Nom Nom
While this appears to be fine, it turns out that the module required by dynamic-require is NOT required based on the module's path, but on current-directory. So, if I run the program in the directory the module is defined, that's fine, but if I'm in another directory, everything breaks:
$ racket lunch2.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch2.rkt
; default-load-handler: cannot open module file
Obviously I could just change the current-directory to this module's directory if I know where it is. But if I don't know this module's path, is there any way to get it? Or, more directly, is it possible to dynamic-require a module relative to the requiring's module path?
The define-runtime-path form defines a path that will be available at runtime and is independent of the current-directory. Use it to define the path to the module you want to require dynamically, for example:
#lang racket
(require racket/runtime-path)
(define-runtime-path eat "eat.rkt")
(dynamic-require eat 'bite)
The easiest way to dynamic-require a module relative to the current module path (which is to say the path where the module is saved), is to get that module path and append it your relative module.
You can do this with #%variable-reference and variable-reference->module-path-index. (You may also want to use variable-reference->resolved-module-path for other situations, but we will not do it here.) Composing these two functions gives us a module-path-index? to the module being defined. (Or in general, the module that the #%variable-reference came from.)
So, we can a variable like:
(define here (variable-reference->module-path-index (#%variable-reference)))
Now all that is left is to compose this here path with the relative path to the module we want to require. We are looking for the module path analogy of build-path, if you will.
It turns out that the function we are looking for is: module-path-index-join, which takes a base path and a relative path and appends them together. The result will look something like:
(module-path-index-join "eat.rkt" here)
(Yes, it is backwards of what you would expect from build-path, but the base path comes second for this function.)
The resulting module, lunch3.rkt looks like:
#lang racket
(define here (variable-reference->module-path-index (#%variable-reference)))
(define bite (dynamic-require (module-path-index-join "eat.rkt" here) 'bite))
And now lunch3.rkt will require eat.rkt relative to where its defined, not based on the current-directory:
$ racket lunch3.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch3.rkt
"Nom Nom"
Thank you to Matthew Flatt for helping with this answer.
I'd like to selectively run a Racket module's submodules from another module. Please help me fill in the blanks!
File 1
#lang racket/base
;; <big file, lots of code>
(module+ small-tests
;; basic correctness checks
(displayln "Small tests pass!")
)
(module+ big-tests
;; heavy duty stress tests
(displayln "Big tests pass!")
)
File 2
#lang racket/base
(module+ main
;; Trigger either the small-tests or the big-tests,
;; depending on what's written here.
(require '???)
)
It would also be great if running the big tests would automatically run the small tests, too.
The submod form is used to require a module's submodule.
As an example:
#lang racket
(module A racket
(module+ main
(displayln "Hello World")))
(module B racket
(require (submod ".." A main)))
(require 'B)
Thanks to Leif and Alexis's hints, the way to get File 2 to run the small-tests submodule is to replace the '??? with:
(submod "file1.rkt" small-tests)
Also, editing the big-tests submodule to include the line:
(require (submod ".." small-tests))
will cause both small & big tests to run when File 2 executes (require (submod "file1.rkt" big-tests)).
I have a file "exceptions.rkt"
#lang racket
(module exceptions racket
(provide Macro/Raise Macro/Assert Macro/Assert* Macro/Domain-Assert)
; ... Definitions for provided symbols...
) ; End of module, end of file
Macro/Raise etc are not actually macros defined with define-syntax, they're just unary functions generated with syntax-rules and assigned a name
(define Macro/Raise
(syntax-rules ()
; ... body not important ...
))
and in the same folder as "exceptions.rkt", I have a file "tables.rkt".
#lang racket
(module tables racket
(require "exceptions.rkt")
(define-syntax Assert Macro/Assert)
; ... more stuff...
) ; End of module, end of file
but this results in Macro/Assert: undefined; cannot reference an identifier before its definition in module: 'tables phase: 1
I've tried reading the doc and can't figure out what I'm doing wrong... So what am I doing wrong?
In order for definitions to be usable during the macro definition phase, use for-syntax:
(require (for-syntax "exceptions.rkt"))
Also you don't need the (module exceptions racket ...) wrapper over the code since #lang racket already generates a module.
Haskell's main function does just what I want: evaluate when the file is loaded by itself (e.g. ./myfile.hs or runhaskell myfile.hs) and in no other case. main will not be called when the file is imported by another file. newLISP also has this functionality.
Is there equivalent code for Common Lisp?
I read the source code for CLISP. Here's what happens when the user enters clisp myfile.lisp or ./myfile.lisp:
CLISP saves myfile.lisp as p->argv_execute_file.
CLISP creates the expression (LOAD "p->argv_execute_file") and pushes it onto the Lisp stack.
CLISP saves any additional command-line arguments in a list.
CLISP stores the arguments in the Lisp variable *args*.
CLISP never makes a Lisp variable referring to p->argv_execute_file, so there is no way to discern whether myfile.lisp was loaded directly, by the user in the REPL, or by another Lisp file. If only (car *args*) were myfile.lisp, my task would be easy.
Note: Shebangs give CLISP trouble if the file is loaded from the REPL, so I put this code in ~/.clisprc.lisp:
(set-dispatch-macro-character #\# #\!
(lambda (stream character n)
(declare (ignore character n))
(read-line stream nil nil t)
nil))
I found a solution. It's a bit of shell trickery, but it works. I'll soon modify this to work on CL implementations other than CLISP.
#!/bin/sh
#|
exec clisp -q -q $0 $0 ${1+"$#"}
exit
|#
;;; Usage: ./scriptedmain.lisp
(defun main (args)
(format t "Hello World!~%")
(quit))
;;; With help from Francois-Rene Rideau
;;; http://tinyurl.com/cli-args
(let ((args
#+clisp ext:*args*
#+sbcl sb-ext:*posix-argv*
#+clozure (ccl::command-line-arguments)
#+gcl si:*command-args*
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
#+cmu extensions:*command-line-strings*
#+allegro (sys:command-line-arguments)
#+lispworks sys:*line-arguments-list*
))
(if (member (pathname-name *load-truename*)
args
:test #'(lambda (x y) (search x y :test #'equalp)))
(main args)))
(eval-when (situation*) ...)
Update sorry for the confusing answer.
I could be wrong, but it seems to be impossible to do what you want exactly. I would make a shell script and call clisp -i myfile.lisp -x (main).
Is there any reason to not make it executable (described here)?
P.S. Common Lisp is a language and clisp is one of the implementations.