mirror of
https://github.com/Reuh/candran.git
synced 2025-10-27 09:59:29 +00:00
Changed a LOT. Notable changes: * Removed decorators, as they're not that useful, unless rewriting most Lua libraries API. * Added functions parameters default values. * Added Lua 5.3 stuff and building to Lua 5.1. * Remplaced the LuaMinify parser by lua-parser. It now requires some non-Lua dependencies (LPeg) unfortunately, but it's waaaaaay easier to handle. Code should be adaptable to any Metalua-like AST generator anyway. * The generated code now look like shit, and comment are stripped, because the parser ignore them. Oh well. * Changed a few things in the preprocessor environment. * Nobody will read this commit message I guess. If you did, create an issue saying "I love pineapple flavored bread".
148 lines
4.4 KiB
Text
148 lines
4.4 KiB
Text
#import("util")
|
|
#import("compiler.lua53")
|
|
#import("compiler.luajit")
|
|
#import("lua-parser.scope")
|
|
#import("lua-parser.validator")
|
|
#import("lua-parser.pp")
|
|
#import("lua-parser.parser")
|
|
#import("cmdline")
|
|
|
|
local util = require("util")
|
|
|
|
local candran = {
|
|
VERSION = "0.2.0"
|
|
}
|
|
|
|
--- Run the preprocessor
|
|
-- @tparam input string input code
|
|
-- @tparam args table arguments for the preprocessor. They will be inserted into the preprocessor environement.
|
|
-- @treturn output string output code
|
|
function candran.preprocess(input, args={})
|
|
-- generate preprocessor code
|
|
local preprocessor = ""
|
|
for line in (input.."\n"):gmatch("(.-\n)") do
|
|
if line:match("^%s*#") and not line:match("^#!") then -- exclude shebang
|
|
preprocessor ..= line:gsub("^%s*#", "")
|
|
else
|
|
preprocessor ..= ("write(%q)"):format(line:sub(1, -2)) .. "\n"
|
|
end
|
|
end
|
|
preprocessor ..= "return output"
|
|
|
|
-- make preprocessor environement
|
|
local env = {}
|
|
for k,v in pairs(_G) do
|
|
env[k] = v
|
|
end
|
|
for k, v in pairs(args) do
|
|
env[k] = v
|
|
end
|
|
--- Candran library table
|
|
env.candran = candran
|
|
--- Current preprocessor output
|
|
env.output = ""
|
|
--- Import an external Candran/Lua module into the generated file
|
|
-- @tparam modpath string module path
|
|
-- @tparam margs table preprocessor arguments to use when preprocessessing the module
|
|
-- @tparam autoRequire[opt=true] boolean true to automatically load the module into a local variable
|
|
env.import = function(modpath, margs=args, autoRequire=true)
|
|
local filepath = assert(util.search(modpath), "No module named \""..modpath.."\"")
|
|
|
|
-- open module file
|
|
local f = io.open(filepath)
|
|
if not f then error("Can't open the module file to import") end
|
|
for k, v in pairs(args) do
|
|
if margs[k] == nil then margs[k] = v end
|
|
end
|
|
local modcontent = candran.preprocess(f:read("*a"), margs)
|
|
f:close()
|
|
|
|
-- get module name (ex: module name of path.to.module is module)
|
|
local modname = modpath:match("[^%.]+$")
|
|
|
|
env.write(
|
|
"-- MODULE \""..modpath.."\" --\n"..
|
|
"local function _()\n"..
|
|
modcontent.."\n"..
|
|
"end\n"..
|
|
(autoRequire and "local "..modname.." = _() or "..modname.."\n" or "").. -- auto require
|
|
"package.loaded[\""..modpath.."\"] = "..(autoRequire and modname or "_()").." or true\n".. -- add to package.loaded
|
|
"-- END OF MODULE \""..modpath.."\" --"
|
|
)
|
|
end
|
|
--- Include another file content in the preprocessor output.
|
|
-- @tparam file string filepath
|
|
env.include = function(file)
|
|
local f = io.open(file)
|
|
if not f then error("Can't open the file "..file.." to include") end
|
|
env.write(f:read("*a"))
|
|
f:close()
|
|
end
|
|
--- Write a line in the preprocessor output.
|
|
-- @tparam ... string strings to write (similar to print)
|
|
env.write = function(...)
|
|
env.output ..= table.concat({...}, "\t") .. "\n"
|
|
end
|
|
--- Will be replaced with the content of the variable with the given name, if it exists.
|
|
-- @tparam name string variable name
|
|
env.placeholder = function(name)
|
|
if env[name] then
|
|
env.write(env[name])
|
|
end
|
|
end
|
|
|
|
-- compile & load preprocessor
|
|
local preprocess, err = util.loadenv(candran.compile(preprocessor, args.target), "candran preprocessor", env)
|
|
if not preprocess then error("Error while creating Candran preprocessor: " .. err) end
|
|
|
|
-- execute preprocessor
|
|
local success, output = pcall(preprocess)
|
|
if not success then error("Error while preprocessing file: " .. output .. "\nWith preprocessor : \n" .. preprocessor) end
|
|
|
|
return output
|
|
end
|
|
|
|
-- Compiler
|
|
function candran.compile(input, target="lua53")
|
|
local parse = require("lua-parser.parser").parse
|
|
|
|
local ast, errmsg = parse(input, "candran")
|
|
|
|
if not ast then
|
|
error("Compiler: error while parsing file: "..errmsg)
|
|
end
|
|
|
|
return require("compiler."..target)(ast)
|
|
end
|
|
|
|
-- Preprocess & compile
|
|
function candran.make(code, args={})
|
|
return candran.compile(candran.preprocess(code, args), args.target)
|
|
end
|
|
|
|
function candran.searcher(modpath)
|
|
-- get module filepath
|
|
local notfound = ""
|
|
local filepath
|
|
for path in package.path:gsub("%.lua", ".can"):gmatch("[^;]+") do
|
|
local path = path:gsub("%?", (modpath:gsub("%.", "/")))
|
|
local f = io.open(path)
|
|
if f then
|
|
f:close()
|
|
filepath = path
|
|
else
|
|
notfound = notfound .. "\n\tno Candran file '"..path.."'"
|
|
end
|
|
end
|
|
if not filepath then return notfound end
|
|
|
|
-- open module file
|
|
local f = io.open(filepath)
|
|
if not f then error("Can't open the module file to import") end
|
|
local modcontent = f:read("*a")
|
|
f:close()
|
|
|
|
return load(candran.make(modcontent))
|
|
end
|
|
|
|
return candran
|