Port of Micro Python to NuttX. From Dave Marples

This commit is contained in:
Gregory Nutt 2015-01-11 09:34:51 -06:00
parent 632480ce24
commit 63b265b640
13 changed files with 1547 additions and 5 deletions

@ -38,10 +38,14 @@ ifeq ($(CONFIG_INTERPRETERS_BAS),y)
CONFIGURED_APPS += interpreters/bas
endif
ifeq ($(CONFIG_INTERPRETERS_PCODE),y)
CONFIGURED_APPS += interpreters/pcode
endif
ifeq ($(CONFIG_INTERPRETERS_FICL),y)
CONFIGURED_APPS += interpreters/ficl
endif
ifeq ($(CONFIG_INTERPRETERS_MICROPYTHON),y)
CONFIGURED_APPS += interpreters/micropython
endif
ifeq ($(CONFIG_INTERPRETERS_PCODE),y)
CONFIGURED_APPS += interpreters/pcode
endif

@ -37,7 +37,7 @@
# Sub-directories containing interpreter runtime
SUBDIRS = pcode prun ficl bas
SUBDIRS = bas ficl micropython pcode prun
# Create the list of installed runtime modules (INSTALLED_DIRS)

@ -12,6 +12,25 @@ ficl
is not in that directory, only an environment and instructions that will
let you build Ficl under NuttX. The rest is up to you.
micropython
-----------
This is a port of a build environment for Micro Python:
https://micropython.org/
NOTE that Micro Python is not included in this directory. Before building
this example, you must first download Micro Python from:
https://micropython.org/download/
Or clone from the GIT repository:
https://github.com/micropython/
This port was contributed by Dave Marples using Micro Python circu
1.3.8. It may not be compatible with other versions.
pcode
-----

11
interpreters/micropython/.gitignore vendored Normal file

