#!/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 [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