1 module feature.parser;
2 import std.stdio;
3 import std.array;
4 public class Parser{
5 	public Node parse(string source){
6 		Node root = new Node();
7 		root.name = "root";
8 		string val = "";
9 		string name = "";
10 		Node curnode = new Node();
11 		Node ParentNode = root;
12 		uint mode = 0; // 0 - collect name, 1 - collect value
13 		uint deep = 0;
14 		char lastchar;
15 		uint lastdeep = 0;
16 		foreach(chr; source){
17 			lastchar = chr;
18 			if(chr == '\t')
19 			{
20 				deep++;
21 				continue;
22 			}
23 			if(chr == ' '){
24 				if(mode == 0){
25 					mode = 1;
26 					continue;
27 				}
28 			}
29 			if(lastchar == '\t' && chr != '\t'){
30 				if(this.nottag(name)){
31 					curnode.name = "raw_text_";
32 					val = name ~ ' ' ~ val;
33 				}
34 				else
35 					curnode.name = name;
36 
37 				curnode.value = val;
38 				mode = 0;
39 				ParentNode.children ~= [curnode];
40 				ParentNode = curnode;
41 				curnode = new Node();
42 				name = "";
43 				val = "";
44 				if(lastdeep > deep){
45 					curnode = getParent(ParentNode, lastdeep - deep);
46 				}
47 				lastdeep = deep;
48 				deep = 0;
49 			}
50 			if(chr == '\r' || chr == '\n'){
51 				continue;
52 			}
53 			if(mode == 0)
54 				name ~= chr;
55 			if(mode == 1)
56 				val ~= chr;
57 		}
58 		return root;
59 	}
60 	private Node getParent(Node node, uint deep){
61 		Node parent = node;
62 		for(uint i = 0; i < deep; i++){
63 			parent = getParent(parent);
64 		}
65 		return parent;
66 	}
67 	private Node getParent(Node node){
68 		return node.parent;
69 	}
70 	private bool nottag(string tag){
71 		switch(tag)
72 		{
73 			case "html":
74 			case "head":
75 			case "body":
76 			case "title":
77 			case "p":
78 				return false;
79 			default:
80 				return true;
81 		}
82 	}
83 }
84 public class HtmlGenerator{
85 	private string html;
86 	public string Generate(Node root){
87 		this.html = "";
88 		visit(root, 0);
89 		return this.html;
90 	}
91 	private void visit(Node node, uint deep){
92 		if(node.name != "raw_text_")
93 			this.html ~= '<' ~ node.name ~ GetAttr(node) ~ '>';
94 		else
95 			this.html ~= node.value;
96 		foreach(n; node.children){
97 			visit(n, deep + 1);
98 		}
99 		if(node.name != "raw_text_")
100 			this.html ~= "</" ~ node.name ~ '>';
101 	}
102 	private string GetAttr(Node node){
103 		string attr = "";
104 		foreach(at; node.attr.byPair){
105 			attr ~= " " ~ at.key ~ "=\"" ~ at.value ~ "\" ";
106 		}
107 		return attr;
108 	}
109 }
110 public class Node{
111 	Node parent;
112 	Node[] children;
113 	string value;
114 	string name;
115 	string[string] attr;
116 	this(Node parent = null, Node[] children = new Node[0], string value = "", string name = ""){
117 		this.parent = parent;
118 		this.children = children;
119 		this.value = value;
120 		this.name = name;
121 	}
122 }