1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 09:59:29 +00:00
candran/candran.can
Reuh 2a1e293aa5 Candran 0.2
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".
2017-08-06 18:45:52 +02:00

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