@ -0,0 +1,11 @@
/Make.dep
/.depend
/.built
/*.asm
/*.obj
/*.rel
/*.lst
/*.sym
/*.adb
/*.lib
/*.src

@ -0,0 +1,34 @@
#
# For a description of the syntax of this configuration file,
# see misc/tools/kconfig-language.txt.
#
config INTERPRETERS_MICROPYTHON
bool "Micro Python support"
default n
---help---
Enable support for the Micro Python interpreter
if INTERPRETERS_MICROPYTHON
config INTERPRETERS_MICROPYTHON_APPNAME
string "Executable name"
default "micropython"
depends on NSH_BUILTIN_APPS
config INTERPRETERS_MICROPYTHON_STACKSIZE
int "Interpreter stack size"
default 2048
depends on NSH_BUILTIN_APPS
config INTERPRETERS_MICROPYTHON_PRIORITY
int "Interpreter priority"
default 100
depends on NSH_BUILTIN_APPS
CONFIG_INTERPRETERS_MICROPYTHON_PROGNAME
string "Program name"
default "micropython"
depends on BUILD_KERNEL
endif # INTERPRETERS_MICROPYTHON

@ -0,0 +1,143 @@
############################################################################
# apps/ interpreters/micropython/Makefile
#
# Copyright (C) 2015 Gregory Nutt. All rights reserved.
# Authors: Gregory Nutt <gnutt@nuttx.org>
# Dave Marples <dave@marples.net>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
###########################################################################
TOP ?= ../../../../micropython
TOPDIR ?= ../../../nuttx
APPDIR ?= ../../../apps
MICROPYTHON_DIR = $(TOP)/py
include $(MICROPYTHON_DIR)/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include $(MICROPYTHON_DIR)/py.mk
-include $(TOPDIR)/.config
-include $(TOPDIR)/Make.defs
include $(APPDIR)/Make.defs
# c99 is needed for micropython
CFLAGS+=-std=c99 -Wno-shadow -Wno-strict-prototypes
INC = -I. -I$(TOP) -I$(PY_SRC) -I$(BUILD)
CFLAGS +=$(INC)
CONFIG_INTERPRETERS_MICROPYTHON_APPNAME ?= micropython
CONFIG_INTERPRETERS_MICROPYTHON_STACKSIZE ?= 2048
CONFIG_INTERPRETERS_MICROPYTHON_PRIORITY ?= SCHED_PRIORITY_DEFAULT
APPNAME = $(CONFIG_INTERPRETERS_MICROPYTHON_APPNAME)
STACKSIZE = $(CONFIG_INTERPRETERS_MICROPYTHON_STACKSIZE)
PRIORITY = $(CONFIG_INTERPRETERS_MICROPYTHON_PRIORITY)
CONFIG_INTERPRETERS_MICROPYTHON_PROGNAME ?= micropython$(EXEEXT)
PROGNAME = $(CONFIG_INTERPRETERS_MICROPYTHON_PROGNAME)
ASRCS =
CSRCS = pyexec.c py_readline.c
MAINSRC = micropython_main.c
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(ASRC:.S=$(OBJEXT)) $(CSRCS:.c=$(OBJEXT)))
ifneq ($(CONFIG_BUILD_KERNEL),y)
OBJ += $(addprefix $(BUILD)/, $(MAINSRC:.c=$(OBJEXT)))
endif
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
BIN = ..\..\libapps$(LIBEXT)
else
ifeq ($(WINTOOL),y)
BIN = ..\\..\\libapps$(LIBEXT)
else
BIN = ../../libapps$(LIBEXT)
endif
endif
ifeq ($(WINTOOL),y)
INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}"
else
INSTALL_DIR = $(BIN_DIR)
endif
ROOTDEPPATH = --dep-path .
# Common build
all: .built
.built: $(OBJ)
$(call ARCHIVE, $(BIN), $(OBJ))
@touch .built
ifeq ($(CONFIG_BUILD_KERNEL),y)
$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJ) $(MAINOBJ)
@echo "LD: $(PROGNAME)"
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
$(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME)
install: $(BIN_DIR)$(DELIM)$(PROGNAME)
else
install:
endif
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y)
$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile
$(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),micropython_main)
context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat
else
context:
endif
.depend: Makefile $(SRCS)
@$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
depend: .depend
distclean: clean
$(call DELFILE, Make.dep)
$(call DELFILE, .depend)
include $(MICROPYTHON_DIR)/mkrules.mk
-include Make.dep

@ -0,0 +1,263 @@
/****************************************************************************
* interpreters/micropython/micropython_main.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>
* Dave Marples <dave@marples.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <debug.h>
#include <stdio.h>
#include <math.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "repl.h"
#include "pfenv.h"
#include "pyexec.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
__x = (x); \
(void)__x; \
} else if (sizeof(x) == sizeof(double)) { \
volatile double __x; \
__x = (x); \
(void)__x; \
} else { \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while(0);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Function
****************************************************************************/
void do_str(FAR const char *src)
{
FAR mp_lexer_t *lex =
mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL)
{
return;
}
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind);
if (pn == MP_PARSE_NODE_NULL)
{
/* parse error */
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
return;
}
/* parse okay */
qstr source_name = lex->source_name;
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
if (mp_obj_is_exception_instance(module_fun))
{
/* compile error */
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
return;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0)
{
mp_call_function_0(module_fun);
nlr_pop();
}
else
{
/* uncaught exception */
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t) nlr.ret_val);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
float nanf(FAR const char *tagp)
{
(void)tagp;
return 0;
}
float copysignf(float x, float y)
{
if (y < 0)
{
return -fabsf(x);
}
return fabsf(x);
}
float truncf(float x)
{
union
{
float f;
uint32_t i;
} u =
{
x};
int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9;
uint32_t m;
if (e >= 23 + 9)
{
return x;
}
if (e < 9)
{
e = 1;
}
m = -1U >> e;
if ((u.i & m) == 0)
{
return x;
}
FORCE_EVAL(x + 0x1 p120f);
u.i &= ~m;
return u.f;
}
/****************************************************************************
* mp_import_stat
****************************************************************************/
mp_import_stat_t mp_import_stat(FAR const char *path)
{
return MP_IMPORT_STAT_NO_EXIST;
}
/****************************************************************************
* mp_lexer_new_from_file
****************************************************************************/
mp_lexer_t *mp_lexer_new_from_file(FAR const char *filename)
{
return NULL;
}
/****************************************************************************
* mp_builtin_open
****************************************************************************/
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t * args, mp_map_t * kwargs)
{
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
/****************************************************************************
* nlr_jump_fail
****************************************************************************/
void nlr_jump_fail(void *val)
{
fprintf(stderr, "FATAL: uncaught exception %p\n", val);
exit(-1);
}
/****************************************************************************
* micropython_main
****************************************************************************/
#ifdef CONFIG_INTERPRETERS_MICROPYTHON
int micropython_main(int argc, char *argv[])
{
mp_init();
for (;;)
{
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL)
{
if (pyexec_raw_repl() != 0)
{
break;
}
}
else
{
if (pyexec_friendly_repl() != 0)
{
break;
}
}
}
mp_deinit();
return 0;
}
#endif

