REPL: Add basic parser.
Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
parent
9b4660bd75
commit
a7fe04e077
|
@ -15,11 +15,16 @@
|
|||
/* Private */
|
||||
#include "app_mrb_repl.h"
|
||||
|
||||
static mrb_state *mrb;
|
||||
static mrbc_context *cxt;
|
||||
static struct mrb_parser_state *parser_state;
|
||||
/* FIXME: We use static variables here since linenoise can't be used for multiple instances. */
|
||||
|
||||
static char *prompt_str;
|
||||
static mrb_state *s_mrb_state;
|
||||
static mrbc_context *s_mrbc_cxt;
|
||||
static int s_gc_arena_idx;
|
||||
|
||||
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)
|
||||
|
||||
|
@ -30,60 +35,209 @@ static void app_mrb_repl_heap_usage(uint32_t *used, uint32_t *total) {
|
|||
*total = m_info.fordblks + m_info.uordblks;
|
||||
}
|
||||
|
||||
static bool app_mrb_repl_code_block_open(struct mrb_parser_state *state) {
|
||||
bool ret = false;
|
||||
|
||||
/* This is reference to mirb's is_code_block_open. */
|
||||
|
||||
/* HEREDOC */
|
||||
if (state->parsing_heredoc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Unterminated string */
|
||||
if (state->lex_strterm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state->nerr > 0) {
|
||||
const char unexpected_end[] = "syntax error, unexpected end of file";
|
||||
const char *message = state->error_buffer[0].message;
|
||||
|
||||
/* Compare error strings, the code block finished except unexpected EOF. */
|
||||
if (strncmp(message, unexpected_end, sizeof(unexpected_end) - 1) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp(message, "syntax error, unexpected keyword_end") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(message, "syntax error, unexpected tREGEXP_BEG") == 0) {
|
||||
return false;
|
||||
}
|
||||
return ret; /* Other errors, still need to close the block */
|
||||
}
|
||||
|
||||
switch (state->lstate) {
|
||||
case EXPR_BEG:
|
||||
case EXPR_ARG:
|
||||
ret = false;
|
||||
break;
|
||||
case EXPR_DOT:
|
||||
case EXPR_CLASS:
|
||||
case EXPR_FNAME:
|
||||
case EXPR_VALUE:
|
||||
ret = true;
|
||||
break;
|
||||
case EXPR_CMDARG:
|
||||
case EXPR_END:
|
||||
case EXPR_ENDARG:
|
||||
case EXPR_ENDFN:
|
||||
case EXPR_MID:
|
||||
case EXPR_MAX_STATE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int app_mrb_repl_init(void) {
|
||||
prompt_str = malloc(64);
|
||||
if (prompt_str == NULL) {
|
||||
int ret = 0;
|
||||
|
||||
s_prompt_str = malloc(64);
|
||||
if (s_prompt_str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mrb = mrb_open();
|
||||
cxt = mrbc_context_new(mrb);
|
||||
s_mrb_state = mrb_open();
|
||||
if (s_mrb_state == NULL) {
|
||||
ret = -1;
|
||||
goto mrb_alloc_fail;
|
||||
}
|
||||
s_mrbc_cxt = mrbc_context_new(s_mrb_state);
|
||||
if (s_mrbc_cxt == NULL) {
|
||||
ret = -1;
|
||||
goto mrbc_cxt_alloc_fail;
|
||||
}
|
||||
|
||||
mrb_show_version(mrb);
|
||||
mrb_show_copyright(mrb);
|
||||
s_mrbc_cxt->capture_errors = TRUE;
|
||||
s_mrbc_cxt->lineno = 1;
|
||||
|
||||
char mrb_code[] = "name = 'LPCXpresso55S69'\nputs \"Greetings #{name}, from MRuby #{RUBY_VERSION}.\"";
|
||||
s_gc_arena_idx = mrb_gc_arena_save(s_mrb_state);
|
||||
|
||||
parser_state = mrb_parse_string(mrb, mrb_code, cxt);
|
||||
|
||||
mrb_load_exec(mrb, parser_state, cxt);
|
||||
mrb_show_version(s_mrb_state);
|
||||
mrb_show_copyright(s_mrb_state);
|
||||
|
||||
return 0;
|
||||
|
||||
mrbc_cxt_alloc_fail:
|
||||
mrb_close(s_mrb_state);
|
||||
|
||||
mrb_alloc_fail:
|
||||
free(s_prompt_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int app_mrb_repl_deinit(void) {
|
||||
linenoiseAtExit();
|
||||
|
||||
free(prompt_str);
|
||||
free(s_prompt_str);
|
||||
|
||||
mrbc_cleanup_local_variables(mrb, cxt);
|
||||
mrbc_context_free(mrb, cxt);
|
||||
mrb_close(mrb);
|
||||
mrbc_cleanup_local_variables(s_mrb_state, s_mrbc_cxt);
|
||||
mrbc_context_free(s_mrb_state, s_mrbc_cxt);
|
||||
mrb_close(s_mrb_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_mrb_repl_exec(bool *exit) {
|
||||
char *line;
|
||||
char *line;
|
||||
uint32_t heap_used, heap_total;
|
||||
|
||||
char prompt_identifier;
|
||||
if (s_code_block_open) {
|
||||
prompt_identifier = '*';
|
||||
} else {
|
||||
prompt_identifier = '>';
|
||||
}
|
||||
|
||||
app_mrb_repl_heap_usage(&heap_used, &heap_total);
|
||||
snprintf(prompt_str, 64, "[%.02lf/%.02lfkiB](mirb)> ", APP_B_TO_KF(heap_used), APP_B_TO_KF(heap_total));
|
||||
snprintf(s_prompt_str, 64, "[%.02lf/%.02lfkiB](mirb)%c ", APP_B_TO_KF(heap_used), APP_B_TO_KF(heap_total),
|
||||
prompt_identifier);
|
||||
|
||||
line = linenoise(prompt_str);
|
||||
line = linenoise(s_prompt_str);
|
||||
|
||||
if(line == NULL) {
|
||||
if (line == NULL) {
|
||||
*exit = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strlen(line) != 0) {
|
||||
linenoiseHistoryAdd(line);
|
||||
printf("You entered: %s\n", line);
|
||||
/* Input nothing, just a return */
|
||||
if (strlen(line) == 0) {
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
linenoiseHistoryAdd(line);
|
||||
|
||||
/* First item in the block */
|
||||
if (s_ruby_code == NULL) {
|
||||
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);
|
||||
*exit = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(s_ruby_code, line);
|
||||
s_ruby_code[nts_len - 2] = '\n';
|
||||
s_ruby_code[nts_len - 1] = '\0';
|
||||
} else {
|
||||
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);
|
||||
free(s_ruby_code);
|
||||
|
||||
*exit = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s_ruby_code = alloc_buf;
|
||||
|
||||
strcat(s_ruby_code, line);
|
||||
s_ruby_code[nts_len - 2] = '\n';
|
||||
s_ruby_code[nts_len - 1] = '\0';
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
printf("%s\n", s_ruby_code);
|
||||
|
||||
struct mrb_parser_state *parser = mrb_parser_new(s_mrb_state);
|
||||
if (parser == NULL) {
|
||||
*exit = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
parser->s = s_ruby_code;
|
||||
parser->send = s_ruby_code + strlen(s_ruby_code);
|
||||
parser->lineno = s_mrbc_cxt->lineno;
|
||||
|
||||
mrb_parser_parse(parser, s_mrbc_cxt);
|
||||
|
||||
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 */
|
||||
/* FIXME: Leakage found in this code path, FIX IT!! */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mrb_parser_free(parser);
|
||||
|
||||
*exit = false;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue