1 /++
2 Used for debugging compiler
3 Generates a HTML page that represents a readable representation of AST nodes
4 Only available in `qsCompiler` configuration (`dub -c=qsCompiler`)
5 +/
6 module qscript.compiler.asthtml;
7
8 import qscript.compiler.ast;
9
10 import utils.misc;
11 import utils.lists;
12
13 import std.conv : to;
14
15 version (compiler){
16 /// stores the style sheet for the page
17 private enum STYLESHEET = "<style>*{font-family:monospace;border:1px solid #cccccc;border-collapse:collapse;}</style>";
18 /// some commonly used html codes
19 private enum HTML : string{
20 TABLE_HEADING_START = "<table><tr><th>",
21 TABLE_HEADING_END = "</th></tr>",
22 TABLE_END = "</table>",
23 ROW_START = "<tr>",
24 ROW_END = "</tr>",
25 DATA_START = "<td>",
26 DATA_END = "</td>",
27 BOLD_START = "<b>",
28 BOLD_END = "</b>",
29 }
30 /// to generate an html page representing AST nodes
31 class ASTHtml{
32 private:
33 /// stores the html page while it's being generated
34 List!string _html;
35 /// replaces non alpabet, non numeric chars with html codes
36 static string htmlEncode(string str){
37 if (str.isAlphabet || str.isNum)
38 return str;
39 char[] r;
40 foreach (c; str){
41 if ((cast(string)[c]).isAlphabet || (cast(string)[c]).isNum)
42 r ~= c;
43 else
44 r ~= "&#"~((cast(int)c).to!string)~';';
45 }
46 return cast(string)r;
47 }
48 /// appends a new table with a heading
49 void tableNew(string heading, bool asRow = false){
50 if (asRow)
51 _html.append(HTML.ROW_START);
52 _html.append(HTML.TABLE_HEADING_START~htmlEncode(heading)~HTML.TABLE_HEADING_END);
53 if (asRow)
54 _html.append(HTML.ROW_END);
55 }
56 /// appends a table end tag
57 void tableEnd(){
58 _html.append(HTML.TABLE_END);
59 }
60 /// appends a row to table
61 void tableRow(string[] values, bool bold=false){
62 _html.append(HTML.ROW_START);
63 if (bold)
64 _html.append(HTML.BOLD_START);
65 foreach (val; values)
66 _html.append(HTML.DATA_START~htmlEncode(val)~HTML.DATA_END);
67 if (bold)
68 _html.append(HTML.BOLD_END);
69 _html.append(HTML.ROW_END);
70 }
71
72 /// generate html for EnumNodes
73 void generateHtml(EnumNode[] nodes){
74 tableNew("enums");
75 tableRow(["id", "name", "visibility", "members"], true);
76 foreach (i, node; nodes)
77 tableRow([i.to!string, node.name, node.visibility.to!string, node.members.to!string]);
78 tableEnd();
79 }
80 /// generates html for StructNodes
81 void generateHtml(StructNode[] nodes){
82 tableNew("structs");
83 foreach (i, node; nodes){
84 tableNew(node.name, true);
85 tableRow(["id", i.to!string]);
86 tableRow(["visibility", node.visibility.to!string]);
87 tableRow(["containsRef", node.containsRef.to!string]);
88 tableRow(["members:"], true);
89 foreach (memberId; 0 .. node.membersName.length)
90 tableRow([node.membersDataType[memberId].name, node.membersName[i]]);
91 tableEnd();
92 }
93 tableEnd();
94 }
95 /// generates html for global variables
96 void generateHtml(VarDeclareNode[] nodes){
97 tableNew("global variables");
98 foreach (i, node; nodes){
99
100 }
101 tableEnd();
102 }
103 /// generates html for VarDeclareNode
104 void generateHtml(VarDeclareNode node, bool asRow = false){
105 if (asRow){
106 // id, data type, name, value
107 //foreach (node.) TODO
108 }
109 }
110 public:
111 /// constructor
112 this(){
113 _html = new List!string;
114 }
115 ~this(){
116 .destroy(_html);
117 }
118 /// generates html page for ScriptNode
119 void generateHtml(ScriptNode node){
120 // throw stylesheet first
121 _html.append(STYLESHEET);
122 if (node.imports.length){
123 tableNew("imports");
124 foreach (i, importName; node.imports)
125 tableRow([to!string(i), importName]);
126 tableEnd();
127 }
128 if (node.enums.length){
129 generateHtml(node.enums);
130 }
131 if (node.structs.length){
132 tableNew("structs");
133 /*foreach (structNode; node.structs)
134 this.generateHtml(structNode);
135 tableEnd();
136 }
137 if (node.variables.length){
138 tableNew("global variables");
139 foreach(var; node.variables)
140 generateHtml(var);
141 tableEnd();
142 }
143 if (node.functions.length){
144 tableNew("functions");
145 foreach (func; node.functions)
146 generateHtml(func);
147 tableEnd();*/
148 }
149 }
150 /// Returns: generated page as a string[] where each string is a separate line. does **not** include endl characters
151 @property string[] html(){
152 return _html.toArray;
153 }
154 }
155 }