Last active
August 29, 2015 14:18
-
-
Save leafi/9cac45df526be3625e8a to your computer and use it in GitHub Desktop.
to_variants.lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--Assertion: all 'functions =' lines are either: | |
-- functions = { | |
--or: | |
-- functions = { | |
--...EXCEPT those representing module functions, where it's: | |
-- functions = { | |
--or: | |
-- functions = { | |
-- The first 'special' module functions line should only happen once per file. | |
-- If we see a 'types = {' line, we need to exit special mode. (for love_api.lua which has mod funs at top) | |
-- Yep, we're really doing this based on indentation. | |
-- This program operates in three stages: | |
-- #1: Make sure all files match our parser's expectations. | |
-- #2: Perform the rewrite. | |
-- #3: require("love_api") and check everything looks OK lua-side. | |
-- Given this is a bit risky, let's first ensure we're actually correct. | |
local allFiles = {"love_api.lua", "modules/Audio.lua", "modules/Event.lua", | |
"modules/Filesystem.lua", "modules/Graphics.lua", "modules/Image.lua", | |
"modules/Joystick.lua", "modules/Keyboard.lua", "modules/Math.lua", | |
"modules/Mouse.lua", "modules/Physics.lua", "modules/Sound.lua", | |
"modules/System.lua", "modules/Thread.lua", "modules/Timer.lua", | |
"modules/Window.lua"} | |
local fspecial1 = ' functions = {' | |
local cspecial1 = ' callbacks = {' | |
local fspecial2 = ' functions = {' | |
local f1 = ' functions = {' | |
local f2 = ' functions = {' | |
-- | |
-- ASSERT that in all files, any line containing string 'functions' that | |
-- also contains an = sign and NOT containing 'description', is a line that | |
-- matches the rules at the top of the file. | |
-- | |
local failed = false | |
for _, fname in ipairs(allFiles) do | |
local lspecial1 = 0 | |
local lspecial2 = 0 | |
local l1 = 0 | |
local l2 = 0 | |
local bad = 0 | |
local special = false | |
local doneSpecial = false | |
print(fname .. ":") | |
local linenum = 1 | |
for line in io.lines(fname) do | |
if line:find("types = {") then | |
special = false | |
end | |
if (line:find("functions") and line:find("=") and not line:find("description")) or | |
(line:find("callbacks") and line:find("=") and not line:find("description")) then | |
if special then | |
-- Expect fspecial2. | |
if line:find(fspecial2) == 1 then | |
lspecial2 = lspecial2 + 1 | |
doneSpecial = true | |
else | |
bad = bad + 1 | |
print(" ! bad functions line. expected fspecial2. line: " .. tostring(linenum) .. " s: " .. line) | |
end | |
else | |
-- Usual functions lines - but watch out for fspecial1... | |
if line:find(f1) == 1 then | |
l1 = l1 + 1 | |
elseif line:find(f2) == 1 then | |
if l1 > 0 then | |
l2 = l2 + 1 | |
else | |
bad = bad + 1 | |
print(" ! bad (f2 before f1) line: " .. tostring(linenum) .. " s: " .. line) | |
end | |
elseif line:find(fspecial1) == 1 or line:find(cspecial1) == 1 then | |
if (fname ~= "love_api.lua") and doneSpecial then error(" ! line: " .. tostring(linenum) .. ": already seen fspecial1/cspecial1!") end | |
lspecial1 = lspecial1 + 1 | |
special = true | |
else | |
bad = bad + 1 | |
print(" ! bad (just bad) f1/f2 line: " .. tostring(linenum) .. " s: " .. line) | |
end | |
end | |
end | |
linenum = linenum + 1 | |
end | |
if bad > 0 then | |
print(" ! Non-zero number of unrecognized 'functions =' lines.") | |
failed = true | |
end | |
if (lspecial1 ~= 1) or (lspecial2 < 1) then | |
if not (fname == "love_api.lua" and lspecial1 == 2) then | |
print(" ! Failed to find fspecial1 (i.e. module functions definition) in this file.") | |
failed = true | |
end | |
end | |
print(" Found f1: " .. tostring(l1) .. " f2: " .. tostring(l2) .. " fspecial1: " .. tostring(lspecial1) .. " fspecial2: " .. tostring(lspecial2) .. " BAD: " .. tostring(bad)) | |
end | |
if failed then | |
error("Assertion failed. :(") | |
end | |
print("") | |
print("*****") | |
print(" Yeah, format looks good - I *think* we can do this!") | |
print("*****") | |
-- | |
-- Go through all the files again, but this time, rewrite inner 'functions' lines to be 'variants'. | |
-- | |
for _, fname in ipairs(allFiles) do | |
local special = false | |
print("Rewriting " .. fname .. ":") | |
local oldLines = {} | |
for line in io.lines(fname) do | |
table.insert(oldLines, line) | |
end | |
local f = io.open(fname, "w") | |
for _, line in ipairs(oldLines) do | |
if line:find("types = {") then | |
special = false | |
end | |
if (line:find("functions") and line:find("=") and not line:find("description")) or | |
(line:find("callbacks") and line:find("=") and not line:find("description")) then | |
if special then | |
-- Expect fspecial2. | |
if line:find(fspecial2) == 1 then | |
f:write(' variants = {' .. '\n') | |
else | |
error(" ! bad functions line. expected fspecial2.") | |
end | |
else | |
-- Usual functions lines - but watch out for fspecial1... | |
if line:find(f1) == 1 then | |
f:write(line .. '\n') | |
elseif line:find(f2) == 1 then | |
f:write(' variants = {' .. '\n') | |
elseif line:find(fspecial1) == 1 or line:find(cspecial1) == 1 then | |
special = true | |
f:write(line .. '\n') | |
else | |
error(" ! bad (just bad) f1/f2.") | |
end | |
end | |
else | |
f:write(line .. '\n') | |
end | |
end | |
f:close() | |
end | |
print("*** Rewriting done, I think.") | |
-- | |
-- Now we load love_api as Lua and make sure it matches our expectations. | |
-- | |
print("") | |
print("OK - let's load love_api into our namespace, trawl through the modules, and make sure everything makes sense.") | |
local love_api = require("love_api") | |
local mods = {} | |
table.insert(mods, love_api) | |
for _, v in ipairs(love_api.modules) do | |
table.insert(mods, v) | |
end | |
print("found #" .. #mods .. "modules") | |
if #mods ~= #allFiles then | |
error("! On verify, different number of found logical modules vs number of .lua files! (" .. tostring(#mods) .. " vs " .. tostring(#allFiles) .. ")") | |
end | |
for _, mod in ipairs(mods) do | |
print(" Verifying " .. (mod.name or "love_api") .. "...") | |
-- First, check module-level functions. | |
if mod.variants then error((mod.name or "love_api") .. " now has .variants. We failed horribly.") end | |
for _, fun in ipairs(mod.functions or {}) do | |
if fun.functions then | |
error((mod.name or "love_api") .. "'s module-level function '" .. fun.name .. "' contained 'functions' field.") | |
elseif not fun.variants then | |
error((mod.name or "love_api") .. "'s module-level function '" .. fun.name .. "' did not contain a 'variants' field!") | |
end | |
print(" im " .. fun.name) | |
end | |
-- Check module-level callbacks, if any. | |
for _, fun in ipairs(mod.callbacks or {}) do | |
if fun.functions then | |
error((mod.name or "love_api") .. "'s module-level callback '" .. fun.name .. "' contained 'functions' field.") | |
elseif not fun.variants then | |
error((mod.name or "love_api") .. "'s module-level callback '" .. fun.name .. "' did not contain a 'variants' field!") | |
end | |
print(" ic " .. fun.name) | |
end | |
-- Now check type-level functions. | |
for _, t in ipairs(mod.types or {}) do | |
if t.variants then error((mod.name or "love_api") .. "'s type " .. t.name .. " now has .variants. We failed utterly.") end | |
for _, fun in ipairs(t.functions or {}) do | |
if fun.functions then | |
error((mod.name or "love_api") .. "'s type " .. t.name .. " type-level function '" .. fun.name .. "' contained 'functions' field.") | |
elseif not fun.variants then | |
error((mod.name or "love_api") .. "'s type " .. t.name .. " type-level function '" .. fun.name .. "' did not contain a 'variants' field!") | |
end | |
print(" i " .. t.name .. " " .. fun.name) | |
end | |
end | |
end | |
print("") | |
print("*** Looks OK to me!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment