Compare commits

..

222 Commits
v1.0.1 ... v1.1

Author SHA1 Message Date
Damien George
8340c48389 py: Revert change of include, "" back to <> for mpconfigport.h. 2014-06-12 19:50:17 +01:00
Paul Sokolovsky
fbdf2f1d63 py: Rename builtin "io" to "_io".
Functionality we provide in builtin io module is fairly minimal. Some
code, including CPython stdlib, depends on more functionality. So, there's
a choice to either implement it in C, or move it _io, and let implement other
functionality in Python. 2nd choice is pursued. This setup matches CPython
too (_io is builtin, io is Python-level).
2014-06-12 01:22:25 +03:00
Damien George
8a0801ad24 py: Make 3 functions static. 2014-06-11 19:55:46 +01:00
Damien George
73c98d8709 py: Fix static defn in qstr; include mpconfigport.h with "" (not <>). 2014-06-11 19:18:03 +01:00
Paul Sokolovsky
0c0f446840 objfun: Remove no longer used mp_obj_fun_prepare_simple_args(). 2014-06-11 20:43:47 +03:00
Paul Sokolovsky
f4bf065dac tests: Add testcases for "complicated" args to generator functions. 2014-06-11 20:43:47 +03:00
Paul Sokolovsky
5f4a667ea4 objgenerator: Finish refactor to use mp_setup_code_state(). 2014-06-11 20:43:47 +03:00
Paul Sokolovsky
f77d0c5bb3 objgenerator: First iteration of refactor to use mp_setup_code_state(). 2014-06-11 20:43:47 +03:00
Paul Sokolovsky
49df795d1d objfun: Factor out mp_setup_code_state() function to set up code_state object.
It needs to be reused for generator functions, too.
2014-06-11 20:43:47 +03:00
Damien George
820896746c stmhal, file: Seek to end of file if opened in 'a' mode. 2014-06-11 16:01:52 +01:00
Damien George
b7572ad11b stmhal, file: Implement a,x,+ open modes, seek and tell.
Also now returns correct POSIX errno when an IO operation fails.

Addresses issues #516 and #676.
2014-06-11 15:41:14 +01:00
Damien George
58cbb4d661 py: Implement __contains__ special method. 2014-06-10 23:07:56 +01:00
Paul Sokolovsky
62f7ba7a81 Merge pull request #675 from Rosuav/seq_simplify
Remove unnecessary bounds check from mp_seq_get_fast_slice_indexes.
2014-06-09 23:40:04 +03:00
Chris Angelico
1f44e118f0 Remove unnecessary bounds check from mp_seq_get_fast_slice_indexes.
At this point, start will be >= 0, so checking if stop < 0 is redundant with
checking if start > stop a few lines later.
2014-06-10 03:59:55 +10:00
Paul Sokolovsky
195de3247b objtype: Fix passing of class param to inherited classmethods.
This is getting more and more tangled, but that's old news.
2014-06-08 22:28:44 +03:00
Paul Sokolovsky
639863d36e objtype: Optimize stack usage mp_obj_class_lookup().
As before, instead of pushing constant values on stack again and again, just
pass around pointer to a structure.
2014-06-08 20:50:12 +03:00
Damien George
57b4dfa9c9 stmhal: Fix pyb.bootloader so it works for gcc-4.9.0.
See PR #618.
2014-06-08 14:01:43 +01:00
Damien George
26a95ae1e7 windows: Move include of malloc.h outside #ifdef msvc. 2014-06-08 13:50:57 +01:00
Damien George
4297fed1c3 tests: Run 'micropython' tests on pyboard. 2014-06-08 13:46:03 +01:00
Damien George
70c289a7a6 Merge branch 'marcusva-alloca' 2014-06-08 13:26:02 +01:00
Damien George
4480cb3711 Provide definition of alloca() in mpconfigport.h. 2014-06-08 13:25:33 +01:00
Damien George
df896eceef Merge branch 'alloca' of github.com:marcusva/micropython into marcusva-alloca 2014-06-08 13:18:14 +01:00
Damien George
9e951498b2 tests: Add more tests for default keyword-only args. 2014-06-08 12:58:32 +01:00
Damien George
049a7a8153 py: Simplify function call of a bytecode object. 2014-06-08 00:37:40 +01:00
Damien George
c06427c019 tests: Fix default arg test. 2014-06-08 00:12:32 +01:00
Paul Sokolovsky
b4efac14cd py: Make sure getattr() works with non-interned strings (by interning them). 2014-06-08 01:15:06 +03:00
Damien George
d31a093f9c Merge branch 'master' of github.com:micropython/micropython
Conflicts:
	py/emitglue.c
2014-06-07 22:02:35 +01:00
Paul Sokolovsky
5473f743f3 objtype: Enable __lt__ method support for instances. 2014-06-08 00:01:46 +03:00
Damien George
f0778a7ccb py: Implement default keyword only args.
Should finish addressing issue #524.
2014-06-07 22:01:00 +01:00
Paul Sokolovsky
b9b9354e6c modsys: Add optional support for sys.platform.
Ports which wants to have it, should define MICROPY_PY_SYS_PLATFORM to a
string value they need.
2014-06-07 23:40:04 +03:00
Paul Sokolovsky
7e4a2b0edc py: Add generic mp_not_implemented() func to use instead of assert().
Benefits: won't crash baremetal targets, will provide Python source location
when not implemented feature used (it will no longer provide C source
location, but just grep for error message).
2014-06-07 23:26:27 +03:00
Damien George
aabd83ea20 py: Merge mp_execute_bytecode into fun_bc_call.
This reduces stack usage by 16 words (64 bytes) for stmhal/ port.

See issue #640.
2014-06-07 14:16:08 +01:00
Damien George
82ed3d62f6 py, mk: Revert change where build variables set with ?=.
?= operator does not do delayed expansion (unlike =).
2014-06-07 13:14:45 +01:00
Damien George
a9b5248e18 Merge pull request #672 from marcusva/makefile
toolchain fixes to enable cross compatibility
2014-06-07 13:03:29 +01:00
Damien George
dc931934b3 Merge pull request #674 from marcusva/fbsd-patches
Build patches for FreeBSD (as discussed in the former pull request #666)
2014-06-07 13:00:35 +01:00
Marcus von Appen
585a3394df - Cast the struct stat sb.st_ino field to machine_int_t explicitly to avoid a
cast error in MP_OBJ_NEW_SMALL_INT(). This is necessary for FreeBSD, where
  st_ino is of different size
- If MP_CLOCKS_PER_SEC is defined on the target host, simply define CLOCK_DIV
  as a fraction, regardless of the value of MP_CLOCKS_PER_SEC.
  FreeBSD uses a non-POSIX compliant value of 128 for CLOCKS_PER_SEC
2014-06-07 09:50:18 +02:00
Marcus von Appen
0c90eb1658 - FreeBSD provides alloca() via stdlib.h, in contrast to Linux and Windows
- Move the includes for alloca() intp mpconfigport.h
2014-06-07 09:36:04 +02:00
Marcus von Appen
8ffc02495f - Let the build environment decide about the toolchain to be used, in case
there are special tweaks and paths to be considered. Just provide some
  defaults, in case the values are undefined.
- py-version.sh does not need any bash specific features.
- Use libdl only on Linux for now. FreeBSD provides dl*() calls from libc.
2014-06-07 09:16:42 +02:00
Damien George
c61be8e1e1 Merge pull request #662 from stinos/windows-pathsep
unix: Fix path seperator used depending on OS
2014-06-07 00:05:59 +01:00
Paul Sokolovsky
180751fbf3 Merge pull request #670 from Rosuav/stringhash
Bring the C and Python compute_hash functions into consistency
2014-06-07 00:10:10 +03:00
Chris Angelico
de09caaa37 Bring the C and Python compute_hash functions into consistency 2014-06-07 07:06:18 +10:00
Paul Sokolovsky
d72bc2713a objint: Fix corner case in buffer access. 2014-06-06 23:08:37 +03:00
Paul Sokolovsky
b56a53dfd6 Merge pull request #667 from Rosuav/testfixes
A couple of small fixes to run-tests
2014-06-06 22:23:23 +03:00
Paul Sokolovsky
8c75bd26e2 Merge pull request #668 from dhylands/print-prec
Fix str.modulo when precision is specified.
2014-06-06 22:12:42 +03:00
Dave Hylands
b69f9fa31f Fix str.modulo when precision is specified. 2014-06-05 23:09:02 -07:00
Paul Sokolovsky
380f147d2e modgc: Real 64-bit cleanness. 2014-06-06 03:01:39 +03:00
Paul Sokolovsky
a3ef8087e8 modgc: 64-bit cleanness. 2014-06-06 02:34:17 +03:00
Chris Angelico
047db2299c Turn the Travis CI test skipping mechanism into something more generic 2014-06-06 07:51:01 +10:00
Chris Angelico
88b11b50e5 Figure out the test_name before using it (significant only to Travis skips) 2014-06-06 07:51:01 +10:00
Paul Sokolovsky
755a55f507 modgc: Implement return value for gc.collect(), enable on Unix. 2014-06-05 22:48:02 +03:00
Damien George
d4c2bddd0c py: Raise TypeError when trying to format non-int with %x,%o,%X.
This behaviour follows Python 3.5 standard (in 3.4 it's a
DeprecationWarning which we'd rather make a TypeError).
2014-06-05 19:44:54 +01:00
Paul Sokolovsky
f675ff3957 Merge pull request #665 from Rosuav/naming3.3
Change comments (mainly URLs) to no longer specifically say Python 3.3
2014-06-05 21:17:46 +03:00
Damien George
11de8399fe py: Small changes to objstr.c, including a bug fix.
Some small fixed:

- Combine 'x' and 'X' cases in str format code.

- Remove trailing spaces from some lines.

- Make exception messages consistently begin with lower case (then
needed to change those in objarray and objtuple so the same
constant string data could be used).

- Fix bug with exception message having %c instead of %%c.
2014-06-05 18:57:38 +01:00
Chris Angelico
daf973ae00 Change comments (mainly URLs) to no longer specifically say Python 3.3 2014-06-06 03:51:03 +10:00
Damien George
c074cd38c3 Merge pull request #663 from Rosuav/floatpercentx
Remove tests that fail under CPython 3.5
2014-06-05 18:39:08 +01:00
Paul Sokolovsky
75ce9256b2 objstr: Implement "%(key)s" % {} formatting for strings and dicts.
Also, make sure that args to "*" format specifiers are bounds-checked
properly and don't lead for segfaults in case of mismatch.
2014-06-05 20:06:15 +03:00
Chris Angelico
7a6e09635a Remove tests that fail under CPython 3.5
See http://bugs.python.org/issue19995 for rationale. As micropython currently
aims for Python 3.3 compatibility I have not changed behaviour, but this
change allows the test suite to be run against a newer Python without having
spurious failures.
2014-06-05 22:34:11 +10:00
stijn
df3ab07994 unix: Fix path seperator used depending on OS
';' is the standard seperator used for paths in environment variables on Windows
2014-06-05 12:34:41 +02:00
Paul Sokolovsky
1e82ef3ae8 Merge pull request #660 from Rosuav/assert0
Replace assert(0) with a self-documenting TODO string
2014-06-05 12:11:48 +03:00
Paul Sokolovsky
76c8a4c91b unix: Add setjmp-based GC register helper implementation.
As I suspected for a long time, for x86, register helper doesn't really make
any difference - there's simply not enough register to keep anything in
them for any prolonged time. Anything gets pushed on stack anyway. So, on
x86, uPy passed all tests even with empty reg helper. So, this setjmp
implementation goes as "untested".
2014-06-05 04:32:17 +03:00
Chris Angelico
9ab8ab2117 Replace assert(0) with a self-documenting TODO string 2014-06-05 06:05:57 +10:00
Damien George
30583f58d5 Merge pull request #653 from Metallicow/switch-example-correction
remove `__doc__ =` and fix tweak doc diffs
2014-06-04 13:46:35 +01:00
Damien George
95fd3528c1 Merge pull request #650 from bvernoux/master
micropython port for HydraBus
2014-06-03 19:29:03 +01:00
Damien George
9b967dd3cd Merge pull request #655 from Rosuav/master
Two small changes
2014-06-03 19:25:37 +01:00
Chris Angelico
4867413e69 Simplify detection of quote characters in mp_str_print_quoted.
Once a double quote has been found, the subsequent discovery of a single quote
won't change behaviour at all, so don't bother looking for one.
2014-06-04 03:26:40 +10:00
bvernoux
82560fce75 Merge branch 'master' of https://github.com/micropython/micropython 2014-06-03 19:26:34 +02:00
Chris Angelico
29bf7393c1 Correct file reference (there's no qstrraw.h) 2014-06-04 03:15:46 +10:00
bvernoux
0a1dbfe02f Merge branch 'master' of https://github.com/bvernoux/micropython
Conflicts:
	README.md
2014-06-03 19:00:31 +02:00
bvernoux
c3c353d7f1 Cleanup/removed specific stuff specific to HydraBus (except board). 2014-06-03 18:59:24 +02:00
Metallicow
3d5ffa8318 remove __doc__ = and fix tweak doc diffs 2014-06-03 07:46:12 -06:00
Damien George
b294a7e3c9 py: Properly fix configuration of float and math module. 2014-06-03 13:43:20 +01:00
Damien George
3f52262465 py: Allow tail call optimisation in mp_call_function_n_kw.
This saves 4 words of stack space per Python call.
2014-06-03 13:40:16 +01:00
Damien George
65ec33200a py: Fix configuration of math module. 2014-06-03 12:33:38 +00:00
Damien George
bcb6ca4d5e py: Implement full behaviour of dict.update(), and dict().
Add keyword args to dict.update(), and ability to take a dictionary as
argument.

dict() class constructor can now use dict.update() directly.

This patch loses fast path for dict(other_dict), but is that really
needed?  Any anyway, this idiom will now re-hash the dictionary, so is
arguably more memory efficient.

Addresses issue #647.
2014-06-03 12:53:44 +01:00
Damien George
07995e9479 Merge pull request #649 from pfalcon/multi-opt
Support multiple bytecode optimisation levels
2014-06-03 10:46:36 +01:00
Paul Sokolovsky
411732e93b vm: If there's no lineno info, set lineno in traceback to 0, not 1.
To clearly signify that lineno is not known.
2014-06-03 12:32:59 +03:00
Paul Sokolovsky
b8f117dd32 py: For optimization level -O3 and higher, remove lineno info from bytecode. 2014-06-03 12:32:59 +03:00
Paul Sokolovsky
d3439d0c60 py: Instead of having "debug on" var, have "optimization level" var.
This allows to have multiple "optimization" levels (CPython has two
(-OO removes docstrings), we can have more).
2014-06-03 12:32:59 +03:00
Paul Sokolovsky
509c7a7854 Merge pull request #651 from dhylands/fix-af-csv2
Add missing commas to stm32f4xx-af.csv
2014-06-03 11:16:31 +03:00
Dave Hylands
4e0573e5cf Add missing commas to stm32f4xx-af.csv 2014-06-02 23:11:14 -07:00
Paul Sokolovsky
f753971e5d showbc: Make micropython -v also dump bytecode in hex form. 2014-06-03 01:39:13 +03:00
Paul Sokolovsky
a4ac5b9f05 showbc: Make sure it's possible to trace MAKE_FUNCTION arg to actual bytecode. 2014-06-03 01:26:51 +03:00
Paul Sokolovsky
dd0dee3afc unix: Properly print script filename in case of error. 2014-06-03 01:26:43 +03:00
Benjamin Vernoux
2abfeebf4a Update README.md 2014-06-02 22:09:47 +02:00
bvernoux
65a97e8d9c Merge branch 'master' of https://github.com/bvernoux/micropython 2014-06-02 22:09:20 +02:00
bvernoux
586f02a015 HydraBus board 2014-06-02 22:08:59 +02:00
Benjamin Vernoux
a5892a13b4 Update README.md 2014-06-02 22:04:37 +02:00
Benjamin Vernoux
a7d963d171 Update README.md 2014-06-02 22:03:22 +02:00
Benjamin Vernoux
d7da92a8f0 Update README.md 2014-06-02 21:54:48 +02:00
Benjamin Vernoux
8db7804496 Update README.md 2014-06-02 21:53:52 +02:00
bvernoux
569aa90137 micropython port for HydraBus 2014-06-02 21:43:02 +02:00
Paul Sokolovsky
8bf8404c15 showbc: Print code block header at the beginning, not in the middle of dump.
Also, dump code block in bytes.
2014-06-02 16:35:57 +03:00
Paul Sokolovsky
b325d25e46 lexer: Add another comment for somewhat obscure way __debug__ is handled. 2014-06-02 16:35:57 +03:00
Paul Sokolovsky
62798831be modstruct: Add one more extension to typecodes - 'S', a pointer to C string.
Also, add comment with description of extension to CPython's typecodes.
2014-06-02 16:35:56 +03:00
Damien George
b55a59de4c Merge branch 'Metallicow-LED-Fix' 2014-06-01 18:35:57 +01:00
Damien George
517f292c8d examples, switch: Make run_loop take sequence of LED objects. 2014-06-01 18:34:58 +01:00
Damien George
15a5738e1d Merge branch 'LED-Fix' of github.com:Metallicow/micropython into Metallicow-LED-Fix 2014-06-01 18:30:03 +01:00
Damien George
fcc9cf63f1 py, str: Replace enum with actual function pointer.
This way, it's slightly more efficient, uses less ROM (60 bytes less
for stmhal), and doesn't require to raise exception if bad operation
given.
2014-06-01 18:22:09 +01:00
Damien George
f1dbd78b30 stmhal: Document pyb.Accel() constructor, that it takes time to start. 2014-06-01 17:57:06 +01:00
Metallicow
9500e98433 __doc__ switch, make importable, and easy to test 2014-06-01 08:18:13 -06:00
Damien George
f917f06384 bare-arm: Disable slice and set. 2014-06-01 13:49:54 +01:00
Damien George
c49ddb9315 py: Fix configurability of builtin slice. 2014-06-01 13:49:35 +01:00
Damien George
3ebd4d0cae py: Add option to disable set() object (enabled by default). 2014-06-01 13:46:47 +01:00
Damien George
fb510b3bf9 Rename bultins config variables to MICROPY_PY_BUILTINS_*.
This renames:
MICROPY_PY_FROZENSET -> MICROPY_PY_BUILTINS_FROZENSET
MICROPY_PY_PROPERTY -> MICROPY_PY_BUILTINS_PROPERTY
MICROPY_PY_SLICE -> MICROPY_PY_BUILTINS_SLICE
MICROPY_ENABLE_FLOAT -> MICROPY_PY_BUILTINS_FLOAT

See issue #35 for discussion.
2014-06-01 13:32:54 +01:00
Damien George
c60a261ef0 py, vm: Replace save_ip, save_sp with code_state->{ip, sp}.
This may seem a bit of a risky change, in that it may introduce crazy
bugs with respect to volatile variables in the VM loop.  But, I think it
should be fine: code_state points to some external memory, so the
compiler should always read/write to that memory when accessing the
ip/sp variables (ie not put them in registers).

Anyway, it passes all tests and improves on all efficiency fronts: about
2-4% faster (64-bit unix), 16 bytes less stack space per call (64-bit
unix) and slightly less executable size (unix and stmhal).

The reason it's more efficient is save_ip and save_sp were volatile
variables, so were anyway stored on the stack (in memory, not regs).
Thus converting them to code_state->{ip, sp} doesn't cost an extra
memory dereference (except maybe to get code_state, but that can be put
in a register and then made more efficient for other uses of it).
2014-06-01 12:32:28 +01:00
Damien George
c7969857f4 Merge branch 'pfalcon-vm-alloca' 2014-06-01 12:08:55 +01:00
Damien George
1b87d1098a Merge branch 'vm-alloca' of github.com:pfalcon/micropython into pfalcon-vm-alloca
Conflicts:
	py/vm.c

Fixed stack underflow check.  Use UINT_FMT/INT_FMT where necessary.
Specify maximum VM-stack byte size by multiple of machine word size, so
that on 64 bit machines it has same functionality as 32 bit.
2014-06-01 12:06:17 +01:00
Metallicow
f94cc975a2 Add switch test example 2014-05-31 23:15:04 -06:00
Metallicow
fa82aa81c0 LED Fix 2014-05-31 23:10:10 -06:00
Damien George
6c13d7965e Merge branch 'master' of github.com:micropython/micropython 2014-05-31 18:35:00 +01:00
Damien George
4d659f566f tests: Add feature test for when heap allocation is disabled. 2014-05-31 18:33:16 +01:00
Damien George
6e18835b94 Merge pull request #643 from dhylands/fix-af-csv
Add a comma to make the .csv look proper in github
2014-05-31 18:13:28 +01:00
Damien George
a053e37b2c tests: Change --test_dirs to --test-dirs. 2014-05-31 18:11:01 +01:00
Damien George
e7412ab37b Merge pull request #632 from stinos/tests-dir-argument
tests: Add argument to allow specifying which directories to test
2014-05-31 18:11:03 +01:00
Damien George
5b5562c1d1 py: Fix stack underflow with optimised for loop. 2014-05-31 17:59:11 +01:00
Damien George
049a01d148 tests: Add another test for break-from-for-loop. 2014-05-31 16:56:15 +01:00
Paul Sokolovsky
b4ebad3310 vm: Factor out structure with code execution state and pass it around.
This improves stack usage in callers to mp_execute_bytecode2, and is step
forward towards unifying execution interface for function and generators
(which is important because generators don't even support full forms
of arguments passing (keywords, etc.)).
2014-05-31 18:22:01 +03:00
Paul Sokolovsky
b16523aa95 vm: Don't unconditionally allocate state on stack, do that only if needed.
This makes sure that only as much stack allocated as actually used, reducing
stack usage for each Python function call.
2014-05-31 18:19:33 +03:00
Paul Sokolovsky
ff8da0b835 vm: Detect stack underflow in addition to overflow. 2014-05-31 18:14:54 +03:00
Paul Sokolovsky
ae9c82d5f3 objstr: str_uni_istype(): Spurious whitespace on empty lines. 2014-05-31 11:00:25 +03:00
Paul Sokolovsky
f69b9d379c objstr: str_uni_istype(): Codestyle. 2014-05-31 10:59:34 +03:00
Paul Sokolovsky
69a8b23651 Merge pull request #644 from kimbauters/master
add methods isspace(), isalpha(), isdigit(), isupper() and islower() to str
2014-05-31 10:52:20 +03:00
Kim Bauters
a3f4b83018 add methods isspace(), isalpha(), isdigit(), isupper() and islower() to str 2014-05-31 07:30:57 +01:00
Dave Hylands
b5fb9b22e2 Add a comma to make the .csv look proper in github 2014-05-30 22:18:52 -07:00
Paul Sokolovsky
1f07b7e3c3 py: Reformat few long functions argument lists for clarity. 2014-05-31 03:36:37 +03:00
Paul Sokolovsky
3dfa76cb85 unix: 64-bit cleanness. 2014-05-31 03:19:15 +03:00
Paul Sokolovsky
914bcf16d8 unix: Add poorman's stack usage info to mem_info() dump. 2014-05-31 02:34:39 +03:00
Paul Sokolovsky
b30a777ace objfun: Typo fixes in comments. 2014-05-31 02:24:47 +03:00
Paul Sokolovsky
347b3a3d1f modsocket: Add some comments on intended usage/API design of module. 2014-05-31 01:48:26 +03:00
Paul Sokolovsky
50b08c920a modsocket: Remove stale ifdef. 2014-05-31 01:41:41 +03:00
Paul Sokolovsky
ccd0e0afcd tests: Add test for break in for.
For #635 / 25c84643b6.
2014-05-31 00:43:41 +03:00
Damien George
25c84643b6 py: Fix break from within a for loop.
Needed to pop the iterator object when breaking out of a for loop.  Need
also to be careful to unwind exception handler before popping iterator.

Addresses issue #635.
2014-05-30 15:20:41 +01:00
Paul Sokolovsky
8827682b35 objstr: *strip(): If nothing is stripped, don't create dup string. 2014-05-30 03:15:17 +03:00
Paul Sokolovsky
bcdffe53c6 objstr: *strip(): Fix handling of one-char subject strings. 2014-05-30 03:15:17 +03:00
Paul Sokolovsky
059f95b2cb Merge pull request #633 from stinos/msvc-fix-genhdr-dep
msvc: Only update generated headers when there are changes
2014-05-30 02:48:04 +03:00
Paul Sokolovsky
97953f6ce7 qemu-arm: Add port README.
Based on https://github.com/micropython/micropython/pull/630 by @errordeveloper.
2014-05-30 02:40:09 +03:00
Damien George
f55cf10101 py: Implement bignum '&' with negatives on lhs and rhs.
Needs proper coverage testing.  Doesn't implement -ve & -ve.
Addresses issue #611.
2014-05-29 15:01:49 +01:00
stijn
48d641e41a msvc: Only update generated headers when there are changes
This fixes generating the headers casuing complete rebuilds,
even when the headere's content didn't really change.
2014-05-28 16:03:38 +02:00
Damien George
d1e355ea8e py: Fix check of small-int overflow when parsing ints.
Also unifies use of SMALL_INT_FITS macro across parser and runtime.
2014-05-28 14:51:12 +01:00
Damien George
813ed3bda6 py: Make int(<longint>) work by just returning the longint. 2014-05-28 14:09:46 +01:00
Damien George
503d611033 py: Implement long int parsing in int(...).
Addresses issue #627.
2014-05-28 14:07:21 +01:00
Paul Sokolovsky
1d567592b1 unix/gccollect.c: Make Clang workaround apply only to it. Unbreaks gcc builds. 2014-05-28 15:37:22 +03:00
stijn
8ac3b578e5 tests: Add argument to allow specifying which directories to test 2014-05-28 14:33:30 +02:00
Paul Sokolovsky
168a9ce863 Revert "Fix DEBUG=1 builds"
This reverts commit 6e76f7bc90.

This patch tries to workaround a previous clang workaround. Instead of going
into workaround of workaround spiral, the original workaround should be tamed.
2014-05-28 15:28:30 +03:00
Damien George
ae13758dd7 Merge pull request #631 from stinos/fix-win-def
windows: Complete rename of MICROPY_PATH_MAX to MICROPY_ALLOC_PATH_MAX (...
2014-05-28 13:10:03 +01:00
Damien George
4de2fe10b4 Merge pull request #629 from dhylands/fix-unix-debug
Fix unix DEBUG=1 builds
2014-05-28 13:00:02 +01:00
stijn
34c24a0fc2 windows: Complete rename of MICROPY_PATH_MAX to MICROPY_ALLOC_PATH_MAX (58ebde4) 2014-05-27 14:35:56 +02:00
Dave Hylands
6e76f7bc90 Fix DEBUG=1 builds
Without this fix, I get the following error:

CC gccollect.c
gccollect.c: In function ‘gc_helper_get_regs’:
gccollect.c:63:1: error: bp cannot be used in asm here
2014-05-26 16:29:24 -07:00
Paul Sokolovsky
0405b2210d modos: stat(): Accept bytes argument. 2014-05-26 02:02:47 +03:00
Paul Sokolovsky
d07bf029b7 tests: Add small testcase for 3-arg slices. 2014-05-26 02:02:47 +03:00
Damien George
d8675541a9 py, vm: Where possible, make variables local to each opcode.
This helps the compiler do its optimisation, makes it clear which
variables are local per opcode and which global, and makes it consistent
when extra variables are needed in an opcode (in addition to old obj1,
obj2 pair, for example).

Could also make unum local, but that's for another time.
2014-05-25 22:58:04 +01:00
Damien George
f600a6a085 py: Slightly improve efficiency of mp_obj_new_str; rename str_new.
Reorder interning logic in mp_obj_new_str, to be more efficient.

str_new is globally accessible, so should be prefixed with mp_obj_.
2014-05-25 22:34:34 +01:00
Damien George
2617eebf2f Change const byte* to const char* where sensible.
This removes need for some casts (at least, more than it adds need
for new casts!).
2014-05-25 22:27:57 +01:00
Damien George
f88fc7bd23 Merge branch 'pfalcon-keep-strings-uninterned' 2014-05-25 22:13:47 +01:00
Damien George
5042bce8fb py: Don't automatically intern strings in parser.
This completes non-automatic interning of strings in the parser, so that
doc strings don't take up RAM.  It complicates the parser and compiler,
and bloats stmhal by about 300 bytes.  It's complicated because now
there are 2 kinds of parse-nodes that can be strings: interned leaves
and non-interned structs.
2014-05-25 22:06:06 +01:00
Paul Sokolovsky
5fd5af98d0 objlist: Implement support for arbitrary (3-arg) slices. 2014-05-25 22:12:56 +03:00
Paul Sokolovsky
de4b9329f9 py: Refactor slice helpers, preparing to support arbitrary slicing. 2014-05-25 21:21:57 +03:00
Damien George
3aaabd11a0 Merge branch 'keep-strings-uninterned' of github.com:pfalcon/micropython into pfalcon-keep-strings-uninterned
Conflicts:
	py/parse.c
2014-05-25 13:19:31 +01:00
Paul Sokolovsky
ff4b6daa4f sequence: Throw exception for not implemented slice steps. 2014-05-25 03:02:57 +03:00
Paul Sokolovsky
2705f4c782 objlist: Implement growing slice assignment.
This means that complete slice operations are supported for lists (but not
for bytearray's and array.array's).
2014-05-25 02:36:12 +03:00
Paul Sokolovsky
69d081a7cf py: Handle case of slice start > stop in common sequence function. 2014-05-25 02:29:40 +03:00
Paul Sokolovsky
afaaf535e6 objslice: Support arbitrary objects start, stop, and step.
Older int-only encoding is not expressive enough to support arbitrary slice
assignment operations.
2014-05-25 01:42:24 +03:00
Damien George
7a4ddd2428 Add SystemExit exception and use it in unix/ and stmhal/ ports.
Addresses issue #598.
2014-05-24 23:32:19 +01:00
Damien George
ee3fd46f13 Rename configuration variables controling Python features.
Now of the form MICROPY_PY_*.  See issue #35.
2014-05-24 23:03:12 +01:00
Paul Sokolovsky
d0ceb04b90 modsocket: 64-bit cleanness. 2014-05-24 23:00:09 +03:00
Paul Sokolovsky
d098c6bf85 objstr: Implement .endswith(). 2014-05-24 22:46:51 +03:00
Paul Sokolovsky
561789d718 unix modsocket: Make .makefile() method more compliant.
.makefile() should allow to specify which stream time to create - byte
or text.
2014-05-24 21:24:37 +03:00
Paul Sokolovsky
806ea1f6ca py: Initial attempts to actually allow implementing __new__ in Python.
Caveat is that __new__ should recurse to base class __new__, and ultimately,
object.__new__ is what handles instance allocation.
2014-05-22 00:32:00 +03:00
Paul Sokolovsky
0c937fa25a objobject: Fix arguments to __init__(). 2014-05-21 23:10:48 +03:00
Damien George
efaef6eea3 unix: Fix casting issue, int to small int object. 2014-05-21 20:53:56 +01:00
Damien George
90886807a1 Merge branch 'master' of github.com:micropython/micropython 2014-05-21 20:35:02 +01:00
Damien George
58ebde4664 Tidy up some configuration options.
MP_ALLOC_* -> MICROPY_ALLOC_*
MICROPY_PATH_MAX -> MICROPY_ALLOC_PATH_MAX
MICROPY_ENABLE_REPL_HELPERS -> MICROPY_HELPER_REPL
MICROPY_ENABLE_LEXER_UNIX -> MICROPY_HELPER_LEXER_UNIX
MICROPY_EXTRA_* -> MICROPY_PORT_*

See issue #35.
2014-05-21 20:32:59 +01:00
Paul Sokolovsky
a8408a8abe objtype: super: Fall back to "object" lookup as last resort.
Also, define object.__init__() (semantically empty, purely CPython compat
measure). Addresses #520.
2014-05-21 22:27:03 +03:00
Paul Sokolovsky
6a410789b8 objtype: super: Add stop condition for looking up in base types. 2014-05-21 22:27:03 +03:00
Damien George
aa7cf6f72f stm: Remove long-obsolete stm/ port. 2014-05-21 20:14:27 +01:00
Damien George
63436ce22e unix, Mac support: Generate order.def via Makefile. 2014-05-21 19:56:54 +01:00
Damien George
0fd01683c6 Merge pull request #607 from Anton-2/osx-clang
Allow compilation of unix port under clang on OS X
2014-05-21 19:51:05 +01:00
Damien George
6ac5dced24 py: Rename MP_OBJ_NOT_SUPPORTED to MP_OBJ_NULL.
See issue #608 for justification.
2014-05-21 19:42:43 +01:00
Damien George
6d197740cf stmhal: Stop USB before entering DFU by software. 2014-05-21 19:25:34 +01:00
Paul Sokolovsky
008343f640 Merge pull request #621 from stinos/migw-w64-fix
windows: Fix compilation with mingw-w64 so it uses correct printf implem...
2014-05-20 16:38:16 +03:00
Paul Sokolovsky
053765414c modstruct: struct_calcsize: Fix case of uninitialized var. 2014-05-20 16:34:05 +03:00
stijn
32acd4b9f1 windows: Fix compilation with mingw-w64 so it uses correct printf implementations
Without this flag, mingw-w64 uses the MS implementations of snpintf and the likes.
This is not really a problem since they work with the the fixes provided for msvc,
but due to the way mingw-w64's stdio.h is structured we cannot get it to use the fixes.
2014-05-20 12:14:28 +02:00
Paul Sokolovsky
44a949d58c qemu-arm: Disable "io" module. 2014-05-19 22:33:35 +03:00
Paul Sokolovsky
9e29666bf9 py: Implement proper separation between io.FileIO and io.TextIOWrapper.
io.FileIO is binary I/O, ans actually optional. Default file type is
io.TextIOWrapper, which provides str results. CPython3 explicitly describes
io.TextIOWrapper as buffered I/O, but we don't have buffering support yet
anyway.
2014-05-19 21:56:07 +03:00
Paul Sokolovsky
52386cafa0 objexcept: Implement explicit __init__ method, useful for subclasses. 2014-05-19 21:56:07 +03:00
Paul Sokolovsky
66ab571cca tests: Update subclass-native2.py for __new__/__init__ refactor.
Now case of subclassing tuple works, and list is broken, see comments.
2014-05-19 21:56:07 +03:00
Paul Sokolovsky
13684fd60b objtype: Separate __new__ and __init__ methods.
Now schedule is: for native types, we call ->make_new() C-level method, which
should perform actions of __new__ and __init__ (note that this is not
compliant, but is efficient), but for user types, __new__ and __init__ are
called as expected.

Also, make sure we convert scalar attribute value to a bound-pair tight in
mp_obj_class_lookup() method, which avoids converting it again and again in
its callers.
2014-05-19 21:56:06 +03:00
Damien George
eee31288dd stmhal: Fix DAC documentation: need to convert float to int for buf. 2014-05-19 19:08:12 +01:00
Damien George
2de4d59171 stmhal: Fix write_timed function for DAC(2).
Addresses issue #617.
2014-05-19 18:58:53 +01:00
Damien George
f905ebb173 stmhal: Make pyb.bootloader take no arguments. 2014-05-19 18:26:51 +01:00
Damien George
404f7cf902 Merge pull request #618 from swegener/jump-to-bootloader
Jump to bootloader
2014-05-19 18:13:34 +01:00
Sven Wegener
9bf4f7e3d3 stmhal: Remap system flash and adjust addresses
Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2014-05-18 13:15:02 +02:00
Sven Wegener
7ae8e4b679 stmhal: Activate bootloader with pyb.bootloader()
Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2014-05-18 12:51:21 +02:00
Paul Sokolovsky
5cdff5fa61 Merge pull request #615 from swegener/for-upstream
py: Fix mp_obj_t -> mp_const_obj_t for mp_obj_int_get_checked()
2014-05-17 23:30:00 +03:00
Sven Wegener
7ba0fedf13 py: Fix mp_obj_t -> mp_const_obj_t for mp_obj_int_get_checked()
Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2014-05-17 11:21:12 +02:00
Paul Sokolovsky
bf27140193 py: More mp_identity usage. 2014-05-17 11:20:10 +03:00
Paul Sokolovsky
ab7bf28489 py: More const usage. 2014-05-17 11:20:10 +03:00
Paul Sokolovsky
c18ef2a9dd objstr: startswith(): Accept optional "start" arg. 2014-05-15 21:33:18 +03:00
Paul Sokolovsky
70328e419a py: Implement more complete bytes comparison handling. 2014-05-15 20:58:40 +03:00
Paul Sokolovsky
ad3baec12f sequence: Fix yet another case of improper sequence comparison.
This time, in mp_seq_cmp_bytes(). How many more cases are still lurking?
2014-05-15 19:09:06 +03:00
Paul Sokolovsky
767e45c290 modos: Clean 64-bit issues. 2014-05-15 18:38:54 +03:00
Paul Sokolovsky
a47b64ae2d objstringio: Implement io.BytesIO.
Done in generalized manner, allowing any stream class to be specified as
working with bytes.
2014-05-15 07:28:19 +03:00
Paul Sokolovsky
0c124c3123 unix: Add "_os" module with stat().
stat() is bad function to use using FFI, because its ABI is largely private.
To start with, Glibc .so doesn't even have "stat" symbol. Then, layout of
struct stat is too implementation-dependent. So, introduce _os to deal
with stat() and other similar cases.
2014-05-14 22:08:45 +03:00
Paul Sokolovsky
2a27365854 objstr.c: Partial implementation of .rsplit().
sep=None is TODO.
2014-05-14 02:42:20 +03:00
Damien George
51fab28e94 py: Improve mpz_and function.
This should now have correct (and optimal) behaviour.
2014-05-13 22:58:00 +01:00
Damien George
f6e430f77f Merge pull request #600 from stinos/unix-exitcode
unix: Use standard return codes for main
2014-05-13 22:39:35 +01:00
Damien George
aeeb448eb6 Merge pull request #613 from pfalcon/pauls-copyr
py, unix: Add copyright for modules I worked closely on.
2014-05-13 22:36:36 +01:00
Paul Sokolovsky
da9f0924ef py, unix: Add copyright for modules I worked closely on. 2014-05-13 18:41:25 +03:00
Paul Sokolovsky
7074f25768 tests/int-long.py: Try to expose issue with recent "&" optimization. 2014-05-13 08:24:54 +03:00
Damien George
561e425903 py: Fix bug in mpz_and function.
Addresses issue #610.
2014-05-12 23:27:29 +01:00
Damien George
cc97446ca5 unix: Implement -O option to turn off __debug__ flag. 2014-05-12 23:14:52 +01:00
Damien George
915197a8f9 py: Remove emit_glue init and deinit. Needed only for debugging.
Debugging output for emit_glue now simplified so that the init and
deinit functions are no longer needed.
2014-05-12 23:11:14 +01:00
Damien George
97f9a2813e py: Add support for __debug__ constant.
__debug__ now resolves to True or False.  Its value needs to be set by
mp_set_debug().

TODO: call mp_set_debug in unix/ port.

TODO: optimise away "if False:" statements in compiler.
2014-05-12 23:07:34 +01:00
Damien George
96f137b24a py: Rename BYTE_CODE to BYTECODE (this was missed in previous rename). 2014-05-12 22:35:37 +01:00
stijn
f42dbb98d1 unix: Fix linker errors when time/ffi modules are disabled
When disabling these via mpconfigport.mk or on the commandline,
the correspoding build options are not set and the sources are not
built so the modules should not be added to the
MICROPY_EXTRA_BUILTIN_MODULES list since they are undefined.
2014-05-13 00:03:24 +03:00
Paul Sokolovsky
df94b717b4 modstruct: Implement count specifier for strings (e.g. "100s").
Infra for counts of other types is there, need last mile to be implemented.
2014-05-12 23:45:50 +03:00
Antonin ENFRUN
da1fffaa09 Fix some unused variables, and silence a clang warning about initialization override in vmentrytable.h 2014-05-12 09:06:18 +02:00
Antonin ENFRUN
ceac71f1f5 unix: Add asm statements needed to read registers with clang. Code generated by gcc 4.9.0 is unchanged (same statements, different order).
Both are inefficient, saving unmodified registers on the stack.
2014-05-12 09:06:18 +02:00
Antonin ENFRUN
1b901c320b tests: create result file for test/basics/memoryerror.py .
On Mac OS "python3 test/basics/memoryerror.py" never runs out of memory, the process is frozen by the os before.
2014-05-12 00:13:10 +02:00
Antonin ENFRUN
6caae0bcb1 unix: Create __bss_start and _end symbols for Mach-O targets.
It's a hack, but can't find a cleaner way to do it.
2014-05-12 00:13:10 +02:00
stijn
9e040b7cd8 unix: Use standard return codes for main
As in the CPython manual: "Unix programs generally use 2 for
command line syntax errors and 1 for all other kind of errors"
2014-05-11 19:23:30 +02:00
Paul Sokolovsky
9e76b1181b Draft approach towards resolving https://github.com/micropython/micropython/issues/560#issuecomment-42213955 2014-05-08 22:43:46 +03:00
381 changed files with 3977 additions and 94998 deletions

View File

@@ -29,15 +29,13 @@ Major components in this repository:
- py/ -- the core Python implementation, including compiler and runtime.
- unix/ -- a version of Micro Python that runs on Unix.
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
with an STM32F405RG (using ST's new Cube HAL drivers).
with an STM32F405RG (using ST's Cube HAL drivers).
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
(preliminary but functional).
Additional components:
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Start
with this if you want to port Micro Python to another microcontroller.
- stm/ -- obsolete version of Micro Python for the Micro Python board
that uses ST's old peripheral drivers.
- unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing).
- tests/ -- test framework and test scripts.
- tools/ -- various tools, including the pyboard.py module.

View File

@@ -2,26 +2,29 @@
// 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_ENABLE_REPL_HELPERS (0)
#define MICROPY_ENABLE_LEXER_UNIX (0)
#define MICROPY_HELPER_REPL (0)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_MOD_COLLECTIONS (0)
#define MICROPY_ENABLE_MOD_MATH (0)
#define MICROPY_ENABLE_MOD_CMATH (0)
#define MICROPY_ENABLE_MOD_IO (0)
#define MICROPY_ENABLE_MOD_STRUCT (0)
#define MICROPY_ENABLE_MOD_SYS (0)
#define MICROPY_ENABLE_PROPERTY (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_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_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
#define MICROPY_PATH_MAX (512)
// type definitions for the specific machine
@@ -37,6 +40,8 @@ typedef const void *machine_const_ptr_t; // must be of pointer size
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
#define MICROPY_EXTRA_BUILTINS \
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
// We need to provide a declaration/definition of alloca()
#include <alloca.h>

View File

@@ -2,9 +2,9 @@ import pyb
def led_angle(seconds_to_run_for):
# make LED objects
l1 = pyb.Led(1)
l2 = pyb.Led(2)
accel = pyb.Accel()
l1 = pyb.LED(1)
l2 = pyb.LED(2)
accel = pyb.Accel()
for i in range(20 * seconds_to_run_for):
# get x-axis

45
examples/switch.py Normal file
View File

@@ -0,0 +1,45 @@
"""
switch.py
=========
Light up some leds when the USR switch on the pyboard is pressed.
Example Usage::
Micro Python v1.0.1 on 2014-05-12; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> import switch
>>> switch.run_loop()
Loop started.
Press Ctrl+C to break out of the loop.
"""
import pyb
switch = pyb.Switch()
red_led = pyb.LED(1)
green_led = pyb.LED(2)
orange_led = pyb.LED(3)
blue_led = pyb.LED(4)
all_leds = (red_led, green_led, orange_led, blue_led)
def run_loop(leds=all_leds):
"""
Start the loop.
:param `leds`: Which LEDs to light up upon switch press.
:type `leds`: sequence of LED objects
"""
print('Loop started.\nPress Ctrl+C to break out of the loop.')
while 1:
try:
if switch():
[led.on() for led in leds]
else:
[led.off() for led in leds]
except OSError: # VCPInterrupt # Ctrl+C in interpreter mode.
break
if __name__ == '__main__':
run_loop()

19
py/bc.h
View File

@@ -36,9 +36,22 @@ typedef struct _mp_exc_stack {
byte opcode;
} mp_exc_stack_t;
mp_vm_return_kind_t mp_execute_bytecode(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret);
mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, volatile mp_obj_t inject_exc);
void mp_bytecode_print(const byte *code, int len);
typedef struct _mp_code_state {
const byte *code_info;
const byte *ip;
mp_obj_t *sp;
// bit 0 is saved currently_in_except_block value
mp_exc_stack_t *exc_sp;
uint n_state;
// Variable-length
mp_obj_t state[0];
// Variable-length, never accessed by name, only as (void*)(state + n_state)
//mp_exc_stack_t exc_state[0];
} mp_code_state;
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
void mp_bytecode_print(const void *descr, const byte *code, int len);
void mp_bytecode_print2(const byte *code, int len);
// Helper macros to access pointer with least significant bit holding a flag

View File

@@ -26,6 +26,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "misc.h"
@@ -75,7 +76,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
case 'q': case 'Q':
// TODO: This is for x86
align = sizeof(int); size = sizeof(long long); break;
case 'P': case 'O':
case 'P': case 'O': case 'S':
align = size = sizeof(void*); break;
}
}
@@ -114,7 +115,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
// TODO: Explode API more to cover signedness
return mp_obj_new_int_from_ll(((long long*)p)[index]);
#endif
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case 'f':
return mp_obj_new_float(((float*)p)[index]);
case 'd':
@@ -161,6 +162,8 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
*ptr += size;
if (val_type == 'O') {
return (mp_obj_t)val;
} else if (val_type == 'S') {
return mp_obj_new_str((char*)val, strlen((char*)val), false);
} else if (is_signed(val_type)) {
return mp_obj_new_int(val);
} else {
@@ -217,7 +220,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
switch (typecode) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case 'f':
((float*)p)[index] = mp_obj_float_get(val_in);
break;
@@ -260,7 +263,7 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine
((long long*)p)[index] = val;
break;
#endif
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case 'f':
((float*)p)[index] = val;
break;

View File

@@ -37,7 +37,7 @@
#include "runtime.h"
#include "builtin.h"
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
#endif
@@ -104,7 +104,7 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
val = -val;
}
return MP_OBJ_NEW_SMALL_INT(val);
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_float)) {
mp_float_t value = mp_obj_float_get(o_in);
// TODO check for NaN etc
@@ -172,7 +172,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
int ord = mp_obj_get_int(o_in);
if (0 <= ord && ord <= 0x10ffff) {
byte str[1] = {ord};
char str[1] = {ord};
return mp_obj_new_str(str, 1, true);
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
@@ -391,7 +391,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print);
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
vstr_t *vstr = vstr_new();
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
}
@@ -452,12 +452,17 @@ STATIC inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t d
}
STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_QSTR(args[1]));
mp_obj_t attr = args[1];
if (MP_OBJ_IS_TYPE(attr, &mp_type_str)) {
attr = mp_obj_str_intern(attr);
} else if (!MP_OBJ_IS_QSTR(attr)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "string required"));
}
mp_obj_t defval = MP_OBJ_NULL;
if (n_args > 2) {
defval = args[2];
}
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(args[1]), defval);
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(attr), defval);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr);
@@ -466,7 +471,7 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
assert(MP_OBJ_IS_QSTR(attr_in));
mp_obj_t dest[2];
// TODO: https://docs.python.org/3.3/library/functions.html?highlight=hasattr#hasattr
// TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr
// explicitly says "This is implemented by calling getattr(object, name) and seeing
// whether it raises an AttributeError or not.", so we should explicitly wrap this
// in nlr_push and handle exception.

