1 #include "minilang.h"
2 #include "ml_file.h"
3 #include "ml_object.h"
4 #include "ml_iterfns.h"
5 #include "ml_macros.h"
6 #include "ml_console.h"
7 #include "linenoise.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <gc/gc.h>
12 
13 //!xe
14 
15 typedef struct xe_node_t {
16 	const ml_type_t *Type;
17 	ml_value_t *Tag, *Attributes, *Content;
18 	ml_source_t Source;
19 } xe_node_t;
20 
21 typedef struct xe_var_t {
22 	const ml_type_t *Type;
23 	ml_value_t *Name;
24 } xe_var_t;
25 
26 ML_TYPE(XENodeT, (), "xe-node");
27 ML_TYPE(XEVarT, (), "xe-var");
28 
node_append(ml_value_t * List,ml_value_t * Node)29 static void node_append(ml_value_t *List, ml_value_t *Node) {
30 	if (ml_is(Node, MLListT)) {
31 		ML_LIST_FOREACH(Node, Iter) node_append(List, Iter->Value);
32 	} else if (ml_is(Node, MLStringT)) {
33 		if (ml_list_length(List) > 0) {
34 			ml_value_t *Tail = ml_list_get(List, -1);
35 			if (ml_is(Tail, MLStringT)) {
36 				int Length1 = ml_string_length(Tail);
37 				int Length2 = ml_string_length(Node);
38 				char *Concat = GC_malloc_atomic(Length1 + Length2 + 1);
39 				memcpy(Concat, ml_string_value(Tail), Length1);
40 				memcpy(Concat + Length1, ml_string_value(Node), Length2);
41 				Concat[Length1 + Length2] = 0;
42 				ml_list_set(List, -1, ml_string(Concat, Length1 + Length2));
43 			} else {
44 				ml_list_put(List, Node);
45 			}
46 		} else {
47 			ml_list_put(List, Node);
48 		}
49 	} else if (ml_is(Node, MLIntegerT)) {
50 		ml_list_put(List, ml_string_format("%ld", ml_integer_value_fast(Node)));
51 	} else if (ml_is(Node, MLDoubleT)) {
52 		ml_list_put(List, ml_string_format("%f", ml_real_value(Node)));
53 	} else if (ml_is(Node, XENodeT)) {
54 		ml_list_put(List, Node);
55 	} else if (ml_is(Node, XEVarT)) {
56 		ml_list_put(List, Node);
57 	}
58 }
59 
60 typedef struct xe_stream_t xe_stream_t;
61 
62 struct xe_stream_t {
63 	const char *Next;
64 	const char *(*read)(xe_stream_t *);
65 	void *Data;
66 	const char *Source;
67 	int LineNo;
68 };
69 
70 static ml_value_t *parse_node(xe_stream_t *Stream);
71 
parse_escape(const char * P,ml_stringbuffer_t * Buffer)72 static const char *parse_escape(const char *P, ml_stringbuffer_t *Buffer) {
73 	switch (P[1]) {
74 	case '\\':
75 		ml_stringbuffer_add(Buffer, "\\", 1);
76 		break;
77 	case 't':
78 		ml_stringbuffer_add(Buffer, "\t", 1);
79 		break;
80 	case 'r':
81 		ml_stringbuffer_add(Buffer, "\r", 1);
82 		break;
83 	case 'n':
84 		ml_stringbuffer_add(Buffer, "\n", 1);
85 		break;
86 	case '\"':
87 		ml_stringbuffer_add(Buffer, "\"", 1);
88 		break;
89 	case '<':
90 		ml_stringbuffer_add(Buffer, "<", 1);
91 		break;
92 	case '>':
93 		ml_stringbuffer_add(Buffer, ">", 1);
94 		break;
95 	case 'x': {
96 		unsigned char C;
97 		switch (P[2]) {
98 		case '0' ... '9': C = P[2] - '0'; break;
99 		case 'a' ... 'f': C = 10 + P[2] - 'a'; break;
100 		case 'A' ... 'F': C = 10 + P[2] - 'A'; break;
101 		default: return 0;
102 		}
103 		C *= 16;
104 		switch (P[3]) {
105 		case '0' ... '9': C += P[3] - '0'; break;
106 		case 'a' ... 'f': C += 10 + P[3] - 'a'; break;
107 		case 'A' ... 'F': C += 10 + P[3] - 'A'; break;
108 		default: return 0;
109 		}
110 		ml_stringbuffer_add(Buffer, (char *)&C, 1);
111 		P += 2;
112 		break;
113 	}
114 	}
115 	return P + 2;
116 }
117 
parse_string(xe_stream_t * Stream)118 static ml_value_t *parse_string(xe_stream_t *Stream) {
119 	ml_stringbuffer_t Buffer[1] = {ML_STRINGBUFFER_INIT};
120 	const char *Next = Stream->Next;
121 	const char *P = Next;
122 	for (;;) {
123 		if (P[0] == 0) {
124 			return ml_error("ParseError", "End of input in string at line %d in %s", Stream->LineNo, Stream->Source);
125 		} else if (P[0] == '\\') {
126 			ml_stringbuffer_add(Buffer, Next, P - Next);
127 			P = Next = parse_escape(P, Buffer);
128 			if (!P) return ml_error("ParseError", "Invalid escape sequence at line %d in %s", Stream->LineNo, Stream->Source);
129 		} else if (P[0] == '\"') {
130 			ml_stringbuffer_add(Buffer, Next, P - Next);
131 			Stream->Next = P + 1;
132 			break;
133 		} else {
134 			++P;
135 		}
136 	}
137 	return ml_stringbuffer_value(Buffer);
138 }
139 
140 #define SKIP_WHITESPACE \
141 	while (Next[0] <= ' ') { \
142 		if (Next[0] == 0) { \
143 			Next = Stream->read(Stream); \
144 			if (!Next) return ml_error("ParseError", "Unexpected end of input at line %d in %s", Stream->LineNo, Stream->Source); \
145 			++Stream->LineNo; \
146 		} else { \
147 			++Next; \
148 		} \
149 	}
150 
parse_value(xe_stream_t * Stream)151 static ml_value_t *parse_value(xe_stream_t *Stream) {
152 	const char *Next = Stream->Next;
153 	SKIP_WHITESPACE;
154 	if (Next[0] == '<') {
155 		Stream->Next = Next + 1;
156 		return parse_node(Stream);
157 	} else if (Next[0] == '[') {
158 		++Next;
159 		ml_value_t *List = ml_list();
160 		SKIP_WHITESPACE;
161 		if (Next[0] != ']') for (;;) {
162 			Stream->Next = Next;
163 			ml_value_t *Value = parse_value(Stream);
164 			Next = Stream->Next;
165 			if (ml_is_error(Value)) return Value;
166 			ml_list_put(List, Value);
167 			SKIP_WHITESPACE;
168 			if (Next[0] == ']') break;
169 			if (Next[0] != ',') return ml_error("ParseError", "Expected , at %d in %s", Stream->LineNo, Stream->Source);
170 			++Next;
171 		}
172 		Stream->Next = Next + 1;
173 		return List;
174 	} else if (Next[0] == '{') {
175 		return ml_error("ParseError", "Map parsing not complete yet at %d in %s", Stream->LineNo, Stream->Source);
176 	} else if (Next[0] == '\"') {
177 		Stream->Next = Next + 1;
178 		return parse_string(Stream);
179 	} else if (Next[0] == '-' || ('0' <= Next[0] && Next[0] <= '9') || Next[0] == '.') {
180 		char *End;
181 		long Value = strtol(Next, &End, 10);
182 		if (End[0] == '.' || End[0] == 'e' || End[0] == 'E') {
183 			double Value = strtod(Next, &End);
184 			Stream->Next = End;
185 			return ml_real(Value);
186 		} else {
187 			Stream->Next = End;
188 			return ml_integer(Value);
189 		}
190 	} else {
191 		return ml_error("ParseError", "Invalid value syntax at line %d in %s", Stream->LineNo, Stream->Source);
192 	}
193 }
194 
parse_node(xe_stream_t * Stream)195 static ml_value_t *parse_node(xe_stream_t *Stream) {
196 	int LineNo = Stream->LineNo;
197 	const char *Next = Stream->Next;
198 	for (;;) {
199 		char Delim = *Next;
200 		if (Delim <= ' ') break;
201 		if (Delim == ':') break;
202 		if (Delim == '|') break;
203 		if (Delim == '>') break;
204 		++Next;
205 	}
206 	int TagLength = Next - Stream->Next;
207 	if (Stream->Next[0] == '$') {
208 		--TagLength;
209 		char *Name = GC_malloc_atomic(TagLength + 1);
210 		memcpy(Name, Stream->Next + 1, TagLength);
211 		Name[TagLength] = 0;
212 		SKIP_WHITESPACE;
213 		Stream->Next = Next + 1;
214 		xe_var_t *Var = new(xe_var_t);
215 		Var->Type = XEVarT;
216 		if (!TagLength) {
217 			Var->Name = MLNil;
218 		} else if (isalpha(Name[0])) {
219 			Var->Name = ml_string(Name, TagLength);
220 		} else {
221 			Var->Name = ml_integer(atoi(Name));
222 		}
223 		return (ml_value_t *)Var;
224 	} else {
225 		ml_value_t *Tag;
226 		ml_value_t *Attributes = ml_map();
227 		ml_value_t *Content = ml_list();
228 		int Index = 1;
229 		if (Stream->Next[0] == '@') {
230 			Tag = ml_cstring("@");
231 			ml_map_insert(Attributes, ml_integer(Index++), ml_string(Stream->Next + 1, TagLength - 1));
232 		} else {
233 			Tag = ml_string(Stream->Next, TagLength);
234 		}
235 		for (;;) {
236 			SKIP_WHITESPACE;
237 			if (Next[0] != ':' && Next[0] != '|' && Next[0] != '>' && Next[0] != '?') {
238 				const char *Start = Next;
239 				for (;;) {
240 					if (!isalpha(*Next)) break;
241 					/*char Delim = *Next;
242 					if (Delim <= ' ') break;
243 					if (Delim == ':') break;
244 					if (Delim == '|') break;
245 					if (Delim == '>') break;
246 					if (Delim == '=') break;*/
247 					++Next;
248 				}
249 				int NameLength = Next - Start;
250 				ml_value_t *Name;
251 				if (NameLength) {
252 					Name = ml_string(Start, NameLength);
253 					SKIP_WHITESPACE;
254 					if (Next[0] != '=') return ml_error("ParseError", "Expected = at line %d in %s", Stream->LineNo, Stream->Source);
255 					++Next;
256 					SKIP_WHITESPACE;
257 				} else {
258 					Name = ml_integer(Index++);
259 				}
260 				Stream->Next = Next;
261 				ml_value_t *Value = parse_value(Stream);
262 				if (ml_is_error(Value)) return Value;
263 				ml_map_insert(Attributes, Name, Value);
264 				Next = Stream->Next;
265 			} else {
266 				break;
267 			}
268 		}
269 		if (Next[0] == ':') {
270 			ml_stringbuffer_t Buffer[1] = {ML_STRINGBUFFER_INIT};
271 			const char *End = ++Next;
272 			for (;;) {
273 				if (End[0] == 0) {
274 					ml_stringbuffer_add(Buffer, Next, End - Next);
275 					//ml_stringbuffer_add(Buffer, "\n", 1);
276 					Next = Stream->read(Stream);
277 					if (!Next) return ml_error("ParseError", "Unexpected end of input at line %d in %s", Stream->LineNo, Stream->Source);
278 					++Stream->LineNo;
279 					End = Next;
280 				} else if (End[0] == '\\') {
281 					ml_stringbuffer_add(Buffer, Next, End - Next);
282 					End = Next = parse_escape(End, Buffer);
283 					if (!End) return ml_error("ParseError", "Invalid escape sequence at line %d in %s", Stream->LineNo, Stream->Source);
284 				} else if (End[0] == '<') {
285 					ml_stringbuffer_add(Buffer, Next, End - Next);
286 					if (Buffer->Length) node_append(Content, ml_stringbuffer_value(Buffer));
287 					Stream->Next = End + 1;
288 					ml_list_put(Content, parse_node(Stream));
289 					End = Next = Stream->Next;
290 				} else if (End[0] == '>') {
291 					ml_stringbuffer_add(Buffer, Next, End - Next);
292 					if (Buffer->Length) node_append(Content, ml_stringbuffer_value(Buffer));
293 					break;
294 				} else {
295 					++End;
296 				}
297 			}
298 			Stream->Next = End + 1;
299 		} else if (Next[0] == '|') {
300 			const char *End = ++Next;
301 			for (;;) {
302 				if (End[0] == 0) {
303 					Next = Stream->read(Stream);
304 					if (!Next) return ml_error("ParseError", "Unexpected end of input at line %d in %s", Stream->LineNo, Stream->Source);
305 					++Stream->LineNo;
306 					End = Next;
307 				} else if (End[0] == '<') {
308 					Stream->Next = End + 1;
309 					ml_list_put(Content, parse_node(Stream));
310 					End = Next = Stream->Next;
311 				} else if (End[0] == '>') {
312 					break;
313 				} else if (End[0] <= ' ') {
314 					++End;
315 				} else {
316 					return ml_error("ParseError", "Non whitespace character in | node at line %d in %s", Stream->LineNo, Stream->Source);
317 				}
318 			}
319 			Stream->Next = End + 1;
320 		} else {
321 			Stream->Next = Next + 1;
322 		}
323 		xe_node_t *Node = new(xe_node_t);
324 		Node->Type = XENodeT;
325 		Node->Tag = Tag;
326 		Node->Attributes = Attributes;
327 		Node->Content = Content;
328 		Node->Source.Name = Stream->Source;
329 		Node->Source.Line = LineNo;
330 		return (ml_value_t *)Node;
331 	}
332 }
333 
334 typedef struct xe_scope_t xe_scope_t;
335 
336 struct xe_scope_t {
337 	const ml_type_t *Type;
338 	stringmap_t Symbols[1];
339 	stringmap_t Parents[1];
340 };
341 
342 ML_TYPE(XEScopeT, (), "xe-scope");
343 
node_eval(ml_value_t * Value,ml_value_t * Attributes,ml_value_t * Content,xe_scope_t * Scope)344 static ml_value_t *node_eval(ml_value_t *Value, ml_value_t *Attributes, ml_value_t *Content, xe_scope_t *Scope) {
345 	if (ml_is(Value, MLListT)) {
346 		ml_value_t *List = ml_list();
347 		ML_LIST_FOREACH(Value, Iter) {
348 			ml_value_t *Value2 = node_eval(Iter->Value, Attributes, Content, Scope);
349 			if (ml_is_error(Value2)) return Value2;
350 			node_append(List, Value2);
351 		}
352 		return List;
353 	} else if (ml_is(Value, XENodeT)) {
354 		xe_node_t *Node = (xe_node_t *)Value;
355 		ml_value_t *Attributes2 = ml_map();
356 		ML_MAP_FOREACH(Node->Attributes, Iter) {
357 			ml_value_t *Value2 = node_eval(Iter->Value, Attributes, Content, Scope);
358 			if (ml_is_error(Value2)) return Value2;
359 			ml_map_insert(Attributes2, Iter->Key, Value2);
360 		}
361 		ml_value_t *Content2 = ml_list();
362 		ML_LIST_FOREACH(Node->Content, Iter) {
363 			ml_value_t *Value2 = node_eval(Iter->Value, Attributes, Content, Scope);
364 			if (ml_is_error(Value2)) return Value2;
365 			node_append(Content2, Value2);
366 		}
367 		xe_node_t *Node2 = new(xe_node_t);
368 		Node2->Type = XENodeT;
369 		Node2->Tag = Node->Tag;
370 		Node2->Attributes = Attributes2;
371 		Node2->Content = Content2;
372 		Node2->Source = Node->Source;
373 		return (ml_value_t *)Node2;
374 	} else if (ml_is(Value, MLIntegerT)) {
375 		return Value;
376 	} else if (ml_is(Value, MLDoubleT)) {
377 		return Value;
378 	} else if (ml_is(Value, MLStringT)) {
379 		return Value;
380 	} else if (ml_is(Value, XEVarT)) {
381 		xe_var_t *Var = (xe_var_t *)Value;
382 		if (Var->Name != MLNil) {
383 			ml_value_t *Value2 = ml_map_search(Attributes, Var->Name);
384 			if (Value2 == MLNil) return (ml_value_t *)Var;
385 			return Value2;
386 		} else {
387 			return Content;
388 		}
389 	} else if (ml_is(Value, MLFunctionT)) {
390 		return ml_simple_inline(Value, 3, Attributes, Content, Scope);
391 	} else {
392 		return Value;
393 	}
394 }
395 
396 typedef struct node_path_t node_path_t;
397 
398 struct node_path_t {
399 	node_path_t *Parent;
400 	const char *Tag;
401 };
402 
403 static xe_scope_t GlobalScope[1] = {{
404 	XEScopeT,
405 	{STRINGMAP_INIT},
406 	{STRINGMAP_INIT}
407 }};
408 
define_lookup(xe_scope_t * Defines,const char * Tag,node_path_t * Path)409 static ml_value_t *define_lookup(xe_scope_t *Defines, const char *Tag, node_path_t *Path) {
410 	if (Path) {
411 		xe_scope_t *Parent = stringmap_search(Defines->Parents, Path->Tag);
412 		if (Parent) {
413 			ml_value_t *Value = define_lookup(Parent, Tag, Path->Parent);
414 			if (Value) return Value;
415 		}
416 	}
417 	return stringmap_search(Defines->Symbols, Tag);
418 }
419 
node_expand(ml_value_t * Value,node_path_t * Path,xe_scope_t * Scope)420 static ml_value_t *node_expand(ml_value_t *Value, node_path_t *Path, xe_scope_t *Scope) {
421 	for (;;) {
422 		if (ml_is(Value, MLListT)) {
423 			ml_value_t *List = ml_list();
424 			ML_LIST_FOREACH(Value, Iter) {
425 				ml_value_t *Value2 = node_expand(Iter->Value, Path, Scope);
426 				if (ml_is_error(Value2)) return Value2;
427 				node_append(List, Value2);
428 			}
429 			return List;
430 		} else if (ml_is(Value, XENodeT)) {
431 			xe_node_t *Node = (xe_node_t *)Value;
432 			const char *Tag = ml_string_value(Node->Tag);
433 			ml_value_t *Define = define_lookup(GlobalScope, Tag, Path);
434 			if (Define) {
435 				Value = node_eval(Define, Node->Attributes, Node->Content, Scope);
436 			} else {
437 				node_path_t SubPath[1] = {{Path, Tag}};
438 				ML_MAP_FOREACH(Node->Attributes, Iter) {
439 					Iter->Value = node_expand(Iter->Value, SubPath, Scope);
440 				}
441 				ml_value_t *Content = ml_list();
442 				ML_LIST_FOREACH(Node->Content, Iter) {
443 					ml_value_t *Value2 = node_expand(Iter->Value, SubPath, Scope);
444 					if (ml_is_error(Value2)) return Value2;
445 					node_append(Content, Value2);
446 				}
447 				Node->Content = Content;
448 				return (ml_value_t *)Node;
449 			}
450 		} else {
451 			return Value;
452 		}
453 	}
454 	return MLNil;
455 }
456 
compile_string(ml_value_t * Value,ml_stringbuffer_t * Source)457 static void compile_string(ml_value_t *Value, ml_stringbuffer_t *Source) {
458 	ml_stringbuffer_add(Source, "\"", 1);
459 	int Length = ml_string_length(Value);
460 	const char *String = ml_string_value(Value);
461 	int I = 0;
462 	for (int J = 0; J < Length; ++J) {
463 		if (String[J] < ' ') {
464 			if (J > I) ml_stringbuffer_add(Source, String + I, J - I);
465 			switch (String[J]) {
466 			case '\t':
467 				ml_stringbuffer_add(Source, "\\t", 2);
468 				break;
469 			case '\r':
470 				ml_stringbuffer_add(Source, "\\r", 2);
471 				break;
472 			case '\n':
473 				ml_stringbuffer_add(Source, "\\n", 2);
474 				break;
475 			}
476 			I = J + 1;
477 		} else if (String[J] == '\"') {
478 			if (J > I) ml_stringbuffer_add(Source, String + I, J - I);
479 			ml_stringbuffer_add(Source, "\\\"", 2);
480 			I = J + 1;
481 		}
482 	}
483 	if (Length > I) ml_stringbuffer_add(Source, String + I, Length - I);
484 	ml_stringbuffer_add(Source, "\"", 1);
485 }
486 
487 static void compile_inline_node(ml_value_t *Value, ml_stringbuffer_t *Source);
488 
compile_inline_value(ml_value_t * Value,ml_stringbuffer_t * Source)489 static void compile_inline_value(ml_value_t *Value, ml_stringbuffer_t *Source) {
490 	if (ml_is(Value, MLListT)) {
491 		ml_stringbuffer_add(Source, "[", 1);
492 		int Comma = 0;
493 		ML_LIST_FOREACH(Value, Iter) {
494 			if (Comma) ml_stringbuffer_add(Source, ",", 1);
495 			compile_inline_node(Iter->Value, Source);
496 			Comma = 1;
497 		}
498 		ml_stringbuffer_add(Source, "]", 1);
499 	} else if (ml_is(Value, XENodeT)) {
500 		compile_inline_node(Value, Source);
501 	} else if (ml_is(Value, XEVarT)) {
502 		xe_var_t *Var = (xe_var_t *)Value;
503 		ml_stringbuffer_add(Source, "var(", 4);
504 		if (ml_string_length(Var->Name)) compile_string(Var->Name, Source);
505 		ml_stringbuffer_add(Source, ")", 1);
506 	} else if (ml_is(Value, MLStringT)) {
507 		compile_string(Value, Source);
508 	} else if (ml_is(Value, MLIntegerT)) {
509 		ml_stringbuffer_addf(Source, "%ld", ml_integer_value_fast(Value));
510 	} else if (ml_is(Value, MLDoubleT)) {
511 		ml_stringbuffer_addf(Source, "%f", ml_real_value(Value));
512 	} else {
513 		printf("Unknown value here: <%s>\n", ml_typeof(Value)->Name);
514 	}
515 }
516 
compile_inline_node(ml_value_t * Value,ml_stringbuffer_t * Source)517 static void compile_inline_node(ml_value_t *Value, ml_stringbuffer_t *Source) {
518 	if (ml_is(Value, XENodeT)) {
519 		xe_node_t *Node = (xe_node_t *)Value;
520 		if (ml_string_length(Node->Tag)) {
521 			ml_stringbuffer_add(Source, "node(", 5);
522 			compile_string(Node->Tag, Source);
523 			ml_stringbuffer_add(Source, ",{", 2);
524 			int Comma = 0;
525 			ML_MAP_FOREACH(Node->Attributes, Iter) {
526 				if (Comma) ml_stringbuffer_add(Source, ",", 1);
527 				compile_string(Iter->Key, Source);
528 				ml_stringbuffer_add(Source, " is ", 4);
529 				compile_inline_value(Iter->Value, Source);
530 				Comma = 1;
531 			}
532 			ml_stringbuffer_add(Source, "},[", 3);
533 			Comma = 0;
534 			ML_LIST_FOREACH(Node->Content, Iter) {
535 				if (Comma) ml_stringbuffer_add(Source, ",", 1);
536 				compile_inline_node(Iter->Value, Source);
537 				Comma = 1;
538 			}
539 			ml_stringbuffer_add(Source, "])", 2);
540 		} else {
541 			ML_LIST_FOREACH(Node->Content, Iter) {
542 				ml_value_t *Value = Iter->Value;
543 				if (ml_is(Value, MLStringT)) {
544 					ml_stringbuffer_add(Source, ml_string_value(Value), ml_string_length(Value));
545 				} else {
546 					compile_inline_node(Value, Source);
547 				}
548 			}
549 		}
550 	} else if (ml_is(Value, XEVarT)) {
551 		xe_var_t *Var = (xe_var_t *)Value;
552 		ml_stringbuffer_add(Source, "var(", 4);
553 		if (ml_string_length(Var->Name)) compile_string(Var->Name, Source);
554 		ml_stringbuffer_add(Source, ")", 1);
555 	} else if (ml_is(Value, MLStringT)) {
556 		compile_string(Value, Source);
557 	} else if (ml_is(Value, MLIntegerT)) {
558 		ml_stringbuffer_addf(Source, "%ld", ml_integer_value_fast(Value));
559 	} else if (ml_is(Value, MLDoubleT)) {
560 		ml_stringbuffer_addf(Source, "%f", ml_real_value(Value));
561 	} else {
562 
563 	}
564 }
565 
string_read(xe_stream_t * Stream)566 static const char *string_read(xe_stream_t *Stream) {
567 	const char *Next = (const char *)Stream->Data, *End = Next;
568 	if (!Next) return 0;
569 	while (End[0] >= ' ') ++End;
570 	int Length = (End - Next) + 1;
571 	char *Line = GC_malloc_atomic(Length + 1);
572 	memcpy(Line, Next, Length);
573 	Line[Length] = 0;
574 	if (End[0]) {
575 		Stream->Data = (void *)(End + 1);
576 	} else {
577 		Stream->Data = 0;
578 	}
579 	return Line;
580 }
581 
582 static stringmap_t Globals[1] = {STRINGMAP_INIT};
583 
global_get(void * Data,const char * Name)584 static ml_value_t *global_get(void *Data, const char *Name) {
585 	return stringmap_search(Globals, Name) ?: MLNil;
586 }
587 
compile_macro(ml_value_t * Value)588 static ml_value_t *compile_macro(ml_value_t *Value) {
589 	if (ml_is(Value, MLListT)) {
590 		ML_LIST_FOREACH(Value, Iter) {
591 			Iter->Value = compile_macro(Iter->Value);
592 		}
593 	} else if (ml_is(Value, XENodeT)) {
594 		xe_node_t *Node = (xe_node_t *)Value;
595 		ML_MAP_FOREACH(Node->Attributes, Iter) {
596 			Iter->Value = compile_macro(Iter->Value);
597 		}
598 		compile_macro(Node->Content);
599 	}
600 	return Value;
601 }
602 
attribute_get(ml_value_t * Attributes,const char * Name)603 static ml_value_t *attribute_get(ml_value_t *Attributes, const char *Name) {
604 	ml_value_t *Value = ml_map_search(Attributes, ml_cstring(Name));
605 	if (Value == MLNil) return global_get(Globals, Name);
606 	return Value;
607 }
608 
ML_FUNCTIONX(XEFunction)609 ML_FUNCTIONX(XEFunction) {
610 	ml_value_t *Attributes = Args[0];
611 	ml_value_t *Content = Args[1];
612 	xe_scope_t *Scope = (xe_scope_t *)Args[2];
613 	ml_stringbuffer_t Source[1] = {ML_STRINGBUFFER_INIT};
614 	ml_stringbuffer_add(Source, "fun(Args, Content, Scope) do ", strlen("fun(Args, Content, Scope) do "));
615 	ML_LIST_FOREACH(Content, Iter) {
616 		ml_value_t *Value2 = Iter->Value;
617 		if (ml_is(Value2, MLStringT)) {
618 			ml_stringbuffer_add(Source, ml_string_value(Value2), ml_string_length(Value2));
619 		} else {
620 			compile_inline_node(Value2, Source);
621 		}
622 	}
623 	ml_stringbuffer_add(Source, " end", 4);
624 	xe_stream_t Stream[1];
625 	Stream->Data = ml_stringbuffer_get(Source);
626 	//printf("Function = %s\n", (char *)Stream->Data);
627 	Stream->read = string_read;
628 	ml_parser_t *Parser = ml_parser((void *)string_read, Stream);
629 	ml_compiler_t *Compiler = ml_compiler((ml_getter_t)attribute_get, Attributes);
630 	ml_parser_source(Parser, ml_debugger_source(Caller));
631 	ml_result_state_t *State = ml_result_state_new(Caller->Context);
632 	ml_command_evaluate((ml_state_t *)State, Parser, Compiler);
633 	ml_value_t *Macro = State->Value;
634 	if (Macro == MLEndOfInput) Macro = ml_error("ParseError", "Empty body");
635 	if (ml_is_error(Macro)) ML_RETURN(Macro);
636 	ml_value_t *Name = ml_map_search(Attributes, ml_integer(1));
637 	if (Name == MLNil) ML_RETURN(Macro);
638 	if (!ml_is(Name, MLStringT)) ML_RETURN(ml_error("MacroError", "name attribute must be a string"));
639 	if (ml_string_length(Name) == 0) ML_RETURN(Macro);
640 	stringmap_insert(Scope->Symbols, ml_string_value(Name), Macro);
641 	ML_RETURN(MLNil);
642 }
643 
ML_FUNCTION(XEDefine)644 ML_FUNCTION(XEDefine) {
645 	ml_value_t *Attributes = Args[0];
646 	ml_value_t *Content = Args[1];
647 	xe_scope_t *Scope = (xe_scope_t *)Args[2];
648 	ml_value_t *Name = ml_map_search(Attributes, ml_integer(1));
649 	if (Name == MLNil) return ml_error("MacroError", "define macro requires name attribute");
650 	if (!ml_is(Name, MLStringT)) return ml_error("MacroError", "name attribute must be a string");
651 	ml_value_t *Macro = compile_macro(Content);
652 	stringmap_insert(Scope->Symbols, ml_string_value(Name), Macro);
653 	return MLNil;
654 }
655 
xe_scope_parse(xe_scope_t * Scope,xe_node_t * Path)656 static xe_scope_t *xe_scope_parse(xe_scope_t *Scope, xe_node_t *Path) {
657 	if (!ml_is((ml_value_t *)Path, XENodeT)) return (xe_scope_t *)ml_error("MacroError", "path attribute must be a node");
658 	xe_node_t *Next = (xe_node_t *)ml_list_get(Path->Content, 1);
659 	if (Next) {
660 		Scope = xe_scope_parse(Scope, Next);
661 		if (ml_is_error((ml_value_t *)Scope)) return Scope;
662 	}
663 	xe_scope_t **Slot = (xe_scope_t **)stringmap_slot(Scope->Parents, ml_string_value(Path->Tag));
664 	if (!Slot[0]) {
665 		Scope = Slot[0] = new(xe_scope_t);
666 		Scope->Type = XEScopeT;
667 	} else {
668 		Scope = Slot[0];
669 	}
670 	return Scope;
671 }
672 
ML_FUNCTION(XEIn)673 ML_FUNCTION(XEIn) {
674 	ml_value_t *Attributes = Args[0];
675 	ml_value_t *Content = Args[1];
676 	xe_scope_t *Scope = (xe_scope_t *)Args[2];
677 	ml_value_t *Path = ml_map_search(Attributes, ml_integer(1));
678 	if (Path == MLNil) return ml_error("MacroError", "in macro requires path attribute");
679 	Scope = xe_scope_parse(Scope, (xe_node_t *)Path);
680 	if (ml_is_error((ml_value_t *)Scope)) return (ml_value_t *)Scope;
681 	ML_LIST_FOREACH(Content, Iter) node_expand(Iter->Value, NULL, Scope);
682 	return MLNil;
683 }
684 
ML_FUNCTIONX(XEDo)685 ML_FUNCTIONX(XEDo) {
686 	ml_value_t *Attributes = Args[0];
687 	ml_value_t *Content = Args[1];
688 	ml_stringbuffer_t Source[1] = {ML_STRINGBUFFER_INIT};
689 	ML_LIST_FOREACH(Content, Iter) {
690 		ml_value_t *Value = Iter->Value;
691 		if (ml_is(Value, MLStringT)) {
692 			ml_stringbuffer_add(Source, ml_string_value(Value), ml_string_length(Value));
693 		} else {
694 			compile_inline_node(Value, Source);
695 		}
696 	}
697 	ml_value_t *Result = MLNil;
698 	xe_stream_t Stream[1];
699 	Stream->Data = ml_stringbuffer_get(Source);
700 	//printf("Do = %s\n", (char *)Stream->Data);
701 	Stream->read = string_read;
702 	ml_parser_t *Parser = ml_parser((void *)string_read, Stream);
703 	ml_compiler_t *Compiler = ml_compiler((ml_getter_t)attribute_get, Attributes);
704 	ml_parser_source(Parser, ml_debugger_source(Caller));
705 	ml_result_state_t *State = ml_result_state_new(Caller->Context);
706 	for (;;) {
707 		ml_command_evaluate((ml_state_t *)State, Parser, Compiler);
708 		if (State->Value == MLEndOfInput) break;
709 		if (ml_is_error(State->Value)) {
710 			Result = State->Value;
711 			break;
712 		}
713 		Result = ml_deref(State->Value);
714 	}
715 	ML_RETURN(Result);
716 }
717 
ML_FUNCTIONX(XEDo2)718 ML_FUNCTIONX(XEDo2) {
719 	ml_value_t *Attributes = Args[0];
720 	ml_value_t *Content = Args[1];
721 	ml_stringbuffer_t Source[1] = {ML_STRINGBUFFER_INIT};
722 	ML_LIST_FOREACH(Content, Iter) {
723 		ml_value_t *Value = Iter->Value;
724 		if (ml_is(Value, MLStringT)) {
725 			ml_stringbuffer_add(Source, ml_string_value(Value), ml_string_length(Value));
726 		} else {
727 			compile_inline_node(Value, Source);
728 		}
729 	}
730 	xe_stream_t Stream[1];
731 	Stream->Data = ml_stringbuffer_get(Source);
732 	//printf("Do = %s\n", (char *)Stream->Data);
733 	Stream->read = string_read;
734 	ml_parser_t *Parser = ml_parser((void *)string_read, Stream);
735 	ml_compiler_t *Compiler = ml_compiler((ml_getter_t)attribute_get, Attributes);
736 	ml_parser_source(Parser, ml_debugger_source(Caller));
737 	ml_value_t *Result = MLNil;
738 	ml_result_state_t *State = ml_result_state_new(Caller->Context);
739 	for (;;) {
740 		ml_command_evaluate((ml_state_t *)State, Parser, Compiler);
741 		if (State->Value == MLEndOfInput) break;
742 		if (ml_is_error(State->Value)) {
743 			Result = State->Value;
744 			break;
745 		}
746 	}
747 	ML_RETURN(Result);
748 }
749 
file_read(xe_stream_t * Stream)750 static const char *file_read(xe_stream_t *Stream) {
751 	FILE *File = (FILE *)Stream->Data;
752 	char *Line = 0;
753 	size_t Length = 0;
754 	ssize_t Read = getline(&Line, &Length, File);
755 	if (Read < 0) {
756 		fclose(File);
757 		return 0;
758 	}
759 	return Line;
760 }
761 
ML_FUNCTION(XEInclude)762 ML_FUNCTION(XEInclude) {
763 	ml_value_t *Attributes = Args[0];
764 	ml_value_t *FileArg = ml_map_search(Attributes, ml_integer(1));
765 	if (FileArg == MLNil) return ml_error("MacroError", "include macro requires file attribute");
766 	if (!ml_is(FileArg, MLStringT)) return ml_error("MacroError", "file attribute must be a string");
767 	const char *FileName = ml_string_value(FileArg);
768 	FILE *File = fopen(FileName, "r");
769 	if (!File) return ml_error("FileError", "Error opening file %s", FileName);
770 	xe_stream_t Stream[1];
771 	Stream->Data = (void *)File;
772 	Stream->LineNo = 1;
773 	Stream->Source = FileName;
774 	Stream->read = file_read;
775 	const char *Next = file_read(Stream);
776 	ml_value_t *Contents = ml_list();
777 	for (;;) {
778 		while (Next[0] <= ' ') {
779 			if (Next[0] == 0) {
780 				Next = Stream->read(Stream);
781 				if (!Next) return Contents;
782 				++Stream->LineNo;
783 			} else {
784 				++Next;
785 			}
786 		}
787 		if (Next[0] != '<') return ml_error("ParseError", "Node must begin with <");
788 		Stream->Next = Next + 1;
789 		ml_value_t *Node = parse_node(Stream);
790 		if (ml_is_error(Node)) return Node;
791 		ml_list_put(Contents, Node);
792 		Next = Stream->Next;
793 	}
794 	return Contents;
795 }
796 
ML_FUNCTION(XEMap)797 ML_FUNCTION(XEMap) {
798 	return Args[0];
799 }
800 
ML_FUNCTION(XEList)801 ML_FUNCTION(XEList) {
802 	return Args[1];
803 }
804 
ML_FUNCTION(XEAttr)805 ML_FUNCTION(XEAttr) {
806 	ml_value_t *Attr = ml_map_search(Args[0], ml_integer(1));
807 	if (!ml_is(Attr, MLStringT)) return ml_error("TypeError", "String required, not %s", ml_typeof(Attr)->Name);
808 	xe_node_t *Node = (xe_node_t *)ml_map_search(Args[0], ml_integer(2));
809 	if (!ml_is((ml_value_t *)Node, XENodeT)) return ml_error("TypeError", "Node required, not %s", ml_typeof((ml_value_t *)Node)->Name);
810 	return ml_map_search(Node->Attributes, Attr);
811 }
812 
xe_attribute_to_string(ml_value_t * Key,ml_value_t * Value,ml_stringbuffer_t * Buffer)813 static int xe_attribute_to_string(ml_value_t *Key, ml_value_t *Value, ml_stringbuffer_t *Buffer) {
814 	ml_stringbuffer_add(Buffer, " ", 1);
815 	ml_stringbuffer_append(Buffer, Key);
816 	ml_stringbuffer_add(Buffer, "=", 1);
817 	if (ml_is(Value, XENodeT)) {
818 		ml_stringbuffer_append(Buffer, Value);
819 	} else {
820 		compile_inline_value(Value, Buffer);
821 	}
822 	return 0;
823 }
824 
825 ML_METHOD("append", MLStringBufferT, XENodeT) {
826 	ml_stringbuffer_t *Buffer = (ml_stringbuffer_t *)Args[0];
827 	xe_node_t *Node = (xe_node_t *)Args[1];
828 	ml_stringbuffer_add(Buffer, "<", 1);
829 	ml_stringbuffer_add(Buffer, ml_string_value(Node->Tag), ml_string_length(Node->Tag));
830 	if (ml_map_size(Node->Attributes)) {
831 		ml_map_foreach(Node->Attributes, Buffer, (void *)xe_attribute_to_string);
832 	}
833 	if (ml_list_length(Node->Content)) {
834 		ml_stringbuffer_add(Buffer, ":", 1);
835 		ML_LIST_FOREACH(Node->Content, Iter) {
836 			ml_stringbuffer_append(Buffer, Iter->Value);
837 		}
838 	}
839 	ml_stringbuffer_add(Buffer, ">", 1);
840 	return Args[0];
841 }
842 
ML_METHOD(MLStringT,XENodeT)843 ML_METHOD(MLStringT, XENodeT) {
844 	xe_node_t *Node = (xe_node_t *)Args[0];
845 	ml_stringbuffer_t Buffer[1] = {ML_STRINGBUFFER_INIT};
846 	ml_stringbuffer_add(Buffer, "<", 1);
847 	ml_stringbuffer_add(Buffer, ml_string_value(Node->Tag), ml_string_length(Node->Tag));
848 	if (ml_map_size(Node->Attributes)) {
849 		ml_map_foreach(Node->Attributes, Buffer, (void *)xe_attribute_to_string);
850 	}
851 	if (ml_list_length(Node->Content)) {
852 		ml_stringbuffer_add(Buffer, ":", 1);
853 		ML_LIST_FOREACH(Node->Content, Iter) {
854 			ml_stringbuffer_append(Buffer, Iter->Value);
855 		}
856 	}
857 	ml_stringbuffer_add(Buffer, ">", 1);
858 	return ml_stringbuffer_value(Buffer);
859 }
860 
861 ML_METHOD("append", MLStringBufferT, XEVarT) {
862 	ml_stringbuffer_t *Buffer = (ml_stringbuffer_t *)Args[0];
863 	xe_var_t *Var = (xe_var_t *)Args[1];
864 	ml_stringbuffer_add(Buffer, "<$", 2);
865 	ml_stringbuffer_append(Buffer, Var->Name);
866 	ml_stringbuffer_add(Buffer, ">", 1);
867 	return Args[0];
868 }
869 
ML_METHOD(MLStringT,XEVarT)870 ML_METHOD(MLStringT, XEVarT) {
871 	xe_var_t *Var = (xe_var_t *)Args[0];
872 	if (ml_is(Var->Name, MLIntegerT)) {
873 		return ml_string_format("<$%ld>", ml_integer_value_fast(Var->Name));
874 	} else {
875 		return ml_string_format("<$%s>", ml_string_value(Var->Name));
876 	}
877 }
878 
ML_FUNCTION(XEParseString)879 ML_FUNCTION(XEParseString) {
880 	ML_CHECK_ARG_COUNT(1);
881 	ML_CHECK_ARG_TYPE(0, MLStringT);
882 	xe_stream_t Stream[1];
883 	Stream->Data = (void *)ml_string_value(Args[0]);
884 	Stream->LineNo = 1;
885 	Stream->Source = "string";
886 	Stream->read = string_read;
887 	const char *Next = string_read(Stream);
888 	SKIP_WHITESPACE;
889 	if (Next[0] != '<') return ml_error("ParseError", "Node must begin with <");
890 	Stream->Next = Next + 1;
891 	return parse_node(Stream);
892 }
893 
ML_FUNCTION(XEParseFile)894 ML_FUNCTION(XEParseFile) {
895 	ML_CHECK_ARG_COUNT(1);
896 	ML_CHECK_ARG_TYPE(0, MLStringT);
897 	const char *FileName = ml_string_value(Args[0]);
898 	FILE *File = fopen(FileName, "r");
899 	if (!File) return ml_error("FileError", "Error opening file %s", FileName);
900 	xe_stream_t Stream[1];
901 	Stream->Data = (void *)File;
902 	Stream->LineNo = 1;
903 	Stream->Source = FileName;
904 	Stream->read = file_read;
905 	const char *Next = file_read(Stream);
906 	SKIP_WHITESPACE;
907 	if (Next[0] != '<') return ml_error("ParseError", "Node must begin with <");
908 	Stream->Next = Next + 1;
909 	return parse_node(Stream);
910 }
911 
ML_FUNCTION(XEExpand)912 ML_FUNCTION(XEExpand) {
913 	ML_CHECK_ARG_COUNT(1);
914 	xe_scope_t *Scope = GlobalScope;
915 	if (Count > 1) {
916 		ML_CHECK_ARG_TYPE(1, XEScopeT);
917 		Scope = (xe_scope_t *)Args[1];
918 	}
919 	return node_expand(Args[0], NULL, Scope);
920 }
921 
ML_FUNCTIONX(XENode)922 ML_FUNCTIONX(XENode) {
923 	ML_CHECKX_ARG_COUNT(3);
924 	ML_CHECKX_ARG_TYPE(0, MLStringT);
925 	ML_CHECKX_ARG_TYPE(1, MLMapT);
926 	ML_CHECKX_ARG_TYPE(2, MLListT);
927 	xe_node_t *Node = new(xe_node_t);
928 	Node->Type = XENodeT;
929 	Node->Tag = Args[0];
930 	Node->Attributes = Args[1];
931 	Node->Content = Args[2];
932 	Node->Source = ml_debugger_source(Caller);
933 	ML_RETURN(Node);
934 }
935 
ML_FUNCTIONX(XEVar)936 ML_FUNCTIONX(XEVar) {
937 	ML_CHECKX_ARG_COUNT(1);
938 	ML_CHECKX_ARG_TYPE(0, MLStringT);
939 	xe_var_t *Var = new(xe_var_t);
940 	Var->Type = XEVarT;
941 	Var->Name = Args[0];
942 	ML_RETURN(Var);
943 }
944 
ML_FUNCTION(XEEval)945 ML_FUNCTION(XEEval) {
946 	ML_CHECK_ARG_COUNT(2);
947 	ml_value_t *Content;
948 	if (Count > 2) {
949 		ML_CHECK_ARG_TYPE(2, MLListT);
950 		Content = Args[2];
951 	} else {
952 		Content = ml_list();
953 	}
954 	xe_scope_t *Scope = GlobalScope;
955 	if (Count > 3) {
956 		ML_CHECK_ARG_TYPE(1, XEScopeT);
957 		Scope = (xe_scope_t *)Args[3];
958 	}
959 	return node_eval(Args[0], Args[1], Content, Scope);
960 }
961 
ML_FUNCTION(XEAppend)962 ML_FUNCTION(XEAppend) {
963 	ML_CHECK_ARG_COUNT(2);
964 	ML_CHECK_ARG_TYPE(0, MLListT);
965 	node_append(Args[0], Args[1]);
966 	return Args[0];
967 }
968 
969 ML_METHOD("tag", XENodeT) {
970 	xe_node_t *Node = (xe_node_t *)Args[0];
971 	return Node->Tag;
972 }
973 
974 ML_METHOD("attributes", XENodeT) {
975 	xe_node_t *Node = (xe_node_t *)Args[0];
976 	return Node->Attributes;
977 }
978 
979 ML_METHOD("content", XENodeT) {
980 	xe_node_t *Node = (xe_node_t *)Args[0];
981 	return Node->Content;
982 }
983 
print(void * Data,int Count,ml_value_t ** Args)984 static ml_value_t *print(void *Data, int Count, ml_value_t **Args) {
985 	for (int I = 0; I < Count; ++I) {
986 		ml_value_t *Result = Args[I];
987 		if (!ml_is(Result, MLStringT)) {
988 			Result = ml_simple_call((ml_value_t *)MLStringT, 1, &Result);
989 			if (ml_is_error(Result)) return Result;
990 			if (!ml_is(Result, MLStringT)) return ml_error("ResultError", "string method did not return string");
991 		}
992 		fwrite(ml_string_value(Result), 1, ml_string_length(Result), stdout);
993 	}
994 	fflush(stdout);
995 	return MLNil;
996 }
997 
error(void * Data,int Count,ml_value_t ** Args)998 static ml_value_t *error(void *Data, int Count, ml_value_t **Args) {
999 	ML_CHECK_ARG_COUNT(2);
1000 	ML_CHECK_ARG_TYPE(0, MLStringT);
1001 	ML_CHECK_ARG_TYPE(1, MLStringT);
1002 	return ml_error(ml_string_value(Args[0]), "%s", ml_string_value(Args[1]));
1003 }
1004 
xe_line_read(xe_stream_t * Stream)1005 static const char *xe_line_read(xe_stream_t *Stream) {
1006 #ifdef __MINGW32__
1007 	fputs("--> ", stdout);
1008 	char *Line;
1009 	if (!ml_read_line(stdin, 0, &Line)) return NULL;
1010 #else
1011 	const char *Line = linenoise("--> ");
1012 	if (!Line) return NULL;
1013 	linenoiseHistoryAdd(Line);
1014 #endif
1015 	int Length = strlen(Line);
1016 	char *Buffer = snew(Length + 2);
1017 	memcpy(Buffer, Line, Length);
1018 	Buffer[Length] = '\n';
1019 	Buffer[Length + 1] = 0;
1020 	return Buffer;
1021 }
1022 
1023 static ml_value_t *MainArgs[1];
1024 
ml_loaded_run(ml_state_t * State,ml_value_t * Result)1025 static void ml_loaded_run(ml_state_t *State, ml_value_t *Result) {
1026 	if (ml_is_error(Result)) {
1027 		printf("Error: %s\n", ml_error_message(Result));
1028 		ml_source_t Source;
1029 		int Level = 0;
1030 		while (ml_error_source(Result, Level++, &Source)) {
1031 			printf("\t%s:%d\n", Source.Name, Source.Line);
1032 		}
1033 		exit(1);
1034 	}
1035 	Result = ml_simple_call(Result, 1, MainArgs);
1036 	if (ml_is_error(Result)) {
1037 		printf("Error: %s\n", ml_error_message(Result));
1038 		ml_source_t Source;
1039 		int Level = 0;
1040 		while (ml_error_source(Result, Level++, &Source)) {
1041 			printf("\t%s:%d\n", Source.Name, Source.Line);
1042 		}
1043 		exit(1);
1044 	}
1045 }
1046 
1047 static ml_state_t MLLoadedState[1] = {{
1048 	MLStateT, NULL, ml_loaded_run
1049 }};
1050 
main(int Argc,char ** Argv)1051 int main(int Argc, char **Argv) {
1052 	static const char *Parameters[] = {"Args", NULL};
1053 	ml_init();
1054 	ml_types_init(Globals);
1055 	ml_file_init(Globals);
1056 	ml_object_init(Globals);
1057 	ml_iterfns_init(Globals);
1058 	stringmap_insert(Globals, "print", ml_cfunction(0, print));
1059 	stringmap_insert(Globals, "error", ml_cfunction(0, error));
1060 	stringmap_insert(Globals, "parse_string", XEParseString);
1061 	stringmap_insert(Globals, "parse_file", XEParseFile);
1062 	stringmap_insert(Globals, "expand", XEExpand);
1063 	stringmap_insert(Globals, "node", XENode);
1064 	stringmap_insert(Globals, "var", XEVar);
1065 	stringmap_insert(Globals, "eval", XEEval);
1066 	stringmap_insert(Globals, "append", XEAppend);
1067 	stringmap_insert(GlobalScope->Symbols, "!function", XEFunction);
1068 	stringmap_insert(GlobalScope->Symbols, "!define", XEDefine);
1069 	stringmap_insert(GlobalScope->Symbols, "!in", XEIn);
1070 	stringmap_insert(GlobalScope->Symbols, "!do", XEDo2);
1071 	stringmap_insert(GlobalScope->Symbols, "", XEDo);
1072 	stringmap_insert(GlobalScope->Symbols, "!include", XEInclude);
1073 	stringmap_insert(GlobalScope->Symbols, "!map", XEMap);
1074 	stringmap_insert(GlobalScope->Symbols, "!list", XEList);
1075 	stringmap_insert(GlobalScope->Symbols, "@", XEAttr);
1076 	//stringmap_insert(GlobalScope->Symbols, "!for", XEFor);
1077 	//stringmap_insert(GlobalScope->Symbols, "!if", XEIf);
1078 #include "minixe_init.c"
1079 	ml_value_t *Args = ml_list();
1080 	const char *FileName = 0;
1081 	int Interactive = 0;
1082 	for (int I = 1; I < Argc; ++I) {
1083 		if (Argv[I][0] == '-') {
1084 			switch (Argv[I][1]) {
1085 			case 'i': Interactive = 1; break;
1086 			}
1087 		} else if (!FileName) {
1088 			FileName = Argv[I];
1089 		} else {
1090 			ml_list_put(Args, ml_string(Argv[I], -1));
1091 		}
1092 	}
1093 	MainArgs[0] = Args;
1094 	if (Interactive) {
1095 		xe_stream_t Stream[1];
1096 		Stream->LineNo = 1;
1097 		Stream->Source = "string";
1098 		if (FileName) {
1099 			FILE *File = fopen(FileName, "r");
1100 			if (!File) {
1101 				printf("Error: Error opening file %s", FileName);
1102 				return 1;
1103 			}
1104 			Stream->Data = File;
1105 			Stream->read = file_read;
1106 		} else {
1107 			Stream->read = xe_line_read;
1108 		}
1109 		Stream->Next = "";
1110 		for (;;) {
1111 			const char *Next = Stream->Next;
1112 			while (Next[0] <= ' ') {
1113 				if (Next[0] == 0) {
1114 					Next = Stream->read(Stream);
1115 					if (!Next) return 0;
1116 					++Stream->LineNo;
1117 				} else {
1118 					++Next;
1119 				}
1120 			}
1121 			ml_value_t *Result;
1122 			if (Next[0] != '<') {
1123 				Stream->Next = "";
1124 				Result = ml_error("ParseError", "Node must begin with <");
1125 			} else {
1126 				Stream->Next = Next + 1;
1127 				Result = parse_node(Stream);
1128 			}
1129 			if (ml_is(Result, XENodeT)) Result = node_expand(Result, NULL, GlobalScope);
1130 			if (ml_is_error(Result)) {
1131 				printf("Error: %s\n", ml_error_message(Result));
1132 				ml_source_t Source;
1133 				int Level = 0;
1134 				while (ml_error_source(Result, Level++, &Source)) {
1135 					printf("\t%s:%d\n", Source.Name, Source.Line);
1136 				}
1137 			} else {
1138 				print(NULL, 1, &Result);
1139 				puts("");
1140 			}
1141 		}
1142 	} else if (FileName) {
1143 		ml_load_file(MLLoadedState, global_get, Globals, FileName, Parameters);
1144 	} else {
1145 		ml_console(&MLRootContext, global_get, Globals, "--> ", "... ");
1146 	}
1147 	return 0;
1148 }
1149