Skip to content

Latest commit

 

History

History
144 lines (124 loc) · 3.84 KB

README.md

File metadata and controls

144 lines (124 loc) · 3.84 KB

luaclj

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.

Why?

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.

Usage

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

Supported language features

  • Local and global variable declarations
  • if, while, repeat, for (with break statements)
  • function calls/definitions, both local and global
  • tables
  • correct operator precedence

Not supported yet

  • metatables
  • varargs
  • standard library functions, except for pairs and ipairs
  • multiple return values from functions
  • labels

Acknowledgments

Special thanks goes to Mark Engelberg (Instaparse), Zach Tellman (Proteus), and Nathan Marz (Specter). The library incorporates a slightly modified version of Proteus.

License

Distributed under the MIT License.