mruby mbed

Dependencies:   EthernetInterface SDFileSystem mbed-rtos mbed-src mruby-mbed

Committer:
mzta
Date:
Wed Mar 25 18:25:34 2015 +0000
Revision:
0:4bb480aaa402
mruby_mbed_web initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mzta 0:4bb480aaa402 1 /*
mzta 0:4bb480aaa402 2 ** mirb - Embeddable Interactive Ruby Shell
mzta 0:4bb480aaa402 3 **
mzta 0:4bb480aaa402 4 ** This program takes code from the user in
mzta 0:4bb480aaa402 5 ** an interactive way and executes it
mzta 0:4bb480aaa402 6 ** immediately. It's a REPL...
mzta 0:4bb480aaa402 7 */
mzta 0:4bb480aaa402 8
mzta 0:4bb480aaa402 9 #include "mbed.h"
mzta 0:4bb480aaa402 10
mzta 0:4bb480aaa402 11 extern Serial pc;
mzta 0:4bb480aaa402 12
mzta 0:4bb480aaa402 13 #include <stdlib.h>
mzta 0:4bb480aaa402 14 #include <string.h>
mzta 0:4bb480aaa402 15 #include <stdio.h>
mzta 0:4bb480aaa402 16 #include <ctype.h>
mzta 0:4bb480aaa402 17
mzta 0:4bb480aaa402 18 #ifdef ENABLE_READLINE
mzta 0:4bb480aaa402 19 #include <readline/readline.h>
mzta 0:4bb480aaa402 20 #include <readline/history.h>
mzta 0:4bb480aaa402 21 #define MIRB_ADD_HISTORY(line) add_history(line)
mzta 0:4bb480aaa402 22 #define MIRB_READLINE(ch) readline(ch)
mzta 0:4bb480aaa402 23 #define MIRB_WRITE_HISTORY(path) write_history(path)
mzta 0:4bb480aaa402 24 #define MIRB_READ_HISTORY(path) read_history(path)
mzta 0:4bb480aaa402 25 #define MIRB_USING_HISTORY() using_history()
mzta 0:4bb480aaa402 26 #elif defined(ENABLE_LINENOISE)
mzta 0:4bb480aaa402 27 #define ENABLE_READLINE
mzta 0:4bb480aaa402 28 #include <linenoise.h>
mzta 0:4bb480aaa402 29 #define MIRB_ADD_HISTORY(line) linenoiseHistoryAdd(line)
mzta 0:4bb480aaa402 30 #define MIRB_READLINE(ch) linenoise(ch)
mzta 0:4bb480aaa402 31 #define MIRB_WRITE_HISTORY(path) linenoiseHistorySave(path)
mzta 0:4bb480aaa402 32 #define MIRB_READ_HISTORY(path) linenoiseHistoryLoad(history_path)
mzta 0:4bb480aaa402 33 #define MIRB_USING_HISTORY()
mzta 0:4bb480aaa402 34 #endif
mzta 0:4bb480aaa402 35
mzta 0:4bb480aaa402 36 #include "mruby.h"
mzta 0:4bb480aaa402 37 #include "mruby/array.h"
mzta 0:4bb480aaa402 38 #include "mruby/proc.h"
mzta 0:4bb480aaa402 39 #include "mruby/compile.h"
mzta 0:4bb480aaa402 40 #include "mruby/string.h"
mzta 0:4bb480aaa402 41
mzta 0:4bb480aaa402 42 #ifdef ENABLE_READLINE
mzta 0:4bb480aaa402 43
mzta 0:4bb480aaa402 44 static const char history_file_name[] = ".mirb_history";
mzta 0:4bb480aaa402 45
mzta 0:4bb480aaa402 46 static char *
mzta 0:4bb480aaa402 47 get_history_path(mrb_state *mrb)
mzta 0:4bb480aaa402 48 {
mzta 0:4bb480aaa402 49 char *path = NULL;
mzta 0:4bb480aaa402 50 const char *home = getenv("HOME");
mzta 0:4bb480aaa402 51
mzta 0:4bb480aaa402 52 #ifdef _WIN32
mzta 0:4bb480aaa402 53 if (home != NULL) {
mzta 0:4bb480aaa402 54 home = getenv("USERPROFILE");
mzta 0:4bb480aaa402 55 }
mzta 0:4bb480aaa402 56 #endif
mzta 0:4bb480aaa402 57
mzta 0:4bb480aaa402 58 if (home != NULL) {
mzta 0:4bb480aaa402 59 int len = snprintf(NULL, 0, "%s/%s", home, history_file_name);
mzta 0:4bb480aaa402 60 if (len >= 0) {
mzta 0:4bb480aaa402 61 size_t size = len + 1;
mzta 0:4bb480aaa402 62 path = (char *)mrb_malloc_simple(mrb, size);
mzta 0:4bb480aaa402 63 if (path != NULL) {
mzta 0:4bb480aaa402 64 int n = snprintf(path, size, "%s/%s", home, history_file_name);
mzta 0:4bb480aaa402 65 if (n != len) {
mzta 0:4bb480aaa402 66 mrb_free(mrb, path);
mzta 0:4bb480aaa402 67 path = NULL;
mzta 0:4bb480aaa402 68 }
mzta 0:4bb480aaa402 69 }
mzta 0:4bb480aaa402 70 }
mzta 0:4bb480aaa402 71 }
mzta 0:4bb480aaa402 72
mzta 0:4bb480aaa402 73 return path;
mzta 0:4bb480aaa402 74 }
mzta 0:4bb480aaa402 75
mzta 0:4bb480aaa402 76 #endif
mzta 0:4bb480aaa402 77
mzta 0:4bb480aaa402 78 static void
mzta 0:4bb480aaa402 79 p(mrb_state *mrb, mrb_value obj, int prompt)
mzta 0:4bb480aaa402 80 {
mzta 0:4bb480aaa402 81 obj = mrb_funcall(mrb, obj, "inspect", 0);
mzta 0:4bb480aaa402 82 if (prompt) {
mzta 0:4bb480aaa402 83 if (!mrb->exc) {
mzta 0:4bb480aaa402 84 pc.printf(" => ");
mzta 0:4bb480aaa402 85 }
mzta 0:4bb480aaa402 86 else {
mzta 0:4bb480aaa402 87 obj = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
mzta 0:4bb480aaa402 88 }
mzta 0:4bb480aaa402 89 }
mzta 0:4bb480aaa402 90 fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout);
mzta 0:4bb480aaa402 91 putc('\n', stdout);
mzta 0:4bb480aaa402 92 }
mzta 0:4bb480aaa402 93
mzta 0:4bb480aaa402 94 /* Guess if the user might want to enter more
mzta 0:4bb480aaa402 95 * or if he wants an evaluation of his code now */
mzta 0:4bb480aaa402 96 static mrb_bool
mzta 0:4bb480aaa402 97 is_code_block_open(struct mrb_parser_state *parser)
mzta 0:4bb480aaa402 98 {
mzta 0:4bb480aaa402 99 mrb_bool code_block_open = FALSE;
mzta 0:4bb480aaa402 100
mzta 0:4bb480aaa402 101 /* check for heredoc */
mzta 0:4bb480aaa402 102 if (parser->parsing_heredoc != NULL) return TRUE;
mzta 0:4bb480aaa402 103 if (parser->heredoc_end_now) {
mzta 0:4bb480aaa402 104 parser->heredoc_end_now = FALSE;
mzta 0:4bb480aaa402 105 return FALSE;
mzta 0:4bb480aaa402 106 }
mzta 0:4bb480aaa402 107
mzta 0:4bb480aaa402 108 /* check for unterminated string */
mzta 0:4bb480aaa402 109 if (parser->lex_strterm) return TRUE;
mzta 0:4bb480aaa402 110
mzta 0:4bb480aaa402 111 /* check if parser error are available */
mzta 0:4bb480aaa402 112 if (0 < parser->nerr) {
mzta 0:4bb480aaa402 113 const char unexpected_end[] = "syntax error, unexpected $end";
mzta 0:4bb480aaa402 114 const char *message = parser->error_buffer[0].message;
mzta 0:4bb480aaa402 115
mzta 0:4bb480aaa402 116 /* a parser error occur, we have to check if */
mzta 0:4bb480aaa402 117 /* we need to read one more line or if there is */
mzta 0:4bb480aaa402 118 /* a different issue which we have to show to */
mzta 0:4bb480aaa402 119 /* the user */
mzta 0:4bb480aaa402 120
mzta 0:4bb480aaa402 121 if (strncmp(message, unexpected_end, sizeof(unexpected_end) - 1) == 0) {
mzta 0:4bb480aaa402 122 code_block_open = TRUE;
mzta 0:4bb480aaa402 123 }
mzta 0:4bb480aaa402 124 else if (strcmp(message, "syntax error, unexpected keyword_end") == 0) {
mzta 0:4bb480aaa402 125 code_block_open = FALSE;
mzta 0:4bb480aaa402 126 }
mzta 0:4bb480aaa402 127 else if (strcmp(message, "syntax error, unexpected tREGEXP_BEG") == 0) {
mzta 0:4bb480aaa402 128 code_block_open = FALSE;
mzta 0:4bb480aaa402 129 }
mzta 0:4bb480aaa402 130 return code_block_open;
mzta 0:4bb480aaa402 131 }
mzta 0:4bb480aaa402 132
mzta 0:4bb480aaa402 133 switch (parser->lstate) {
mzta 0:4bb480aaa402 134
mzta 0:4bb480aaa402 135 /* all states which need more code */
mzta 0:4bb480aaa402 136
mzta 0:4bb480aaa402 137 case EXPR_BEG:
mzta 0:4bb480aaa402 138 /* beginning of a statement, */
mzta 0:4bb480aaa402 139 /* that means previous line ended */
mzta 0:4bb480aaa402 140 code_block_open = FALSE;
mzta 0:4bb480aaa402 141 break;
mzta 0:4bb480aaa402 142 case EXPR_DOT:
mzta 0:4bb480aaa402 143 /* a message dot was the last token, */
mzta 0:4bb480aaa402 144 /* there has to come more */
mzta 0:4bb480aaa402 145 code_block_open = TRUE;
mzta 0:4bb480aaa402 146 break;
mzta 0:4bb480aaa402 147 case EXPR_CLASS:
mzta 0:4bb480aaa402 148 /* a class keyword is not enough! */
mzta 0:4bb480aaa402 149 /* we need also a name of the class */
mzta 0:4bb480aaa402 150 code_block_open = TRUE;
mzta 0:4bb480aaa402 151 break;
mzta 0:4bb480aaa402 152 case EXPR_FNAME:
mzta 0:4bb480aaa402 153 /* a method name is necessary */
mzta 0:4bb480aaa402 154 code_block_open = TRUE;
mzta 0:4bb480aaa402 155 break;
mzta 0:4bb480aaa402 156 case EXPR_VALUE:
mzta 0:4bb480aaa402 157 /* if, elsif, etc. without condition */
mzta 0:4bb480aaa402 158 code_block_open = TRUE;
mzta 0:4bb480aaa402 159 break;
mzta 0:4bb480aaa402 160
mzta 0:4bb480aaa402 161 /* now all the states which are closed */
mzta 0:4bb480aaa402 162
mzta 0:4bb480aaa402 163 case EXPR_ARG:
mzta 0:4bb480aaa402 164 /* an argument is the last token */
mzta 0:4bb480aaa402 165 code_block_open = FALSE;
mzta 0:4bb480aaa402 166 break;
mzta 0:4bb480aaa402 167
mzta 0:4bb480aaa402 168 /* all states which are unsure */
mzta 0:4bb480aaa402 169
mzta 0:4bb480aaa402 170 case EXPR_CMDARG:
mzta 0:4bb480aaa402 171 break;
mzta 0:4bb480aaa402 172 case EXPR_END:
mzta 0:4bb480aaa402 173 /* an expression was ended */
mzta 0:4bb480aaa402 174 break;
mzta 0:4bb480aaa402 175 case EXPR_ENDARG:
mzta 0:4bb480aaa402 176 /* closing parenthese */
mzta 0:4bb480aaa402 177 break;
mzta 0:4bb480aaa402 178 case EXPR_ENDFN:
mzta 0:4bb480aaa402 179 /* definition end */
mzta 0:4bb480aaa402 180 break;
mzta 0:4bb480aaa402 181 case EXPR_MID:
mzta 0:4bb480aaa402 182 /* jump keyword like break, return, ... */
mzta 0:4bb480aaa402 183 break;
mzta 0:4bb480aaa402 184 case EXPR_MAX_STATE:
mzta 0:4bb480aaa402 185 /* don't know what to do with this token */
mzta 0:4bb480aaa402 186 break;
mzta 0:4bb480aaa402 187 default:
mzta 0:4bb480aaa402 188 /* this state is unexpected! */
mzta 0:4bb480aaa402 189 break;
mzta 0:4bb480aaa402 190 }
mzta 0:4bb480aaa402 191
mzta 0:4bb480aaa402 192 return code_block_open;
mzta 0:4bb480aaa402 193 }
mzta 0:4bb480aaa402 194
mzta 0:4bb480aaa402 195
mzta 0:4bb480aaa402 196 #if defined(__cplusplus)
mzta 0:4bb480aaa402 197 extern "C" {
mzta 0:4bb480aaa402 198 #endif
mzta 0:4bb480aaa402 199 void mrb_show_version(mrb_state *);
mzta 0:4bb480aaa402 200 void mrb_show_copyright(mrb_state *);
mzta 0:4bb480aaa402 201 #if defined(__cplusplus)
mzta 0:4bb480aaa402 202 }
mzta 0:4bb480aaa402 203 #endif
mzta 0:4bb480aaa402 204
mzta 0:4bb480aaa402 205 struct _args {
mzta 0:4bb480aaa402 206 mrb_bool verbose : 1;
mzta 0:4bb480aaa402 207 int argc;
mzta 0:4bb480aaa402 208 char** argv;
mzta 0:4bb480aaa402 209 };
mzta 0:4bb480aaa402 210
mzta 0:4bb480aaa402 211 static void
mzta 0:4bb480aaa402 212 usage(const char *name)
mzta 0:4bb480aaa402 213 {
mzta 0:4bb480aaa402 214 static const char *const usage_msg[] = {
mzta 0:4bb480aaa402 215 "switches:",
mzta 0:4bb480aaa402 216 "-v print version number, then run in verbose mode",
mzta 0:4bb480aaa402 217 "--verbose run in verbose mode",
mzta 0:4bb480aaa402 218 "--version print the version",
mzta 0:4bb480aaa402 219 "--copyright print the copyright",
mzta 0:4bb480aaa402 220 NULL
mzta 0:4bb480aaa402 221 };
mzta 0:4bb480aaa402 222 const char *const *p = usage_msg;
mzta 0:4bb480aaa402 223
mzta 0:4bb480aaa402 224 pc.printf("Usage: %s [switches]\n", name);
mzta 0:4bb480aaa402 225 while (*p)
mzta 0:4bb480aaa402 226 pc.printf(" %s\n", *p++);
mzta 0:4bb480aaa402 227 }
mzta 0:4bb480aaa402 228
mzta 0:4bb480aaa402 229 static int
mzta 0:4bb480aaa402 230 parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
mzta 0:4bb480aaa402 231 {
mzta 0:4bb480aaa402 232 static const struct _args args_zero = { 0 };
mzta 0:4bb480aaa402 233
mzta 0:4bb480aaa402 234 *args = args_zero;
mzta 0:4bb480aaa402 235
mzta 0:4bb480aaa402 236 for (argc--,argv++; argc > 0; argc--,argv++) {
mzta 0:4bb480aaa402 237 char *item;
mzta 0:4bb480aaa402 238 if (argv[0][0] != '-') break;
mzta 0:4bb480aaa402 239
mzta 0:4bb480aaa402 240 item = argv[0] + 1;
mzta 0:4bb480aaa402 241 switch (*item++) {
mzta 0:4bb480aaa402 242 case 'v':
mzta 0:4bb480aaa402 243 if (!args->verbose) mrb_show_version(mrb);
mzta 0:4bb480aaa402 244 args->verbose = TRUE;
mzta 0:4bb480aaa402 245 break;
mzta 0:4bb480aaa402 246 case '-':
mzta 0:4bb480aaa402 247 if (strcmp((*argv) + 2, "version") == 0) {
mzta 0:4bb480aaa402 248 mrb_show_version(mrb);
mzta 0:4bb480aaa402 249 exit(EXIT_SUCCESS);
mzta 0:4bb480aaa402 250 }
mzta 0:4bb480aaa402 251 else if (strcmp((*argv) + 2, "verbose") == 0) {
mzta 0:4bb480aaa402 252 args->verbose = TRUE;
mzta 0:4bb480aaa402 253 break;
mzta 0:4bb480aaa402 254 }
mzta 0:4bb480aaa402 255 else if (strcmp((*argv) + 2, "copyright") == 0) {
mzta 0:4bb480aaa402 256 mrb_show_copyright(mrb);
mzta 0:4bb480aaa402 257 exit(EXIT_SUCCESS);
mzta 0:4bb480aaa402 258 }
mzta 0:4bb480aaa402 259 default:
mzta 0:4bb480aaa402 260 return EXIT_FAILURE;
mzta 0:4bb480aaa402 261 }
mzta 0:4bb480aaa402 262 }
mzta 0:4bb480aaa402 263 return EXIT_SUCCESS;
mzta 0:4bb480aaa402 264 }
mzta 0:4bb480aaa402 265
mzta 0:4bb480aaa402 266 static void
mzta 0:4bb480aaa402 267 cleanup(mrb_state *mrb, struct _args *args)
mzta 0:4bb480aaa402 268 {
mzta 0:4bb480aaa402 269 mrb_close(mrb);
mzta 0:4bb480aaa402 270 }
mzta 0:4bb480aaa402 271
mzta 0:4bb480aaa402 272 /* Print a short remark for the user */
mzta 0:4bb480aaa402 273 static void
mzta 0:4bb480aaa402 274 print_hint(void)
mzta 0:4bb480aaa402 275 {
mzta 0:4bb480aaa402 276 pc.printf("mirb - Embeddable Interactive Ruby Shell\n\n");
mzta 0:4bb480aaa402 277 }
mzta 0:4bb480aaa402 278
mzta 0:4bb480aaa402 279 #ifndef ENABLE_READLINE
mzta 0:4bb480aaa402 280 /* Print the command line prompt of the REPL */
mzta 0:4bb480aaa402 281 static void
mzta 0:4bb480aaa402 282 print_cmdline(int code_block_open)
mzta 0:4bb480aaa402 283 {
mzta 0:4bb480aaa402 284 if (code_block_open) {
mzta 0:4bb480aaa402 285 pc.printf("* ");
mzta 0:4bb480aaa402 286 }
mzta 0:4bb480aaa402 287 else {
mzta 0:4bb480aaa402 288 pc.printf("> ");
mzta 0:4bb480aaa402 289 }
mzta 0:4bb480aaa402 290 }
mzta 0:4bb480aaa402 291 #endif
mzta 0:4bb480aaa402 292
mzta 0:4bb480aaa402 293 #if defined(__cplusplus)
mzta 0:4bb480aaa402 294 extern "C" {
mzta 0:4bb480aaa402 295 #endif
mzta 0:4bb480aaa402 296 void mrb_codedump_all(mrb_state*, struct RProc*);
mzta 0:4bb480aaa402 297 #if defined(__cplusplus)
mzta 0:4bb480aaa402 298 }
mzta 0:4bb480aaa402 299 #endif
mzta 0:4bb480aaa402 300
mzta 0:4bb480aaa402 301 static int
mzta 0:4bb480aaa402 302 check_keyword(const char *buf, const char *word)
mzta 0:4bb480aaa402 303 {
mzta 0:4bb480aaa402 304 const char *p = buf;
mzta 0:4bb480aaa402 305 size_t len = strlen(word);
mzta 0:4bb480aaa402 306
mzta 0:4bb480aaa402 307 /* skip preceding spaces */
mzta 0:4bb480aaa402 308 while (*p && isspace((unsigned char)*p)) {
mzta 0:4bb480aaa402 309 p++;
mzta 0:4bb480aaa402 310 }
mzta 0:4bb480aaa402 311 /* check keyword */
mzta 0:4bb480aaa402 312 if (strncmp(p, word, len) != 0) {
mzta 0:4bb480aaa402 313 return 0;
mzta 0:4bb480aaa402 314 }
mzta 0:4bb480aaa402 315 p += len;
mzta 0:4bb480aaa402 316 /* skip trailing spaces */
mzta 0:4bb480aaa402 317 while (*p) {
mzta 0:4bb480aaa402 318 if (!isspace((unsigned char)*p)) return 0;
mzta 0:4bb480aaa402 319 p++;
mzta 0:4bb480aaa402 320 }
mzta 0:4bb480aaa402 321 return 1;
mzta 0:4bb480aaa402 322 }
mzta 0:4bb480aaa402 323
mzta 0:4bb480aaa402 324 int
mzta 0:4bb480aaa402 325 cmd_mirb(int argc, char **argv)
mzta 0:4bb480aaa402 326 {
mzta 0:4bb480aaa402 327 char ruby_code[1024] = { 0 };
mzta 0:4bb480aaa402 328 char last_code_line[1024] = { 0 };
mzta 0:4bb480aaa402 329 #ifndef ENABLE_READLINE
mzta 0:4bb480aaa402 330 int last_char;
mzta 0:4bb480aaa402 331 int char_index;
mzta 0:4bb480aaa402 332 #else
mzta 0:4bb480aaa402 333 char *history_path;
mzta 0:4bb480aaa402 334 #endif
mzta 0:4bb480aaa402 335 mrbc_context *cxt;
mzta 0:4bb480aaa402 336 struct mrb_parser_state *parser;
mzta 0:4bb480aaa402 337 mrb_state *mrb;
mzta 0:4bb480aaa402 338 mrb_value result;
mzta 0:4bb480aaa402 339 struct _args args;
mzta 0:4bb480aaa402 340 int n;
mzta 0:4bb480aaa402 341 mrb_bool code_block_open = FALSE;
mzta 0:4bb480aaa402 342 int ai;
mzta 0:4bb480aaa402 343 unsigned int stack_keep = 0;
mzta 0:4bb480aaa402 344
mzta 0:4bb480aaa402 345 /* new interpreter instance */
mzta 0:4bb480aaa402 346 mrb = mrb_open();
mzta 0:4bb480aaa402 347 if (mrb == NULL) {
mzta 0:4bb480aaa402 348 pc.printf("Invalid mrb interpreter, exiting mirb\n");
mzta 0:4bb480aaa402 349 return EXIT_FAILURE;
mzta 0:4bb480aaa402 350 }
mzta 0:4bb480aaa402 351 mrb_define_global_const(mrb, "ARGV", mrb_ary_new_capa(mrb, 0));
mzta 0:4bb480aaa402 352
mzta 0:4bb480aaa402 353 n = parse_args(mrb, argc, argv, &args);
mzta 0:4bb480aaa402 354 if (n == EXIT_FAILURE) {
mzta 0:4bb480aaa402 355 cleanup(mrb, &args);
mzta 0:4bb480aaa402 356 usage(argv[0]);
mzta 0:4bb480aaa402 357 return n;
mzta 0:4bb480aaa402 358 }
mzta 0:4bb480aaa402 359
mzta 0:4bb480aaa402 360 #ifdef ENABLE_READLINE
mzta 0:4bb480aaa402 361 history_path = get_history_path(mrb);
mzta 0:4bb480aaa402 362 if (history_path == NULL) {
mzta 0:4bb480aaa402 363 pc.printf("failed to get history path\n");
mzta 0:4bb480aaa402 364 mrb_close(mrb);
mzta 0:4bb480aaa402 365 return EXIT_FAILURE;
mzta 0:4bb480aaa402 366 }
mzta 0:4bb480aaa402 367
mzta 0:4bb480aaa402 368 MIRB_USING_HISTORY();
mzta 0:4bb480aaa402 369 MIRB_READ_HISTORY(history_path);
mzta 0:4bb480aaa402 370 #endif
mzta 0:4bb480aaa402 371
mzta 0:4bb480aaa402 372 print_hint();
mzta 0:4bb480aaa402 373
mzta 0:4bb480aaa402 374 cxt = mrbc_context_new(mrb);
mzta 0:4bb480aaa402 375 cxt->capture_errors = TRUE;
mzta 0:4bb480aaa402 376 cxt->lineno = 1;
mzta 0:4bb480aaa402 377 mrbc_filename(mrb, cxt, "(mirb)");
mzta 0:4bb480aaa402 378 if (args.verbose) cxt->dump_result = TRUE;
mzta 0:4bb480aaa402 379
mzta 0:4bb480aaa402 380 ai = mrb_gc_arena_save(mrb);
mzta 0:4bb480aaa402 381
mzta 0:4bb480aaa402 382 while (TRUE) {
mzta 0:4bb480aaa402 383 #ifndef ENABLE_READLINE
mzta 0:4bb480aaa402 384 print_cmdline(code_block_open);
mzta 0:4bb480aaa402 385
mzta 0:4bb480aaa402 386 char_index = 0;
mzta 0:4bb480aaa402 387 while ((last_char = pc.getc()) != '\n') {
mzta 0:4bb480aaa402 388 pc.printf("%c", last_char);
mzta 0:4bb480aaa402 389 if (last_char == EOF) break;
mzta 0:4bb480aaa402 390 if (char_index > sizeof(last_code_line)-2) {
mzta 0:4bb480aaa402 391 pc.printf("input string too long\n");
mzta 0:4bb480aaa402 392 continue;
mzta 0:4bb480aaa402 393 }
mzta 0:4bb480aaa402 394 if (last_char == '\x08') {
mzta 0:4bb480aaa402 395 if (char_index > 0) char_index--;
mzta 0:4bb480aaa402 396 continue;
mzta 0:4bb480aaa402 397 } else {
mzta 0:4bb480aaa402 398 last_code_line[char_index++] = last_char;
mzta 0:4bb480aaa402 399 }
mzta 0:4bb480aaa402 400 }
mzta 0:4bb480aaa402 401 pc.printf("\n");
mzta 0:4bb480aaa402 402
mzta 0:4bb480aaa402 403 if (last_char == EOF) {
mzta 0:4bb480aaa402 404 pc.printf("\n");
mzta 0:4bb480aaa402 405 break;
mzta 0:4bb480aaa402 406 }
mzta 0:4bb480aaa402 407
mzta 0:4bb480aaa402 408 last_code_line[char_index++] = '\n';
mzta 0:4bb480aaa402 409 last_code_line[char_index] = '\0';
mzta 0:4bb480aaa402 410 #else
mzta 0:4bb480aaa402 411 char* line = MIRB_READLINE(code_block_open ? "* " : "> ");
mzta 0:4bb480aaa402 412 if (line == NULL) {
mzta 0:4bb480aaa402 413 printf("\n");
mzta 0:4bb480aaa402 414 break;
mzta 0:4bb480aaa402 415 }
mzta 0:4bb480aaa402 416 if (strlen(line) > sizeof(last_code_line)-2) {
mzta 0:4bb480aaa402 417 pc.printf("input string too long\n");
mzta 0:4bb480aaa402 418 continue;
mzta 0:4bb480aaa402 419 }
mzta 0:4bb480aaa402 420 strcpy(last_code_line, line);
mzta 0:4bb480aaa402 421 strcat(last_code_line, "\n");
mzta 0:4bb480aaa402 422 MIRB_ADD_HISTORY(line);
mzta 0:4bb480aaa402 423 free(line);
mzta 0:4bb480aaa402 424 #endif
mzta 0:4bb480aaa402 425
mzta 0:4bb480aaa402 426 if (code_block_open) {
mzta 0:4bb480aaa402 427 if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) {
mzta 0:4bb480aaa402 428 pc.printf("concatenated input string too long\n");
mzta 0:4bb480aaa402 429 continue;
mzta 0:4bb480aaa402 430 }
mzta 0:4bb480aaa402 431 strcat(ruby_code, last_code_line);
mzta 0:4bb480aaa402 432 }
mzta 0:4bb480aaa402 433 else {
mzta 0:4bb480aaa402 434 if (check_keyword(last_code_line, "quit") || check_keyword(last_code_line, "exit")) {
mzta 0:4bb480aaa402 435 break;
mzta 0:4bb480aaa402 436 }
mzta 0:4bb480aaa402 437 strcpy(ruby_code, last_code_line);
mzta 0:4bb480aaa402 438 }
mzta 0:4bb480aaa402 439
mzta 0:4bb480aaa402 440 /* parse code */
mzta 0:4bb480aaa402 441 parser = mrb_parser_new(mrb);
mzta 0:4bb480aaa402 442 if (parser == NULL) {
mzta 0:4bb480aaa402 443 pc.printf("create parser state error\n");
mzta 0:4bb480aaa402 444 break;
mzta 0:4bb480aaa402 445 }
mzta 0:4bb480aaa402 446 parser->s = ruby_code;
mzta 0:4bb480aaa402 447 parser->send = ruby_code + strlen(ruby_code);
mzta 0:4bb480aaa402 448 parser->lineno = cxt->lineno;
mzta 0:4bb480aaa402 449 mrb_parser_parse(parser, cxt);
mzta 0:4bb480aaa402 450 code_block_open = is_code_block_open(parser);
mzta 0:4bb480aaa402 451
mzta 0:4bb480aaa402 452 if (code_block_open) {
mzta 0:4bb480aaa402 453 /* no evaluation of code */
mzta 0:4bb480aaa402 454 }
mzta 0:4bb480aaa402 455 else {
mzta 0:4bb480aaa402 456 if (0 < parser->nerr) {
mzta 0:4bb480aaa402 457 /* syntax error */
mzta 0:4bb480aaa402 458 pc.printf("line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
mzta 0:4bb480aaa402 459 }
mzta 0:4bb480aaa402 460 else {
mzta 0:4bb480aaa402 461 /* generate bytecode */
mzta 0:4bb480aaa402 462 struct RProc *proc = mrb_generate_code(mrb, parser);
mzta 0:4bb480aaa402 463 if (proc == NULL) {
mzta 0:4bb480aaa402 464 pc.printf("codegen error\n");
mzta 0:4bb480aaa402 465 mrb_parser_free(parser);
mzta 0:4bb480aaa402 466 break;
mzta 0:4bb480aaa402 467 }
mzta 0:4bb480aaa402 468
mzta 0:4bb480aaa402 469 if (args.verbose) {
mzta 0:4bb480aaa402 470 mrb_codedump_all(mrb, proc);
mzta 0:4bb480aaa402 471 }
mzta 0:4bb480aaa402 472 /* pass a proc for evaulation */
mzta 0:4bb480aaa402 473 /* evaluate the bytecode */
mzta 0:4bb480aaa402 474 result = mrb_context_run(mrb,
mzta 0:4bb480aaa402 475 proc,
mzta 0:4bb480aaa402 476 mrb_top_self(mrb),
mzta 0:4bb480aaa402 477 stack_keep);
mzta 0:4bb480aaa402 478 stack_keep = proc->body.irep->nlocals;
mzta 0:4bb480aaa402 479 /* did an exception occur? */
mzta 0:4bb480aaa402 480 if (mrb->exc) {
mzta 0:4bb480aaa402 481 p(mrb, mrb_obj_value(mrb->exc), 0);
mzta 0:4bb480aaa402 482 mrb->exc = 0;
mzta 0:4bb480aaa402 483 }
mzta 0:4bb480aaa402 484 else {
mzta 0:4bb480aaa402 485 /* no */
mzta 0:4bb480aaa402 486 if (!mrb_respond_to(mrb, result, mrb_intern_lit(mrb, "inspect"))){
mzta 0:4bb480aaa402 487 result = mrb_any_to_s(mrb, result);
mzta 0:4bb480aaa402 488 }
mzta 0:4bb480aaa402 489 p(mrb, result, 1);
mzta 0:4bb480aaa402 490 }
mzta 0:4bb480aaa402 491 }
mzta 0:4bb480aaa402 492 ruby_code[0] = '\0';
mzta 0:4bb480aaa402 493 last_code_line[0] = '\0';
mzta 0:4bb480aaa402 494 mrb_gc_arena_restore(mrb, ai);
mzta 0:4bb480aaa402 495 }
mzta 0:4bb480aaa402 496 mrb_parser_free(parser);
mzta 0:4bb480aaa402 497 cxt->lineno++;
mzta 0:4bb480aaa402 498 }
mzta 0:4bb480aaa402 499
mzta 0:4bb480aaa402 500 #ifdef ENABLE_READLINE
mzta 0:4bb480aaa402 501 MIRB_WRITE_HISTORY(history_path);
mzta 0:4bb480aaa402 502 mrb_free(mrb, history_path);
mzta 0:4bb480aaa402 503 #endif
mzta 0:4bb480aaa402 504
mzta 0:4bb480aaa402 505 mrbc_context_free(mrb, cxt);
mzta 0:4bb480aaa402 506 mrb_close(mrb);
mzta 0:4bb480aaa402 507
mzta 0:4bb480aaa402 508 return 0;
mzta 0:4bb480aaa402 509 }