View File

@@ -25,6 +25,7 @@
*/
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args);
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +29,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <alloca.h>
#include "mpconfig.h"
#include "nlr.h"
@@ -54,7 +54,7 @@
#define PATH_SEP_CHAR '/'
mp_import_stat_t stat_dir_or_file(vstr_t *path) {
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
//printf("stat %s\n", vstr_str(path));
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
if (stat == MP_IMPORT_STAT_DIR) {
@@ -68,11 +68,11 @@ mp_import_stat_t stat_dir_or_file(vstr_t *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
// extract the list of paths
uint path_num = 0;
mp_obj_t *path_items;
#if MICROPY_ENABLE_MOD_SYS
#if MICROPY_PY_SYS
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
#endif
@@ -102,7 +102,7 @@ mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
}
}
void do_load(mp_obj_t module_obj, vstr_t *file) {
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
@@ -162,16 +162,6 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
mp_globals_set(old_globals);
}
// TODO: Move to objdict?
STATIC inline mp_obj_t mp_obj_dict_get(mp_obj_t dict_in, mp_obj_t key) {
mp_obj_dict_t *dict = dict_in;
mp_map_elem_t *elem = mp_map_lookup(&dict->map, key, MP_MAP_LOOKUP);
if (elem == NULL) {
return elem;
}
return elem->value;
}
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
#if DEBUG_PRINT
printf("__import__:\n");
@@ -277,7 +267,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
DEBUG_printf("Module not yet loaded\n");
uint last = 0;
VSTR_FIXED(path, MICROPY_PATH_MAX)
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
module_obj = MP_OBJ_NULL;
mp_obj_t top_module_obj = MP_OBJ_NULL;
mp_obj_t outer_module_obj = MP_OBJ_NULL;
@@ -315,9 +305,9 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
if (stat == MP_IMPORT_STAT_DIR) {
DEBUG_printf("%s is dir\n", vstr_str(&path));
// https://docs.python.org/3.3/reference/import.html
// https://docs.python.org/3/reference/import.html
// "Specifically, any module that contains a __path__ attribute is considered a package."
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str((byte*)vstr_str(&path), vstr_len(&path), false));
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false));
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_str(&path, "__init__.py");
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {

View File

@@ -44,27 +44,29 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
{ MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_dict), (mp_obj_t)&mp_type_dict },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enumerate), (mp_obj_t)&mp_type_enumerate },
{ MP_OBJ_NEW_QSTR(MP_QSTR_filter), (mp_obj_t)&mp_type_filter },
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
{ MP_OBJ_NEW_QSTR(MP_QSTR_float), (mp_obj_t)&mp_type_float },
#endif
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
{ MP_OBJ_NEW_QSTR(MP_QSTR_frozenset), (mp_obj_t)&mp_type_frozenset },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
#if MICROPY_ENABLE_PROPERTY
#if MICROPY_PY_BUILTINS_PROPERTY
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_range), (mp_obj_t)&mp_type_range },
#if MICROPY_PY_BUILTINS_SET
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&mp_type_set },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_str), (mp_obj_t)&mp_type_str },
{ MP_OBJ_NEW_QSTR(MP_QSTR_super), (mp_obj_t)&mp_type_super },
{ MP_OBJ_NEW_QSTR(MP_QSTR_tuple), (mp_obj_t)&mp_type_tuple },
@@ -140,7 +142,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
// TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation
// Extra builtins as defined by a port
MICROPY_EXTRA_BUILTINS
MICROPY_PORT_BUILTINS
};
const mp_obj_dict_t mp_builtin_object_dict_obj = {
@@ -159,31 +161,33 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
#if MICROPY_ENABLE_MOD_IO
{ MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io },
#if MICROPY_PY_IO
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
#endif
#if MICROPY_ENABLE_MOD_COLLECTIONS
#if MICROPY_PY_COLLECTIONS
{ MP_OBJ_NEW_QSTR(MP_QSTR__collections), (mp_obj_t)&mp_module_collections },
#endif
#if MICROPY_ENABLE_MOD_STRUCT
#if MICROPY_PY_STRUCT
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_struct },
#endif
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#if MICROPY_PY_MATH
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&mp_module_math },
#if MICROPY_ENABLE_MOD_CMATH
#endif
#if MICROPY_PY_CMATH
{ MP_OBJ_NEW_QSTR(MP_QSTR_cmath), (mp_obj_t)&mp_module_cmath },
#endif
#endif
#if MICROPY_ENABLE_MOD_SYS
#if MICROPY_PY_SYS
{ MP_OBJ_NEW_QSTR(MP_QSTR_sys), (mp_obj_t)&mp_module_sys },
#endif
#if MICROPY_ENABLE_MOD_GC && MICROPY_ENABLE_GC
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
#endif
// extra builtin modules as defined by a port
MICROPY_EXTRA_BUILTIN_MODULES
MICROPY_PORT_BUILTIN_MODULES
};
const mp_obj_dict_t mp_builtin_module_dict_obj = {

View File

@@ -56,6 +56,7 @@ typedef enum {
#include "grammar.h"
#undef DEF_RULE
PN_maximum_number_of,
PN_string, // special node for non-interned string
} pn_kind_t;
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
@@ -72,8 +73,8 @@ typedef struct _compiler_t {
uint next_label;
uint break_label;
uint continue_label;
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
uint16_t continue_label;
int break_continue_except_level;
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
@@ -104,7 +105,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
STATIC const mp_map_elem_t mp_constants_table[] = {
// Extra constants as defined by a port
MICROPY_EXTRA_CONSTANTS
MICROPY_PORT_CONSTANTS
};
STATIC const mp_map_t mp_constants_map = {
@@ -119,7 +120,7 @@ STATIC const mp_map_t mp_constants_map = {
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
if (0) {
// dummy
#if MICROPY_ENABLE_CONST
#if MICROPY_COMP_CONST
} else if (MP_PARSE_NODE_IS_ID(pn)) {
// lookup identifier in table of dynamic constants
qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);
@@ -133,7 +134,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
// fold some parse nodes before folding their arguments
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
#if MICROPY_ENABLE_CONST
#if MICROPY_COMP_CONST
case PN_expr_stmt:
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
@@ -177,6 +178,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
}
break;
#endif
case PN_string:
return pn;
}
// fold arguments
@@ -246,7 +249,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
// shouldn't happen
assert(0);
}
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
if (MP_SMALL_INT_FITS(arg0)) {
//printf("%ld + %ld\n", arg0, arg1);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
@@ -261,7 +264,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
// int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) {
arg0 *= arg1;
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
if (MP_SMALL_INT_FITS(arg0)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
}
@@ -334,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
mp_load_method_maybe(elem->value, q_attr, dest);
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
if (MP_PARSE_FITS_SMALL_INT(val)) {
if (MP_SMALL_INT_FITS(val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
}
}
@@ -426,6 +429,9 @@ void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
#if MICROPY_EMIT_CPYTHON
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
return true;
}
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
return false;
}
@@ -435,9 +441,7 @@ STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
return true;
}
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
uint len;
const byte *str = qstr_data(qstr, &len);
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
bool has_single_quote = false;
bool has_double_quote = false;
for (int i = 0; i < len; i++) {
@@ -476,6 +480,12 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
}
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (machine_uint_t)pns->nodes[1], false);
return;
}
assert(MP_PARSE_NODE_IS_LEAF(pn));
if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
@@ -487,8 +497,13 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst
case MP_PARSE_NODE_ID: assert(0);
case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
case MP_PARSE_NODE_STRING: cpython_c_print_quoted_str(vstr, arg, false); break;
case MP_PARSE_NODE_BYTES: cpython_c_print_quoted_str(vstr, arg, true); break;
case MP_PARSE_NODE_STRING:
case MP_PARSE_NODE_BYTES: {
uint len;
const byte *str = qstr_data(arg, &len);
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
break;
}
case MP_PARSE_NODE_TOKEN:
switch (arg) {
case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break;
@@ -1020,7 +1035,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
if (comp->have_star) {
comp->num_dict_params += 1;
#if !MICROPY_EMIT_CPYTHON
#if MICROPY_EMIT_CPYTHON
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
compile_node(comp, pn_equal);
#else
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
if (comp->num_dict_params == 1) {
// in Micro Python we put the default positional parameters into a tuple using the bytecode
@@ -1033,11 +1051,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
// first default dict param, so make the map
EMIT_ARG(build_map, 0);
}
#endif
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
// compile value then key, then store it to the dict
compile_node(comp, pn_equal);
#if !MICROPY_EMIT_CPYTHON
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
EMIT(store_map);
#endif
} else {
@@ -1147,7 +1164,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
if (attr == MP_QSTR_bytecode) {
*emit_options = MP_EMIT_OPT_BYTE_CODE;
*emit_options = MP_EMIT_OPT_BYTECODE;
#if MICROPY_EMIT_NATIVE
} else if (attr == MP_QSTR_native) {
*emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
@@ -1730,6 +1747,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// And, if the loop never runs, the loop variable should never be assigned
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
START_BREAK_CONTINUE_BLOCK
// note that we don't need to pop anything when breaking from an optimise for loop
uint top_label = comp_next_label(comp);
uint entry_label = comp_next_label(comp);
@@ -1828,6 +1846,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
#endif
START_BREAK_CONTINUE_BLOCK
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
uint pop_label = comp_next_label(comp);
uint end_label = comp_next_label(comp);
@@ -2058,7 +2077,8 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
} else {
// for non-REPL, evaluate then discard the expression
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) {
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
// do nothing with a lonely constant
} else {
compile_node(comp, pns->nodes[0]); // just an expression
@@ -2498,26 +2518,40 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
int n_bytes = 0;
int string_kind = MP_PARSE_NODE_NULL;
for (int i = 0; i < n; i++) {
assert(MP_PARSE_NODE_IS_LEAF(pns->nodes[i]));
int pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
int pn_kind;
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
} else {
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i]));
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
pn_kind = MP_PARSE_NODE_STRING;
n_bytes += (machine_uint_t)pns_string->nodes[1];
}
if (i == 0) {
string_kind = pn_kind;
} else if (pn_kind != string_kind) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "cannot mix bytes and nonbytes literals");
return;
}
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
}
// concatenate string/bytes
byte *q_ptr;
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
for (int i = 0; i < n; i++) {
uint s_len;
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
memcpy(s_dest, s, s_len);
s_dest += s_len;
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
uint s_len;
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
memcpy(s_dest, s, s_len);
s_dest += s_len;
} else {
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
memcpy(s_dest, (const char*)pns_string->nodes[0], (machine_uint_t)pns_string->nodes[1]);
s_dest += (machine_uint_t)pns_string->nodes[1];
}
}
qstr q = qstr_build_end(q_ptr);
@@ -2848,15 +2882,19 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
} else {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
EMIT_ARG(set_line_number, pns->source_line);
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
#if MICROPY_DEBUG_PRINTERS
mp_parse_node_print(pn, 0);
#endif
compile_syntax_error(comp, pn, "internal compiler error");
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (machine_uint_t)pns->nodes[1]), false);
} else {
f(comp, pns);
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
#if MICROPY_DEBUG_PRINTERS
mp_parse_node_print(pn, 0);
#endif
compile_syntax_error(comp, pn, "internal compiler error");
} else {
f(comp, pns);
}
}
}
}
@@ -3033,13 +3071,13 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
// check the first statement for a doc string
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) {
mp_parse_node_struct_t* pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0])) {
int kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]);
if (kind == MP_PARSE_NODE_STRING) {
compile_node(comp, pns->nodes[0]); // a doc string
// store doc string
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0])
&& MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING)
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
// compile the doc string
compile_node(comp, pns->nodes[0]);
// store the doc string
EMIT_ARG(store_id, MP_QSTR___doc__);
}
}
}
#endif

View File

@@ -27,7 +27,7 @@
// These must fit in 8 bits; see scope.h
enum {
MP_EMIT_OPT_NONE,
MP_EMIT_OPT_BYTE_CODE,
MP_EMIT_OPT_BYTECODE,
MP_EMIT_OPT_NATIVE_PYTHON,
MP_EMIT_OPT_VIPER,
MP_EMIT_OPT_ASM_THUMB,

View File

@@ -44,6 +44,8 @@ typedef enum {
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
typedef struct _emit_t emit_t;
typedef struct _emit_method_table_t {

View File

@@ -352,6 +352,10 @@ STATIC void emit_bc_adjust_stack_size(emit_t *emit, int delta) {
STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
#if MICROPY_ENABLE_SOURCE_LINE
if (mp_optimise_value >= 3) {
// If we compile with -O3, don't store line numbers.
return;
}
if (source_line > emit->last_source_line) {
uint bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
uint lines_to_skip = source_line - emit->last_source_line;
@@ -617,11 +621,15 @@ STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
if (except_depth == 0) {
emit_bc_jump(emit, label);
} else {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label);
emit_write_bytecode_byte(emit, except_depth);
if (label & MP_EMIT_BREAK_FROM_FOR) {
// need to pop the iterator if we are breaking out of a for loop
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
}
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
} else {
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | except_depth);
}
}

View File

@@ -49,24 +49,6 @@
#define DEBUG_OP_printf(...) (void)0
#endif
#ifdef WRITE_CODE
FILE *fp_write_code = NULL;
#endif
void mp_emit_glue_init(void) {
#ifdef WRITE_CODE
fp_write_code = fopen("out-code", "wb");
#endif
}
void mp_emit_glue_deinit(void) {
#ifdef WRITE_CODE
if (fp_write_code != NULL) {
fclose(fp_write_code);
}
#endif
}
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
rc->kind = MP_CODE_RESERVED;
@@ -89,17 +71,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
DEBUG_printf(" %s", qstr_str(arg_names[i]));
}
DEBUG_printf("\n");
for (int i = 0; i < 128 && i < len; i++) {
if (i > 0 && i % 16 == 0) {
DEBUG_printf("\n");
}
DEBUG_printf(" %02x", code[i]);
}
DEBUG_printf("\n");
#endif
#if MICROPY_DEBUG_PRINTERS
if (mp_verbose_flag > 0) {
mp_bytecode_print(code, len);
for (int i = 0; i < 128 && i < len; i++) {
if (i > 0 && i % 16 == 0) {
printf("\n");
}
printf(" %02x", code[i]);
}
printf("\n");
mp_bytecode_print(rc, code, len);
}
#endif
}
@@ -123,10 +105,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
DEBUG_printf("\n");
#ifdef WRITE_CODE
if (fp_write_code != NULL) {
fwrite(fun_data, len, 1, fp_write_code);
fflush(fp_write_code);
}
FILE *fp_write_code = fopen("out-code", "wb");
fwrite(fun_data, len, 1, fp_write_code);
fclose(fp_write_code);
#endif
#endif
}
@@ -138,14 +119,14 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
// def_args must be MP_OBJ_NULL or a tuple
assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
// TODO implement default kw args
assert(def_kw_args == MP_OBJ_NULL);
// def_kw_args must be MP_OBJ_NULL or a dict
assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict));
// make the function, depending on the raw code kind
mp_obj_t fun;
switch (rc->kind) {
case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, rc->u_byte.code);
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
break;
case MP_CODE_NATIVE_PY:
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);

View File

@@ -52,9 +52,6 @@ typedef struct _mp_code_t {
};
} mp_raw_code_t;
void mp_emit_glue_init(void);
void mp_emit_glue_deinit(void);
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);

View File

@@ -704,7 +704,7 @@ STATIC void emit_native_load_const_int(emit_t *emit, qstr qst) {
DEBUG_printf("load_const_int %s\n", qstr_str(st));
// for viper: load integer, check fits in 32 bits
emit_native_pre(emit);
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_qstr, qst, REG_ARG_1);
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_load_const_int, qst, REG_ARG_1);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
@@ -1043,7 +1043,7 @@ STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
}
STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
emit_native_jump(emit, label); // TODO properly
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
}
STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {

10
py/gc.c
View File

@@ -231,7 +231,14 @@ STATIC void gc_deal_with_stack_overflow(void) {
}
}
#if MICROPY_PY_GC_COLLECT_RETVAL
uint gc_collected;
#endif
STATIC void gc_sweep(void) {
#if MICROPY_PY_GC_COLLECT_RETVAL
gc_collected = 0;
#endif
// free unmarked heads and their tails
int free_tail = 0;
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
@@ -254,6 +261,9 @@ STATIC void gc_sweep(void) {
}
#endif
free_tail = 1;
#if MICROPY_PY_GC_COLLECT_RETVAL
gc_collected++;
#endif
// fall through to free the head
case AT_TAIL:

View File

@@ -64,6 +64,8 @@ struct _mp_lexer_t {
mp_token_t tok_cur;
};
uint mp_optimise_value;
// TODO replace with a call to a standard function
bool str_strn_equal(const char *str, const char *strn, int len) {
uint i = 0;
@@ -211,8 +213,8 @@ STATIC void next_char(mp_lexer_t *lex) {
void indent_push(mp_lexer_t *lex, uint indent) {
if (lex->num_indent_level >= lex->alloc_indent_level) {
// TODO use m_renew_maybe and somehow indicate an error if it fails... probably by using MP_TOKEN_MEMORY_ERROR
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MP_ALLOC_LEXEL_INDENT_INC);
lex->alloc_indent_level += MP_ALLOC_LEXEL_INDENT_INC;
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);
lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC;
}
lex->indent_level[lex->num_indent_level++] = indent;
}
@@ -303,7 +305,7 @@ STATIC const char *tok_kw[] = {
"while",
"with",
"yield",
NULL,
"__debug__",
};
STATIC int hex_digit(unichar c) {
@@ -687,9 +689,19 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// check for keywords
if (tok->kind == MP_TOKEN_NAME) {
for (int i = 0; tok_kw[i] != NULL; i++) {
// We check for __debug__ here and convert it to its value. This is so
// the parser gives a syntax error on, eg, x.__debug__. Otherwise, we
// need to check for this special token in many places in the compiler.
// TODO improve speed of these string comparisons
//for (int i = 0; tok_kw[i] != NULL; i++) {
for (int i = 0; i < ARRAY_SIZE(tok_kw); i++) {
if (str_strn_equal(tok_kw[i], tok->str, tok->len)) {
tok->kind = MP_TOKEN_KW_FALSE + i;
if (i == ARRAY_SIZE(tok_kw) - 1) {
// tok_kw[ARRAY_SIZE(tok_kw) - 1] == "__debug__"
tok->kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
} else {
tok->kind = MP_TOKEN_KW_FALSE + i;
}
break;
}
}
@@ -715,7 +727,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
lex->column = 1;
lex->emit_dent = 0;
lex->nested_bracket_level = 0;
lex->alloc_indent_level = MP_ALLOC_LEXER_INDENT_INIT;
lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;
lex->num_indent_level = 1;
lex->indent_level = m_new_maybe(uint16_t, lex->alloc_indent_level);
vstr_init(&lex->vstr, 32);

View File

@@ -176,3 +176,5 @@ typedef enum {
mp_import_stat_t mp_import_stat(const char *path);
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
extern uint mp_optimise_value;

View File

@@ -27,7 +27,7 @@
#include "misc.h"
#include "mpconfig.h"
#if MICROPY_ENABLE_LEXER_UNIX
#if MICROPY_HELPER_LEXER_UNIX
#include <stdio.h>
#include <unistd.h>
@@ -81,4 +81,4 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
}
#endif // MICROPY_ENABLE_LEXER_UNIX
#endif // MICROPY_HELPER_LEXER_UNIX

View File

@@ -27,7 +27,8 @@ def compute_hash(qstr):
hash = 5381
for char in qstr:
hash = (hash * 33) ^ ord(char)
return hash & 0xffff
# Make sure that valid hash is never zero, zero means "hash not computed"
return (hash & 0xffff) or 1
def do_work(infiles):
# read the qstrs in from the input files

View File

@@ -96,6 +96,8 @@ bool unichar_isalpha(unichar c);
bool unichar_isprint(unichar c);
bool unichar_isdigit(unichar c);
bool unichar_isxdigit(unichar c);
bool unichar_isupper(unichar c);
bool unichar_islower(unichar c);
unichar unichar_tolower(unichar c);
unichar unichar_toupper(unichar c);

View File

@@ -32,7 +32,7 @@
#include "obj.h"
#include "builtin.h"
#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
// These are defined in modmath.c
extern const mp_obj_float_t mp_math_e_obj;
@@ -154,4 +154,4 @@ const mp_obj_module_t mp_module_cmath = {
.globals = (mp_obj_dict_t*)&mp_module_cmath_globals,
};
#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH

View File

@@ -30,7 +30,7 @@
#include "obj.h"
#include "builtin.h"
#if MICROPY_ENABLE_MOD_COLLECTIONS
#if MICROPY_PY_COLLECTIONS
STATIC const mp_map_elem_t mp_module_collections_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__collections) },
@@ -54,4 +54,4 @@ const mp_obj_module_t mp_module_collections = {
.globals = (mp_obj_dict_t*)&mp_module_collections_globals,
};
#endif // MICROPY_ENABLE_MOD_COLLECTIONS
#endif // MICROPY_PY_COLLECTIONS

View File

@@ -35,11 +35,17 @@
#include "objstr.h"
#include "gc.h"
#if MICROPY_ENABLE_MOD_GC && MICROPY_ENABLE_GC
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
extern uint gc_collected;
STATIC mp_obj_t py_gc_collect(void) {
gc_collect();
#if MICROPY_PY_GC_COLLECT_RETVAL
return MP_OBJ_NEW_SMALL_INT((machine_uint_t)gc_collected);
#else
return mp_const_none;
#endif
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);

View File

@@ -30,15 +30,26 @@
#include "obj.h"
#include "builtin.h"
#if MICROPY_ENABLE_MOD_IO
#if MICROPY_PY_IO
extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
STATIC const mp_map_elem_t mp_module_io_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) },
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__io) },
// Note: mp_builtin_open_obj should be defined by port, it's not
// part of the core.
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_stringio },
#if MICROPY_PY_IO_FILEIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_FileIO), (mp_obj_t)&mp_type_fileio },
#endif
#if MICROPY_CPYTHON_COMPAT
{ MP_OBJ_NEW_QSTR(MP_QSTR_TextIOWrapper), (mp_obj_t)&mp_type_textio },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_StringIO), (mp_obj_t)&mp_type_stringio },
#if MICROPY_PY_IO_BYTESIO
{ MP_OBJ_NEW_QSTR(MP_QSTR_BytesIO), (mp_obj_t)&mp_type_bytesio },
#endif
};
STATIC const mp_obj_dict_t mp_module_io_globals = {
@@ -54,7 +65,7 @@ STATIC const mp_obj_dict_t mp_module_io_globals = {
const mp_obj_module_t mp_module_io = {
.base = { &mp_type_module },
.name = MP_QSTR_io,
.name = MP_QSTR__io,
.globals = (mp_obj_dict_t*)&mp_module_io_globals,
};

View File

@@ -32,7 +32,7 @@
#include "obj.h"
#include "builtin.h"
#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
//TODO: Change macros to check for overflow and raise OverflowError or RangeError
#define MATH_FUN_1(py_name, c_name) \
@@ -151,6 +151,7 @@ STATIC const mp_map_elem_t mp_module_math_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_copysign), (mp_obj_t)&mp_math_copysign_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_fabs), (mp_obj_t)&mp_math_fabs_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&mp_math_floor_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_fmod), (mp_obj_t)&mp_math_fmod_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_frexp), (mp_obj_t)&mp_math_frexp_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ldexp), (mp_obj_t)&mp_math_ldexp_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_modf), (mp_obj_t)&mp_math_modf_obj },
@@ -183,4 +184,4 @@ const mp_obj_module_t mp_module_math = {
.globals = (mp_obj_dict_t*)&mp_module_math_globals,
};
#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH
#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,8 +35,25 @@
#include "objtuple.h"
#include "objstr.h"
#include "binary.h"
#include "parsenum.h"
#if MICROPY_ENABLE_MOD_STRUCT
#if MICROPY_PY_STRUCT
/*
This module implements most of character typecodes from CPython, with
some extensions:
O - (Pointer to) an arbitrary Python object. This is useful for callback
data, etc. Note that you must keep reference to passed object in
your Python application, otherwise it may be garbage-collected,
and then when you get back this value from callback it may be
invalid (and lead to crash).
S - Pointer to a string (returned as a Python string). Note the
difference from "Ns", - the latter says "in this place of structure
is character data of up to N bytes length", while "S" means
"in this place of a structure is a pointer to zero-terminated
character data".
*/
STATIC char get_fmt_type(const char **fmt) {
char t = **fmt;
@@ -56,9 +74,26 @@ STATIC char get_fmt_type(const char **fmt) {
return t;
}
STATIC machine_uint_t get_fmt_num(const char **p) {
const char *num = *p;
uint len = 1;
while (unichar_isdigit(*++num)) {
len++;
}
machine_uint_t val = (machine_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10));
*p = num;
return val;
}
STATIC uint calcsize_items(const char *fmt) {
// TODO
return strlen(fmt);
uint cnt = 0;
while (*fmt) {
// TODO supports size spec only for "s"
if (!unichar_isdigit(*fmt++)) {
cnt++;
}
}
return cnt;
}
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
@@ -66,10 +101,24 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
char fmt_type = get_fmt_type(&fmt);
machine_uint_t size;
for (size = 0; *fmt; fmt++) {
uint align;
int sz = mp_binary_get_size(fmt_type, *fmt, &align);
uint align = 1;
machine_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
if (cnt > 1) {
// TODO: count spec support only for string len
assert(*fmt == 's');
}
machine_uint_t sz;
if (*fmt == 's') {
sz = cnt;
} else {
sz = (machine_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
}
// TODO
assert(sz != -1);
assert(sz != (machine_uint_t)-1);
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz;
@@ -89,7 +138,22 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
byte *p = bufinfo.buf;
for (uint i = 0; i < size; i++) {
mp_obj_t item = mp_binary_get_val(fmt_type, *fmt++, &p);
machine_uint_t sz = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
if (sz > 1) {
// TODO: size spec support only for string len
assert(*fmt == 's');
}
mp_obj_t item;
if (*fmt == 's') {
item = mp_obj_new_bytes(p, sz);
p += sz;
fmt++;
} else {
item = mp_binary_get_val(fmt_type, *fmt++, &p);
}
res->items[i] = item;
}
return res;
@@ -106,7 +170,29 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
memset(p, 0, size);
for (uint i = 1; i < n_args; i++) {
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
machine_uint_t sz = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
if (sz > 1) {
// TODO: size spec support only for string len
assert(*fmt == 's');
}
if (*fmt == 's') {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ);
machine_uint_t to_copy = sz;
if (bufinfo.len < to_copy) {
to_copy = bufinfo.len;
}
memcpy(p, bufinfo.buf, to_copy);
memset(p + to_copy, 0, sz - to_copy);
p += sz;
fmt++;
} else {
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
}
}
return res;
}

