diff --git a/src/awesomewm.d.tl/entity/Function_Info.tl b/src/awesomewm.d.tl/entity/Function_Info.tl index 6b8c821..d8605ad 100644 --- a/src/awesomewm.d.tl/entity/Function_Info.tl +++ b/src/awesomewm.d.tl/entity/Function_Info.tl @@ -1,42 +1,56 @@ local List = require "pl.List" local Type_Info = require "entity.Type_Info" +local Variable_Info = require "entity.Variable_Info" local record Function_Info - metamethod __call: function(Function_Info): Function_Info + metamethod __call: function( + Function_Info, + name: string, + parameters: List, + return_types: List + ): Function_Info Function_Info: Function_Info - record Parameter - name: string - types: List - end name: string - parameters: List - return_types: List + parameters: List + return_types: List append_parameter: function(self: Function_Info, name: string, type: string) append_return_type: function(self: Function_Info, return_type: string) + + fixup: function(Function_Info) end local __Function_Info: metatable = { - __call = function(_self: Function_Info): Function_Info - return { - name = "", - parameters = List(), - return_types = List(), - } + __call = function( + _self: Function_Info, + name: string, + parameters: List, + return_types: List): Function_Info + return { + name = name or "", + parameters = parameters or (List() as List), + return_types = return_types or (List() as List), + + fixup = function(self: Function_Info) + for p in self.parameters:iter() do + p:fixup() + end + for r in self.return_types:iter() do + r:fixup() + end + end, + } end, } function Function_Info:append_parameter(name: string, types: List) - self.parameters:append { - name = name, - types = types, - } + self.parameters:append(Variable_Info(name, types)) end function Function_Info:append_return_type(return_type: string) - self.return_types:append(return_type) + self.return_types:append(Type_Info(return_type)) end return setmetatable({} as Function_Info, __Function_Info) diff --git a/src/awesomewm.d.tl/entity/Module_Doc.tl b/src/awesomewm.d.tl/entity/Module_Doc.tl index 2d4495f..612df1b 100644 --- a/src/awesomewm.d.tl/entity/Module_Doc.tl +++ b/src/awesomewm.d.tl/entity/Module_Doc.tl @@ -1,7 +1,14 @@ local Function_Info = require "entity.Function_Info" local List = require "pl.List" +local Map = require "pl.Map" local Variable_Info = require "entity.Variable_Info" +local module_to_require : Map = Map({ + Shape = "gears.shape", + Surface = "gears.surface", + Widget = "wibox.widget", +}) + local record Module_Doc metamethod __call: function(Module_Doc): Module_Doc @@ -15,6 +22,11 @@ local record Module_Doc properties: List static_functions: List signals: List + + requires: Map + + fixup: function(Module_Doc) + populate_requires: function(Module_Doc) end local __Module_Doc: metatable = { @@ -25,6 +37,78 @@ local __Module_Doc: metatable = { properties = List(), static_functions = List(), signals = List(), + requires = Map(), + + fixup = function(self: Module_Doc) + for c in self.constructors:iter() do + c:fixup() + if #c.return_types == 1 then + c.return_types[1].name = self.record_name + end + end + for m in self.methods:iter() do + m:fixup() + end + for p in self.properties:iter() do + p:fixup() + end + for s in self.static_functions:iter() do + s:fixup() + end + end, + populate_requires = function(self: Module_Doc) + -- TODO : Move this to other Entities. Can be a little tricky because we populate a map + for c in self.constructors:iter() do + for p in c.parameters:iter() do + for t in p.types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + end + for m in self.methods:iter() do + for p in m.parameters:iter() do + for t in p.types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + for t in m.return_types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + for p in self.properties:iter() do + for t in p.types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + for s in self.static_functions:iter() do + for p in s.parameters:iter() do + for t in p.types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + for t in s.return_types:iter() do + local mod = module_to_require:get(t.name) + if mod then + self.requires:set(t.name, mod) + end + end + end + end } end, } diff --git a/src/awesomewm.d.tl/entity/Type_Info.tl b/src/awesomewm.d.tl/entity/Type_Info.tl index 1aa2b1e..819a0a6 100644 --- a/src/awesomewm.d.tl/entity/Type_Info.tl +++ b/src/awesomewm.d.tl/entity/Type_Info.tl @@ -1,6 +1,21 @@ local List = require "pl.List" local Map = require "pl.Map" +local type_fix : Map = Map({ + bool = "boolean", + client = "Client", + ["gears.shape"] = "Shape", + ["gears.surface"] = "Surface", + image = "Image", + int = "integer", + screen = "Screen", + shape = "Shape", + surface = "Surface", + tag = "Tag", + ["wibox.widget"] = "Widget", + widget = "Widget", +}) + local record Type_Info metamethod __call: function(Type_Info, record_name: string): Type_Info @@ -11,19 +26,26 @@ local record Type_Info -- Map : name -> type -- We can't use Variable_Info here because it's a circular dependency. record_entries: Map> | nil + + fixup: function(self: Type_Info) end local __Type_Info: metatable = { __call = function(_self: Type_Info, record_name: string): Type_Info - if record_name ~= nil then - return { - name = record_name, - record_entries = Map() - } - end return { - name = "", - record_entries = nil, + name = record_name and record_name or "", + record_entries = record_name and Map() or nil, + + fixup = function(self: Type_Info) + self.name = type_fix:get(self.name) or self.name + if self.record_entries then + for _, types in (self.record_entries as Map>):iter() do + for t in types:iter() do + t:fixup() + end + end + end + end } end, } diff --git a/src/awesomewm.d.tl/entity/Variable_Info.tl b/src/awesomewm.d.tl/entity/Variable_Info.tl index 0469f2d..03f169e 100644 --- a/src/awesomewm.d.tl/entity/Variable_Info.tl +++ b/src/awesomewm.d.tl/entity/Variable_Info.tl @@ -10,6 +10,8 @@ local record Variable_Info types: List constraints: List + + fixup: function(self: Variable_Info) end local __Variable_Info: metatable = { @@ -19,6 +21,12 @@ local __Variable_Info: metatable = { return { name = name, types = types, + + fixup = function(self: Variable_Info) + for t in self.types:iter() do + t:fixup() + end + end, } end, } diff --git a/src/awesomewm.d.tl/generator/snippets.tl b/src/awesomewm.d.tl/generator/snippets.tl index 7eb86df..7d3209b 100644 --- a/src/awesomewm.d.tl/generator/snippets.tl +++ b/src/awesomewm.d.tl/generator/snippets.tl @@ -9,13 +9,14 @@ local Variable_Info = require "entity.Variable_Info" local record Module indent: function(str: string, level: number): string + render_requires: function(requires: Map): string render_typed_variable: function(name: string, types: List): string render_anonymous_function_signature: function(item: Function_Info.Function_Info): string render_record_functions: function(items: List): string render_enum: function(name: string, values: List): string render_record_properties: function(items: List): string render_record: function(name: string, items: List): string - render_records_from_Parameters: function(items: List): string + render_records_from_Parameters: function(items: List): string end @@ -26,6 +27,22 @@ function snippets.indent(str: string, level: number): string return stringx.rstrip(stringx.indent(str, level, string.rep(" ", 3))) end +function snippets.render_requires(requires: Map): string + local tmpl = [[local $(name) = require "$(path)"]] + + local require_statements = List() + for name, path in requires:iter() do + local tmpl_args = { + name = name, + path = path, + } + + require_statements:append(utils.do_or_fail(template.substitute, tmpl, tmpl_args)) + end + + return require_statements:concat("\n") +end + function snippets.render_typed_variable(name: string, types: List): string local tmpl = [[$(name): $(types)]] @@ -44,17 +61,21 @@ function snippets.render_anonymous_function_signature(item: Function_Info.Functi local tmpl_args = { function_name = item.name, - function_parameter = item.parameters:map(function(param: Function_Info.Parameter): string + function_parameter = item.parameters:map(function(param: Variable_Info.Variable_Info): string return snippets.render_typed_variable(param.name, param.types) end):concat(", "), - function_return = item.return_types:concat(", "), + function_return = item.return_types:map( + function(return_type: Type_Info.Type_Info): string + return return_type.name + end + ):concat(", "), } return utils.do_or_fail(template.substitute, tmpl, tmpl_args) end -function snippets.render_records_from_Parameters(items: List): string - return items:map(function(param: Function_Info.Parameter): string +function snippets.render_records_from_Parameters(items: List): string + return items:map(function(param: Variable_Info.Variable_Info): string if #param.types == 0 then return "" end diff --git a/src/awesomewm.d.tl/generator/teal_type_definitions.tl b/src/awesomewm.d.tl/generator/teal_type_definitions.tl index 1697d0b..0a1d31a 100644 --- a/src/awesomewm.d.tl/generator/teal_type_definitions.tl +++ b/src/awesomewm.d.tl/generator/teal_type_definitions.tl @@ -8,6 +8,10 @@ local snippets = require "generator.snippets" local tmpl = [[ -- Auto generated file (Do not manually edit this file!) +# if module.requires:len() ~= 0 then +$(snippets.render_requires(module.requires)) +# end -- /requires + local record $(module.record_name) # if #module.signals ~= 0 then $(snippets.indent(snippets.render_enum("Signal", module.signals))) diff --git a/src/awesomewm.d.tl/init.tl b/src/awesomewm.d.tl/init.tl index 743a5ec..e5156ae 100644 --- a/src/awesomewm.d.tl/init.tl +++ b/src/awesomewm.d.tl/init.tl @@ -27,6 +27,8 @@ log:info("Finished Module List scrapping, found " .. #module_infos .. " modules" local function do_one_file(url: string, module_name: string, output: string) local html = crawler.fetch(url) local module_doc = scraper.module_doc.get_doc_from_page(html, module_name) + module_doc:fixup() + module_doc:populate_requires() filesystem.file_writer.write( generator.teal_type_definitions.generate_teal(module_doc), output diff --git a/src/awesomewm.d.tl/scraper/module_doc.tl b/src/awesomewm.d.tl/scraper/module_doc.tl index 81e58dd..a92740b 100644 --- a/src/awesomewm.d.tl/scraper/module_doc.tl +++ b/src/awesomewm.d.tl/scraper/module_doc.tl @@ -18,13 +18,13 @@ end local function parse_parameter_types(parameter_type: string): List if parameter_type == "" then - local type_info: Type_Info.Type_Info = { name = "any" } + local type_info: Type_Info.Type_Info = Type_Info("any") return List({ type_info }) end return stringx.split(parameter_type, " or "):map( function(type_name: string): Type_Info.Type_Info - return { name = utils.sanitize_string(type_name) } + return Type_Info(utils.sanitize_string(type_name)) end ) end @@ -33,7 +33,7 @@ local function extract_item_name(item_name_node: scan.HTMLNode): string return item_name_node and ((item_name_node.attr.name as string):gsub("^.*[%.:]", "")) end -local function extract_function_parameter_Parameters(tr_node: scan.HTMLNode): { Function_Info.Parameter } +local function extract_function_parameter_Parameters(tr_node: scan.HTMLNode): { Variable_Info.Variable_Info } local query_selectors = { name = "span.parameter", types = "span.types" @@ -42,21 +42,21 @@ local function extract_function_parameter_Parameters(tr_node: scan.HTMLNode): { return scraper_utils.scrape_tuples( tr_node:outer_html(), { query_selectors.name, query_selectors.types }, - function(nodes: { string : scan.HTMLNode | nil }): Function_Info.Parameter - return { - name = extract_node_text(nodes[query_selectors.name] as scan.HTMLNode), - types = parse_parameter_types(extract_node_text(nodes[query_selectors.types] as scan.HTMLNode)), - } + function(nodes: { string : scan.HTMLNode | nil }): Variable_Info.Variable_Info + return Variable_Info( + extract_node_text(nodes[query_selectors.name] as scan.HTMLNode), + parse_parameter_types(extract_node_text(nodes[query_selectors.types] as scan.HTMLNode)) + ) end) end -local function extract_function_parameters(function_parameters_node: scan.HTMLNode): { Function_Info.Parameter } +local function extract_function_parameters(function_parameters_node: scan.HTMLNode): { Variable_Info.Variable_Info } local current_record_parameter: Type_Info.Type_Info | nil = nil return scraper_utils.scrape( function_parameters_node:outer_html(), "tr", - function(line_node: scan.HTMLNode): Function_Info.Parameter + function(line_node: scan.HTMLNode): Variable_Info.Variable_Info local parameters = extract_function_parameter_Parameters(line_node) if #parameters == 0 then return nil @@ -81,20 +81,17 @@ local function extract_function_parameters(function_parameters_node: scan.HTMLNo if #types == 1 and types[1].name == "table" then local record_name = utils.capitalize(name) current_record_parameter = Type_Info(record_name) - return { - name = name, - types = List({ current_record_parameter }), - } + return Variable_Info( + name, + List({ current_record_parameter }) + ) end - return { - name = name, - types = types, - } + return Variable_Info(name, types) end) end -local function extract_function_return_types(function_return_types_node: scan.HTMLNode): { string } +local function extract_function_return_types(function_return_types_node: scan.HTMLNode): List if not function_return_types_node then return {} end @@ -102,7 +99,10 @@ local function extract_function_return_types(function_return_types_node: scan.HT local selector = "span.types .type" local html = function_return_types_node:outer_html() - return scraper_utils.scrape(html, selector, extract_node_text) + return List(scraper_utils.scrape(html, selector, extract_node_text)):map( + function(type_name: string): Type_Info.Type_Info + return Type_Info(type_name) + end) end local function extract_property_constraints(property_constraint_node: scan.HTMLNode): { string } @@ -141,19 +141,19 @@ local function extract_section_functions(dl: string): { Function_Info.Function_I body:outer_html(), { query_selectors.parameters, query_selectors.return_types } ) - return { - name = scraper_utils.scrape( + return Function_Info( + scraper_utils.scrape( header:outer_html(), query_selectors.name, extract_item_name )[1], - parameters = #body_elements:get(query_selectors.parameters) ~= 0 and + #body_elements:get(query_selectors.parameters) ~= 0 and List(extract_function_parameters(body_elements:get(query_selectors.parameters)[1])) or - (List() as List), - return_types = #body_elements:get(query_selectors.return_types) ~= 0 and - List(extract_function_return_types(body_elements:get(query_selectors.return_types)[1])) or - (List() as List), - } + (List() as List), + #body_elements:get(query_selectors.return_types) ~= 0 and + extract_function_return_types(body_elements:get(query_selectors.return_types)[1]) or + (List() as List) + ) end ) end @@ -209,11 +209,8 @@ function module.get_doc_from_page(html: string, module_name: string): Module_Doc local module_doc = Module_Doc() module_doc.record_name = utils.capitalize((module_name:gsub(".*%.", ""))) - local self_type: Type_Info.Type_Info = { name = module_doc.record_name } - local self_parameter: Function_Info.Parameter = { - name = "self", - types = List({ self_type }), - } + local self_type = Type_Info(module_doc.record_name) + local self_parameter = Variable_Info("self", List({ self_type })) for i = 1, #nodes:get("h2.section-header") do local h2 = nodes:get("h2.section-header")[i]