pyexec.c 15.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

27
28
#include <stdlib.h>
#include <stdio.h>
Dave Hylands's avatar
Dave Hylands committed
29
#include <stdint.h>
30

31
32
33
34
35
#include "py/nlr.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/gc.h"
36
#ifdef MICROPY_HAL_H
37
#include MICROPY_HAL_H
38
#endif
39
40
41
42
#if defined(USE_DEVICE_MODE)
#include "irq.h"
#include "usb.h"
#endif
43
#include "readline.h"
44
#include "pyexec.h"
45
#include "genhdr/mpversion.h"
46

47
48
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
STATIC bool repl_display_debugging_info = 0;
49

50
51
52
53
#define EXEC_FLAG_PRINT_EOF (1)
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
#define EXEC_FLAG_IS_REPL (4)

54
55
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
56
57
58
59
60
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, int exec_flags) {
    int ret = 0;
61
    uint32_t start = 0;
62

63
64
    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
65
66
        // parse and compile the script
        qstr source_name = lex->source_name;
67
68
        mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
        mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);
69
70

        // execute code
71
        mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
72
        start = HAL_GetTick();
Damien George's avatar
Damien George committed
73
        mp_call_function_0(module_fun);
74
        mp_hal_set_interrupt_char(-1); // disable interrupt
75
        nlr_pop();
76
        ret = 1;
77
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
78
            mp_hal_stdout_tx_strn("\x04", 1);
79
        }
80
81
82
    } else {
        // uncaught exception
        // FIXME it could be that an interrupt happens just before we disable it here
83
        mp_hal_set_interrupt_char(-1); // disable interrupt
84
85
        // print EOF after normal output
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
86
            mp_hal_stdout_tx_strn("\x04", 1);
87
        }
88
        // check for SystemExit
89
90
91
92
        if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
            // at the moment, the value of SystemExit is unused
            ret = PYEXEC_FORCED_EXIT;
        } else {
93
            mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
94
            ret = 0;
95
        }
96
97
98
    }

    // display debugging info if wanted
99
    if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
100
101
        mp_uint_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
        printf("took " UINT_FMT " ms\n", ticks);
102
103
104
        gc_collect();
        // qstr info
        {
105
            mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
106
            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
107
            printf("qstr:\n  n_pool=" UINT_FMT "\n  n_qstr=" UINT_FMT "\n  n_str_data_bytes=" UINT_FMT "\n  n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
108
109
110
        }

        // GC info
111
        gc_dump_info();
112
113
    }

114
    if (exec_flags & EXEC_FLAG_PRINT_EOF) {
115
        mp_hal_stdout_tx_strn("\x04", 1);
116
117
    }

118
119
120
    return ret;
}

121
122
#if MICROPY_REPL_EVENT_DRIVEN

123
124
typedef struct _repl_t {
    // XXX line holds a root pointer!
125
126
    vstr_t line;
    bool cont_line;
127
128
129
} repl_t;

repl_t repl;
130

131
132
STATIC int pyexec_raw_repl_process_char(int c);
STATIC int pyexec_friendly_repl_process_char(int c);
133

134
void pyexec_event_repl_init(void) {
135
136
    vstr_init(&repl.line, 32);
    repl.cont_line = false;
137
    readline_init(&repl.line, ">>> ");
138
139
140
141
142
    if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
        pyexec_raw_repl_process_char(CHAR_CTRL_A);
    } else {
        pyexec_friendly_repl_process_char(CHAR_CTRL_B);
    }
143
144
}

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
STATIC int pyexec_raw_repl_process_char(int c) {
    if (c == CHAR_CTRL_A) {
        // reset raw REPL
        mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");
        goto reset;
    } else if (c == CHAR_CTRL_B) {
        // change to friendly REPL
        pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
        repl.cont_line = false;
        pyexec_friendly_repl_process_char(CHAR_CTRL_B);
        return 0;
    } else if (c == CHAR_CTRL_C) {
        // clear line
        vstr_reset(&repl.line);
        return 0;
    } else if (c == CHAR_CTRL_D) {
        // input finished
    } else {
        // let through any other raw 8-bit value
        vstr_add_byte(&repl.line, c);
        return 0;
    }

    // indicate reception of command
    mp_hal_stdout_tx_str("OK");

    if (repl.line.len == 0) {
        // exit for a soft reset
        mp_hal_stdout_tx_str("\r\n");
        vstr_clear(&repl.line);
        return PYEXEC_FORCED_EXIT;
    }

    mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, repl.line.buf, repl.line.len, 0);
    if (lex == NULL) {
        mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04");
    } else {
        int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
        if (ret & PYEXEC_FORCED_EXIT) {
            return ret;
        }
    }

