feat(printer): indent generated code

This commit is contained in:
Aire-One 2023-05-13 14:33:10 +02:00
parent c2e0da3ba6
commit 8928e67f24
3 changed files with 92 additions and 38 deletions

View File

@ -11,6 +11,7 @@
"ansicolors",
"awesomewm",
"buildx",
"concat",
"dryrun",
"getcontent",
"gitea",
@ -33,6 +34,7 @@
"modname",
"reportfile",
"rockspec",
"rstrip",
"runreport",
"setopt",
"statsfile",

View File

@ -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()

View File

@ -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 <total>: { 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