Jarc> (let x 10 (let y 11 (+ x y z))) Error: Symbol 'z' has no value 0: z DEBUG 0: b Backtrace: 0: z 1: (+ x y z) 2: ((fn (y) (+ x y z)) 11) 3: ((fn (x) (let y 11 (+ x y z))) 10) 4: (with (x 10) (let y 11 (+ x y z))) 5: (let x 10 (let y 11 (+ x y z))) 0: z DEBUG 0: h Debugger commands: b Print the Lisp backtrace d Move down the backtrace e Eval following expression f Move to the specified frame h Print this help m Print the error message p Print the current frame in the backtrace q Quit the debugger and return to top-level r Return following expression as value of current frame s Print the Java stack trace u Move up the backtrace 0: z DEBUG 0: e x 10 0: z DEBUG 0: r 13 34 Jarc>
Jarc 12 now has a compiler which optimizes tail-recursive functions. It's not generic tail-call elimination, but it can optimize functions that call themselves.
(use 'sql) (sql-driver "com.mysql.jdbc.Driver") (= jdbc-url "jdbc:mysql://localhost/MyDB") (= db-username "root") (= db-password "") (def blah-create () (with-open db (sql-connect jdbc-url db-username db-password) (sql-update db "CREATE TABLE Blah ( id INTEGER NOT NULL PRIMARY KEY, value VARCHAR(100) NULL ) TYPE=InnoDB"))) (def blah-insert-values (id value) (with-open db (sql-connect jdbc-url db-username db-password) (sql-update db "insert into Blah (id,value) values (?,?)" id value))) (def blah-insert (blah-obj) (with-open db (sql-connect jdbc-url db-username db-password) (sql-insert db "Blah" blah-obj))) (def blah-list () (with-open db (sql-connect jdbc-url db-username db-password) (with-open stmt (sql-stmt db "select id,value from Blah") (with-open rs (sql-query stmt) (while (next rs) (prn (getObject rs 1) "\t" (getObject rs "value"))))))) (def blah-update-values (id value) (with-open db (sql-connect jdbc-url db-username db-password) (sql-update db "update Blah set value=? where id=?" value id))) (def blah-update (id blah-obj) (with-open db (sql-connect jdbc-url db-username db-password) (sql-modify db "Blah" blah-obj "where id=?" id))) Jarc> (blah-create) 0 Jarc> (blah-insert-values 10 "can") 1 Jarc> (blah-insert (obj id 11 value "cannot")) 1 Jarc> (blah-list) 10 can 11 cannot nil Jarc> (sql-trace 't) nil Jarc> (blah-update 11 (obj id 11 value "can't")) SQL: com.mysql.jdbc.PreparedStatement@5c435a3a: update Blah set value='can\'t',id=11 where id=11 1 Jarc> (blah-list) SQL: com.mysql.jdbc.PreparedStatement@585976c2: select id,value from Blah 10 can 11 can't nil
Tracing displays the SQL statements (in the current thread only). Prepared statements are used in the implementation which improves performance and minimizes SQL injection attacks.
SQL selects require closing the result set (rs) before closing the statement, so the statement (stmt) has to be created explicitly when using sql-query. When using sql-update the statement is created internally.
The macro with-open does the same things as let and then also calls close at the end of the let body.
For a more complete example see testsql.sql.
Jarc> (match "(\S+) " "foo bar") "foo" Jarc> (let it "foo bar baz" (match "(\S+) (\S+)")) ("bar" "foo") Jarc>
Like Perl, match searches the default variable, which in Arc is "it".
Jarc> (while-matches "(\w+)=(\w*)" "foo=1\nbar=2\nbaz=3" (prn \1 " => " \2)) foo => 1 bar => 2 baz => 3 nil
Jarc has a Java Servlet for creating web apps in arc. It doesn't use the standard arc html package. Jarc web apps looks like this:
(use 'jtml) (def /hello (req res) (html (head) (body "Hello World. " ;; Query parameters are available by apply: (p "Hi to " req!name) ;; All getXXX methods of HttpServletRequest are available by apply also: (p "Request method is " req!Method) (p "Cookies: " (ul (each cookie req!Cookies (li (pr (getName cookie) '= (getValue cookie)))))) (p (a href '/ "Index")) ) ) )
(def msec () (getTime (new java.util.Date)))
The "new" function creates an instance of a Java class.
The interpreter dispatches on the first argument. [1] So "getTime" is a Java method on Date. Jarc does a run-time method lookup on the Java class and finds "getTime". Arguments are automatically converted into the appropriate Java types to make the call whereever possible. In this simple example there are no arguments being passed to "getTime".
Static Java method calls also look just like Arc function calls:
(def system (cmd) (let proc (exec (java.lang.Runtime.getRuntime) cmd) (let in (new java.io.BufferedReader (new java.io.InputStreamReader (getInputStream proc))) (awhile (readLine in) (prn it)) (close in))))
This conflicts with the dot notation in Arc. Jarc trades-off compatibility in this one instance for easier Java method access. It saves typing one whole token!
If a static method is not found, then Arc dot notation semantics are used, so in practice there isn't any conflict.
Starting with Jarc 8 methods on java.lang.String automatically apply to Jarc strings.
(replaceAll "foo" "o" "e") => "fee"
You can override methods on java.lang.String with macros, but not with functions. Java method calls take precedence over Arc functions. And macros take precedence over everything, of course.
I started writing this because I wanted a powerful language to write quick and dirty throw-away programs that call existing Java APIs. Like the Java API for the network management product I used to work on during the day. The main goal is that calling Java classes should be as concise as possible.
Jarc began in 2005 before Paul Graham released arc0. He had written enough on his web site about his ideas for Arc, that I was able to build something close to what Arc actually is.
I have used this at work to build two prototypes and also for some throw-away data crunching. It has been a great tool. Much better than writing in Java!
After Arc was released I updated Jarc to be compatible with Arc.
The biggest difference was that Jarc had dynamic binding and Arc does not. Changing that broke the cool things about Arc, like the debugger and sql package. They had to be converted to not rely on dynamic binding.
The lastest version is available at: Jarc SourceForge download page.
You can also browse the source code on SourceForge.
[1] Paul Graham suggested that Arc might have dispatch on first arg in Arc at 3 Weeks.