1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 09:59:29 +00:00
candran/compiler/lua53.can
Reuh 4af2b41a0d Candran 0.3.0
* Added @ self alias
* Added short anonymous functions declaration
* Made assignment operators works in every direction, except up, down,
behind and below, because this would be hard to visualize.
* Moved files around.
* Error rewriting.
* Discover the amazing can commandline tool, which includes a fantastic°
REPL and program running abilities.
* Added functions which plagiarize Lua.
* Added 0.1.0 to the version number.
* If you still love pineapple flavored bread, don't hesitate to show
your feelings.

Also, the tests are out of date. Sad.

°: not really.
2017-08-16 22:33:44 +02:00

314 lines
7.8 KiB
Text

return function(code, ast, options)
local lastInputPos = 1
local prevLinePos = 1
local lastSource = "nil"
local lastLine = 1
local indentLevel = 0
local function newline()
local r = options.newline .. string.rep(options.indentation, indentLevel)
if options.mapLines then
local sub = code:sub(lastInputPos)
local source, line = sub:sub(1, sub:find("\n")):match("%-%- (.-)%:(%d+)\n")
if source and line then
lastSource = source
lastLine = tonumber(line)
else
for _ in code:sub(prevLinePos, lastInputPos):gmatch("\n") do
lastLine += 1
end
end
prevLinePos = lastInputPos
r = " -- " .. lastSource .. ":" .. lastLine .. r
end
return r
end
local function indent()
indentLevel += 1
return newline()
end
local function unindent()
indentLevel -= 1
return newline()
end
local required = {}
local requireStr = ""
local function addRequire(str, name, field)
if not required[str] then
requireStr ..= "local " .. options.requirePrefix .. name .. (" = require(%q)"):format(str) .. (field and "."..field or "") .. options.newline
required[str] = true
end
end
local function getRequire(name)
return options.requirePrefix .. name
end
local tags
local function lua(ast, forceTag, ...)
if options.mapLines and ast.pos then
lastInputPos = ast.pos
end
return tags[forceTag or ast.tag](ast, ...)
end
tags = setmetatable({
-- block: { stat* } --
Block = function(t)
local r = ""
for i=1, #t-1, 1 do
r = r .. lua(t[i]) .. newline()
end
if t[#t] then
r = r .. lua(t[#t])
end
return r
end,
-- stat --
-- Do{ stat* }
Do = function(t)
return "do" .. indent() .. lua(t, "Block") .. unindent() .. "end"
end,
-- Set{ {lhs+} (opid? = opid?)? {expr+} }
Set = function(t)
if #t == 2 then
return lua(t[1], "_lhs") .. " = " .. lua(t[2], "_lhs")
elseif #t == 3 then
return lua(t[1], "_lhs") .. " = " .. lua(t[3], "_lhs")
elseif #t == 4 then
if t[3] == "=" then
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], t[4][1] }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do
r = r .. ", " .. lua({ t[2], t[1][i], t[4][i] }, "Op")
end
return r
else
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[3], t[4][1], t[1][1] }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do
r = r .. ", " .. lua({ t[3], t[4][i], t[1][i] }, "Op")
end
return r
end
else -- You are mad.
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], { tag = "Op", t[4], t[5][1], t[1][1] } }, "Op")
for i=2, math.min(#t[5], #t[1]), 1 do
r = r .. ", " .. lua({ t[2], t[1][i], { tag = "Op", t[4], t[5][i], t[1][i] } }, "Op")
end
return r
end
end,
-- While{ expr block }
While = function(t)
return "while " .. lua(t[1]) .. " do" .. indent() .. lua(t[2]) .. unindent() .. "end"
end,
-- Repeat{ block expr }
Repeat = function(t)
return "repeat".. indent() .. lua(t[1]) .. unindent() .. "until " .. lua(t[2])
end,
-- If{ (expr block)+ block? }
If = function(t)
local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent()
for i=3, #t-1, 2 do
r = r .. "elseif " .. lua(t[i]) .. " then" .. indent() .. lua(t[i+1]) .. unindent()
end
if #t % 2 == 1 then
r = r .. "else" .. indent() .. lua(t[#t]) .. unindent()
end
return r .. "end"
end,
-- Fornum{ ident expr expr expr? block }
Fornum = function(t)
local r = "for " .. lua(t[1]) .. " = " .. lua(t[2]) .. ", " .. lua(t[3])
if #t == 5 then
return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end"
else
return r .. " do" .. indent() .. lua(t[4]) .. unindent() .. "end"
end
end,
-- Forin{ {ident+} {expr+} block }
Forin = function(t)
return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. lua(t[3]) .. unindent() .. "end"
end,
-- Local{ {ident+} {expr+}? }
Local = function(t)
local r = "local "..lua(t[1], "_lhs")
if t[2][1] then
r = r .. " = "..lua(t[2], "_lhs")
end
return r
end,
-- Localrec{ ident expr }
Localrec = function(t)
return "local function "..lua(t[1][1])..lua(t[2][1], "_functionWithoutKeyword")
end,
-- Goto{ <string> }
Goto = function(t)
return "goto " .. lua(t[1], "Id")
end,
-- Label{ <string> }
Label = function(t)
return "::" .. lua(t[1], "Id") .. "::"
end,
-- Return{ <expr*> }
Return = function(t)
return "return "..lua(t, "_lhs")
end,
-- Break
Break = function()
return "break"
end,
-- apply (below)
-- expr --
-- Nil
Nil = function()
return "nil"
end,
-- Dots
Dots = function()
return "..."
end,
-- Boolean{ <boolean> }
Boolean = function(t)
return tostring(t[1])
end,
-- Number{ <number> }
Number = function(t)
return tostring(t[1])
end,
-- String{ <string> }
String = function(t)
return ("%q"):format(t[1])
end,
-- Function{ { ( `ParPair{ Id expr } | `Id{ <string> } )* `Dots? } block }
_functionWithoutKeyword = function(t)
local r = "("
local decl = {}
if t[1][1] then
if t[1][1].tag == "ParPair" then
local id = lua(t[1][1][1])
indentLevel += 1
table.insert(decl, id .. " = " .. id .. " == nil and " .. lua(t[1][1][2]) .. " or " .. id)
indentLevel -= 1
r = r .. id
else
r = r .. lua(t[1][1])
end
for i=2, #t[1], 1 do
if t[1][i].tag == "ParPair" then
local id = lua(t[1][i][1])
indentLevel += 1
table.insert(decl, "if " .. id .. " == nil then " .. id .. " = " .. lua(t[1][i][2]) .. " end")
indentLevel -= 1
r = r .. ", " ..id
else
r = r .. ", " .. lua(t[1][i])
end
end
end
r = r .. ")" .. indent()
for _, d in ipairs(decl) do
r = r .. d .. newline()
end
return r .. lua(t[2]) .. unindent() .. "end"
end,
Function = function(t)
return "function" .. lua(t, "_functionWithoutKeyword")
end,
-- Table{ ( `Pair{ expr expr } | expr )* }
Pair = function(t)
return "[" .. lua(t[1]) .. "] = " .. lua(t[2])
end,
Table = function(t)
if #t == 0 then
return "{}"
elseif #t == 1 then
return "{ " .. lua(t, "_lhs") .. " }"
else
return "{" .. indent() .. lua(t, "_lhs") .. unindent() .. "}"
end
end,
-- Op{ opid expr expr? }
Op = function(t)
local r
if #t == 2 then
if type(tags._opid[t[1]]) == "string" then
r = tags._opid[t[1]] .. " " .. lua(t[2])
else
r = tags._opid[t[1]](t[2])
end
else
if type(tags._opid[t[1]]) == "string" then
r = lua(t[2]) .. " " .. tags._opid[t[1]] .. " " .. lua(t[3])
else
r = tags._opid[t[1]](t[2], t[3])
end
end
return r
end,
-- Paren{ expr }
Paren = function(t)
return "(" .. lua(t[1]) .. ")"
end,
-- apply (below)
-- lhs (below)
-- apply --
-- Call{ expr expr* }
Call = function(t)
return lua(t[1]) .. "(" .. lua(t, "_lhs", 2) .. ")"
end,
-- Invoke{ expr `String{ <string> } expr* }
Invoke = function(t)
return lua(t[1])..":"..lua(t[2], "Id").."("..lua(t, "_lhs", 3)..")"
end,
-- lhs --
_lhs = function(t, start)
start = start or 1
local r
if t[start] then
r = lua(t[start])
for i=start+1, #t, 1 do
r = r .. ", "..lua(t[i])
end
else
r = ""
end
return r
end,
-- Id{ <string> }
Id = function(t)
return t[1]
end,
-- Index{ expr expr }
Index = function(t)
return lua(t[1]).."["..lua(t[2]).."]"
end,
-- opid --
_opid = {
add = "+", sub = "-", mul = "*", div = "/",
idiv = "//", mod = "%", pow = "^", concat = "..",
band = "&", bor = "|", bxor = "~", shl = "<<", shr = ">>",
eq = "==", ne = "~=", lt = "<", gt = ">", le = "<=", ge = ">=",
["and"] = "and", ["or"] = "or", unm = "-", len = "#", bnot = "~", ["not"] = "not"
}
}, {
__index = function(self, key)
error("don't know how to compile a "..tostring(key).." to Lua 5.3")
end
})
#placeholder("patch")
return requireStr .. lua(ast) .. newline()
end