reset:
189
    vstr_reset(&repl.line);
190
191
192
    mp_hal_stdout_tx_str(">");

    return 0;
193
194
}

195
STATIC int pyexec_friendly_repl_process_char(int c) {
196
197
198
199
200
201
202
    int ret = readline_process_char(c);

    if (!repl.cont_line) {

        if (ret == CHAR_CTRL_A) {
            // change to raw REPL
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
203
            mp_hal_stdout_tx_str("\r\n");
204
205
            pyexec_raw_repl_process_char(CHAR_CTRL_A);
            return 0;
206
207
        } else if (ret == CHAR_CTRL_B) {
            // reset friendly REPL
208
            mp_hal_stdout_tx_str("\r\n");
209
            mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
210
211
            mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
            goto input_restart;
212
213
        } else if (ret == CHAR_CTRL_C) {
            // break
214
            mp_hal_stdout_tx_str("\r\n");
215
216
217
            goto input_restart;
        } else if (ret == CHAR_CTRL_D) {
            // exit for a soft reset
218
            mp_hal_stdout_tx_str("\r\n");
219
220
221
222
223
224
225
226
            vstr_clear(&repl.line);
            return PYEXEC_FORCED_EXIT;
        }

        if (ret < 0) {
            return 0;
        }

227
        if (!mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) {
228
229
230
            goto exec;
        }

231
        vstr_add_byte(&repl.line, '\n');
232
        repl.cont_line = true;
233
        readline_note_newline("... ");
234
235
236
237
238
        return 0;

    } else {

        if (ret == CHAR_CTRL_C) {
239
240
241
242
           // cancel everything
           mp_hal_stdout_tx_str("\r\n");
           repl.cont_line = false;
           goto input_restart;
243
        } else if (ret == CHAR_CTRL_D) {
244
245
            // stop entering compound statement
            goto exec;
246
247
248
249
250
251
        }

        if (ret < 0) {
            return 0;
        }

252
        if (mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) {
253
            vstr_add_byte(&repl.line, '\n');
254
            readline_note_newline("... ");
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
            return 0;
        }

exec: ;
        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&repl.line), vstr_len(&repl.line), 0);
        if (lex == NULL) {
            printf("MemoryError\n");
        } else {
            int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
            if (ret & PYEXEC_FORCED_EXIT) {
                return ret;
            }
        }

input_restart:
270
271
272
        vstr_reset(&repl.line);
        repl.cont_line = false;
        readline_init(&repl.line, ">>> ");
273
274
275
276
        return 0;
    }
}

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
int pyexec_event_repl_process_char(int c) {
    if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
        return pyexec_raw_repl_process_char(c);
    } else {
        return pyexec_friendly_repl_process_char(c);
    }
}

#else // MICROPY_REPL_EVENT_DRIVEN

int pyexec_raw_repl(void) {
    vstr_t line;
    vstr_init(&line, 32);

raw_repl_reset:
    mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n");

    for (;;) {
        vstr_reset(&line);
        mp_hal_stdout_tx_str(">");
        for (;;) {
            int c = mp_hal_stdin_rx_chr();
            if (c == CHAR_CTRL_A) {
                // reset raw REPL
                goto raw_repl_reset;
            } else if (c == CHAR_CTRL_B) {
                // change to friendly REPL
                mp_hal_stdout_tx_str("\r\n");
                vstr_clear(&line);
                pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
                return 0;
            } else if (c == CHAR_CTRL_C) {
                // clear line
                vstr_reset(&line);
            } else if (c == CHAR_CTRL_D) {
                // input finished
                break;
            } else {
                // let through any other raw 8-bit value
                vstr_add_byte(&line, c);
            }
        }

        // indicate reception of command
        mp_hal_stdout_tx_str("OK");

        if (line.len == 0) {
            // exit for a soft reset
            mp_hal_stdout_tx_str("\r\n");
            vstr_clear(&line);
            return PYEXEC_FORCED_EXIT;
        }

        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0);
        if (lex == NULL) {
            printf("\x04MemoryError\n\x04");
        } else {
            int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
            if (ret & PYEXEC_FORCED_EXIT) {
                return ret;
            }
        }
    }
}
341

342
343
344
345
int pyexec_friendly_repl(void) {
    vstr_t line;
    vstr_init(&line, 32);

346
347
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
    // in host mode, we enable the LCD for the repl
Damien George's avatar
Damien George committed
348
349
    mp_obj_t lcd_o = mp_call_function_0(mp_load_name(qstr_from_str("LCD")));
    mp_call_function_1(mp_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
350
351
#endif

352
friendly_repl_reset:
353
    mp_hal_stdout_tx_str("MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n");
354
    mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n");
355
356
357
358
359
360
361
362

    // to test ctrl-C
    /*
    {
        uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
        for (;;) {
            nlr_buf_t nlr;
            printf("pyexec_repl: %p\n", x);
363
            mp_hal_set_interrupt_char(CHAR_CTRL_C);
364
365
366
367
368
369
370
371
372
373
374
            if (nlr_push(&nlr) == 0) {
                for (;;) {
                }
            } else {
                printf("break\n");
            }
        }
    }
    */

    for (;;) {
375
    input_restart:
376
377
378
379
380
381
382
383
384
385
386
387
388
389

        #if defined(USE_DEVICE_MODE)
        if (usb_vcp_is_enabled()) {
            // If the user gets to here and interrupts are disabled then
            // they'll never see the prompt, traceback etc. The USB REPL needs
            // interrupts to be enabled or no transfers occur. So we try to
            // do the user a favor and reenable interrupts.
            if (query_irq() == IRQ_STATE_DISABLED) {
                enable_irq(IRQ_STATE_ENABLED);
                mp_hal_stdout_tx_str("PYB: enabling IRQs\r\n");
            }
        }
        #endif

390
391
        vstr_reset(&line);
        int ret = readline(&line, ">>> ");
392
        mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
393

394
        if (ret == CHAR_CTRL_A) {
395
            // change to raw REPL
396
            mp_hal_stdout_tx_str("\r\n");
397
398
399
            vstr_clear(&line);
            pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
            return 0;
400
        } else if (ret == CHAR_CTRL_B) {
401
            // reset friendly REPL
402
            mp_hal_stdout_tx_str("\r\n");
403
            goto friendly_repl_reset;
404
        } else if (ret == CHAR_CTRL_C) {
405
            // break
406
            mp_hal_stdout_tx_str("\r\n");
407
            continue;
408
        } else if (ret == CHAR_CTRL_D) {
409
            // exit for a soft reset
410
            mp_hal_stdout_tx_str("\r\n");
411
            vstr_clear(&line);
412
            return PYEXEC_FORCED_EXIT;
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
        } else if (ret == CHAR_CTRL_E) {
            // paste mode
            mp_hal_stdout_tx_str("\r\npaste mode; CTRL-C to cancel, CTRL-D to finish\r\n=== ");
            vstr_reset(&line);
            for (;;) {
                char c = mp_hal_stdin_rx_chr();
                if (c == CHAR_CTRL_C) {
                    // cancel everything
                    mp_hal_stdout_tx_str("\r\n");
                    goto input_restart;
                } else if (c == CHAR_CTRL_D) {
                    // end of input
                    mp_hal_stdout_tx_str("\r\n");
                    break;
                } else {
                    // add char to buffer and echo
                    vstr_add_byte(&line, c);
                    if (c == '\r') {
                        mp_hal_stdout_tx_str("\r\n=== ");
                    } else {
                        mp_hal_stdout_tx_strn(&c, 1);
                    }
                }
            }
            parse_input_kind = MP_PARSE_FILE_INPUT;
438
439
        } else if (vstr_len(&line) == 0) {
            continue;
440
441
442
443
444
445
446
447
448
449
450
451
452
        } else {
            // got a line with non-zero length, see if it needs continuing
            while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
                vstr_add_byte(&line, '\n');
                ret = readline(&line, "... ");
                if (ret == CHAR_CTRL_C) {
                    // cancel everything
                    mp_hal_stdout_tx_str("\r\n");
                    goto input_restart;
                } else if (ret == CHAR_CTRL_D) {
                    // stop entering compound statement
                    break;
                }
453
454
455
456
            }
        }

        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
457
458
459
        if (lex == NULL) {
            printf("MemoryError\n");
        } else {
460
            ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
461
462
463
            if (ret & PYEXEC_FORCED_EXIT) {
                return ret;
            }
464
        }
465
466
467
    }
}

468
#endif // MICROPY_REPL_EVENT_DRIVEN
469

470
int pyexec_file(const char *filename) {
471
472
473
474
475
476
477
    mp_lexer_t *lex = mp_lexer_new_from_file(filename);

    if (lex == NULL) {
        printf("could not open file '%s' for reading\n", filename);
        return false;
    }

478
    return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0);
479
480
481
482
483
484
485
486
}

mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
    repl_display_debugging_info = mp_obj_get_int(o_value);
    return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);