View File

@@ -34,7 +34,7 @@
#include "objtuple.h"
#include "objstr.h"
#if MICROPY_ENABLE_MOD_SYS
#if MICROPY_PY_SYS
// These should be implemented by ports, specific types don't matter,
// only addresses.
@@ -51,6 +51,9 @@ mp_obj_list_t mp_sys_argv_obj;
STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3), I(4), I(0)}};
#undef I
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
#ifdef MICROPY_PY_SYS_PLATFORM
STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
#endif
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },
@@ -59,17 +62,20 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_argv), (mp_obj_t)&mp_sys_argv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_version), (mp_obj_t)&version_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_version_info), (mp_obj_t)&mp_sys_version_info_obj },
#ifdef MICROPY_PY_SYS_PLATFORM
{ MP_OBJ_NEW_QSTR(MP_QSTR_platform), (mp_obj_t)&platform_obj },
#endif
#if MP_ENDIANNESS_LITTLE
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_little) },
#else
{ MP_OBJ_NEW_QSTR(MP_QSTR_byteorder), MP_OBJ_NEW_QSTR(MP_QSTR_big) },
#endif
#if MICROPY_MOD_SYS_EXIT
#if MICROPY_PY_SYS_EXIT
{ MP_OBJ_NEW_QSTR(MP_QSTR_exit), (mp_obj_t)&mp_sys_exit_obj },
#endif
#if MICROPY_MOD_SYS_STDFILES
#if MICROPY_PY_SYS_STDFILES
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdin), (mp_obj_t)&mp_sys_stdin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_stdout), (mp_obj_t)&mp_sys_stdout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_stderr), (mp_obj_t)&mp_sys_stderr_obj },

View File

@@ -37,43 +37,54 @@
/* Memory allocation policy */
// Initial amount for lexer indentation level
#ifndef MP_ALLOC_LEXER_INDENT_INIT
#define MP_ALLOC_LEXER_INDENT_INIT (10)
#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT
#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)
#endif
// Increment for lexer indentation level
#ifndef MP_ALLOC_LEXEL_INDENT_INC
#define MP_ALLOC_LEXEL_INDENT_INC (8)
#ifndef MICROPY_ALLOC_LEXEL_INDENT_INC
#define MICROPY_ALLOC_LEXEL_INDENT_INC (8)
#endif
// Initial amount for parse rule stack
#ifndef MP_ALLOC_PARSE_RULE_INIT
#define MP_ALLOC_PARSE_RULE_INIT (64)
#ifndef MICROPY_ALLOC_PARSE_RULE_INIT
#define MICROPY_ALLOC_PARSE_RULE_INIT (64)
#endif
// Increment for parse rule stack
#ifndef MP_ALLOC_PARSE_RULE_INC
#define MP_ALLOC_PARSE_RULE_INC (16)
#ifndef MICROPY_ALLOC_PARSE_RULE_INC
#define MICROPY_ALLOC_PARSE_RULE_INC (16)
#endif
// Initial amount for parse result stack
#ifndef MP_ALLOC_PARSE_RESULT_INIT
#define MP_ALLOC_PARSE_RESULT_INIT (32)
#ifndef MICROPY_ALLOC_PARSE_RESULT_INIT
#define MICROPY_ALLOC_PARSE_RESULT_INIT (32)
#endif
// Increment for parse result stack
#ifndef MP_ALLOC_PARSE_RESULT_INC
#define MP_ALLOC_PARSE_RESULT_INC (16)
#ifndef MICROPY_ALLOC_PARSE_RESULT_INC
#define MICROPY_ALLOC_PARSE_RESULT_INC (16)
#endif
// Strings this length or less will be interned by the parser
#ifndef MICROPY_ALLOC_PARSE_INTERN_STRING_LEN
#define MICROPY_ALLOC_PARSE_INTERN_STRING_LEN (10)
#endif
// Initial amount for ids in a scope
#ifndef MP_ALLOC_SCOPE_ID_INIT
#define MP_ALLOC_SCOPE_ID_INIT (4)
#ifndef MICROPY_ALLOC_SCOPE_ID_INIT
#define MICROPY_ALLOC_SCOPE_ID_INIT (4)
#endif
// Increment for ids in a scope
#ifndef MP_ALLOC_SCOPE_ID_INC
#define MP_ALLOC_SCOPE_ID_INC (6)
#ifndef MICROPY_ALLOC_SCOPE_ID_INC
#define MICROPY_ALLOC_SCOPE_ID_INC (6)
#endif
// Maximum length of a path in the filesystem
// So we can allocate a buffer on the stack for path manipulation in import
#ifndef MICROPY_ALLOC_PATH_MAX
#define MICROPY_ALLOC_PATH_MAX (512)
#endif
/*****************************************************************************/
@@ -100,6 +111,14 @@
#define MICROPY_EMIT_INLINE_THUMB (0)
#endif
/*****************************************************************************/
/* Compiler configuration */
// Whether to enable constant optimisation; id = const(value)
#ifndef MICROPY_COMP_CONST
#define MICROPY_COMP_CONST (1)
#endif
/*****************************************************************************/
/* Internal debugging stuff */
@@ -117,13 +136,17 @@
#endif
/*****************************************************************************/
/* Fine control over Python features */
/* Optimisations */
// Whether to enable constant optimisation; id = const(value)
#ifndef MICROPY_ENABLE_CONST
#define MICROPY_ENABLE_CONST (1)
// Whether to use computed gotos in the VM, or a switch
// Computed gotos are roughly 10% faster, and increase VM code size by a little
#ifndef MICROPY_OPT_COMPUTED_GOTO
#define MICROPY_OPT_COMPUTED_GOTO (0)
#endif
/*****************************************************************************/
/* Python internal features */
// Whether to include the garbage collector
#ifndef MICROPY_ENABLE_GC
#define MICROPY_ENABLE_GC (0)
@@ -135,13 +158,13 @@
#endif
// Whether to include REPL helper function
#ifndef MICROPY_ENABLE_REPL_HELPERS
#define MICROPY_ENABLE_REPL_HELPERS (0)
#ifndef MICROPY_HELPER_REPL
#define MICROPY_HELPER_REPL (0)
#endif
// Whether to include lexer helper function for unix
#ifndef MICROPY_ENABLE_LEXER_UNIX
#define MICROPY_ENABLE_LEXER_UNIX (0)
#ifndef MICROPY_HELPER_LEXER_UNIX
#define MICROPY_HELPER_LEXER_UNIX (0)
#endif
// Long int implementation
@@ -189,76 +212,15 @@ typedef long long mp_longint_impl_t;
#endif
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#define MICROPY_ENABLE_FLOAT (1)
#define MICROPY_PY_BUILTINS_FLOAT (1)
#define MICROPY_FLOAT_C_FUN(fun) fun##f
typedef float mp_float_t;
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
#define MICROPY_ENABLE_FLOAT (1)
#define MICROPY_PY_BUILTINS_FLOAT (1)
#define MICROPY_FLOAT_C_FUN(fun) fun
typedef double mp_float_t;
#else
#define MICROPY_ENABLE_FLOAT (0)
#endif
// Whether to provide "collections" module
#ifndef MICROPY_ENABLE_MOD_COLLECTIONS
#define MICROPY_ENABLE_MOD_COLLECTIONS (1)
#endif
// Whether to provide "math" module
#ifndef MICROPY_ENABLE_MOD_MATH
#define MICROPY_ENABLE_MOD_MATH (1)
#endif
// Whether to provide "cmath" module
#ifndef MICROPY_ENABLE_MOD_CMATH
#define MICROPY_ENABLE_MOD_CMATH (0)
#endif
// Whether to provide "gc" module
#ifndef MICROPY_ENABLE_MOD_GC
#define MICROPY_ENABLE_MOD_GC (1)
#endif
// Whether to provide "io" module
#ifndef MICROPY_ENABLE_MOD_IO
#define MICROPY_ENABLE_MOD_IO (1)
#endif
// Whether to provide "struct" module
#ifndef MICROPY_ENABLE_MOD_STRUCT
#define MICROPY_ENABLE_MOD_STRUCT (1)
#endif
// Whether to provide "sys" module
#ifndef MICROPY_ENABLE_MOD_SYS
#define MICROPY_ENABLE_MOD_SYS (1)
#endif
// sys.exit() availability
#ifndef MICROPY_MOD_SYS_EXIT
#define MICROPY_MOD_SYS_EXIT (0)
#endif
// sys.{stdin,stdout,stderr} availability
#ifndef MICROPY_MOD_SYS_STDFILES
#define MICROPY_MOD_SYS_STDFILES (0)
#endif
// Whether to support slice object and correspondingly
// slice subscript operators
#ifndef MICROPY_ENABLE_SLICE
#define MICROPY_ENABLE_SLICE (1)
#endif
// Whether to support frozenset object
#ifndef MICROPY_ENABLE_FROZENSET
#define MICROPY_ENABLE_FROZENSET (0)
#endif
// Whether to support the property object
#ifndef MICROPY_ENABLE_PROPERTY
#define MICROPY_ENABLE_PROPERTY (1)
#define MICROPY_PY_BUILTINS_FLOAT (0)
#endif
// Enable features which improve CPython compatibility
@@ -269,36 +231,110 @@ typedef double mp_float_t;
#define MICROPY_CPYTHON_COMPAT (1)
#endif
// Maximum length of a path in the filesystem
// So we can allocate a buffer on the stack for path manipulation in import
#ifndef MICROPY_PATH_MAX
#define MICROPY_PATH_MAX (512)
#endif
// Whether POSIX-semantics non-blocking streams are supported
#ifndef MICROPY_STREAMS_NON_BLOCK
#define MICROPY_STREAMS_NON_BLOCK (0)
#endif
// Whether to use computed gotos in the VM, or a switch
// Computed gotos are roughly 10% faster, and increase VM code size by a little
#ifndef MICROPY_USE_COMPUTED_GOTO
#define MICROPY_USE_COMPUTED_GOTO (0)
/*****************************************************************************/
/* Fine control over Python builtins, classes, modules, etc */
// Whether to support set object
#ifndef MICROPY_PY_BUILTINS_SET
#define MICROPY_PY_BUILTINS_SET (1)
#endif
// Whether to support slice subscript operators and slice object
#ifndef MICROPY_PY_BUILTINS_SLICE
#define MICROPY_PY_BUILTINS_SLICE (1)
#endif
// Whether to support frozenset object
#ifndef MICROPY_PY_BUILTINS_FROZENSET
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#endif
// Whether to support property object
#ifndef MICROPY_PY_BUILTINS_PROPERTY
#define MICROPY_PY_BUILTINS_PROPERTY (1)
#endif
// Whether to provide "collections" module
#ifndef MICROPY_PY_COLLECTIONS
#define MICROPY_PY_COLLECTIONS (1)
#endif
// Whether to provide "math" module
#ifndef MICROPY_PY_MATH
#define MICROPY_PY_MATH (1)
#endif
// Whether to provide "cmath" module
#ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0)
#endif
// Whether to provide "gc" module
#ifndef MICROPY_PY_GC
#define MICROPY_PY_GC (1)
#endif
// Whether to return number of collected objects from gc.collect()
#ifndef MICROPY_PY_GC_COLLECT_RETVAL
#define MICROPY_PY_GC_COLLECT_RETVAL (0)
#endif
// Whether to provide "io" module
#ifndef MICROPY_PY_IO
#define MICROPY_PY_IO (1)
#endif
// Whether to provide "io.FileIO" class
#ifndef MICROPY_PY_IO_FILEIO
#define MICROPY_PY_IO_FILEIO (0)
#endif
// Whether to provide "io.BytesIO" class
#ifndef MICROPY_PY_IO_BYTESIO
#define MICROPY_PY_IO_BYTESIO (1)
#endif
// Whether to provide "struct" module
#ifndef MICROPY_PY_STRUCT
#define MICROPY_PY_STRUCT (1)
#endif
// Whether to provide "sys" module
#ifndef MICROPY_PY_SYS
#define MICROPY_PY_SYS (1)
#endif
// Whether to provide "sys.exit" function
#ifndef MICROPY_PY_SYS_EXIT
#define MICROPY_PY_SYS_EXIT (0)
#endif
// Whether to provide sys.{stdin,stdout,stderr} objects
#ifndef MICROPY_PY_SYS_STDFILES
#define MICROPY_PY_SYS_STDFILES (0)
#endif
/*****************************************************************************/
/* Hooks for a port to add builtins */
// Additional builtin function definitions - see builtintables.c:builtin_object_table for format.
#ifndef MICROPY_EXTRA_BUILTINS
#define MICROPY_EXTRA_BUILTINS
#ifndef MICROPY_PORT_BUILTINS
#define MICROPY_PORT_BUILTINS
#endif
// Additional builtin module definitions - see builtintables.c:builtin_module_table for format.
#ifndef MICROPY_EXTRA_BUILTIN_MODULES
#define MICROPY_EXTRA_BUILTIN_MODULES
#ifndef MICROPY_PORT_BUILTIN_MODULES
#define MICROPY_PORT_BUILTIN_MODULES
#endif
// Additional constant definitions for the compiler - see compile.c:mp_constants_table.
#ifndef MICROPY_EXTRA_CONSTANTS
#define MICROPY_EXTRA_CONSTANTS
#ifndef MICROPY_PORT_CONSTANTS
#define MICROPY_PORT_CONSTANTS
#endif
/*****************************************************************************/

View File

@@ -207,17 +207,47 @@ STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
mpz_dig_t *oidig = idig;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
*idig = *jdig & *kdig;
}
for (; jlen > 0; --jlen, ++idig) {
*idig = 0;
// remove trailing zeros
for (--idig; idig >= oidig && *idig == 0; --idig) {
}
return idig - oidig;
return idig + 1 - oidig;
}
/* computes i = j & -k = j & (~k + 1)
returns number of digits in i
assumes enough memory in i; assumes normalised j, k
can have i, j, k pointing to same memory
*/
STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = 1;
for (; jlen > 0 && klen > 0; --jlen, --klen, ++idig, ++jdig, ++kdig) {
carry += *kdig ^ DIG_MASK;
*idig = (*jdig & carry) & DIG_MASK;
carry >>= DIG_SIZE;
}
for (; jlen > 0; --jlen, ++idig, ++jdig) {
carry += DIG_MASK;
*idig = (*jdig & carry) & DIG_MASK;
carry >>= DIG_SIZE;
}
if (carry != 0) {
*idig = carry;
} else {
// remove trailing zeros
for (--idig; idig >= oidig && *idig == 0; --idig) {
}
}
return idig + 1 - oidig;
}
/* computes i = j | k
@@ -898,23 +928,35 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
can have dest, lhs, rhs the same
*/
void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
if (mpn_cmp(lhs->dig, lhs->len, rhs->dig, rhs->len) < 0) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
if (lhs->neg == rhs->neg) {
mpz_need_dig(dest, lhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
if (lhs->neg == 0) {
// make sure lhs has the most digits
if (lhs->len < rhs->len) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
// do the and'ing
mpz_need_dig(dest, rhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
dest->neg = 0;
} else {
// TODO both args are negative
assert(0);
}
} else {
mpz_need_dig(dest, lhs->len);
// TODO
assert(0);
// dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
// args have different sign
// make sure lhs is the positive arg
if (rhs->neg == 0) {
const mpz_t *temp = lhs;
lhs = rhs;
rhs = temp;
}
mpz_need_dig(dest, lhs->len + 1);
dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
assert(dest->len <= dest->alloc);
dest->neg = 0;
}
dest->neg = lhs->neg;
}
/* computes dest = lhs | rhs
@@ -1220,7 +1262,7 @@ bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
return true;
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *i) {
mp_float_t val = 0;
mpz_dig_t *d = i->dig + i->len;

View File

@@ -98,7 +98,7 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs);
machine_int_t mpz_as_int(const mpz_t *z);
bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value);
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *z);
#endif
uint mpz_as_str_size(const mpz_t *z, uint base);

View File

@@ -32,6 +32,10 @@
#if !defined(__CYGWIN__)
#if (defined(__APPLE__) && defined(__MACH__))
#define nlr_jump_fail _nlr_jump_fail
#endif // (defined(__APPLE__) && defined(__MACH__))
/* uint nlr_push(rdi=nlr_buf_t *nlr) */
#if !(defined(__APPLE__) && defined(__MACH__))
.globl nlr_push

View File

@@ -122,7 +122,7 @@ int mp_obj_is_true(mp_obj_t arg) {
mp_obj_type_t *type = mp_obj_get_type(arg);
if (type->unary_op != NULL) {
mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
if (result != MP_OBJ_NOT_SUPPORTED) {
if (result != MP_OBJ_NULL) {
return result == mp_const_true;
}
}
@@ -212,7 +212,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
mp_obj_type_t *type = mp_obj_get_type(o1);
if (type->binary_op != NULL) {
mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
if (r != MP_OBJ_NOT_SUPPORTED) {
if (r != MP_OBJ_NULL) {
return r == mp_const_true ? true : false;
}
}
@@ -222,7 +222,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
return false;
}
machine_int_t mp_obj_get_int(mp_obj_t arg) {
machine_int_t mp_obj_get_int(mp_const_obj_t arg) {
// This function essentially performs implicit type conversion to int
// Note that Python does NOT provide implicit type conversion from
// float to int in the core expression language, try some_list[1.0].
@@ -242,7 +242,7 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) {
// returns false if arg is not of integral type
// returns true and sets *value if it is of integral type
// can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) {
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value) {
if (arg == mp_const_false) {
*value = 0;
} else if (arg == mp_const_true) {
@@ -257,7 +257,7 @@ bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) {
return true;
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_get_float(mp_obj_t arg) {
if (arg == mp_const_false) {
return 0;
@@ -357,12 +357,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
} else {
mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->unary_op != NULL) {
mp_obj_t val = type->unary_op(MP_UNARY_OP_LEN, o_in);
// TODO: Here's the case of having MP_OBJ_NOT_SUPPORTED is confusing
if (val == MP_OBJ_NOT_SUPPORTED) {
return MP_OBJ_NULL;
}
return val;
return type->unary_op(MP_UNARY_OP_LEN, o_in);
} else {
return MP_OBJ_NULL;
}
@@ -373,7 +368,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
mp_obj_type_t *type = mp_obj_get_type(base);
if (type->subscr != NULL) {
mp_obj_t ret = type->subscr(base, index, value);
if (ret != MP_OBJ_NOT_SUPPORTED) {
if (ret != MP_OBJ_NULL) {
return ret;
}
// TODO: call base classes here?

View File

@@ -52,8 +52,7 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// These fake objects are used to indicate certain things in arguments or return
// values, and should only be used when explicitly allowed.
//
// - MP_OBJ_NULL : used to indicate the absence of an object.
// - MP_OBJ_NOT_SUPPORTED : a return value that indicates an unsupported operation.
// - MP_OBJ_NULL : used to indicate the absence of an object, or unsupported operation.
// - MP_OBJ_STOP_ITERATION : used instead of throwing a StopIteration, for efficiency.
// - MP_OBJ_SENTINEL : used for various internal purposes where one needs
// an object which is unique from all other objects, including MP_OBJ_NULL.
@@ -63,22 +62,16 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
#if NDEBUG
#define MP_OBJ_NULL ((mp_obj_t)0)
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)0)
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)0)
#define MP_OBJ_SENTINEL ((mp_obj_t)4)
#else
#define MP_OBJ_NULL ((mp_obj_t)0)
#define MP_OBJ_NOT_SUPPORTED ((mp_obj_t)4)
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)8)
#define MP_OBJ_SENTINEL ((mp_obj_t)12)
#define MP_OBJ_STOP_ITERATION ((mp_obj_t)4)
#define MP_OBJ_SENTINEL ((mp_obj_t)8)
#endif
// These macros check for small int, qstr or object, and access small int and qstr values
// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
#define MP_OBJ_FITS_SMALL_INT(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
// these macros have now become inline functions; see below
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_small_int_t)(o)) & 1) != 0)
//#define MP_OBJ_IS_QSTR(o) ((((mp_small_int_t)(o)) & 3) == 2)
@@ -158,7 +151,7 @@ typedef enum _mp_map_lookup_kind_t {
MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2
} mp_map_lookup_kind_t;
static inline bool MP_MAP_SLOT_IS_FILLED(mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, machine_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
void mp_map_init(mp_map_t *map, int n);
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
@@ -177,7 +170,7 @@ typedef struct _mp_set_t {
mp_obj_t *table;
} mp_set_t;
static inline bool MP_SET_SLOT_IS_FILLED(mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, machine_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
void mp_set_init(mp_set_t *set, int n);
mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
@@ -246,6 +239,7 @@ typedef struct _mp_stream_p_t {
machine_int_t (*read)(mp_obj_t obj, void *buf, machine_uint_t size, int *errcode);
machine_int_t (*write)(mp_obj_t obj, const void *buf, machine_uint_t size, int *errcode);
// add seek() ?
int is_bytes : 1;
} mp_stream_p_t;
struct _mp_obj_type_t {
@@ -255,15 +249,15 @@ struct _mp_obj_type_t {
mp_make_new_fun_t make_new; // to make an instance of the type
mp_call_fun_t call;
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NOT_SUPPORTED if op not supported
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NOT_SUPPORTED if op not supported
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported
mp_load_attr_fun_t load_attr;
mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute
mp_subscr_fun_t subscr; // implements load, store, delete subscripting
// value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store
// can return MP_OBJ_NOT_SUPPORTED
// can return MP_OBJ_NULL if op not supported
mp_fun_1_t getiter;
mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args)
@@ -321,6 +315,7 @@ extern const mp_obj_type_t mp_type_staticmethod;
extern const mp_obj_type_t mp_type_classmethod;
extern const mp_obj_type_t mp_type_property;
extern const mp_obj_type_t mp_type_stringio;
extern const mp_obj_type_t mp_type_bytesio;
// Exceptions
extern const mp_obj_type_t mp_type_BaseException;
@@ -345,6 +340,7 @@ extern const mp_obj_type_t mp_type_RuntimeError;
extern const mp_obj_type_t mp_type_StopIteration;
extern const mp_obj_type_t mp_type_SyntaxError;
extern const mp_obj_type_t mp_type_SystemError;
extern const mp_obj_type_t mp_type_SystemExit;
extern const mp_obj_type_t mp_type_TypeError;
extern const mp_obj_type_t mp_type_ValueError;
extern const mp_obj_type_t mp_type_ZeroDivisionError;
@@ -371,11 +367,11 @@ mp_obj_t mp_obj_new_bool(bool value);
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
mp_obj_t mp_obj_new_int(machine_int_t value);
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
mp_obj_t mp_obj_new_int_from_qstr(qstr qst);
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base);
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
mp_obj_t mp_obj_new_str(const byte* data, uint len, bool make_qstr_if_not_already);
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already);
mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_obj_t mp_obj_new_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
@@ -384,7 +380,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, const byte *code);
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
@@ -422,9 +418,9 @@ bool mp_obj_is_callable(mp_obj_t o_in);
machine_int_t mp_obj_hash(mp_obj_t o_in);
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
machine_int_t mp_obj_get_int(mp_obj_t arg);
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value);
#if MICROPY_ENABLE_FLOAT
machine_int_t mp_obj_get_int(mp_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value);
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_get_float(mp_obj_t self_in);
void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
#endif
@@ -445,12 +441,12 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
// int
// For long int, returns value truncated to machine_int_t
machine_int_t mp_obj_int_get(mp_obj_t self_in);
#if MICROPY_ENABLE_FLOAT
machine_int_t mp_obj_int_get(mp_const_obj_t self_in);
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_int_as_float(mp_obj_t self_in);
#endif
// Will raise exception if value doesn't fit into machine_int_t
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in);
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
// exception
#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
@@ -472,20 +468,21 @@ uint mp_obj_str_get_len(mp_obj_t self_in);
qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len);
mp_obj_t mp_obj_str_intern(mp_obj_t str);
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len);
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
// float
typedef struct _mp_obj_float_t {
mp_obj_base_t base;
mp_float_t value;
} mp_obj_float_t;
mp_float_t mp_obj_float_get(mp_obj_t self_in);
mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NOT_SUPPORTED
mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
// complex
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NOT_SUPPORTED
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported
#endif
// tuple
@@ -509,6 +506,7 @@ typedef struct _mp_obj_dict_t {
} mp_obj_dict_t;
void mp_obj_dict_init(mp_obj_dict_t *dict, int n_args);
uint mp_obj_dict_len(mp_obj_t self_in);
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
@@ -517,7 +515,7 @@ mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
// slice
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
// array
uint mp_obj_array_len(mp_obj_t self_in);
@@ -536,9 +534,7 @@ typedef struct _mp_obj_fun_native_t { // need this so we can define const object
// such functions won't be able to access the global scope, but that's probably okay
} mp_obj_fun_native_t;
bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2);
const char *mp_obj_fun_get_name(mp_obj_t fun);
const char *mp_obj_fun_get_name(mp_const_obj_t fun);
const char *mp_obj_code_get_name(const byte *code_info);
mp_obj_t mp_identity(mp_obj_t self);
@@ -563,14 +559,25 @@ typedef struct _mp_obj_static_class_method_t {
const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
// sequence helpers
// slice indexes resolved to particular sequence
typedef struct {
machine_uint_t start;
machine_uint_t stop;
machine_int_t step;
} mp_bound_slice_t;
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end);
#if MICROPY_PY_BUILTINS_SLICE
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
#endif
#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))
#define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); }
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2);
bool mp_seq_cmp_objs(int op, const mp_obj_t *items1, uint len1, const mp_obj_t *items2, uint len2);
mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args);
mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
mp_obj_t mp_seq_extract_slice(uint len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_t) \
@@ -578,3 +585,8 @@ mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
memcpy(dest + beg, slice, slice_len * sizeof(item_t)); \
/*printf("memcpy(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
memcpy(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_t) \
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t));*/ \
memmove(dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t)); \
memcpy(dest + beg, slice, slice_len * sizeof(item_t));

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -139,7 +140,7 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -165,26 +166,30 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
// TODO implement
// TODO: confirmed that both bytearray and array.array support
// slice deletion
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
} else {
mp_obj_array_t *o = self_in;
if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
if (0) {
#if MICROPY_PY_BUILTINS_SLICE
} else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
if (value != MP_OBJ_SENTINEL) {
// Only getting a slice is suported so far, not assignment
// TODO: confirmed that both bytearray and array.array support
// slice assignment (incl. of different size)
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &start, &stop)) {
assert(0);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
mp_obj_array_t *res = array_new(o->typecode, stop - start);
mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start);
int sz = mp_binary_get_size('@', o->typecode, NULL);
assert(sz > 0);
byte *p = o->items;
memcpy(res->items, p + start * sz, (stop - start) * sz);
memcpy(res->items, p + slice.start * sz, (slice.stop - slice.start) * sz);
return res;
#endif
} else {
uint index = mp_get_index(o->base.type, o->len, index_in, false);
if (value == MP_OBJ_SENTINEL) {

View File

@@ -76,7 +76,7 @@ STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in);
}
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
const mp_obj_type_t mp_type_bool = {

View File

@@ -36,7 +36,7 @@
#include "runtime0.h"
#include "runtime.h"
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
@@ -123,7 +123,7 @@ STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->real != 0 || o->imag != 0);
case MP_UNARY_OP_POSITIVE: return o_in;
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -233,7 +233,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_real == rhs_real && lhs_imag == rhs_imag);
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
return mp_obj_new_complex(lhs_real, lhs_imag);
}

View File

@@ -40,7 +40,7 @@
STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
STATIC mp_obj_t dict_copy(mp_obj_t self_in);
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs);
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = self_in;
@@ -61,40 +61,13 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
}
STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_t dict;
switch (n_args) {
case 0:
dict = mp_obj_new_dict(0);
break;
case 1: {
if (MP_OBJ_IS_TYPE(args[0], &mp_type_dict)) {
return dict_copy(args[0]);
}
// TODO create dict from an arbitrary mapping!
// Make dict from iterable of pairs
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_t dict = mp_obj_new_dict(0);
// TODO: support arbitrary seq as a pair
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
mp_obj_t *sub_items;
mp_obj_get_array_fixed_n(item, 2, &sub_items);
mp_obj_dict_store(dict, sub_items[0], sub_items[1]);
}
return dict;
}
default:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "dict takes at most 1 argument"));
mp_obj_t dict = mp_obj_new_dict(0);
if (n_args > 0 || n_kw > 0) {
mp_obj_t args2[2] = {dict, args[0]}; // args[0] is always valid, even if it's not a positional arg
mp_map_t kwargs;
mp_map_init_fixed_table(&kwargs, n_kw, args + n_args);
dict_update(n_args + 1, args2, &kwargs); // dict_update will check that n_args + 1 == 1 or 2
}
// add to the new dict any keyword args
for (const mp_obj_t *a = args + n_args; n_kw > 0; n_kw--, a += 2) {
mp_obj_dict_store(dict, a[0], a[1]);
}
return dict;
}
@@ -103,7 +76,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->map.used);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -140,7 +113,18 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
default:
// op not supported
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL;
}
}
// TODO: Make sure this is inlined in dict_subscr() below.
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {
mp_obj_dict_t *self = self_in;
mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP);
if (elem == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>"));
} else {
return elem->value;
}
}
@@ -348,31 +332,57 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict));
mp_obj_dict_t *self = self_in;
/* TODO: check for the "keys" method */
mp_obj_t iter = mp_getiter(iterable);
mp_obj_t next = NULL;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
mp_obj_t inneriter = mp_getiter(next);
mp_obj_t key = mp_iternext(inneriter);
mp_obj_t value = mp_iternext(inneriter);
mp_obj_t stop = mp_iternext(inneriter);
if (key == MP_OBJ_STOP_ITERATION
|| value == MP_OBJ_STOP_ITERATION
|| stop != MP_OBJ_STOP_ITERATION) {
nlr_raise(mp_obj_new_exception_msg(
&mp_type_ValueError,
"dictionary update sequence has the wrong length"));
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
mp_obj_dict_t *self = args[0];
mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
if (n_args == 2) {
// given a positional argument
if (MP_OBJ_IS_TYPE(args[1], &mp_type_dict)) {
// update from other dictionary (make sure other is not self)
if (args[1] != self) {
// TODO don't allocate heap object for this iterator
mp_obj_t *dict_iter = mp_obj_new_dict_iterator(args[1], 0);
mp_map_elem_t *elem = NULL;
while ((elem = dict_it_iternext_elem(dict_iter)) != MP_OBJ_STOP_ITERATION) {
mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;
}
}
} else {
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
// update from a generic iterable of pairs
mp_obj_t iter = mp_getiter(args[1]);
mp_obj_t next = NULL;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
mp_obj_t inneriter = mp_getiter(next);
mp_obj_t key = mp_iternext(inneriter);
mp_obj_t value = mp_iternext(inneriter);
mp_obj_t stop = mp_iternext(inneriter);
if (key == MP_OBJ_STOP_ITERATION
|| value == MP_OBJ_STOP_ITERATION
|| stop != MP_OBJ_STOP_ITERATION) {
nlr_raise(mp_obj_new_exception_msg(
&mp_type_ValueError,
"dictionary update sequence has the wrong length"));
} else {
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
}
}
}
}
// update the dict with any keyword args
for (machine_uint_t i = 0; i < kwargs->alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
mp_map_lookup(&self->map, kwargs->table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = kwargs->table[i].value;
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(dict_update_obj, dict_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dict_update_obj, 1, dict_update);
/******************************************************************************/
@@ -463,13 +473,13 @@ STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void
}
STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
/* only supported for the 'keys' kind until sets and dicts are refactored */
// only supported for the 'keys' kind until sets and dicts are refactored
mp_obj_dict_view_t *o = lhs_in;
if (o->kind != MP_DICT_VIEW_KEYS) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
if (op != MP_BINARY_OP_IN) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
return dict_binary_op(op, o->dict, rhs_in);
}

View File