@ -0,0 +1,117 @@
/****************************************************************************
* interpreters/micropython/mpconfigport.h
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Authors: Dave Marples <dave@marples.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __APPS_INTERPRETERS_MICROPYTHON_MPCONFIGPORT_H
#define __APPS_INTERPRETERS_MICROPYTHON_MPCONFIGPORT_H 1
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
#include <wchar_t.h>
/* We need to provide a declaration/definition of alloca() */
#include <alloca.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* options to control how Micro Python is built */
#define MICROPY_ALLOC_PATH_MAX (512)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (0)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPL)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
/* type definitions for the specific machine */
#define BYTES_PER_WORD (4)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
/****************************************************************************
* Public Types
****************************************************************************/
typedef int32_t mp_int_t; /* must be pointer size */
typedef uint32_t mp_uint_t; /* must be pointer size */
typedef void *machine_ptr_t; /* must be of pointer size */
typedef const void *machine_const_ptr_t; /* must be of pointer size */
typedef long mp_off_t;
/****************************************************************************
* Public Data
****************************************************************************/
/* extra built in names to add to the global namespace */
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#endif /* __APPS_INTERPRETERS_MICROPYTHON_MPCONFIGPORT_H */

@ -0,0 +1,431 @@
/****************************************************************************
* interpreters/micropython/py_readline.c
*
* This file originated from the Micro Python project, http://micropython.org/
* It has been hacked around to fit into Nuttx
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Further edits (c) 2015 Dave Marples
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py_readline.h"
#if 0 /* print debugging info */
# define DEBUG_PRINT (1)
# define DEBUG_printf printf
#else /* don't print debugging info */
# define DEBUG_printf(...) (void)0
#endif
#define READLINE_HIST_SIZE (8)
#define CURSOR_BACK ('\b')
#define KEY_TAB ('\t')
/****************************************************************************
* Private Types
****************************************************************************/
enum
{
ESEQ_NONE,
ESEQ_ESC,
ESEQ_ESC_BRACKET,
ESEQ_ESC_BRACKET_DIGIT,
ESEQ_ESC_O
};
/****************************************************************************
* Private Data
****************************************************************************/
static const char *readline_hist[READLINE_HIST_SIZE];
/****************************************************************************
* Private Functions
****************************************************************************/
STATIC char *str_dup_maybe(const char *str)
{
uint32_t len = strlen(str);
char *s2 = m_new_maybe(char, len + 1);
if (s2 == NULL)
{
return NULL;
}
memcpy(s2, str, len + 1);
return s2;
}
/****************************************************************************
* Public Functions
****************************************************************************/
void readline_init0(void)
{
memset(readline_hist, 0, READLINE_HIST_SIZE * sizeof(const char *));
}
int py_readline(vstr_t * line, const char *prompt)
{
fprintf(stdout, prompt);
fflush(stdout);
int orig_line_len = line->len;
int escape_seq = ESEQ_NONE;
char escape_seq_buf[1] = { 0 };
int hist_cur = -1;
int cursor_pos = orig_line_len;
for (;;)
{
int c = getc(stdin);
int last_line_len = line->len;
int redraw_step_back = 0;
bool redraw_from_cursor = false;
int redraw_step_forward = 0;
if (escape_seq == ESEQ_NONE)
{
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_D &&
vstr_len(line) == orig_line_len)
{
/* control character with empty line */
return c;
}
else if (c == CHAR_CTRL_A)
{
/* CTRL-A with non-empty line is go-to-start-of-line */
goto home_key;
}
else if (c == CHAR_CTRL_C)
{
/* CTRL-C with non-empty line is cancel */
return c;
}
else if (c == CHAR_CTRL_E)
{
/* CTRL-E is go-to-end-of-line */
goto end_key;
}
else if (c == '\r')
{
/* newline */
fputs("\r\n", stdout);
if (line->len > orig_line_len &&
(readline_hist[0] == NULL ||
strcmp(readline_hist[0], line->buf + orig_line_len) != 0))
{
/* a line which is not empty and different from the last one
* so update the history
*/
char *most_recent_hist =
str_dup_maybe(line->buf + orig_line_len);
if (most_recent_hist != NULL)
{
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--)
{
readline_hist[i] = readline_hist[i - 1];
}
readline_hist[0] = most_recent_hist;
}
}
return 0;
}
else if (c == 27)
{
/* escape sequence */
escape_seq = ESEQ_ESC;
}
else if (c == 8 || c == 127)
{
/* backspace/delete */
if (cursor_pos > orig_line_len)
{
vstr_cut_out_bytes(line, cursor_pos - 1, 1);
/* set redraw parameters */
redraw_step_back = 1;
redraw_from_cursor = true;
}
}
else if ((KEY_TAB == c) || (32 <= c && c <= 126))
{
/* printable character */
vstr_ins_char(line, cursor_pos, c);
/* set redraw parameters */
redraw_from_cursor = true;
redraw_step_forward = 1;
}
}
else if (escape_seq == ESEQ_ESC)
{
switch (c)
{
case '[':
escape_seq = ESEQ_ESC_BRACKET;
break;
case 'O':
escape_seq = ESEQ_ESC_O;
break;
default:
DEBUG_printf("(ESC %d)", c);
escape_seq = ESEQ_NONE;
}
}
else if (escape_seq == ESEQ_ESC_BRACKET)
{
if ('0' <= c && c <= '9')
{
escape_seq = ESEQ_ESC_BRACKET_DIGIT;
escape_seq_buf[0] = c;
}
else
{
escape_seq = ESEQ_NONE;
if (c == 'A')
{
/* up arrow */
if (hist_cur + 1 < READLINE_HIST_SIZE &&
readline_hist[hist_cur + 1] != NULL)
{
/* increase hist num */
hist_cur += 1;
/* set line to history */
line->len = orig_line_len;
vstr_add_str(line, readline_hist[hist_cur]);
/* set redraw parameters */
redraw_step_back = cursor_pos - orig_line_len;
redraw_from_cursor = true;
redraw_step_forward = line->len - orig_line_len;
}
}
else if (c == 'B')
{
/* down arrow */
if (hist_cur >= 0)
{
/* decrease hist num */
hist_cur -= 1;
/* set line to history */
vstr_cut_tail_bytes(line, line->len - orig_line_len);
if (hist_cur >= 0)
{
vstr_add_str(line, readline_hist[hist_cur]);
}
/* set redraw parameters */
redraw_step_back = cursor_pos - orig_line_len;
redraw_from_cursor = true;
redraw_step_forward = line->len - orig_line_len;
}
}
else if (c == 'C')
{
/* right arrow */
if (cursor_pos < line->len)
{
redraw_step_forward = 1;
}
}
else if (c == 'D')
{
/* left arrow */
if (cursor_pos > orig_line_len)
{
redraw_step_back = 1;
}
}
else if (c == 'H')
{
/* home */
goto home_key;
}
else if (c == 'F')
{
/* end */
goto end_key;
}
else
{
DEBUG_printf("(ESC [ %d)", c);
}
}
}
else if (escape_seq == ESEQ_ESC_BRACKET_DIGIT)
{
if (c == '~')
{
if (escape_seq_buf[0] == '1' || escape_seq_buf[0] == '7')
{
home_key:
redraw_step_back = cursor_pos - orig_line_len;
}
else if (escape_seq_buf[0] == '4' || escape_seq_buf[0] == '8')
{
end_key:
redraw_step_forward = line->len - cursor_pos;
}
else
{
DEBUG_printf("(ESC [ %c %d)", escape_seq_buf[0], c);
}
}
else
{
DEBUG_printf("(ESC [ %c %d)", escape_seq_buf[0], c);
}
escape_seq = ESEQ_NONE;
}
else if (escape_seq == ESEQ_ESC_O)
{
switch (c)
{
case 'H':
goto home_key;
case 'F':
goto end_key;
default:
DEBUG_printf("(ESC O %d)", c);
escape_seq = ESEQ_NONE;
}
}
else
{
escape_seq = ESEQ_NONE;
}
/* redraw command prompt, efficiently
* TODO we can probably use some more sophisticated VT100 commands here
*/
if (redraw_step_back > 0)
{
for (int i = 0; i < redraw_step_back; i++)
{
fputc(CURSOR_BACK, stdout);
}
cursor_pos -= redraw_step_back;
}
if (redraw_from_cursor)
{
if (line->len < last_line_len)
{
/* erase old chars */
for (int i = cursor_pos; i < last_line_len; i++)
{
fputc(' ', stdout);
}
/* step back */
for (int i = cursor_pos; i < last_line_len; i++)
{
fputc(CURSOR_BACK, stdout);
}
}
/* draw new chars */
int charCount = 0;
do
{
fputc(*(line->buf + cursor_pos + charCount), stdout);
}
while (charCount++ < (line->len - cursor_pos));
/* move cursor forward if needed (already moved forward by length of
* line, so move it back)
*/
for (int i = cursor_pos + redraw_step_forward; i < line->len; i++)
{
fputc(CURSOR_BACK, stdout);
}
cursor_pos += redraw_step_forward;
}
else if (redraw_step_forward > 0)
{
/* draw over old chars to move cursor forwards */
int charCount = 0;
do
{
fputc(*(line->buf + cursor_pos + charCount), stdout);
}
while (charCount++ < redraw_step_forward);
cursor_pos += redraw_step_forward;
}
fflush(stdout);
}
}

