On Nov 23, 2008, at 2:30 PM, Stuart Sierra wrote:

> Hmm, you mean write the REPL in Clojure?  I hadn't though of that.
> Intriguing idea.  It would be neat if the REPL were just a function,
> so you could start it from within a program using arbitrary input/
> output streams.  Something to think about...

I've uploaded a patch along those lines: ant-compile-main.patch, 
http://tinyurl.com/5azp3u 
  based on our recent work on this. This includes Compile.java,  
main.clj, and modifies build.xml.

I'd appreciate interested folks giving it a try and giving feedback.  
(I've included instructions at the end of this message if you're  
unfamiliar with doing that.) The patch changes clojure.jar to point to  
the new class "clojure.main" for its main entry point. In the patched  
Clojure, a new, flexible Clojure main is defined in src/clj/clojure/ 
main.clj .

I decided not to include compile as one of the options in main.clj for  
now because it shares little with the other options and made the help  
text longer. I'd be comfortable with a "clj" script that does eval,  
scripting, and repl and a separate "cljc" script that does compiling  
(analogous to java and javac). Opinions welcome.

Here are some examples of using the proposed clojure.main via "java - 
jar clojure.jar":

Display usage info:

% java -jar clojure.jar --help
Usage: java -jar clojure.jar [option*] [file-arg*] [--] [arg*]

options:
   -h, --help       Print this help message and exit
   -e, --eval expr  Evaluate an expression and print its value
   -r, --repl       Run an interactive Read-Eval-Print Loop
   file             Run code from from file
   -                Run code from standard input

   With no options, Clojure runs a repl.

   The eval options may be repeated but must not appear after other  
options.

   The remaining options stop options processing and consider the rest  
of
   the command line arguments as file-args and args, separated by "--",
   all of which are optional. Clojure binds the list of args to
   *command-line-args*, loads any files named by file-args, then  
starts the
   repl or loads from the file or standard in.

With no options, run a repl:

        % java -jar clojure.jar
        Clojure
        user=> (+ 3 4)
        7
        user=>

Evaluate Clojure code from the command line:

        % java -jar clojure.jar -e 3 -e "(+ 3 4)" -e "*ns*" -e "\"this is fun 
\""
        3
        7
        #<Namespace clojure.core>
        this is fun

Here are some Clojure source code files to illustrate the order of  
things:

        % cat init.clj
        (print "hi from init.clj, arguments are ")
        (prn *command-line-args*)
        % cat init2.clj
        (print "hi from init2.clj, arguments are ")
        (prn *command-line-args*)
        % cat script.clj
        (print "hi from script.clj, arguments are ")
        (prn *command-line-args*)

Combining eval and repl, demonstrating that the repl can load files  
and see arguments:

        % java -jar clojure.jar -e "\"welcome to the repl\"" --repl init.clj  
-- 1 2 :a :b
        welcome to the repl
        hi from init.clj, arguments are ("1" "2" ":a" ":b")
        Clojure
        user=> *command-line-args*
        (1 2 :a :b)
        user=>

Run a script from a file by just giving the filename:

        % java -jar clojure.jar script.clj
        hi from script.clj, arguments are nil

Now using a filename, no files to load, and arguments:

        % java -jar clojure.jar script.clj -- 1 2 3
        hi from script.clj, arguments are ("1" "2" "3")

Now using a filename, files to load before it, and arguments

        % java -jar clojure.jar script.clj init.clj init2.clj -- a b c
        hi from init.clj, arguments are ("a" "b" "c")
        hi from init2.clj, arguments are ("a" "b" "c")
        hi from script.clj, arguments are ("a" "b" "c")

Executing Clojure code piped into standard in:

        % echo "(prn (sort '(:a :z :m :q)))" | java -jar clojure.jar -
        (:a :m :q :z)

The patch also includes a repl written in Clojure in src/clj/clojure/ 
main.clj. It supports optional keyword arguments that let you  
customize it quite a bit while defaulting to the familiar behavior of  
java version:

-------------------------
clojure.main/repl
([& options])
   Read-eval-print loop. Options are sequential keyword-value
   pairs. Available options and their defaults:

      - :ns, symbol naming the initial namespace for the repl
        default: 'user

      - :prompt, function of no arguments, prompts for more input
        default: #(printf "%s=> " (ns-name *ns*))

      - :flush, function of no arguments, flushes output
        default: flush

      - :read, function of one argument, returns the next object read  
from
        the input, or its argument iff the input is exhausted
        default: #(read *in* false %)

      - :eval, funtion of one argument, returns the evaluation of its
        argument
        default: eval

      - :print, function of one argument, prints its argument to the  
output
        default: println

      - :caught, function of one argument, a throwable, called when
        read, eval, or print throws an exception or error
        default: #(.println *err* (repl-exception %))

Using the customization we can, for example, run a sub-repl with  
customized prompt and eval as one might like to do to produce examples  
for a book or explore reader macros. This version of eval returns a  
string that notes what it got from the reader and the result of the  
eval.

user=> (clojure.main/repl :prompt #(print "? ") :eval #(str % " =>  
" (eval %)))
? 14
14 => 14
? (/ 14 3)
(/ 14 3) => 14/3
? '(1 2 3)
(quote (1 2 3)) => (1 2 3)
? ^#'+
(clojure.core/meta (var +)) => {:arglists ([] [x] [x y] [x y &  
more]), :file "core.clj", :name +, :inline #<core$fn__2834 clojure.core 
[EMAIL PROTECTED]>, :line 540, :doc "Returns the sum of nums. (+)  
returns 0.", :inline-arities #{2}, :ns #<Namespace clojure.core>}
? nil
user=>

Comments and suggestions are welcome. It would be great if we could  
converge on something that Rich would find worthwhile to include in  
Clojure.

--Steve


Here's a quick rundown on patching Clojure to try out a patch  
(requires that the svn command (subversion) be available in your path)  
and that you copy the patch to /tmp:

download a fresh clojure, patch it, and run the jar:

        cd /tmp
        svn co https://clojure.svn.sourceforge.net/svnroot/clojure/trunk  
clojure
        cd clojure
        patch -p0 < /tmp/ant-compile-main.patch
        ant
        java -jar clojure.jar
        Enjoy!



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to