@@ -120,12 +120,27 @@ STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
}
STATIC mp_obj_t exc___init__(uint n_args, const mp_obj_t *args) {
mp_obj_exception_t *self = args[0];
mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1);
self->args = argst;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__);
STATIC const mp_map_elem_t exc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&exc___init___obj },
};
STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table);
const mp_obj_type_t mp_type_BaseException = {
{ &mp_type_type },
.name = MP_QSTR_BaseException,
.print = mp_obj_exception_print,
.make_new = mp_obj_exception_make_new,
.load_attr = exception_load_attr,
.locals_dict = (mp_obj_t)&exc_locals_dict,
};
#define MP_DEFINE_EXCEPTION_BASE(base_name) \
@@ -142,9 +157,9 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
};
// List of all exceptions, arranged as in the table at:
// http://docs.python.org/3.3/library/exceptions.html
// http://docs.python.org/3/library/exceptions.html
MP_DEFINE_EXCEPTION_BASE(BaseException)
//MP_DEFINE_EXCEPTION(SystemExit, BaseException)
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
MP_DEFINE_EXCEPTION(Exception, BaseException)
@@ -168,11 +183,13 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION(KeyError, LookupError)
MP_DEFINE_EXCEPTION(MemoryError, Exception)
MP_DEFINE_EXCEPTION(NameError, Exception)
MP_DEFINE_EXCEPTION_BASE(NameError)
//MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
MP_DEFINE_EXCEPTION(OSError, Exception)
MP_DEFINE_EXCEPTION_BASE(OSError)
/*
MP_DEFINE_EXCEPTION_BASE(NameError)
MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
*/
MP_DEFINE_EXCEPTION(OSError, Exception)
/*
MP_DEFINE_EXCEPTION_BASE(OSError)
MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
MP_DEFINE_EXCEPTION(ConnectionError, OSError)
@@ -266,7 +283,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
va_start(ap, fmt);
vstr_vprintf(vstr, fmt, ap);
va_end(ap);
o->args->items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
o->args->items[0] = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
}
}

View File

@@ -39,7 +39,7 @@
#include "runtime0.h"
#include "runtime.h"
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#include "formatfloat.h"
@@ -96,7 +96,7 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->value != 0);
case MP_UNARY_OP_POSITIVE: return o_in;
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-o->value);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -165,9 +165,9 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) {
case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val);
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
return mp_obj_new_float(lhs_val);
}
#endif // MICROPY_ENABLE_FLOAT
#endif // MICROPY_PY_BUILTINS_FLOAT

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +28,6 @@
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <alloca.h>
#include "mpconfig.h"
#include "nlr.h"
@@ -58,7 +58,7 @@ STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// we don't even need to check for 2nd arg type.
return MP_BOOL(lhs_in == rhs_in);
}
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
@@ -153,8 +153,8 @@ const char *mp_obj_code_get_name(const byte *code_info) {
return qstr_str(block_name);
}
const char *mp_obj_fun_get_name(mp_obj_t fun_in) {
mp_obj_fun_bc_t *fun = fun_in;
const char *mp_obj_fun_get_name(mp_const_obj_t fun_in) {
const mp_obj_fun_bc_t *fun = fun_in;
const byte *code_info = fun->bytecode;
return mp_obj_code_get_name(code_info);
}
@@ -193,66 +193,32 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui
#endif
}
// If it's possible to call a function without allocating new argument array,
// this function returns true, together with pointers to 2 subarrays to be used
// as arguments. Otherwise, it returns false. It is expected that this fucntion
// will be accompanied by another, mp_obj_fun_prepare_full_args(), which will
// instead take pointer to full-length out-array, and will fill it in. Rationale
// being that a caller can try this function and if it succeeds, the function call
// can be made without allocating extra memory. Otherwise, caller can allocate memory
// and try "full" function. These functions are expected to be refactoring of
// code in fun_bc_call() and evenrually replace it.
bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args,
uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) {
// With this macro you can tune the maximum number of function state bytes
// that will be allocated on the stack. Any function that needs more
// than this will use the heap.
#define VM_MAX_STATE_ON_STACK (10 * sizeof(machine_uint_t))
// Set this to enable a simple stack overflow check.
#define VM_DETECT_STACK_OVERFLOW (0)
// code_state should have ->ip filled in (pointing past code info block),
// as well as ->n_state.
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_fun_bc_t *self = self_in;
DEBUG_printf("mp_obj_fun_prepare_simple_args: given: %d pos, %d kw, expected: %d pos (%d default)\n",
n_args, n_kw, self->n_pos_args, self->n_def_args);
machine_uint_t n_state = code_state->n_state;
const byte *ip = code_state->ip;
assert(n_kw == 0);
assert(self->n_kwonly_args == 0);
assert(self->takes_var_args == 0);
assert(self->takes_kw_args == 0);
code_state->code_info = self->bytecode;
code_state->sp = &code_state->state[0] - 1;
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
uint n_extra_args = 0;
if (n_args > self->n_pos_args) {
goto arg_error;
} else {
if (n_args >= self->n_pos_args - self->n_def_args) {
extra_args -= self->n_pos_args - n_args;
n_extra_args += self->n_pos_args - n_args;
} else {
fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
}
}
*out_args1 = args;
*out_args1_len = n_args;
*out_args2 = extra_args;
*out_args2_len = n_extra_args;
return true;
arg_error:
fun_pos_args_mismatch(self, self->n_pos_args, n_args);
}
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
// usage for the common case of positional only args.
//
// extra_args layout: def_args, var_arg tuple, kwonly args, var_kw dict
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
DEBUG_printf("Input pos args: ");
dump_args(args, n_args);
DEBUG_printf("Input kw args: ");
dump_args(args + n_args, n_kw * 2);
mp_obj_fun_bc_t *self = self_in;
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
// zero out the local stack to begin with
memset(code_state->state, 0, n_state * sizeof(*code_state->state));
const mp_obj_t *kwargs = args + n_args;
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
uint n_extra_args = 0;
// var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
// check positional arguments
@@ -262,57 +228,53 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
fun_pos_args_mismatch(self, self->n_pos_args, n_args);
}
// put extra arguments in varargs tuple
*extra_args = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
n_extra_args = 1;
*var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
n_args = self->n_pos_args;
} else {
if (self->takes_var_args) {
DEBUG_printf("passing empty tuple as *args\n");
*extra_args = mp_const_empty_tuple;
n_extra_args = 1;
*var_pos_kw_args-- = mp_const_empty_tuple;
}
// Apply processing and check below only if we don't have kwargs,
// otherwise, kw handling code below has own extensive checks.
if (n_kw == 0) {
if (n_kw == 0 && !self->has_def_kw_args) {
if (n_args >= self->n_pos_args - self->n_def_args) {
// given enough arguments, but may need to use some default arguments
extra_args -= self->n_pos_args - n_args;
n_extra_args += self->n_pos_args - n_args;
for (uint i = n_args; i < self->n_pos_args; i++) {
code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
}
} else {
fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
}
}
}
// copy positional args into state
for (uint i = 0; i < n_args; i++) {
code_state->state[n_state - 1 - i] = args[i];
}
// check keyword arguments
if (n_kw != 0) {
// We cannot use dynamically-sized array here, because GCC indeed
// deallocates it on leaving defining scope (unlike most static stack allocs).
// So, we have 2 choices: allocate it unconditionally at the top of function
// (wastes stack), or use alloca which is guaranteed to dealloc on func exit.
//mp_obj_t flat_args[self->n_args];
mp_obj_t *flat_args = alloca((self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t));
for (int i = self->n_pos_args + self->n_kwonly_args - 1; i >= 0; i--) {
flat_args[i] = MP_OBJ_NULL;
}
memcpy(flat_args, args, sizeof(*args) * n_args);
if (n_kw != 0 || self->has_def_kw_args) {
DEBUG_printf("Initial args: ");
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
mp_obj_t dict = MP_OBJ_NULL;
if (self->takes_kw_args) {
dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
*var_pos_kw_args = dict;
}
for (uint i = 0; i < n_kw; i++) {
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
for (uint j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
if (arg_name == self->args[j]) {
if (flat_args[j] != MP_OBJ_NULL) {
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function got multiple values for argument '%s'", qstr_str(arg_name)));
}
flat_args[j] = kwargs[2 * i + 1];
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
goto continue2;
}
}
@@ -323,43 +285,47 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
continue2:;
}
DEBUG_printf("Args with kws flattened: ");
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
// Now fill in defaults for positional args
mp_obj_t *d = &flat_args[self->n_pos_args - 1];
DEBUG_printf("Args with kws flattened: ");
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
// fill in defaults for positional args
mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
for (int i = self->n_def_args; i > 0; i--, d--, s--) {
for (int i = self->n_def_args; i > 0; i--, d++, s--) {
if (*d == MP_OBJ_NULL) {
*d = *s;
}
}
DEBUG_printf("Args after filling defaults: ");
dump_args(flat_args, self->n_pos_args + self->n_kwonly_args);
DEBUG_printf("Args after filling default positional: ");
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
// Check that all mandatory positional args are specified
while (d >= flat_args) {
if (*d-- == MP_OBJ_NULL) {
while (d < &code_state->state[n_state]) {
if (*d++ == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required positional argument #%d", d - flat_args));
"function missing required positional argument #%d", &code_state->state[n_state] - d));
}
}
// Check that all mandatory keyword args are specified
for (int i = 0; i < self->n_kwonly_args; i++) {
if (flat_args[self->n_pos_args + i] == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
// Fill in default kw args if we have them
for (uint i = 0; i < self->n_kwonly_args; i++) {
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
mp_map_elem_t *elem = NULL;
if (self->has_def_kw_args) {
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
}
if (elem != NULL) {
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
}
}
}
args = flat_args;
n_args = self->n_pos_args + self->n_kwonly_args;
if (self->takes_kw_args) {
extra_args[n_extra_args] = dict;
n_extra_args += 1;
}
} else {
// no keyword arguments given
if (self->n_kwonly_args != 0) {
@@ -367,20 +333,122 @@ continue2:;
"function missing keyword-only argument"));
}
if (self->takes_kw_args) {
extra_args[n_extra_args] = mp_obj_new_dict(0);
n_extra_args += 1;
*var_pos_kw_args = mp_obj_new_dict(0);
}
}
// bytecode prelude: initialise closed over variables
for (uint n_local = *ip++; n_local > 0; n_local--) {
uint local_num = *ip++;
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
}
// now that we skipped over the prelude, set the ip for the VM
code_state->ip = ip;
DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
dump_args(code_state->state, n_state);
}
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
// usage for the common case of positional only args.
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
DEBUG_printf("Input pos args: ");
dump_args(args, n_args);
DEBUG_printf("Input kw args: ");
dump_args(args + n_args, n_kw * 2);
mp_obj_fun_bc_t *self = self_in;
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
const byte *ip = self->bytecode;
// get code info size, and skip line number table
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
ip += code_info_size;
// bytecode prelude: state size and exception stack size; 16 bit uints
machine_uint_t n_state = ip[0] | (ip[1] << 8);
machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
ip += 4;
#if VM_DETECT_STACK_OVERFLOW
n_state += 1;
#endif
// allocate state for locals and stack
uint state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
mp_code_state *code_state;
if (state_size > VM_MAX_STATE_ON_STACK) {
code_state = m_new_obj_var(mp_code_state, byte, state_size);
} else {
code_state = alloca(sizeof(mp_code_state) + state_size);
}
code_state->n_state = n_state;
code_state->ip = ip;
mp_setup_code_state(code_state, self_in, n_args, n_kw, args);
// execute the byte code with the correct globals context
mp_obj_dict_t *old_globals = mp_globals_get();
mp_globals_set(self->globals);
mp_obj_t result;
DEBUG_printf("Calling: args=%p, n_args=%d, extra_args=%p, n_extra_args=%d\n", args, n_args, extra_args, n_extra_args);
dump_args(args, n_args);
dump_args(extra_args, n_extra_args);
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(self->bytecode, args, n_args, extra_args, n_extra_args, &result);
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);
mp_globals_set(old_globals);
#if VM_DETECT_STACK_OVERFLOW
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
if (code_state->sp < code_state->state) {
printf("VM stack underflow: " INT_FMT "\n", code_state->sp - code_state->state);
assert(0);
}
}
// We can't check the case when an exception is returned in state[n_state - 1]
// and there are no arguments, because in this case our detection slot may have
// been overwritten by the returned exception (which is allowed).
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && self->n_pos_args + self->n_kwonly_args == 0)) {
// Just check to see that we have at least 1 null object left in the state.
bool overflow = true;
for (uint i = 0; i < n_state - self->n_pos_args - self->n_kwonly_args; i++) {
if (code_state->state[i] == MP_OBJ_NULL) {
overflow = false;
break;
}
}
if (overflow) {
printf("VM stack overflow state=%p n_state+1=" UINT_FMT "\n", code_state->state, n_state);
assert(0);
}
}
#endif
mp_obj_t result;
switch (vm_return_kind) {
case MP_VM_RETURN_NORMAL:
// return value is in *sp
result = *code_state->sp;
break;
case MP_VM_RETURN_EXCEPTION:
// return value is in state[n_state - 1]
result = code_state->state[n_state - 1];
break;
case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
default:
assert(0);
result = mp_const_none;
vm_return_kind = MP_VM_RETURN_NORMAL;
break;
}
// free the state if it was allocated on the heap
if (state_size > VM_MAX_STATE_ON_STACK) {
m_del_var(mp_code_state, byte, state_size, code_state);
}
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
return result;
} else { // MP_VM_RETURN_EXCEPTION
@@ -398,7 +466,7 @@ const mp_obj_type_t mp_type_fun_bc = {
.binary_op = fun_binary_op,
};
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, const byte *code) {
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
uint n_def_args = 0;
uint n_extra_args = 0;
mp_obj_tuple_t *def_args = def_args_in;
@@ -407,10 +475,7 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
n_def_args = def_args->len;
n_extra_args = def_args->len;
}
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
n_extra_args += 1;
}
if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
if (def_kw_args != MP_OBJ_NULL) {
n_extra_args += 1;
}
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
@@ -420,18 +485,15 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
o->n_pos_args = n_pos_args;
o->n_kwonly_args = n_kwonly_args;
o->n_def_args = n_def_args;
o->has_def_kw_args = def_kw_args != MP_OBJ_NULL;
o->takes_var_args = (scope_flags & MP_SCOPE_FLAG_VARARGS) != 0;
o->takes_kw_args = (scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0;
o->bytecode = code;
memset(o->extra_args, 0, n_extra_args * sizeof(mp_obj_t));
if (def_args != MP_OBJ_NULL) {
memcpy(o->extra_args, def_args->items, n_def_args * sizeof(mp_obj_t));
}
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
o->extra_args[n_def_args] = MP_OBJ_NULL;
}
if ((scope_flags & MP_SCOPE_FLAG_VARARGS) != 0) {
o->extra_args[n_extra_args - 1] = MP_OBJ_NULL;
if (def_kw_args != MP_OBJ_NULL) {
o->extra_args[n_def_args] = def_kw_args;
}
return o;
}
@@ -468,7 +530,7 @@ STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
} else {
mp_obj_type_t *type = mp_obj_get_type(obj);
if (0) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (type == &mp_type_float) {
// convert float to int (could also pass in float registers)
return (machine_int_t)mp_obj_float_get(obj);

View File

@@ -30,10 +30,15 @@ typedef struct _mp_obj_fun_bc_t {
machine_uint_t n_pos_args : 16; // number of arguments this function takes
machine_uint_t n_kwonly_args : 16; // number of arguments this function takes
machine_uint_t n_def_args : 16; // number of default arguments
machine_uint_t has_def_kw_args : 1; // set if this function has default keyword args
machine_uint_t takes_var_args : 1; // set if this function takes variable args
machine_uint_t takes_kw_args : 1; // set if this function takes keyword args
const byte *bytecode; // bytecode for the function
qstr *args; // argument names (needed to resolve positional args passed as keywords)
// values of default args (if any), plus a slot at the end for var args and/or kw args (if it takes them)
// the following extra_args array is allocated space to take (in order):
// - values of positional default args (if any)
// - a single slot for default kw args dict (if it has them)
// - a single slot for var args tuple (if it takes them)
// - a single slot for kw args dict (if it takes them)
mp_obj_t extra_args[];
} mp_obj_fun_bc_t;

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -45,21 +46,37 @@ typedef struct _mp_obj_gen_wrap_t {
mp_obj_t *fun;
} mp_obj_gen_wrap_t;
mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
uint n_args2, const mp_obj_t *args2);
typedef struct _mp_obj_gen_instance_t {
mp_obj_base_t base;
mp_obj_dict_t *globals;
mp_code_state code_state;
} mp_obj_gen_instance_t;
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_gen_wrap_t *self = self_in;
mp_obj_fun_bc_t *self_fun = (mp_obj_fun_bc_t*)self->fun;
assert(MP_OBJ_IS_TYPE(self_fun, &mp_type_fun_bc));
const mp_obj_t *args1, *args2;
uint len1, len2;
if (!mp_obj_fun_prepare_simple_args(self_fun, n_args, n_kw, args, &len1, &args1, &len2, &args2)) {
assert(0);
}
const byte *bytecode = self_fun->bytecode;
// get code info size, and skip the line number table
machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
bytecode += code_info_size;
return mp_obj_new_gen_instance(self_fun->globals, self_fun->bytecode, len1, args1, len2, args2);
// bytecode prelude: get state size and exception stack size
machine_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
bytecode += 4;
// allocate the generator object, with room for local stack and exception stack
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte,
n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
o->base.type = &mp_type_gen_instance;
o->globals = self_fun->globals;
o->code_state.n_state = n_state;
o->code_state.ip = bytecode;
mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args);
return o;
}
const mp_obj_type_t mp_type_gen_wrap = {
@@ -78,49 +95,28 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) {
/******************************************************************************/
/* generator instance */
typedef struct _mp_obj_gen_instance_t {
mp_obj_base_t base;
mp_obj_dict_t *globals;
const byte *code_info;
const byte *ip;
mp_obj_t *sp;
// bit 0 is saved currently_in_except_block value
mp_exc_stack_t *exc_sp;
uint n_state;
// Variable-length
mp_obj_t state[0];
// Variable-length, never accessed by name, only as (void*)(state + n_state)
//mp_exc_stack_t exc_state[0];
} mp_obj_gen_instance_t;
void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_gen_instance_t *self = self_in;
print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_info), self_in);
}
mp_obj_t gen_instance_getiter(mp_obj_t self_in) {
return self_in;
print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_state.code_info), self_in);
}
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance));
mp_obj_gen_instance_t *self = self_in;
if (self->ip == 0) {
if (self->code_state.ip == 0) {
*ret_val = MP_OBJ_STOP_ITERATION;
return MP_VM_RETURN_NORMAL;
}
if (self->sp == self->state - 1) {
if (self->code_state.sp == self->code_state.state - 1) {
if (send_value != mp_const_none) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator"));
}
} else {
*self->sp = send_value;
*self->code_state.sp = send_value;
}
mp_obj_dict_t *old_globals = mp_globals_get();
mp_globals_set(self->globals);
mp_vm_return_kind_t ret_kind = mp_execute_bytecode2(self->code_info, &self->ip,
&self->state[self->n_state - 1], &self->sp, (mp_exc_stack_t*)(self->state + self->n_state),
&self->exc_sp, throw_value);
mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
mp_globals_set(old_globals);
switch (ret_kind) {
@@ -130,17 +126,17 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
// again and again, leading to side effects.
// TODO: check how return with value behaves under such conditions
// in CPython.
self->ip = 0;
*ret_val = *self->sp;
self->code_state.ip = 0;
*ret_val = *self->code_state.sp;
break;
case MP_VM_RETURN_YIELD:
*ret_val = *self->sp;
*ret_val = *self->code_state.sp;
break;
case MP_VM_RETURN_EXCEPTION:
self->ip = 0;
*ret_val = self->state[self->n_state - 1];
self->code_state.ip = 0;
*ret_val = self->code_state.state[self->code_state.n_state - 1];
break;
default:
@@ -250,53 +246,7 @@ const mp_obj_type_t mp_type_gen_instance = {
{ &mp_type_type },
.name = MP_QSTR_generator,
.print = gen_instance_print,
.getiter = gen_instance_getiter,
.getiter = mp_identity,
.iternext = gen_instance_iternext,
.locals_dict = (mp_obj_t)&gen_instance_locals_dict,
};
mp_obj_t mp_obj_new_gen_instance(mp_obj_dict_t *globals, const byte *bytecode, uint n_args, const mp_obj_t *args,
uint n_args2, const mp_obj_t *args2) {
const byte *code_info = bytecode;
// get code info size, and skip the line number table
machine_uint_t code_info_size = bytecode[0] | (bytecode[1] << 8) | (bytecode[2] << 16) | (bytecode[3] << 24);
bytecode += code_info_size;
// bytecode prelude: get state size and exception stack size
machine_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
machine_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
bytecode += 4;
// allocate the generator object, with room for local stack and exception stack
mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t));
o->base.type = &mp_type_gen_instance;
o->globals = globals;
o->code_info = code_info;
o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state
o->exc_sp = (mp_exc_stack_t*)(o->state + n_state) - 1;
o->n_state = n_state;
// copy args to end of state array, in reverse (that's how mp_execute_bytecode2 needs it)
for (uint i = 0; i < n_args; i++) {
o->state[n_state - 1 - i] = args[i];
}
for (uint i = 0; i < n_args2; i++) {
o->state[n_state - 1 - n_args - i] = args2[i];
}
// set rest of state to MP_OBJ_NULL
for (uint i = 0; i < n_state - n_args - n_args2; i++) {
o->state[i] = MP_OBJ_NULL;
}
// bytecode prelude: initialise closed over variables
for (uint n_local = *bytecode++; n_local > 0; n_local--) {
uint local_num = *bytecode++;
o->state[n_state - 1 - local_num] = mp_obj_new_cell(o->state[n_state - 1 - local_num]);
}
// set ip to start of actual byte code
o->ip = bytecode;
return o;
}

View File

@@ -35,12 +35,13 @@
#include "qstr.h"
#include "obj.h"
#include "parsenum.h"
#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
#include "runtime.h"
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
#endif
@@ -53,16 +54,20 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
return MP_OBJ_NEW_SMALL_INT(0);
case 1:
if (MP_OBJ_IS_STR(args[0])) {
if (MP_OBJ_IS_INT(args[0])) {
// already an int (small or long), just return it
return args[0];
} else if (MP_OBJ_IS_STR(args[0])) {
// a string, parse it
uint l;
const char *s = mp_obj_str_get_data(args[0], &l);
return mp_parse_num_integer(s, l, 0);
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
#endif
} else {
// try to convert to small int (eg from bool)
return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
}
@@ -122,14 +127,14 @@ STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma)
return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
}
// This routine expects you to pass in a buffer and size (in *buf and buf_size).
// This routine expects you to pass in a buffer and size (in *buf and *buf_size).
// If, for some reason, this buffer is too small, then it will allocate a
// buffer and return the allocated buffer and size in *buf and *buf_size. It
// is the callers responsibility to free this allocated buffer.
//
// The resulting formatted string will be returned from this function and the
// formatted size will be in *fmt_size.
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
fmt_int_t num;
if (MP_OBJ_IS_SMALL_INT(self_in)) {
@@ -139,7 +144,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
// Not a small int.
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
mp_obj_int_t *self = self_in;
const mp_obj_int_t *self = self_in;
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
num = self->val;
#else
@@ -149,7 +154,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
#endif
} else {
// Not an int.
buf[0] = '\0';
**buf = '\0';
*fmt_size = 0;
return *buf;
}
@@ -216,7 +221,7 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) {
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
// This is called for operations on SMALL_INT that are not handled by mp_binary_op
@@ -225,7 +230,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
// This is called only with strings whose value doesn't fit in SMALL_INT
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
return mp_const_none;
}
@@ -247,22 +252,22 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
if (MP_OBJ_FITS_SMALL_INT(value)) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
return mp_const_none;
}
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
@@ -285,7 +290,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_
return mp_binary_op(op, rhs_in, lhs_in);
}
}
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
// this is a classmethod

View File

@@ -34,9 +34,9 @@ typedef struct _mp_obj_int_t {
} mp_obj_int_t;
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
bool mp_obj_int_is_positive(mp_obj_t self_in);
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +34,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
@@ -63,7 +65,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
case MP_UNARY_OP_POSITIVE: return o_in;
case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val);
case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -76,7 +78,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
} else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
lhs_val = ((mp_obj_int_t*)lhs_in)->val;
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
@@ -134,12 +136,12 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(lhs_val == rhs_val);
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
if (MP_OBJ_FITS_SMALL_INT(value)) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
return mp_obj_new_int_from_ll(value);
@@ -161,36 +163,32 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
return o;
}
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
const char *s = qstr_str(qst);
long long v;
char *end;
// TODO: this doesn't handle Python hacked 0o octal syntax
v = strtoll(s, &end, 0);
if (*end != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
}
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
// TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated
// TODO check overflow
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
o->base.type = &mp_type_int;
o->val = v;
char *endptr;
o->val = strtoll(*str, &endptr, base);
*str = endptr;
return o;
}
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
} else {
mp_obj_int_t *self = self_in;
const mp_obj_int_t *self = self_in;
return self->val;
}
}
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
// TODO: Check overflow
return mp_obj_int_get(self_in);
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);

View File

@@ -35,6 +35,7 @@
#include "qstr.h"
#include "parsenumbase.h"
#include "obj.h"
#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
@@ -58,10 +59,10 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
// formatted size will be in *fmt_size.
//
// This particular routine should only be called for the mpz representation of the int.
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
mp_obj_int_t *self = self_in;
const mp_obj_int_t *self = self_in;
uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma);
if (needed_size > *buf_size) {
@@ -90,7 +91,7 @@ mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
case MP_UNARY_OP_POSITIVE: return o_in;
case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return o2; }
case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return o2; }
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -108,7 +109,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
zlhs = &((mp_obj_int_t*)lhs_in)->mpz;
} else {
// unsupported type
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL;
}
// if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
@@ -117,7 +118,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
zrhs = &z_int;
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
zrhs = &((mp_obj_int_t*)rhs_in)->mpz;
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) {
return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
@@ -129,7 +130,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
if (0) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
mp_float_t flhs = mpz_as_float(zlhs);
mp_float_t frhs = mpz_as_float(zrhs);
@@ -213,7 +214,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
break;
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
return res;
@@ -233,13 +234,13 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(cmp == 0);
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
if (MP_OBJ_FITS_SMALL_INT(value)) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
return mp_obj_new_int_from_ll(value);
@@ -260,35 +261,27 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
return mp_obj_new_int_from_ll(value);
}
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
mp_obj_int_t *o = mp_obj_int_new_mpz();
uint len;
const char* str = (const char*)qstr_data(qst, &len);
int base = 0;
int skip = mp_parse_num_base(str, len, &base);
str += skip;
len -= skip;
uint n = mpz_set_from_str(&o->mpz, str, len, false, base);
if (n != len) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
}
uint n = mpz_set_from_str(&o->mpz, *str, len, neg, base);
*str += n;
return o;
}
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
} else {
mp_obj_int_t *self = self_in;
const mp_obj_int_t *self = self_in;
return mpz_as_int(&self->mpz);
}
}
machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
} else {
mp_obj_int_t *self = self_in;
const mp_obj_int_t *self = self_in;
machine_int_t value;
if (mpz_as_int_checked(&self->mpz, &value)) {
return value;
@@ -299,7 +292,7 @@ machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
}
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);

View File

@@ -103,7 +103,7 @@ STATIC mp_obj_t list_unary_op(int op, mp_obj_t self_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -112,7 +112,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
switch (op) {
case MP_BINARY_OP_ADD: {
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
mp_obj_list_t *p = rhs;
mp_obj_list_t *s = list_new(o->len + p->len);
@@ -121,7 +121,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
case MP_BINARY_OP_INPLACE_ADD: {
if (!MP_OBJ_IS_TYPE(rhs, &mp_type_list)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
list_extend(lhs, rhs);
return o;
@@ -129,7 +129,7 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
case MP_BINARY_OP_MULTIPLY: {
machine_int_t n;
if (!mp_obj_get_int_maybe(rhs, &n)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
mp_obj_list_t *s = list_new(o->len * n);
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
@@ -143,25 +143,25 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return MP_BOOL(list_cmp_helper(op, lhs, rhs));
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_NULL) {
// delete
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_obj_list_t *self = self_in;
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
assert(0);
}
int len_adj = start - stop;
int len_adj = slice.start - slice.stop;
//printf("Len adj: %d\n", len_adj);
assert(len_adj <= 0);
mp_seq_replace_slice_no_grow(self->items, self->len, start, stop, self->items/*NULL*/, 0, mp_obj_t);
mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, mp_obj_t);
// Clear "freed" elements at the end of list
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
self->len += len_adj;
@@ -174,37 +174,48 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
} else if (value == MP_OBJ_SENTINEL) {
// load
mp_obj_list_t *self = self_in;
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
assert(0);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
return mp_seq_extract_slice(self->len, self->items, &slice);
}
mp_obj_list_t *res = list_new(stop - start);
mp_seq_copy(res->items, self->items + start, res->len, mp_obj_t);
mp_obj_list_t *res = list_new(slice.stop - slice.start);
mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);
return res;
}
#endif
uint index_val = mp_get_index(self->base.type, self->len, index, false);
return self->items[index_val];
} else {
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_obj_list_t *self = self_in;
assert(MP_OBJ_IS_TYPE(value, &mp_type_list));
mp_obj_list_t *slice = value;
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
mp_bound_slice_t slice_out;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
assert(0);
}
int len_adj = slice->len - (stop - start);
int len_adj = slice->len - (slice_out.stop - slice_out.start);
//printf("Len adj: %d\n", len_adj);
assert(len_adj <= 0);
mp_seq_replace_slice_no_grow(self->items, self->len, start, stop, slice->items, slice->len, mp_obj_t);
// Clear "freed" elements at the end of list
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
if (len_adj > 0) {
if (self->len + len_adj > self->alloc) {
// TODO: Might optimize memory copies here by checking if block can
// be grown inplace or not
self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj);
self->alloc = self->len + len_adj;
}
mp_seq_replace_slice_grow_inplace(self->items, self->len,
slice_out.start, slice_out.stop, slice->items, slice->len, len_adj, mp_obj_t);
} else {
mp_seq_replace_slice_no_grow(self->items, self->len,
slice_out.start, slice_out.stop, slice->items, slice->len, mp_obj_t);
// Clear "freed" elements at the end of list
mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
// TODO: apply allocation policy re: alloc_size
}
self->len += len_adj;
// TODO: apply allocation policy re: alloc_size
return mp_const_none;
}
#endif

View File

@@ -56,10 +56,6 @@ STATIC mp_obj_t map_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
return o;
}
STATIC mp_obj_t map_getiter(mp_obj_t self_in) {
return self_in;
}
STATIC mp_obj_t map_iternext(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_map));
mp_obj_map_t *self = self_in;
@@ -80,6 +76,6 @@ const mp_obj_type_t mp_type_map = {
{ &mp_type_type },
.name = MP_QSTR_map,
.make_new = map_make_new,
.getiter = map_getiter,
.getiter = mp_identity,
.iternext = map_iternext,
};

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,7 +34,7 @@
#include "obj.h"
#include "objtuple.h"
#if MICROPY_ENABLE_MOD_COLLECTIONS
#if MICROPY_PY_COLLECTIONS
typedef struct _mp_obj_namedtuple_type_t {
mp_obj_type_t base;
@@ -173,4 +174,4 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) {
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type);
#endif // MICROPY_ENABLE_MOD_COLLECTIONS
#endif // MICROPY_PY_COLLECTIONS

View File

@@ -44,7 +44,7 @@ STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env
STATIC mp_obj_t none_unary_op(int op, mp_obj_t o_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return mp_const_false;
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}

View File

@@ -33,6 +33,8 @@
#include "obj.h"
#include "runtime0.h"
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
typedef struct _mp_obj_object_t {
mp_obj_base_t base;
} mp_obj_object_t;
@@ -47,8 +49,35 @@ STATIC mp_obj_t object_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
return o;
}
#if MICROPY_CPYTHON_COMPAT
STATIC mp_obj_t object___init__(mp_obj_t self) {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__);
STATIC mp_obj_t object___new__(mp_obj_t cls) {
mp_obj_t o = MP_OBJ_SENTINEL;
mp_obj_t res = instance_make_new(cls, 1, 0, &o);
return res;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, (const mp_obj_t)&object___new___fun_obj);
#endif
STATIC const mp_map_elem_t object_locals_dict_table[] = {
#if MICROPY_CPYTHON_COMPAT
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&object___init___obj },
#endif
#if MICROPY_CPYTHON_COMPAT
{ MP_OBJ_NEW_QSTR(MP_QSTR___new__), (mp_obj_t)&object___new___obj },
#endif
};
STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);
const mp_obj_type_t mp_type_object = {
{ &mp_type_type },
.name = MP_QSTR_object,
.make_new = object_make_new,
.locals_dict = (mp_obj_t)&object_locals_dict,
};

View File

@@ -34,7 +34,7 @@
#include "obj.h"
#include "runtime.h"
#if MICROPY_ENABLE_PROPERTY
#if MICROPY_PY_BUILTINS_PROPERTY
typedef struct _mp_obj_property_t {
mp_obj_base_t base;
@@ -115,4 +115,4 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) {
return self->proxy;
}
#endif // MICROPY_ENABLE_PROPERTY
#endif // MICROPY_PY_BUILTINS_PROPERTY

View File

@@ -37,6 +37,8 @@
#include "runtime0.h"
#include "builtin.h"
#if MICROPY_PY_BUILTINS_SET
typedef struct _mp_obj_set_t {
mp_obj_base_t base;
mp_set_t set;
@@ -52,13 +54,13 @@ STATIC mp_obj_t set_it_iternext(mp_obj_t self_in);
STATIC bool is_set_or_frozenset(mp_obj_t o) {
return MP_OBJ_IS_TYPE(o, &mp_type_set)
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
|| MP_OBJ_IS_TYPE(o, &mp_type_frozenset)
#endif
;
}
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
STATIC void check_set_or_frozenset(mp_obj_t o) {
if (!is_set_or_frozenset(o)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'set' object required"));
@@ -72,7 +74,7 @@ STATIC void check_set(mp_obj_t o) {
if (!MP_OBJ_IS_TYPE(o, &mp_type_set)) {
// Emulate CPython behavior
// AttributeError: 'frozenset' object has no attribute 'add'
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"));
}
@@ -83,11 +85,11 @@ STATIC void check_set(mp_obj_t o) {
STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_set_t *self = self_in;
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
bool is_frozen = MP_OBJ_IS_TYPE(self_in, &mp_type_frozenset);
#endif
if (self->set.used == 0) {
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, "frozen");
}
@@ -96,7 +98,7 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env,
return;
}
bool first = true;
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, "frozenset(");
}
@@ -112,7 +114,7 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env,
}
}
print(env, "}");
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, ")");
}
@@ -475,7 +477,7 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -514,7 +516,7 @@ STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return MP_BOOL(elem != NULL);
}
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
@@ -556,7 +558,7 @@ const mp_obj_type_t mp_type_set = {
.locals_dict = (mp_obj_t)&set_locals_dict,
};
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
const mp_obj_type_t mp_type_frozenset = {
{ &mp_type_type },
.name = MP_QSTR_frozenset,
@@ -584,3 +586,5 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
mp_obj_set_t *self = self_in;
mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
#endif // MICROPY_PY_BUILTINS_SET

View File

@@ -56,19 +56,26 @@ const mp_obj_ellipsis_t mp_const_ellipsis_obj = {{&mp_type_ellipsis}};
/******************************************************************************/
/* slice object */
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
// TODO: This implements only variant of slice with 2 integer args only.
// CPython supports 3rd arg (step), plus args can be arbitrary Python objects.
typedef struct _mp_obj_slice_t {
mp_obj_base_t base;
machine_int_t start;
machine_int_t stop;
mp_obj_t start;
mp_obj_t stop;
mp_obj_t step;
} mp_obj_slice_t;
void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_slice_t *o = o_in;
print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop);
print(env, "slice(");
mp_obj_print_helper(print, env, o->start, PRINT_REPR);
print(env, ", ");
mp_obj_print_helper(print, env, o->stop, PRINT_REPR);
print(env, ", ");
mp_obj_print_helper(print, env, o->step, PRINT_REPR);
print(env, ")");
}
const mp_obj_type_t mp_type_slice = {
@@ -77,39 +84,21 @@ const mp_obj_type_t mp_type_slice = {
.print = slice_print,
};
// TODO: Make sure to handle "empty" values, which are signified by None in CPython
mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
assert(ostep == NULL);
machine_int_t start = 0, stop = 0;
if (ostart != mp_const_none) {
start = mp_obj_get_int(ostart);
}
if (ostop != mp_const_none) {
stop = mp_obj_get_int(ostop);
if (stop == 0) {
// [x:0] is a special case - in our slice object, stop = 0 means
// "end of sequence". Fortunately, [x:0] is an empty seqence for
// any x (including negative). [x:x] is also always empty sequence.
// but x also can be 0. But note that b""[x:x] is b"" for any x (i.e.
// no IndexError, at least in Python 3.3.3). So, we just use -1's to
// signify that. -1 is catchy "special" number in case someone will
// try to print [x:0] slice ever.
start = stop = -1;
}
}
mp_obj_slice_t *o = m_new(mp_obj_slice_t, 1);
mp_obj_slice_t *o = m_new_obj(mp_obj_slice_t);
o->base.type = &mp_type_slice;
o->start = start;
o->stop = stop;
return (mp_obj_t)o;
o->start = ostart;
o->stop = ostop;
o->step = ostep;
return o;
}
void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step) {
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_slice));
mp_obj_slice_t *self = self_in;
*start = self->start;
*stop = self->stop;
*step = 1;
*step = self->step;
}
#endif

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,8 +38,9 @@
#include "runtime.h"
#include "pfenv.h"
#include "objstr.h"
#include "objlist.h"
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args);
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict);
const mp_obj_t mp_const_empty_bytes;
// use this macro to extract the string hash
@@ -52,7 +54,6 @@ const mp_obj_t mp_const_empty_bytes;
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
STATIC NORETURN void arg_type_mixup();
@@ -67,7 +68,7 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
// this escapes characters, but it will be very slow to print (calling print many times)
bool has_single_quote = false;
bool has_double_quote = false;
for (const byte *s = str_data, *top = str_data + str_len; (!has_single_quote || !has_double_quote) && s < top; s++) {
for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
if (*s == '\'') {
has_single_quote = true;
} else if (*s == '"') {
@@ -127,7 +128,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
{
vstr_t *vstr = vstr_new();
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR);
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
}
@@ -141,7 +142,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
}
GET_STR_DATA_LEN(args[0], str_data, str_len);
GET_STR_HASH(args[0], str_hash);
mp_obj_str_t *o = str_new(&mp_type_str, NULL, str_len);
mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len);
o->data = str_data;
o->hash = str_hash;
return o;
@@ -169,7 +170,7 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
}
GET_STR_DATA_LEN(args[0], str_data, str_len);
GET_STR_HASH(args[0], str_hash);
mp_obj_str_t *o = str_new(&mp_type_bytes, NULL, str_len);
mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len);
o->data = str_data;
o->hash = str_hash;
return o;
@@ -294,7 +295,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_MULTIPLY: {
if (!MP_OBJ_IS_SMALL_INT(rhs_in)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
int n = MP_OBJ_SMALL_INT_VALUE(rhs_in);
byte *data;
@@ -306,14 +307,19 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_MODULO: {
mp_obj_t *args;
uint n_args;
mp_obj_t dict = MP_OBJ_NULL;
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple)) {
// TODO: Support tuple subclasses?
mp_obj_tuple_get(rhs_in, &n_args, &args);
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_dict)) {
args = NULL;
n_args = 0;
dict = rhs_in;
} else {
args = &rhs_in;
n_args = 1;
}
return str_modulo_format(lhs_in, n_args, args);
return str_modulo_format(lhs_in, n_args, args, dict);
}
//case MP_BINARY_OP_NOT_EQUAL: // This is never passed here
@@ -326,9 +332,20 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len);
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));
}
if (lhs_type == &mp_type_bytes) {
mp_buffer_info_t bufinfo;
if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {
goto uncomparable;
}
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_data, lhs_len, bufinfo.buf, bufinfo.len));
}
uncomparable:
if (op == MP_BINARY_OP_EQUAL) {
return mp_const_false;
}
}
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
@@ -336,23 +353,24 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
GET_STR_DATA_LEN(self_in, self_data, self_len);
if (value == MP_OBJ_SENTINEL) {
// load
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(self_len, index, &start, &stop)) {
assert(0);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
return str_new(type, self_data + start, stop - start);
return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
}
#endif
uint index_val = mp_get_index(type, self_len, index, false);
if (type == &mp_type_bytes) {
return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self_data[index_val]);
} else {
return mp_obj_new_str(self_data + index_val, 1, true);
return mp_obj_new_str((char*)self_data + index_val, 1, true);
}
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
@@ -433,7 +451,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
while (s < top && splits != 0) {
const byte *start = s;
while (s < top && !is_ws(*s)) s++;
mp_obj_list_append(res, str_new(self_type, start, s - start));
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
if (s >= top) {
break;
}
@@ -444,7 +462,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
}
if (s < top) {
mp_obj_list_append(res, str_new(self_type, s, top - s));
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, s, top - s));
}
} else {
@@ -468,7 +486,7 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
}
s++;
}
mp_obj_list_append(res, str_new(self_type, start, s - start));
mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start));
if (s >= top) {
break;
}
@@ -482,6 +500,68 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
return res;
}
STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
if (n_args < 3) {
// If we don't have split limit, it doesn't matter from which side
// we split.
return str_split(n_args, args);
}
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
mp_obj_t sep = args[1];
GET_STR_DATA_LEN(args[0], s, len);
machine_int_t splits = mp_obj_get_int(args[2]);
machine_int_t org_splits = splits;
// Preallocate list to the max expected # of elements, as we
// will fill it from the end.
mp_obj_list_t *res = mp_obj_new_list(splits + 1, NULL);
int idx = splits;
if (sep == mp_const_none) {
assert(!"TODO: rsplit(None,n) not implemented");
} else {
uint sep_len;
const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
if (sep_len == 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator"));
}
const byte *beg = s;
const byte *last = s + len;
for (;;) {
s = last - sep_len;
for (;;) {
if (splits == 0 || s < beg) {
break;
} else if (memcmp(s, sep_str, sep_len) == 0) {
break;
}
s--;
}
if (s < beg || splits == 0) {
res->items[idx] = mp_obj_new_str_of_type(self_type, beg, last - beg);
break;
}
res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len);
last = s;
if (splits > 0) {
splits--;
}
}
if (idx != 0) {
// We split less parts than split limit, now go cleanup surplus
int used = org_splits + 1 - idx;
memcpy(res->items, &res->items[idx], used * sizeof(mp_obj_t));
mp_seq_clear(res->items, used, res->alloc, sizeof(*res->items));
res->len = used;
}
}
return res;
}
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) {
assert(2 <= n_args && n_args <= 4);
assert(MP_OBJ_IS_STR(args[0]));
@@ -530,13 +610,28 @@ STATIC mp_obj_t str_rindex(uint n_args, const mp_obj_t *args) {
}
// TODO: (Much) more variety in args
STATIC mp_obj_t str_startswith(mp_obj_t self_in, mp_obj_t arg) {
GET_STR_DATA_LEN(self_in, str, str_len);
GET_STR_DATA_LEN(arg, prefix, prefix_len);
if (prefix_len > str_len) {
STATIC mp_obj_t str_startswith(uint n_args, const mp_obj_t *args) {
GET_STR_DATA_LEN(args[0], str, str_len);
GET_STR_DATA_LEN(args[1], prefix, prefix_len);
uint index_val = 0;
if (n_args > 2) {
index_val = mp_get_index(&mp_type_str, str_len, args[2], true);
}
if (prefix_len + index_val > str_len) {
return mp_const_false;
}
return MP_BOOL(memcmp(str, prefix, prefix_len) == 0);
return MP_BOOL(memcmp(str + index_val, prefix, prefix_len) == 0);
}
STATIC mp_obj_t str_endswith(uint n_args, const mp_obj_t *args) {
GET_STR_DATA_LEN(args[0], str, str_len);
GET_STR_DATA_LEN(args[1], suffix, suffix_len);
assert(n_args == 2);
if (suffix_len > str_len) {
return mp_const_false;
}
return MP_BOOL(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0);
}
enum { LSTRIP, RSTRIP, STRIP };
@@ -576,6 +671,7 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
for (machine_uint_t len = orig_str_len; len > 0; len--) {
if (find_subbytes(chars_to_del, chars_to_del_len, &orig_str[i], 1, 1) == NULL) {
if (!first_good_char_pos_set) {
first_good_char_pos_set = true;
first_good_char_pos = i;
if (type == LSTRIP) {
last_good_char_pos = orig_str_len - 1;
@@ -585,14 +681,13 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
last_good_char_pos = i;
break;
}
first_good_char_pos_set = true;
}
last_good_char_pos = i;
}
i += delta;
}
if (first_good_char_pos == 0 && last_good_char_pos == 0) {
if (!first_good_char_pos_set) {
// string is all whitespace, return ''
return MP_OBJ_NEW_QSTR(MP_QSTR_);
}
@@ -600,7 +695,13 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
assert(last_good_char_pos >= first_good_char_pos);
//+1 to accomodate the last character
machine_uint_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
return str_new(self_type, orig_str + first_good_char_pos, stripped_len);
if (stripped_len == orig_str_len) {
// If nothing was stripped, don't bother to dup original string
// TODO: watch out for this case when we'll get to bytearray.strip()
assert(first_good_char_pos == 0);
return args[0];
}
return mp_obj_new_str_of_type(self_type, orig_str + first_good_char_pos, stripped_len);
}
STATIC mp_obj_t str_strip(uint n_args, const mp_obj_t *args) {
@@ -644,14 +745,14 @@ static bool arg_looks_integer(mp_obj_t arg) {
static bool arg_looks_numeric(mp_obj_t arg) {
return arg_looks_integer(arg)
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
|| MP_OBJ_IS_TYPE(arg, &mp_type_float)
#endif
;
}
static mp_obj_t arg_as_int(mp_obj_t arg) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
// TODO: Needs a way to construct an mpz integer from a float
@@ -680,7 +781,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
vstr_add_char(vstr, '}');
continue;
}
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Single '}' encountered in format string"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "single '}' encountered in format string"));
}
if (*str != '{') {
vstr_add_char(vstr, *str);
@@ -726,7 +827,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
// '{:d}'.format(True) returns '1'
// So we treat {:} as {} and this later gets treated to be {!s}
if (*str != '}') {
format_spec = vstr_new();
format_spec = vstr_new();
while (str < top && *str != '}') {
vstr_add_char(format_spec, *str++);
}
@@ -744,7 +845,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
if (field_name) {
if (arg_i > 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from automatic field numbering to manual field specification"));
}
int index = 0;
if (str_to_int(vstr_str(field_name), &index) != vstr_len(field_name) - 1) {
@@ -759,7 +860,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
field_name = NULL;
} else {
if (arg_i < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from manual field specification to automatic field numbering"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't switch from manual field specification to automatic field numbering"));
}
if (arg_i >= n_args - 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range"));
@@ -777,11 +878,11 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
} else if (conversion == 'r') {
print_kind = PRINT_REPR;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown conversion specifier %c", conversion));
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", conversion));
}
vstr_t *arg_vstr = vstr_new();
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, arg_vstr, arg, print_kind);
arg = mp_obj_new_str((const byte *)vstr_str(arg_vstr), vstr_len(arg_vstr), false);
arg = mp_obj_new_str(vstr_str(arg_vstr), vstr_len(arg_vstr), false);
vstr_free(arg_vstr);
}
@@ -880,7 +981,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
if (arg_looks_integer(arg)) {
switch (type) {
case 'b':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width);
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width, 0);
continue;
case 'c':
@@ -893,7 +994,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
case '\0': // No explicit format type implies 'd'
case 'n': // I don't think we support locales in uPy so use 'd'
case 'd':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width);
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width, 0);
continue;
case 'o':
@@ -901,15 +1002,12 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
flags |= PF_FLAG_SHOW_OCTAL_LETTER;
}
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width);
continue;
case 'x':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'a', flags, fill, width);
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, 0);
continue;
case 'X':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, 'A', flags, fill, width);
case 'x':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width, 0);
continue;
case 'e':
@@ -925,7 +1023,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
default:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"Unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg)));
"unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg)));
}
}
@@ -937,7 +1035,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
// Even though the docs say that an unspecified type is the same
// as 'g', there is one subtle difference, when the exponent
// is one less than the precision.
//
//
// '{:10.1}'.format(0.0) ==> '0e+00'
// '{:10.1g}'.format(0.0) ==> '0'
//
@@ -969,14 +1067,14 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
flags |= PF_FLAG_PAD_NAN_INF; // '{:06e}'.format(float('-inf')) should give '-00inf'
switch (type) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision);
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision);
break;
case '%':
@@ -987,7 +1085,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
default:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"Unknown format code '%c' for object of type 'float'",
"unknown format code '%c' for object of type 'float'",
type, mp_obj_get_type_str(arg)));
}
} else {
@@ -1018,18 +1116,18 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
default:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"Unknown format code '%c' for object of type 'str'",
"unknown format code '%c' for object of type 'str'",
type, mp_obj_get_type_str(arg)));
}
}
}
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
}
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict) {
assert(MP_OBJ_IS_STR(pattern));
GET_STR_DATA_LEN(pattern, str, len);
@@ -1041,6 +1139,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
pfenv_vstr.print_strn = pfenv_vstr_add_strn;
for (const byte *top = str + len; str < top; str++) {
mp_obj_t arg = MP_OBJ_NULL;
if (*str != '%') {
vstr_add_char(vstr, *str);
continue;
@@ -1052,17 +1151,29 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
vstr_add_char(vstr, '%');
continue;
}
if (arg_i >= n_args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
// Dictionary value lookup
if (*str == '(') {
const byte *key = ++str;
while (*str != ')') {
if (str >= top) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format key"));
}
++str;
}
mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true);
arg = mp_obj_dict_get(dict, k_obj);
str++;
}
int flags = 0;
char fill = ' ';
bool alt = false;
int alt = 0;
while (str < top) {
if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*str == '#') alt = true;
else if (*str == '#') alt = PF_FLAG_SHOW_PREFIX;
else if (*str == '0') {
flags |= PF_FLAG_PAD_AFTER_SIGN;
fill = '0';
@@ -1070,9 +1181,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
str++;
}
// parse width, if it exists
int width = 0;
int width = 0;
if (str < top) {
if (*str == '*') {
if (arg_i >= n_args) {
goto not_enough_args;
}
width = mp_obj_get_int(args[arg_i++]);
str++;
} else {
@@ -1085,6 +1199,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
if (str < top && *str == '.') {
if (++str < top) {
if (*str == '*') {
if (arg_i >= n_args) {
goto not_enough_args;
}
prec = mp_obj_get_int(args[arg_i++]);
str++;
} else {
@@ -1099,14 +1216,22 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
if (str >= top) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format"));
}
mp_obj_t arg = args[arg_i];
// Tuple value lookup
if (arg == MP_OBJ_NULL) {
if (arg_i >= n_args) {
not_enough_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
}
arg = args[arg_i++];
}
switch (*str) {
case 'c':
if (MP_OBJ_IS_STR(arg)) {
uint len;
const char *s = mp_obj_str_get_data(arg, &len);
if (len != 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "%%c requires int or char"));
break;
}
pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width);
@@ -1117,23 +1242,23 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width);
break;
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
// This is what CPython reports, so we report the same.
if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
}
#endif
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
break;
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
break;
case 'd':
case 'i':
case 'u':
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width);
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width, prec);
break;
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
@@ -1148,7 +1273,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
if (alt) {
flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
}
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 8, 'a', flags, fill, width);
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, prec);
break;
case 'r':
@@ -1169,18 +1294,9 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
break;
}
case 'x':
if (alt) {
flags |= PF_FLAG_SHOW_PREFIX;
}
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'a', flags, fill, width);
break;
case 'X':
if (alt) {
flags |= PF_FLAG_SHOW_PREFIX;
}
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'A', flags, fill, width);
case 'x':
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
break;
default:
@@ -1188,14 +1304,13 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
"unsupported format character '%c' (0x%x) at index %d",
*str, *str, str - start_str));
}
arg_i++;
}
if (arg_i != n_args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting"));
}
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
}
@@ -1363,9 +1478,9 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di
const byte *position_ptr = find_subbytes(str, str_len, sep, sep_len, direction);
if (position_ptr != NULL) {
machine_uint_t position = position_ptr - str;
result[0] = str_new(self_type, str, position);
result[0] = mp_obj_new_str_of_type(self_type, str, position);
result[1] = arg;
result[2] = str_new(self_type, str + position + sep_len, str_len - position - sep_len);
result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);
}
return mp_obj_new_tuple(3, result);
@@ -1379,30 +1494,77 @@ STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) {
return str_partitioner(self_in, arg, -1);
}
enum { CASE_UPPER, CASE_LOWER };
// Supposedly not too critical operations, so optimize for code size
STATIC mp_obj_t str_caseconv(int op, mp_obj_t self_in) {
STATIC mp_obj_t str_caseconv(unichar (*op)(unichar), mp_obj_t self_in) {
GET_STR_DATA_LEN(self_in, self_data, self_len);
byte *data;
mp_obj_t s = mp_obj_str_builder_start(mp_obj_get_type(self_in), self_len, &data);
for (int i = 0; i < self_len; i++) {
if (op == CASE_UPPER) {
*data++ = unichar_toupper(*self_data++);
} else {
*data++ = unichar_tolower(*self_data++);
}
*data++ = op(*self_data++);
}
*data = 0;
return mp_obj_str_builder_end(s);
}
STATIC mp_obj_t str_lower(mp_obj_t self_in) {
return str_caseconv(CASE_LOWER, self_in);
return str_caseconv(unichar_tolower, self_in);
}
STATIC mp_obj_t str_upper(mp_obj_t self_in) {
return str_caseconv(CASE_UPPER, self_in);
return str_caseconv(unichar_toupper, self_in);
}
STATIC mp_obj_t str_uni_istype(bool (*f)(unichar), mp_obj_t self_in) {
GET_STR_DATA_LEN(self_in, self_data, self_len);
if (self_len == 0) {
return mp_const_false; // default to False for empty str
}
if (f != unichar_isupper && f != unichar_islower) {
for (int i = 0; i < self_len; i++) {
if (!f(*self_data++)) {
return mp_const_false;
}
}
} else {
bool contains_alpha = false;
for (int i = 0; i < self_len; i++) { // only check alphanumeric characters
if (unichar_isalpha(*self_data++)) {
contains_alpha = true;
if (!f(*(self_data - 1))) { // -1 because we already incremented above
return mp_const_false;
}
}
}
if (!contains_alpha) {
return mp_const_false;
}
}
return mp_const_true;
}
STATIC mp_obj_t str_isspace(mp_obj_t self_in) {
return str_uni_istype(unichar_isspace, self_in);
}
STATIC mp_obj_t str_isalpha(mp_obj_t self_in) {
return str_uni_istype(unichar_isalpha, self_in);
}
STATIC mp_obj_t str_isdigit(mp_obj_t self_in) {
return str_uni_istype(unichar_isdigit, self_in);
}
STATIC mp_obj_t str_isupper(mp_obj_t self_in) {
return str_uni_istype(unichar_isupper, self_in);
}
STATIC mp_obj_t str_islower(mp_obj_t self_in) {
return str_uni_istype(unichar_islower, self_in);
}
#if MICROPY_CPYTHON_COMPAT
@@ -1459,7 +1621,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_startswith_obj, str_startswith);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
@@ -1470,6 +1634,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
STATIC const mp_map_elem_t str_locals_dict_table[] = {
#if MICROPY_CPYTHON_COMPAT
@@ -1482,7 +1651,9 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_rindex), (mp_obj_t)&str_rindex_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rsplit), (mp_obj_t)&str_rsplit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_endswith), (mp_obj_t)&str_endswith_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_lstrip), (mp_obj_t)&str_lstrip_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rstrip), (mp_obj_t)&str_rstrip_obj },
@@ -1493,6 +1664,11 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj },
};
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
@@ -1545,7 +1721,7 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
return o;
}
STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len) {
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
o->base.type = type;
o->len = len;
@@ -1559,22 +1735,29 @@ STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
return o;
}
mp_obj_t mp_obj_new_str(const byte* data, uint len, bool make_qstr_if_not_already) {
qstr q = qstr_find_strn(data, len);
if (q != MP_QSTR_NULL) {
// qstr with this data already exists
return MP_OBJ_NEW_QSTR(q);
} else if (make_qstr_if_not_already) {
// no existing qstr, make a new one
return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len));
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already) {
if (make_qstr_if_not_already) {
// use existing, or make a new qstr
return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));
} else {
// no existing qstr, don't make one
return str_new(&mp_type_str, data, len);
qstr q = qstr_find_strn(data, len);
if (q != MP_QSTR_NULL) {
// qstr with this data already exists
return MP_OBJ_NEW_QSTR(q);
} else {
// no existing qstr, don't make one
return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len);
}
}
}
mp_obj_t mp_obj_str_intern(mp_obj_t str) {
GET_STR_DATA_LEN(str, data, len);
return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len));
}
mp_obj_t mp_obj_new_bytes(const byte* data, uint len) {
return str_new(&mp_type_bytes, data, len);
return mp_obj_new_str_of_type(&mp_type_bytes, data, len);
}
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
@@ -1672,7 +1855,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
mp_obj_str_it_t *self = self_in;
GET_STR_DATA_LEN(self->str, str, len);
if (self->cur < len) {
mp_obj_t o_out = mp_obj_new_str(str + self->cur, 1, true);
mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true);
self->cur += 1;
return o_out;
} else {

View File

@@ -36,3 +36,4 @@ typedef struct _mp_obj_str_t {
#define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str};
mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len);

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -34,8 +35,9 @@
#include "obj.h"
#include "runtime.h"
#include "stream.h"
#include "objstr.h"
#if MICROPY_ENABLE_MOD_IO
#if MICROPY_PY_IO
typedef struct _mp_obj_stringio_t {
mp_obj_base_t base;
@@ -46,7 +48,7 @@ typedef struct _mp_obj_stringio_t {
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_stringio_t *self = self_in;
print(env, "<io.StringIO 0x%x>", self->vstr);
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
}
STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) {
@@ -77,9 +79,11 @@ STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint
return size;
}
#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
mp_obj_stringio_t *self = self_in;
return mp_obj_new_str((byte*)self->vstr->buf, self->vstr->len, false);
return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
@@ -96,16 +100,16 @@ mp_obj_t stringio___exit__(uint n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
STATIC mp_obj_stringio_t *stringio_new() {
STATIC mp_obj_stringio_t *stringio_new(mp_obj_t type_in) {
mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
o->base.type = &mp_type_stringio;
o->base.type = type_in;
o->vstr = vstr_new();
o->pos = 0;
return o;
}
STATIC mp_obj_t stringio_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_stringio_t *o = stringio_new();
mp_obj_stringio_t *o = stringio_new(type_in);
if (n_args > 0) {
mp_buffer_info_t bufinfo;
@@ -135,6 +139,12 @@ STATIC const mp_stream_p_t stringio_stream_p = {
.write = stringio_write,
};
STATIC const mp_stream_p_t bytesio_stream_p = {
.read = stringio_read,
.write = stringio_write,
.is_bytes = true,
};
const mp_obj_type_t mp_type_stringio = {
{ &mp_type_type },
.name = MP_QSTR_StringIO,
@@ -146,4 +156,17 @@ const mp_obj_type_t mp_type_stringio = {
.locals_dict = (mp_obj_t)&stringio_locals_dict,
};
#if MICROPY_PY_IO_BYTESIO
const mp_obj_type_t mp_type_bytesio = {
{ &mp_type_type },
.name = MP_QSTR_BytesIO,
.print = stringio_print,
.make_new = stringio_make_new,
.getiter = mp_identity,
.iternext = mp_stream_unbuffered_iter,
.stream_p = &bytesio_stream_p,
.locals_dict = (mp_obj_t)&stringio_locals_dict,
};
#endif
#endif

View File

@@ -120,7 +120,7 @@ mp_obj_t mp_obj_tuple_unary_op(int op, mp_obj_t self_in) {
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(self->len != 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
default: return MP_OBJ_NOT_SUPPORTED;
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -129,7 +129,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
switch (op) {
case MP_BINARY_OP_ADD: {
if (!mp_obj_is_subclass_fast(mp_obj_get_type(rhs), (mp_obj_t)&mp_type_tuple)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
mp_obj_tuple_t *p = rhs;
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len + p->len, NULL);
@@ -138,7 +138,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
case MP_BINARY_OP_MULTIPLY: {
if (!MP_OBJ_IS_SMALL_INT(rhs)) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
int n = MP_OBJ_SMALL_INT_VALUE(rhs);
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
@@ -153,8 +153,7 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return MP_BOOL(tuple_cmp_helper(op, lhs, rhs));
default:
// op not supported
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
@@ -162,21 +161,22 @@ mp_obj_t mp_obj_tuple_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) {
// load
mp_obj_tuple_t *self = self_in;
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
machine_uint_t start, stop;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &start, &stop)) {
assert(0);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
mp_obj_tuple_t *res = mp_obj_new_tuple(stop - start, NULL);
mp_seq_copy(res->items, self->items + start, res->len, mp_obj_t);
mp_obj_tuple_t *res = mp_obj_new_tuple(slice.stop - slice.start, NULL);
mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);
return res;
}
#endif
uint index_value = mp_get_index(self->base.type, self->len, index, false);
return self->items[index_value];
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -48,8 +49,10 @@
/******************************************************************************/
// instance object
#define is_instance_type(type) ((type)->make_new == instance_make_new)
#define is_native_type(type) ((type)->make_new != instance_make_new)
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) {
mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
@@ -95,18 +98,26 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
// it was - because instance->subobj[0] is of that type. The only exception is when
// object is not yet constructed, then we need to know base native type to construct
// instance->subobj[0]. This case is handled via instance_count_native_bases() though.
STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) {
assert(dest[0] == NULL);
assert(dest[1] == NULL);
struct class_lookup_data {
mp_obj_instance_t *obj;
qstr attr;
machine_uint_t meth_offset;
mp_obj_t *dest;
bool is_type;
};
STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
assert(lookup->dest[0] == NULL);
assert(lookup->dest[1] == NULL);
for (;;) {
// Optimize special method lookup for native types
// This avoids extra method_name => slot lookup. On the other hand,
// this should not be applied to class types, as will result in extra
// lookup either.
if (meth_offset != 0 && is_native_type(type)) {
if (*(void**)((char*)type + meth_offset) != NULL) {
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(attr));
dest[0] = MP_OBJ_SENTINEL;
if (lookup->meth_offset != 0 && is_native_type(type)) {
if (*(void**)((char*)type + lookup->meth_offset) != NULL) {
DEBUG_printf("mp_obj_class_lookup: matched special meth slot for %s\n", qstr_str(lookup->attr));
lookup->dest[0] = MP_OBJ_SENTINEL;
return;
}
}
@@ -115,23 +126,33 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
// search locals_dict (the set of methods/attributes)
assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
if (elem != NULL) {
dest[0] = elem->value;
if (o != MP_OBJ_NULL && is_native_type(type)) {
dest[1] = o->subobj[0];
lookup->dest[0] = elem->value;
if (lookup->is_type) {
// If we look up class method, we need to pass original type there,
// not type where we found a class method.
const mp_obj_type_t *org_type = (const mp_obj_type_t*)lookup->obj;
instance_convert_return_attr(NULL, org_type, elem->value, lookup->dest);
} else if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && is_native_type(type)) {
instance_convert_return_attr(lookup->obj->subobj[0], type, elem->value, lookup->dest);
} else {
instance_convert_return_attr(lookup->obj, type, elem->value, lookup->dest);
}
// TODO: Sensibly, we should call instance_convert_return_attr() here,
// instead of multiple places later. Also, this code duplicates runtime.c much.
#if DEBUG_PRINT
printf("mp_obj_class_lookup: Returning: ");
mp_obj_print(lookup->dest[0], PRINT_REPR); printf(" ");
mp_obj_print(lookup->dest[1], PRINT_REPR); printf("\n");
#endif
return;
}
}
// Try this for completeness, but all native methods should be statically defined
// in locals_dict, and would be handled by above.
if (o != MP_OBJ_NULL && is_native_type(type)) {
mp_load_method_maybe(o->subobj[0], attr, dest);
if (dest[0] != MP_OBJ_NULL) {
if (lookup->obj != MP_OBJ_NULL && !lookup->is_type && is_native_type(type)) {
mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);
if (lookup->dest[0] != MP_OBJ_NULL) {
return;
}
}
@@ -156,8 +177,8 @@ STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type,
// Not a "real" type
continue;
}
mp_obj_class_lookup(o, bt, attr, meth_offset, dest);
if (dest[0] != MP_OBJ_NULL) {
mp_obj_class_lookup(lookup, bt);
if (lookup->dest[0] != MP_OBJ_NULL) {
return;
}
}
@@ -176,10 +197,18 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
mp_obj_instance_t *self = self_in;
qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, meth, offsetof(mp_obj_type_t, print), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = meth,
.meth_offset = offsetof(mp_obj_type_t, print),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
// If there's no __str__, fall back to __repr__
mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
lookup.attr = MP_QSTR___repr__;
lookup.meth_offset = 0;
mp_obj_class_lookup(&lookup, self->base.type);
}
if (member[0] == MP_OBJ_SENTINEL) {
@@ -205,7 +234,7 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
}
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
mp_obj_type_t *self = self_in;
@@ -215,38 +244,73 @@ STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, cons
mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases);
// look for __init__ function
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(NULL, self, MP_QSTR___init__, offsetof(mp_obj_type_t, make_new), init_fn);
// This executes only "__new__" part of obejection creation.
// TODO: This won't work will for classes with native bases.
// TODO: This is hack, should be resolved along the lines of
// https://github.com/micropython/micropython/issues/606#issuecomment-43685883
if (n_args == 1 && *args == MP_OBJ_SENTINEL) {
return o;
}
// look for __new__ function
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
.obj = NULL,
.attr = MP_QSTR___new__,
.meth_offset = offsetof(mp_obj_type_t, make_new),
.dest = init_fn,
};
mp_obj_class_lookup(&lookup, self);
mp_obj_t new_ret = o;
if (init_fn[0] == MP_OBJ_SENTINEL) {
// Native type's constructor is what wins - it gets all our arguments,
// and none Python classes are initialized at all.
o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, n_args, n_kw, args);
} else if (init_fn[0] != MP_OBJ_NULL) {
// We need to default-initialize any native subobjs first
if (num_native_bases > 0) {
o->subobj[0] = native_base->make_new((mp_obj_type_t*)native_base, 0, 0, NULL);
}
// now call Python class __init__ function with all args
mp_obj_t init_ret;
// now call Python class __new__ function with all args
if (n_args == 0 && n_kw == 0) {
init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&o);
new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&self_in);
} else {
mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
args2[0] = o;
args2[0] = self_in;
memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
init_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
}
}
// https://docs.python.org/3.4/reference/datamodel.html#object.__new__
// "If __new__() does not return an instance of cls, then the new instances __init__() method will not be invoked."
if (mp_obj_get_type(new_ret) != self_in) {
return new_ret;
}
o = new_ret;
// now call Python class __init__ function with all args
init_fn[0] = init_fn[1] = NULL;
lookup.obj = o;
lookup.attr = MP_QSTR___init__;
lookup.meth_offset = 0;
mp_obj_class_lookup(&lookup, self);
if (init_fn[0] != MP_OBJ_NULL) {
mp_obj_t init_ret;
if (n_args == 0 && n_kw == 0) {
init_ret = mp_call_method_n_kw(0, 0, init_fn);
} else {
mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);
args2[0] = init_fn[0];
args2[1] = init_fn[1];
memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
init_ret = mp_call_method_n_kw(n_args, n_kw, args2);
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
}
if (init_ret != mp_const_none) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
}
} else {
if (n_args != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object() takes no parameters"));
}
}
return o;
@@ -266,17 +330,23 @@ STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) {
qstr op_name = unary_op_method_name[op];
/* Still try to lookup native slot
if (op_name == 0) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL;
}
*/
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, op_name, offsetof(mp_obj_type_t, unary_op), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, unary_op),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_SENTINEL) {
return mp_unary_op(op, self->subobj[0]);
} else if (member[0] != MP_OBJ_NULL) {
return mp_call_function_1(member[0], self_in);
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
@@ -307,14 +377,16 @@ STATIC const qstr binary_op_method_name[] = {
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
MP_BINARY_OP_INPLACE_MODULO,
MP_BINARY_OP_INPLACE_POWER,
MP_BINARY_OP_LESS,
MP_BINARY_OP_MORE,
MP_BINARY_OP_INPLACE_POWER,*/
[MP_BINARY_OP_LESS] = MP_QSTR___lt__,
/*MP_BINARY_OP_MORE,
MP_BINARY_OP_EQUAL,
MP_BINARY_OP_LESS_EQUAL,
MP_BINARY_OP_MORE_EQUAL,
MP_BINARY_OP_NOT_EQUAL,
MP_BINARY_OP_IN,
*/
[MP_BINARY_OP_IN] = MP_QSTR___contains__,
/*
MP_BINARY_OP_IS,
*/
[MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
@@ -323,8 +395,8 @@ STATIC const qstr binary_op_method_name[] = {
// Given a member that was extracted from an instance, convert it correctly
// and put the result in the dest[] array for a possible method call.
// Conversion means dealing with static/class methods, callables, and values.
// see http://docs.python.org/3.3/howto/descriptor.html
STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t *dest) {
// see http://docs.python.org/3/howto/descriptor.html
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {
assert(dest[1] == NULL);
if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) {
// return just the function
@@ -332,7 +404,7 @@ STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_
} else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) {
// return a bound method, with self being the type of this object
dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
dest[1] = mp_obj_get_type(self);
dest[1] = (mp_obj_t)type;
} else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
// Don't try to bind types
dest[0] = member;
@@ -353,26 +425,30 @@ STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
qstr op_name = binary_op_method_name[op];
/* Still try to lookup native slot
if (op_name == 0) {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL;
}
*/
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), member);
if (member[0] == MP_OBJ_SENTINEL) {
mp_obj_t dest[3] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
.obj = lhs,
.attr = op_name,
.meth_offset = offsetof(mp_obj_type_t, binary_op),
.dest = dest,
};
mp_obj_class_lookup(&lookup, lhs->base.type);
if (dest[0] == MP_OBJ_SENTINEL) {
return mp_binary_op(op, lhs->subobj[0], rhs_in);
} else if (member[0] != MP_OBJ_NULL) {
mp_obj_t dest[3];
dest[1] = MP_OBJ_NULL;
instance_convert_return_attr(lhs_in, member[0], dest);
} else if (dest[0] != MP_OBJ_NULL) {
dest[2] = rhs_in;
return mp_call_method_n_kw(1, 0, dest);
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// logic: look in obj members then class locals (TODO check this against CPython)
assert(is_instance_type(mp_obj_get_type(self_in)));
mp_obj_instance_t *self = self_in;
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
@@ -383,12 +459,17 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return;
}
mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.dest = dest,
};
mp_obj_class_lookup(&lookup, self->base.type);
mp_obj_t member = dest[0];
if (member != MP_OBJ_NULL) {
if (0) {
#if MICROPY_ENABLE_PROPERTY
} else if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
#if MICROPY_PY_BUILTINS_PROPERTY
if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
// object member is a property
// delegate the store to the property
// TODO should this be part of instance_convert_return_attr?
@@ -399,15 +480,8 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
// TODO should we convert the returned value using instance_convert_return_attr?
}
#endif
} else {
// not a property
// if we don't yet have bound method (supposedly from native base), go
// try to convert own attrs.
if (dest[1] == MP_OBJ_NULL) {
instance_convert_return_attr(self_in, member, dest);
}
}
#endif
return;
}
@@ -428,11 +502,17 @@ STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
mp_obj_instance_t *self = self_in;
#if MICROPY_ENABLE_PROPERTY
#if MICROPY_PY_BUILTINS_PROPERTY
// for property, we need to do a lookup first in the class dict
// this makes all stores slow... how to fix?
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, attr, 0, member);
struct class_lookup_data lookup = {
.obj = self,
.attr = attr,
.meth_offset = 0,
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] != MP_OBJ_NULL && MP_OBJ_IS_TYPE(member[0], &mp_type_property)) {
// attribute already exists and is a property
// delegate the store to the property
@@ -462,18 +542,26 @@ STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
.obj = self,
.meth_offset = offsetof(mp_obj_type_t, subscr),
.dest = member,
};
uint meth_args;
if (value == MP_OBJ_NULL) {
// delete item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___delitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 2;
} else if (value == MP_OBJ_SENTINEL) {
// load item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___getitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 2;
} else {
// store item
mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
lookup.attr = MP_QSTR___setitem__;
mp_obj_class_lookup(&lookup, self->base.type);
meth_args = 3;
}
if (member[0] == MP_OBJ_SENTINEL) {
@@ -488,16 +576,22 @@ STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value
return mp_const_none;
}
} else {
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, MP_QSTR___call__, offsetof(mp_obj_type_t, call), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___call__,
.meth_offset = offsetof(mp_obj_type_t, call),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL) {
return MP_OBJ_NULL;
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in)));
}
if (member[0] == MP_OBJ_SENTINEL) {
return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
@@ -509,13 +603,20 @@ STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
mp_obj_instance_t *self = self_in;
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self, self->base.type, MP_QSTR___iter__, offsetof(mp_obj_type_t, getiter), member);
struct class_lookup_data lookup = {
.obj = self,
.attr = MP_QSTR___iter__,
.meth_offset = offsetof(mp_obj_type_t, getiter),
.dest = member,
};
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] == MP_OBJ_NULL) {
// This kinda duplicates code in mp_getiter()
mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, 0, member);
lookup.attr = MP_QSTR___getitem__;
lookup.meth_offset = 0; // TODO
mp_obj_class_lookup(&lookup, self->base.type);
if (member[0] != MP_OBJ_NULL) {
// __getitem__ exists, create an iterator
instance_convert_return_attr(self_in, member[0], member);
return mp_obj_new_getitem_iter(member);
}
return MP_OBJ_NULL;
@@ -583,24 +684,14 @@ STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return;
}
#endif
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(NULL, self, attr, 0, member);
if (member[0] != MP_OBJ_NULL) {
// check if the methods are functions, static or class methods
// see http://docs.python.org/3.3/howto/descriptor.html
if (MP_OBJ_IS_TYPE(member[0], &mp_type_staticmethod)) {
// return just the function
dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
} else if (MP_OBJ_IS_TYPE(member[0], &mp_type_classmethod)) {
// return a bound method, with self being this class
dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
dest[1] = self_in;
} else {
// return just the function
// TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception
dest[0] = member[0];
}
}
struct class_lookup_data lookup = {
.obj = self_in,
.attr = attr,
.meth_offset = 0,
.dest = dest,
.is_type = true,
};
mp_obj_class_lookup(&lookup, self);
}
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
@@ -639,7 +730,7 @@ STATIC mp_obj_t type_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return MP_BOOL(lhs_in == rhs_in);
default:
return MP_OBJ_NOT_SUPPORTED;
return MP_OBJ_NULL; // op not supported
}
}
@@ -739,15 +830,20 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
uint len;
mp_obj_t *items;
mp_obj_tuple_get(type->bases_tuple, &len, &items);
struct class_lookup_data lookup = {
.obj = self->obj,
.attr = attr,
.meth_offset = 0,
.dest = dest,
};
for (uint i = 0; i < len; i++) {
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
mp_obj_t member[2] = {MP_OBJ_NULL};
mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, member);
if (member[0] != MP_OBJ_NULL) {
instance_convert_return_attr(self->obj, member[0], dest);
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)items[i]);
if (dest[0] != MP_OBJ_NULL) {
return;
}
}
mp_obj_class_lookup(&lookup, &mp_type_object);
}
const mp_obj_type_t mp_type_super = {

View File

@@ -28,6 +28,7 @@
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
@@ -35,6 +36,7 @@
#include "lexer.h"
#include "parsenumbase.h"
#include "parse.h"
#include "smallint.h"
#define RULE_ACT_KIND_MASK (0xf0)
#define RULE_ACT_ARG_MASK (0x0f)
@@ -70,6 +72,7 @@ enum {
#include "grammar.h"
#undef DEF_RULE
RULE_maximum_number_of,
RULE_string, // special node for non-interned string
};
#define or(n) (RULE_ACT_OR | n)
@@ -134,13 +137,13 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar
return;
}
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MP_ALLOC_PARSE_RULE_INC);
rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC);
if (rs == NULL) {
memory_error(parser);
return;
}
parser->rule_stack = rs;
parser->rule_stack_alloc += MP_ALLOC_PARSE_RULE_INC;
parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC;
}
rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
rs->src_line = src_line;
@@ -170,26 +173,26 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
return (mp_parse_node_t)(kind | (arg << 5));
}
uint mp_parse_node_free(mp_parse_node_t pn) {
uint cnt = 0;
void mp_parse_node_free(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
uint rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
if (rule_id == RULE_string) {
return;
}
bool adjust = ADD_BLANK_NODE(rule_id);
if (adjust) {
n--;
}
for (uint i = 0; i < n; i++) {
cnt += mp_parse_node_free(pns->nodes[i]);
mp_parse_node_free(pns->nodes[i]);
}
if (adjust) {
n++;
}
m_del_var(mp_parse_node_struct_t, mp_parse_node_t, n, pns);
cnt++;
}
return cnt;
}
#if MICROPY_DEBUG_PRINTERS
@@ -219,15 +222,20 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
default: assert(0);
}
} else {
// node must be a mp_parse_node_struct_t
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_string) {
printf("literal str(%.*s)\n", (int)pns->nodes[1], (char*)pns->nodes[0]);
} else {
uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
#ifdef USE_RULE_NAME
printf("%s(%d) (n=%d)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, MP_PARSE_NODE_STRUCT_KIND(pns), n);
printf("%s(%d) (n=%d)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, MP_PARSE_NODE_STRUCT_KIND(pns), n);
#else
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
#endif
for (uint i = 0; i < n; i++) {
mp_parse_node_print(pns->nodes[i], indent + 2);
for (uint i = 0; i < n; i++) {
mp_parse_node_print(pns->nodes[i], indent + 2);
}
}
}
}
@@ -263,17 +271,32 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {
return;
}
if (parser->result_stack_top >= parser->result_stack_alloc) {
mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MP_ALLOC_PARSE_RESULT_INC);
mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MICROPY_ALLOC_PARSE_RESULT_INC);
if (pn == NULL) {
memory_error(parser);
return;
}
parser->result_stack = pn;
parser->result_stack_alloc += MP_ALLOC_PARSE_RESULT_INC;
parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC;
}
parser->result_stack[parser->result_stack_top++] = pn;
}
STATIC void push_result_string(parser_t *parser, int src_line, const char *str, uint len) {
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, 2);
if (pn == NULL) {
memory_error(parser);
return;
}
pn->source_line = src_line;
pn->kind_num_nodes = RULE_string | (2 << 8);
char *p = m_new(char, len);
memcpy(p, str, len);
pn->nodes[0] = (machine_int_t)p;
pn->nodes[1] = len;
push_result_node(parser, (mp_parse_node_t)pn);
}
STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
const mp_token_t *tok = mp_lexer_cur(lex);
mp_parse_node_t pn;
@@ -289,13 +312,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
int i = mp_parse_num_base(str, len, &base);
bool overflow = false;
for (; i < len; i++) {
machine_int_t old_val = int_val;
int dig;
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
int_val = base * int_val + str[i] - '0';
dig = str[i] - '0';
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
int_val = base * int_val + str[i] - 'a' + 10;
dig = str[i] - 'a' + 10;
} else if (base == 16 && 'A' <= str[i] && str[i] <= 'F') {
int_val = base * int_val + str[i] - 'A' + 10;
dig = str[i] - 'A' + 10;
} else if (str[i] == '.' || str[i] == 'e' || str[i] == 'E' || str[i] == 'j' || str[i] == 'J') {
dec = true;
break;
@@ -303,23 +326,41 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
small_int = false;
break;
}
if (int_val < old_val) {
// If new value became less than previous, it's overflow
// add next digi and check for overflow
if (mp_small_int_mul_overflow(int_val, base)) {
overflow = true;
} else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
// If signed number changed sign - it's overflow
}
int_val = int_val * base + dig;
if (!MP_SMALL_INT_FITS(int_val)) {
overflow = true;
}
}
if (dec) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_DECIMAL, qstr_from_strn(str, len));
} else if (small_int && !overflow && MP_PARSE_FITS_SMALL_INT(int_val)) {
} else if (small_int && !overflow && MP_SMALL_INT_FITS(int_val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, int_val);
} else {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_INTEGER, qstr_from_strn(str, len));
}
} else if (tok->kind == MP_TOKEN_STRING) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_STRING, qstr_from_strn(tok->str, tok->len));
// Don't automatically intern all strings. doc strings (which are usually large)
// will be discarded by the compiler, and so we shouldn't intern them.
qstr qst = MP_QSTR_NULL;
if (tok->len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) {
// intern short strings
qst = qstr_from_strn(tok->str, tok->len);
} else {
// check if this string is already interned
qst = qstr_find_strn(tok->str, tok->len);
}
if (qst != MP_QSTR_NULL) {
// qstr exists, make a leaf node
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_STRING, qst);
} else {
// not interned, make a node holding a pointer to the string data
push_result_string(parser, mp_lexer_cur(lex)->src_line, tok->str, tok->len);
return;
}
} else if (tok->kind == MP_TOKEN_BYTES) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_BYTES, qstr_from_strn(tok->str, tok->len));
} else {
@@ -350,11 +391,11 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
parser.had_memory_error = false;
parser.rule_stack_alloc = MP_ALLOC_PARSE_RULE_INIT;
parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT;
parser.rule_stack_top = 0;
parser.rule_stack = m_new_maybe(rule_stack_t, parser.rule_stack_alloc);
parser.result_stack_alloc = MP_ALLOC_PARSE_RESULT_INIT;
parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT;
parser.result_stack_top = 0;
parser.result_stack = m_new_maybe(mp_parse_node_t, parser.result_stack_alloc);
@@ -516,14 +557,13 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
}
}
#if 0 && !MICROPY_ENABLE_DOC_STRING
// this code discards lonely statement, such as doc strings
// problem is that doc strings have already been interned, so this doesn't really help reduce RAM usage
#if !MICROPY_EMIT_CPYTHON && !MICROPY_ENABLE_DOC_STRING
// this code discards lonely statements, such as doc strings
if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
mp_parse_node_t p = peek_result(&parser, 1);
if (MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) {
pop_result(parser);
pop_result(parser);
if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_string)) {
pop_result(&parser);
pop_result(&parser);
push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0);
break;
}

View File

@@ -37,13 +37,6 @@ struct _mp_lexer_t;
// - xx...x10010: a string of bytes; bits 5 and above are the qstr holding the value
// - xx...x10110: a token; bits 5 and above are mp_token_kind_t
// TODO: these can now be unified with MP_OBJ_FITS_SMALL_INT(x)
// makes sure the top 2 bits of x are all cleared (positive number) or all set (negavite number)
// these macros can probably go somewhere else because they are used more than just in the parser
#define MP_UINT_HIGH_2_BITS (~((~((machine_uint_t)0)) >> 2))
// parser's small ints are different from VM small int
#define MP_PARSE_FITS_SMALL_INT(x) (((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == 0) || ((((machine_uint_t)(x)) & MP_UINT_HIGH_2_BITS) == MP_UINT_HIGH_2_BITS))
#define MP_PARSE_NODE_NULL (0)
#define MP_PARSE_NODE_SMALL_INT (0x1)
#define MP_PARSE_NODE_ID (0x02)
@@ -82,7 +75,7 @@ typedef struct _mp_parse_node_struct_t {
#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns) ((pns)->kind_num_nodes >> 8)
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg);
uint mp_parse_node_free(mp_parse_node_t pn);
void mp_parse_node_free(mp_parse_node_t pn);
void mp_parse_node_print(mp_parse_node_t pn, int indent);

View File

@@ -34,14 +34,16 @@
#include "obj.h"
#include "parsenumbase.h"
#include "parsenum.h"
#include "smallint.h"
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
#endif
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
const char *restrict top = str + len;
bool neg = false;
mp_obj_t ret_val;
// check radix base
if ((base != 0 && base < 2) || base > 36) {
@@ -69,16 +71,16 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
machine_int_t int_val = 0;
const char *restrict str_val_start = str;
for (; str < top; str++) {
machine_int_t old_val = int_val;
// get next digit as a value
int dig = *str;
if (unichar_isdigit(dig) && dig - '0' < base) {
// 0-9 digit
int_val = base * int_val + dig - '0';
dig = dig - '0';
} else if (base == 16) {
dig |= 0x20;
if ('a' <= dig && dig <= 'f') {
// a-f hex digit
int_val = base * int_val + dig - 'a' + 10;
dig = dig - 'a' + 10;
} else {
// unknown character
break;
@@ -87,18 +89,15 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
// unknown character
break;
}
if (int_val < old_val) {
// If new value became less than previous, it's overflow
goto overflow;
} else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
// If signed number changed sign - it's overflow
// add next digi and check for overflow
if (mp_small_int_mul_overflow(int_val, base)) {
goto overflow;
}
int_val = int_val * base + dig;
if (!MP_SMALL_INT_FITS(int_val)) {
goto overflow;
}
}
// check we parsed something
if (str == str_val_start) {
goto value_error;
}
// negate value if needed
@@ -106,6 +105,15 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
int_val = -int_val;
}
// create the small int
ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
have_ret_val:
// check we parsed something
if (str == str_val_start) {
goto value_error;
}
// skip trailing space
for (; str < top && unichar_isspace(*str); str++) {
}
@@ -116,14 +124,19 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
}
// return the object
return MP_OBJ_NEW_SMALL_INT(int_val);
value_error:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str));
return ret_val;
overflow:
// TODO reparse using bignum
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer"));
// reparse using long int
{
const char *s2 = str_val_start;
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
str = s2;
goto have_ret_val;
}
value_error:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str));
}
#define PARSE_DEC_IN_INTG (1)
@@ -131,7 +144,7 @@ overflow:
#define PARSE_DEC_IN_EXP (3)
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
const char *top = str + len;
mp_float_t dec_val = 0;
bool dec_neg = false;

View File

@@ -39,7 +39,7 @@
#include <stdio.h>
#endif
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
#include "formatfloat.h"
#endif
@@ -91,8 +91,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
left_pad -= p;
}
}
pfenv->print_strn(pfenv->data, str, len);
total_chars_printed += len;
if (len) {
pfenv->print_strn(pfenv->data, str, len);
total_chars_printed += len;
}
if (right_pad > 0) {
total_chars_printed += right_pad;
while (right_pad > 0) {
@@ -181,13 +183,19 @@ int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, i
return len;
}
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec) {
if (!MP_OBJ_IS_INT(x)) {
// This will convert booleans to int, or raise an error for
// non-integer types.
x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));
}
if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') {
if (prec > width) {
width = prec;
}
prec = 0;
}
char prefix_buf[4];
char *prefix = prefix_buf;
@@ -230,6 +238,9 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
int fmt_size = 0;
char *str;
if (prec > 1) {
flags |= PF_FLAG_PAD_AFTER_SIGN;
}
char sign = '\0';
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
// We add the pad in this function, so since the pad goes after
@@ -245,7 +256,39 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
x, base, prefix, base_char, comma);
}
int spaces_before = 0;
int spaces_after = 0;
if (prec > 1) {
// If prec was specified, then prec specifies the width to zero-pad the
// the number to. This zero-padded number then gets left or right
// aligned in width characters.
int prec_width = fmt_size; // The digits
if (prec_width < prec) {
prec_width = prec;
}
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
if (sign) {
prec_width++;
}
prec_width += prefix_len;
}
if (prec_width < width) {
if (flags & PF_FLAG_LEFT_ADJUST) {
spaces_after = width - prec_width;
} else {
spaces_before = width - prec_width;
}
}
fill = '0';
flags &= ~PF_FLAG_LEFT_ADJUST;
}
int len = 0;
if (spaces_before) {
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before);
}
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
// pad after sign implies pad after prefix as well.
if (sign) {
@@ -257,16 +300,23 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
width -= prefix_len;
}
}
if (prec > 1) {
width = prec;
}
len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width);
if (spaces_after) {
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after);
}
if (buf != stack_buf) {
m_free(buf, buf_size);
}
return len;
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec) {
char buf[32];
char sign = '\0';

View File

@@ -45,7 +45,7 @@ void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len);
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width);
int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width);
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width);
#if MICROPY_ENABLE_FLOAT
int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec);
#if MICROPY_PY_BUILTINS_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
#endif

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# Note: git describe doesn't work if no tag is available
git_tag="$(git describe --dirty --always)"

View File

@@ -77,7 +77,7 @@ typedef struct _qstr_pool_t {
const byte *qstrs[];
} qstr_pool_t;
const static qstr_pool_t const_pool = {
STATIC const qstr_pool_t const_pool = {
NULL, // no previous pool
0, // no previous pool
10, // set so that the first dynamically allocated pool is twice this size; must be <= the len (just below)
@@ -130,7 +130,7 @@ STATIC qstr qstr_add(const byte *q_ptr) {
return last_pool->total_prev_len + last_pool->len - 1;
}
qstr qstr_find_strn(const byte *str, uint str_len) {
qstr qstr_find_strn(const char *str, uint str_len) {
// work out hash of str
machine_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
@@ -152,7 +152,7 @@ qstr qstr_from_str(const char *str) {
}
qstr qstr_from_strn(const char *str, uint len) {
qstr q = qstr_find_strn((const byte*)str, len);
qstr q = qstr_find_strn(str, len);
if (q == 0) {
machine_uint_t hash = qstr_compute_hash((const byte*)str, len);
byte *q_ptr = m_new(byte, 4 + len + 1);
@@ -167,12 +167,6 @@ qstr qstr_from_strn(const char *str, uint len) {
return q;
}
qstr qstr_from_strn_take(char *str, uint alloc_len, uint len) {
qstr q = qstr_from_strn(str, len);
m_del(char, str, alloc_len);
return q;
}
byte *qstr_build_start(uint len, byte **q_ptr) {
assert(len <= 65535);
*q_ptr = m_new(byte, 4 + len + 1);
@@ -182,7 +176,7 @@ byte *qstr_build_start(uint len, byte **q_ptr) {
}
qstr qstr_build_end(byte *q_ptr) {
qstr q = qstr_find_strn(Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
if (q == 0) {
machine_uint_t len = Q_GET_LENGTH(q_ptr);
machine_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);

View File

@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
// See qstrraw.h for a list of qstr's that are available as constants.
// See qstrdefs.h for a list of qstr's that are available as constants.
// Reference them as MP_QSTR_xxxx.
//
// Note: it would be possible to define MP_QSTR_xxx as qstr_from_str_static("xxx")
@@ -46,12 +46,11 @@ typedef machine_uint_t qstr;
void qstr_init(void);
machine_uint_t qstr_compute_hash(const byte *data, uint len);
qstr qstr_find_strn(const byte *str, uint str_len); // returns MP_QSTR_NULL if not found
qstr qstr_find_strn(const char *str, uint str_len); // returns MP_QSTR_NULL if not found
qstr qstr_from_str(const char *str);
qstr qstr_from_strn(const char *str, uint len);
//qstr qstr_from_str_static(const char *str);
qstr qstr_from_strn_take(char *str, uint alloc_len, uint len);
//qstr qstr_from_strn_copy(const char *str, int len);
byte* qstr_build_start(uint len, byte **q_ptr);

View File

@@ -34,6 +34,7 @@ Q(__class__)
Q(__doc__)
Q(__import__)
Q(__init__)
Q(__new__)
Q(__locals__)
Q(__main__)
Q(__module__)
@@ -59,6 +60,7 @@ Q(__str__)
Q(__getattr__)
Q(__del__)
Q(__call__)
Q(__lt__)
Q(micropython)
Q(bytecode)
@@ -101,6 +103,7 @@ Q(OverflowError)
Q(RuntimeError)
Q(SyntaxError)
Q(SystemError)
Q(SystemExit)
Q(TypeError)
Q(UnboundLocalError)
Q(ValueError)
@@ -124,7 +127,7 @@ Q(bool)
Q(bytearray)
Q(bytes)
Q(callable)
#if MICROPY_ENABLE_MOD_STRUCT
#if MICROPY_PY_STRUCT
Q(calcsize)
#endif
Q(chr)
@@ -236,12 +239,19 @@ Q(find)
Q(rfind)
Q(rindex)
Q(split)
Q(rsplit)
Q(startswith)
Q(endswith)
Q(replace)
Q(partition)
Q(rpartition)
Q(lower)
Q(upper)
Q(isspace)
Q(isalpha)
Q(isdigit)
Q(isupper)
Q(islower)
Q(iterable)
Q(start)
@@ -254,11 +264,11 @@ Q(iterator)
Q(module)
Q(slice)
#if MICROPY_ENABLE_FROZENSET
#if MICROPY_PY_BUILTINS_FROZENSET
Q(frozenset)
#endif
#if MICROPY_ENABLE_MOD_MATH || MICROPY_ENABLE_MOD_CMATH
#if MICROPY_PY_MATH || MICROPY_PY_CMATH
Q(math)
Q(e)
Q(pi)
@@ -302,7 +312,7 @@ Q(gamma)
Q(lgamma)
#endif
#if MICROPY_ENABLE_MOD_CMATH
#if MICROPY_PY_CMATH
Q(cmath)
Q(phase)
Q(polar)
@@ -328,12 +338,15 @@ Q(decode)
Q(utf-8)
#endif
#if MICROPY_ENABLE_MOD_SYS
#if MICROPY_PY_SYS
Q(argv)
Q(byteorder)
Q(big)
Q(exit)
Q(little)
#ifdef MICROPY_PY_SYS_PLATFORM
Q(platform)
#endif
Q(stdin)
Q(stdout)
Q(stderr)
@@ -341,30 +354,32 @@ Q(version)
Q(version_info)
#endif
#if MICROPY_ENABLE_MOD_STRUCT
#if MICROPY_PY_STRUCT
Q(struct)
Q(pack)
Q(unpack)
#endif
#if MICROPY_ENABLE_MOD_IO
Q(io)
#if MICROPY_PY_IO
Q(_io)
Q(readall)
Q(readline)
Q(readlines)
Q(FileIO)
Q(TextIOWrapper)
Q(StringIO)
Q(BytesIO)
Q(getvalue)
#endif
#if MICROPY_ENABLE_MOD_GC
#if MICROPY_PY_GC
Q(gc)
Q(collect)
Q(disable)
Q(enable)
#endif
#if MICROPY_ENABLE_PROPERTY
#if MICROPY_PY_BUILTINS_PROPERTY
Q(property)
Q(getter)
Q(setter)

View File

@@ -28,7 +28,7 @@
#include "mpconfig.h"
#include "repl.h"
#if MICROPY_ENABLE_REPL_HELPERS
#if MICROPY_HELPER_REPL
bool str_startswith_word(const char *str, const char *head) {
int i;
@@ -107,4 +107,4 @@ bool mp_repl_continue_with_input(const char *input) {
return false;
}
#endif // MICROPY_ENABLE_REPL_HELPERS
#endif // MICROPY_HELPER_REPL

View File

@@ -24,6 +24,6 @@
* THE SOFTWARE.
*/
#if MICROPY_ENABLE_REPL_HELPERS
#if MICROPY_HELPER_REPL
bool mp_repl_continue_with_input(const char *input);
#endif

View File

@@ -27,7 +27,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <alloca.h>
#include "mpconfig.h"
#include "nlr.h"
@@ -45,6 +44,7 @@
#include "bc.h"
#include "smallint.h"
#include "objgenerator.h"
#include "lexer.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -69,12 +69,13 @@ const mp_obj_module_t mp_module___main__ = {
};
void mp_init(void) {
// call port specific initialization if any
// call port specific initialization if any
#ifdef MICROPY_PORT_INIT_FUNC
MICROPY_PORT_INIT_FUNC;
#endif
mp_emit_glue_init();
// optimization disabled by default
mp_optimise_value = 0;
// init global module stuff
mp_module_init();
@@ -90,7 +91,6 @@ void mp_init(void) {
void mp_deinit(void) {
//mp_obj_dict_free(&dict_main);
mp_module_deinit();
mp_emit_glue_deinit();
// call port specific deinitialization if any
#ifdef MICROPY_PORT_INIT_FUNC
@@ -98,6 +98,13 @@ void mp_deinit(void) {
#endif
}
mp_obj_t mp_load_const_int(qstr qstr) {
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
uint len;
const byte* data = qstr_data(qstr, &len);
return mp_parse_num_integer((const char*)data, len, 0);
}
mp_obj_t mp_load_const_dec(qstr qstr) {
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
uint len;
@@ -200,7 +207,7 @@ mp_obj_t mp_unary_op(int op, mp_obj_t arg) {
mp_obj_type_t *type = mp_obj_get_type(arg);
if (type->unary_op != NULL) {
mp_obj_t result = type->unary_op(op, arg);
if (result != MP_OBJ_NOT_SUPPORTED) {
if (result != MP_OBJ_NULL) {
return result;
}
}
@@ -346,7 +353,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);
break;
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
case MP_BINARY_OP_TRUE_DIVIDE:
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
if (rhs_val == 0) {
@@ -364,7 +371,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER:
if (rhs_val < 0) {
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
lhs = mp_obj_new_float(lhs_val);
goto generic_binary_op;
#else
@@ -406,12 +413,12 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
goto unsupported_op;
}
// TODO: We just should make mp_obj_new_int() inline and use that
if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
if (MP_SMALL_INT_FITS(lhs_val)) {
return MP_OBJ_NEW_SMALL_INT(lhs_val);
} else {
return mp_obj_new_int(lhs_val);
}
#if MICROPY_ENABLE_FLOAT
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs);
if (res == MP_OBJ_NULL) {
@@ -439,7 +446,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_type_t *type = mp_obj_get_type(rhs);
if (type->binary_op != NULL) {
mp_obj_t res = type->binary_op(op, rhs, lhs);
if (res != MP_OBJ_NOT_SUPPORTED) {
if (res != MP_OBJ_NULL) {
return res;
}
}
@@ -467,7 +474,7 @@ generic_binary_op:
type = mp_obj_get_type(lhs);
if (type->binary_op != NULL) {
mp_obj_t result = type->binary_op(op, lhs, rhs);
if (result != MP_OBJ_NOT_SUPPORTED) {
if (result != MP_OBJ_NULL) {
return result;
}
}
@@ -518,10 +525,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp
// do the call
if (type->call != NULL) {
mp_obj_t res = type->call(fun_in, n_args, n_kw, args);
if (res != NULL) {
return res;
}
return type->call(fun_in, n_args, n_kw, args);
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in)));
@@ -832,7 +836,7 @@ void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
if (elem != NULL) {
// check if the methods are functions, static or class methods
// see http://docs.python.org/3.3/howto/descriptor.html
// see http://docs.python.org/3/howto/descriptor.html
if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) {
// return just the function
dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
@@ -1145,10 +1149,14 @@ void *m_malloc_fail(int num_bytes) {
nlr_raise((mp_obj_t)&mp_const_MemoryError_obj);
}
NORETURN void mp_not_implemented(const char *msg) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, msg));
}
// these must correspond to the respective enum
void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_load_const_int,
mp_load_const_dec,
mp_obj_new_int_from_qstr,
mp_load_const_str,
mp_load_name,
mp_load_global,
@@ -1166,8 +1174,10 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_obj_list_append,
mp_obj_new_dict,
mp_obj_dict_store,
#if MICROPY_PY_BUILTINS_SET
mp_obj_new_set,
mp_obj_set_store,
#endif
mp_make_function_from_raw_code,
mp_call_function_n_kw_for_native,
mp_call_method_n_kw,
@@ -1176,7 +1186,9 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_import_name,
mp_import_from,
mp_import_all,
#if MICROPY_PY_BUILTINS_SLICE
mp_obj_new_slice,
#endif
mp_unpack_sequence,
mp_unpack_ex,
};

View File

@@ -75,6 +75,7 @@ void mp_delete_global(qstr qstr);
mp_obj_t mp_unary_op(int op, mp_obj_t arg);
mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
mp_obj_t mp_load_const_int(qstr qstr);
mp_obj_t mp_load_const_dec(qstr qstr);
mp_obj_t mp_load_const_str(qstr qstr);
mp_obj_t mp_load_const_bytes(qstr qstr);
@@ -111,6 +112,9 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
mp_obj_t mp_import_from(mp_obj_t module, qstr name);
void mp_import_all(mp_obj_t module);
// Raise NotImplementedError with given message
NORETURN void mp_not_implemented(const char *msg);
extern struct _mp_obj_list_t mp_sys_path_obj;
extern struct _mp_obj_list_t mp_sys_argv_obj;
#define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)

View File

@@ -96,8 +96,8 @@ typedef enum {
} mp_binary_op_t;
typedef enum {
MP_F_LOAD_CONST_DEC = 0,
MP_F_LOAD_CONST_INT,
MP_F_LOAD_CONST_INT = 0,
MP_F_LOAD_CONST_DEC,
MP_F_LOAD_CONST_STR,
MP_F_LOAD_NAME,
MP_F_LOAD_GLOBAL,
@@ -115,8 +115,10 @@ typedef enum {
MP_F_LIST_APPEND,
MP_F_BUILD_MAP,
MP_F_STORE_MAP,
#if MICROPY_PY_BUILTINS_SET
MP_F_BUILD_SET,
MP_F_STORE_SET,
#endif
MP_F_MAKE_FUNCTION_FROM_RAW_CODE,
MP_F_CALL_FUNCTION_N_KW_FOR_NATIVE,
MP_F_CALL_METHOD_N_KW,
@@ -125,7 +127,9 @@ typedef enum {
MP_F_IMPORT_NAME,
MP_F_IMPORT_FROM,
MP_F_IMPORT_ALL,
#if MICROPY_PY_BUILTINS_SLICE
MP_F_NEW_SLICE,
#endif
MP_F_UNPACK_SEQUENCE,
MP_F_UNPACK_EX,
MP_F_NUMBER_OF,

View File

@@ -71,7 +71,7 @@ scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, uint
}
scope->raw_code = mp_emit_glue_new_raw_code();
scope->emit_options = emit_options;
scope->id_info_alloc = MP_ALLOC_SCOPE_ID_INIT;
scope->id_info_alloc = MICROPY_ALLOC_SCOPE_ID_INIT;
scope->id_info = m_new(id_info_t, scope->id_info_alloc);
return scope;
@@ -92,8 +92,8 @@ id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added) {
// make sure we have enough memory
if (scope->id_info_len >= scope->id_info_alloc) {
scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MP_ALLOC_SCOPE_ID_INC);
scope->id_info_alloc += MP_ALLOC_SCOPE_ID_INC;
scope->id_info = m_renew(id_info_t, scope->id_info, scope->id_info_alloc, scope->id_info_alloc + MICROPY_ALLOC_SCOPE_ID_INC);
scope->id_info_alloc += MICROPY_ALLOC_SCOPE_ID_INC;
}
// add new id to end of array of all ids; this seems to match CPython

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -50,11 +51,22 @@ void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void
}
}
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_uint_t *begin, machine_uint_t *end) {
machine_int_t start, stop, step;
mp_obj_slice_get(slice, &start, &stop, &step);
if (step != 1) {
return false;
#if MICROPY_PY_BUILTINS_SLICE
bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) {
mp_obj_t ostart, ostop, ostep;
machine_int_t start, stop;
mp_obj_slice_get(slice, &ostart, &ostop, &ostep);
if (ostart == mp_const_none) {
start = 0;
} else {
start = MP_OBJ_SMALL_INT_VALUE(ostart);
}
if (ostop == mp_const_none) {
stop = len;
} else {
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
}
// Unlike subscription, out-of-bounds slice indexes are never error
@@ -66,20 +78,51 @@ bool mp_seq_get_fast_slice_indexes(machine_uint_t len, mp_obj_t slice, machine_u
} else if (start > len) {
start = len;
}
if (stop <= 0) {
if (stop < 0) {
stop = len + stop;
// CPython returns empty sequence in such case
if (stop < 0) {
stop = start;
}
} else if (stop > len) {
stop = len;
}
*begin = start;
*end = stop;
// CPython returns empty sequence in such case, or point for assignment is at start
if (start > stop) {
stop = start;
}
indexes->start = start;
indexes->stop = stop;
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
indexes->step = MP_OBJ_SMALL_INT_VALUE(ostep);
return false;
}
indexes->step = 1;
return true;
}
#endif
mp_obj_t mp_seq_extract_slice(uint len, const mp_obj_t *seq, mp_bound_slice_t *indexes) {
machine_int_t start = indexes->start, stop = indexes->stop;
machine_int_t step = indexes->step;
mp_obj_t res = mp_obj_new_list(0, NULL);
if (step < 0) {
stop--;
while (start <= stop) {
mp_obj_list_append(res, seq[stop]);
stop += step;
}
} else {
while (start < stop) {
mp_obj_list_append(res, seq[start]);
start += step;
}
}
return res;
}
// Special-case comparison function for sequences of bytes
// Don't pass MP_BINARY_OP_NOT_EQUAL here
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2) {
@@ -99,6 +142,10 @@ bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, u
}
uint min_len = len1 < len2 ? len1 : len2;
int res = memcmp(data1, data2, min_len);
if (op == MP_BINARY_OP_EQUAL) {
// If we are checking for equality, here're the answer
return res == 0;
}
if (res < 0) {
return false;
}

View File

@@ -56,7 +56,7 @@
void mp_bytecode_print2(const byte *ip, int len);
void mp_bytecode_print(const byte *ip, int len) {
void mp_bytecode_print(const void *descr, const byte *ip, int len) {
const byte *ip_start = ip;
// get code info size
@@ -64,6 +64,11 @@ void mp_bytecode_print(const byte *ip, int len) {
const byte *code_info = ip;
ip += code_info_size;
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
printf("File %s, code block '%s' (descriptor: %p, bytecode @%p %d bytes)\n",
qstr_str(source_file), qstr_str(block_name), descr, code_info, len);
// bytecode prelude: state size and exception stack size; 16 bit uints
{
uint n_state = ip[0] | (ip[1] << 8);
@@ -87,9 +92,6 @@ void mp_bytecode_print(const byte *ip, int len) {
// print out line number info
{
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
printf("File %s, block '%s'\n", qstr_str(source_file), qstr_str(block_name));
machine_int_t bc = (code_info + code_info_size) - ip;
machine_uint_t source_line = 1;
printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
@@ -419,7 +421,7 @@ void mp_bytecode_print2(const byte *ip, int len) {
printf("SET_ADD " UINT_FMT, unum);
break;
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
case MP_BC_BUILD_SLICE:
DECODE_UINT;
printf("BUILD_SLICE " UINT_FMT, unum);
@@ -433,25 +435,25 @@ void mp_bytecode_print2(const byte *ip, int len) {
case MP_BC_MAKE_FUNCTION:
DECODE_PTR;
printf("MAKE_FUNCTION " UINT_FMT, unum);
printf("MAKE_FUNCTION %p", (void*)unum);
break;
case MP_BC_MAKE_FUNCTION_DEFARGS:
DECODE_PTR;
printf("MAKE_FUNCTION_DEFARGS " UINT_FMT, unum);
printf("MAKE_FUNCTION_DEFARGS %p", (void*)unum);
break;
case MP_BC_MAKE_CLOSURE: {
DECODE_PTR;
machine_uint_t n_closed_over = *ip++;
printf("MAKE_CLOSURE " UINT_FMT " " UINT_FMT, unum, n_closed_over);
printf("MAKE_CLOSURE %p " UINT_FMT, (void*)unum, n_closed_over);
break;
}
case MP_BC_MAKE_CLOSURE_DEFARGS: {
DECODE_PTR;
machine_uint_t n_closed_over = *ip++;
printf("MAKE_CLOSURE_DEFARGS " UINT_FMT " " UINT_FMT, unum, n_closed_over);
printf("MAKE_CLOSURE_DEFARGS %p " UINT_FMT, (void*)unum, n_closed_over);
break;
}

View File

@@ -28,6 +28,7 @@
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "smallint.h"
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) {
// Check for multiply overflow; see CERT INT32-C

View File

@@ -26,6 +26,11 @@
// Functions for small integer arithmetic
// In SMALL_INT, next-to-highest bits is used as sign, so both must match for value in range
#define MP_SMALL_INT_MIN ((mp_small_int_t)(((machine_int_t)WORD_MSBIT_HIGH) >> 1))
#define MP_SMALL_INT_MAX ((mp_small_int_t)(~(MP_SMALL_INT_MIN)))
#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & WORD_MSBIT_HIGH) == 0)
bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y);
machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor);
machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom);

View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,6 +32,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "objstr.h"
#include "stream.h"
#if MICROPY_STREAMS_NON_BLOCK
#include <errno.h>
@@ -52,6 +54,8 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
#define is_nonblocking_error(errno) (0)
#endif
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_bytes) ? &mp_type_bytes : &mp_type_str)
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
@@ -77,7 +81,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error));
} else {
mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size
mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), buf, out_sz); // will reallocate to use exact size
m_free(buf, sz);
return s;
}
@@ -154,7 +158,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
}
}
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, total_size, false);
mp_obj_t s = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, total_size);
vstr_free(vstr);
return s;
}
@@ -203,7 +207,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
}
}
// TODO need a string creation API that doesn't copy the given data
mp_obj_t ret = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
mp_obj_t ret = mp_obj_new_str_of_type(STREAM_CONTENT_TYPE(o->type->stream_p), (byte*)vstr->buf, vstr->len);
vstr_free(vstr);
return ret;
}

