This is a Lua-to-Clojure parser. It takes Lua source code string as an input and produces eval'able Clojure code. This is a work-in-progress, and some language features are not supported currently (and maybe never will). Targeted Lua version is 5.3.
This library can be used when you need to express certain logic in a very simple imperative language. These bits of logic can be then externalised into files or directly used inside a Clojure program via a macro.
There is a very transparent boundary between Lua and Clojure functions when using luaclj: all Lua functions become Clojure functions, and all Clojure functions can be directly invoked in Lua code. Lua tables become Clojure maps, and vice versa.
In project.clj:
[luaclj "0.1.3"]
And in target namespace:
(ns example.core
(:require [luaclj.core :refer :all]
[luaclj.library :refer :all]
))
luaclj.core namespace exports several functions:
(lua->clj "local v = 0; for i = 1,100 do v = v + i end return v")
Result:
(clojure.core/fn
anonymous-chunk
[]
(luaclj.util/process-return
(luaclj.proteus/let-mutable
[v
0
_
(luaclj.util/process-break
(clojure.core/doseq
[i (clojure.core/range 1 (clojure.core/inc 100))]
(do (set! v (+ v i)))))
_
(return v)])))
process-return
and process-break
are internal macros that deal with return and break statements.
lua->clj
also accepts two optional keyword parameters: :fns
and :nowrap
:
:fns
tells the parser that a list of function definitions is excepted, so for instance
(lua->clj
"function f1(arg1, arg2)
return arg1 + arg2
end
function f2(x,y,z)
return x^y*z
end"
:fns)
will yield:
((def
f1
(clojure.core/fn
f1
[arg1 arg2]
(luaclj.util/process-return (return (+ arg1 arg2)))))
(def
f2
(clojure.core/fn
f2
[x y z]
(luaclj.util/process-return (return (* (expt x y) z))))))
:nowrap
tells parser not to wrap generated code into an anonymous fn. Compare:
(lua->clj "return 8^8")
(clojure.core/fn anonymous-chunk [] (luaclj.util/process-return (return (expt 8 8))))
and
(lua->clj "return 8^8" :nowrap)
(luaclj.util/process-return (return (expt 8 8)))
eval-lua
will invoke lua->clj
and then eval it in context of current namespace
(eval-lua "return 2^3+3")
Result:
#function[/eval141857/anonymous-chunk--141858] ;your results may differ
There is also a lua
macro that can serve as an infix syntax helper. For instance:
(lua if 3 < 5 then return "true" else return "false" end)
There are some caveats, however: all commas, table constructors and accessors should be surrounded with quotes. Otherwise Clojure reader will ignore commas and complain when tables contain odd number of entries. So the following sample Lua code:
sum = 0
for j = 1, 99 do
sum = sum + j
end
t = {1, 10, 30}
t['a'] = 9
has to be presented as:
sum = 0
for j = 1"," 99 do
sum = sum + j
end
t = "{1, 10, 30}"
t"['a']" = 9
- Local and global variable declarations
- if, while, repeat, for (with break statements)
- function calls/definitions, both local and global
- tables
- correct operator precedence
- metatables
- varargs
- standard library functions, except for
pairs
andipairs
- multiple return values from functions
- labels
Special thanks goes to Mark Engelberg (Instaparse), Zach Tellman (Proteus), and Nathan Marz (Specter). The library incorporates a slightly modified version of Proteus.
Distributed under the MIT License.