Port of MicroPython to the mbed platform. See micropython-repl for an interactive program.

Dependents:   micropython-repl

This a port of MicroPython to the mbed Classic platform.

This provides an interpreter running on the board's USB serial connection.

Getting Started

Import the micropython-repl program into your IDE workspace on developer.mbed.org. Compile and download to your board. Connect to the USB serial port in your usual manner. You should get a startup message similar to the following:

  MicroPython v1.7-155-gdddcdd8 on 2016-04-23; K64F with ARM
  Type "help()" for more information.
  >>>

Then you can start using micropython. For example:

  >>> from mbed import DigitalOut
  >>> from pins import LED1
  >>> led = DigitalOut(LED1)
  >>> led.write(1)

Requirements

You need approximately 100K of flash memory, so this will be no good for boards with smaller amounts of storage.

Caveats

This can be considered an alpha release of the port; things may not work; APIs may change in later releases. It is NOT an official part part the micropython project, so if anything doesn't work, blame me. If it does work, most of the credit is due to micropython.

  • Only a few of the mbed classes are available in micropython so far, and not all methods of those that are.
  • Only a few boards have their full range of pin names available; for others, only a few standard ones (USBTX, USBRX, LED1) are implemented.
  • The garbage collector is not yet implemented. The interpreter will gradually consume memory and then fail.
  • Exceptions from the mbed classes are not yet handled.
  • Asynchronous processing (e.g. events on inputs) is not supported.

Credits

  • Damien P. George and other contributors who created micropython.
  • Colin Hogben, author of this port.
