Adapt generator code to new entities design #10 #12
|
@ -10,7 +10,7 @@ end
|
||||||
|
|
||||||
package.path = lua_module_paths("lua_modules/share/lua/" .. version)
|
package.path = lua_module_paths("lua_modules/share/lua/" .. version)
|
||||||
.. lua_module_paths "types"
|
.. lua_module_paths "types"
|
||||||
.. lua_module_paths "build/awesomewm.d.tl"
|
.. lua_module_paths "src/awesomewm.d.tl"
|
||||||
.. package.path
|
.. package.path
|
||||||
|
|
||||||
package.cpath = "lua_modules/lib/lua/" .. version .. "/?.so;" .. package.cpath
|
package.cpath = "lua_modules/lib/lua/" .. version .. "/?.so;" .. package.cpath
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
local List = require "pl.List"
|
local List = require "pl.List"
|
||||||
|
|
||||||
local record Parameter
|
|
||||||
name: string
|
|
||||||
type: string
|
|
||||||
end
|
|
||||||
|
|
||||||
local record Function_Info
|
local record Function_Info
|
||||||
metamethod __call: function(Function_Info): Function_Info
|
metamethod __call: function(Function_Info): Function_Info
|
||||||
|
|
||||||
Function_Info: Function_Info
|
Function_Info: Function_Info
|
||||||
|
record Parameter
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
end
|
||||||
|
|
||||||
name: string
|
name: string
|
||||||
parameters: List<Parameter>
|
parameters: List<Parameter>
|
||||||
|
@ -20,7 +19,11 @@ end
|
||||||
|
|
||||||
local __Function_Info: metatable<Function_Info> = {
|
local __Function_Info: metatable<Function_Info> = {
|
||||||
__call = function(_self: Function_Info): Function_Info
|
__call = function(_self: Function_Info): Function_Info
|
||||||
return {}
|
return {
|
||||||
|
name = "",
|
||||||
|
parameters = List(),
|
||||||
|
return_types = List(),
|
||||||
|
}
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
local file = require "pl.file"
|
||||||
|
local log = require "logger"
|
||||||
|
local path = require "pl.path"
|
||||||
|
|
||||||
|
local function write_file(file_content: string, file_path: string): boolean, nil | string
|
||||||
|
-- Make sure the directory we want to write the file to exists
|
||||||
|
local directory = path.dirname(file_path)
|
||||||
|
if not path.isdir(directory) then
|
||||||
|
path.mkdir(directory)
|
||||||
|
end
|
||||||
|
|
||||||
|
return file.write(file_path, file_content, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
local module = {}
|
||||||
|
|
||||||
|
function module.write(file_content: string, file_path: string)
|
||||||
|
local success, error_message = write_file(file_content, file_path)
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
log:error {
|
||||||
|
"generator.write error",
|
||||||
|
error = error_message,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
log:info { "Successfully wrote file", file = file_path }
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
|
@ -0,0 +1,3 @@
|
||||||
|
return {
|
||||||
|
file_writer = require "filesystem.file_writer",
|
||||||
|
}
|
|
@ -1,84 +1,4 @@
|
||||||
local file = require "pl.file"
|
return {
|
||||||
local template = require "pl.template"
|
teal_type_definitions = require "generator.teal_type_definitions",
|
||||||
local path = require "pl.path"
|
snippets = require "generator.snippets",
|
||||||
local log = require "logger"
|
|
||||||
local utils = require "utils"
|
|
||||||
local snippets = require "generator.snippets"
|
|
||||||
|
|
||||||
local tmpl = (function(mod: string): string
|
|
||||||
local package_path = utils.do_or_fail(path.package_path, mod)
|
|
||||||
local package_dir = path.dirname(package_path)
|
|
||||||
return utils.do_or_fail(file.read, package_dir .. "/template.tl.tmpl", false)
|
|
||||||
end)(...)
|
|
||||||
|
|
||||||
local generator = {}
|
|
||||||
|
|
||||||
local record Generate_Teal_Data_Record
|
|
||||||
section: string
|
|
||||||
items: { snippets.Anonymous_Function_Record }
|
|
||||||
end
|
|
||||||
function generator.generate_teal(data: { Generate_Teal_Data_Record }): string
|
|
||||||
-- TODO : add the required modules to the generated code
|
|
||||||
-- TODO : replace this with a proper way to get the module name (will also probably need the module path)
|
|
||||||
local record Module_Data_Record
|
|
||||||
name: string
|
|
||||||
static_functions: { snippets.Anonymous_Function_Record }
|
|
||||||
constructors: { snippets.Anonymous_Function_Record }
|
|
||||||
methods: { string }
|
|
||||||
properties: { snippets.Anonymous_Function_Record }
|
|
||||||
signals: { snippets.Anonymous_Function_Record }
|
|
||||||
end
|
|
||||||
local module_data: Module_Data_Record = { name = "module_name" }
|
|
||||||
for _, item in ipairs(data) do
|
|
||||||
if item.section == "Static functions" then
|
|
||||||
-- TODO
|
|
||||||
module_data.static_functions = item.items
|
|
||||||
elseif item.section == "Constructors" then
|
|
||||||
-- TODO
|
|
||||||
module_data.constructors = item.items
|
|
||||||
elseif item.section == "Object properties" then
|
|
||||||
-- TODO
|
|
||||||
module_data.properties = item.items
|
|
||||||
elseif item.section == "Object methods" then
|
|
||||||
module_data.methods = {}
|
|
||||||
-- TODO : add the self parameter
|
|
||||||
-- TODO : define overrides to use the signal type in connect/emit functions
|
|
||||||
for _, i in ipairs(item.items) do
|
|
||||||
table.insert(
|
|
||||||
module_data.methods,
|
|
||||||
i.name .. ": " .. snippets.anonymous_function(i)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
elseif item.section == "Signals" then
|
|
||||||
module_data.signals = item.items
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local env = {
|
|
||||||
ipairs = ipairs,
|
|
||||||
module = module_data,
|
|
||||||
}
|
}
|
||||||
return utils.do_or_fail(template.substitute, tmpl, env)
|
|
||||||
end
|
|
||||||
|
|
||||||
function generator.write(file_content:string, file_path: string)
|
|
||||||
-- Make sure the directory we want to write the file to exists
|
|
||||||
local directory = path.dirname(file_path)
|
|
||||||
if not path.isdir(directory) then
|
|
||||||
path.mkdir(directory)
|
|
||||||
end
|
|
||||||
|
|
||||||
local success, error_message = file.write(file_path, file_content, false)
|
|
||||||
|
|
||||||
if not success then
|
|
||||||
log:error {
|
|
||||||
"generator.write error",
|
|
||||||
error = error_message,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
log:info { "Successfully wrote file", file = file_path }
|
|
||||||
end
|
|
||||||
|
|
||||||
return generator
|
|
||||||
|
|
|
@ -1,66 +1,50 @@
|
||||||
|
local Function_Info = require "entities.Function_Info"
|
||||||
|
local List = require "pl.List"
|
||||||
local utils = require "utils"
|
local utils = require "utils"
|
||||||
local template = require "pl.template"
|
local template = require "pl.template"
|
||||||
|
|
||||||
-- Refactor scraper code to use pl.List objects
|
local snippets = {}
|
||||||
local function join<T>(arr: { string }, delim: string): string
|
|
||||||
|
function snippets.indent(str: string, level: number): string
|
||||||
|
level = level or 1
|
||||||
local ret = ""
|
local ret = ""
|
||||||
for i, t in ipairs(arr) do
|
for line in str:gmatch("[^\n]+") do
|
||||||
ret = ret .. t
|
ret = ret .. string.rep(" ", level * 3) .. line .. "\n"
|
||||||
if i < #arr then
|
|
||||||
ret = ret .. delim
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
local record Anonymous_Function_Parameter_Record
|
function snippets.render_typed_variable(name: string, types: List<string>): string
|
||||||
name: string
|
local tmpl =
|
||||||
type: { string }
|
[[$(name): $(types)]]
|
||||||
end
|
|
||||||
|
|
||||||
local record Anonymous_Function_Record
|
local tmpl_args = {
|
||||||
name: string
|
name = name,
|
||||||
parameters: { Anonymous_Function_Parameter_Record }
|
types = types:concat(", "),
|
||||||
returns: { string }
|
|
||||||
end
|
|
||||||
|
|
||||||
local snippets = {
|
|
||||||
Anonymous_Function_Parameter_Record = Anonymous_Function_Parameter_Record,
|
|
||||||
Anonymous_Function_Record = Anonymous_Function_Record,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function snippets.types_list(types: { string }): string
|
return utils.do_or_fail(template.substitute, tmpl, tmpl_args)
|
||||||
return join(types, ", ")
|
|
||||||
end
|
|
||||||
|
|
||||||
function snippets.anonymous_function(item: Anonymous_Function_Record): string
|
|
||||||
local parameters_string = ""
|
|
||||||
if item.parameters then
|
|
||||||
for i, param in ipairs(item.parameters) do
|
|
||||||
parameters_string = parameters_string .. param.name
|
|
||||||
local types = "any"
|
|
||||||
if param.type then
|
|
||||||
types = snippets.types_list(param.type)
|
|
||||||
end
|
|
||||||
parameters_string = parameters_string .. ": " .. types
|
|
||||||
if i < #item.parameters then
|
|
||||||
parameters_string = parameters_string .. ", "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local returns_string = ""
|
|
||||||
if item.returns then
|
|
||||||
returns_string = snippets.types_list(item.returns)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function snippets.render_anonymous_function_signature(item: Function_Info.Function_Info): string
|
||||||
local tmpl =
|
local tmpl =
|
||||||
[[function($(parameters_string))$(#returns_string > 0 and (": " .. returns_string))]]
|
[[$(function_name): function($(function_parameter))$(#function_return > 0 and (": " .. function_return))]]
|
||||||
|
|
||||||
return utils.do_or_fail(template.substitute, tmpl, {
|
local tmpl_args = {
|
||||||
parameters_string = parameters_string,
|
function_name = item.name,
|
||||||
returns_string = returns_string,
|
function_parameter = item.parameters:map(function(param: Function_Info.Parameter): string
|
||||||
})
|
return snippets.render_typed_variable(param.name, List({param.type})) -- TODO : add support for multiple types
|
||||||
|
end):concat(", "),
|
||||||
|
function_return = item.return_types:concat(", "),
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.do_or_fail(template.substitute, tmpl, tmpl_args)
|
||||||
|
end
|
||||||
|
|
||||||
|
function snippets.render_record_functions(items: List<Function_Info.Function_Info>): string
|
||||||
|
return items:map(function(item: Function_Info.Function_Info): string
|
||||||
|
return snippets.render_anonymous_function_signature(item)
|
||||||
|
end):concat("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
return snippets
|
return snippets
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
local Module_Doc = require "entities.Module_Doc"
|
||||||
|
local template = require "pl.template"
|
||||||
|
local utils = require "utils"
|
||||||
|
local snippets = require "generator.snippets"
|
||||||
|
|
||||||
|
-- The long therm goal is to have so many `snippets.render_*` functions that
|
||||||
|
-- we can render the whole file with the smallest template possible.
|
||||||
|
local tmpl = [[
|
||||||
|
-- Auto generated file (Do not manually edit this file!)
|
||||||
|
|
||||||
|
# if module.signals then
|
||||||
|
local enum signals
|
||||||
|
# for _, signal in ipairs(module.signals) do
|
||||||
|
"$(signal.name)"
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
|
# end -- /signals
|
||||||
|
local record $(mod_name)
|
||||||
|
# if #module.methods then
|
||||||
|
-- Object methods
|
||||||
|
$(snippets.indent(snippets.render_record_functions(module.methods)))
|
||||||
|
# end -- /methods
|
||||||
|
end
|
||||||
|
|
||||||
|
return $(mod_name)
|
||||||
|
]]
|
||||||
|
|
||||||
|
local module = {}
|
||||||
|
|
||||||
|
function module.generate_teal(mod: string, data: Module_Doc.Module_Doc): string
|
||||||
|
local tmpl_args = {
|
||||||
|
ipairs = ipairs,
|
||||||
|
mod_name = mod,
|
||||||
|
module = data,
|
||||||
|
snippets = snippets,
|
||||||
|
}
|
||||||
|
return utils.do_or_fail(template.substitute, tmpl, tmpl_args)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
|
@ -1,20 +0,0 @@
|
||||||
-- Auto generated file (Do not manually edit this file!)
|
|
||||||
|
|
||||||
# if module.signals then
|
|
||||||
local enum signals
|
|
||||||
# for _, signal in ipairs(module.signals) do
|
|
||||||
"$(signal.name)"
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
|
|
||||||
# end -- /signals
|
|
||||||
local record $(module.name)
|
|
||||||
# if module.methods then
|
|
||||||
-- Object methods
|
|
||||||
# for _, method in ipairs(module.methods) do
|
|
||||||
$(method)
|
|
||||||
# end
|
|
||||||
# end -- /methods
|
|
||||||
end
|
|
||||||
|
|
||||||
return $(module.name)
|
|
|
@ -1,9 +1,10 @@
|
||||||
local crawler = require "crawler"
|
local crawler = require "crawler"
|
||||||
|
local filesystem = require "filesystem"
|
||||||
local inspect = require "inspect"
|
local inspect = require "inspect"
|
||||||
local log = require "logger"
|
local log = require "logger"
|
||||||
local properties = require "properties"
|
local properties = require "properties"
|
||||||
local scraper = require "scraper"
|
local scraper = require "scraper"
|
||||||
-- local generator = require "generator"
|
local generator = require "generator"
|
||||||
|
|
||||||
log:info(
|
log:info(
|
||||||
inspect { message = "Start extraction", base_url = properties.base_url }
|
inspect { message = "Start extraction", base_url = properties.base_url }
|
||||||
|
@ -28,12 +29,13 @@ log:info(inspect { modules_found = #module_infos })
|
||||||
local html =
|
local html =
|
||||||
crawler.fetch(properties.base_url .. "/widgets/wibox.widget.textbox.html")
|
crawler.fetch(properties.base_url .. "/widgets/wibox.widget.textbox.html")
|
||||||
local module_doc = scraper.module_doc.get_doc_from_page(html)
|
local module_doc = scraper.module_doc.get_doc_from_page(html)
|
||||||
log:info(inspect { module_doc = module_doc })
|
-- log:info(inspect { module_doc = module_doc })
|
||||||
|
|
||||||
-- local items = scraper.get_doc_from_page(page)
|
-- local items = scraper.get_doc_from_page(page)
|
||||||
-- log:info(inspect { items })
|
-- log:info(inspect { items })
|
||||||
|
|
||||||
-- generator.write(
|
local mod = "textbox"
|
||||||
-- generator.generate_teal(items),
|
filesystem.file_writer.write(
|
||||||
-- properties.out_directory .. "/test.tl"
|
generator.teal_type_definitions.generate_teal(mod, module_doc),
|
||||||
-- )
|
properties.out_directory .. "/" .. mod .. ".d.tl"
|
||||||
|
)
|
||||||
|
|
|
@ -58,9 +58,9 @@ end
|
||||||
-- At some point, we should probably write a wrapper to make penlight's function work with pcalls.
|
-- At some point, we should probably write a wrapper to make penlight's function work with pcalls.
|
||||||
function utils.do_or_fail<T>(func: function<T>(...: any): (T | nil, string), ...: any): T
|
function utils.do_or_fail<T>(func: function<T>(...: any): (T | nil, string), ...: any): T
|
||||||
local log = require "logger"
|
local log = require "logger"
|
||||||
local res, err = func(...)
|
local ok, res, err = pcall(func, ...)
|
||||||
|
|
||||||
if not res then
|
if not (ok and res) then
|
||||||
log:error { "do_or_fail failed!", error = err }
|
log:error { "do_or_fail failed!", error = err }
|
||||||
error(err)
|
error(err)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue