PageRenderTime 91ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/swank.lua

http://github.com/matsu911/swank-lua
Lua | 370 lines | 355 code | 14 blank | 1 comment | 18 complexity | e1640a7460464d56e7dccfb7cc9007fa MD5 | raw file
  1. -- -*- mode: lua; indent-tabs-mode: nil -*-
  2. function identity(x) return x end
  3. function string.left_common(s1, s2)
  4. local i = 1
  5. while s1:sub(i, i) == s2:sub(i, i) do
  6. i = i + 1
  7. end
  8. return s1:sub(1, i - 1)
  9. end
  10. function table.keys(tbl)
  11. if not tbl then return {} end
  12. local ret = {}
  13. for k,_ in pairs(tbl) do
  14. table.insert(ret, k)
  15. end
  16. return ret
  17. end
  18. function string.split(s, sep)
  19. local ret = {}
  20. while s:find(sep) do
  21. local i,j = s:find(sep)
  22. table.insert(ret, s:sub(1, i-1))
  23. s = s:sub(j+1)
  24. end
  25. if s then
  26. table.insert(ret, s)
  27. end
  28. return ret
  29. end
  30. function double_quote(s)
  31. return '"' .. (s or "") .. '"'
  32. end
  33. function filter(pred, tbl)
  34. local function filter_aux(pred, tbl, ret)
  35. if #tbl == 0 then
  36. return ret
  37. else
  38. if pred(tbl[1]) then
  39. table.insert(ret, tbl[1])
  40. end
  41. return filter_aux(pred, {unpack(tbl, 2)}, ret)
  42. end
  43. end
  44. return filter_aux(pred, tbl, {})
  45. end
  46. function map(f, tbl)
  47. local function map_aux(f, tbl, ret)
  48. if #tbl == 0 then
  49. return ret
  50. else
  51. table.insert(ret, f(tbl[1]))
  52. return map_aux(f, {unpack(tbl, 2)}, ret)
  53. end
  54. end
  55. return map_aux(f, tbl, {})
  56. end
  57. function reduce(f, tbl)
  58. local function reduce_aux(f, tbl, acc)
  59. if #tbl == 0 then
  60. return acc
  61. else
  62. return reduce_aux(f, {unpack(tbl, 2)}, f(acc, tbl[1]))
  63. end
  64. end
  65. if not tbl or #tbl == 0 then
  66. return nil
  67. else
  68. return reduce_aux(f, {unpack(tbl, 2)}, tbl[1])
  69. end
  70. end
  71. function print_capture()
  72. local self = { out={} }
  73. local mt = { __call = function(...) table.insert(self.out, table.concat(arg, "\t", 2)) end }
  74. setmetatable(self, mt)
  75. return self
  76. end
  77. function encode_message(command)
  78. return string.format("%06x", command:len()) .. command
  79. end
  80. function sexpr2table(s)
  81. local function sexpr2table_aux(s)
  82. local inside_quote = false
  83. local escaping = false
  84. local chunk = nil
  85. local ret = {}
  86. local i = 1
  87. while i <= s:len() do
  88. local c = s:sub(i, i)
  89. if escaping then
  90. chunk = (chunk or "") .. c
  91. escaping = false
  92. elseif c == '\\' then
  93. escaping = true
  94. elseif inside_quote then
  95. if c == '"' then
  96. inside_quote = not inside_quote
  97. else
  98. chunk = (chunk or "") .. c
  99. end
  100. elseif c == ' ' or c == ')' then
  101. if chunk then
  102. table.insert(ret, chunk)
  103. chunk = nil
  104. end
  105. if c == ')' then break end
  106. elseif c == '(' then
  107. local n, t = sexpr2table_aux(s:sub(i + 1))
  108. table.insert(ret, t)
  109. i = i + n
  110. elseif c == '"' then
  111. inside_quote = not inside_quote
  112. else
  113. chunk = (chunk or "") .. c
  114. end
  115. i = i + 1
  116. end
  117. return i, ret
  118. end
  119. local i, t = sexpr2table_aux(s)
  120. return t[1]
  121. end
  122. -- t = sexpr2table('(:emacs-rex (swank:connection-info) "COMMON-LISP-USER" t 1)\n')
  123. -- t = sexpr2table('(:emacs-rex (swank:listener-eval "\"abc\"\n") "LUA" :repl-thread 4)')
  124. -- t = sexpr2table('(:emacs-rex (swank:listener-eval "print(1)\n") "LUA" :repl-thread 7)')
  125. -- t = sexpr2table('(:emacs-rex (swank:listener-eval "\"abc\"\n") "LUA" :repl-thread 5)')
  126. -- t = sexpr2table('(swank:listener-eval "\"abc\"\n")')
  127. -- t = sexpr2table('(:emacs-rex (swank:listener-eval "\'abc\'\n") "LUA" :repl-thread 5)')
  128. -- for k,v in ipairs(t) do
  129. -- print(k,v)
  130. -- end
  131. function table2sexpstr(tbl)
  132. local ret = nil
  133. for k,v in pairs(tbl) do
  134. if type(v) == "table" then
  135. v = table2sexpstr(v)
  136. end
  137. if ret then
  138. ret = ret .. " " .. v
  139. else
  140. ret = v
  141. end
  142. end
  143. if ret then
  144. return "(" .. ret .. ")"
  145. else
  146. return "nil"
  147. end
  148. end
  149. function return_message(data, serial)
  150. return table2sexpstr({":return", data, serial})
  151. end
  152. function return_ok_message(data, serial)
  153. return return_message({":ok", data}, serial)
  154. end
  155. function return_abort_message(data, serial)
  156. return return_message({":abort", data}, serial)
  157. end
  158. function write_string_message(s, is_result)
  159. if is_result then
  160. return table2sexpstr({":write-string", s, ":repl-result"})
  161. else
  162. return table2sexpstr({":write-string", s})
  163. end
  164. end
  165. local swank = {}
  166. function swank.eval(self, str, serial, is_listener)
  167. local eval_str = "return " .. str
  168. self.logger("str", eval_str)
  169. local eval = loadstring(eval_str)
  170. if not eval then
  171. eval = loadstring(str)
  172. end
  173. if not eval then
  174. return nil, {}
  175. end
  176. local print_orig = _G.print
  177. local p = print_capture()
  178. _G.print = p
  179. local status, ret = pcall(eval)
  180. _G.print = print_orig
  181. self.logger("ret", ret)
  182. return self:result_message(serial, status, ret, p.out, is_listener)
  183. end
  184. function swank.completions(self, args, serial)
  185. local names = args[1]:split('%.')
  186. local prefix, base = {unpack(names, 1, #names-1)}, names[#names]
  187. local g = _G
  188. for _, name in ipairs(prefix) do
  189. g = g[name]
  190. if not g then break end
  191. end
  192. local function prepend_prefix(x)
  193. local s = table.concat(prefix, ".")
  194. if s:len() > 0 then
  195. return s .. "." .. x
  196. end
  197. return x
  198. end
  199. local candidates = filter(function(x) return x:find("^" .. base .. ".*" ) end, table.keys(g))
  200. return return_ok_message({map(double_quote, map(prepend_prefix, candidates)),
  201. double_quote(reduce(string.left_common,
  202. map(prepend_prefix, candidates)))}, serial), {}
  203. end
  204. function swank.listener_eval(self, args, serial)
  205. if args[1] == '\n' then
  206. selfl.ua_command = nil -- reset
  207. end
  208. self.lua_command = (self.lua_command or "") .. '\n' .. args[1]
  209. self.lua_command = self.lua_command:gsub("^%s*", ""):gsub("%s*$", "")
  210. self.logger(self.lua_command:len(), self.lua_command)
  211. if self.lua_command:len() == 0 then
  212. return return_ok_message('nil', serial), {}
  213. else
  214. local control_msg, write_str = self:eval(self.lua_command, serial, true)
  215. if control_msg then
  216. self.lua_command = nil
  217. else
  218. control_msg = return_ok_message('nil', serial)
  219. end
  220. return control_msg, write_str
  221. end
  222. end
  223. function swank.connection_info(self, args, serial)
  224. local function getpid()
  225. return tonumber(io.open("/proc/self/stat"):read():split(' ')[1])
  226. end
  227. local connection_response =
  228. {":encoding",
  229. {":coding-system", [["utf-8"]], ":external-format", [["UTF-8"]]},
  230. ":lisp-implementation",
  231. {":name", [["LUA"]], ":type", [["LUA"]], ":version", [["0.1"]]},
  232. ":package",
  233. {":name", [["LUA"]], ":prompt", [["LUA"]]},
  234. ":pid", getpid(),
  235. ":version", [["2011-06-21"]]}
  236. return return_ok_message(connection_response, serial), {}
  237. end
  238. function swank.swank_require(self, args, serial)
  239. return return_ok_message({}, serial), {}
  240. end
  241. function swank.create_repl(self, args, serial)
  242. return return_ok_message({[["LUA"]], [["LUA"]]}, serial), {}
  243. end
  244. function swank.quit_lisp(self, args, serial)
  245. os.exit(0)
  246. return return_ok_message('nil', serial), {}
  247. end
  248. function swank.buffer_first_change(self, args, serial)
  249. return return_ok_message(":not-available", serial), {}
  250. end
  251. function swank.autodoc(self, args, serial)
  252. return return_ok_message(":not-available", serial), {}
  253. end
  254. function swank.interactive_eval_region(self, args, serial)
  255. return swank.eval(self, args[1], serial, false)
  256. end
  257. function swank.result_message(self, serial, status, ret, print_messages, is_listener)
  258. local write_str = {}
  259. if status then
  260. for _, msg in pairs(print_messages) do
  261. table.insert(write_str, write_string_message(double_quote(msg), false))
  262. table.insert(write_str, write_string_message('"\n"', false))
  263. end
  264. if is_listener then
  265. table.insert(write_str, write_string_message(double_quote(tostring(ret)), true))
  266. table.insert(write_str, write_string_message('"\n"', true))
  267. return return_ok_message('nil', serial), write_str
  268. else
  269. return return_ok_message(tostring(ret), serial), write_str
  270. end
  271. else
  272. return return_abort_message(double_quote(ret:gsub('"', '\\"')), serial), write_str
  273. end
  274. end
  275. function swank.load_file(self, args, serial)
  276. local print_orig = _G.print
  277. local p = print_capture()
  278. _G.print = p
  279. local status, ret = pcall(dofile, args[1])
  280. _G.print = print_orig
  281. return self:result_message(serial, status, ret, p.out, false)
  282. end
  283. local dispatcher = {
  284. ['swank:connection-info'] = swank.connection_info,
  285. ['swank:swank-require'] = swank.swank_require,
  286. ['swank:create-repl'] = swank.create_repl,
  287. ['swank:quit-lisp'] = swank.quit_lisp,
  288. ['swank:buffer-first-change'] = swank.buffer_first_change,
  289. ['swank:autodoc'] = swank.autodoc,
  290. ['swank:completions'] = swank.completions,
  291. ['swank:interactive-eval-region'] = swank.interactive_eval_region,
  292. ['swank:listener-eval'] = swank.listener_eval,
  293. ['swank:load-file'] = swank.load_file,
  294. }
  295. local socket = require("socket");
  296. local host = host or "localhost";
  297. local port = port or "4005";
  298. local server = assert(socket.bind(host, port));
  299. swank.logger = print
  300. while 1 do
  301. swank.logger("server: waiting for client connection...");
  302. control = assert(server:accept())
  303. while 1 do
  304. local len = tonumber(assert(control:receive(6)), 16)
  305. local command = assert(control:receive(len))
  306. swank.logger("command", command)
  307. command = sexpr2table(command)
  308. local serial = tonumber(command[5])
  309. local swank_command = command[2][1]
  310. local swank_args = {unpack(command[2], 2)}
  311. local control_msg, write_str = nil, {}
  312. swank.logger("swank_command", swank_command)
  313. for k,v in ipairs(command[2]) do
  314. swank.logger(k,v)
  315. end
  316. local func = dispatcher[swank_command]
  317. if func then
  318. control_msg, write_str = func(swank, swank_args, serial)
  319. end
  320. swank.logger("response", control_msg)
  321. swank.logger()
  322. for _, str in pairs(write_str) do
  323. control:send(encode_message(str))
  324. end
  325. if control_msg then
  326. command = ""
  327. control:send(encode_message(control_msg))
  328. end
  329. end
  330. end