425
py/vm.c
View File

@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -39,13 +40,6 @@
#include "bc.h"
#include "objgenerator.h"
// With these macros you can tune the maximum number of state slots
// that will be allocated on the stack. Any function that needs more
// than this will use the heap.
#define VM_MAX_STATE_ON_STACK (10)
#define VM_MAX_EXC_STATE_ON_STACK (4)
#define DETECT_VM_STACK_OVERFLOW (0)
#if 0
#define TRACE(ip) mp_bytecode_print2(ip, 1);
#else
@@ -75,12 +69,10 @@ typedef enum {
} while (0)
#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
#define DECODE_QSTR do { \
qst = 0; \
#define DECODE_QSTR qstr qst = 0; \
do { \
qst = (qst << 7) + (*ip & 0x7f); \
} while ((*ip++ & 0x80) != 0); \
} while (0)
} while ((*ip++ & 0x80) != 0)
#define DECODE_PTR do { \
ip = (byte*)(((machine_uint_t)ip + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1))); /* align ip */ \
unum = *(machine_uint_t*)ip; \
@@ -94,7 +86,7 @@ typedef enum {
#define PUSH_EXC_BLOCK() \
DECODE_ULABEL; /* except labels are always forward */ \
++exc_sp; \
exc_sp->opcode = *save_ip; \
exc_sp->opcode = *code_state->ip; \
exc_sp->handler = ip + unum; \
exc_sp->val_sp = MP_TAGPTR_MAKE(sp, currently_in_except_block); \
exc_sp->prev_exc = MP_OBJ_NULL; \
@@ -104,128 +96,18 @@ typedef enum {
currently_in_except_block = MP_TAGPTR_TAG(exc_sp->val_sp); /* restore previous state */ \
exc_sp--; /* pop back to previous exception handler */
mp_vm_return_kind_t mp_execute_bytecode(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret) {
const byte *ip = code;
// get code info size, and skip line number table
machine_uint_t code_info_size = ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24);
ip += code_info_size;
// bytecode prelude: state size and exception stack size; 16 bit uints
machine_uint_t n_state = ip[0] | (ip[1] << 8);
machine_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
ip += 4;
// allocate state for locals and stack
mp_obj_t temp_state[VM_MAX_STATE_ON_STACK];
mp_obj_t *state = &temp_state[0];
#if DETECT_VM_STACK_OVERFLOW
n_state += 1;
#endif
if (n_state > VM_MAX_STATE_ON_STACK) {
state = m_new(mp_obj_t, n_state);
}
mp_obj_t *sp = &state[0] - 1;
// allocate state for exceptions
mp_exc_stack_t exc_state[VM_MAX_EXC_STATE_ON_STACK];
mp_exc_stack_t *exc_stack = &exc_state[0];
if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
exc_stack = m_new(mp_exc_stack_t, n_exc_stack);
}
mp_exc_stack_t *exc_sp = &exc_stack[0] - 1;
// init args
for (uint i = 0; i < n_args; i++) {
state[n_state - 1 - i] = args[i];
}
for (uint i = 0; i < n_args2; i++) {
state[n_state - 1 - n_args - i] = args2[i];
}
// set rest of state to MP_OBJ_NULL
for (uint i = 0; i < n_state - n_args - n_args2; i++) {
state[i] = MP_OBJ_NULL;
}
// bytecode prelude: initialise closed over variables
for (uint n_local = *ip++; n_local > 0; n_local--) {
uint local_num = *ip++;
state[n_state - 1 - local_num] = mp_obj_new_cell(state[n_state - 1 - local_num]);
}
// execute the byte code
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL);
#if DETECT_VM_STACK_OVERFLOW
// We can't check the case when an exception is returned in state[n_state - 1]
// and there are no arguments, because in this case our detection slot may have
// been overwritten by the returned exception (which is allowed).
if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_args == 0 && n_args2 == 0)) {
// Just check to see that we have at least 1 null object left in the state.
bool overflow = true;
for (uint i = 0; i < n_state - n_args - n_args2; i++) {
if (state[i] == MP_OBJ_NULL) {
overflow = false;
break;
}
}
if (overflow) {
printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state);
assert(0);
}
}
#endif
mp_vm_return_kind_t ret_kind;
switch (vm_return_kind) {
case MP_VM_RETURN_NORMAL:
// return value is in *sp
*ret = *sp;
ret_kind = MP_VM_RETURN_NORMAL;
break;
case MP_VM_RETURN_EXCEPTION:
// return value is in state[n_state - 1]
*ret = state[n_state - 1];
ret_kind = MP_VM_RETURN_EXCEPTION;
break;
case MP_VM_RETURN_YIELD: // byte-code shouldn't yield
default:
assert(0);
*ret = mp_const_none;
ret_kind = MP_VM_RETURN_NORMAL;
}
// free the state if it was allocated on the heap
if (n_state > VM_MAX_STATE_ON_STACK) {
m_free(state, n_state);
}
// free the exception state if it was allocated on the heap
if (n_exc_stack > VM_MAX_EXC_STATE_ON_STACK) {
m_free(exc_stack, n_exc_stack);
}
return ret_kind;
}
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
// sp points to bottom of stack which grows up
// returns:
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
// MP_VM_RETURN_EXCEPTION, exception in fastn[0]
mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_in_out,
mp_obj_t *fastn, mp_obj_t **sp_in_out,
mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out,
volatile mp_obj_t inject_exc) {
#if MICROPY_USE_COMPUTED_GOTO
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc) {
#if MICROPY_OPT_COMPUTED_GOTO
#include "vmentrytable.h"
#define DISPATCH() do { \
TRACE(ip); \
save_ip = ip; \
code_state->ip = ip; \
goto *entry_table[*ip++]; \
} while(0)
#define ENTRY(op) entry_##op
@@ -242,11 +124,13 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
// loop and the exception handler, leading to very obscure bugs.
#define RAISE(o) do { nlr_pop(); nlr.ret_val = o; goto exception_handler; } while(0)
// Pointers which are constant for particular invocation of mp_execute_bytecode()
mp_obj_t *const fastn = &code_state->state[code_state->n_state - 1];
mp_exc_stack_t *const exc_stack = (mp_exc_stack_t*)(code_state->state + code_state->n_state);
// variables that are visible to the exception handler (declared volatile)
volatile bool currently_in_except_block = MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(*exc_sp_in_out); // stack grows up, exc_sp points to top of stack
const byte *volatile save_ip = *ip_in_out; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
mp_obj_t *volatile save_sp = *sp_in_out; // this is so we can access sp in the exception handler when needed
volatile bool currently_in_except_block = MP_TAGPTR_TAG(code_state->exc_sp); // 0 or 1, to detect nested exceptions
mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack
// outer exception handling loop
for (;;) {
@@ -254,11 +138,10 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
outer_dispatch_loop:
if (nlr_push(&nlr) == 0) {
// local variables that are not visible to the exception handler
const byte *ip = *ip_in_out;
mp_obj_t *sp = *sp_in_out;
const byte *ip = code_state->ip;
mp_obj_t *sp = code_state->sp;
machine_uint_t unum;
qstr qst;
mp_obj_t obj1, obj2;
mp_obj_t obj_shared;
// If we have exception to inject, now that we finish setting up
// execution context, raise it. This works as if RAISE_VARARGS
@@ -266,20 +149,20 @@ outer_dispatch_loop:
// Injecting exc into yield from generator is a special case,
// handled by MP_BC_YIELD_FROM itself
if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) {
obj1 = inject_exc;
mp_obj_t exc = inject_exc;
inject_exc = MP_OBJ_NULL;
obj1 = mp_make_raise_obj(obj1);
RAISE(obj1);
exc = mp_make_raise_obj(exc);
RAISE(exc);
}
// loop to execute byte code
for (;;) {
dispatch_loop:
#if MICROPY_USE_COMPUTED_GOTO
#if MICROPY_OPT_COMPUTED_GOTO
DISPATCH();
#else
TRACE(ip);
save_ip = ip;
code_state->ip = ip;
switch (*ip++) {
#endif
@@ -312,88 +195,98 @@ dispatch_loop:
DISPATCH();
}
ENTRY(MP_BC_LOAD_CONST_INT):
ENTRY(MP_BC_LOAD_CONST_INT): {
DECODE_QSTR;
PUSH(mp_obj_new_int_from_qstr(qst));
PUSH(mp_load_const_int(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_CONST_DEC):
ENTRY(MP_BC_LOAD_CONST_DEC): {
DECODE_QSTR;
PUSH(mp_load_const_dec(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_CONST_BYTES):
ENTRY(MP_BC_LOAD_CONST_BYTES): {
DECODE_QSTR;
PUSH(mp_load_const_bytes(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_CONST_STRING):
ENTRY(MP_BC_LOAD_CONST_STRING): {
DECODE_QSTR;
PUSH(mp_load_const_str(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_NULL):
PUSH(MP_OBJ_NULL);
DISPATCH();
ENTRY(MP_BC_LOAD_FAST_0):
obj1 = fastn[0];
obj_shared = fastn[0];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_1):
obj1 = fastn[-1];
obj_shared = fastn[-1];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_2):
obj1 = fastn[-2];
obj_shared = fastn[-2];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_N):
DECODE_UINT;
obj1 = fastn[-unum];
obj_shared = fastn[-unum];
load_check:
if (obj1 == MP_OBJ_NULL) {
local_name_error:
obj1 = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment");
RAISE(obj1);
if (obj_shared == MP_OBJ_NULL) {
local_name_error: {
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment");
RAISE(obj);
}
}
PUSH(obj1);
PUSH(obj_shared);
DISPATCH();
ENTRY(MP_BC_LOAD_DEREF):
DECODE_UINT;
obj1 = mp_obj_cell_get(fastn[-unum]);
obj_shared = mp_obj_cell_get(fastn[-unum]);
goto load_check;
ENTRY(MP_BC_LOAD_NAME):
ENTRY(MP_BC_LOAD_NAME): {
DECODE_QSTR;
PUSH(mp_load_name(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_GLOBAL):
ENTRY(MP_BC_LOAD_GLOBAL): {
DECODE_QSTR;
PUSH(mp_load_global(qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_ATTR):
ENTRY(MP_BC_LOAD_ATTR): {
DECODE_QSTR;
SET_TOP(mp_load_attr(TOP(), qst));
DISPATCH();
}
ENTRY(MP_BC_LOAD_METHOD):
ENTRY(MP_BC_LOAD_METHOD): {
DECODE_QSTR;
mp_load_method(*sp, qst, sp);
sp += 1;
DISPATCH();
}
ENTRY(MP_BC_LOAD_BUILD_CLASS):
PUSH(mp_load_build_class());
DISPATCH();
ENTRY(MP_BC_LOAD_SUBSCR):
obj1 = POP();
SET_TOP(mp_obj_subscr(TOP(), obj1, MP_OBJ_SENTINEL));
ENTRY(MP_BC_LOAD_SUBSCR): {
mp_obj_t index = POP();
SET_TOP(mp_obj_subscr(TOP(), index, MP_OBJ_SENTINEL));
DISPATCH();
}
ENTRY(MP_BC_STORE_FAST_0):
fastn[0] = POP();
@@ -417,21 +310,24 @@ dispatch_loop:
mp_obj_cell_set(fastn[-unum], POP());
DISPATCH();
ENTRY(MP_BC_STORE_NAME):
ENTRY(MP_BC_STORE_NAME): {
DECODE_QSTR;
mp_store_name(qst, POP());
DISPATCH();
}
ENTRY(MP_BC_STORE_GLOBAL):
ENTRY(MP_BC_STORE_GLOBAL): {
DECODE_QSTR;
mp_store_global(qst, POP());
DISPATCH();
}
ENTRY(MP_BC_STORE_ATTR):
ENTRY(MP_BC_STORE_ATTR): {
DECODE_QSTR;
mp_store_attr(sp[0], qst, sp[-1]);
sp -= 2;
DISPATCH();
}
ENTRY(MP_BC_STORE_SUBSCR):
mp_obj_subscr(sp[-1], sp[0], sp[-2]);
@@ -454,20 +350,23 @@ dispatch_loop:
mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL);
DISPATCH();
ENTRY(MP_BC_DELETE_NAME):
ENTRY(MP_BC_DELETE_NAME): {
DECODE_QSTR;
mp_delete_name(qst);
DISPATCH();
}
ENTRY(MP_BC_DELETE_GLOBAL):
ENTRY(MP_BC_DELETE_GLOBAL): {
DECODE_QSTR;
mp_delete_global(qst);
DISPATCH();
}
ENTRY(MP_BC_DUP_TOP):
obj1 = TOP();
PUSH(obj1);
ENTRY(MP_BC_DUP_TOP): {
mp_obj_t top = TOP();
PUSH(top);
DISPATCH();
}
ENTRY(MP_BC_DUP_TOP_TWO):
sp += 2;
@@ -479,18 +378,20 @@ dispatch_loop:
sp -= 1;
DISPATCH();
ENTRY(MP_BC_ROT_TWO):
obj1 = sp[0];
ENTRY(MP_BC_ROT_TWO): {
mp_obj_t top = sp[0];
sp[0] = sp[-1];
sp[-1] = obj1;
sp[-1] = top;
DISPATCH();
}
ENTRY(MP_BC_ROT_THREE):
obj1 = sp[0];
ENTRY(MP_BC_ROT_THREE): {
mp_obj_t top = sp[0];
sp[0] = sp[-1];
sp[-1] = sp[-2];
sp[-2] = obj1;
sp[-2] = top;
DISPATCH();
}
ENTRY(MP_BC_JUMP):
DECODE_SLABEL;
@@ -529,14 +430,15 @@ dispatch_loop:
}
DISPATCH();
ENTRY(MP_BC_SETUP_WITH):
obj1 = TOP();
SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__));
mp_load_method(obj1, MP_QSTR___enter__, sp + 1);
obj2 = mp_call_method_n_kw(0, 0, sp + 1);
ENTRY(MP_BC_SETUP_WITH): {
mp_obj_t obj = TOP();
SET_TOP(mp_load_attr(obj, MP_QSTR___exit__));
mp_load_method(obj, MP_QSTR___enter__, sp + 1);
mp_obj_t ret = mp_call_method_n_kw(0, 0, sp + 1);
PUSH_EXC_BLOCK();
PUSH(obj2);
PUSH(ret);
DISPATCH();
}
ENTRY(MP_BC_WITH_CLEANUP): {
// Arriving here, there's "exception control block" on top of stack,
@@ -546,21 +448,21 @@ dispatch_loop:
static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none};
if (TOP() == mp_const_none) {
sp--;
obj1 = TOP();
mp_obj_t obj = TOP();
SET_TOP(mp_const_none);
obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc);
mp_call_function_n_kw(obj, 3, 0, no_exc);
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
mp_obj_t cause = POP();
switch (MP_OBJ_SMALL_INT_VALUE(cause)) {
case UNWIND_RETURN: {
mp_obj_t retval = POP();
obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc);
mp_call_function_n_kw(TOP(), 3, 0, no_exc);
SET_TOP(retval);
PUSH(cause);
break;
}
case UNWIND_JUMP: {
obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
mp_call_function_n_kw(sp[-2], 3, 0, no_exc);
// Pop __exit__ boundmethod at sp[-2]
sp[-2] = sp[-1];
sp[-1] = sp[0];
@@ -572,14 +474,14 @@ dispatch_loop:
}
} else if (mp_obj_is_exception_type(TOP())) {
mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]};
obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args);
mp_obj_t ret_value = mp_call_function_n_kw(sp[-3], 3, 0, args);
// Pop __exit__ boundmethod at sp[-3]
// TODO: Once semantics is proven, optimize for case when obj2 == True
// TODO: Once semantics is proven, optimize for case when ret_value == True
sp[-3] = sp[-2];
sp[-2] = sp[-1];
sp[-1] = sp[0];
sp--;
if (mp_obj_is_true(obj2)) {
if (mp_obj_is_true(ret_value)) {
// This is what CPython does
//PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED));
// But what we need to do is - pop exception from value stack...
@@ -601,10 +503,10 @@ dispatch_loop:
ENTRY(MP_BC_UNWIND_JUMP):
DECODE_SLABEL;
PUSH((void*)(ip + unum)); // push destination ip for jump
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind
PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind (0x80 bit set if we also need to pop stack)
unwind_jump:
unum = (machine_uint_t)POP(); // get number of exception handlers to unwind
while (unum > 0) {
while ((unum & 0x7f) > 0) {
unum -= 1;
assert(exc_sp >= exc_stack);
if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) {
@@ -621,6 +523,9 @@ unwind_jump:
exc_sp--;
}
ip = (const byte*)POP(); // pop destination ip for jump
if (unum != 0) {
sp--;
}
DISPATCH();
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
@@ -660,18 +565,19 @@ unwind_jump:
SET_TOP(mp_getiter(TOP()));
DISPATCH();
ENTRY(MP_BC_FOR_ITER):
ENTRY(MP_BC_FOR_ITER): {
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
save_sp = sp;
code_state->sp = sp;
assert(TOP());
obj1 = mp_iternext_allow_raise(TOP());
if (obj1 == MP_OBJ_STOP_ITERATION) {
mp_obj_t value = mp_iternext_allow_raise(TOP());
if (value == MP_OBJ_STOP_ITERATION) {
--sp; // pop the exhausted iterator
ip += unum; // jump to after for-block
} else {
PUSH(obj1); // push the next iteration value
PUSH(value); // push the next iteration value
}
DISPATCH();
}
// matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
ENTRY(MP_BC_POP_BLOCK):
@@ -705,12 +611,13 @@ unwind_jump:
SET_TOP(mp_unary_op(unum, TOP()));
DISPATCH();
ENTRY(MP_BC_BINARY_OP):
ENTRY(MP_BC_BINARY_OP): {
unum = *ip++;
obj2 = POP();
obj1 = TOP();
SET_TOP(mp_binary_op(unum, obj1, obj2));
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(unum, lhs, rhs));
DISPATCH();
}
ENTRY(MP_BC_BUILD_TUPLE):
DECODE_UINT;
@@ -748,6 +655,7 @@ unwind_jump:
sp -= 2;
DISPATCH();
#if MICROPY_PY_BUILTINS_SET
ENTRY(MP_BC_BUILD_SET):
DECODE_UINT;
sp -= unum - 1;
@@ -760,19 +668,20 @@ unwind_jump:
mp_obj_set_store(sp[-unum], sp[0]);
sp--;
DISPATCH();
#endif
#if MICROPY_ENABLE_SLICE
#if MICROPY_PY_BUILTINS_SLICE
ENTRY(MP_BC_BUILD_SLICE):
DECODE_UINT;
if (unum == 2) {
obj2 = POP();
obj1 = TOP();
SET_TOP(mp_obj_new_slice(obj1, obj2, NULL));
mp_obj_t stop = POP();
mp_obj_t start = TOP();
SET_TOP(mp_obj_new_slice(start, stop, mp_const_none));
} else {
obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported");
nlr_pop();
fastn[0] = obj1;
return MP_VM_RETURN_EXCEPTION;
mp_obj_t step = POP();
mp_obj_t stop = POP();
mp_obj_t start = TOP();
SET_TOP(mp_obj_new_slice(start, stop, step));
}
DISPATCH();
#endif
@@ -794,12 +703,13 @@ unwind_jump:
PUSH(mp_make_function_from_raw_code((mp_raw_code_t*)unum, MP_OBJ_NULL, MP_OBJ_NULL));
DISPATCH();
ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS):
ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): {
DECODE_PTR;
// Stack layout: def_tuple def_dict <- TOS
obj1 = POP();
SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1));
mp_obj_t def_dict = POP();
SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), def_dict));
DISPATCH();
}
ENTRY(MP_BC_MAKE_CLOSURE): {
DECODE_PTR;
@@ -874,38 +784,40 @@ unwind_return:
exc_sp--;
}
nlr_pop();
*sp_in_out = sp;
code_state->sp = sp;
assert(exc_sp == exc_stack - 1);
return MP_VM_RETURN_NORMAL;
ENTRY(MP_BC_RAISE_VARARGS):
ENTRY(MP_BC_RAISE_VARARGS): {
unum = *ip++;
mp_obj_t obj;
assert(unum <= 1);
if (unum == 0) {
// search for the inner-most previous exception, to reraise it
obj1 = MP_OBJ_NULL;
obj = MP_OBJ_NULL;
for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) {
if (e->prev_exc != MP_OBJ_NULL) {
obj1 = e->prev_exc;
obj = e->prev_exc;
break;
}
}
if (obj1 == MP_OBJ_NULL) {
obj1 = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise");
RAISE(obj1);
if (obj == MP_OBJ_NULL) {
obj = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise");
RAISE(obj);
}
} else {
obj1 = POP();
obj = POP();
}
obj1 = mp_make_raise_obj(obj1);
RAISE(obj1);
obj = mp_make_raise_obj(obj);
RAISE(obj);
}
ENTRY(MP_BC_YIELD_VALUE):
yield:
nlr_pop();
*ip_in_out = ip;
*sp_in_out = sp;
*exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
code_state->ip = ip;
code_state->sp = sp;
code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
return MP_VM_RETURN_YIELD;
ENTRY(MP_BC_YIELD_FROM): {
@@ -913,30 +825,31 @@ yield:
#define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type)
#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { RAISE(t); }
mp_vm_return_kind_t ret_kind;
obj1 = POP();
mp_obj_t send_value = POP();
mp_obj_t t_exc = MP_OBJ_NULL;
mp_obj_t ret_value;
if (inject_exc != MP_OBJ_NULL) {
t_exc = inject_exc;
inject_exc = MP_OBJ_NULL;
ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &obj2);
ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &ret_value);
} else {
ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2);
ret_kind = mp_resume(TOP(), send_value, MP_OBJ_NULL, &ret_value);
}
if (ret_kind == MP_VM_RETURN_YIELD) {
ip--;
PUSH(obj2);
PUSH(ret_value);
goto yield;
}
if (ret_kind == MP_VM_RETURN_NORMAL) {
// Pop exhausted gen
sp--;
if (obj2 == MP_OBJ_NULL) {
if (ret_value == MP_OBJ_NULL) {
// Optimize StopIteration
// TODO: get StopIteration's value
PUSH(mp_const_none);
} else {
PUSH(obj2);
PUSH(ret_value);
}
// If we injected GeneratorExit downstream, then even
@@ -947,41 +860,44 @@ yield:
if (ret_kind == MP_VM_RETURN_EXCEPTION) {
// Pop exhausted gen
sp--;
if (EXC_MATCH(obj2, &mp_type_StopIteration)) {
PUSH(mp_obj_exception_get_value(obj2));
if (EXC_MATCH(ret_value, &mp_type_StopIteration)) {
PUSH(mp_obj_exception_get_value(ret_value));
// If we injected GeneratorExit downstream, then even
// if it was swallowed, we re-raise GeneratorExit
GENERATOR_EXIT_IF_NEEDED(t_exc);
DISPATCH();
} else {
RAISE(obj2);
RAISE(ret_value);
}
}
}
ENTRY(MP_BC_IMPORT_NAME):
ENTRY(MP_BC_IMPORT_NAME): {
DECODE_QSTR;
obj1 = POP();
SET_TOP(mp_import_name(qst, obj1, TOP()));
mp_obj_t obj = POP();
SET_TOP(mp_import_name(qst, obj, TOP()));
DISPATCH();
}
ENTRY(MP_BC_IMPORT_FROM):
ENTRY(MP_BC_IMPORT_FROM): {
DECODE_QSTR;
obj1 = mp_import_from(TOP(), qst);
PUSH(obj1);
mp_obj_t obj = mp_import_from(TOP(), qst);
PUSH(obj);
DISPATCH();
}
ENTRY(MP_BC_IMPORT_STAR):
mp_import_all(POP());
DISPATCH();
ENTRY_DEFAULT:
obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
ENTRY_DEFAULT: {
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
nlr_pop();
fastn[0] = obj1;
fastn[0] = obj;
return MP_VM_RETURN_EXCEPTION;
}
#if !MICROPY_USE_COMPUTED_GOTO
#if !MICROPY_OPT_COMPUTED_GOTO
} // switch
#endif
} // for loop
@@ -991,12 +907,12 @@ exception_handler:
// exception occurred
// check if it's a StopIteration within a for block
if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
const byte *ip = save_ip + 1;
if (*code_state->ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
const byte *ip = code_state->ip + 1;
machine_uint_t unum;
DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward
*ip_in_out = ip + unum; // jump to after for-block
*sp_in_out = save_sp - 1; // pop the exhausted iterator
code_state->ip = ip + unum; // jump to after for-block
code_state->sp -= 1; // pop the exhausted iterator
goto outer_dispatch_loop; // continue with dispatch loop
}
@@ -1005,15 +921,20 @@ exception_handler:
// But consider how to handle nested exceptions.
// TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
const byte *code_info = code_state->code_info;
machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
machine_uint_t source_line = 1;
machine_uint_t bc = save_ip - code_info - code_info_size;
machine_uint_t source_line = 0;
machine_uint_t bc = code_state->ip - code_info - code_info_size;
//printf("find %lu %d %d\n", bc, code_info[12], code_info[13]);
for (const byte* ci = code_info + 12; *ci && bc >= ((*ci) & 31); ci++) {
bc -= *ci & 31;
source_line += *ci >> 5;
const byte* ci = code_info + 12;
if (*ci) {
source_line = 1;
for (; *ci && bc >= ((*ci) & 31); ci++) {
bc -= *ci & 31;
source_line += *ci >> 5;
}
}
mp_obj_exception_add_traceback(nlr.ret_val, source_file, source_line, block_name);
}
@@ -1035,7 +956,7 @@ exception_handler:
currently_in_except_block = 1;
// catch exception and pass to byte code
*ip_in_out = exc_sp->handler;
code_state->ip = exc_sp->handler;
mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp);
// save this exception in the stack so it can be used in a reraise, if needed
exc_sp->prev_exc = nlr.ret_val;
@@ -1043,7 +964,7 @@ exception_handler:
PUSH(mp_const_none);
PUSH(nlr.ret_val);
PUSH(mp_obj_get_type(nlr.ret_val));
*sp_in_out = sp;
code_state->sp = sp;
} else {
// propagate exception to higher level

View File

@@ -24,6 +24,11 @@
* THE SOFTWARE.
*/
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winitializer-overrides"
#endif // __clang__
static void* entry_table[256] = {
[0 ... 255] = &&entry_default,
[MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE,
@@ -110,3 +115,7 @@ static void* entry_table[256] = {
[MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM,
[MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR,
};
#if __clang__
#pragma clang diagnostic pop
#endif // __clang__

23
qemu-arm/README.md Normal file
View File

@@ -0,0 +1,23 @@
This is experimental, community-supported port for Cortex-M emulation as
provided my QEMU (http://qemu.org).
The purposes of this port are to enable:
1. Continuous integration
- run tests agains architecture-specific parts of code base
2. Experimentation
- simulation & prototyping of anything that has architecture-specific
code
- exploring instruction set in terms of optimising some part of
MicroPython or a module
3. Streamlined debugging
- no need for JTAG or even an MCU chip itself
- no need to use OpenOCD or anything else that might slow down the
process in terms of plugging things together, pressing buttons, etc.
This port will only work with with [GCC ARM Embedded](launchpad.net/gcc-arm-embedded)
toolchain and not with CodeSourcery toolchain. You will need to modify
`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`.
The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while
ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be
passed to the linker.

View File

@@ -2,18 +2,19 @@
// 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_ENABLE_REPL_HELPERS (0)
#define MICROPY_ENABLE_LEXER_UNIX (0)
#define MICROPY_HELPER_REPL (0)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
#define MICROPY_PATH_MAX (512)
#define MICROPY_PY_IO (0)
// type definitions for the specific machine
@@ -29,6 +30,8 @@ typedef const void *machine_const_ptr_t; // must be of pointer size
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
#define MICROPY_EXTRA_BUILTINS \
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
// We need to provide a declaration/definition of alloca()
#include <alloca.h>

1
stm/.gitignore vendored
View File

@@ -1 +0,0 @@
build

View File

@@ -1,220 +0,0 @@
include ../py/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include ../py/py.mk
CMSIS_DIR=cmsis
STMPERIPH_DIR=stmperiph
STMUSB_DIR=stmusb
STMUSBD_DIR=stmusbd
STMUSBH_DIR=stmusbh
FATFS_DIR=fatfs
CC3K_DIR=cc3k
DFU=../tools/dfu.py
CROSS_COMPILE = arm-none-eabi-
INC = -I.
INC += -I$(PY_SRC)
INC += -I$(BUILD)
INC += -I$(CMSIS_DIR)
INC += -I$(STMPERIPH_DIR)
INC += -I$(STMUSB_DIR)
INC += -I$(STMUSBD_DIR)
INC += -I$(STMUSBH_DIR)
INC += -I$(FATFS_DIR)
#INC += -I$(CC3K_DIR)
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M4) $(COPT)
BOARD ?= PYBOARD4
ifeq ($(wildcard boards/$(BOARD)/.),)
$(error Invalid BOARD specified)
endif
CFLAGS += -Iboards/$(BOARD)
#Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -g -DPENDSV_DEBUG
COPT = -O0
else
COPT += -Os -DNDEBUG
endif
LDFLAGS = --nostdlib -T stm32f405.ld -Map=$(@:.elf=.map) --cref
LIBS =
# uncomment this if you want libgcc
#LIBS += $(shell $(CC) -print-libgcc-file-name)
SRC_C = \
main.c \
printf.c \
math.c \
system_stm32f4xx.c \
stm32fxxx_it.c \
string0.c \
malloc0.c \
systick.c \
pendsv.c \
gccollect.c \
lexerfatfs.c \
import.c \
pyexec.c \
led.c \
gpio.c \
lcd.c \
servo.c \
flash.c \
storage.c \
accel.c \
usart.c \
usb.c \
timer.c \
audio.c \
sdcard.c \
i2c.c \
adc.c \
rtc.c \
file.c \
pin.c \
pin_named_pins.c \
pin_map.c \
exti.c \
usrsw.c \
pybmodule.c \
# pybwlan.c \
SRC_S = \
startup_stm32f40xx.s \
gchelper.s \
SRC_STMPERIPH = $(addprefix $(STMPERIPH_DIR)/,\
stm_misc.c \
stm32f4xx_rcc.c \
stm32f4xx_syscfg.c \
stm32f4xx_flash.c \
stm32f4xx_dma.c \
stm32f4xx_gpio.c \
stm32f4xx_exti.c \
stm32f4xx_tim.c \
stm32f4xx_sdio.c \
stm32f4xx_pwr.c \
stm32f4xx_rtc.c \
stm32f4xx_usart.c \
stm32f4xx_spi.c \
stm32f4xx_dac.c \
stm32f4xx_rng.c \
stm32f4xx_i2c.c \
stm32f4xx_adc.c \
stm324x7i_eval.c \
stm324x7i_eval_sdio_sd.c \
)
SRC_STMUSB = $(addprefix $(STMUSB_DIR)/,\
usb_core.c \
usb_bsp.c \
usb_dcd.c \
usb_dcd_int.c \
usb_hcd.c \
usb_hcd_int.c \
)
# usb_otg.c \
SRC_STMUSBD = $(addprefix $(STMUSBD_DIR)/,\
usbd_core.c \
usbd_ioreq.c \
usbd_req.c \
usbd_usr.c \
usbd_desc.c \
usbd_pyb_core.c \
usbd_pyb_core2.c \
usbd_cdc_vcp.c \
usbd_msc_bot.c \
usbd_msc_data.c \
usbd_msc_scsi.c \
usbd_storage_msd.c \
)
SRC_STMUSBH = $(addprefix $(STMUSBH_DIR)/,\
usbh_core.c \
usbh_hcs.c \
usbh_stdreq.c \
usbh_ioreq.c \
usbh_usr.c \
usbh_hid_core.c \
usbh_hid_mouse.c \
usbh_hid_keybd.c \
)
SRC_FATFS = $(addprefix $(FATFS_DIR)/,\
ff.c \
diskio.c \
ccsbcs.c \
)
SRC_CC3K = $(addprefix $(CC3K_DIR)/,\
cc3000_common.c \
evnt_handler.c \
hci.c \
netapp.c \
nvmem.c \
security.c \
socket.c \
wlan.c \
ccspi.c \
pybcc3k.c \
)
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o) $(SRC_STMPERIPH:.c=.o) $(SRC_STMUSB:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBD:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBH:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o))
OBJ += $(BUILD)/pins_$(BOARD).o
all: $(BUILD)/flash.dfu
$(BUILD)/flash.dfu: $(BUILD)/flash0.bin $(BUILD)/flash1.bin
$(ECHO) "Create $@"
$(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/flash0.bin -b 0x08020000:$(BUILD)/flash1.bin $@
$(BUILD)/flash0.bin: $(BUILD)/flash.elf
$(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $@
$(BUILD)/flash1.bin: $(BUILD)/flash.elf
$(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $@
$(BUILD)/flash.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
$(Q)$(SIZE) $@
MAKE_PINS = boards/make-pins.py
BOARD_PINS = boards/$(BOARD)/pins.csv
AF_FILE = boards/stm32f4xx-af.csv
PREFIX_FILE = boards/stm32f4xx-prefix.c
GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
GEN_PINS_HDR = $(BUILD)/pins.h
# Making OBJ use an order-only depenedency on the generated pins.h file
# has the side effect of making the pins.h file before we actually compile
# any of the objects. The normal dependency generation will deal with the
# case when pins.h is modified. But when it doesn't exist, we don't know
# which source files might need it.
$(OBJ): | $(BUILD)/pins.h
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
$(BUILD)/%_$(BOARD).c $(BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE)
$(ECHO) "Create $@"
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC)
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
$(call compile_c)
include ../py/mkrules.mk

View File

@@ -1,300 +0,0 @@
#include <stdio.h>
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "systick.h"
#include "obj.h"
#include "runtime.h"
#include "accel.h"
#define ACCEL_ADDR (0x4c)
void accel_init(void) {
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // enable I2C1
//gpio_pin_init(GPIOB, 6 /* B6 is SCL */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */);
//gpio_pin_init(GPIOB, 7 /* B7 is SDA */, 2 /* AF mode */, 1 /* open drain output */, 1 /* 25 MHz */, 0 /* no pull up or pull down */);
//gpio_pin_af(GPIOB, 6, 4 /* AF 4 for I2C1 */);
//gpio_pin_af(GPIOB, 7, 4 /* AF 4 for I2C1 */);
// XXX untested GPIO init! (was above code)
GPIO_InitTypeDef GPIO_InitStructure;
// PB5 is connected to AVDD; pull high to enable MMA accel device
GPIOB->BSRRH = GPIO_Pin_5; // PB5 low to start with
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// PB6=SCL, PB7=SDA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// alternate functions for SCL and SDA
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
// get clock speeds
RCC_ClocksTypeDef rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
// disable the I2C peripheral before we configure it
I2C1->CR1 &= ~I2C_CR1_PE;
// program peripheral input clock
I2C1->CR2 = 4; // no interrupts; 4 MHz (hopefully!) (could go up to 42MHz)
// configure clock control reg
uint32_t freq = rcc_clocks.PCLK1_Frequency / (100000 << 1); // want 100kHz, this is the formula for freq
I2C1->CCR = freq; // standard mode (speed), freq calculated as above
// configure rise time reg
I2C1->TRISE = (rcc_clocks.PCLK1_Frequency / 1000000) + 1; // formula for trise, gives maximum rise time
// enable the I2C peripheral
I2C1->CR1 |= I2C_CR1_PE;
// wait 20ms, then turn on AVDD, then wait 20ms again; this seems to work, but maybe can decrease delays
// doesn't work for soft reboot; 50ms doesn't work either...
sys_tick_delay_ms(20);
GPIOB->BSRRL = GPIO_Pin_5;
sys_tick_delay_ms(20);
// set START bit in CR1 to generate a start cond!
// init the chip via I2C commands
accel_start(ACCEL_ADDR, 1);
accel_send_byte(0);
accel_stop();
/*
// read and print all 11 registers
accel_start(ACCEL_ADDR, 1);
accel_send_byte(0);
accel_restart(ACCEL_ADDR, 0);
for (int i = 0; i <= 0xa; i++) {
int data;
if (i == 0xa) {
data = accel_read_nack();
} else {
data = accel_read_ack();
}
printf(" %02x", data);
}
printf("\n");
*/
// put into active mode
accel_start(ACCEL_ADDR, 1);
accel_send_byte(7); // mode
accel_send_byte(1); // active mode
accel_stop();
/*
// infinite loop to read values
for (;;) {
sys_tick_delay_ms(500);
accel_start(ACCEL_ADDR, 1);
accel_send_byte(0);
accel_restart(ACCEL_ADDR, 0);
for (int i = 0; i <= 3; i++) {
int data;
if (i == 3) {
data = accel_read_nack();
printf(" %02x\n", data);
} else {
data = accel_read_ack() & 0x3f;
if (data & 0x20) {
data |= ~0x1f;
}
printf(" % 2d", data);
}
}
}
*/
}
static uint32_t i2c_get_sr(void) {
// must read SR1 first, then SR2, as the read can clear some flags
uint32_t sr1 = I2C1->SR1;
uint32_t sr2 = I2C1->SR2;
return (sr2 << 16) | sr1;
}
void accel_restart(uint8_t addr, int write) {
// send start condition
I2C1->CR1 |= I2C_CR1_START;
// wait for BUSY, MSL and SB --> Slave has acknowledged start condition
uint32_t timeout = 1000000;
while ((i2c_get_sr() & 0x00030001) != 0x00030001) {
if (--timeout == 0) {
printf("timeout in accel_restart\n");
return;
}
}
if (write) {
// send address and write bit
I2C1->DR = (addr << 1) | 0;
// wait for BUSY, MSL, ADDR, TXE and TRA
timeout = 1000000;
while ((i2c_get_sr() & 0x00070082) != 0x00070082) {
if (--timeout == 0) {
printf("timeout in accel_restart write\n");
return;
}
}
} else {
// send address and read bit
I2C1->DR = (addr << 1) | 1;
// wait for BUSY, MSL and ADDR flags
timeout = 1000000;
while ((i2c_get_sr() & 0x00030002) != 0x00030002) {
if (--timeout == 0) {
printf("timeout in accel_restart read\n");
return;
}
}
}
}
void accel_start(uint8_t addr, int write) {
// wait until I2C is not busy
uint32_t timeout = 1000000;
while (I2C1->SR2 & I2C_SR2_BUSY) {
if (--timeout == 0) {
printf("timeout in accel_start\n");
return;
}
}
// do rest of start
accel_restart(addr, write);
}
void accel_send_byte(uint8_t data) {
// send byte
I2C1->DR = data;
// wait for TRA, BUSY, MSL, TXE and BTF (byte transmitted)
uint32_t timeout = 1000000;
while ((i2c_get_sr() & 0x00070084) != 0x00070084) {
if (--timeout == 0) {
printf("timeout in accel_send_byte\n");
return;
}
}
}
uint8_t accel_read_ack(void) {
// enable ACK of received byte
I2C1->CR1 |= I2C_CR1_ACK;
// wait for BUSY, MSL and RXNE (byte received)
uint32_t timeout = 1000000;
while ((i2c_get_sr() & 0x00030040) != 0x00030040) {
if (--timeout == 0) {
printf("timeout in accel_read_ack\n");
break;
}
}
// read and return data
uint8_t data = I2C1->DR;
return data;
}
uint8_t accel_read_nack(void) {
// disable ACK of received byte (to indicate end of receiving)
I2C1->CR1 &= (uint16_t)~((uint16_t)I2C_CR1_ACK);
// last byte should apparently also generate a stop condition
I2C1->CR1 |= I2C_CR1_STOP;
// wait for BUSY, MSL and RXNE (byte received)
uint32_t timeout = 1000000;
while ((i2c_get_sr() & 0x00030040) != 0x00030040) {
if (--timeout == 0) {
printf("timeout in accel_read_nack\n");
break;
}
}
// read and return data
uint8_t data = I2C1->DR;
return data;
}
void accel_stop(void) {
// send stop condition
I2C1->CR1 |= I2C_CR1_STOP;
}
/******************************************************************************/
/* Micro Python bindings */
int accel_buf[12];
mp_obj_t pyb_accel_read(void) {
for (int i = 0; i <= 6; i += 3) {
accel_buf[0 + i] = accel_buf[0 + i + 3];
accel_buf[1 + i] = accel_buf[1 + i + 3];
accel_buf[2 + i] = accel_buf[2 + i + 3];
}
accel_start(ACCEL_ADDR, 1);
accel_send_byte(0);
accel_restart(ACCEL_ADDR, 0);
for (int i = 0; i <= 2; i++) {
int v = accel_read_ack() & 0x3f;
if (v & 0x20) {
v |= ~0x1f;
}
accel_buf[9 + i] = v;
}
int jolt_info = accel_read_nack();
mp_obj_t data[4];
data[0] = mp_obj_new_int(accel_buf[0] + accel_buf[3] + accel_buf[6] + accel_buf[9]);
data[1] = mp_obj_new_int(accel_buf[1] + accel_buf[4] + accel_buf[7] + accel_buf[10]);
data[2] = mp_obj_new_int(accel_buf[2] + accel_buf[5] + accel_buf[8] + accel_buf[11]);
data[3] = mp_obj_new_int(jolt_info);
return mp_obj_new_tuple(4, data);
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_obj, pyb_accel_read);
mp_obj_t pyb_accel_read_all(void) {
mp_obj_t data[11];
accel_start(ACCEL_ADDR, 1);
accel_send_byte(0);
accel_restart(ACCEL_ADDR, 0);
for (int i = 0; i <= 9; i++) {
data[i] = mp_obj_new_int(accel_read_ack());
}
data[10] = mp_obj_new_int(accel_read_nack());
return mp_obj_new_tuple(11, data);
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_all_obj, pyb_accel_read_all);
mp_obj_t pyb_accel_write_mode(mp_obj_t o_int, mp_obj_t o_mode) {
accel_start(ACCEL_ADDR, 1);
accel_send_byte(6); // start at int
accel_send_byte(mp_obj_get_int(o_int));
accel_send_byte(mp_obj_get_int(o_mode));
accel_stop();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_write_mode_obj, pyb_accel_write_mode);

View File

@@ -1,11 +0,0 @@
void accel_init(void);
void accel_restart(uint8_t addr, int write);
void accel_start(uint8_t addr, int write);
void accel_send_byte(uint8_t data);
uint8_t accel_read_ack(void);
uint8_t accel_read_nack(void);
void accel_stop(void);
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_all_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_accel_write_mode_obj);

446
stm/adc.c
View File

@@ -1,446 +0,0 @@
#include <stdio.h>
#include <stm32f4xx.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "adc.h"
/* ADC defintions */
#define ADCx (ADC1)
#define ADCx_CLK (RCC_APB2Periph_ADC1)
#define ADC_NUM_CHANNELS (16)
/* Internally connected ADC channels Temp/VBAT/VREF*/
#if defined (STM32F40XX) || defined(STM32F41XX) || defined(STM32F40_41xxx)
#define ADC_TEMP_CHANNEL (16)
#define ADC_VBAT_CHANNEL (18)
#define ADC_VREF_CHANNEL (17)
#elif defined (STM32F42XX) || defined(STM32F43XX)
#define ADC_TEMP_CHANNEL (18)
#define ADC_VBAT_CHANNEL (18) /* same channel as TEMP */
#define ADC_VREF_CHANNEL (17)
#endif
/* Core temperature sensor definitions */
#define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */
#define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */
/* VBAT divider */
#if defined (STM32F40XX) || defined(STM32F41XX) || defined(STM32F40_41xxx)
#define VBAT_DIV (2)
#elif defined (STM32F42XX) || defined(STM32F43XX)
#define VBAT_DIV (4)
#endif
/* GPIO struct */
typedef struct {
GPIO_TypeDef* port;
uint32_t pin;
} gpio_t;
/* ADC GPIOs */
static const gpio_t adc_gpio[] = {
{GPIOA, GPIO_Pin_0}, /* ADC123_IN0 */
{GPIOA, GPIO_Pin_1}, /* ADC123_IN1 */
{GPIOA, GPIO_Pin_2}, /* ADC123_IN2 */
{GPIOA, GPIO_Pin_3}, /* ADC123_IN3 */
{GPIOA, GPIO_Pin_4}, /* ADC12_IN4 */
{GPIOA, GPIO_Pin_5}, /* ADC12_IN5 */
{GPIOA, GPIO_Pin_6}, /* ADC12_IN6 */
{GPIOA, GPIO_Pin_7}, /* ADC12_IN7 */
{GPIOB, GPIO_Pin_0}, /* ADC12_IN8 */
{GPIOB, GPIO_Pin_1}, /* ADC12_IN9 */
{GPIOC, GPIO_Pin_0}, /* ADC123_IN10 */
{GPIOC, GPIO_Pin_1}, /* ADC123_IN11 */
{GPIOC, GPIO_Pin_2}, /* ADC123_IN12 */
{GPIOC, GPIO_Pin_3}, /* ADC123_IN13 */
{GPIOC, GPIO_Pin_4}, /* ADC12_IN14 */
{GPIOC, GPIO_Pin_5}, /* ADC12_IN15 */
};
void adc_init_all(uint32_t resolution) {
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* Enable ADCx, DMA and GPIO clocks */
#if 0
/* GPIO clocks enabled in main */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC, ENABLE);
#endif
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* Configure ADC GPIOs */
for (int i=0; i<ADC_NUM_CHANNELS; i++) {
GPIO_InitStructure.GPIO_Pin = adc_gpio[i].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(adc_gpio[i].port, &GPIO_InitStructure);
}
/* ADCx Init */
// ADC_DeInit();
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADCx, &ADC_InitStructure);
/* Enable ADCx */
ADC_Cmd(ADCx, ENABLE);
/* Enable VBAT/VREF monitor */
ADC_VBATCmd(ENABLE);
/* Enable temperature sensor */
ADC_TempSensorVrefintCmd(ENABLE);
}
void adc_init_single(uint32_t channel) {
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* Enable ADCx, DMA and GPIO clocks */
#if 0
/* GPIO clocks enabled in main */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |
RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC, ENABLE);
#endif
RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* Configure ADC GPIO for the single channel */
GPIO_InitStructure.GPIO_Pin = adc_gpio[channel].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(adc_gpio[channel].port, &GPIO_InitStructure);
/* ADCx Init */
// ADC_DeInit();
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADCx, &ADC_InitStructure);
/* Enable ADCx */
ADC_Cmd(ADCx, ENABLE);
/* Enable VBAT/VREF monitor */
ADC_VBATCmd(ENABLE);
/* Enable temperature sensor */
ADC_TempSensorVrefintCmd(ENABLE);
}
uint32_t adc_read_channel(int channel)
{
int timeout = 10000;
if (channel > (ADC_NUM_CHANNELS-1)) {
return 0;
}
/* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */
ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_15Cycles);
/* Start ADC single conversion */
ADC_SoftwareStartConv(ADCx);
/* Wait for conversion to be complete*/
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
}
/* ADC conversion timed out */
if (timeout == 0) {
return 0;
}
/* Return converted data */
return ADC_GetConversionValue(ADCx);
}
int adc_read_core_temp()
{
int timeout = 10000;
/* ADC temperature sensor channel config ADC/Channel/SEQ Rank/Sample time */
/* Note: sample time must be higher than minimum sample time */
ADC_RegularChannelConfig(ADCx, ADC_TEMP_CHANNEL, 1, ADC_SampleTime_480Cycles);
/* Start ADC single conversion */
ADC_SoftwareStartConv(ADCx);
/* Wait for conversion to be complete*/
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
}
/* ADC conversion timed out */
if (timeout == 0) {
return 0;
}
/* Convert ADC reading to temperature */
/* Temperature formula from datasheet P.411 */
return ((ADC_GetConversionValue(ADCx) - CORE_TEMP_V25) / CORE_TEMP_AVG_SLOPE) + 25;
}
float adc_read_core_vbat()
{
int timeout = 10000;
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
/* Note: sample time must be higher than minimum sample time */
ADC_RegularChannelConfig(ADCx, ADC_VBAT_CHANNEL, 1, ADC_SampleTime_144Cycles);
/* Start ADC single conversion */
ADC_SoftwareStartConv(ADCx);
/* Wait for conversion to be complete */
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
}
/* ADC conversion timed out */
if (timeout == 0) {
return 0;
}
/* Convert ADC reading to voltage, VBAT pin is
internally connected to a bridge divider by VBAT_DIV */
return ADC_GetConversionValue(ADCx)*VBAT_DIV/4096.0f*3.3f;
}
float adc_read_core_vref()
{
int timeout = 10000;
/* ADC VBAT channel config ADC/Channel/SEQ Rank/Sample time */
/* Note: sample time must be higher than minimum sample time */
ADC_RegularChannelConfig(ADCx, ADC_VREF_CHANNEL, 1, ADC_SampleTime_112Cycles);
/* Start ADC single conversion */
ADC_SoftwareStartConv(ADCx);
/* Wait for conversion to be complete*/
while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) {
}
/* ADC conversion timed out */
if (timeout == 0) {
return 0;
}
/* Convert ADC reading to voltage */
return ADC_GetConversionValue(ADCx)/4096.0f*3.3f;
}
/******************************************************************************/
/* Micro Python bindings : adc_all object */
typedef struct _pyb_obj_adc_all_t {
mp_obj_base_t base;
bool is_enabled;
} pyb_obj_adc_all_t;
static void adc_all_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
print(env, "<ADC all>");
}
static mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
pyb_obj_adc_all_t *self = self_in;
if (self->is_enabled) {
uint32_t chan = mp_obj_get_int(channel);
uint32_t data = adc_read_channel(chan);
return mp_obj_new_int(data);
} else {
return mp_const_none;
}
}
static mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
pyb_obj_adc_all_t *self = self_in;
if (self->is_enabled) {
int data = adc_read_core_temp();
return mp_obj_new_int(data);
} else {
return mp_const_none;
}
}
static mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
pyb_obj_adc_all_t *self = self_in;
if (self->is_enabled) {
float data = adc_read_core_vbat();
return mp_obj_new_float(data);
} else {
return mp_const_none;
}
}
static mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
pyb_obj_adc_all_t *self = self_in;
if (self->is_enabled) {
float data = adc_read_core_vref();
return mp_obj_new_float(data);
} else {
return mp_const_none;
}
}
static MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_channel), (mp_obj_t) &adc_all_read_channel_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_temp), (mp_obj_t)&adc_all_read_core_temp_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vbat), (mp_obj_t)&adc_all_read_core_vbat_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vref), (mp_obj_t)&adc_all_read_core_vref_obj},
};
STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
static const mp_obj_type_t adc_all_type = {
{ &mp_type_type },
.name = MP_QSTR_ADC,
.print = adc_all_print,
.locals_dict = (mp_obj_t)&adc_all_locals_dict,
};
mp_obj_t pyb_ADC_all(mp_obj_t resolution) {
/* init ADC */
adc_init_all(mp_obj_get_int(resolution));
pyb_obj_adc_all_t *o = m_new_obj(pyb_obj_adc_all_t);
o->base.type = &adc_all_type;
o->is_enabled = true;
return o;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_all_obj, pyb_ADC_all);
/******************************************************************************/
/* Micro Python bindings : adc object (single channel) */
typedef struct _pyb_obj_adc_t {
mp_obj_base_t base;
mp_obj_t pin_name;
int channel;
bool is_enabled;
} pyb_obj_adc_t;
static void adc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_obj_adc_t *self = self_in;
print(env, "<ADC on ");
mp_obj_print_helper(print, env, self->pin_name, PRINT_STR);
print(env, " channel=%lu>", self->channel);
}
static mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
if (self->is_enabled) {
uint32_t data = adc_read_channel(self->channel);
return mp_obj_new_int(data);
} else {
return mp_const_none;
}
}
static MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
static const mp_obj_type_t adc_type = {
{ &mp_type_type },
.name = MP_QSTR_ADC,
.print = adc_print,
.locals_dict = (mp_obj_t)&adc_locals_dict,
};
mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) {
pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
o->base.type = &adc_type;
o->pin_name = pin_name_obj;
// work out the channel from the pin name
const char *pin_name = mp_obj_str_get_str(pin_name_obj);
GPIO_TypeDef *port;
switch (pin_name[0]) {
case 'A': case 'a': port = GPIOA; break;
case 'B': case 'b': port = GPIOB; break;
case 'C': case 'c': port = GPIOC; break;
default: goto pin_error;
}
uint pin_num = 0;
for (const char *s = pin_name + 1; *s; s++) {
if (!('0' <= *s && *s <= '9')) {
goto pin_error;
}
pin_num = 10 * pin_num + *s - '0';
}
if (!(0 <= pin_num && pin_num <= 15)) {
goto pin_error;
}
int i;
for (i = 0; i < ADC_NUM_CHANNELS; i++) {
if (adc_gpio[i].port == port && adc_gpio[i].pin == (1 << pin_num)) {
o->channel = i;
break;
}
}
if (i == ADC_NUM_CHANNELS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin_name));
}
// init ADC just for this channel
adc_init_single(o->channel);
o->is_enabled = true;
return o;
pin_error:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not exist", pin_name));
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_obj, pyb_ADC);

