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 }