Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4ec195b

Browse files
committed
Mermaid visitor
1 parent e8e043c commit 4ec195b

File tree

3 files changed

+90
-5
lines changed

3 files changed

+90
-5
lines changed

lib/syntax_tree.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require "cgi"
34
require "etc"
45
require "fiddle"
56
require "json"
@@ -18,6 +19,7 @@
1819
require_relative "syntax_tree/visitor/field_visitor"
1920
require_relative "syntax_tree/visitor/json_visitor"
2021
require_relative "syntax_tree/visitor/match_visitor"
22+
require_relative "syntax_tree/visitor/mermaid_visitor"
2123
require_relative "syntax_tree/visitor/mutation_visitor"
2224
require_relative "syntax_tree/visitor/pretty_print_visitor"
2325
require_relative "syntax_tree/visitor/environment"

lib/syntax_tree/node.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,19 @@ def format(q)
127127
end
128128

129129
def pretty_print(q)
130-
visitor = Visitor::PrettyPrintVisitor.new(q)
131-
visitor.visit(self)
130+
accept(Visitor::PrettyPrintVisitor.new(q))
132131
end
133132

134133
def to_json(*opts)
135-
visitor = Visitor::JSONVisitor.new
136-
visitor.visit(self).to_json(*opts)
134+
accept(Visitor::JSONVisitor.new).to_json(*opts)
137135
end
138136

139137
def construct_keys
140-
PrettierPrint.format(+"") { |q| Visitor::MatchVisitor.new(q).visit(self) }
138+
PrettierPrint.format(+"") { |q| accept(Visitor::MatchVisitor.new(q)) }
139+
end
140+
141+
def mermaid
142+
accept(Visitor::MermaidVisitor.new)
141143
end
142144
end
143145

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# frozen_string_literal: true
2+
3+
module SyntaxTree
4+
class Visitor
5+
# This visitor transforms the AST into a mermaid flow chart.
6+
class MermaidVisitor < FieldVisitor
7+
attr_reader :output, :target
8+
9+
def initialize
10+
@output = StringIO.new
11+
@output.puts("flowchart TD")
12+
13+
@target = nil
14+
end
15+
16+
def visit_program(node)
17+
super
18+
output.string
19+
end
20+
21+
private
22+
23+
def comments(node)
24+
# Ignore
25+
end
26+
27+
def field(name, value)
28+
case value
29+
when Node
30+
node_id = visit(value)
31+
output.puts(" #{target} -- \"#{name}\" --> #{node_id}")
32+
when String
33+
node_id = "#{target}_#{name}"
34+
output.puts(" #{node_id}([#{CGI.escapeHTML(value.inspect)}])")
35+
output.puts(" #{target} -- \"#{name}\" --> #{node_id}")
36+
when nil
37+
# skip
38+
else
39+
node_id = "#{target}_#{name}"
40+
output.puts(" #{node_id}([\"#{CGI.escapeHTML(value.inspect)}\"])")
41+
output.puts(" #{target} -- \"#{name}\" --> #{node_id}")
42+
end
43+
end
44+
45+
def list(name, values)
46+
values.each_with_index do |value, index|
47+
field("#{name}[#{index}]", value)
48+
end
49+
end
50+
51+
def node(node, type)
52+
previous_target = target
53+
54+
begin
55+
@target = "node_#{node.object_id}"
56+
57+
yield
58+
59+
output.puts(" #{@target}[\"#{type}\"]")
60+
@target
61+
ensure
62+
@target = previous_target
63+
end
64+
end
65+
66+
def pairs(name, values)
67+
values.each_with_index do |(key, value), index|
68+
node_id = "#{target}_#{name}_#{index}"
69+
output.puts(" #{node_id}((\"&nbsp;\"))")
70+
output.puts(" #{target} -- \"#{name}[#{index}]\" --> #{node_id}")
71+
output.puts(" #{node_id} -- \"[0]\" --> #{visit(key)}")
72+
output.puts(" #{node_id} -- \"[1]\" --> #{visit(value)}") if value
73+
end
74+
end
75+
76+
def text(name, value)
77+
field(name, value)
78+
end
79+
end
80+
end
81+
end

0 commit comments

Comments
 (0)