From 5d9e2b87d68c2db57f7851e0e321ded41deceffe Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 24 Jan 2023 22:42:09 +0100 Subject: examples/railroad: init grammar diagram --- examples/railroad.lua | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 examples/railroad.lua diff --git a/examples/railroad.lua b/examples/railroad.lua new file mode 100644 index 0000000..8e74441 --- /dev/null +++ b/examples/railroad.lua @@ -0,0 +1,347 @@ +package.cpath = package.cpath .. ";../target/debug/?.so" +package.path = package.path .. ";../lua-bindings/?.lua" + +local dia = require("diaphragm") + +dia.util.eprint("----------") + +local nord_colors = { + base00 = "#2E3440", + base01 = "#3B4252", + base02 = "#434C5E", + base03 = "#4C566A", + base04 = "#D8DEE9", + base05 = "#E5E9F0", + base06 = "#ECEFF4", + base07 = "#8FBCBB", + base08 = "#BF616A", + base09 = "#D08770", + base0A = "#EBCB8B", + base0B = "#A3BE8C", + base0C = "#88C0D0", + base0D = "#81A1C1", + base0E = "#B48EAD", + base0F = "#5E81AC", +} + +local function begin(params) + local result = dia.shape(params) + + result.icon = dia.rectangle.surrounding(result, { + height = 10, + width = 10, + fill_color = nord_colors.base00, + }) + result.beginning = result.middle_left + result.ending = result.middle_right + + function result:draw() + self.icon:draw() + end + + return result +end + +local function stop(params) + return begin(params) +end + +function token(params) + local result = dia.shape(params) + + result.name = params.name or "token" + result.font = params.font or dia.text.font({ family = "Fira Code", size = 14 * 1024 }) + result.text = params.text or dia.text.new({ + content = result.name, + font = result.font, + }) + + result.fill_color = params.fill_color or nord_colors.base04 + result.padding = params.padding or 5 + result.box = dia.rectangle.surrounding(result.text, { + fill_color = result.fill_color, + -- TODO: make that a parameter + margin_left = 5, + margin_right = 5, + margin_top = 2, + margin_bottom = 2, + }) + dia.constraint.inset(result.box, result) + + result.beginning = result.box.middle_left + result.ending = result.box.middle_right + + function result:draw() + self.box:draw() + self.text:draw() + end + + return result +end + +function optional(params) + local result = dia.shape(params) + + result.line_spacing = params.line_spacing or 10 + + result.beginning = result.element.beginning - { x = result.line_spacing } + result.ending = result.element.ending + { x = result.line_spacing } + result.top_left = result.element.top_left - { + x = result.line_spacing, + y = result.line_spacing, + } + result.top_right = result.element.top_right + { + x = result.line_spacing, + y = -result.line_spacing, + } + + result.overline = dia.straight_path.new({ + points = { + result.beginning, + result.top_left, + result.top_right, + result.ending, + }, + }) + result.left_line = dia.straight_path.new({ + points = { result.beginning, result.element.beginning }, + }) + result.right_line = dia.straight_path.new({ + points = { result.element.ending, result.ending }, + }) + + result.bottom = result.element.bottom + + function result:draw() + result.overline:draw() + result.left_line:draw() + result.right_line:draw() + result.element:draw() + end + + return result +end + +function choice(params) + local result = dia.shape(params) + + result.line_spacing = params.line_spacing or 10 + result.padding = params.padding or 10 + + result.stack = dia.layout.vstack({ + elements = result.choices, + align = "left", + top = result.top, + bottom = result.bottom, + spacing = result.padding, + }) + + result.beginning = result.choices[1].beginning - { x = result.line_spacing } + result.ending = { + x = result.stack.right + result.line_spacing, + y = result.choices[1].ending.y, + } + + result.left_hook = dia.straight_path.new({ + points = { + result.choices[1].beginning, + result.beginning, + result.choices[#result.choices].beginning - { x = result.line_spacing }, + result.choices[#result.choices].beginning, + }, + }) + result.right_hook = dia.straight_path.new({ + points = { + result.choices[1].ending, + result.ending, + { + x = result.ending.x, + y = result.choices[#result.choices].ending.y, + }, + result.choices[#result.choices].ending, + }, + }) + + result.left_connections = {} + result.right_connections = {} + for i = 2, #result.choices - 1 do + table.insert( + result.left_connections, + dia.straight_path.new({ + points = { + result.choices[i].beginning - { x = result.line_spacing }, + result.choices[i].beginning, + }, + }) + ) + table.insert( + result.right_connections, + dia.straight_path.new({ + points = { + result.choices[i].ending, + { x = result.ending.x, y = result.choices[i].ending.y }, + }, + }) + ) + end + + dia.constraint.inset(result.stack, result, { + margin_left = result.line_spacing, + margin_right = result.line_spacing, + }) + + function result:draw() + result.left_hook:draw() + result.right_hook:draw() + for _, left_conn in ipairs(self.left_connections) do + left_conn:draw() + end + for _, right_conn in ipairs(self.right_connections) do + right_conn:draw() + end + + self.stack:draw() + end + + return result +end + +function ident(params) + return token(dia.util.tbl_extend({ + fill_color = nord_colors.base0A, + }, params)) +end + +function typ(params) + return token(dia.util.tbl_extend({ + fill_color = nord_colors.base08, + }, params)) +end + +function tt(params) + return token(dia.util.tbl_extend({ + fill_color = nord_colors.base0C, + }, params)) +end + +function connect(params) + local result = dia.shape(params) + + result.elements = params.elements or {} + result.spacing = params.spacing or 10 + + result.beginning = result.elements[1].beginning + result.ending = result.elements[#result.elements].ending + + result.stack = dia.layout.hstack({ + elements = result.elements, + align = "none", + spacing = result.spacing, + }) + dia.constraint.inset(result.stack, result) + + result.lines = {} + + for i = 1, #result.elements - 1 do + local left_el = result.elements[i] + local right_el = result.elements[i + 1] + + table.insert( + result.lines, + dia.straight_path.new({ + points = { left_el.ending, right_el.beginning }, + }) + ) + + dia.constrain(left_el.ending.y:eq(right_el.beginning.y)) + end + + function result:draw() + self.stack:draw() + for _, line in ipairs(self.lines) do + line:draw() + end + end + + return result +end + +dia.draw({ + draw = function(self) + local figure = connect({ + elements = { + begin(), + optional({ element = token({ name = "pub" }) }), + ident({ name = "name" }), + token({ name = "<" }), + typ({ name = "a" }), + choice({ + choices = { + connect({ + elements = { + token({ name = "," }), + choice({ + choices = { + connect({ + elements = { + typ({ name = "i" }), + token({ name = "," }), + typ({ name = "o" }), + optional({ + element = connect({ + elements = { + token({ name = "," }), + typ({ name = "e" }), + }, + }), + }), + }, + }), + typ({ name = "o" }), + }, + }), + token({ name = ">" }), + }, + }), + connect({ + elements = { + token({ name = ">" }), + optional({ + element = connect({ + elements = { + token({ name = "(" }), + typ({ name = "i" }), + token({ name = ")" }), + token({ name = "->" }), + typ({ name = "o" }), + }, + }), + }), + }, + }), + }, + }), + token({ name = "," }), + optional({ element = token({ name = "mut" }) }), + ident({ name = "self_" }), + token({ name = "," }), + ident({ name = "submac" }), + token({ name = "!" }), + token({ name = "(" }), + optional({ element = tt({ name = "args" }) }), + token({ name = ")" }), + stop(), + }, + center = self.center, + }) + dia.rectangle + .surrounding(self, { + fill_color = nord_colors.base06, + stroke_width = 0, + }) + :draw() + figure:draw() + dia.constraint.inset(figure, self, { margin = 20 }) + end, + output = {}, +}) -- cgit v1.2.3