Committer:
Colin Hogben
Date:
Wed Apr 27 22:11:29 2016 +0100
Revision:
10:33521d742af1
Parent:
2:c89e95946844
Update README and version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pythontech 0:5868e8752d44 1 /*
pythontech 0:5868e8752d44 2 * This file is part of the Micro Python project, http://micropython.org/
pythontech 0:5868e8752d44 3 *
pythontech 0:5868e8752d44 4 * The MIT License (MIT)
pythontech 0:5868e8752d44 5 *
pythontech 0:5868e8752d44 6 * Copyright (c) 2013-2015 Damien P. George
pythontech 0:5868e8752d44 7 *
pythontech 0:5868e8752d44 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
pythontech 0:5868e8752d44 9 * of this software and associated documentation files (the "Software"), to deal
pythontech 0:5868e8752d44 10 * in the Software without restriction, including without limitation the rights
pythontech 0:5868e8752d44 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
pythontech 0:5868e8752d44 12 * copies of the Software, and to permit persons to whom the Software is
pythontech 0:5868e8752d44 13 * furnished to do so, subject to the following conditions:
pythontech 0:5868e8752d44 14 *
pythontech 0:5868e8752d44 15 * The above copyright notice and this permission notice shall be included in
pythontech 0:5868e8752d44 16 * all copies or substantial portions of the Software.
pythontech 0:5868e8752d44 17 *
pythontech 0:5868e8752d44 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
pythontech 0:5868e8752d44 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
pythontech 0:5868e8752d44 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
pythontech 0:5868e8752d44 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
pythontech 0:5868e8752d44 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
pythontech 0:5868e8752d44 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
pythontech 0:5868e8752d44 24 * THE SOFTWARE.
pythontech 0:5868e8752d44 25 */
pythontech 0:5868e8752d44 26
pythontech 0:5868e8752d44 27 #include <string.h>
pythontech 0:5868e8752d44 28 #include "py/obj.h"
pythontech 0:5868e8752d44 29 #include "py/runtime.h"
pythontech 0:5868e8752d44 30 #include "py/repl.h"
pythontech 0:5868e8752d44 31
pythontech 0:5868e8752d44 32 #if MICROPY_HELPER_REPL
pythontech 0:5868e8752d44 33
pythontech 0:5868e8752d44 34 STATIC bool str_startswith_word(const char *str, const char *head) {
pythontech 0:5868e8752d44 35 mp_uint_t i;
pythontech 0:5868e8752d44 36 for (i = 0; str[i] && head[i]; i++) {
pythontech 0:5868e8752d44 37 if (str[i] != head[i]) {
pythontech 0:5868e8752d44 38 return false;
pythontech 0:5868e8752d44 39 }
pythontech 0:5868e8752d44 40 }
pythontech 0:5868e8752d44 41 return head[i] == '\0' && (str[i] == '\0' || !unichar_isident(str[i]));
pythontech 0:5868e8752d44 42 }
pythontech 0:5868e8752d44 43
pythontech 0:5868e8752d44 44 bool mp_repl_continue_with_input(const char *input) {
pythontech 0:5868e8752d44 45 // check for blank input
pythontech 0:5868e8752d44 46 if (input[0] == '\0') {
pythontech 0:5868e8752d44 47 return false;
pythontech 0:5868e8752d44 48 }
pythontech 0:5868e8752d44 49
pythontech 0:5868e8752d44 50 // check if input starts with a certain keyword
pythontech 0:5868e8752d44 51 bool starts_with_compound_keyword =
pythontech 0:5868e8752d44 52 input[0] == '@'
pythontech 0:5868e8752d44 53 || str_startswith_word(input, "if")
pythontech 0:5868e8752d44 54 || str_startswith_word(input, "while")
pythontech 0:5868e8752d44 55 || str_startswith_word(input, "for")
pythontech 0:5868e8752d44 56 || str_startswith_word(input, "try")
pythontech 0:5868e8752d44 57 || str_startswith_word(input, "with")
pythontech 0:5868e8752d44 58 || str_startswith_word(input, "def")
pythontech 0:5868e8752d44 59 || str_startswith_word(input, "class")
Colin Hogben 2:c89e95946844 60 #if MICROPY_PY_ASYNC_AWAIT
Colin Hogben 2:c89e95946844 61 || str_startswith_word(input, "async")
Colin Hogben 2:c89e95946844 62 #endif
pythontech 0:5868e8752d44 63 ;
pythontech 0:5868e8752d44 64
pythontech 0:5868e8752d44 65 // check for unmatched open bracket, quote or escape quote
pythontech 0:5868e8752d44 66 #define Q_NONE (0)
pythontech 0:5868e8752d44 67 #define Q_1_SINGLE (1)
pythontech 0:5868e8752d44 68 #define Q_1_DOUBLE (2)
pythontech 0:5868e8752d44 69 #define Q_3_SINGLE (3)
pythontech 0:5868e8752d44 70 #define Q_3_DOUBLE (4)
pythontech 0:5868e8752d44 71 int n_paren = 0;
pythontech 0:5868e8752d44 72 int n_brack = 0;
pythontech 0:5868e8752d44 73 int n_brace = 0;
pythontech 0:5868e8752d44 74 int in_quote = Q_NONE;
pythontech 0:5868e8752d44 75 const char *i;
pythontech 0:5868e8752d44 76 for (i = input; *i; i++) {
pythontech 0:5868e8752d44 77 if (*i == '\'') {
pythontech 0:5868e8752d44 78 if ((in_quote == Q_NONE || in_quote == Q_3_SINGLE) && i[1] == '\'' && i[2] == '\'') {
pythontech 0:5868e8752d44 79 i += 2;
pythontech 0:5868e8752d44 80 in_quote = Q_3_SINGLE - in_quote;
pythontech 0:5868e8752d44 81 } else if (in_quote == Q_NONE || in_quote == Q_1_SINGLE) {
pythontech 0:5868e8752d44 82 in_quote = Q_1_SINGLE - in_quote;
pythontech 0:5868e8752d44 83 }
pythontech 0:5868e8752d44 84 } else if (*i == '"') {
pythontech 0:5868e8752d44 85 if ((in_quote == Q_NONE || in_quote == Q_3_DOUBLE) && i[1] == '"' && i[2] == '"') {
pythontech 0:5868e8752d44 86 i += 2;
pythontech 0:5868e8752d44 87 in_quote = Q_3_DOUBLE - in_quote;
pythontech 0:5868e8752d44 88 } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) {
pythontech 0:5868e8752d44 89 in_quote = Q_1_DOUBLE - in_quote;
pythontech 0:5868e8752d44 90 }
pythontech 0:5868e8752d44 91 } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"')) {
pythontech 0:5868e8752d44 92 if (in_quote != Q_NONE) {
pythontech 0:5868e8752d44 93 i++;
pythontech 0:5868e8752d44 94 }
pythontech 0:5868e8752d44 95 } else if (in_quote == Q_NONE) {
pythontech 0:5868e8752d44 96 switch (*i) {
pythontech 0:5868e8752d44 97 case '(': n_paren += 1; break;
pythontech 0:5868e8752d44 98 case ')': n_paren -= 1; break;
pythontech 0:5868e8752d44 99 case '[': n_brack += 1; break;
pythontech 0:5868e8752d44 100 case ']': n_brack -= 1; break;
pythontech 0:5868e8752d44 101 case '{': n_brace += 1; break;
pythontech 0:5868e8752d44 102 case '}': n_brace -= 1; break;
pythontech 0:5868e8752d44 103 default: break;
pythontech 0:5868e8752d44 104 }
pythontech 0:5868e8752d44 105 }
pythontech 0:5868e8752d44 106 }
pythontech 0:5868e8752d44 107
pythontech 0:5868e8752d44 108 // continue if unmatched brackets or quotes
pythontech 0:5868e8752d44 109 if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) {
pythontech 0:5868e8752d44 110 return true;
pythontech 0:5868e8752d44 111 }
pythontech 0:5868e8752d44 112
pythontech 0:5868e8752d44 113 // continue if last character was backslash (for line continuation)
pythontech 0:5868e8752d44 114 if (i[-1] == '\\') {
pythontech 0:5868e8752d44 115 return true;
pythontech 0:5868e8752d44 116 }
pythontech 0:5868e8752d44 117
pythontech 0:5868e8752d44 118 // continue if compound keyword and last line was not empty
pythontech 0:5868e8752d44 119 if (starts_with_compound_keyword && i[-1] != '\n') {
pythontech 0:5868e8752d44 120 return true;
pythontech 0:5868e8752d44 121 }
pythontech 0:5868e8752d44 122
pythontech 0:5868e8752d44 123 // otherwise, don't continue
pythontech 0:5868e8752d44 124 return false;
pythontech 0:5868e8752d44 125 }
pythontech 0:5868e8752d44 126
pythontech 0:5868e8752d44 127 mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t *print, const char **compl_str) {
pythontech 0:5868e8752d44 128 // scan backwards to find start of "a.b.c" chain
pythontech 0:5868e8752d44 129 const char *top = str + len;
pythontech 0:5868e8752d44 130 for (const char *s = top; --s >= str;) {
pythontech 0:5868e8752d44 131 if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) {
pythontech 0:5868e8752d44 132 ++s;
pythontech 0:5868e8752d44 133 str = s;
pythontech 0:5868e8752d44 134 break;
pythontech 0:5868e8752d44 135 }
pythontech 0:5868e8752d44 136 }
pythontech 0:5868e8752d44 137
pythontech 0:5868e8752d44 138 // begin search in locals dict
pythontech 0:5868e8752d44 139 mp_obj_dict_t *dict = mp_locals_get();
pythontech 0:5868e8752d44 140
pythontech 0:5868e8752d44 141 for (;;) {
pythontech 0:5868e8752d44 142 // get next word in string to complete
pythontech 0:5868e8752d44 143 const char *s_start = str;
pythontech 0:5868e8752d44 144 while (str < top && *str != '.') {
pythontech 0:5868e8752d44 145 ++str;
pythontech 0:5868e8752d44 146 }
pythontech 0:5868e8752d44 147 mp_uint_t s_len = str - s_start;
pythontech 0:5868e8752d44 148
pythontech 0:5868e8752d44 149 if (str < top) {
pythontech 0:5868e8752d44 150 // a complete word, lookup in current dict
pythontech 0:5868e8752d44 151
pythontech 0:5868e8752d44 152 mp_obj_t obj = MP_OBJ_NULL;
pythontech 0:5868e8752d44 153 for (mp_uint_t i = 0; i < dict->map.alloc; i++) {
pythontech 0:5868e8752d44 154 if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
pythontech 0:5868e8752d44 155 mp_uint_t d_len;
pythontech 0:5868e8752d44 156 const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
pythontech 0:5868e8752d44 157 if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) {
pythontech 0:5868e8752d44 158 obj = dict->map.table[i].value;
pythontech 0:5868e8752d44 159 break;
pythontech 0:5868e8752d44 160 }
pythontech 0:5868e8752d44 161 }
pythontech 0:5868e8752d44 162 }
pythontech 0:5868e8752d44 163
pythontech 0:5868e8752d44 164 if (obj == MP_OBJ_NULL) {
pythontech 0:5868e8752d44 165 // lookup failed
pythontech 0:5868e8752d44 166 return 0;
pythontech 0:5868e8752d44 167 }
pythontech 0:5868e8752d44 168
pythontech 0:5868e8752d44 169 // found an object of this name; try to get its dict
pythontech 0:5868e8752d44 170 if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) {
pythontech 0:5868e8752d44 171 dict = mp_obj_module_get_globals(obj);
pythontech 0:5868e8752d44 172 } else {
pythontech 0:5868e8752d44 173 mp_obj_type_t *type;
pythontech 0:5868e8752d44 174 if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) {
pythontech 0:5868e8752d44 175 type = MP_OBJ_TO_PTR(obj);
pythontech 0:5868e8752d44 176 } else {
pythontech 0:5868e8752d44 177 type = mp_obj_get_type(obj);
pythontech 0:5868e8752d44 178 }
pythontech 0:5868e8752d44 179 if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) {
pythontech 0:5868e8752d44 180 dict = type->locals_dict;
pythontech 0:5868e8752d44 181 } else {
pythontech 0:5868e8752d44 182 // obj has no dict
pythontech 0:5868e8752d44 183 return 0;
pythontech 0:5868e8752d44 184 }
pythontech 0:5868e8752d44 185 }
pythontech 0:5868e8752d44 186
pythontech 0:5868e8752d44 187 // skip '.' to move to next word
pythontech 0:5868e8752d44 188 ++str;
pythontech 0:5868e8752d44 189
pythontech 0:5868e8752d44 190 } else {
pythontech 0:5868e8752d44 191 // end of string, do completion on this partial name
pythontech 0:5868e8752d44 192
pythontech 0:5868e8752d44 193 // look for matches
pythontech 0:5868e8752d44 194 int n_found = 0;
pythontech 0:5868e8752d44 195 const char *match_str = NULL;
pythontech 0:5868e8752d44 196 mp_uint_t match_len = 0;
pythontech 0:5868e8752d44 197 for (mp_uint_t i = 0; i < dict->map.alloc; i++) {
pythontech 0:5868e8752d44 198 if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
pythontech 0:5868e8752d44 199 mp_uint_t d_len;
pythontech 0:5868e8752d44 200 const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
pythontech 0:5868e8752d44 201 if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
pythontech 0:5868e8752d44 202 if (match_str == NULL) {
pythontech 0:5868e8752d44 203 match_str = d_str;
pythontech 0:5868e8752d44 204 match_len = d_len;
pythontech 0:5868e8752d44 205 } else {
pythontech 0:5868e8752d44 206 // search for longest common prefix of match_str and d_str
pythontech 0:5868e8752d44 207 // (assumes these strings are null-terminated)
pythontech 0:5868e8752d44 208 for (mp_uint_t j = s_len; j <= match_len && j <= d_len; ++j) {
pythontech 0:5868e8752d44 209 if (match_str[j] != d_str[j]) {
pythontech 0:5868e8752d44 210 match_len = j;
pythontech 0:5868e8752d44 211 break;
pythontech 0:5868e8752d44 212 }
pythontech 0:5868e8752d44 213 }
pythontech 0:5868e8752d44 214 }
pythontech 0:5868e8752d44 215 ++n_found;
pythontech 0:5868e8752d44 216 }
pythontech 0:5868e8752d44 217 }
pythontech 0:5868e8752d44 218 }
pythontech 0:5868e8752d44 219
pythontech 0:5868e8752d44 220 // nothing found
pythontech 0:5868e8752d44 221 if (n_found == 0) {
pythontech 0:5868e8752d44 222 return 0;
pythontech 0:5868e8752d44 223 }
pythontech 0:5868e8752d44 224
pythontech 0:5868e8752d44 225 // 1 match found, or multiple matches with a common prefix
pythontech 0:5868e8752d44 226 if (n_found == 1 || match_len > s_len) {
pythontech 0:5868e8752d44 227 *compl_str = match_str + s_len;
pythontech 0:5868e8752d44 228 return match_len - s_len;
pythontech 0:5868e8752d44 229 }
pythontech 0:5868e8752d44 230
pythontech 0:5868e8752d44 231 // multiple matches found, print them out
pythontech 0:5868e8752d44 232
pythontech 0:5868e8752d44 233 #define WORD_SLOT_LEN (16)
pythontech 0:5868e8752d44 234 #define MAX_LINE_LEN (4 * WORD_SLOT_LEN)
pythontech 0:5868e8752d44 235
pythontech 0:5868e8752d44 236 int line_len = MAX_LINE_LEN; // force a newline for first word
pythontech 0:5868e8752d44 237 for (mp_uint_t i = 0; i < dict->map.alloc; i++) {
pythontech 0:5868e8752d44 238 if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
pythontech 0:5868e8752d44 239 mp_uint_t d_len;
pythontech 0:5868e8752d44 240 const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
pythontech 0:5868e8752d44 241 if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
pythontech 0:5868e8752d44 242 int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len;
pythontech 0:5868e8752d44 243 if (gap < 2) {
pythontech 0:5868e8752d44 244 gap += WORD_SLOT_LEN;
pythontech 0:5868e8752d44 245 }
pythontech 0:5868e8752d44 246 if (line_len + gap + d_len <= MAX_LINE_LEN) {
pythontech 0:5868e8752d44 247 // TODO optimise printing of gap?
pythontech 0:5868e8752d44 248 for (int j = 0; j < gap; ++j) {
pythontech 0:5868e8752d44 249 mp_print_str(print, " ");
pythontech 0:5868e8752d44 250 }
pythontech 0:5868e8752d44 251 mp_print_str(print, d_str);
pythontech 0:5868e8752d44 252 line_len += gap + d_len;
pythontech 0:5868e8752d44 253 } else {
pythontech 0:5868e8752d44 254 mp_printf(print, "\n%s", d_str);
pythontech 0:5868e8752d44 255 line_len = d_len;
pythontech 0:5868e8752d44 256 }
pythontech 0:5868e8752d44 257 }
pythontech 0:5868e8752d44 258 }
pythontech 0:5868e8752d44 259 }
pythontech 0:5868e8752d44 260 mp_print_str(print, "\n");
pythontech 0:5868e8752d44 261
pythontech 0:5868e8752d44 262 return (mp_uint_t)(-1); // indicate many matches
pythontech 0:5868e8752d44 263 }
pythontech 0:5868e8752d44 264 }
pythontech 0:5868e8752d44 265 }
pythontech 0:5868e8752d44 266
pythontech 0:5868e8752d44 267 #endif // MICROPY_HELPER_REPL