Added MRB REPL.
Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
parent
2321865084
commit
8fe997a252
|
@ -1 +1 @@
|
|||
Subproject commit 05ebbc3a9baec28ed4acfe4b84495d272c74456a
|
||||
Subproject commit dd483b90b3f88a0684337b883d6de0c1c6df6344
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue