1 #include "ml_console.h"
2 #include "ml_runtime.h"
3 #include "ml_debugger.h"
4 #include "minilang.h"
5 #include "ml_macros.h"
6 #include "ml_compiler.h"
7 #include "stringmap.h"
8 #ifndef __MINGW32__
9 #include "linenoise.h"
10 #endif
11 #include <gc.h>
12 #include <stdio.h>
13 #include <string.h>
14
15 typedef struct {
16 ml_state_t Base;
17 ml_parser_t *Parser;
18 ml_compiler_t *Compiler;
19 const char *Prompt;
20 const char *DefaultPrompt, *ContinuePrompt;
21 ml_debugger_t *Debugger;
22 } ml_console_t;
23
24 #ifdef __MINGW32__
ml_read_line(FILE * File,ssize_t Offset,char ** Result)25 static ssize_t ml_read_line(FILE *File, ssize_t Offset, char **Result) {
26 char Buffer[129];
27 if (fgets(Buffer, 129, File) == NULL) return -1;
28 int Length = strlen(Buffer);
29 if (Length == 128) {
30 ssize_t Total = ml_read_line(File, Offset + 128, Result);
31 memcpy(*Result + Offset, Buffer, 128);
32 return Total;
33 } else {
34 *Result = GC_MALLOC_ATOMIC(Offset + Length + 1);
35 strcpy(*Result + Offset, Buffer);
36 return Offset + Length;
37 }
38 }
39 #endif
40
ml_console_line_read(ml_console_t * Console)41 static const char *ml_console_line_read(ml_console_t *Console) {
42 #ifdef __MINGW32__
43 fputs(Console->Prompt, stdout);
44 char *Line;
45 if (!ml_read_line(stdin, 0, &Line)) return NULL;
46 #else
47 const char *Line = linenoise(Console->Prompt);
48 if (!Line) return NULL;
49 linenoiseHistoryAdd(Line);
50 #endif
51 int Length = strlen(Line);
52 char *Buffer = snew(Length + 2);
53 memcpy(Buffer, Line, Length);
54 Buffer[Length] = '\n';
55 Buffer[Length + 1] = 0;
56 Console->Prompt = Console->ContinuePrompt;
57 return Buffer;
58 }
59
ml_stringbuffer_print(FILE * File,const char * String,size_t Length)60 static int ml_stringbuffer_print(FILE *File, const char *String, size_t Length) {
61 fwrite(String, 1, Length, File);
62 return 0;
63 }
64
ml_console_log(void * Data,ml_value_t * Value)65 static void ml_console_log(void *Data, ml_value_t *Value) {
66 if (ml_is_error(Value)) {
67 error:
68 printf("%s: %s\n", ml_error_type(Value), ml_error_message(Value));
69 ml_source_t Source;
70 int Level = 0;
71 while (ml_error_source(Value, Level++, &Source)) {
72 printf("\t%s:%d\n", Source.Name, Source.Line);
73 }
74 } else {
75 ml_stringbuffer_t Buffer[1] = {ML_STRINGBUFFER_INIT};
76 Value = ml_stringbuffer_append(Buffer, Value);
77 if (ml_is_error(Value)) goto error;
78 ml_stringbuffer_foreach(Buffer, stdout, (void *)ml_stringbuffer_print);
79 puts("");
80 fflush(stdout);
81 }
82 }
83
ml_console_repl_run(ml_console_t * Console,ml_value_t * Result)84 static void ml_console_repl_run(ml_console_t *Console, ml_value_t *Result) {
85 if (Result == MLEndOfInput) return;
86 Console->Prompt = Console->DefaultPrompt;
87 Result = ml_deref(Result);
88 ml_console_log(NULL, Result);
89 if (ml_is_error(Result)) ml_parser_reset(Console->Parser);
90 return ml_command_evaluate((ml_state_t *)Console, Console->Parser, Console->Compiler);
91 }
92
93 typedef struct {
94 ml_console_t *Console;
95 interactive_debugger_t *Debugger;
96 } ml_console_debugger_t;
97
ml_console_debugger_get(ml_console_debugger_t * ConsoleDebugger,const char * Name)98 static ml_value_t *ml_console_debugger_get(ml_console_debugger_t *ConsoleDebugger, const char *Name) {
99 ml_value_t *Value = interactive_debugger_get(ConsoleDebugger->Debugger, Name);
100 if (Value) return Value;
101 return ml_compiler_lookup(ConsoleDebugger->Console->Compiler, Name);
102 }
103
ml_console_debug_enter(ml_console_t * Console,interactive_debugger_t * Debugger,ml_source_t Source,int Index)104 static void ml_console_debug_enter(ml_console_t *Console, interactive_debugger_t *Debugger, ml_source_t Source, int Index) {
105 ml_console_debugger_t *ConsoleDebugger = new(ml_console_debugger_t);
106 ConsoleDebugger->Console = Console;
107 ConsoleDebugger->Debugger = Debugger;
108 printf("Debug break [%d]: %s:%d\n", Index, Source.Name, Source.Line);
109 ml_console(Console->Base.Context, (void *)ml_console_debugger_get, ConsoleDebugger, "\e[34m>>>\e[0m ", "\e[34m...\e[0m ");
110 interactive_debugger_resume(Debugger);
111 }
112
ml_console_debug_exit(void * Data,interactive_debugger_t * Debugger,ml_state_t * Caller,int Index)113 static void ml_console_debug_exit(void *Data, interactive_debugger_t *Debugger, ml_state_t *Caller, int Index) {
114 ML_RETURN(MLEndOfInput);
115 }
116
ml_console(ml_context_t * Context,ml_getter_t GlobalGet,void * Globals,const char * DefaultPrompt,const char * ContinuePrompt)117 void ml_console(ml_context_t *Context, ml_getter_t GlobalGet, void *Globals, const char *DefaultPrompt, const char *ContinuePrompt) {
118 ml_console_t Console[1];
119 Console->Base.run = (void *)ml_console_repl_run;
120 Console->Base.Context = Context;
121 Console->Prompt = Console->DefaultPrompt = DefaultPrompt;
122 Console->ContinuePrompt = ContinuePrompt;
123 Console->Debugger = NULL;
124 ml_parser_t *Parser = ml_parser((void *)ml_console_line_read, Console);
125 ml_compiler_t *Compiler = ml_compiler(GlobalGet, Globals);
126 ml_compiler_define(Compiler, "debugger", interactive_debugger(
127 (void *)ml_console_debug_enter,
128 (void *)ml_console_debug_exit,
129 ml_console_log,
130 Console,
131 GlobalGet,
132 Globals
133 ));
134
135 ml_parser_source(Parser, (ml_source_t){"<console>", 1});
136 Console->Parser = Parser;
137 Console->Compiler = Compiler;
138 ml_command_evaluate((ml_state_t *)Console, Parser, Compiler);
139 }
140