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