diff --git a/.vscode/settings.json b/.vscode/settings.json index e0a991d..f071b81 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ "ansicolors", "awesomewm", "buildx", + "concat", "dryrun", "getcontent", "gitea", @@ -33,6 +34,7 @@ "modname", "reportfile", "rockspec", + "rstrip", "runreport", "setopt", "statsfile", diff --git a/spec/printer/teal_type_definition_spec.tl b/spec/printer/teal_type_definition_spec.tl index 9c37e19..1174c1e 100644 --- a/spec/printer/teal_type_definition_spec.tl +++ b/spec/printer/teal_type_definition_spec.tl @@ -7,7 +7,7 @@ local printer = teal_type_definition_printer.printer -- We need to remove the last newline inserted by Penlight's dedent local function dedent(str: string): string - return (stringx.dedent(str):sub(1, -3):gsub("\n *", "\n")) -- we remove indentation for now, the printer should be fixed soon + return (stringx.dedent(str):sub(1, -2)) end local function gen(ast: Node, expected_code: string): function() diff --git a/src/awesomewm.d.tl/printer/teal_type_definition.tl b/src/awesomewm.d.tl/printer/teal_type_definition.tl index f43981b..4f089e4 100644 --- a/src/awesomewm.d.tl/printer/teal_type_definition.tl +++ b/src/awesomewm.d.tl/printer/teal_type_definition.tl @@ -9,97 +9,149 @@ local function render_types(types: { string }): string if not types or #types == 0 then return "" end + return ": " .. table.concat(types, " | ") +end - return ": " .. stringx.join(" | ", types) +local function dedent(str: string): string + return stringx.dedent(str):sub(1, -2) +end + +local function render_code(code: string, indent_level: integer): string + if not code or code == "" then + return "" + end + + local generated = "" + for line in stringx.lines(dedent(code)) do + generated = generated .. stringx.rstrip(string.rep(" ", 3 * indent_level) .. line) .. "\n" + end + return generated end local record Node_Printer_Function - on_node: function(node: Node): string - before_node: nil | function(node: Node): string - after_node: nil | function(node: Node): string + on_node: function(node: Node, indent_level: integer): string, integer + before_node: nil | function(node: Node, indent_level: integer): string, integer + after_node: nil | function(node: Node, indent_level: integer): string, integer end -- pre-declare functions to prevent forward reference errors -local print_teal: function(node: Node): string +local print_teal: function(node: Node, indent_level: integer | nil): string local print_children: function(node: Node): string local node_printer : { Node.Token : Node_Printer_Function } = { ["module"] = { - before_node = function(node: Node): string - return "-- This file was auto-generated.\n\nlocal record " .. node.name .. "\n" + before_node = function(node: Node, indent_level: integer): string, integer + return render_code( + string.format( + [[ + -- This file was auto-generated. + + local record %s + ]], + node.name), + indent_level), indent_level + 1 end, - on_node = function(node: Node): string - return print_children(node) + on_node = function(node: Node, indent_level: integer): string, integer + return render_code(print_children(node), indent_level), indent_level end, - after_node = function(node: Node): string - return "end\n\nreturn " .. node.name + after_node = function(node: Node, indent_level: integer): string, integer + return render_code("end", indent_level - 1) .. + "\n" .. + render_code( + string.format("return %s", node.name), + indent_level - 1 + ), indent_level - 1 end, }, ["record"] = { - before_node = function(node: Node): string - return "record " .. node.name .. "\n" + before_node = function(node: Node, indent_level: integer): string, integer + return render_code( + string.format( + "record %s", + node.name), + indent_level), indent_level + 1 end, - on_node = function(node: Node): string - return print_children(node) + on_node = function(node: Node, indent_level: integer): string, integer + return render_code(print_children(node), indent_level), indent_level end, - after_node = function(): string - return "end" + after_node = function(_: Node, indent_level: integer): string, integer + return render_code("end", indent_level - 1), indent_level - 1 end, }, ["enum"] = { - before_node = function(node: Node): string - return "enum " .. node.name .. "\n" + before_node = function(node: Node, indent_level: integer): string, integer + return render_code( + string.format( + "enum %s", + node.name), + indent_level), indent_level + 1 end, - on_node = function(node: Node): string - return print_children(node) + on_node = function(node: Node, indent_level: integer): string, integer + return render_code(print_children(node), indent_level), indent_level end, - after_node = function(): string - return "end" + after_node = function(_: Node, indent_level: integer): string, integer + return render_code("end", indent_level - 1), indent_level - 1 end, }, ["identifier"] = { - on_node = function(node: Node): string - return "\"" .. node.name .. "\"" + on_node = function(node: Node, indent_level: integer): string, integer + return render_code(string.format('"%s"', node.name), indent_level), indent_level end, }, ["variable"] = { - on_node = function(node: Node): string - return node.name .. render_types(node.types) + on_node = function(node: Node, indent_level: integer): string, integer + return render_code( + string.format( + "%s%s", + node.name, + render_types(node.types)), + indent_level), indent_level end, }, ["function"] = { - on_node = function(node: Node): string + on_node = function(node: Node, indent_level: integer): string, integer local args = {} for _, parameter in ipairs(node.parameters) do - table.insert(args, print_teal(parameter)) + table.insert(args, print_teal(parameter):sub(1, -2)) -- need to remove the newline ending end - return node.name .. ": function(" .. table.concat(args, ", ") .. ")" .. render_types(node.return_types) + return render_code( + string.format( + "%s: function(%s)%s", + node.name, + table.concat(args, ", "), + render_types(node.return_types)), + indent_level), indent_level end, }, ["metamethod"] = { - on_node = function(): string + on_node = function(): string, integer log:warn("Metamethods are not supported yet") end, } } -function print_teal(node: Node): string +function print_teal(node: Node, indent_level: integer | nil): string + indent_level = indent_level or 0 local printer = node_printer[node.token] local generated = "" + local full_generated = "" if printer.before_node then - generated = (printer.before_node as function(node: Node): string)(node) + generated, indent_level = (printer.before_node as function(Node, integer): string, integer)(node, indent_level) + full_generated = generated end - generated = generated .. printer.on_node(node) + generated, indent_level = printer.on_node(node, indent_level) + full_generated = full_generated .. generated if printer.after_node then - generated = generated .. (printer.after_node as function(node: Node): string)(node) + generated, indent_level = (printer.after_node as function(Node, integer): string, integer)(node, indent_level) + full_generated = full_generated .. generated end - return generated + return full_generated end function print_children(node: Node): string local generated = "" for _, child in ast.iter_children(node) do - generated = generated .. print_teal(child) .. "\n" + generated = generated .. print_teal(child) end return generated end