home readme diff tree note docs

0commit f2b5c8202fbc904e2ed78260e3fdbd55164799d2
1Author: Mason Wright <mason@lakefox.net>
2Date:   Wed Jun 18 16:02:43 2025 -0600
3
4    Parser supports everything, may add some more grim specific stuff later
5
6diff --git a/element.cc b/element.cc
7index 08f9888..4994d06 100755
8--- a/element.cc
9+++ b/element.cc
10@@ -220,7 +220,7 @@ class Node {
11 
12 			// Print attributes
13 			for (const auto& attr_pair : getAttributes()) {
14-				if (attr_pair.first == "innerText") {
15+				if (attr_pair.first == "innerText" || attr_pair.first == "tagName") {
16 					continue;
17 				}
18 				std::cout << " " << attr_pair.first;
19@@ -244,26 +244,50 @@ class Node {
20 			}
21 
22 			// Print closing tag if it's not a self-closing/root tag
23-			// (Assuming you'll refine logic for self-closing tags eventually)
24-			if (!children.empty() || !getInnerText().empty()) {
25-				for (int i = 0; i < indent; ++i) {
26-					std::cout << "  ";
27-				}
28-				std::cout << "</" << getTagName() << ">" << std::endl;
29+			for (int i = 0; i < indent; ++i) {
30+				std::cout << "  ";
31 			}
32+			std::cout << "</" << getTagName() << ">" << std::endl;
33 		}
34 };
35 
36-std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::string> tokens) {
37+std::unordered_map<std::string, std::string> parseAttributes(std::string token) {
38 	std::unordered_map<std::string, std::string> attrs;
39+	
40+	bool inQuote = false;
41+	bool escaped = false;
42+	char quoteType = '"';
43+
44+
45+	std::string word;
46+	for (unsigned short i = 0; i < token.length(); i++) {
47+		char current = token[i];
48+		if ((current == '"' || current == '\'') && !escaped) {
49+			if (inQuote && current == quoteType) {
50+				inQuote = false;
51+			} else if (!inQuote) {
52+				inQuote = true;
53+				quoteType = current;
54+			}
55+		}
56+
57+		if (current == '\\') { //'
58+			escaped = true;
59+			continue;
60+		}
61+
62+		if ((!std::isspace(current) || inQuote) && i != token.length()-1) {
63+			word += current;
64+		} else {
65+			if (i == token.length()-1) {
66+				word += current;
67+			}
68 
69-	for (unsigned short i = 0; i < tokens.size(); i++) {
70-		if (i != 0) {
71 			std::string name = "";
72 			std::string value = "";
73 			bool setValue = false;
74 			
75-			for (auto c : tokens[i]) {
76+			for (auto c : word) {
77 				if (c == '=') {
78 					setValue = true;
79 					continue;
80@@ -276,6 +300,8 @@ std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::st
81 				}
82 			}
83 
84+			word = "";
85+
86 			std::string trimmedName = "";
87 			for (auto c : name) {
88 				if (!std::isspace(c)) {
89@@ -283,6 +309,11 @@ std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::st
90 				}
91 			}
92 
93+			if (attrs.size() == 0) {
94+				value = '"'+trimmedName+'"';
95+				trimmedName = "tagName";
96+			}
97+
98 			std::string trimmedValue = "";
99 			int sliceStart = 0;
100 			int sliceEnd = value.length();
101@@ -296,7 +327,8 @@ std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::st
102 				}
103 
104 				for (int t = value.length()-1; t >= 0; t--) {
105-					if (!std::isspace(value[t])) {
106+					// Trim the trailing / on self closing elements if there isn't a space inbetween
107+					if (!std::isspace(value[t]) && value[t] != '/') {
108 						sliceEnd = t;
109 						break;
110 					}
111@@ -315,17 +347,6 @@ std::unordered_map<std::string, std::string> parseAttributes(std::vector<std::st
112 	return attrs;
113 }
114 
115-enum Type {
116-	TEXT,
117-	NODE
118-};
119-
120-struct Token {
121-	Type type;
122-	std::string data;
123-};
124-
125-// !TODO: Make a html string parser as well
126 std::unique_ptr<Node> parseStream(std::istream& inputStream) {
127 	std::unique_ptr<Node> root = std::make_unique<Node>();
128 	root->setTagName("root");
129@@ -335,12 +356,40 @@ std::unique_ptr<Node> parseStream(std::istream& inputStream) {
130 	bool inTag = false;
131 	bool escaped = false;
132 	bool inQuote = false;
133+	bool inComment = false;
134 	char quoteType = '"';
135 
136-	std::vector<Token> tokens;
137+	std::string token;
138 
139 	char current;
140 	while (inputStream.get(current)) {
141+
142+		// Finds the --> and removes it then resets inComment
143+		if (inComment) {
144+			// added the peek to prevent hitting on every -
145+			if (current == '-' && inputStream.peek() == '-') {
146+				char a,b;
147+				// load the next two
148+				if (inputStream.get(a) && inputStream.get(b)) {
149+					// We know b == -
150+					if (b == '>') {
151+						// Close the comment
152+						inComment = false;
153+					}
154+				}
155+
156+				if (!inComment) {
157+					// we don't put anything back and that puts us where we need to be
158+					continue;
159+				} else {
160+					// Not the end 
161+					inputStream.putback(b);
162+					inputStream.putback(a);
163+				}
164+			}
165+			continue;
166+		}
167+
168 		if (inTag) {
169 			 if ((current == '"' || current == '\'') && !escaped) {
170 				if (inQuote && current == quoteType) {
171@@ -350,23 +399,129 @@ std::unique_ptr<Node> parseStream(std::istream& inputStream) {
172 					quoteType = current;
173 				}
174 			}
175+
176 			if (current == '>' && !inQuote && !escaped) {
177 				inTag = false;
178 				// Even if the next tag is next still add a text tag as we can just check if its empty and remove it
179 				// this check would still have to be done either way so we aren't wasting anything
180-				std::string data = "";
181-				Token newToken = Token{TEXT, data};
182-				tokens.push_back(newToken);
183-				// for closing tags, use them as a checksum and to manage the position in the tree
184+				if (token.length() > 0) {
185+					bool empty = true;
186+					bool closingTag = false;
187+					for (int i = 0; i < token.length(); i++) {
188+						auto c = token[i];
189+						if (std::isspace(c)) {
190+							continue;
191+						} else if (c == '/') {
192+							closingTag = true;
193+						} else {
194+							empty = false;
195+							break;
196+						}
197+					}
198+
199+					bool selfClosing = false;
200+					int selfClosingPosition = token.length()-1;
201+					if (!closingTag) {
202+						for (int i = token.length()-1; i >= 0; i--) {
203+							auto c = token[i];
204+							if (std::isspace(c)) {
205+								continue;
206+							} else if (c == '/') {
207+								selfClosingPosition = i;
208+								selfClosing = true;
209+								break;
210+							} else {
211+								break;
212+							}
213+						}
214+					}
215+
216+					if (!empty) {
217+						if (selfClosing) {
218+							//Create element and don't jump inside
219+							// Use node instead of currentNode because we do not need to jump into the created element
220+							auto attrs = parseAttributes(token.substr(0, selfClosingPosition));
221+							auto node = currentNode->createElement(attrs["tagName"]);
222+							for (auto const& pair : attrs) {
223+								// All attributes are stored as strings so we can just throw them in
224+								node->setAttribute(pair.first, pair.second);
225+							}
226+						} else if (closingTag) {
227+							// Checksum and tree move
228+							std::string tagName = "";
229+							for (auto t : token) {
230+								if (!std::isspace(t) && t != '/') {
231+									tagName += t;
232+								} else if (t == '/') {
233+									// For closing tags we just want the name
234+									continue;
235+								} else if (tagName.length() > 0) {
236+									break;
237+								}
238+							}
239+							if (currentNode->getTagName() == tagName) {
240+								currentNode = currentNode->parent;
241+							} else {
242+								std::cerr << "malformed html: closing tag (</" << tagName << ">) found for <" << currentNode->getTagName() << ">" << std::endl;
243+							}
244+						} else {
245+							// Create a element and jump inside
246+							auto attrs = parseAttributes(token);
247+							currentNode = currentNode->createElement(attrs["tagName"]);
248+							for (auto const& pair : attrs) {
249+								// All attributes are stored as strings so we can just throw them in
250+								currentNode->setAttribute(pair.first, pair.second);
251+							}
252+
253+						}
254+					}
255+				}
256+
257+				token = "";	
258 				continue;
259 			}
260 		} else if (!escaped && current == '<') {
261+			// if the next charector is a !
262+			if (inputStream.peek() == '!') {
263+				char a,b,c;
264+				// load the next three charecters (includes !)
265+				if (inputStream.get(a) && inputStream.get(b) && inputStream.get(c)) {
266+					// We know a == !
267+					if (b == '-' && c == '-') {
268+						inComment = true;
269+					}
270+				}
271+
272+				if (inComment) {
273+					continue;
274+				} else {
275+					// Not a comment add all back
276+					inputStream.putback(c);
277+					inputStream.putback(b);
278+					inputStream.putback(a);
279+				}
280+			}
281 			inTag = true;
282-			std::string data = "";
283-			Token newToken = Token{NODE, data};
284-			tokens.push_back(newToken);
285+			
286 			// Heres where you actually make the text node and above the real nodes
287 			// can also prob make the vector of tokens a single variable
288+			// it really just needs to be a data string bc we know the type based on inTag
289+
290+
291+			bool hasText = false;
292+			for (auto t : token) {
293+				if (!std::isspace(t)) {
294+					hasText = true;
295+					break;
296+				}
297+			}
298+			if (hasText) {
299+				auto node = currentNode->createElement("text");
300+				node->setInnerText(token);
301+			}
302+
303+
304+			token = "";
305 			continue;
306 		}
307 		
308@@ -377,13 +532,7 @@ std::unique_ptr<Node> parseStream(std::istream& inputStream) {
309 			continue;
310 		}
311 
312-		if (!tokens.empty()) {	
313-			tokens.back().data += current;
314-		}
315-	}
316-
317-	for (auto t : tokens) {
318-		std::cout << t.type << t.data << std::endl;
319+		token += current;
320 	}
321 
322 	return root;
323@@ -396,7 +545,7 @@ int main() {
324 
325 	std::ifstream inputFile("./index.html");
326 	auto document = parseStream(inputFile);
327-
328+	
329 	document->print();
330 	return 0;
331 }
332diff --git a/index.html b/index.html
333index 47a71eb..e4e370d 100644
334--- a/index.html
335+++ b/index.html
336@@ -1,5 +1,15 @@
337 <html>
338-	<h1 id="<"></h1>
339+	<h1 id="<">
340+
341+<!-- asdjkasdhjklsahdjklsa -->
342+<!-- 	 
343+	<b></b>
344+-->
345+<!-- -->
346+<!---->
347+	</h1>
348+	<br />
349+	<input type="text"/>
350 	<p id="test">
351 		this is a test
352 	</p>
353diff --git a/main b/main
354index 445d49b..688e6e3 100755
355Binary files a/main and b/main differ