View File

@@ -1,2 +0,0 @@
MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_all_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_obj);

View File

@@ -1,256 +0,0 @@
#include <stdint.h>
#include <string.h>
#include "stm32f4xx_dac.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "parse.h"
#include "obj.h"
#include "runtime.h"
#include "audio.h"
STATIC void TIM7_Config(uint freq) {
// TIM7 clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
// reset TIM7
TIM_DeInit(TIM7);
// Compute the prescaler value so TIM7 triggers at freq-Hz
uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1;
// Time base configuration
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = period; // timer triggers with this period
TIM_TimeBaseStructure.TIM_Prescaler = 0; // timer runs at SystemCoreClock / 2
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // unused for TIM7
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // unused for TIM7
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
// TIM7 TRGO selection
TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);
// TIM7 enable counter
TIM_Cmd(TIM7, ENABLE);
}
/******************************************************************************/
// Micro Python bindings
typedef struct _pyb_audio_t {
mp_obj_base_t base;
uint dac_channel; // DAC_Channel_1 or DAC_Channel_2
DMA_Stream_TypeDef *dma_stream; // DMA1_Stream6 or DMA1_Stream7
} pyb_audio_t;
mp_obj_t pyb_audio_noise(mp_obj_t self_in, mp_obj_t freq) {
pyb_audio_t *self = self_in;
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config(mp_obj_get_int(freq));
DAC_Cmd(self->dac_channel, DISABLE);
DAC_InitTypeDef DAC_InitStructure;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Noise;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits10_0;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(self->dac_channel, &DAC_InitStructure);
DAC_Cmd(self->dac_channel, ENABLE);
if (self->dac_channel == DAC_Channel_1) {
DAC_SetChannel1Data(DAC_Align_12b_L, 0x7ff0);
} else {
DAC_SetChannel2Data(DAC_Align_12b_L, 0x7ff0);
}
return mp_const_none;
}
mp_obj_t pyb_audio_triangle(mp_obj_t self_in, mp_obj_t freq) {
pyb_audio_t *self = self_in;
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config(mp_obj_get_int(freq));
DAC_Cmd(self->dac_channel, DISABLE);
DAC_InitTypeDef DAC_InitStructure;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(self->dac_channel, &DAC_InitStructure);
DAC_Cmd(self->dac_channel, ENABLE);
// set base value of triangle wave
if (self->dac_channel == DAC_Channel_1) {
DAC_SetChannel1Data(DAC_Align_12b_R, 0x100);
} else {
DAC_SetChannel2Data(DAC_Align_12b_R, 0x100);
}
return mp_const_none;
}
// direct access to DAC
mp_obj_t pyb_audio_dac(mp_obj_t self_in, mp_obj_t val) {
pyb_audio_t *self = self_in;
if (self->dac_channel == DAC_Channel_1) {
DAC_SetChannel1Data(DAC_Align_8b_R, mp_obj_get_int(val));
} else {
DAC_SetChannel2Data(DAC_Align_8b_R, mp_obj_get_int(val));
}
return mp_const_none;
}
#define DAC_DHR8R1_ADDRESS (DAC_BASE + 0x10)
#define DAC_DHR8R2_ADDRESS (DAC_BASE + 0x1c)
// initiates a burst of RAM->DAC using DMA
// input data is treated as an array of bytes (8 bit data)
// TIM7 is used to set the frequency of the transfer
mp_obj_t pyb_audio_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_audio_t *self = args[0];
// set TIM7 to trigger the DAC at the given frequency
TIM7_Config(mp_obj_get_int(args[2]));
mp_obj_type_t *type = mp_obj_get_type(args[1]);
if (type->buffer_p.get_buffer == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol"));
}
mp_buffer_info_t bufinfo;
type->buffer_p.get_buffer(args[1], &bufinfo, MP_BUFFER_READ);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_Cmd(self->dma_stream, DISABLE);
while (DMA_GetCmdStatus(self->dma_stream) != DISABLE) {
}
DAC_Cmd(self->dac_channel, DISABLE);
// DAC channel configuration
DAC_InitTypeDef DAC_InitStructure;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1; // unused, but need to set it to a valid value
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(self->dac_channel, &DAC_InitStructure);
// DMA1_Stream[67] channel7 configuration
DMA_DeInit(self->dma_stream);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
if (self->dac_channel == DAC_Channel_1) {
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_ADDRESS;
} else {
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R2_ADDRESS;
}
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)bufinfo.buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = bufinfo.len;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
mp_map_elem_t *kw_mode = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("mode")), MP_MAP_LOOKUP);
DMA_InitStructure.DMA_Mode = kw_mode == NULL ? DMA_Mode_Normal : mp_obj_get_int(kw_mode->value); // normal = 0, circular = 0x100
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(self->dma_stream, &DMA_InitStructure);
// enable DMA stream
DMA_Cmd(self->dma_stream, ENABLE);
while (DMA_GetCmdStatus(self->dma_stream) == DISABLE) {
}
// enable DAC channel
DAC_Cmd(self->dac_channel, ENABLE);
// enable DMA for DAC channel
DAC_DMACmd(self->dac_channel, ENABLE);
//printf("DMA: %p %lu\n", bufinfo.buf, bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_noise_obj, pyb_audio_noise);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_triangle_obj, pyb_audio_triangle);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_dac_obj, pyb_audio_dac);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_audio_dma_obj, 3, pyb_audio_dma);
STATIC const mp_map_elem_t pyb_audio_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_audio_noise_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_triangle), (mp_obj_t)&pyb_audio_triangle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dac), (mp_obj_t)&pyb_audio_dac_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dma), (mp_obj_t)&pyb_audio_dma_obj },
};
STATIC MP_DEFINE_CONST_DICT(pyb_audio_locals_dict, pyb_audio_locals_dict_table);
STATIC const mp_obj_type_t pyb_audio_type = {
{ &mp_type_type },
.name = MP_QSTR_,
.locals_dict = (mp_obj_t)&pyb_audio_locals_dict,
};
STATIC const pyb_audio_t pyb_audio_channel_1 = {{&pyb_audio_type}, DAC_Channel_1, DMA1_Stream5};
STATIC const pyb_audio_t pyb_audio_channel_2 = {{&pyb_audio_type}, DAC_Channel_2, DMA1_Stream6};
// create the audio object
// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
STATIC mp_obj_t pyb_Audio(mp_obj_t id) {
// DAC peripheral clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
int dac_id = mp_obj_get_int(id);
uint pin;
const pyb_audio_t *dac_obj;
if (dac_id == 1) {
pin = GPIO_Pin_4;
dac_obj = &pyb_audio_channel_1;
} else {
pin = GPIO_Pin_5;
dac_obj = &pyb_audio_channel_2;
}
// DAC channel configuration
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// DAC channel Configuration
DAC_InitTypeDef DAC_InitStructure;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(dac_obj->dac_channel, &DAC_InitStructure);
// Enable DAC Channel
DAC_Cmd(dac_obj->dac_channel, ENABLE);
// from now on use DAC_SetChannel[12]Data to trigger a conversion
// return static object
return (mp_obj_t)dac_obj;
}
MP_DEFINE_CONST_FUN_OBJ_1(pyb_Audio_obj, pyb_Audio);

View File

@@ -1 +0,0 @@
MP_DECLARE_CONST_FUN_OBJ(pyb_Audio_obj);

View File

@@ -1,38 +0,0 @@
#define NETDUINO_PLUS_2
#define MICROPY_HW_BOARD_NAME "NetduinoPlus2"
#define MICROPY_HW_HAS_SWITCH (1)
// On the netuino, the sdcard appears to be wired up as a 1-bit
// SPI, so the driver needs to be converted to support that before
// we can turn this on.
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_HAS_WLAN (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (0)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_AUDIO (0)
// USRSW is pulled low. Pressing the button makes the input go high.
#define USRSW_PIN (pin_B11)
#define USRSW_PUPD (GPIO_PuPd_NOPULL)
#define USRSW_EXTI_EDGE (EXTI_Trigger_Rising)
#define USRSW_PRESSED (1)
/* LED */
#define PYB_LED1 (pin_A10) // Blue LED
#define PYB_LED2 (pin_C13) // White LED (aka Power)
#define PYB_LED3 (pin_A10) // Same as Led(1)
#define PYB_LED4 (pin_C13) // Same as Led(2)
#define PYB_OTYPE (GPIO_OType_PP)
#define PYB_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define PYB_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
#define HSE_VALUE (25000000)

View File

@@ -1,28 +0,0 @@
D0,PC7
D1,PC6
D2,PA3
D3,PA2
D4,PB12
D5,PB8
D6,PB9
D7,PA1
D8,PA0
D9,PA6
D10,PB10
D11,PB15
D12,PB14
D13,PB13
A0,PC0
A1,PC1
A2,PC2
A3,PC3
A4,PC4
A5,PC5
LED,PA10
SW,PB11
PWR_LED,PC13
PWR_SD,PB1
PWR_HDR,PB2
PWR_ETH,PC15
RST_ETH,PD2
1 D0 PC7
2 D1 PC6
3 D2 PA3
4 D3 PA2
5 D4 PB12
6 D5 PB8
7 D6 PB9
8 D7 PA1
9 D8 PA0
10 D9 PA6
11 D10 PB10
12 D11 PB15
13 D12 PB14
14 D13 PB13
15 A0 PC0
16 A1 PC1
17 A2 PC2
18 A3 PC3
19 A4 PC4
20 A5 PC5
21 LED PA10
22 SW PB11
23 PWR_LED PC13
24 PWR_SD PB1
25 PWR_HDR PB2
26 PWR_ETH PC15
27 RST_ETH PD2

View File

@@ -1,32 +0,0 @@
#define PYBOARD3
#define MICROPY_HW_BOARD_NAME "PYBv3"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_HAS_WLAN (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_AUDIO (0)
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define USRSW_PIN (pin_A13)
#define USRSW_PUPD (GPIO_PuPd_UP)
#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling)
#define USRSW_PRESSED (0)
/* LED */
#define PYB_LED1 (pin_A8) // R1 - red
#define PYB_LED2 (pin_A10) // R2 - red
#define PYB_LED3 (pin_C4) // G1 - green
#define PYB_LED4 (pin_C5) // G2 - green
#define PYB_OTYPE (GPIO_OType_PP)
#define PYB_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask)
#define PYB_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask)

View File

@@ -1,37 +0,0 @@
B13,PB13
B14,PB14
B15,PB15
C6,PC6
C7,PC7
A13,PA13
A14,PA14
A15,PA15
B3,PB3
B4,PB4
B6,PB6
B7,PB7
B8,PB8
B9,PB9
C0,PC0
C1,PC1
C2,PC2
C3,PC3
A0,PA0
A1,PA1
A2,PA2
A3,PA3
A4,PA4
A5,PA5
A6,PA6
A7,PA7
B0,PB0
B1,PB1
B10,PB10
B11,PB11
B12,PB12
LED_R1,PA8
LED_R2,PA10
LED_G1,PC4
LED_G2,PC5
SW,PA13
1 B13 PB13
2 B14 PB14
3 B15 PB15
4 C6 PC6
5 C7 PC7
6 A13 PA13
7 A14 PA14
8 A15 PA15
9 B3 PB3
10 B4 PB4
11 B6 PB6
12 B7 PB7
13 B8 PB8
14 B9 PB9
15 C0 PC0
16 C1 PC1
17 C2 PC2
18 C3 PC3
19 A0 PA0
20 A1 PA1
21 A2 PA2
22 A3 PA3
23 A4 PA4
24 A5 PA5
25 A6 PA6
26 A7 PA7
27 B0 PB0
28 B1 PB1
29 B10 PB10
30 B11 PB11
31 B12 PB12
32 LED_R1 PA8
33 LED_R2 PA10
34 LED_G1 PC4
35 LED_G2 PC5
36 SW PA13

View File

@@ -1,33 +0,0 @@
#define PYBOARD4
#define MICROPY_HW_BOARD_NAME "PYBv4"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (1)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (1)
#define MICROPY_HW_HAS_WLAN (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_AUDIO (1)
// USRSW has no pullup or pulldown, and pressing the switch makes the input go low
#define USRSW_PIN (pin_B3)
#define USRSW_PUPD (GPIO_PuPd_UP)
#define USRSW_EXTI_EDGE (EXTI_Trigger_Falling)
#define USRSW_PRESSED (0)
/* LED */
#define PYB_LED1 (pin_A13) // red
#define PYB_LED2 (pin_A14) // green
#define PYB_LED3 (pin_A15) // yellow
#define PYB_LED4 (pin_B4) // blue
#define PYB_OTYPE (GPIO_OType_PP)
#define PYB_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define PYB_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)

View File

@@ -1,45 +0,0 @@
X1,PA0
X2,PA1
X3,PA2
X4,PA3
X5,PA4
X6,PA5
X7,PA6
X8,PA7
X9,PB6
X10,PB7
X11,PC4
X12,PC5
X13,Reset
X14,GND
X15,3.3V
X16,VIN
X17,PB3
X18,PC13
X19,PC0
X20,PC1
X21,PC2
X22,PC3
X23,A3.3V
X24,AGND
Y1,PC6
Y2,PC7
Y3,PB8
Y4,PB9
Y5,PB12
Y6,PB13
Y7,PB14
Y8,PB15
Y9,PB10
Y10,PB11
Y11,PB0
Y12,PB1
Y13,Reset
Y14,GND
Y15,3.3V
Y16,VIN
LED_BLUE,PB4
LED_RED,PA13
LED_GREEN,PA14
LED_YELLOW,PA15
SW,PB3
1 X1 PA0
2 X2 PA1
3 X3 PA2
4 X4 PA3
5 X5 PA4
6 X6 PA5
7 X7 PA6
8 X8 PA7
9 X9 PB6
10 X10 PB7
11 X11 PC4
12 X12 PC5
13 X13 Reset
14 X14 GND
15 X15 3.3V
16 X16 VIN
17 X17 PB3
18 X18 PC13
19 X19 PC0
20 X20 PC1
21 X21 PC2
22 X22 PC3
23 X23 A3.3V
24 X24 AGND
25 Y1 PC6
26 Y2 PC7
27 Y3 PB8
28 Y4 PB9
29 Y5 PB12
30 Y6 PB13
31 Y7 PB14
32 Y8 PB15
33 Y9 PB10
34 Y10 PB11
35 Y11 PB0
36 Y12 PB1
37 Y13 Reset
38 Y14 GND
39 Y15 3.3V
40 Y16 VIN
41 LED_BLUE PB4
42 LED_RED PA13
43 LED_GREEN PA14
44 LED_YELLOW PA15
45 SW PB3

Some files were not shown because too many files have changed in this diff Show More