Added MRB REPL.

Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
Yilin Sun 2023-03-08 21:58:41 +08:00
parent 2321865084
commit 8fe997a252
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
4 changed files with 102 additions and 36 deletions

@ -1 +1 @@
Subproject commit 05ebbc3a9baec28ed4acfe4b84495d272c74456a
Subproject commit dd483b90b3f88a0684337b883d6de0c1c6df6344

View File

@ -12,28 +12,38 @@
/* mruby */
#include "mruby.h"
#include "mruby/compile.h"
#include "mruby/error.h"
#include "mruby/internal.h"
#include "mruby/presym.h"
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/variable.h"
/* Private */
#include "app_mrb_repl.h"
typedef struct {
float used;
float total;
} app_mrb_repl_heap_usage_t;
/* FIXME: We use static variables here since linenoise can't be used for multiple instances. */
static mrb_state *s_mrb_state;
static mrbc_context *s_mrbc_cxt;
static int s_gc_arena_idx;
static int s_stack_keep = 0;
static bool s_code_block_open = false;
static char *s_prompt_str = NULL;
static char *s_ruby_code = NULL;
#define APP_B_TO_KF(x) ((float)x / 1024.0f)
static void app_mrb_repl_heap_usage(uint32_t *used, uint32_t *total) {
static void app_mrb_repl_heap_usage(app_mrb_repl_heap_usage_t *usage) {
struct mallinfo m_info = mallinfo();
*used = m_info.uordblks;
*total = m_info.fordblks + m_info.uordblks;
usage->used = (float)m_info.uordblks / 1024.0f;
usage->total = (float)(m_info.fordblks + m_info.uordblks) / 1024.0f;
}
static bool app_mrb_repl_code_block_open(struct mrb_parser_state *state) {
@ -94,6 +104,24 @@ static bool app_mrb_repl_code_block_open(struct mrb_parser_state *state) {
return ret;
}
static void app_mrb_repl_p(mrb_state *mrb, mrb_value obj, int prompt) {
mrb_value val;
val = mrb_funcall_id(mrb, obj, MRB_SYM(inspect), 0);
if (prompt) {
if (!mrb->exc) {
printf("=> ");
} else {
val = mrb_funcall_id(mrb, mrb_obj_value(mrb->exc), MRB_SYM(inspect), 0);
}
}
if (!mrb_string_p(val)) {
val = mrb_obj_as_string(mrb, obj);
}
printf("%s\n", RSTRING_PTR(val));
}
int app_mrb_repl_init(void) {
int ret = 0;
@ -121,13 +149,13 @@ int app_mrb_repl_init(void) {
mrb_show_version(s_mrb_state);
mrb_show_copyright(s_mrb_state);
time_t rawtime;
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("Time: %s", asctime(timeinfo));
printf("Time: %s\n", asctime(timeinfo));
return 0;
@ -141,6 +169,9 @@ mrb_alloc_fail:
}
int app_mrb_repl_deinit(void) {
printf("Destroying old world...\n\n");
linenoiseClearScreen();
linenoiseAtExit();
free(s_prompt_str);
@ -149,12 +180,16 @@ int app_mrb_repl_deinit(void) {
mrbc_context_free(s_mrb_state, s_mrbc_cxt);
mrb_close(s_mrb_state);
s_code_block_open = 0;
s_gc_arena_idx = 0;
s_stack_keep = 0;
return 0;
}
int app_mrb_repl_exec(bool *exit) {
char *line;
uint32_t heap_used, heap_total;
char *line;
app_mrb_repl_heap_usage_t heap_stat;
char prompt_identifier;
if (s_code_block_open) {
@ -163,8 +198,8 @@ int app_mrb_repl_exec(bool *exit) {
prompt_identifier = '>';
}
app_mrb_repl_heap_usage(&heap_used, &heap_total);
snprintf(s_prompt_str, 64, "[%.02lf/%.02lfkiB](mirb)%c ", APP_B_TO_KF(heap_used), APP_B_TO_KF(heap_total),
app_mrb_repl_heap_usage(&heap_stat);
snprintf(s_prompt_str, 64, "[%.02fkiB|%.02fkiB](mirb)(%d)%c ", heap_stat.used, heap_stat.total, s_mrbc_cxt->lineno,
prompt_identifier);
line = linenoise(s_prompt_str);
@ -176,7 +211,7 @@ int app_mrb_repl_exec(bool *exit) {
/* Input nothing, just a return */
if (strlen(line) == 0) {
free(line);
linenoiseFree(line);
return 0;
}
@ -187,7 +222,7 @@ int app_mrb_repl_exec(bool *exit) {
size_t nts_len = strlen(line) + 2; /* for an additional \n and NUL */
s_ruby_code = malloc(nts_len);
if (s_ruby_code == NULL) {
free(line);
linenoiseFree(line);
*exit = true;
return -1;
}
@ -199,7 +234,7 @@ int app_mrb_repl_exec(bool *exit) {
size_t nts_len = strlen(s_ruby_code) + strlen(line) + 2; /* Same */
void *alloc_buf = realloc(s_ruby_code, nts_len);
if (alloc_buf == NULL) {
free(line);
linenoiseFree(line);
free(s_ruby_code);
*exit = true;
@ -213,7 +248,7 @@ int app_mrb_repl_exec(bool *exit) {
s_ruby_code[nts_len - 1] = '\0';
}
free(line);
linenoiseFree(line);
struct mrb_parser_state *parser = mrb_parser_new(s_mrb_state);
if (parser == NULL) {
@ -230,27 +265,57 @@ int app_mrb_repl_exec(bool *exit) {
s_code_block_open = app_mrb_repl_code_block_open(parser);
if (s_code_block_open) {
/* TODO: Nothing, continue processing */
} else {
/* TODO: Compile block and feed to VM */
/* TODO: Adjust CXT->lineno */
if(parser->nerr) {
printf("Error at line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
}
if(parser->nwarn) {
printf("Warn at line %d: %s\n", parser->warn_buffer[0].lineno, parser->warn_buffer[0].message);
}
mrb_gc_arena_restore(s_mrb_state, s_gc_arena_idx);
/* We are done with current block, free buffer */
free(s_ruby_code);
s_ruby_code = NULL;
goto next_iter;
}
if (parser->nwarn) {
printf("Warn at line %d: %s\n", parser->warn_buffer[0].lineno, parser->warn_buffer[0].message);
}
if (parser->nerr) {
printf("Error at line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
goto block_has_error;
}
/* Compile byte code */
struct RProc *proc = mrb_generate_code(s_mrb_state, parser);
if (proc == NULL) {
goto block_has_error;
}
/* Mysterious ENV */
if (s_mrb_state->c->cibase->u.env) {
struct REnv *e = mrb_vm_ci_env(s_mrb_state->c->cibase);
if (e && MRB_ENV_LEN(e) < proc->body.irep->nlocals) {
MRB_ENV_SET_LEN(e, proc->body.irep->nlocals);
}
}
/* Run */
mrb_value result = mrb_vm_run(s_mrb_state, proc, mrb_top_self(s_mrb_state), s_stack_keep);
s_stack_keep = proc->body.irep->nlocals;
/* Exception occurred? */
if (s_mrb_state->exc) {
app_mrb_repl_p(s_mrb_state, mrb_obj_value(s_mrb_state->exc), 0);
s_mrb_state->exc = 0;
} else {
if (!mrb_respond_to(s_mrb_state, result, MRB_SYM(inspect))) {
result = mrb_any_to_s(s_mrb_state, result);
}
app_mrb_repl_p(s_mrb_state, result, 1);
}
block_has_error:
mrb_gc_arena_restore(s_mrb_state, s_gc_arena_idx);
/* We are done with current block, free buffer */
free(s_ruby_code);
s_ruby_code = NULL;
next_iter:
mrb_parser_free(parser);
s_mrbc_cxt->lineno++;
*exit = false;
return 0;

View File

@ -35,6 +35,7 @@
#define APP_STDIO_UART_EVENT_ERROR (1 << 2U)
#define APP_TIME_RTC_INIT_RETRIES 32
#define APP_TIME_RTC_OFFSET_EPOCH (1612137600ULL) /* Magic number, don't ask. */
static SemaphoreHandle_t s_malloc_lock = NULL;
@ -271,7 +272,7 @@ int _fstat(int file, struct stat *st) {
}
int _gettimeofday(struct timeval *ptimeval, void *ptimezone) {
ptimeval->tv_sec = RTC_GetSecondsTimerCount(RTC);
ptimeval->tv_sec = APP_TIME_RTC_OFFSET_EPOCH + RTC_GetSecondsTimerCount(RTC);
ptimeval->tv_usec = 0ULL;
return 0;

View File

@ -29,7 +29,7 @@ int main(void) {
goto dead_loop;
}
if (xTaskCreate(app_mrb_runtime_task, "MRB_RT", 3072, NULL, 2, NULL) != pdPASS) {
if (xTaskCreate(app_mrb_runtime_task, "MRB_RT", 6144, NULL, 2, NULL) != pdPASS) {
goto dead_loop;
}