14 return setmetatable (self, synth)
17 function synth:run (ast)
18 --if getmetatable (self) ~= synth and not ast then
20 self, ast = synth.new(), self
24 return table.concat (self._acc)
27 function synth:acc (x)
28 if x then table.insert (self._acc, x) end
32 if self.current_indent == 0 then
35 self:acc ("\n" .. self.indent_step:rep (self.current_indent))
38 function synth:nlindent ()
39 self.current_indent = self.current_indent + 1
43 function synth:nldedent ()
44 self.current_indent = self.current_indent - 1
45 self:acc ("\n" .. self.indent_step:rep (self.current_indent))
48 local keywords = table.transpose {
72 local function is_ident (id)
73 return id:strmatch "^[%a_][%w_]*$" and not keywords[id]
76 local function is_idx_stack (ast)
78 | `Id{ _ } -> return true
79 | `Index{ left, `String{ _ } } -> return is_idx_stack (left)
86 { "lt", "le", "eq", "ne" },
89 { "mul", "div", "mod" },
90 { "unary", "not", "len" },
96 for prec, ops in ipairs (op_preprec) do
97 for op in ivalues (ops) do
120 function synth:node (node)
121 assert (self~=synth and self._acc)
123 self:list (node, self.nl)
125 local f = synth[node.tag]
126 if type (f) == "function" then
127 f (self, node, unpack (node))
128 elseif type (f) == "string" then
132 self:acc (table.tostring (node, "nohash"))
138 function synth:list (list, sep, start)
139 for i = start or 1, # list do
143 elseif type (sep) == "function" then sep (self)
144 elseif type (sep) == "string" then self:acc (sep)
145 else error "Invalid list separator" end
150 function synth:Do (node)
153 self:list (node, self.nl)
158 function synth:Set (node)
160 | `Set{ { `Index{ lhs, `String{ method } } },
161 { `Function{ { `Id "self", ... } == params, body } } }
162 if is_idx_stack (lhs) and is_ident (method) ->
163 -- function foo:bar(...) ... end
169 self:list (params, ", ", 2)
172 self:list (body, self.nl)
176 | `Set{ { lhs }, { `Function{ params, body } } } if is_idx_stack (lhs) ->
177 -- function foo(...) ... end
181 self:list (params, ", ")
184 self:list (body, self.nl)
188 | `Set{ { `Id{ lhs1name } == lhs1, ... } == lhs, rhs } if not is_ident (lhs1name) ->
189 -- foo, ... = ... when foo isn't a valid identifier
195 self:list (lhs, ", ", 2)
198 self:list (rhs, ", ")
200 | `Set{ lhs, rhs } ->
202 self:list (lhs, ", ")
204 self:list (rhs, ", ")
208 function synth:While (node, cond, body)
213 self:list (body, self.nl)
218 function synth:Repeat (node, body, cond)
221 self:list (body, self.nl)
227 function synth:If (node)
228 for i = 1, #node-1, 2 do
229 local cond, body = node[i], node[i+1]
230 self:acc (i==1 and "if " or "elseif ")
234 self:list (body, self.nl)
240 self:list (node[#node], self.nl)
246 function synth:Fornum (node, var, first, last)
247 local body = node[#node]
256 self:node (node[4]) -- step increment
260 self:list (body, self.nl)
265 function synth:Forin (node, vars, generators, body)
267 self:list (vars, ", ")
269 self:list (generators, ", ")
272 self:list (body, self.nl)
277 function synth:Local (node, lhs, rhs)
279 self:list (lhs, ", ")
282 self:list (rhs, ", ")
286 function synth:Localrec (node, lhs, rhs)
288 | `Localrec{ { `Id{name} }, { `Function{ params, body } } } if is_ident (name) ->
289 self:acc "local function "
292 self:list (params, ", ")
295 self:list (body, self.nl)
301 self:acc (table.tostring (node, 'nohash', 80))
307 function synth:Call (node, f)
310 | `Call{ _, `String{_} }
311 | `Call{ _, `Table{...}} -> parens = false
320 self:list (node, ", ", 2)
326 function synth:Invoke (node, f, method)
329 | `Invoke{ _, _, `String{_} }
330 | `Invoke{ _, _, `Table{...}} -> parens = false
336 self:acc (parens and " (" or " ")
337 self:list (node, ", ", 3)
343 function synth:Return (node)
345 self:list (node, ", ")
348 synth.Break = "break"
350 synth.False = "false"
354 function synth:Number (node, n)
355 self:acc (tostring (n))
358 function synth:String (node, str)
359 self:acc (string.format ("%q", str):gsub ("\\\n", "\\n"))
362 function synth:Function (node, params, body)
365 self:list (params, ", ")
368 self:list (body, self.nl)
373 function synth:Table (node)
374 if not node[1] then self:acc "{ }" else
377 for i, elem in ipairs (node) do
379 | `Pair{ `String{ key }, value } if is_ident (key) ->
384 | `Pair{ key, value } ->
403 function synth:Op (node, op, a, b)
404 -- Transform not (a == b) into a ~= b
406 | `Op{ "not", `Op{ "eq", _a, _b } }
407 | `Op{ "not", `Paren{ `Op{ "eq", _a, _b } } } ->
408 op, a, b = "ne", _a, _b
413 local left_paren, right_paren
415 | `Op{ op_a, ...} if op_prec[op] >= op_prec[op_a] -> left_paren = true
416 | _ -> left_paren = false
419 match b with -- FIXME: might not work with right assoc operators
420 | `Op{ op_b, ...} if op_prec[op] >= op_prec[op_b] -> right_paren = true
421 | _ -> right_paren = false
424 self:acc (left_paren and "(")
426 self:acc (left_paren and ")")
428 self:acc (op_symbol [op])
430 self:acc (right_paren and "(")
432 self:acc (right_paren and ")")
438 | `Op{ op_a, ... } if op_prec[op] >= op_prec[op_a] -> paren = true
441 self:acc (op_symbol[op])
442 self:acc (paren and "(")
444 self:acc (paren and ")")
448 function synth:Paren (node, content)
454 function synth:Index (node, table, key)
457 | `Op{ op, ... } if op_prec[op] < op_prec.index -> paren_table = true
458 | _ -> paren_table = false
461 self:acc (paren_table and "(")
463 self:acc (paren_table and ")")
466 | `String{ field } if is_ident (field) ->
476 function synth:Id (node, name)
477 if is_ident (name) then
481 self:String (node, name)
487 local filename = (arg[2] or arg[1]) or arg[0]
488 local ast = mlc.luafile_to_ast (filename)
489 local status, src = xpcall (function () print(synth.run(ast)) end,
492 print (debug.traceback())
495 --print (synth.run (ast))