@ -0,0 +1,50 @@
/****************************************************************************
* interpreters/micropython/py_readline.h
*
* 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.
*
****************************************************************************/
#ifndef __APPS_INTERPRETERS_MICROPYTHON_PY_READLINE_H
#define __APPS_INTERPRETERS_MICROPYTHON_PY_READLINE_H 1
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define CHAR_CTRL_A (1)
#define CHAR_CTRL_B (2)
#define CHAR_CTRL_C (3)
#define CHAR_CTRL_D (4)
#define CHAR_CTRL_E (5)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
void readline_init0(void);
int py_readline(vstr_t *line, const char *prompt);
#endif /* __APPS_INTERPRETERS_MICROPYTHON_PY_READLINE_H */

@ -0,0 +1,404 @@
/****************************************************************************
* interpreters/micropython/py_readline.c
*
* This file was part of the Micro Python project, http://micropython.org/
* and has been integrated into Nuttx by Dave Marples (dave@marples.net)
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include "py/nlr.h"
#include "py/parsehelper.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/gc.h"
#include "py/pfenv.h"
#include "py_readline.h"
#include "pyexec.h"
#include "genhdr/py-version.h"
#define EXEC_FLAG_PRINT_EOF (1)
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
#define EXEC_FLAG_IS_REPL (4)
/****************************************************************************
* Public Data
****************************************************************************/
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
STATIC bool repl_display_debugging_info = 0;
/****************************************************************************
* Private Functions
****************************************************************************/
/* parses, compiles and executes the code in the lexer
* frees the lexer before returning
* 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;
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
qstr source_name = lex->source_name;
/* check for parse error */
if (pn == MP_PARSE_NODE_NULL)
{
if (exec_flags & EXEC_FLAG_PRINT_EOF)
{
fprintf(stdout, "\x04");
}
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
goto finish;
}
mp_lexer_free(lex);
mp_obj_t module_fun =
mp_compile(pn, source_name, MP_EMIT_OPT_NONE,
exec_flags & EXEC_FLAG_IS_REPL);
/* check for compile error */
if (mp_obj_is_exception_instance(module_fun))
{
if (exec_flags & EXEC_FLAG_PRINT_EOF)
{
fprintf(stdout, "\x04");
}
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
goto finish;
}
/* execute code */
nlr_buf_t nlr;
struct timespec start;
clock_gettime(CLOCK_REALTIME, &start);
if (nlr_push(&nlr) == 0)
{
// mp_hal_set_interrupt_char(CHAR_CTRL_C); /* allow ctrl-C to interrupt us */
mp_call_function_0(module_fun);
// mp_hal_set_interrupt_char(-1); /* disable interrupt */
nlr_pop();
ret = 1;
if (exec_flags & EXEC_FLAG_PRINT_EOF)
{
fprintf(stdout, "\x04");
}
}
else
{
/* uncaught exception */
// mp_hal_set_interrupt_char(-1); /* disable interrupt */
/* print EOF after normal output */
if (exec_flags & EXEC_FLAG_PRINT_EOF)
{
fprintf(stdout, "\x04");
}
/* check for SystemExit */
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
{
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t) nlr.ret_val);
ret = 0;
}
}
/* display debugging info if wanted */
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info)
{
struct timespec endTime;
clock_gettime(CLOCK_REALTIME, &endTime);
mp_uint_t ticks = ((endTime.tv_sec - start.tv_sec) * 1000) +
((((endTime.tv_nsec / 1000000) + 1000) -
(start.tv_nsec / 1000000)) % 1000);
printf("took " UINT_FMT " ms\n", ticks);
/* qstr info */
{
mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
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);
}
}
finish:
if (exec_flags & EXEC_FLAG_PRINT_EOF)
{
fprintf(stdout, "\x04");
}
return ret;
}
int pyexec_raw_repl(void)
{
vstr_t line;
vstr_init(&line, 32);
raw_repl_reset:
fprintf(stdout, "raw REPL; CTRL-B to exit\r\n");
for (;;)
{
vstr_reset(&line);
fputc('>', stdout);
fflush(stdout);
for (;;)
{
char c = getc(stdin);
if (c == CHAR_CTRL_A)
{
/* reset raw REPL */
goto raw_repl_reset;
}
else if (c == CHAR_CTRL_B)
{
/* change to friendly REPL */
fprintf(stdout, "\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 if (c <= 127)
{
/* let through any other ASCII character */
vstr_add_char(&line, c);
fputc(c, stdout);
}
fflush(stdout);
}
/* indicate reception of command */
fprintf(stdout, "OK");
if (line.len == 0)
{
/* exit for a soft reset */
fprintf(stdout, "\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;
}
}
fflush(stdout);
}
}
int pyexec_friendly_repl(void)
{
vstr_t line;
vstr_init(&line, 32);
friendly_repl_reset:
fprintf(stdout,
"Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE
"; NuttX with " CONFIG_ARCH_FAMILY " " CONFIG_ARCH_CHIP "\r\n");
fprintf(stdout, "Type \"help()\" for more information.\r\n");
for (;;)
{
input_restart:
vstr_reset(&line);
int ret = py_readline(&line, ">>> ");
if (ret == CHAR_CTRL_A)
{
/* change to raw REPL */
fprintf(stdout, "\r\n");
vstr_clear(&line);
pyexec_mode_kind = PYEXEC_MODE_RAW_REPL;
return 0;
}
else if (ret == CHAR_CTRL_B)
{
/* reset friendly REPL */
fprintf(stdout, "\r\n");
goto friendly_repl_reset;
}
else if (ret == CHAR_CTRL_C)
{
/* break */
fprintf(stdout, "\r\n");
continue;
}
else if (ret == CHAR_CTRL_D)
{
/* exit for a soft reset */
fprintf(stdout, "\r\n");
vstr_clear(&line);
return PYEXEC_FORCED_EXIT;
}
else if (vstr_len(&line) == 0)
{
continue;
}
while (mp_repl_continue_with_input(vstr_str(&line)))
{
vstr_add_char(&line, '\n');
int ret = py_readline(&line, "... ");
if (ret == CHAR_CTRL_C)
{
/* cancel everything */
fprintf(stdout, "\r\n");
goto input_restart;
}
else if (ret == CHAR_CTRL_D)
{
/* stop entering compound statement */
break;
}
}
mp_lexer_t *lex =
mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line),
vstr_len(&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;
}
}
}
}
/****************************************************************************
* Private Functions
****************************************************************************/
int pyexec_file(const char *filename)
{
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;
}
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0);
}
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);

@ -0,0 +1,65 @@
/****************************************************************************
* examples/micropython/pexec.h
*
* 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.
*
****************************************************************************/
#ifndef __APPS_INTERPRETERS_MICROPYTHON_PYEXEC_H
#define __APPS_INTERPRETERS_MICROPYTHON_PYEXEC_H 1
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PYEXEC_FORCED_EXIT (0x100)
/****************************************************************************
* Public Types
****************************************************************************/
typedef enum
{
PYEXEC_MODE_RAW_REPL,
PYEXEC_MODE_FRIENDLY_REPL,
} pyexec_mode_kind_t;
/****************************************************************************
* Public Data
****************************************************************************/
extern pyexec_mode_kind_t pyexec_mode_kind;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int pyexec_raw_repl(void);
int pyexec_friendly_repl(void);
int pyexec_file(const char *filename);
MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj);
#endif /* __APPS_INTERPRETERS_MICROPYTHON_PYEXEC_H */

@ -0,0 +1 @@
/* qstrs specific to this port */