1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 17:59:30 +00:00
candran/lune.lune
2014-04-21 19:24:00 +02:00

180 lines
No EOL
4.8 KiB
Lua

#!/usr/bin/lua
--[[
Lune language & compiler by Thomas99.
LICENSE :
Copyright (c) 2014 Thomas99
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject
to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be appreciated
but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
]]
#include("lib/lexer.lua")
#include("lib/table.lua")
local lune = {}
lune.VERSION = "0.0.1"
lune.syntax = {
affectation = { ["+"] = "= %s +", ["-"] = "= %s -", ["*"] = "= %s *", ["/"] = "= %s /",
["^"] = "= %s ^", ["%"] = "= %s %%", [".."] = "= %s .." },
incrementation = { ["+"] = " = %s + 1" , ["-"] = " = %s - 1" },
}
-- Preprocessor
function lune.preprocess(input, args)
-- generate preprocessor
local preprocessor = "return function()\n"
local lines = {}
for line in (input.."\n"):gmatch("(.-)\n") do
table.insert(lines, line)
if line:sub(1,1) == "#" then
-- exclude shebang
if not (line:sub(1,2) == "#!" and #lines ==1) then
preprocessor ..= line:sub(2) .. "\n"
else
preprocessor ..= "output ..= lines[" .. #lines .. "] .. \"\\n\"\n"
end
else
preprocessor ..= "output ..= lines[" .. #lines .. "] .. \"\\n\"\n"
end
end
preprocessor ..= "return output\nend"
-- make preprocessor environement
local env = table.copy(_G)
env.lune = lune
env.output = ""
env.include = function(file)
local f = io.open(file)
if not f then error("can't open the file to include") end
local filename = file:match("([^%/%\\]-)%.[^%.]-$")
env.output ..=
"-- INCLUSION OF FILE \""..file.."\" --\n"..
"local function _()\n"..
f:read("*a").."\n"..
"end\n"..
"local "..filename.." = _() or "..filename.."\n"..
"-- END OF INCLUDSION OF FILE \""..file.."\" --\n"
f:close()
end
env.rawInclude = function(file)
local f = io.open(file)
if not f then error("can't open the file to raw include") end
env.output ..= f:read("*a").."\n"
f:close()
end
env.print = function(...)
env.output ..= table.concat({...}, "\t") .. "\n"
end
env.args = args or {}
env.lines = lines
-- load preprocessor
local preprocess, err = load(lune.compile(preprocessor), "Preprocessor", nil, env)
if not preprocess then error("Error while creating preprocessor :\n" .. err) end
-- execute preprocessor
local success, output = pcall(preprocess())
if not success then error("Error while preprocessing file :\n" .. output .. "\nWith preprocessor : \n" .. preprocessor) end
return output
end
-- Compiler
function lune.compile(input)
local output = ""
local last = {}
for t,v in lexer.lua(input, {}, {}) do
local toInsert = v
-- affectation
if t == "=" then
if table.hasKey(lune.syntax.affectation, last.token) then
toInsert = string.format(lune.syntax.affectation[last.token], last.varName)
output = output:sub(1, -1 -#last.token) -- remove token before =
end
end
-- self-incrementation
if table.hasKey(lune.syntax.incrementation, t) and t == last.token then
toInsert = string.format(lune.syntax.incrementation[last.token], last.varName)
output = output:sub(1, -#last.token*2) -- remove token ++/--
end
-- reconstitude full variable name (ex : ith.game.camera)
if t == "iden" then
if last.token == "." then
last.varName ..= "." .. v
else
last.varName = v
end
end
last[t] = v
last.token = t
last.value = v
output ..= toInsert
end
return output
end
-- Preprocess & compile
function lune.make(code, args)
local preprocessed = lune.preprocess(code, args or {})
local output = lune.compile(preprocessed)
return output
end
-- Standalone mode
if debug.getinfo(3) == nil and arg then
-- Check args
if #arg < 1 then
print("Lune version "..lune.VERSION.." by Thomas99")
print("Command-line usage :")
print("lua lune.lua <filename> [preprocessor arguments]")
return lune
end
-- Parse args
local inputFilePath = arg[1]
local args = {}
-- Parse compilation args
for i=2, #arg, 1 do
if arg[i]:sub(1,2) == "--" then
args[arg[i]:sub(3)] = arg[i+1]
i = i +1 -- skip argument value
end
end
-- Open & read input file
local inputFile, err = io.open(inputFilePath, "r")
if not inputFile then error("Error while opening input file : "..err) end
local input = inputFile:read("*a")
inputFile:close()
-- End
print(lune.make(input, args))
end
return lune