Compare commits

..

342 Commits
v1.1 ... v1.3.1

Author SHA1 Message Date
Damien George
110ba35980 py: Move native glue code from runtime.c to new file nativeglue.c.
This way, the native glue code is only compiled if native code is
enabled (which makes complete sense; thanks to Paul Sokolovsky for
the idea).

Should fix issue #834.
2014-08-28 23:37:02 +01:00
Damien George
1ac6faa732 Merge pull request #833 from Vogtinator/arm-native
Basic native ARM emitter
2014-08-28 23:24:43 +01:00
Damien George
516b09efc3 py, gc: Further reduce heap fragmentation with new, faster gc alloc.
The heap allocation is now exactly as it was before the "faster gc
alloc" patch, but it's still nearly as fast.  It is fixed by being
careful to always update the "last free block" pointer whenever the heap
changes (eg free or realloc).

Tested on all tests by enabling EXTENSIVE_HEAP_PROFILING in py/gc.c:
old and new allocator have exactly the same behaviour, just the new one
is much faster.
2014-08-28 23:06:38 +01:00
Damien George
b796e3d848 py: Reduce fragmentation of GC heap.
Recent speed up of GC allocation made the GC have a fragmented heap.
This patch restores "original fragmentation behaviour" whilst still
retaining relatively fast allocation.  This patch works because there is
always going to be a single block allocated now and then, which advances
the gc_last_free_atb_index pointer often enough so that the whole heap
doesn't need scanning.

Should address issue #836.
2014-08-28 10:18:40 +01:00
Fabian Vogt
16ee30c6fa Clarify copyright on asmarm files 2014-08-28 01:18:56 +02:00
Fabian Vogt
fe3d16e8c2 Basic native ARM emitter 2014-08-27 18:18:50 +02:00
Damien George
a97e091d4e Merge branch 'dhylands-int-bytes' 2014-08-27 09:21:41 +01:00
Damien George
a75b02ea9b py: Improve efficiency of MP_OBJ_IS_STR_OR_BYTES.
Saves ROM (16 on stmhal, 240 on 64-bit unix) and should be quicker since
there is 1 less branch.
2014-08-27 09:20:30 +01:00
Damien George
ad4c014d46 Merge branch 'int-bytes' of https://github.com/dhylands/micropython into dhylands-int-bytes 2014-08-27 09:13:15 +01:00
Dave Hylands
b7f7c655ed Make int(b'123') work properly. 2014-08-26 19:15:04 -07:00
Paul Sokolovsky
f3c3010ffc pip-micropython: Revert to using PIP_MICROPY_DEST environment var.
-t/--target is a pip option. Trying to use pip options for different meanings
in pip-micropython may lead to big confusion. That's why the original passed
any extra parameters using environment variables. "All options belong to pip."
2014-08-27 02:53:06 +03:00
Damien George
b427d6ae86 py: Fix line number printing for file with 1 line.
With a file with 1 line (and an error on that line), used to show the
line as number 0.  Now shows it correctly as line number 1.

But, when line numbers are disabled, it now prints line number 1 for any
line that has an error (instead of 0 as previously).  This might end up
being confusing, but requires extra RAM and/or hack logic to make it
print something special in the case of no line numbers.
2014-08-26 23:35:57 +01:00
Damien George
f05b87bd63 Merge pull request #824 from dhylands/sdcard-power
Fix sdcard_power_on to not do anything if the card is already powered on...
2014-08-26 22:58:54 +01:00
Damien George
3b72da674e stmhal, STM32F4DISC: Small changes to ST accel driver. 2014-08-26 22:41:27 +01:00
Damien George
6cf8dd4f51 Merge branch 'siorpaes-master' 2014-08-26 17:31:21 +01:00
Damien George
e00fb08f99 stmhal, staccel.py: Style cleanup. 2014-08-26 17:30:48 +01:00
David Siorpaes
f4ce26de5c Added LIS302DL ID check 2014-08-26 18:23:00 +02:00
Damien George
db63660c19 Add pip-micropython to unix make install.
Also add -t/--target option to pip-micropython to allowing installing to
the pyboard.

Thanks to turbinenreiter/Sebastian Plamauer for the patch.
2014-08-26 16:03:57 +01:00
Damien George
3bb7efc943 stmhal: Hookup USB_VCP.any().
Thanks to Dave Hylands for this patch.
2014-08-26 14:18:22 +01:00
Damien George
cd021bfe56 stmhal: Fix build issues with (old) CC3000 driver.
Addresses issue #825.
2014-08-26 14:13:53 +01:00
Damien George
779794a680 py: Add dispatch for user defined ==, >, <=, >=.
Addresses issue #827.
2014-08-26 09:31:26 +01:00
Damien George
fa1a9bc9fd tests: Add test for pyb.disable_irq and pyb.enable_irq. 2014-08-25 18:44:10 +01:00
Dave Hylands
994bb4a839 Fix sdcard_power_on to not do anything if the card is already powered on. 2014-08-25 10:16:52 -07:00
Damien George
34e43c7ee9 stmhal: Improve efficiency of SysTick IRQ and HAL_Delay.
SysTick IRQ now increases millisecond counter directly (ie without
calling HAL_IncTick).  Provide our own version of HAL_Delay that does a
wfi while waiting.  This more than halves power consumption when running
a loop containing a pyb.delay call.  It used to be like this, but new
version of HAL library regressed this feature.
2014-08-25 18:12:44 +01:00
Damien George
3475b04101 teensy: Fix multiple definition of irq functions. 2014-08-25 18:12:23 +01:00
Damien George
29c92a407c stmhal: Use MP_OBJ_NEW_SMALL_INT directly in pyb.micros/millis.
Also some whitespace cleanup.
2014-08-25 17:38:55 +01:00
Dave Hylands
2bf044442e Add support for pyb.micros() by using the systick timer.
I also removed trailing spaces from modpyb.c which affected a couple
of lines technically not part of this patch.

Tested using: https://github.com/dhylands/upy-examples/blob/master/micros_test.py

which eventually fails due to wraparound issues (I could fix the test to compensate
but didn't bother)
2014-08-25 17:38:55 +01:00
Dave Hylands
8c0add4eee Add save/restore_irq
Factored irq functions into a separate file.
2014-08-25 17:38:55 +01:00
Damien George
e5cbb70328 stmhal: Make enable_irq and disable_irq inline functions.
These functions are generally 1 machine instruction, and are used in
critical code, so makes sense to have them inline.

Also leave these functions uninverted (ie 0 means enable, 1 means
disable) and provide macro constants if you really need to distinguish
the states.  This makes for smaller code as well (combined with
inlining).

Applied to teensy port as well.
2014-08-25 13:24:33 +01:00
Dave Hylands
9480138f0c Add save/restore_irq
Factored irq functions into a separate file.
2014-08-25 12:22:11 +01:00
Damien George
7310fd469a py: Consolidate min/max functions into one, and add key= argument.
Addresses issue #811.
2014-08-24 19:14:09 +01:00
Damien George
1d8a06406a examples: Added pins.py example script to list pin config/af.
Script is due to Dave Hylands.
2014-08-24 18:34:38 +01:00
Damien George
2c4e67e32d stmhal, pin: Update documentation. 2014-08-24 18:30:22 +01:00
Dave Hylands
3d945559d4 Added python script to map AF to a pin name
Added some functions to Pin class to query mode, pull, and af
2014-08-24 18:21:08 +01:00
Damien George
c668d51b08 Merge branch 'dhylands-localtime' 2014-08-24 17:41:31 +01:00
Damien George
8ba832456e stmhal, modtime: Small changes, reduced code size by around 80 bytes.
Also added test for modtime.
2014-08-24 17:40:24 +01:00
Dave Hylands
6678595e7e Add time.mktime and enhance time.localtime (for stmhal)
Now you can use time.localtime on the timestamps presented by os.stat
2014-08-24 17:00:03 +01:00
Damien George
3c658a4e75 py: Fix bug where GC collected native/viper/asm function data.
Because (for Thumb) a function pointer has the LSB set, pointers to
dynamic functions in RAM (eg native, viper or asm functions) were not
being traced by the GC.  This patch is a comprehensive fix for this.

Addresses issue #820.
2014-08-24 16:28:17 +01:00
Damien George
25fc41dd31 unix, modtermios: Make it properly configurable; fix spelling mistake. 2014-08-24 13:19:22 +01:00
Paul Sokolovsky
4f9ebade60 modtermios: Add "termios" unix module, subset of CPython's.
Also provides setraw() function from "tty" module (which in CPython is
implemented in Python). The idea here is that 95% of "termios" module usage
is to set raw mode to allow access to normal serial devices. Then, instead
of exporting gazillion termios symbols, it's better to implement it in C,
and export minimal number of symbols (mostly baud rates and drain values).
2014-08-23 06:09:46 +03:00
Damien George
72b115cbaa extmod, zlibd: Make some simple ROM and RAM savings.
ROM down by 320 bytes on stmhal.  RAM down by 5.5k for a decompression
object.
2014-08-22 18:38:16 +01:00
Damien George
26a0d4f4f1 py: Change hash and len members of str from 16 bit to full word.
This allows to make strings longer than 64k.  It doesn't use any more
RAM with current GC because a str object still fits in a GC block.
2014-08-22 18:34:28 +01:00
Damien George
69b7dae362 py: Small cleanup in stream.c. 2014-08-22 18:30:02 +01:00
Damien George
d5e7f6e37e py: Speed up GC allocation.
This simple patch gives a very significant speed up for memory allocation
with the GC.

Eg, on PYBv1.0:
tests/basics/dict_del.py: 3.55 seconds -> 1.19 seconds
tests/misc/rge_sm.py:     15.3 seconds -> 2.48 seconds
2014-08-22 18:17:02 +01:00
Paul Sokolovsky
13ec400f28 Merge pull request #796 from turbinenreiter/makeinstall
unix: Added install/uninstall
2014-08-18 22:29:37 +03:00
Damien George
7fe2191c9b py: Code clean-up in native emitter; improve thumb native calls. 2014-08-16 22:31:57 +01:00
Damien George
86de21b810 py: Viper can call functions with native types, and raise exceptions. 2014-08-16 22:06:11 +01:00
Damien George
339bdccc58 Merge pull request #803 from dhylands/ld-opt
Put some code into the first 16K of flash
2014-08-16 16:09:39 +01:00
Dave Hylands
3688414d9d Put some code into the first 16K of flash
This basically shrinks the remaining size of flash in the portion
that goes after the internal flash drive.
2014-08-16 08:00:12 -07:00
Damien George
8f81b5cb4b py: Put SystemExit in builtin namespace.
Also fix unix port so that SystemExit with no arg exits with value 0.
2014-08-16 14:32:06 +01:00
Damien George
b63be37be1 stmhal: In safe mode, still mount SD card and present as MSD over USB.
It's still "safe" because no scripts are run.  Remove the SD card if you
want to access the internal flash filesystem.  Addresses issue #616.

Also: remove obsolete pyb.source_dir setting, and reset pyb.main and
pyb.usb_mode settings on soft-reset.
2014-08-16 14:23:22 +01:00
Damien George
b0accc8571 stmhal: Fix printing of pin name in error message. 2014-08-16 13:56:19 +01:00
Damien George
d779b9642f tests: Wait for just over 1 sec when testing RTC.
Waiting for 1000ms between seconds of RTC is sometimes too quick.
Waiting for 1001ms is enough for the RTC to pass 1 second.
2014-08-16 13:39:14 +01:00
Damien George
244476e3e6 stmhal: For non-debug compile, enable CC/LD opt to remove dead code.
Saves over 35k ROM due to elimination of unused HAL functions.  All
tests pass.

Addresses issue #702.
2014-08-16 13:37:05 +01:00
Damien George
c84aa41990 Merge branch 'danpeirce-master' 2014-08-16 11:56:16 +01:00
Dan Peirce
f0c3a7e781 teensy/README.md (corrected typo) 2014-08-16 11:54:36 +01:00
Dan Peirce
6009309c33 modified: teensy/README.md
Updated teensy/README.md to reflect change in build process (teensyduino is no
longer required for build).
2014-08-16 11:54:36 +01:00
Damien George
e6c0dff967 py: Viper can now store to global. 2014-08-15 23:47:59 +01:00
Damien George
a5190a7dac py: Fix typing of viper locals; allow default types in annotation. 2014-08-15 22:39:08 +01:00
Damien George
2ac4af6946 py: Allow viper to have type annotations.
Viper functions can now be annotated with the type of their arguments
and return value.  Eg:

@micropython.viper
def f(x:int) -> int:
    return x + 1
2014-08-15 16:45:41 +01:00
Damien George
6be0b0a8ec py: Clean up and simplify functions in scope; add STATIC in compiler.
Some small code clean-ups that result in about 80 bytes ROM saving for
stmhal.
2014-08-15 14:30:52 +01:00
Damien George
bf133f7737 stmhal: Resolve question in comment about timer clock. 2014-08-14 00:30:14 +01:00
Damien George
2c781eabbd Merge pull request #798 from stinos/msvc-alignof
msvc: Use built-in alignof
2014-08-13 13:34:41 +01:00
Damien George
9b7a8ee8f1 py: Fix mult by negative number of tuple, list, str, bytes.
Multiplication of a tuple, list, str or bytes now yields an empty
sequence (instead of crashing).  Addresses issue #799

Also added ability to mult bytes on LHS by integer.
2014-08-13 13:22:24 +01:00
stijn
8cce8b7c4c msvc: Use built-in alignof
This also fixes a 'unnamed type definition in parentheses' warning on the
alignof implementation define in binary.c
2014-08-13 10:19:56 +02:00
Damien George
9d02780eaf Merge branch 'pfalcon-modzlibd' 2014-08-12 23:24:29 +01:00
Damien George
1ddd844815 extmod: Finish rename of zlib to zlibd; enable zlibd on stmhal. 2014-08-12 23:23:53 +01:00
Paul Sokolovsky
5073d3da07 tests: Add test for zlibd module. 2014-08-13 00:26:26 +03:00
Paul Sokolovsky
8882c20b8f modzlibd: Add tinfl.c from miniz SVN repo, r63.
The only change is line-ending convesion to LF.
2014-08-13 00:26:19 +03:00
Paul Sokolovsky
510296f25a modzlibd: Decompress part of "zlib" module, based on miniz tinfl.c . 2014-08-13 00:26:19 +03:00
Damien George
75ec22bf11 py: #if guard qstrs that are optional.
Also disable gc module on bare-arm port.
2014-08-12 20:16:03 +01:00
Damien George
105e32f1a5 stmhal: Enable moductypes by default.
Also fixes compiler error in moductypes when compiled without debugging.

Addresses issue #778.
2014-08-12 20:02:26 +01:00
Damien George
f20375eedd py: Add .real and .imag attributes to complex numbers. 2014-08-12 19:57:52 +01:00
Damien George
bb91f1195a py: Improve range: add len, subscr, proper print.
Can now index ranges with integers and slices, and reverse ranges
(although reversing is not very efficient).

Not sure how useful this stuff is, but gets us closer to having all of
Python's builtins.
2014-08-12 19:41:18 +01:00
Damien George
4c03b3a899 py: Implement builtin reversed() function.
reversed function now implemented, and works for tuple, list, str, bytes
and user objects with __len__ and __getitem__.

Renamed mp_builtin_len to mp_obj_len to make it publically available (eg
for reversed).
2014-08-12 18:33:40 +01:00
Damien George
69c5fe1df6 py: Make a function static; replace NULL with MP_OBJ_NULL. 2014-08-12 18:13:44 +01:00
Damien George
2eb1f604ee py, objstr: Optimise bytes subscr when unicode is enabled.
Saves code bytes and makes it faster, so why not?
2014-08-11 23:24:29 +01:00
Damien George
7703d71938 py, modcmath: Fix doc comment, and add some more of them. 2014-08-11 22:19:44 +00:00
Paul Sokolovsky
9749b2fb0d objstr: Make sure that bytes are indexed as bytes, not as unicode.
Fixes #795.
2014-08-11 22:38:00 +03:00
Sebastian Plamauer
2eeeafcba5 added install/uninstall 2014-08-11 19:47:00 +02:00
Damien George
6e6bcccdc1 Merge branch 'master' of github.com:micropython/micropython 2014-08-10 22:27:52 +01:00
Damien George
101d87da6a stmhal: Working STM32F4DISC accelerometer, via Python script.
Thanks to David Siorpaes.
2014-08-10 22:26:20 +01:00
Paul Sokolovsky
0c5498540b objstr: split(): check arg type consistency (str vs bytes).
Similar to other methods and following CPython3 strictness.
2014-08-10 23:21:16 +03:00
Paul Sokolovsky
ecca53bd34 py: binary.c: Properly implement alignment for native unpacked structs. 2014-08-10 23:21:08 +03:00
Paul Sokolovsky
2831a8f800 modsocket: .recv() returns bytes object. 2014-08-10 21:24:47 +03:00
Damien George
4ef26c14b1 doc: Fix up a few docs in sys module. 2014-08-10 17:53:43 +01:00
Damien George
30dd23aa7f doc: Document gc, sys, math, cmath. 2014-08-10 17:50:28 +01:00
Damien George
0c64c634ca stmhal: Add sys.platform string to PYBv1.0 (it's "pyboard"). 2014-08-10 17:49:52 +01:00
Damien George
c4ee39dd63 tools, gendoc: Output small descr about module TOC. 2014-08-10 16:51:26 +01:00
Paul Sokolovsky
5f930337bc objarray: Implement equality testing between arrays and other buffers. 2014-08-10 16:22:57 +03:00
Paul Sokolovsky
7133d91773 py: mp_buffer_info_t::buf may be valid, but NULL for empty objects.
This happens for example for zero-size arrays. As .get_buffer() method now
has explicit return value, it's enough to distinguish success vs failure
of getting buffer.
2014-08-10 16:22:48 +03:00
Paul Sokolovsky
5f47ebbf82 moductypes: Remove debug inclusion of stdio.h . 2014-08-10 10:11:22 +03:00
Damien George
2605df3346 stmhal, pin: Save 140 bytes ROM by simplifying pin_print function. 2014-08-09 09:19:37 +01:00
Damien George
04019e365f stmhal, pin: Simplify default value for alternate function init. 2014-08-09 08:51:12 +01:00
Damien George
590b2abdfc tools, gendoc: Put module TOC/index in module/ directory. 2014-08-08 23:34:39 +01:00
Damien George
ea439e59d9 stmhal: Start of documentation for modos and modtime. 2014-08-08 23:30:01 +01:00
Damien George
ef7a066c9c tools, gendoc: Allow constants at module level; gen module index.
Addresses some issues from #585.
2014-08-08 23:29:05 +01:00
Damien George
4162271181 Merge branch 'dhylands-pin-af' 2014-08-08 22:41:06 +01:00
Damien George
b92e7533d3 tests, pyb: Update pin test. 2014-08-08 22:38:58 +01:00
Damien George
284efa89ae stmhal/teensy: Use _ instead of - in source file names.
Trying to move towards consistency, let's use _ exclusively in names of
source files (eg .c, .h, .csv).
2014-08-08 22:34:06 +01:00
Damien George
4b67463be1 stmhal: Fix documentation; remove ability to specify af by str. 2014-08-08 22:26:53 +01:00
Damien George
5b7c0c437b stmhal: Comment out unused functions. 2014-08-08 22:25:46 +01:00
Damien George
196773505a Merge branch 'pin-af' of https://github.com/dhylands/micropython into dhylands-pin-af 2014-08-08 19:42:07 +01:00
Damien George
a1d3ee376c py: Fix bug where GC finaliser table was not completely zeroed out.
This was a nasty bug to track down.  It only had consequences when the
heap size was just the right size to expose the rounding error in the
calculation of the finaliser table size.  And, a script had to allocate
a small (1 or 2 cell) object at the very end of the heap.  And, this
object must not have a finaliser.  And, the initial state of the heap
must have been all bits set to 1.  All these conspire on the pyboard,
but only if your run the script fresh (so unused memory is all 1's),
and if your script allocates a lot of small objects (eg 2-char strings
that are not interned).
2014-08-08 12:33:49 +01:00
Dave Hylands
6f418fc1b0 Add support for selecting pin alternate functions from python.
Converts generted pins to use qstrs instead of string pointers.

This patch also adds the following functions:
pyb.Pin.names()
pyb.Pin.af_list()
pyb.Pin.gpio()

dir(pyb.Pin.board) and dir(pyb.Pin.cpu) also produce useful results.

pyb.Pin now takes kw args.

pyb.Pin.__str__ now prints more useful information about the pin
configuration.

I found the following functions in my boot.py to be useful:
```python
def pins():
    for pin_name in dir(pyb.Pin.board):
        pin = pyb.Pin(pin_name)
        print('{:10s} {:s}'.format(pin_name, str(pin)))

def af():
    for pin_name in dir(pyb.Pin.board):
        pin = pyb.Pin(pin_name)
        print('{:10s} {:s}'.format(pin_name, str(pin.af_list())))
```
2014-08-07 23:15:41 -07:00
Damien George
5d9b816449 py: Fix bug in mpn_shl (multi-prec int shift left).
Before this patch, eg, 1 << 75 (or any large multiple of 15) was setting
the MSB in the digits, which is outside the valid range of DIG_MASK.
2014-08-07 14:27:48 +00:00
Damien George
3ef911345c stmhal: Update STM32Cube F4 HAL driver to V1.3.0.
This patch updates ST's HAL to the latest version, V1.3.0, dated 19 June
2014.  Files were copied verbatim from the ST package.  Only change was
to suppress compiler warning of unused variables in 4 places.

A lot of the changes from ST are cosmetic: comments and white space.
Some small code changes here and there, and addition of F411 header.

Main code change is how SysTick interrupt is set: it now has a
configuration variable to set the priority, so we no longer need to work
around this (originall in system_stm32f4xx.c).
2014-08-06 22:33:31 +01:00
Damien George
8a11d693cf stmhal: Ability to stat /flash and /sd.
Addresses issue #780.
2014-08-06 19:02:34 +01:00
Damien George
2fe2a05f9f stmhal: Put #if guards around all GPIOx_CLK_ENABLE's.
Specifically, teensy port does not have these macros defined.
2014-08-06 16:40:20 +01:00
Damien George
95ea4f0c95 stmhal: Enable relevant GPIO clock when Pin obj is init'd. 2014-08-06 16:04:57 +01:00
Damien George
7cc20e7e99 stmhal: Wrap DAC module and os.urandom in relevant #if's. 2014-08-05 23:35:21 +01:00
Damien George
56da07dcfa stmhal, math: Define _M_LN2 if not already defined.
Addresses issue #790.
2014-08-05 14:13:05 +00:00
Damien George
dd07023cb7 travis: Build stmhal/ST32F4DISC and teensy in Travis tests. 2014-08-05 14:04:11 +00:00
Damien George
6c70511835 Merge pull request #789 from dhylands/fix-teensy-2014-08-04
Follow rename of readline_init to readline_init0 on teensy
2014-08-04 19:51:58 +01:00
Dave Hylands
0538a203e5 Follow rename of readline_init to readline_init0 on teensy 2014-08-04 09:27:29 -07:00
Damien George
2e3e8b2f69 Merge branch 'master' of github.com:micropython/micropython 2014-08-04 11:12:47 +01:00
Damien George
ccacdf44b6 stmhal: Clean up reset/soft-reset code; fix bug init'ing VCP exc.
Make a clearer distinction between init functions that must be done
before any scripts can run (xxx_init0) and those that can be safely
deferred (xxx_init).

Fix bug initialising USB VCP exception.  Addresses issue #788.

Re-order some init function to improve reliability of
reset/soft-reset.
2014-08-04 11:09:51 +01:00
Damien George
8dbbbbc793 Put call to qstr_init and mp_init_emergency_exc_buf in mp_init.
qstr_init is always called exactly before mp_init, so makes sense to
just have mp_init call it.  Similarly with
mp_init_emergency_exception_buf.  Doing this makes the ports simpler and
less error prone (ie they can no longer forget to call these).
2014-08-04 10:05:16 +01:00
Damien George
aa6228eaf5 Merge pull request #786 from dhylands/fix-teensy-2014-08-03
Updated teensys usb.c and switched to using usb.h from stmhal.
2014-08-03 18:39:31 +01:00
Dave Hylands
ecb5792f88 Updated teensys usb.c and switched to using usb.h from stmhal.
Removed the local usb.h from teensey directory and now uses
the usb.h from the stmhal directory.
Fixed the deploy target to use abspath.
2014-08-03 10:03:02 -07:00
Damien George
8362bffb2e stmhal: Document behaviour of usb_vcp_recv_byte. 2014-08-03 17:30:26 +01:00
Damien George
ce23f67d9e Merge pull request #784 from dhylands/fix-teensy-2014-08-02
Fix teensy to work with the latest tree.
2014-08-03 16:48:53 +01:00
Dave Hylands
e40c72210f Fix teensy to work with the latest tree. 2014-08-02 21:28:32 -07:00
Damien George
2e41646eb7 stmhal: Add more documentation for USB_VCP. 2014-08-02 14:43:20 +01:00
Damien George
87bbb388db stmhal: Add documentation for LCD; update docs for USB_VCP. 2014-08-02 14:35:38 +01:00
Damien George
71bed1a9a7 stmhal: Add preliminary driver for ST32F4DISC accelerometer.
Written in Python, not currently working.  See issue #725.
2014-08-02 12:51:18 +01:00
Damien George
8464be15ed Merge pull request #781 from dhylands/fix-disc
Fix modos.c to compile for the STM32F4Discovery board
2014-08-01 16:25:59 +01:00
Dave Hylands
f8f963a14a Fix modos.c to compile for the STM32F4Discovery board (which doesn't have an sdcard) 2014-08-01 08:10:41 -07:00
Damien George
65dd7bc13d stmhal: Change 0:/ and 1:/ to /flash and /sd; add CWD support.
Some important changes to the way the file system is structured on the
pyboard:

1. 0: and 1: drive names are now replaced with POSIX inspired
directories, namely /flash and /sd.

2. Filesystem now supports the notion of a current working directory.
Supports the standard Python way of manipulating it: os.chdir and
os.getcwd.

3. On boot up, current directory is /flash if no SD inserted, else /sd
if SD inserted.  Then runs boot.py and main.py from the current dir.
This is the same as the old behaviour, but is much more consistent and
flexible (eg you can os.chdir in boot.py to change where main.py is run
from).

4. sys.path (for import) is now set to '' (current dir), plus /flash
and /flash/lib, and then /sd and /sd/lib if SD inserted.  This, along
with CWD, means that import now works properly.  You can import a file
from the current directory.

5. os.listdir is fixed to return just the basename, not the full path.

See issue #537 for background and discussion.
2014-07-31 23:44:04 +01:00
Damien George
5aac6aa445 README: Add USB VID/PID to dfu-util command.
This reflects how it's done in stmhal/Makefile, via deploy.
2014-07-31 18:45:34 +01:00
Damien George
4747becc64 py: Improve encoding scheme for line-number to bytecode map.
Reduces by about a factor of 10 on average the amount of RAM needed to
store the line-number to bytecode map in the bytecode prelude.

Using CPython3.4's stdlib for statistics: previously, an average of
13 bytes were used per (bytecode offset, line-number offset) pair, and
now with this improvement, that's down to 1.3 bytes on average.

Large RAM usage before was due to some very large steps in line numbers,
both from the start of the first line in a function way down in the
file, and also functions that have big comments and/or big strings in
them (both cases were significant).

Although the savings are large on average for the CPython stdlib, it
won't have such a big effect for small scripts used in embedded
programming.

Addresses issue #648.
2014-07-31 16:12:01 +00:00
Damien George
8cc2018d47 Merge branch 'master' of https://github.com/micropython/micropython 2014-07-31 13:47:06 +00:00
Damien George
c9aa58e638 py: Improve handling of long-int overflow.
This removes mpz_as_int, since that was a terrible function (it
implemented saturating conversion).

Use mpz_as_int_checked and mpz_as_uint_checked.  These now work
correctly (they previously had wrong overflow checking, eg
print(chr(10000000000000)) on 32-bit machine would incorrectly convert
this large number to a small int).
2014-07-31 13:41:43 +00:00
Damien George
bb4c6f35c6 py: Make MP_OBJ_NEW_SMALL_INT cast arg to mp_int_t itself.
Addresses issue #724.
2014-07-31 10:49:14 +01:00
Damien George
fa1ecda3fd stmhal, accel: Increase start-up times to 30ms; add extra 30ms delay.
For accel to start-up reliably, need to wait 30ms between on/off, and
30ms for it to enter active mode.  With this fix the accel can be read
immediately after initialising it.

Addresses issue #763.
2014-07-31 10:39:52 +01:00
Damien George
3c4db9f91c stmhal: Add USB_VCP class/object, for direct USB VCP control.
Before, pyb.stdin/pyb.stdout allowed some kind of access to the USB VCP
device, but it was basic access.

This patch adds a proper USB_VCP class and object with much more control
over the USB VCP device.  Create an object with pyb.USB_VCP(), then use
this object as if it were a UART object.  It has send, recv, read,
write, and other methods.  send and recv allow a timeout to be specified.

Addresses issue 774.
2014-07-31 10:30:42 +01:00
Damien George
5f27a7e811 py: Add mp_obj_str_builder_end_with_len.
This allows to create str's with a smaller length than initially asked
for.
2014-07-31 10:29:56 +01:00
Damien George
94fbe9711a py: Change lexer stream API to return bytes not chars.
Lexer is now 8-bit clean inside strings.
2014-07-30 11:46:05 +01:00
Damien George
07133415d2 Merge pull request #738 from dhylands/except-args
Add support for storing args during an exception raised by an irq.
2014-07-29 23:15:35 +01:00
Paul Sokolovsky
d0f5e61ab5 py: Implement __file__ attribute for modules. 2014-07-28 21:21:59 +03:00
Paul Sokolovsky
645582fe14 py: Make id() return small int for the most common address space mapping.
Many OSes/CPUs have affinity to put "user" data into lower half of address
space. Take advantage of that and remap such addresses into full small int
range (including negative part).

If address is from upper half, long int will be used. Previously, small
int was returned for lower quarter of address space, and upper quarter. For
2 middle quarters, long int was used, which is clearly worse schedule than
the above.
2014-07-28 21:21:59 +03:00
Damien George
adf0f2ae1a py: Change stream protocol API: fns return uint; is_text for text. 2014-07-27 22:38:58 +01:00
Dave Hylands
5b7fd20fea Add support for storing args during an exception raised by an irq.
The user code should call micropython.alloc_emergency_exception_buf(size)
where size is the size of the buffer used to print the argument
passed to the exception.

With the test code from #732, and a call to
micropython.alloc_emergenncy_exception_buf(100) the following error is
now printed:
```python
>>> import heartbeat_irq
Uncaught exception in Timer(4) interrupt handler
Traceback (most recent call last):
  File "0://heartbeat_irq.py", line 14, in heartbeat_cb
NameError: name 'led' is not defined
```
2014-07-25 14:00:06 -07:00
Damien George
05c255f039 Merge pull request #771 from dhylands/gitignore-GNUmakefile
Add GNUmakefile to the .gitignore file.
2014-07-24 14:32:20 +01:00
Damien George
ffe911d228 py: Make long ints hashable.
Addresses issue #765.
2014-07-24 14:21:37 +01:00
Dave Hylands
1bbdd4ed2a Add GNUmakefile to the .gitignore file. 2014-07-24 00:09:56 -07:00
Paul Sokolovsky
4ecb700fe3 streams: Treat non-error output size as unsigned. 2014-07-23 00:25:46 +03:00
Paul Sokolovsky
e1b1abc1e8 stream: Revert to checking for the correct error value. 2014-07-23 00:23:44 +03:00
Damien George
de993f4573 Merge pull request #766 from dhylands/allow-dfu-override
Allow DFU_UTIL to be overridden from the environment.
2014-07-22 11:02:59 +01:00
Damien George
7cfae9693b Merge pull request #746 from blmorris/master
Enable 16-bit memory addresses for i2c.mem_read and i2c_mem_write
2014-07-22 11:01:42 +01:00
Damien George
3e0bce3587 Merge pull request #767 from dhylands/fix-short-read
Deal with reading a buffer less than what was allocated.
2014-07-22 11:01:24 +01:00
blmorris
7a03b5f56a remove Myriad2 board config files from master 2014-07-21 23:12:07 -04:00
blmorris
86f0b31bcf Change boolean 'use_16bit_addr' to int 'addr_size', can be either 8 or 16 bits, default value is 8
to maintain compatibility with existing code.
2014-07-21 22:45:04 -04:00
Dave Hylands
1d8816c36b Deal with reading a buffer less than what was allocated.
With this fix, file_long_read now passes.
2014-07-21 19:10:10 -07:00
Dave Hylands
a2e7a1315d Allow DFU_UTIL to be overridden from the environment. 2014-07-21 16:28:07 -07:00
Paul Sokolovsky
512465bc66 tests: Add testcase for read by length past EOF.
Currently broken for unicode input streams.
2014-07-22 00:11:37 +03:00
blmorris
721d6240c9 Merge https://github.com/blmorris/micropython into Myriad2 2014-07-21 12:50:10 -04:00
blmorris
4038f513ea Merge https://github.com/micropython/micropython 2014-07-21 12:47:57 -04:00
Damien George
951ed9d02f stmhal: Fix REPL printing by cooking output sent to stdout_obj.
Recent changes to builtin print meant that print was printing to the
mp_sys_stdout_obj, which was sending data raw to the USB CDC device.
The data should be cooked so that \n turns into \r\n.
2014-07-20 13:57:43 +01:00
Damien George
1163cb9cb5 stmhal: Change calls to pfenv_printf to pfenv_vprintf.
Fixes printing bugs introduced by
cb66f41ebc.
2014-07-20 13:10:18 +01:00
Paul Sokolovsky
cb66f41ebc py: Make print() accept "file" argument, and actually print to stream.
And not system printf(), like it was before. For this, move pfenv_printf()
from stmhal port to py/.
2014-07-19 21:27:22 +03:00
Damien George
04c9fec7d1 Merge pull request #757 from stinos/windows-fsync
Add fsync for windows, i.e. _commit. See dce8876
2014-07-19 18:40:49 +01:00
Damien George
2c0701101b Merge pull request #759 from micropython/unicode-read-chars
py: Add stream reading of n unicode chars; unicode support by default.
2014-07-19 18:38:28 +01:00
Damien George
1694bc733d py: Add stream reading of n unicode chars; unicode support by default.
With unicode enabled, this patch allows reading a fixed number of
characters from text-mode streams; eg file.read(5) will read 5 unicode
chars, which can made of more than 5 bytes.

For an ASCII stream (ie no chars > 127) it only needs to do 1 read.  If
there are lots of non-ASCII chars in a stream, then it needs multiple
reads of the underlying object.

Adds a new test for this case.  Enables unicode support by default on
unix and stmhal ports.
2014-07-19 18:34:04 +01:00
Damien George
02bc882c3d stmhal: Add file.flush and os.stat. 2014-07-19 16:39:13 +01:00
blmorris
0f4ee2e44a Merge https://github.com/micropython/micropython 2014-07-18 16:06:22 -04:00
Damien George
5467186b0e py: Remove unnecessary argument in bytearray print. 2014-07-17 21:56:32 +01:00
Paul Sokolovsky
e3737b858a formatfloat.c: Typo fix in comment. 2014-07-17 20:45:58 +03:00
Damien George
a4022c92f0 py, inline asm: Change "and" op name to "and_" to avoid keyword clash.
Addresses issue #753.
2014-07-17 12:37:56 +01:00
Damien George
a50494ab68 Merge pull request #755 from dhylands/teensy-core
Add teensy core files and use same toolchain as stmhal
2014-07-17 12:30:44 +01:00
Damien George
db56ad2915 Merge pull request #754 from dhylands/fix-teensy
Fix teensy to build on latest tree.
2014-07-17 12:26:35 +01:00
stijn
73ab8cc21d Add fsync for windows, i.e. _commit. See dce8876 2014-07-16 09:37:09 +02:00
blmorris
ef204733d6 Initial commit of Myriad2 board-specific configuration files 2014-07-15 15:10:56 -04:00
blmorris
0429d35f37 Merge https://github.com/micropython/micropython 2014-07-15 12:28:49 -04:00
Dave Hylands
04f5ae1d1c Add core files and use same toolchain as stmhal 2014-07-14 22:48:22 -07:00
Dave Hylands
4d9dd26818 Fix teensy to build on latest tree.
Put #include of mpconfig.h before misc.h
Replace uses of ARRAY_SIZE with MP_ARRAY_SIZE
2014-07-14 22:19:27 -07:00
Paul Sokolovsky
dce8876dbe unix: file: No fsync() on Windows. 2014-07-13 23:34:35 +03:00
Paul Sokolovsky
ac736f15c9 stream: Factor out mp_stream_write() method to write a memstring to stream. 2014-07-13 23:14:32 +03:00
Paul Sokolovsky
122c9db3db unix: file: Implement .flush() method.
This method apparently should be part of stream interface.
2014-07-13 23:14:24 +03:00
Paul Sokolovsky
a1760a56ff test: Add run-tests-exp.sh, script to run testsuite with only sh dependency.
This script uses expected test results as generated by run-tests --write-exp,
and requires only standard unix shell funtionality (no bash). It is useful
to run testsuite on embedded systems, where there's no CPython and Bash.
2014-07-13 18:49:56 +03:00
Paul Sokolovsky
b82f34edde unix: Allow to disable MICROPY_EMIT_X64 from commandline.
emitnative in particular requires nlr_* to be real functions, so doesn't
compile with MICROPY_NLR_SETJMP=1.
2014-07-13 13:49:51 +03:00
Paul Sokolovsky
2cf381081a run-tests: Add option to write CPython's test results to .exp files.
Mostly to run testsuite on targets which doesn't have CPython.
2014-07-12 16:34:51 +03:00
Paul Sokolovsky
564e46452d py: Add generic helper to align a pointer. 2014-07-12 15:57:28 +03:00
Paul Sokolovsky
58c9586c34 emitbc: Fix structure field alignment issue.
dummy_data field is accessed as uint value (e.g.
in emit_write_bytecode_byte_ptr), but is not aligned as such, which causes
bus errors or incorrect behavior on any arch requiring strictly aligned
data (ARM pre-v7, MIPS, etc, etc).
2014-07-12 15:57:28 +03:00
blmorris
847a6b30b1 Incorporate stylistic changes suggested by @dhylands 2014-07-11 21:18:09 -04:00
blmorris
e687fdbcbc Add keyword argument 'memaddr_use_16b' to i2c.mem_read and mem_write methods
to allow these methods to transmit 16 bit addresses to an i2c device
Add 'memaddr_use_16b' to qstrdefsport.h
2014-07-11 16:14:01 -04:00
Paul Sokolovsky
2097c8b1e1 moductypes: Add symbolic constants to specify bitfield position/length. 2014-07-11 00:06:36 +03:00
Paul Sokolovsky
8215847b4d moductypes: Foreign data interface module, roughly based on ctype ideas.
But much smaller and memory-efficient. Uses Python builtin data structures
(dict, tuple, int) to describe structure layout.
2014-07-09 19:28:24 +03:00
Damien George
42b6419056 Merge branch 'dhylands-fix-sdcard-read' 2014-07-07 07:29:52 +01:00
Damien George
594699bc88 stmhal: Protect SD_WriteBlocks by IRQ disable/enable pair. 2014-07-07 07:29:06 +01:00
Dave Hylands
90ba80dc36 Disable IRQs around sdcard reads.
Once the code switches to using DMA, this can be removed.
2014-07-06 09:51:22 -07:00
Paul Sokolovsky
5fa5ca40e6 binary: Factor out mp_binary_set_int(). 2014-07-05 23:54:03 +03:00
Damien George
539681fffd tests: Rename test scripts, changing - to _ for consistency.
From now on, all new tests must use underscore.

Addresses issue #727.
2014-07-05 06:14:29 +01:00
Damien George
0182385ab0 py: Automatically ake __new__ a staticmethod.
Addresses issue #622.
2014-07-05 05:55:00 +01:00
Paul Sokolovsky
4e0eeebdc2 py: Implement sys.maxsize, standard way to check platform "bitness".
Implementing it as a static constant is a bit peculiar and require cooperation
from long int implementation.
2014-07-03 18:09:36 +03:00
Damien George
381618269a parser: Convert (u)int to mp_(u)int_t. 2014-07-03 14:13:33 +01:00
Damien George
54eb4e723e lexer: Convert type (u)int to mp_(u)int_t. 2014-07-03 13:47:47 +01:00
Damien George
40f3c02682 Rename machine_(u)int_t to mp_(u)int_t.
See discussion in issue #50.
2014-07-03 13:25:24 +01:00
Damien George
065aba5875 Merge pull request #739 from errordeveloper/patch-1
qemu: fix typo in readme
2014-07-03 10:16:07 +01:00
Ilya Dmitrichenko
e4e55047b3 qemu: fix typo in readme 2014-07-02 18:30:46 +01:00
Damien George
5e6419cb11 Merge branch 'dhylands-add-timer-deinit' 2014-07-02 14:10:18 +01:00
Damien George
e70b5dbe58 stmhal: Some reordering of code/functions. 2014-07-02 14:09:44 +01:00
Damien George
92a47b4dae Merge branch 'add-timer-deinit' of github.com:dhylands/micropython into dhylands-add-timer-deinit 2014-07-02 14:06:28 +01:00
Damien George
9cd96cf25d Merge pull request #709 from windelbouwman/master
Added hexfile target
2014-07-02 13:53:28 +01:00
Damien George
f83debc716 Merge branch 'dhylands-teensy-new' 2014-07-02 13:45:00 +01:00
Damien George
7a37f647a5 Merge branch 'teensy-new' of github.com:dhylands/micropython into dhylands-teensy-new
Conflicts:
	stmhal/pin_named_pins.c
	stmhal/readline.c

Renamed HAL_H to MICROPY_HAL_H.  Made stmhal/mphal.h which intends to
define the generic Micro Python HAL, which in stmhal sits above the ST
HAL.
2014-07-02 13:42:37 +01:00
Damien George
5fc580475f Merge branch 'dhylands-preserve-except' 2014-07-01 14:28:40 +01:00
Damien George
f0b29729aa py, objexcept: Only check for locked gc if gc is enabled. 2014-07-01 14:28:09 +01:00
Damien George
f065344d3b Merge branch 'preserve-except' of github.com:dhylands/micropython into dhylands-preserve-except 2014-07-01 14:26:37 +01:00
Damien George
aa47f3968b Merge pull request #734 from iabdalkader/copysign
Add copysignf
2014-07-01 14:03:55 +01:00
Dave Hylands
2fe841d2fa Try not to cause a MemoryError when raising an exception during nterrupt handling.
Step 1 fixes #732
2014-06-30 22:49:21 -07:00
Paul Sokolovsky
caa7334141 stackctrl: Add "mp_" prefix. 2014-07-01 02:14:08 +03:00
Paul Sokolovsky
e95b6b5e07 modffi: Add special 'C' code for passing a callback function pointer. 2014-07-01 02:05:34 +03:00
Dave Hylands
0d81c133b3 Add timer_deinit and call it just before doing a soft-restart
This fixes #733.
2014-06-30 08:07:38 -07:00
mux
5d44e6a92c Add copysignf
* Fix #692
2014-06-30 16:31:06 +02:00
Damien George
4039a26679 Merge pull request #710 from iabdalkader/assert
Fix assert_func warning/error
2014-06-30 09:09:24 +01:00
Damien George
b601d9574a py: Improvements to native emitter.
Native emitter can now compile try/except blocks using nlr_push/nlr_pop.
It probably only works for 1 level of exception handling.  It doesn't
work on Thumb (only x64).

Native emitter can also handle some additional op codes.

With this patch, 198 tests now pass using "-X emit=native" option to
micropython.
2014-06-30 05:17:25 +01:00
Paul Sokolovsky
5813efd634 stmhal: pyb.adc: Clarify that buffer with elements of any size can be used.
Based on forum post: http://forum.micropython.org/viewtopic.php?f=6&t=193
2014-06-29 21:34:58 +03:00
Paul Sokolovsky
bb35f425f9 Merge pull request #730 from stinos/windows-mpconfig
windows: Sync mpconfigport.h with the unix' version
2014-06-29 20:50:16 +03:00
Paul Sokolovsky
c10a4405cd gendoc.py: Support modules w/o functions and/or classes.
I.e. don't assume that both are always present.
2014-06-29 15:48:30 +03:00
Paul Sokolovsky
a23475979b modffi: Support short types. 2014-06-29 15:48:21 +03:00
stijn
ec6fa8732b windows: Sync mpconfigport.h with the unix' version
- rearrange/add definitions that were not there so it's easier to compare both
- use MICROPY_PY_SYS_PLATFORM in main.c since it's available anyway
- define EWOULDBLOCK, it is missing from ingw32
2014-06-29 09:40:20 +02:00
Paul Sokolovsky
8139494e54 stmhal: Include mpconfig.h before all other includes.
It defines types used by all other headers.

Fixes #691.
2014-06-28 23:32:03 +03:00
Paul Sokolovsky
9e215fa4c2 py: Make unichar_charlen() accept/return machine_uint_t. 2014-06-28 23:15:29 +03:00
Paul Sokolovsky
a62da515af Merge pull request #729 from stinos/fix-include-order
unix: Fix mpconfig.h not being included before misc.h
2014-06-28 23:12:39 +03:00
stijn
5478ed18ea unix: Fix mpconfig.h not being included before misc.h
This fixes count_lead_ones in misc.h not compiling due to unknown types
2014-06-28 20:49:39 +02:00
Damien George
b1b840554d Merge branch 'unicode' 2014-06-28 10:30:53 +01:00
Damien George
635b60e299 unix, stmhal: Add option for STR_UNICODE to mpconfigport.h.
Unicode is disabled by default for now, since FileIO.read(n) is
currently not implemented for text-mode files, and this is an
often function.
2014-06-28 10:29:52 +01:00
Damien George
8546ce1e28 py: Add missing #endif. 2014-06-28 10:29:22 +01:00
Damien George
41736f8201 tests: Write output in byte mode, not text mode.
This enables testing unicode and non-unicode implementations.
2014-06-28 10:29:12 +01:00
Damien George
e04a44e2f6 py: Small comments, name changes, use of machine_int_t. 2014-06-28 10:27:23 +01:00
Damien George
b3a50f0f3e Merge branch 'master' into unicode
Conflicts:
	py/mpconfig.h
2014-06-28 10:27:15 +01:00
Paul Sokolovsky
8993fb6cf0 py: Add protection against printing too nested or recursive data structures.
With a test which cannot be automatically validated so far.
2014-06-28 02:25:04 +03:00
Paul Sokolovsky
7e4ec3bf4f bare-arm: Hint of setting MICROPY_ERROR_REPORTING to REPORTING_TERSE.
Commented out so far, as enabled leads to dozen more bytes used actually
(due to string pooling effects).
2014-06-27 21:02:04 +03:00
Paul Sokolovsky
81df1e6c98 bare-arm: Disable array module and even bytearray type.
To squeeze few more hundreds of bytes.
2014-06-27 21:02:04 +03:00
Paul Sokolovsky
cb78f862cb py: Allow to disable array module and bytearray type.
array.array and bytearray share big deal of code, so to get real savings,
both need to be disabled.
2014-06-27 21:02:04 +03:00
Paul Sokolovsky
0a1ea40273 bare-arm: Enable link map file.
This port supposed to be demo of uPy minimality, so let people behold it in
details.
2014-06-27 21:02:04 +03:00
Paul Sokolovsky
8a96ebea75 py: Move stack_ctrl_init() to mp_init().
As stack checking is enabled by default, ports which don't call
stack_ctrl_init() are broken now (report RuntimeError on startup). Save
them trouble and just init stack control framework in interpreter init.
2014-06-27 21:02:04 +03:00
Paul Sokolovsky
64c58403ef Merge pull request #720 from iabdalkader/mcu_name
Change MCU name config micro
2014-06-27 18:24:32 +03:00
mux
a75e382a9b Change MCU name config micro 2014-06-27 00:35:53 +02:00
Paul Sokolovsky
3c8ce38d20 Merge pull request #717 from stinos/dead-code
unix: Remove unused CTRL-D definition
2014-06-27 01:23:18 +03:00
Paul Sokolovsky
3659af97c5 Merge pull request #703 from iabdalkader/micro_names
Add MICROPY_HW_MICRO_NAME to boards config
2014-06-27 01:19:17 +03:00
Paul Sokolovsky
ed07d035d5 tests: Add basic test for unicode file i/o. 2014-06-27 00:04:20 +03:00
Paul Sokolovsky
f5f6c3b792 streams: Reading by char count from unicode text streams is not implemented. 2014-06-27 00:04:20 +03:00
Paul Sokolovsky
ce81312d8a misc: Add count_lead_ones() function, useful for UTF-8 handling. 2014-06-27 00:04:20 +03:00
Paul Sokolovsky
63143c94ce tests: Test for explicit start/end args to str methods for unicode. 2014-06-27 00:04:20 +03:00
Paul Sokolovsky
ea2c936c7e objstrunicode: Refactor str_index_to_ptr() following objstr. 2014-06-27 00:04:20 +03:00
Paul Sokolovsky
26fda6dc8e objstr: 64-bit issues. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
00c904b47a objstrunicode: Signedness issues. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
1044c3dfe6 unicode: Make get_char()/next_char()/charlen() be 8-bit compatible.
Based on config define.
2014-06-27 00:04:19 +03:00
Paul Sokolovsky
b1949e4c09 tests: Add tests for unicode find()/rfind()/index(). 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
5048df0b7c objstr: find(), rfind(), index(): Make return value be unicode-aware. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
46d31e9ca9 unicode: Add utf8_ptr_to_index().
Useful when we have pointer to char inside string, but need to return char
index. (E.g. str.find()).
2014-06-27 00:04:19 +03:00
Paul Sokolovsky
ded0fc77f7 py: Add dedicated unicode header. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
17994d1bd3 tests: Add test for unicode string iteration. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
79b7fe2ee5 objstrunicode: Implement iterator. 2014-06-27 00:04:19 +03:00
Paul Sokolovsky
cdc020da4b objstrunicode: Re-add buffer protocol back for now, required for io.StringIO. 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
e7f2b4c875 objstrunicode: Revamp len() handling for unicode, and optimize bool(). 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
86d3898e70 objstrunicode: Get rid of bytes checking, it's separate type. 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
d215ee1dc1 py: Make MICROPY_PY_BUILTINS_STR_UNICODE=1 buildable. 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
9731912ccb py: Prune unneeded code from objstrunicode, reuse code in objstr. 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
165eb69b86 vstr: Restore bytestr compatibility. 2014-06-27 00:04:18 +03:00
Paul Sokolovsky
42a52516fe builtin: Restore bytestr compatibility. 2014-06-27 00:04:18 +03:00
Chris Angelico
2ba2299d28 lexer, vstr: Add unicode support. 2014-06-27 00:04:18 +03:00
Chris Angelico
1e3781bc35 tests: Add unicode test. 2014-06-27 00:04:17 +03:00
Chris Angelico
9a1a4beb56 builtin: ord, chr: Unicode support. 2014-06-27 00:04:17 +03:00
Chris Angelico
64b468d873 objstrunicode: Basic implementation of unicode handling.
Squashed commit of the following:

commit 99dc21b67a
Author: Chris Angelico <rosuav@gmail.com>
Date:   Thu Jun 12 02:18:54 2014 +1000

    Optimize as per TODO (thanks Damien!)

commit 5bf0153eca
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 08:42:06 2014 +1000

    Test a default (= UTF-8) encode and decode

commit c962057ac3
Merge: e2c9782 195de32
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 05:23:03 2014 +1000

    Merge branch 'master' into unicode, resolving conflict on py/obj.h

commit e2c9782a65
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 05:05:57 2014 +1000

    More whitespace fixups

commit 086a2a0f57
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 05:04:20 2014 +1000

    Properly implement string slicing

commit 0d339a143e
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 02:24:11 2014 +1000

    Support slicing in str_index_to_ptr, and fix a bounds error

commit 24371c7267
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 02:10:22 2014 +1000

    Break out index-to-pointer calculation into a function

commit 616c24ac01
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 02:03:11 2014 +1000

    Add tests of string slicing, which currently fail

commit a24d19f676
Author: Chris Angelico <rosuav@gmail.com>
Date:   Tue Jun 10 01:56:53 2014 +1000

    Change string indexing to not precalculate the charlen, and add test for neg indexing

commit 0bcc7ab89e
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 22:09:17 2014 +1000

    Clean up constant qstr declarations now that charlen isn't needed

commit 5473e1a1db
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 07:18:42 2014 +1000

    Remove the charlen field from strings, calculating it when required

commit 5c1658ec71
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 07:11:27 2014 +1000

    Get rid of mp_obj_str_get_data_len() which was used in only one place

commit a019ba968b
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 06:58:26 2014 +1000

    Add a unichar_charlen() function to calculate length-in-characters from length-in-bytes

commit 44b0d5cff8
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 06:32:44 2014 +1000

    Use utf8_get/next_char in building up a string's repr

commit 30d1bad33f
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 06:10:45 2014 +1000

    Make utf8_get_char() and utf8_next_char() actually do what their names say

commit bc990dad9a
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sun Jun 8 02:10:59 2014 +1000

    Revert "Add PEP 393-flags to strings and stub usage."

    This reverts commit c239f50952.

commit f9bebb28ad
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 15:41:48 2014 +1000

    Whitespace fixes

commit 279de0c8eb
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 15:28:35 2014 +1000

    Formatting/layout improvements - introduce macros for UTF-8 byte detection, add braces. No functional changes.

commit f1911f53d5
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 11:56:02 2014 +1000

    Make chr() Unicode-aware

commit f51ad737b4
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 11:44:07 2014 +1000

    Make a string's repr Unicode-aware

commit 01bd686846
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 11:33:43 2014 +1000

    Expand the Unicode tests

commit 7bc91904f8
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 11:27:30 2014 +1000

    Record byte lengths for byte strings

commit bb13212071
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 11:25:06 2014 +1000

    Make ord() Unicode-aware

commit 03f0cbe905
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 10:24:35 2014 +1000

    Retain characters as UTF-8 encoded Unicode

commit e924659b85
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 08:37:27 2014 +1000

    Add support for \u and \U escapes, but not \N (with explanatory comment)

commit 231031ac5f
Author: Chris Angelico <rosuav@gmail.com>
Date:   Sat Jun 7 05:09:35 2014 +1000

    Add character length to qstr

commit 6df1b946fb
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 13:48:36 2014 +1000

    Add test of UTF-8 encoded source file resulting in properly formed string

commit 16429b81a8
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 13:44:15 2014 +1000

    Make len(s) return character length (even though creation's still buggy)

commit cd2cf6663c
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 13:15:36 2014 +1000

    HACK - When indexing a qstr, count its charlen. Stupidly inefficient but POC.

    All tests pass now, though string creation is still buggy.

commit 47c234584d
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 13:15:32 2014 +1000

    objstr: Record character length separately from byte length

    CAUTION: Buggy, may crash stuff - qstr needs equivalent functionality too

commit b0f41c72af
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 05:37:36 2014 +1000

    Beginnings of UTF-8 support - construct strings from that many UTF-8-encoded chars, and subscript bytes the same way

commit 89452be641
Author: Chris Angelico <rosuav@gmail.com>
Date:   Fri Jun 6 05:28:47 2014 +1000

    Update comments - now aiming for UTF-8 rather than PEP 393 strings

commit c239f50952
Author: Chris Angelico <rosuav@gmail.com>
Date:   Wed Jun 4 05:28:12 2014 +1000

    Add PEP 393-flags to strings and stub usage.

    The test suite all passes, but nothing has actually been changed.
2014-06-27 00:04:17 +03:00
Paul Sokolovsky
83865347db objstrunicode: Complete copy of objstr, to be patched for unicode support. 2014-06-27 00:04:17 +03:00
Chris Angelico
c88987c1af py: Implement basic unicode functions. 2014-06-27 00:04:17 +03:00
Paul Sokolovsky
12bc13eeb8 mpconfig.h: Add MICROPY_PY_BUILTINS_STR_UNICODE. 2014-06-27 00:04:17 +03:00
Paul Sokolovsky
16ac4962ae tests: Add test for catching infinite function recursion.
Put into misc/ to not complicate life for builds with check disabled.
2014-06-27 00:03:56 +03:00
Paul Sokolovsky
7a8ab5a730 stmhal: Use stackctrl framework. 2014-06-27 00:03:55 +03:00
Paul Sokolovsky
23668698cb py: Add portable framework to query/check C stack usage.
Such mechanism is important to get stable Python functioning, because Python
function calling is handled with C stack. The idea is to sprinkle
STACK_CHECK() calls in places where there can be C recursion.

TODO: Add more STACK_CHECK()'s.
2014-06-27 00:03:55 +03:00
Paul Sokolovsky
91b576d147 Merge pull request #719 from dhylands/pin_fix
Use mp_const_none to initialize mapper and map_dict (fix #701)
2014-06-26 22:49:44 +03:00
Dave Hylands
f170735b73 Use mp_const_none to initialize mapper and map_dict 2014-06-25 16:01:19 -07:00
Paul Sokolovsky
f3de62e6c2 binary: machine_uint_t vs uint dichotomy starts doing real damage. 2014-06-26 00:41:08 +03:00
Paul Sokolovsky
8e01291c18 travis: Use unified diffs for failed tests. 2014-06-26 00:05:53 +03:00
Paul Sokolovsky
7a2f166949 modstruct: Fix alignment handling issues.
Also, factor out mp_binary_get_int() function.
2014-06-25 23:34:44 +03:00
stijn
39b6e27944 unix: Remove unused CTRL-D definition 2014-06-25 13:33:10 +02:00
Paul Sokolovsky
5aa740c3e2 modgc: Add mem_free()/mem_alloc() methods.
Return free/allocated memory on GC heap.
2014-06-25 14:28:11 +03:00
Damien George
e973acde81 Merge branch 'master' of github.com:micropython/micropython 2014-06-25 04:10:34 +01:00
Paul Sokolovsky
939c2e7f44 Merge pull request #690 from stinos/msvc-gc
msvc: Enable GC
2014-06-24 21:34:51 +03:00
Paul Sokolovsky
3c9b24bebe modsocket: Fix uClibc detection. 2014-06-24 21:20:38 +03:00
Paul Sokolovsky
141df2d350 unix: Dump default heap size in usage message. 2014-06-24 16:58:00 +03:00
Damien George
780e54cdc3 py: Implement delete_attr in native emitter. 2014-06-22 18:35:04 +01:00
Paul Sokolovsky
cd590cbfaa unix: Don't error out on #warning directive. 2014-06-22 19:20:55 +03:00
Paul Sokolovsky
ff5932a8d8 modsocket: Workaround uClibc issue with numeric port for getaddrinfo().
It sucks to workaround this on uPy side, but upgrading not upgradable
embedded systems sucks even more.
2014-06-22 19:20:55 +03:00
Paul Sokolovsky
949a49c9da modsocket: Add call to freeaddrinfo(). 2014-06-22 19:11:34 +03:00
Paul Sokolovsky
69d0a1c540 unix: uClibc doesn't like NULL as a buffer arg to realpath().
So, allocate one explicitly.
2014-06-22 19:08:32 +03:00
stijn
de5ce6d461 gc: Use simple cast instead of union to silence compiler 2014-06-22 11:32:32 +02:00
stijn
8abcf666cb windows: Enable GC and implement bss start and end symbols
The pointers to the bss section are acquired in init.c()
by inspecting the PE header. Works for msvc and mingw.
2014-06-22 11:31:16 +02:00
Paul Sokolovsky
a96cc824bd py: Support arm and thumb ARM ISAs, in addition to thumb2.
These changes were tested with QEMU, and by few people of real hardware.
2014-06-22 01:40:45 +03:00
Paul Sokolovsky
59c675a64c py: Include mpconfig.h before all other includes.
It defines types used by all other headers.

Fixes #691.
2014-06-21 22:43:22 +03:00
mux
89b38d96c9 Add NORETURN to __fatal_error 2014-06-21 18:43:44 +02:00
mux
5c8db48541 Fix asser_func warning/error
* Add while(1) to assert_func to avoid func returns warning
* Define a weak attr in mpconfig.h
2014-06-21 17:24:55 +02:00
Paul Sokolovsky
4c4b9d15ab mkrules.mk: Pass $(COPT) to link stage.
In generalize case, optimization options should be passed to all stages of
the build process.
2014-06-20 23:49:30 +03:00
Paul Sokolovsky
0fc7efb663 makefile: Pass STRIPFLAGS_EXTRA to strip.
Expected to be set on command line, with the idea being that for different
targets, there're different smartass ABIs which strive to put unneeded
sections into executables, etc., so let people have flexible way to
strip that.

The option name is similar to previously introduced CLFAGS_EXTRA &
LDFLAGS_EXTRA.
2014-06-20 20:25:35 +03:00
Paul Sokolovsky
17a49431d4 unix: Allow to override MICROPY_GCREGS_SETJMP from cmdline. 2014-06-20 20:22:31 +03:00
Paul Sokolovsky
7cd46a12ae unix: Add CFLAGS_EXTRA & LDFLAGS_EXTRA for command line usage.
The idea is that it should be possible to pass any additional params for
experimentation without need to patch sources (and without need to deviate
from or repeat baseline options).
2014-06-20 20:21:21 +03:00
Paul Sokolovsky
7e56e55252 unix: Refactor order file munging fo MacOSX. 2014-06-20 20:21:11 +03:00
Paul Sokolovsky
eecf3e90c6 unix: Group CFLAGS related stuff together. 2014-06-20 20:21:11 +03:00
Paul Sokolovsky
2099b6897f unix: Allow to override compiler warning options without touching the rest.
Some people want to enable even more warnings. Let them do it without putting
burden on everyone. Some people vice versa think that current settings should
be relaxed. In this regard, -Werror is the most problematic, it disallows to
use #warning directive, and disallows to pass configuration settings on make
command lines. Again, until decided how to deal with these globally, allow to
work around these problems locally.
2014-06-20 20:18:08 +03:00
Paul Sokolovsky
f605172d2b tests/float/: Skip tests if "math" module is not available. 2014-06-20 18:00:23 +03:00
Paul Sokolovsky
3b6f7b95eb py: Separate MICROPY_PY_BUILTINS_COMPLEX from MICROPY_PY_BUILTINS_FLOAT.
One thing is wanting to do 1 / 2 and get something else but 0, and quite
another - doing rocket science ;-).
2014-06-20 18:00:23 +03:00
Paul Sokolovsky
7efbd325bb Merge pull request #697 from stinos/gc-debug
gc: More verbose debugging
2014-06-20 17:33:02 +03:00
Paul Sokolovsky
09e3f8f0d1 Merge pull request #707 from eblot/master-v1.1.1-build-fixes
Fix missing declaration of assert()
Replace ARRAY_SIZE with MP_ARRAY_SIZE
2014-06-20 17:29:58 +03:00
Windel Bouwman
b6af4c8104 Added hexfile target 2014-06-20 16:14:55 +02:00
Paul Sokolovsky
74c710187c bench: Three ways to process a byte buffer. 2014-06-19 22:27:13 +03:00
Paul Sokolovsky
59ced651b5 bench: Add test for map() vs inplace operations in array-likes.
map() is 5 times slower. That's mostly because of inefficiency of creating
containers from iterables of unknown length (like map()).
2014-06-19 22:19:24 +03:00
Paul Sokolovsky
17db096505 bench: Add tests for constructing various containers from iterator.
Both "bound" (like, length known) and "unbound" (length unknown) are tested.
All of list, tuple, bytes, bytesarray offer approximately the same
performance, with "unbound" case being 30 times slower.
2014-06-19 21:44:33 +03:00
Paul Sokolovsky
e53d2197e4 bench: Add test for function call overhead.
For a trivial operation, calling a function is 5 times slower than doing
operation inline.
2014-06-19 20:49:03 +03:00
Emmanuel Blot
f6932d6506 Prefix ARRAY_SIZE with micropython prefix MP_ 2014-06-19 18:54:34 +02:00
Emmanuel Blot
bf3366a48b Add missing “assert.h” file header inclusion from “nlr.h” 2014-06-19 18:47:38 +02:00
mux
fe81eea967 Add MICROPY_HW_MICRO_NAME to boards config 2014-06-19 14:40:57 +02:00
Damien George
b0851e5949 Merge pull request #700 from swegener/for-upstream
bare-arm, stmhal: Disable stack protector
2014-06-18 14:59:39 +01:00
Sven Wegener
c3cabf4e33 bare-arm, stmhal, teensy: Duplicate -nostdlib to CFLAGS
As we are building with -nostdlib gcc features like the stack protector
will fail linking, because the failure handlers are in gcc's internal
libs. Such features are implicitly disabled during compilation when
-nostdlib is used in CFLAGS too.

Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2014-06-18 13:34:07 +02:00
Sven Wegener
afc67c6dc5 bare-arm, stmhal: Fix --nostdlib to -nostdlib
-nostdlib is the correct option, gcc recognizes the double dash version
when in link-only mode, but not when compiling.

Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
2014-06-18 13:33:47 +02:00
stijn
9acb5e4cf0 gc: Turn off debugging info again 2014-06-18 12:29:03 +02:00
stijn
def10cecd1 gc: Keep debug statements at beginning of scope where possible 2014-06-18 10:20:41 +02:00
Damien George
720f55cc4b Merge pull request #698 from dhylands/adc-fix
Fix problem with ADC reads and multiple channels
2014-06-17 20:52:47 +01:00
Damien George
bcb3ab451b stmhal: Toggle LED using ODR ^= pin_mask. 2014-06-17 19:57:17 +01:00
Dave Hylands
535b88133c Fix problem with ADC reads and multiple channels 2014-06-16 09:41:58 -07:00
stijn
bbcea3f62b gc: More verbose debugging
Add more DEBUG_printf statements to trace gc behaviour
2014-06-16 12:43:35 +02:00
Dave Hylands
4f1b7fec9f Updated teensy to build.
Refactored some stmhal files which are shared with teensy.
2014-06-15 22:48:05 -07:00
Damien George
2547928148 stmhal: Add Python function to set UART for REPL.
This adds a hook to get/set pyb_uart_global_debug from Python, using
pyb.repl_uart().  You can set it to an arbitrary UART object, and then
the REPL (in and out) is repeated on this UART object (as well as on USB
CDC).

Ultimately, this will be replaced with a proper Pythonic interface to
set sys.stdin and sys.stdout.
2014-06-15 09:47:27 +01:00
Damien George
c0711cbefa stmhal: Fix type signatures on functions that take variable args. 2014-06-15 09:32:42 +01:00
Damien George
e79c6696c5 stmhal: Fix file print methods to use print instead of printf.
Also make stdout_print_strn static (ultimately this function needs to be
merged with stdout_tx_strn).
2014-06-15 09:10:07 +01:00
Damien George
34ab8dd6dd stmhal: Update and improve LCD driver.
Still some method names to iron out, and funtionality to add, but this
will do for the first, basic version.
2014-06-15 00:41:47 +01:00
Paul Sokolovsky
0294661da5 parsenum: Signedness issues.
char can be signedness, and using signedness types is dangerous - it can
lead to negative offsets when doing table lookups. We apparently should just
ban char usage.
2014-06-14 18:02:21 +03:00
Damien George
812025bd83 Merge pull request #693 from iabdalkader/assert
Add __assert_func
2014-06-14 15:51:40 +01:00
mux
5f6f47a688 Make __assert_func weak 2014-06-14 17:02:50 +02:00
mux
00db5c81e1 Add __assert_func only if DEBUG=1 2014-06-14 15:53:11 +02:00
mux
34e7b67d3c Add __assert_func
* issue #692
2014-06-14 14:41:11 +02:00
Paul Sokolovsky
e3cfc0d33d objstr: Refactor to work with char pointers instead of indexes.
In preparation for unicode support.
2014-06-14 06:30:30 +03:00
Paul Sokolovsky
7ddbd1bee7 unicode: Add trivial implementation of unichar_charlen(). 2014-06-14 06:30:30 +03:00
Paul Sokolovsky
b0bb458810 unicode: String API is const byte*.
We still have that char vs byte dichotomy, but majority of string operations
now use byte.
2014-06-14 06:22:11 +03:00
Paul Sokolovsky
2ec38a17d4 objstr: Be 8-bit clean even for repr().
This will allow roughly the same behavior as Python3 for non-ASCII strings,
for example, print("<phrase in non-Latin script>".split()) will print list
of words, not weird hex dump (like Python2 behaves). (Of course, that it
will print list of words, if there're "words" in that phrase at all, separated
by ASCII-compatible whitespace; that surely won't apply to every human
language in existence).
2014-06-14 01:21:13 +03:00
Damien George
e9036c295c Merge branch 'stinos-gc-pointers' 2014-06-13 22:34:11 +01:00
Damien George
c037694957 py, gc: Revert ret_ptr to void*, casting to byte* for memset. 2014-06-13 22:33:31 +01:00
Damien George
63b2237323 Merge branch 'gc-pointers' of github.com:stinos/micropython into stinos-gc-pointers 2014-06-13 22:30:46 +01:00
Paul Sokolovsky
e22cddbe2a stream: Use mp_obj_is_true() for EOF testing.
Getting a length of string may be expensive, depending on the underlying
implementation.
2014-06-13 23:53:10 +03:00
stijn
f33385f56d gc: Use byte* pointers instead of void* for pointer arithmetic
void* is of unknown size
2014-06-13 20:42:06 +02:00
576 changed files with 35821 additions and 9625 deletions

3
.gitignore vendored
View File

@@ -32,3 +32,6 @@ tests/*.out
# Python cache files
######################
__pycache__/
# Customized Makefile overrides
GNUmakefile

View File

@@ -15,9 +15,11 @@ script:
- make -C bare-arm
- make -C qemu-arm
- make -C stmhal
- make -C stmhal BOARD=STM32F4DISC
- make -C teensy
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
- (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests)
after_failure:
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff $testbase.exp $testbase.out; done)
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)

View File

@@ -92,4 +92,4 @@ You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
AUR. If the above does not work it may be because you don't have the
correct permissions. Try then:
$ sudo dfu-util -a 0 -D build-PYBV10/firmware.dfu
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu

View File

@@ -13,7 +13,7 @@ INC += -I$(PY_SRC)
INC += -I$(BUILD)
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)
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
#Debugging/Optimization
ifeq ($(DEBUG), 1)
@@ -22,7 +22,7 @@ else
CFLAGS += -Os -DNDEBUG
endif
LDFLAGS = --nostdlib -T stm32f405.ld
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
LIBS =
SRC_C = \

View File

@@ -53,7 +53,6 @@ void do_str(const char *src) {
}
int main(int argc, char **argv) {
qstr_init();
mp_init();
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\n')");
mp_deinit();

View File

@@ -12,10 +12,13 @@
#define MICROPY_HELPER_REPL (0)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (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_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
@@ -26,20 +29,24 @@
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
typedef int32_t machine_int_t; // must be pointer size
typedef uint32_t machine_uint_t; // must be pointer size
typedef int32_t mp_int_t; // must be pointer size
typedef uint32_t mp_uint_t; // must be pointer size
typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },

58
examples/pins.py Normal file
View File

@@ -0,0 +1,58 @@
# Print a nice list of pins, their current settings, and available afs.
# Requires pins_af.py from stmhal/build-PYBV10/ directory.
import pyb
import pins_af
def af():
max_name_width = 0
max_af_width = 0
for pin_entry in pins_af.PINS_AF:
max_name_width = max(max_name_width, len(pin_entry[0]))
for af_entry in pin_entry[1:]:
max_af_width = max(max_af_width, len(af_entry[1]))
for pin_entry in pins_af.PINS_AF:
pin_name = pin_entry[0]
print('%-*s ' % (max_name_width, pin_name), end='')
for af_entry in pin_entry[1:]:
print('%2d: %-*s ' % (af_entry[0], max_af_width, af_entry[1]), end='')
print('')
def pins():
mode_str = { pyb.Pin.IN : 'IN',
pyb.Pin.OUT_PP : 'OUT_PP',
pyb.Pin.OUT_OD : 'OUT_OD',
pyb.Pin.AF_PP : 'AF_PP',
pyb.Pin.AF_OD : 'AF_OD',
pyb.Pin.ANALOG : 'ANALOG' }
pull_str = { pyb.Pin.PULL_NONE : '',
pyb.Pin.PULL_UP : 'PULL_UP',
pyb.Pin.PULL_DOWN : 'PULL_DOWN' }
width = [0, 0, 0, 0]
rows = []
for pin_entry in pins_af.PINS_AF:
row = []
pin_name = pin_entry[0]
pin = pyb.Pin(pin_name)
pin_mode = pin.mode()
row.append(pin_name)
row.append(mode_str[pin_mode])
row.append(pull_str[pin.pull()])
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
pin_af = pin.af()
for af_entry in pin_entry[1:]:
if pin_af == af_entry[0]:
af_str = '%d: %s' % (pin_af, af_entry[1])
break
else:
af_str = '%d' % pin_af
else:
af_str = ''
row.append(af_str)
for col in range(len(width)):
width[col] = max(width[col], len(row[col]))
rows.append(row)
for row in rows:
for col in range(len(width)):
print('%-*s ' % (width[col], row[col]), end='')
print('')

595
extmod/miniz/tinfl.c Normal file
View File

@@ -0,0 +1,595 @@
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
See "unlicense" statement at the end of this file.
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
*/
#ifndef TINFL_HEADER_INCLUDED
#define TINFL_HEADER_INCLUDED
#include <stdlib.h>
typedef unsigned char mz_uint8;
typedef signed short mz_int16;
typedef unsigned short mz_uint16;
typedef unsigned int mz_uint32;
typedef unsigned int mz_uint;
typedef unsigned long long mz_uint64;
#if defined(_M_IX86) || defined(_M_X64)
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
#define MINIZ_LITTLE_ENDIAN 1
#endif
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
#define MINIZ_HAS_64BIT_REGISTERS 1
#endif
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
#ifdef _MSC_VER
#define MZ_MACRO_END while (0, 0)
#else
#define MZ_MACRO_END while (0)
#endif
// Decompression flags used by tinfl_decompress().
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
enum
{
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
TINFL_FLAG_HAS_MORE_INPUT = 2,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
TINFL_FLAG_COMPUTE_ADLER32 = 8
};
// High level decompression functions:
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
// On entry:
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
// On return:
// Function returns a pointer to the decompressed data, or NULL on failure.
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
// The caller must free() the returned block when it's no longer needed.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
// Returns 1 on success or 0 on failure.
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
// Max size of LZ dictionary.
#define TINFL_LZ_DICT_SIZE 32768
// Return status.
typedef enum
{
TINFL_STATUS_BAD_PARAM = -3,
TINFL_STATUS_ADLER32_MISMATCH = -2,
TINFL_STATUS_FAILED = -1,
TINFL_STATUS_DONE = 0,
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
TINFL_STATUS_HAS_MORE_OUTPUT = 2
} tinfl_status;
// Initializes the decompressor to its initial state.
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
#define tinfl_get_adler32(r) (r)->m_check_adler32
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
// Internal/private bits follow.
// dpgeorge: TINFL_FAST_LOOKUP_BITS can be adjusted to trade off RAM usage against speed.
enum
{
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
TINFL_FAST_LOOKUP_BITS = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
};
typedef struct
{
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
} tinfl_huff_table;
#if MINIZ_HAS_64BIT_REGISTERS
#define TINFL_USE_64BIT_BITBUF 1
#endif
#if TINFL_USE_64BIT_BITBUF
typedef mz_uint64 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (64)
#else
typedef mz_uint32 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (32)
#endif
struct tinfl_decompressor_tag
{
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
tinfl_bit_buf_t m_bit_buf;
size_t m_dist_from_out_buf_start;
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
};
#endif // #ifdef TINFL_HEADER_INCLUDED
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
#ifndef TINFL_HEADER_FILE_ONLY
#include <string.h>
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
#ifdef MINIZ_NO_MALLOC
#define MZ_MALLOC(x) NULL
#define MZ_FREE(x) x, ((void)0)
#define MZ_REALLOC(p, x) NULL
#else
#define MZ_MALLOC(x) malloc(x)
#define MZ_FREE(x) free(x)
#define MZ_REALLOC(p, x) realloc(p, x)
#endif
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
#else
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
#endif
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
#define TINFL_CR_FINISH }
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
#define TINFL_GET_BYTE(state_index, c) do { \
if (pIn_buf_cur >= pIn_buf_end) { \
for ( ; ; ) { \
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
if (pIn_buf_cur < pIn_buf_end) { \
c = *pIn_buf_cur++; \
break; \
} \
} else { \
c = 0; \
break; \
} \
} \
} else c = *pIn_buf_cur++; } MZ_MACRO_END
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
do { \
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
if (temp >= 0) { \
code_len = temp >> 9; \
if ((code_len) && (num_bits >= code_len)) \
break; \
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
code_len = TINFL_FAST_LOOKUP_BITS; \
do { \
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
} while (num_bits < 15);
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
// The slow path is only executed at the very end of the input buffer.
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
int temp; mz_uint code_len, c; \
if (num_bits < 15) { \
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
} else { \
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
} \
} \
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
code_len = temp >> 9, temp &= 511; \
else { \
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
{
static const mz_uint16 s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
static const mz_uint8 s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static const mz_uint16 s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static const mz_uint8 s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 };
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
TINFL_CR_BEGIN
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
}
do
{
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
if (r->m_type == 0)
{
TINFL_SKIP_BITS(5, num_bits & 7);
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
while ((counter) && (num_bits))
{
TINFL_GET_BITS(51, dist, 8);
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = (mz_uint8)dist;
counter--;
}
while (counter)
{
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
while (pIn_buf_cur >= pIn_buf_end)
{
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
{
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
}
else
{
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
}
}
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
}
}
else if (r->m_type == 3)
{
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
}
else
{
if (r->m_type == 1)
{
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
}
else
{
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
r->m_table_sizes[2] = 19;
}
for ( ; (int)r->m_type >= 0; r->m_type--)
{
int tree_next, tree_cur; tinfl_huff_table *pTable;
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
if ((65536 != total) && (used_syms > 1))
{
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
}
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
{
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
{
tree_cur -= ((rev_code >>= 1) & 1);
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
}
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
}
if (r->m_type == 2)
{
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
{
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
if ((dist == 16) && (!counter))
{
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
}
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
}
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
{
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
}
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
}
}
for ( ; ; )
{
mz_uint8 *pSrc;
for ( ; ; )
{
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
{
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
if (counter >= 256)
break;
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = (mz_uint8)counter;
}
else
{
int sym2; mz_uint code_len;
#if TINFL_USE_64BIT_BITBUF
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
#else
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
#endif
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
code_len = sym2 >> 9;
else
{
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
}
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
if (counter & 256)
break;
#if !TINFL_USE_64BIT_BITBUF
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
#endif
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
code_len = sym2 >> 9;
else
{
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
}
bit_buf >>= code_len; num_bits -= code_len;
pOut_buf_cur[0] = (mz_uint8)counter;
if (sym2 & 256)
{
pOut_buf_cur++;
counter = sym2;
break;
}
pOut_buf_cur[1] = (mz_uint8)sym2;
pOut_buf_cur += 2;
}
}
if ((counter &= 511) == 256) break;
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
{
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
}
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
{
while (counter--)
{
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
}
continue;
}
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
else if ((counter >= 9) && (counter <= dist))
{
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
do
{
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
pOut_buf_cur += 8;
} while ((pSrc += 8) < pSrc_end);
if ((counter &= 7) < 3)
{
if (counter)
{
pOut_buf_cur[0] = pSrc[0];
if (counter > 1)
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur += counter;
}
continue;
}
}
#endif
do
{
pOut_buf_cur[0] = pSrc[0];
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur[2] = pSrc[2];
pOut_buf_cur += 3; pSrc += 3;
} while ((int)(counter -= 3) > 2);
if ((int)counter > 0)
{
pOut_buf_cur[0] = pSrc[0];
if ((int)counter > 1)
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur += counter;
}
}
}
} while (!(r->m_final & 1));
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
}
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
TINFL_CR_FINISH
common_exit:
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
{
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
while (buf_len)
{
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
{
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
}
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
}
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
}
return status;
}
#if 0
// Higher level helper functions.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
{
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
*pOut_len = 0;
tinfl_init(&decomp);
for ( ; ; )
{
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
{
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
}
src_buf_ofs += src_buf_size;
*pOut_len += dst_buf_size;
if (status == TINFL_STATUS_DONE) break;
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
if (!pNew_buf)
{
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
}
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
}
return pBuf;
}
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
{
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
}
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
{
int result = 0;
tinfl_decompressor decomp;
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
if (!pDict)
return TINFL_STATUS_FAILED;
tinfl_init(&decomp);
for ( ; ; )
{
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
in_buf_ofs += in_buf_size;
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
break;
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
{
result = (status == TINFL_STATUS_DONE);
break;
}
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
}
MZ_FREE(pDict);
*pIn_buf_size = in_buf_ofs;
return result;
}
#endif
#endif // #ifndef TINFL_HEADER_FILE_ONLY
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/

634
extmod/moductypes.c Normal file
View File

@@ -0,0 +1,634 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "objtuple.h"
#include "binary.h"
#if MICROPY_PY_UCTYPES
/// \module uctypes - Access data structures in memory
///
/// The module allows to define layout of raw data structure (using terms
/// of C language), and then access memory buffers using this definition.
/// The module also provides convenience functions to access memory buffers
/// contained in Python objects or wrap memory buffers in Python objects.
/// \constant UINT8_1 - uint8_t value type
/// \class struct - C-like structure
///
/// Encapsulalation of in-memory data structure. This class doesn't define
/// any methods, only attribute access (for structure fields) and
/// indexing (for pointer and array fields).
///
/// Usage:
///
/// # Define layout of a structure with 2 fields
/// # 0 and 4 are byte offsets of fields from the beginning of struct
/// # they are logically ORed with field type
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
///
/// # Example memory buffer to access (contained in bytes object)
/// buf = b"\x64\0\0\0\0x14"
///
/// # Create structure object referring to address of
/// # the data in the buffer above
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
///
/// # Access fields
/// print(s.a, s.b)
/// # Result:
/// # 100, 20
#define LAYOUT_LITTLE_ENDIAN (0)
#define LAYOUT_BIG_ENDIAN (1)
#define LAYOUT_NATIVE (2)
#define VAL_TYPE_BITS 4
#define BITF_LEN_BITS 5
#define BITF_OFF_BITS 5
#define OFFSET_BITS 17
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
#error Invalid encoding field length
#endif
enum {
UINT8, INT8, UINT16, INT16,
UINT32, INT32, UINT64, INT64,
BFUINT8, BFINT8, BFUINT16, BFINT16,
BFUINT32, BFINT32,
FLOAT32, FLOAT64,
};
#define AGG_TYPE_BITS 2
enum {
STRUCT, PTR, ARRAY, BITFIELD,
};
// Here we need to set sign bit right
#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1));
// Bit 0 is "is_signed"
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
STATIC const mp_obj_type_t uctypes_struct_type;
typedef struct _mp_obj_uctypes_struct_t {
mp_obj_base_t base;
mp_obj_t desc;
byte *addr;
uint32_t flags;
} mp_obj_uctypes_struct_t;
STATIC NORETURN void syntax_error() {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
}
STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
if (n_args < 2 || n_args > 3) {
syntax_error();
}
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
o->base.type = type_in;
o->desc = args[0];
o->addr = (void*)mp_obj_get_int(args[1]);
o->flags = LAYOUT_NATIVE;
if (n_args == 3) {
o->flags = mp_obj_get_int(args[2]);
}
return o;
}
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_uctypes_struct_t *self = self_in;
const char *typen = "unk";
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
typen = "STRUCT";
} else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
switch (agg_type) {
case PTR: typen = "PTR"; break;
case ARRAY: typen = "ARRAY"; break;
}
} else {
typen = "ERROR";
}
print(env, "<struct %s %p>", typen, self->addr);
}
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
if (val_type == FLOAT32) {
return 4;
} else {
return GET_SCALAR_SIZE(val_type & 7);
}
}
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
mp_obj_dict_t *d = desc_in;
mp_uint_t total_size = 0;
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
syntax_error();
}
for (mp_uint_t i = 0; i < d->map.alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) {
mp_obj_t v = d->map.table[i].value;
if (MP_OBJ_IS_SMALL_INT(v)) {
mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
offset &= VALUE_MASK(VAL_TYPE_BITS);
mp_uint_t s = uctypes_struct_scalar_size(val_type);
if (s > *max_field_size) {
*max_field_size = s;
}
if (offset + s > total_size) {
total_size = offset + s;
}
} else {
if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) {
syntax_error();
}
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
offset &= VALUE_MASK(AGG_TYPE_BITS);
switch (agg_type) {
case STRUCT: {
mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
if (offset + s > total_size) {
total_size = offset + s;
}
break;
}
case PTR: {
if (offset + sizeof(void*) > total_size) {
total_size = offset + sizeof(void*);
}
if (sizeof(void*) > *max_field_size) {
*max_field_size = sizeof(void*);
}
break;
}
case ARRAY: {
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
mp_uint_t item_s;
if (t->len == 2) {
item_s = GET_SCALAR_SIZE(val_type);
if (item_s > *max_field_size) {
*max_field_size = item_s;
}
} else {
item_s = uctypes_struct_size(t->items[2], max_field_size);
}
mp_uint_t byte_sz = item_s * arr_sz;
if (offset + byte_sz > total_size) {
total_size = offset + byte_sz;
}
break;
}
default:
assert(0);
}
}
}
}
// Round size up to alignment of biggest field
total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
return total_size;
}
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
mp_uint_t max_field_size = 0;
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
mp_obj_uctypes_struct_t *obj = obj_in;
obj_in = obj->desc;
}
mp_uint_t size = uctypes_struct_size(obj_in, &max_field_size);
return MP_OBJ_NEW_SMALL_INT(size);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_sizeof_obj, uctypes_struct_sizeof);
STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
mp_int_t val = mp_binary_get_int(GET_SCALAR_SIZE(val_type), val_type & 1, big_endian, p);
if (val_type == UINT32) {
return mp_obj_new_int_from_uint(val);
} else {
return mp_obj_new_int(val);
}
}
STATIC inline void set_unaligned(uint val_type, void *p, int big_endian, mp_obj_t val) {
char struct_type = big_endian ? '>' : '<';
static const char type2char[8] = "BbHhIiQq";
mp_binary_set_val(struct_type, type2char[val_type], val, (byte**)&p);
}
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
switch (val_type) {
case UINT8:
return *(uint8_t*)p;
case UINT16:
return *(uint16_t*)p;
case UINT32:
return *(uint32_t*)p;
}
assert(0);
return 0;
}
static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
switch (val_type) {
case UINT8:
*(uint8_t*)p = (uint8_t)v; return;
case UINT16:
*(uint16_t*)p = (uint16_t)v; return;
case UINT32:
*(uint32_t*)p = (uint32_t)v; return;
}
assert(0);
}
STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
switch (val_type) {
case UINT8:
return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]);
case INT8:
return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]);
case UINT16:
return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]);
case INT16:
return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]);
case UINT32:
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
case INT32:
return mp_obj_new_int(((int32_t*)p)[index]);
case UINT64:
case INT64:
return mp_obj_new_int_from_ll(((int64_t*)p)[index]);
case FLOAT32:
return mp_obj_new_float(((float*)p)[index]);
case FLOAT64:
return mp_obj_new_float(((double*)p)[index]);
default:
assert(0);
return MP_OBJ_NULL;
}
}
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
mp_int_t v = mp_obj_get_int(val);
switch (val_type) {
case UINT8:
((uint8_t*)p)[index] = (uint8_t)v; return;
case INT8:
((int8_t*)p)[index] = (int8_t)v; return;
case UINT16:
((uint16_t*)p)[index] = (uint16_t)v; return;
case INT16:
((int16_t*)p)[index] = (int16_t)v; return;
case UINT32:
((uint32_t*)p)[index] = (uint32_t)v; return;
case INT32:
((int32_t*)p)[index] = (int32_t)v; return;
default:
assert(0);
}
}
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
mp_obj_uctypes_struct_t *self = self_in;
// TODO: Support at least OrderedDict in addition
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: no fields"));
}
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
if (MP_OBJ_IS_SMALL_INT(deref)) {
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
offset &= VALUE_MASK(VAL_TYPE_BITS);
//printf("scalar type=%d offset=%x\n", val_type, offset);
if (val_type <= INT64) {
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
if (self->flags == LAYOUT_NATIVE) {
if (set_val == MP_OBJ_NULL) {
return get_aligned(val_type, self->addr + offset, 0);
} else {
set_aligned(val_type, self->addr + offset, 0, set_val);
return set_val; // just !MP_OBJ_NULL
}
} else {
if (set_val == MP_OBJ_NULL) {
return get_unaligned(val_type, self->addr + offset, self->flags);
} else {
set_unaligned(val_type, self->addr + offset, self->flags, set_val);
return set_val; // just !MP_OBJ_NULL
}
}
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
uint bit_offset = (offset >> 17) & 31;
uint bit_len = (offset >> 22) & 31;
offset &= (1 << 17) - 1;
mp_uint_t val;
if (self->flags == LAYOUT_NATIVE) {
val = get_aligned_basic(val_type & 6, self->addr + offset);
} else {
val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
}
if (set_val == MP_OBJ_NULL) {
val >>= bit_offset;
val &= (1 << bit_len) - 1;
// TODO: signed
assert((val_type & 1) == 0);
return mp_obj_new_int(val);
} else {
mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
mp_uint_t mask = (1 << bit_len) - 1;
set_val_int &= mask;
set_val_int <<= bit_offset;
mask <<= bit_offset;
val = (val & ~mask) | set_val_int;
if (self->flags == LAYOUT_NATIVE) {
set_aligned_basic(val_type & 6, self->addr + offset, val);
} else {
mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
self->addr + offset, (byte*)&val);
}
return set_val; // just !MP_OBJ_NULL
}
}
assert(0);
return MP_OBJ_NULL;
}
if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) {
syntax_error();
}
if (set_val != MP_OBJ_NULL) {
// Cannot assign to aggregate
syntax_error();
}
mp_obj_tuple_t *sub = (mp_obj_tuple_t*)deref;
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
offset &= VALUE_MASK(AGG_TYPE_BITS);
//printf("agg type=%d offset=%x\n", agg_type, offset);
switch (agg_type) {
case STRUCT: {
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
o->base.type = &uctypes_struct_type;
o->desc = sub->items[1];
o->addr = self->addr + offset;
o->flags = self->flags;
return o;
}
case PTR: case ARRAY: {
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
o->base.type = &uctypes_struct_type;
o->desc = sub;
o->addr = self->addr + offset;
o->flags = self->flags;
//printf("PTR/ARR base addr=%p\n", o->addr);
return o;
}
}
// Should be unreachable once all cases are handled
return MP_OBJ_NULL;
}
STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
*dest = val;
}
STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
}
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
mp_obj_uctypes_struct_t *self = self_in;
if (value == MP_OBJ_NULL) {
// delete
return MP_OBJ_NULL; // op not supported
} else if (value == MP_OBJ_SENTINEL) {
// load
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: cannot index"));
}
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
if (agg_type == ARRAY) {
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
if (index >= arr_sz) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range"));
}
if (t->len == 2) {
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
return get_unaligned(val_type, p, self->flags);
} else {
mp_uint_t dummy = 0;
mp_uint_t size = uctypes_struct_size(t->items[2], &dummy);
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
o->base.type = &uctypes_struct_type;
o->desc = t->items[2];
o->addr = self->addr + size * index;
o->flags = self->flags;
return o;
}
} else if (agg_type == PTR) {
byte *p = *(void**)self->addr;
if (MP_OBJ_IS_SMALL_INT(t->items[1])) {
uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
return get_aligned(val_type, p, index);
} else {
mp_uint_t dummy = 0;
mp_uint_t size = uctypes_struct_size(t->items[1], &dummy);
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
o->base.type = &uctypes_struct_type;
o->desc = t->items[1];
o->addr = p + size * index;
o->flags = self->flags;
return o;
}
}
assert(0);
return MP_OBJ_NULL;
} else {
// store
return MP_OBJ_NULL; // op not supported
}
}
/// \function addressof()
/// Return address of object's data (applies to object providing buffer
/// interface).
mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
return mp_obj_new_int((mp_int_t)bufinfo.buf);
}
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
/// \function bytearray_at()
/// Capture memory at given address of given size as bytearray. Memory is
/// captured by reference (and thus memory pointed by bytearray may change
/// or become invalid at later time). Use bytes_at() to capture by value.
mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr));
}
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
/// \function bytes_at()
/// Capture memory at given address of given size as bytes. Memory is
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
/// ("zero copy").
mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
return mp_obj_new_bytes((void*)mp_obj_int_get(ptr), mp_obj_int_get(size));
}
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
STATIC const mp_obj_type_t uctypes_struct_type = {
{ &mp_type_type },
.name = MP_QSTR_struct,
.print = uctypes_struct_print,
.make_new = uctypes_struct_make_new,
.load_attr = uctypes_struct_load_attr,
.store_attr = uctypes_struct_store_attr,
.subscr = uctypes_struct_subscr,
};
STATIC const mp_map_elem_t mp_module_uctypes_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uctypes) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&uctypes_struct_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sizeof), (mp_obj_t)&uctypes_struct_sizeof_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_addressof), (mp_obj_t)&uctypes_struct_addressof_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes_at), (mp_obj_t)&uctypes_struct_bytes_at_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray_at), (mp_obj_t)&uctypes_struct_bytearray_at_obj },
/// \moduleref uctypes
/// \constant NATIVE - Native structure layout - native endianness,
/// platform-specific field alignment
{ MP_OBJ_NEW_QSTR(MP_QSTR_NATIVE), MP_OBJ_NEW_SMALL_INT(LAYOUT_NATIVE) },
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
/// (no alignment constraints)
{ MP_OBJ_NEW_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_LITTLE_ENDIAN) },
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
/// (no alignment constraints)
{ MP_OBJ_NEW_QSTR(MP_QSTR_BIG_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_BIG_ENDIAN) },
/// \constant VOID - void value type, may be used only as pointer target type.
{ MP_OBJ_NEW_QSTR(MP_QSTR_VOID), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
/// \constant UINT8 - uint8_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, 4)) },
/// \constant INT8 - int8_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT8, 4)) },
/// \constant UINT16 - uint16_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT16, 4)) },
/// \constant INT16 - int16_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT16, 4)) },
/// \constant UINT32 - uint32_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT32, 4)) },
/// \constant INT32 - int32_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT32, 4)) },
/// \constant UINT64 - uint64_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT64, 4)) },
/// \constant INT64 - int64_t value type
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT64, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT8, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT8, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT16, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT16, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT32, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT32, 4)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_POS), MP_OBJ_NEW_SMALL_INT(17) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_LEN), MP_OBJ_NEW_SMALL_INT(22) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PTR), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ARRAY), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
};
STATIC const mp_obj_dict_t mp_module_uctypes_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
.table = (mp_map_elem_t*)mp_module_uctypes_globals_table,
},
};
const mp_obj_module_t mp_module_uctypes = {
.base = { &mp_type_module },
.name = MP_QSTR_uctypes,
.globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,
};
#endif

108
extmod/modzlibd.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#if MICROPY_PY_ZLIBD
#include "miniz/tinfl.c"
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
mp_obj_t data = args[0];
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
tinfl_decompressor *decomp = m_new_obj(tinfl_decompressor);
tinfl_init(decomp);
DEBUG_printf("sizeof(tinfl_decompressor)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
byte *out = m_new(byte, bufinfo.len);
size_t out_len = bufinfo.len;
size_t in_buf_ofs = 0, dst_buf_ofs = 0;
size_t dst_buf_sz = bufinfo.len;
while (1) {
size_t in_buf_sz = bufinfo.len - in_buf_ofs;
DEBUG_printf("tinfl in: in_ofs=%d in_sz=%d dst_ofs=%d, dst_sz=%d\n", in_buf_ofs, in_buf_sz, dst_buf_ofs, dst_buf_sz);
tinfl_status st = tinfl_decompress(decomp,
bufinfo.buf + in_buf_ofs, &in_buf_sz,
out, out + dst_buf_ofs, &dst_buf_sz,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER);
DEBUG_printf("tinfl out: st=%d, in_sz=%d, out_sz=%d\n", st, in_buf_sz, dst_buf_sz);
in_buf_ofs += in_buf_sz;
dst_buf_ofs += dst_buf_sz;
if (st != TINFL_STATUS_HAS_MORE_OUTPUT) {
break;
}
out = m_renew(byte, out, out_len, dst_buf_ofs + 256);
out_len = dst_buf_ofs + 256;
dst_buf_sz = out_len - dst_buf_ofs;
}
m_del_obj(tinfl_decompressor, decomp);
return mp_obj_new_bytearray_by_ref(dst_buf_ofs, out);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_zlibd_decompress_obj, 1, 3, mod_zlibd_decompress);
STATIC const mp_map_elem_t mp_module_zlibd_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_zlibd) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_zlibd_decompress_obj },
};
STATIC const mp_obj_dict_t mp_module_zlibd_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
.table = (mp_map_elem_t*)mp_module_zlibd_globals_table,
},
};
const mp_obj_module_t mp_module_zlibd = {
.base = { &mp_type_module },
.name = MP_QSTR_zlibd,
.globals = (mp_obj_dict_t*)&mp_module_zlibd_globals,
};
#endif //MICROPY_PY_ZLIBD

327
py/asmarm.c Normal file
View File

@@ -0,0 +1,327 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Fabian Vogt
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "asmarm.h"
// wrapper around everything in this file
#if MICROPY_EMIT_ARM
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
struct _asm_arm_t {
uint pass;
uint code_offset;
uint code_size;
byte *code_base;
byte dummy_data[4];
uint max_num_labels;
int *label_offsets;
int num_locals;
uint push_reglist;
uint stack_adjust;
};
asm_arm_t *asm_arm_new(uint max_num_labels) {
asm_arm_t *as;
as = m_new0(asm_arm_t, 1);
as->max_num_labels = max_num_labels;
as->label_offsets = m_new(int, max_num_labels);
return as;
}
void asm_arm_free(asm_arm_t *as, bool free_code) {
if (free_code) {
m_del(byte, as->code_base, as->code_size);
}
m_del_obj(asm_arm_t, as);
}
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_ARM_PASS_COMPUTE) {
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
}
}
void asm_arm_end_pass(asm_arm_t *as) {
if (as->pass == ASM_ARM_PASS_COMPUTE) {
// calculate size of code in bytes
as->code_size = as->code_offset;
as->code_base = m_new(byte, as->code_size);
}
}
// all functions must go through this one to emit bytes
// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length
STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) {
if (as->pass < ASM_ARM_PASS_EMIT) {
as->code_offset += num_bytes_to_write;
return as->dummy_data;
} else {
assert(as->code_offset + num_bytes_to_write <= as->code_size);
byte *c = as->code_base + as->code_offset;
as->code_offset += num_bytes_to_write;
return c;
}
}
uint asm_arm_get_code_size(asm_arm_t *as) {
return as->code_size;
}
void *asm_arm_get_code(asm_arm_t *as) {
return as->code_base;
}
// Insert word into instruction flow
STATIC void emit(asm_arm_t *as, uint op) {
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
}
// Insert word into instruction flow, add "ALWAYS" condition code
STATIC void emit_al(asm_arm_t *as, uint op) {
emit(as, op | ARM_CC_AL);
}
// Basic instructions without condition code
STATIC uint asm_arm_op_push(uint reglist) {
// stmfd sp!, {reglist}
return 0x92d0000 | (reglist & 0xFFFF);
}
STATIC uint asm_arm_op_pop(uint reglist) {
// ldmfd sp!, {reglist}
return 0x8bd0000 | (reglist & 0xFFFF);
}
STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) {
// mov rd, rn
return 0x1a00000 | (rd << 12) | rn;
}
STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) {
// mov rd, #imm
return 0x3a00000 | (rd << 12) | imm;
}
STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) {
// mvn rd, #imm
return 0x3e00000 | (rd << 12) | imm;
}
STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) {
// add rd, rn, #imm
return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
}
STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) {
// add rd, rn, rm
return 0x0800000 | (rn << 16) | (rd << 12) | rm;
}
STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) {
// sub rd, rn, #imm
return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
}
void asm_arm_bkpt(asm_arm_t *as) {
// bkpt #0
emit_al(as, 0x1200070);
}
// locals:
// - stored on the stack in ascending order
// - numbered 0 through as->num_locals-1
// - SP points to first local
//
// | SP
// v
// l0 l1 l2 ... l(n-1)
// ^ ^
// | low address | high address in RAM
void asm_arm_entry(asm_arm_t *as, int num_locals) {
if (num_locals < 0) {
num_locals = 0;
}
as->stack_adjust = 0;
as->num_locals = num_locals;
as->push_reglist = 1 << REG_R1 | 1 << REG_R2 | 1 << REG_R3 | 1 << REG_R4
| 1 << REG_R5 | 1 << REG_R6 | 1 << REG_R7 | 1 << REG_R8;
// Only adjust the stack if there are more locals than usable registers
if(num_locals > 3) {
as->stack_adjust = num_locals * 4;
// Align stack to 8 bytes
if(as->num_locals & 1)
as->stack_adjust += 4;
}
emit_al(as, asm_arm_op_push(as->push_reglist | 1 << REG_LR));
if (as->stack_adjust > 0) {
emit_al(as, asm_arm_op_sub_imm(REG_SP, REG_SP, as->stack_adjust));
}
}
void asm_arm_exit(asm_arm_t *as) {
if (as->stack_adjust > 0) {
emit_al(as, asm_arm_op_add_imm(REG_SP, REG_SP, as->stack_adjust));
}
emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << REG_PC)));
}
void asm_arm_label_assign(asm_arm_t *as, uint label) {
assert(label < as->max_num_labels);
if (as->pass < ASM_ARM_PASS_EMIT) {
// assign label offset
assert(as->label_offsets[label] == -1);
as->label_offsets[label] = as->code_offset;
} else {
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
assert(as->label_offsets[label] == as->code_offset);
}
}
void asm_arm_align(asm_arm_t* as, uint align) {
// TODO fill unused data with NOPs?
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
}
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) {
byte *c = asm_arm_get_cur_to_write_bytes(as, bytesize);
// only write to the buffer in the emit pass (otherwise we overflow dummy_data)
if (as->pass == ASM_ARM_PASS_EMIT) {
// little endian
for (uint i = 0; i < bytesize; i++) {
*c++ = val;
val >>= 8;
}
}
}
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {
emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
}
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) {
// TODO: There are more variants of immediate values
if ((imm & 0xFF) == imm) {
emit_al(as, asm_arm_op_mov_imm(rd, imm));
} else if (imm < 0 && ((-imm) & 0xFF) == -imm) {
emit_al(as, asm_arm_op_mvn_imm(rd, -imm));
} else {
//Insert immediate into code and jump over it
emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc]
emit_al(as, 0xa000000); // b pc
emit(as, imm);
}
}
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) {
// str rd, [sp, #local_num*4]
emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2));
}
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) {
// ldr rd, [sp, #local_num*4]
emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2));
}
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) {
// cmp rd, #imm
emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF));
}
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
// cmp rd, rn
emit_al(as, 0x1500000 | (rd << 16) | rn);
}
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn) {
asm_arm_cmp_reg_reg(as, rd, rn); // cmp rd, rn
emit(as, asm_arm_op_mov_imm(REG_RET, 1) | ARM_CC_LT); // movlt REG_RET, #1
emit(as, asm_arm_op_mov_imm(REG_RET, 0) | ARM_CC_GE); // movge REG_RET, #0
}
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
// add rd, rn, rm
emit_al(as, asm_arm_op_add_reg(rd, rn, rm));
}
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {
// add rd, sp, #local_num*4
emit_al(as, asm_arm_op_add_imm(rd, REG_SP, local_num << 2));
}
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
assert(label < as->max_num_labels);
int dest = as->label_offsets[label];
int rel = dest - as->code_offset;
rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction
rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted
if (SIGNED_FIT24(rel)) {
emit(as, cond | 0xa000000 | (rel & 0xffffff));
} else {
printf("asm_arm_bcc: branch does not fit in 24 bits\n");
}
}
void asm_arm_b_label(asm_arm_t *as, uint label) {
asm_arm_bcc_label(as, ARM_CC_AL, label);
}
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
// If the table offset fits into the ldr instruction
if(fun_id < (0x1000 / 4)) {
emit_al(as, asm_arm_op_mov_reg(REG_LR, REG_PC)); // mov lr, pc
emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4]
return;
}
emit_al(as, 0x59f0004 | (reg_temp << 12)); // ldr rd, [pc, #4]
// Set lr after fun_ptr
emit_al(as, asm_arm_op_add_imm(REG_LR, REG_PC, 4)); // add lr, pc, #4
emit_al(as, asm_arm_op_mov_reg(REG_PC, reg_temp)); // mov pc, reg_temp
emit(as, (uint) fun_ptr);
}
#endif // MICROPY_EMIT_ARM

104
py/asmarm.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Fabian Vogt
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define ASM_ARM_PASS_COMPUTE (1)
#define ASM_ARM_PASS_EMIT (2)
#define REG_R0 (0)
#define REG_R1 (1)
#define REG_R2 (2)
#define REG_R3 (3)
#define REG_R4 (4)
#define REG_R5 (5)
#define REG_R6 (6)
#define REG_R7 (7)
#define REG_R8 (8)
#define REG_R9 (9)
#define REG_R10 (10)
#define REG_R11 (11)
#define REG_R12 (12)
#define REG_R13 (13)
#define REG_R14 (14)
#define REG_R15 (15)
#define REG_SP (REG_R13)
#define REG_LR (REG_R14)
#define REG_PC (REG_R15)
#define REG_RET REG_R0
#define REG_ARG_1 REG_R0
#define REG_ARG_2 REG_R1
#define REG_ARG_3 REG_R2
#define REG_ARG_4 REG_R3
#define ARM_CC_EQ (0x0 << 28)
#define ARM_CC_NE (0x1 << 28)
#define ARM_CC_CS (0x2 << 28)
#define ARM_CC_CC (0x3 << 28)
#define ARM_CC_MI (0x4 << 28)
#define ARM_CC_PL (0x5 << 28)
#define ARM_CC_VS (0x6 << 28)
#define ARM_CC_VC (0x7 << 28)
#define ARM_CC_HI (0x8 << 28)
#define ARM_CC_LS (0x9 << 28)
#define ARM_CC_GE (0xa << 28)
#define ARM_CC_LT (0xb << 28)
#define ARM_CC_GT (0xc << 28)
#define ARM_CC_LE (0xd << 28)
#define ARM_CC_AL (0xe << 28)
typedef struct _asm_arm_t asm_arm_t;
asm_arm_t *asm_arm_new(uint max_num_labels);
void asm_arm_free(asm_arm_t *as, bool free_code);
void asm_arm_start_pass(asm_arm_t *as, uint pass);
void asm_arm_end_pass(asm_arm_t *as);
uint asm_arm_get_code_size(asm_arm_t *as);
void *asm_arm_get_code(asm_arm_t *as);
void asm_arm_entry(asm_arm_t *as, int num_locals);
void asm_arm_exit(asm_arm_t *as);
void asm_arm_label_assign(asm_arm_t *as, uint label);
void asm_arm_align(asm_arm_t* as, uint align);
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val);
void asm_arm_bkpt(asm_arm_t *as);
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn);
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
void asm_arm_b_label(asm_arm_t *as, uint label);
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);

View File

@@ -28,8 +28,8 @@
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "asmthumb.h"
// wrapper around everything in this file
@@ -132,8 +132,7 @@ uint asm_thumb_get_code_size(asm_thumb_t *as) {
}
void *asm_thumb_get_code(asm_thumb_t *as) {
// need to set low bit to indicate that it's thumb code
return (void *)(((machine_uint_t)as->code_base) | 1);
return as->code_base;
}
/*
@@ -378,7 +377,7 @@ void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) {
}
}
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32) {
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
// movw, movt does it in 8 bytes
// ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
@@ -496,17 +495,14 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
asm_thumb_op16(as, 0x4780 | (REG_R9 << 3)); // blx reg
*/
if (0) {
// load ptr to function into register using immediate, then branch
// not relocatable
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
asm_thumb_op16(as, OP_BLX(reg_temp));
} else if (1) {
if (fun_id < 32) {
// load ptr to function from table, indexed by fun_id (must be in range 0-31); 4 bytes
asm_thumb_op16(as, OP_FORMAT_9_10(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, reg_temp, REG_R7, fun_id));
asm_thumb_op16(as, OP_BLX(reg_temp));
} else {
// use SVC
asm_thumb_op16(as, OP_SVC(fun_id));
// load ptr to function into register using immediate; 6 bytes
asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
asm_thumb_op16(as, OP_BLX(reg_temp));
}
}

View File

@@ -185,7 +185,7 @@ void asm_thumb_ite_ge(asm_thumb_t *as);
void asm_thumb_b_n(asm_thumb_t *as, uint label);
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32); // convenience
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience

View File

@@ -29,8 +29,8 @@
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
// wrapper around everything in this file
#if MICROPY_EMIT_X64

View File

@@ -50,11 +50,11 @@ typedef struct _mp_code_state {
} 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_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t 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
#define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1)))
#define MP_TAGPTR_TAG(x) ((machine_uint_t)(x) & 1)
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((machine_uint_t)(ptr) | tag))
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))

View File

@@ -26,17 +26,22 @@
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "binary.h"
// Helpers to work with binary-encoded data
#ifndef alignof
#define alignof(type) offsetof(struct { char c; type t; }, t)
#endif
int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
int size = 0;
int align = 1;
@@ -68,16 +73,20 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
case 'b': case 'B':
align = size = 1; break;
case 'h': case 'H':
align = size = sizeof(short); break;
align = alignof(short);
size = sizeof(short); break;
case 'i': case 'I':
align = size = sizeof(int); break;
align = alignof(int);
size = sizeof(int); break;
case 'l': case 'L':
align = size = sizeof(long); break;
align = alignof(long);
size = sizeof(long); break;
case 'q': case 'Q':
// TODO: This is for x86
align = sizeof(int); size = sizeof(long long); break;
align = alignof(long long);
size = sizeof(long long); break;
case 'P': case 'O': case 'S':
align = size = sizeof(void*); break;
align = alignof(void*);
size = sizeof(void*); break;
}
}
}
@@ -88,7 +97,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
}
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
machine_int_t val = 0;
mp_int_t val = 0;
switch (typecode) {
case 'b':
val = ((int8_t*)p)[index];
@@ -125,32 +134,17 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
return MP_OBJ_NEW_SMALL_INT(val);
}
#define is_signed(typecode) (typecode > 'Z')
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
byte *p = *ptr;
uint align;
int size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {
// Make pointer aligned
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
#if MP_ENDIANNESS_LITTLE
struct_type = '<';
#else
struct_type = '>';
#endif
}
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) {
int delta;
if (struct_type == '<') {
if (!big_endian) {
delta = -1;
p += size - 1;
} else {
delta = 1;
}
machine_int_t val = 0;
if (is_signed(val_type) && *p & 0x80) {
mp_int_t val = 0;
if (is_signed && *p & 0x80) {
val = -1;
}
for (uint i = 0; i < size; i++) {
@@ -159,7 +153,28 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
p += delta;
}
*ptr += size;
return val;
}
#define is_signed(typecode) (typecode > 'Z')
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
byte *p = *ptr;
uint align;
int size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {
// Make pointer aligned
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
#if MP_ENDIANNESS_LITTLE
struct_type = '<';
#else
struct_type = '>';
#endif
}
*ptr = p + size;
mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
if (val_type == 'O') {
return (mp_obj_t)val;
} else if (val_type == 'S') {
@@ -171,6 +186,23 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
}
}
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
int in_delta, out_delta;
if (big_endian) {
in_delta = -1;
out_delta = 1;
val_ptr += val_sz - 1;
} else {
in_delta = out_delta = 1;
}
for (uint i = val_sz; i > 0; i--) {
*p = *val_ptr;
p += out_delta;
val_ptr += in_delta;
}
}
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
byte *p = *ptr;
uint align;
@@ -178,18 +210,19 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
int size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {
// Make pointer aligned
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
#if MP_ENDIANNESS_LITTLE
struct_type = '<';
#else
struct_type = '>';
#endif
}
*ptr = p + size;
#if MP_ENDIANNESS_BIG
#error Not implemented
#endif
machine_int_t val;
mp_int_t val;
byte *in = (byte*)&val;
switch (val_type) {
case 'O':
@@ -199,23 +232,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
val = mp_obj_get_int(val_in);
}
int in_delta, out_delta;
uint val_sz = MIN(size, sizeof(val));
if (struct_type == '>') {
in_delta = -1;
out_delta = 1;
in += val_sz - 1;
} else {
in_delta = out_delta = 1;
}
for (uint i = val_sz; i > 0; i--) {
*p = *in;
p += out_delta;
in += in_delta;
}
*ptr += size;
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
}
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
@@ -233,7 +250,7 @@ void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in)
}
}
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
switch (typecode) {
case 'b':
((int8_t*)p)[index] = val;

View File

@@ -31,6 +31,8 @@
int mp_binary_get_size(char struct_type, char val_type, uint *palign);
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val);
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val);
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p);
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr);

View File

@@ -36,6 +36,8 @@
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "stream.h"
#include "pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
@@ -97,9 +99,9 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
if (MP_OBJ_IS_SMALL_INT(o_in)) {
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
if (val < 0) {
val = -val;
}
@@ -113,10 +115,12 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
} else {
return o_in;
}
#if MICROPY_PY_BUILTINS_COMPLEX
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) {
mp_float_t real, imag;
mp_obj_complex_get(o_in, &real, &imag);
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag));
#endif
#endif
} else {
assert(0);
@@ -154,7 +158,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
return mp_obj_str_format(ARRAY_SIZE(args), args);
return mp_obj_str_format(MP_ARRAY_SIZE(args), args);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
@@ -170,13 +174,40 @@ STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
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 MICROPY_PY_BUILTINS_STR_UNICODE
mp_uint_t c = mp_obj_get_int(o_in);
char str[4];
int len = 0;
if (c < 0x80) {
*str = c; len = 1;
} else if (c < 0x800) {
str[0] = (c >> 6) | 0xC0;
str[1] = (c & 0x3F) | 0x80;
len = 2;
} else if (c < 0x10000) {
str[0] = (c >> 12) | 0xE0;
str[1] = ((c >> 6) & 0x3F) | 0x80;
str[2] = (c & 0x3F) | 0x80;
len = 3;
} else if (c < 0x110000) {
str[0] = (c >> 18) | 0xF0;
str[1] = ((c >> 12) & 0x3F) | 0x80;
str[2] = ((c >> 6) & 0x3F) | 0x80;
str[3] = (c & 0x3F) | 0x80;
len = 4;
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
}
return mp_obj_new_str(str, len, true);
#else
mp_int_t ord = mp_obj_get_int(o_in);
if (0 <= ord && ord <= 0x10ffff) {
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)"));
}
#endif
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
@@ -221,8 +252,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
mp_obj_t args[2];
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
@@ -253,74 +284,50 @@ STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in);
if (len == NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
} else {
return len;
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_builtin_len);
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_min_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs, int op) {
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP);
mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value;
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_t max_obj = NULL;
mp_obj_t best_key = MP_OBJ_NULL;
mp_obj_t best_obj = MP_OBJ_NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (max_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, max_obj, item) == mp_const_true)) {
max_obj = item;
mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item);
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
best_key = key;
best_obj = item;
}
}
if (max_obj == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
if (best_obj == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence"));
}
return max_obj;
return best_obj;
} else {
// given many args
mp_obj_t max_obj = args[0];
for (int i = 1; i < n_args; i++) {
if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i]) == mp_const_true) {
max_obj = args[i];
mp_obj_t best_key = MP_OBJ_NULL;
mp_obj_t best_obj = MP_OBJ_NULL;
for (mp_uint_t i = 0; i < n_args; i++) {
mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]);
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
best_key = key;
best_obj = args[i];
}
}
return max_obj;
return best_obj;
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_max_obj, 1, mp_builtin_max);
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_t min_obj = NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (min_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, item, min_obj) == mp_const_true)) {
min_obj = item;
}
}
if (min_obj == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
}
return min_obj;
} else {
// given many args
mp_obj_t min_obj = args[0];
for (int i = 1; i < n_args; i++) {
if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj) == mp_const_true) {
min_obj = args[i];
}
}
return min_obj;
}
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max);
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
mp_obj_t ret = mp_iternext_allow_raise(o);
@@ -342,13 +349,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
uint len;
const char *str = mp_obj_str_get_data(o_in, &len);
#if MICROPY_PY_BUILTINS_STR_UNICODE
mp_uint_t charlen = unichar_charlen(str, len);
if (charlen == 1) {
if (MP_OBJ_IS_STR(o_in) && UTF8_IS_NONASCII(*str)) {
mp_int_t ord = *str++ & 0x7F;
for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
ord &= ~mask;
}
while (UTF8_IS_CONT(*str)) {
ord = (ord << 6) | (*str++ & 0x3F);
}
return mp_obj_new_int(ord);
} else {
return mp_obj_new_int(((const byte*)str)[0]);
}
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", charlen));
}
#else
if (len == 1) {
// don't sign extend when converting to ord
// TODO unicode
return mp_obj_new_int(((const byte*)str)[0]);
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
}
#endif
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
@@ -376,13 +402,36 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
if (end_elem != NULL && end_elem->value != mp_const_none) {
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
}
#if MICROPY_PY_IO
mp_obj_t stream_obj = &mp_sys_stdout_obj;
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
if (file_elem != NULL && file_elem->value != mp_const_none) {
stream_obj = file_elem->value;
}
pfenv_t pfenv;
pfenv.data = stream_obj;
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
#endif
for (int i = 0; i < n_args; i++) {
if (i > 0) {
#if MICROPY_PY_IO
mp_stream_write(stream_obj, sep_data, sep_len);
#else
printf("%.*s", sep_len, sep_data);
#endif
}
#if MICROPY_PY_IO
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
#else
mp_obj_print(args[i], PRINT_STR);
#endif
}
#if MICROPY_PY_IO
mp_stream_write(stream_obj, end_data, end_len);
#else
printf("%.*s", end_len, end_data);
#endif
return mp_const_none;
}
@@ -430,7 +479,21 @@ STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *k
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) {
return mp_obj_new_int((machine_int_t)o_in);
mp_int_t id = (mp_int_t)o_in;
if (!MP_OBJ_IS_OBJ(o_in)) {
return mp_obj_new_int(id);
} else if (id >= 0) {
// Many OSes and CPUs have affinity for putting "user" memories
// into low half of address space, and "system" into upper half.
// We're going to take advantage of that and return small int
// (signed) for such "user" addresses.
return MP_OBJ_NEW_SMALL_INT(id);
} else {
// If that didn't work, well, let's return long int, just as
// a (big) positve value, so it will never clash with the range
// of small int returned in previous case.
return mp_obj_new_int_from_uint((mp_uint_t)id);
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id);
@@ -482,6 +545,7 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
// These two are defined in terms of MicroPython API functions right away
// These are defined in terms of MicroPython API functions right away
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get);
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get);

View File

@@ -26,6 +26,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_obj_t mp_builtin_len(mp_obj_t o);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
@@ -80,3 +81,12 @@ extern const mp_obj_module_t mp_module_micropython;
extern const mp_obj_module_t mp_module_struct;
extern const mp_obj_module_t mp_module_sys;
extern const mp_obj_module_t mp_module_gc;
struct _dummy_t;
extern struct _dummy_t mp_sys_stdin_obj;
extern struct _dummy_t mp_sys_stdout_obj;
extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules
extern const mp_obj_module_t mp_module_uctypes;
extern const mp_obj_module_t mp_module_zlibd;

View File

@@ -120,6 +120,9 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// set the new context
mp_locals_set(mp_obj_module_get_globals(module_obj));
mp_globals_set(mp_obj_module_get_globals(module_obj));
#if MICROPY_PY___FILE__
mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false));
#endif
// parse the imported script
mp_parse_error_kind_t parse_error_kind;

View File

@@ -26,8 +26,8 @@
#include <stdlib.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -43,8 +43,10 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
// built-in types
{ 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 },
#if MICROPY_PY_BUILTINS_BYTEARRAY
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
#if MICROPY_PY_BUILTINS_FLOAT
#endif
#if MICROPY_PY_BUILTINS_COMPLEX
{ 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 },
@@ -64,6 +66,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ 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 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_reversed), (mp_obj_t)&mp_type_reversed },
#if MICROPY_PY_BUILTINS_SET
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&mp_type_set },
#endif
@@ -135,6 +138,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ZeroDivisionError), (mp_obj_t)&mp_type_ZeroDivisionError },
@@ -150,8 +154,8 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_builtin_object_table),
.alloc = ARRAY_SIZE(mp_builtin_object_table),
.used = MP_ARRAY_SIZE(mp_builtin_object_table),
.alloc = MP_ARRAY_SIZE(mp_builtin_object_table),
.table = (mp_map_elem_t*)mp_builtin_object_table,
},
};
@@ -160,7 +164,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ },
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
#if MICROPY_PY_ARRAY
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
#endif
#if MICROPY_PY_IO
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
#endif
@@ -186,6 +192,15 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
#endif
// extmod modules
#if MICROPY_PY_UCTYPES
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
#endif
#if MICROPY_PY_ZLIBD
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
};
@@ -195,8 +210,8 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_builtin_module_table),
.alloc = ARRAY_SIZE(mp_builtin_module_table),
.used = MP_ARRAY_SIZE(mp_builtin_module_table),
.alloc = MP_ARRAY_SIZE(mp_builtin_module_table),
.table = (mp_map_elem_t*)mp_builtin_module_table,
},
};

View File

@@ -31,8 +31,8 @@
#include <assert.h>
#include <math.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -48,8 +48,6 @@
// TODO need to mangle __attr names
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
typedef enum {
PN_none = 0,
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
@@ -95,7 +93,7 @@ typedef struct _compiler_t {
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
// TODO store the error message to a variable in compiler_t instead of printing it
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (machine_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
} else {
printf(" File \"%s\"\n", qstr_str(comp->source_file));
}
@@ -104,6 +102,9 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
}
STATIC const mp_map_elem_t mp_constants_table[] = {
#if MICROPY_PY_UCTYPES
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
#endif
// Extra constants as defined by a port
MICROPY_PORT_CONSTANTS
};
@@ -111,8 +112,8 @@ STATIC const mp_map_elem_t mp_constants_table[] = {
STATIC const mp_map_t mp_constants_map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_constants_table),
.alloc = ARRAY_SIZE(mp_constants_table),
.used = MP_ARRAY_SIZE(mp_constants_table),
.alloc = MP_ARRAY_SIZE(mp_constants_table),
.table = (mp_map_elem_t*)mp_constants_table,
};
@@ -158,7 +159,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
compile_syntax_error(comp, (mp_parse_node_t)pns, "constant must be an integer");
break;
}
machine_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
// store the value in the table of dynamic constants
mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(id_qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
@@ -200,8 +201,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
case PN_expr:
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
// int | int
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
}
break;
@@ -209,16 +210,16 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
case PN_and_expr:
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
// int & int
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
}
break;
case PN_shift_expr:
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
// int << int
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
@@ -235,10 +236,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
break;
case PN_arith_expr:
// overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
// overflow checking here relies on SMALL_INT being strictly smaller than mp_int_t
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
// int + int
arg0 += arg1;
@@ -258,8 +259,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
case PN_term:
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
// int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) {
@@ -288,7 +289,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
case PN_factor_2:
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
// +int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
@@ -336,7 +337,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
mp_obj_t dest[2];
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]);
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
if (MP_SMALL_INT_FITS(val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
}
@@ -351,7 +352,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
}
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
STATIC uint comp_next_label(compiler_t *comp) {
@@ -482,7 +483,7 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len,
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);
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
return;
}
@@ -726,9 +727,9 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
}
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
if (assign_kind != ASSIGN_AUG_STORE) {
compile_node(comp, pns->nodes[0]);
}
@@ -789,7 +790,7 @@ cannot_assign:
}
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
// look for star expression
@@ -829,7 +830,7 @@ void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail,
}
// assigns top of stack to pn
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
tail_recursion:
if (MP_PARSE_NODE_IS_NULL(pn)) {
assert(0);
@@ -944,7 +945,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults
// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults
// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)
void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
assert(n_pos_defaults >= 0);
assert(n_kw_defaults >= 0);
@@ -979,7 +980,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
}
}
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
comp->have_star = true;
/* don't need to distinguish bare from named star
@@ -1251,7 +1252,7 @@ void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(store_id, fname);
}
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_ID(pn)) {
EMIT_ARG(delete_id, MP_PARSE_NODE_LEAF_ARG(pn));
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
@@ -1403,7 +1404,7 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// q_base holds the base of the name
// eg a -> q_base=a
// a.b.c -> q_base=a
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
bool is_as = false;
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
@@ -1463,7 +1464,7 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
}
}
void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
EMIT_ARG(load_const_small_int, 0); // level 0 import
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything
qstr q_base;
@@ -1742,10 +1743,11 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(label_assign, break_label);
}
#if !MICROPY_EMIT_CPYTHON
// TODO preload end and step onto stack if they are not constants
// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
// 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) {
STATIC 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
@@ -1798,6 +1800,7 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
EMIT_ARG(label_assign, break_label);
}
#endif
void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
#if !MICROPY_EMIT_CPYTHON
@@ -1881,7 +1884,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(label_assign, end_label);
}
void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
// setup code
uint l1 = comp_next_label(comp);
uint success_label = comp_next_label(comp);
@@ -1894,7 +1897,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
EMIT_ARG(jump, success_label); // jump over exception handler
EMIT_ARG(label_assign, l1); // start of exception handler
EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
EMIT(start_except_handler);
uint l2 = comp_next_label(comp);
@@ -1966,14 +1969,14 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
compile_decrease_except_level(comp);
EMIT(end_finally);
EMIT_ARG(adjust_stack_size, -5); // stack adjust
EMIT(end_except_handler);
EMIT_ARG(label_assign, success_label);
compile_node(comp, pn_else); // else block, can be null
EMIT_ARG(label_assign, l2);
}
void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
uint l_finally_block = comp_next_label(comp);
EMIT_ARG(setup_finally, l_finally_block);
@@ -2025,7 +2028,7 @@ void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
if (n == 0) {
// no more pre-bits, compile the body of the with
compile_node(comp, body);
@@ -2175,7 +2178,7 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
compile_node(comp, pns->nodes[0]);
for (int i = 1; i < num_nodes; i += 1) {
@@ -2528,7 +2531,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
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];
n_bytes += (mp_uint_t)pns_string->nodes[1];
}
if (i == 0) {
string_kind = pn_kind;
@@ -2549,8 +2552,8 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
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];
memcpy(s_dest, (const char*)pns_string->nodes[0], (mp_uint_t)pns_string->nodes[1]);
s_dest += (mp_uint_t)pns_string->nodes[1];
}
}
qstr q = qstr_build_end(q_ptr);
@@ -2559,7 +2562,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));
mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1];
@@ -2854,14 +2857,14 @@ STATIC compile_function_t compile_function[] = {
#undef DEF_RULE
};
void compile_node(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_NULL(pn)) {
// pass
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
EMIT_ARG(load_const_small_int, arg);
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
case MP_PARSE_NODE_INTEGER: EMIT_ARG(load_const_int, arg); break;
@@ -2883,7 +2886,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
EMIT_ARG(set_line_number, pns->source_line);
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);
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
} else {
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
@@ -2899,11 +2902,10 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
}
}
void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star, bool allow_annotations) {
STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) {
// TODO verify that *k and **k are last etc
qstr param_name = MP_QSTR_NULL;
uint param_flag = ID_FLAG_IS_PARAM;
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
if (MP_PARSE_NODE_IS_ID(pn)) {
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
if (comp->have_star) {
@@ -2918,24 +2920,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
//int node_index = 1; unused
if (allow_annotations) {
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
// this parameter has an annotation
pn_annotation = pns->nodes[1];
}
//node_index = 2; unused
}
/* this is obsolete now that num dict/default params are calculated in compile_funcdef_param
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[node_index])) {
// this parameter has a default value
if (comp->have_star) {
comp->scope_cur->num_dict_params += 1;
} else {
comp->scope_cur->num_default_params += 1;
}
}
*/
if (comp->have_star) {
// comes after a star, so counts as a keyword-only parameter
comp->scope_cur->num_kwonly_args += 1;
@@ -2954,12 +2938,11 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
// named star
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
} else if (allow_annotations && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
// named star with possible annotation
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
pns = (mp_parse_node_struct_t*)pns->nodes[0];
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
pn_annotation = pns->nodes[1];
} else {
// shouldn't happen
assert(0);
@@ -2967,10 +2950,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
// this parameter has an annotation
pn_annotation = pns->nodes[1];
}
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS;
} else {
// TODO anything to implement?
@@ -2979,9 +2958,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
}
if (param_name != MP_QSTR_NULL) {
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
// TODO this parameter has an annotation
}
bool added;
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added);
if (!added) {
@@ -2994,14 +2970,61 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
}
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star);
}
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star);
}
void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) {
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
// no annotation
return;
}
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_name) {
// named parameter with possible annotation
// fallthrough
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_star) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
// named star with possible annotation
pns = (mp_parse_node_struct_t*)pns->nodes[0];
// fallthrough
} else {
// no annotation
return;
}
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star) {
// double star with possible annotation
// fallthrough
} else {
// no annotation
return;
}
mp_parse_node_t pn_annotation = pns->nodes[1];
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
#if MICROPY_EMIT_NATIVE
qstr param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
id_info_t *id_info = scope_find(comp->scope_cur, param_name);
assert(id_info != NULL);
if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER) {
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
qstr arg_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type);
} else {
compile_syntax_error(comp, pn_annotation, "parameter annotation must be an identifier");
}
}
#endif // MICROPY_EMIT_NATIVE
}
}
STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
tail_recursion:
if (MP_PARSE_NODE_IS_NULL(pn_iter)) {
// no more nested if/for; compile inner expression
@@ -3125,9 +3148,28 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
if (comp->pass == MP_PASS_SCOPE) {
comp->have_star = false;
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
}
} else {
// compile annotations; only needed on latter compiler passes
// pns->nodes[2] is return/whole function annotation
// argument annotations
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_annotations);
// pns->nodes[2] is return/whole function annotation
mp_parse_node_t pn_annotation = pns->nodes[2];
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
#if MICROPY_EMIT_NATIVE
if (scope->emit_options == MP_EMIT_OPT_VIPER) {
// nodes[2] can be null or a test-expr
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type);
} else {
compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier");
}
}
#endif // MICROPY_EMIT_NATIVE
}
}
compile_node(comp, pns->nodes[3]); // 3 is function body
// emit return if it wasn't the last opcode
@@ -3337,7 +3379,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
return;
}
if (pass > MP_PASS_SCOPE) {
machine_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
for (uint i = 1; i < n_args; i++) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
@@ -3584,9 +3626,14 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
emit_native = emit_native_thumb_new(max_num_labels);
}
comp->emit_method_table = &emit_native_thumb_method_table;
#elif MICROPY_EMIT_ARM
if (emit_native == NULL) {
emit_native = emit_native_arm_new(max_num_labels);
}
comp->emit_method_table = &emit_native_arm_method_table;
#endif
comp->emit = emit_native;
comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0);
// native emitters need an extra pass to compute stack size
compile_scope(comp, s, MP_PASS_STACK_SIZE);
@@ -3627,6 +3674,8 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
emit_native_x64_free(emit_native);
#elif MICROPY_EMIT_THUMB
emit_native_thumb_free(emit_native);
#elif MICROPY_EMIT_ARM
emit_native_arm_free(emit_native);
#endif
}
#endif

View File

@@ -46,10 +46,14 @@ typedef enum {
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
#define MP_EMIT_NATIVE_TYPE_ENABLE (0)
#define MP_EMIT_NATIVE_TYPE_RETURN (1)
#define MP_EMIT_NATIVE_TYPE_ARG (2)
typedef struct _emit_t emit_t;
typedef struct _emit_method_table_t {
void (*set_native_types)(emit_t *emit, bool do_native_types);
void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2);
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_t *emit);
bool (*last_emit_was_return_value)(emit_t *emit);
@@ -65,7 +69,7 @@ typedef struct _emit_method_table_t {
void (*import_from)(emit_t *emit, qstr qstr);
void (*import_star)(emit_t *emit);
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
void (*load_const_small_int)(emit_t *emit, machine_int_t arg);
void (*load_const_small_int)(emit_t *emit, mp_int_t arg);
void (*load_const_int)(emit_t *emit, qstr qstr);
void (*load_const_dec)(emit_t *emit, qstr qstr);
void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes);
@@ -134,6 +138,11 @@ typedef struct _emit_method_table_t {
void (*yield_value)(emit_t *emit);
void (*yield_from)(emit_t *emit);
// these methods are used to control entry to/exit from an exception handler
// they may or may not emit code
void (*start_except_handler)(emit_t *emit);
void (*end_except_handler)(emit_t *emit);
#if MICROPY_EMIT_CPYTHON
// these methods are only needed for emitcpy
void (*load_const_verbatim_str)(emit_t *emit, const char *str);
@@ -152,17 +161,20 @@ extern const emit_method_table_t emit_cpython_method_table;
extern const emit_method_table_t emit_bc_method_table;
extern const emit_method_table_t emit_native_x64_method_table;
extern const emit_method_table_t emit_native_thumb_method_table;
extern const emit_method_table_t emit_native_arm_method_table;
emit_t *emit_pass1_new(void);
emit_t *emit_cpython_new(uint max_num_labels);
emit_t *emit_bc_new(uint max_num_labels);
emit_t *emit_native_x64_new(uint max_num_labels);
emit_t *emit_native_thumb_new(uint max_num_labels);
emit_t *emit_native_arm_new(uint max_num_labels);
void emit_pass1_free(emit_t *emit);
void emit_bc_free(emit_t *emit);
void emit_native_x64_free(emit_t *emit);
void emit_native_thumb_free(emit_t *emit);
void emit_native_arm_free(emit_t *emit);
typedef struct _emit_inline_asm_t emit_inline_asm_t;

View File

@@ -30,8 +30,8 @@
#include <string.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -50,7 +50,6 @@
struct _emit_t {
pass_kind_t pass : 8;
uint last_emit_was_return_value : 8;
byte dummy_data[DUMMY_DATA_SIZE];
int stack_size;
@@ -67,6 +66,8 @@ struct _emit_t {
uint bytecode_offset;
uint bytecode_size;
byte *code_base; // stores both byte code and code info
// Accessed as uint, so must be aligned as such
byte dummy_data[DUMMY_DATA_SIZE];
};
STATIC void emit_bc_rot_two(emit_t *emit);
@@ -99,7 +100,7 @@ STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_writ
}
STATIC void emit_align_code_info_to_machine_word(emit_t* emit) {
emit->code_info_offset = (emit->code_info_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
emit->code_info_offset = (emit->code_info_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
}
STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
@@ -114,12 +115,24 @@ STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
#if MICROPY_ENABLE_SOURCE_LINE
STATIC void emit_write_code_info_bytes_lines(emit_t* emit, uint bytes_to_skip, uint lines_to_skip) {
assert(bytes_to_skip > 0 || lines_to_skip > 0);
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
while (bytes_to_skip > 0 || lines_to_skip > 0) {
uint b = MIN(bytes_to_skip, 31);
uint l = MIN(lines_to_skip, 7);
mp_uint_t b, l;
if (lines_to_skip <= 6) {
// use 0b0LLBBBBB encoding
b = MIN(bytes_to_skip, 0x1f);
l = MIN(lines_to_skip, 0x3);
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
} else {
// use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
b = MIN(bytes_to_skip, 0xf);
l = MIN(lines_to_skip, 0x7ff);
byte *ci = emit_get_cur_to_write_code_info(emit, 2);
ci[0] = 0x80 | b | ((l >> 4) & 0x70);
ci[1] = l;
}
bytes_to_skip -= b;
lines_to_skip -= l;
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
}
}
#endif
@@ -139,7 +152,7 @@ STATIC byte* emit_get_cur_to_write_bytecode(emit_t* emit, int num_bytes_to_write
}
STATIC void emit_align_bytecode_to_machine_word(emit_t* emit) {
emit->bytecode_offset = (emit->bytecode_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
}
STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
@@ -171,7 +184,7 @@ STATIC void emit_write_bytecode_uint(emit_t* emit, uint num) {
}
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, machine_int_t num) {
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
emit_write_bytecode_byte(emit, b1);
// We store each 7 bits in a separate byte, and that's how many bytes needed
@@ -206,8 +219,10 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, uint num) {
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
emit_write_bytecode_byte(emit, b);
emit_align_bytecode_to_machine_word(emit);
machine_uint_t *c = (machine_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(machine_uint_t));
*c = (machine_uint_t)ptr;
mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
// Verify thar c is already uint-aligned
assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
*c = (mp_uint_t)ptr;
}
/* currently unused
@@ -250,7 +265,7 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint la
c[2] = bytecode_offset >> 8;
}
STATIC void emit_bc_set_native_types(emit_t *emit, bool do_native_types) {
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -269,7 +284,7 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
// write code info size; use maximum space (4 bytes) to write it; TODO possible optimise this
{
byte* c = emit_get_cur_to_write_code_info(emit, 4);
machine_uint_t s = emit->code_info_size;
mp_uint_t s = emit->code_info_size;
c[0] = s & 0xff;
c[1] = (s >> 8) & 0xff;
c[2] = (s >> 16) & 0xff;
@@ -360,7 +375,6 @@ STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
uint bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
uint lines_to_skip = source_line - emit->last_source_line;
emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
emit->last_source_line_offset = emit->bytecode_offset;
emit->last_source_line = source_line;
}
@@ -428,7 +442,7 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
}
}
STATIC void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) {
STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
}
@@ -849,8 +863,16 @@ STATIC void emit_bc_yield_from(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
}
STATIC void emit_bc_start_except_handler(emit_t *emit) {
emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
}
STATIC void emit_bc_end_except_handler(emit_t *emit) {
emit_bc_adjust_stack_size(emit, -5); // stack adjust
}
const emit_method_table_t emit_bc_method_table = {
emit_bc_set_native_types,
emit_bc_set_native_type,
emit_bc_start_pass,
emit_bc_end_pass,
emit_bc_last_emit_was_return_value,
@@ -934,6 +956,9 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_raise_varargs,
emit_bc_yield_value,
emit_bc_yield_from,
emit_bc_start_except_handler,
emit_bc_end_except_handler,
};
#endif // !MICROPY_EMIT_CPYTHON

View File

@@ -28,8 +28,8 @@
#include <stdint.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"

View File

@@ -30,8 +30,8 @@
#include <string.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -63,7 +63,7 @@ emit_t *emit_cpython_new(uint max_num_labels) {
return emit;
}
STATIC void emit_cpy_set_native_types(emit_t *emit, bool do_native_types) {
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -173,7 +173,7 @@ STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
}
}
STATIC void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) {
STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST " INT_FMT "\n", arg);
@@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
}
}
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
}
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
emit_cpy_adjust_stack_size(emit, -5); // stack adjust
}
STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
@@ -814,7 +822,7 @@ STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
}
const emit_method_table_t emit_cpython_method_table = {
emit_cpy_set_native_types,
emit_cpy_set_native_type,
emit_cpy_start_pass,
emit_cpy_end_pass,
emit_cpy_last_emit_was_return_value,
@@ -899,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_yield_value,
emit_cpy_yield_from,
emit_cpy_start_except_handler,
emit_cpy_end_except_handler,
// emitcpy specific functions
emit_cpy_load_const_verbatim_str,
emit_cpy_load_closure,

View File

@@ -30,8 +30,8 @@
#include <string.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
@@ -55,7 +55,7 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
return rc;
}
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) {
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) {
rc->kind = MP_CODE_BYTECODE;
rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args;
@@ -65,7 +65,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
rc->u_byte.len = len;
#ifdef DEBUG_PRINT
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
DEBUG_printf(" arg names:");
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
DEBUG_printf(" %s", qstr_str(arg_names[i]));
@@ -74,7 +74,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
#endif
#if MICROPY_DEBUG_PRINTERS
if (mp_verbose_flag > 0) {
for (int i = 0; i < 128 && i < len; i++) {
for (mp_uint_t i = 0; i < len; i++) {
if (i > 0 && i % 16 == 0) {
printf("\n");
}
@@ -86,31 +86,33 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
#endif
}
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun, uint len, int n_args) {
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
rc->kind = kind;
rc->scope_flags = 0;
rc->n_pos_args = n_args;
rc->u_native.fun = fun;
rc->u_native.fun_data = fun_data;
rc->u_native.type_sig = type_sig;
#ifdef DEBUG_PRINT
DEBUG_printf("assign native: kind=%d fun=%p len=%u n_args=%d\n", kind, fun, len, n_args);
byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
for (int i = 0; i < 128 && i < len; i++) {
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
for (mp_uint_t i = 0; i < fun_len; i++) {
if (i > 0 && i % 16 == 0) {
DEBUG_printf("\n");
}
DEBUG_printf(" %02x", fun_data[i]);
DEBUG_printf(" %02x", ((byte*)fun_data)[i]);
}
DEBUG_printf("\n");
#ifdef WRITE_CODE
FILE *fp_write_code = fopen("out-code", "wb");
fwrite(fun_data, len, 1, fp_write_code);
fwrite(fun_data, fun_len, 1, fp_write_code);
fclose(fp_write_code);
#endif
#endif
}
#endif
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
@@ -128,13 +130,19 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
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, def_kw_args, rc->u_byte.code);
break;
#if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
break;
case MP_CODE_NATIVE_VIPER:
case MP_CODE_NATIVE_ASM:
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun);
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->u_native.type_sig);
break;
#endif
#if MICROPY_EMIT_INLINE_THUMB
case MP_CODE_NATIVE_ASM:
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun_data);
break;
#endif
default:
// raw code was never set (this should not happen)
assert(0);
@@ -149,8 +157,8 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
return fun;
}
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
// make function object
mp_obj_t ffun;
if (n_closed_over & 0x100) {

View File

@@ -37,25 +37,26 @@ typedef enum {
typedef struct _mp_code_t {
mp_raw_code_kind_t kind : 3;
uint scope_flags : 7;
uint n_pos_args : 11;
uint n_kwonly_args : 11;
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
mp_uint_t n_kwonly_args : 11;
qstr *arg_names;
union {
struct {
byte *code;
uint len;
mp_uint_t len;
} u_byte;
struct {
void *fun;
void *fun_data;
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
} u_native;
};
} mp_raw_code_t;
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);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *f, uint len, int n_args);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);

View File

@@ -30,8 +30,8 @@
#include <stdarg.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -99,7 +99,7 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
if (emit->pass == MP_PASS_EMIT) {
void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
}
return emit->success;
@@ -167,7 +167,7 @@ STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t
if (MP_PARSE_NODE_IS_ID(pn)) {
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
const char *reg_str = qstr_str(reg_qstr);
for (uint i = 0; i < ARRAY_SIZE(reg_name_table); i++) {
for (uint i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
const reg_name_t *r = &reg_name_table[i];
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
if (r->reg > max_reg) {
@@ -286,7 +286,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
asm_thumb_b_n(emit->as, label_num);
} else if (op_str[0] == 'b' && op_len == 3) {
uint cc = -1;
for (uint i = 0; i < ARRAY_SIZE(cc_name_table); i++) {
for (uint i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
cc = cc_name_table[i].cc;
}
@@ -315,7 +315,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
} else if (strcmp(op_str, "and") == 0) {
} else if (strcmp(op_str, "and_") == 0) {
op_code = ASM_THUMB_FORMAT_4_AND;
uint reg_dest, reg_src;
op_format_4:
@@ -323,7 +323,6 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
// TODO probably uses less ROM if these ops are in a lookup table
} else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
} else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
} else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
} else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;

File diff suppressed because it is too large Load Diff

View File

@@ -28,8 +28,8 @@
#include <stdint.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -214,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
#if MICROPY_EMIT_CPYTHON
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,

View File

@@ -75,7 +75,7 @@ int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char s
if (buf_size < 7) {
// Smallest exp notion is -9e+99 which is 6 chars plus terminating
// nulll.
// null.
if (buf_size >= 2) {
*s++ = '?';

234
py/gc.c
View File

@@ -33,7 +33,6 @@
#include "misc.h"
#include "gc.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
@@ -47,22 +46,26 @@
#define DEBUG_printf(...) (void)0
#endif
// make this 1 to dump the heap each time it changes
#define EXTENSIVE_HEAP_PROFILING (0)
#define WORDS_PER_BLOCK (4)
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
#define STACK_SIZE (64) // tunable; minimum is 1
STATIC byte *gc_alloc_table_start;
STATIC machine_uint_t gc_alloc_table_byte_len;
STATIC mp_uint_t gc_alloc_table_byte_len;
#if MICROPY_ENABLE_FINALISER
STATIC byte *gc_finaliser_table_start;
#endif
STATIC machine_uint_t *gc_pool_start;
STATIC machine_uint_t *gc_pool_end;
STATIC mp_uint_t *gc_pool_start;
STATIC mp_uint_t *gc_pool_end;
STATIC int gc_stack_overflow;
STATIC machine_uint_t gc_stack[STACK_SIZE];
STATIC machine_uint_t *gc_sp;
STATIC machine_uint_t gc_lock_depth;
STATIC mp_uint_t gc_stack[STACK_SIZE];
STATIC mp_uint_t *gc_sp;
STATIC mp_uint_t gc_lock_depth;
STATIC mp_uint_t gc_last_free_atb_index;
// ATB = allocation table byte
// 0b00 = FREE -- free block
@@ -94,8 +97,8 @@ STATIC machine_uint_t gc_lock_depth;
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
#define BLOCK_FROM_PTR(ptr) (((ptr) - (machine_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (machine_uint_t)gc_pool_start))
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
#if MICROPY_ENABLE_FINALISER
@@ -112,32 +115,35 @@ STATIC machine_uint_t gc_lock_depth;
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
void gc_init(void *start, void *end) {
// align end pointer on block boundary
end = (void*)((machine_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, end - start);
end = (void*)((mp_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
// calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
// T = A + F + P
// F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
// P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
machine_uint_t total_byte_len = end - start;
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
#if MICROPY_ENABLE_FINALISER
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
#else
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
#endif
gc_alloc_table_start = (byte*)start;
#if MICROPY_ENABLE_FINALISER
machine_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB;
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
#endif
machine_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
gc_pool_start = end - gc_pool_block_len * BYTES_PER_BLOCK;
gc_pool_end = end;
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
gc_pool_end = (mp_uint_t*)end;
#if MICROPY_ENABLE_FINALISER
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
#endif
// clear ATBs
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
@@ -154,6 +160,9 @@ void gc_init(void *start, void *end) {
gc_pool_start[i] = 0;
}
// set last free ATB index to start of heap
gc_last_free_atb_index = 0;
// unlock the GC
gc_lock_depth = 0;
@@ -173,16 +182,20 @@ void gc_unlock(void) {
gc_lock_depth--;
}
bool gc_is_locked(void) {
return gc_lock_depth != 0;
}
#define VERIFY_PTR(ptr) ( \
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
&& ptr >= (machine_uint_t)gc_pool_start /* must be above start of pool */ \
&& ptr < (machine_uint_t)gc_pool_end /* must be below end of pool */ \
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
)
#define VERIFY_MARK_AND_PUSH(ptr) \
do { \
if (VERIFY_PTR(ptr)) { \
machine_uint_t _block = BLOCK_FROM_PTR(ptr); \
mp_uint_t _block = BLOCK_FROM_PTR(ptr); \
if (ATB_GET_KIND(_block) == AT_HEAD) { \
/* an unmarked head, mark it, and push it on gc stack */ \
ATB_HEAD_TO_MARK(_block); \
@@ -198,18 +211,18 @@ void gc_unlock(void) {
STATIC void gc_drain_stack(void) {
while (gc_sp > gc_stack) {
// pop the next block off the stack
machine_uint_t block = *--gc_sp;
mp_uint_t block = *--gc_sp;
// work out number of consecutive blocks in the chain starting with this one
machine_uint_t n_blocks = 0;
mp_uint_t n_blocks = 0;
do {
n_blocks += 1;
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
// check this block's children
machine_uint_t *scan = (machine_uint_t*)PTR_FROM_BLOCK(block);
for (machine_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
machine_uint_t ptr2 = *scan;
mp_uint_t *scan = (mp_uint_t*)PTR_FROM_BLOCK(block);
for (mp_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
mp_uint_t ptr2 = *scan;
VERIFY_MARK_AND_PUSH(ptr2);
}
}
@@ -221,7 +234,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
gc_sp = gc_stack;
// scan entire memory looking for blocks which have been marked but not their children
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
// trace (again) if mark bit set
if (ATB_GET_KIND(block) == AT_MARK) {
*gc_sp++ = block;
@@ -241,7 +254,7 @@ STATIC void gc_sweep(void) {
#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++) {
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
switch (ATB_GET_KIND(block)) {
case AT_HEAD:
#if MICROPY_ENABLE_FINALISER
@@ -268,6 +281,7 @@ STATIC void gc_sweep(void) {
case AT_TAIL:
if (free_tail) {
DEBUG_printf("gc_sweep(%p)\n",PTR_FROM_BLOCK(block));
ATB_ANY_TO_FREE(block);
}
break;
@@ -286,9 +300,9 @@ void gc_collect_start(void) {
gc_sp = gc_stack;
}
void gc_collect_root(void **ptrs, machine_uint_t len) {
for (machine_uint_t i = 0; i < len; i++) {
machine_uint_t ptr = (machine_uint_t)ptrs[i];
void gc_collect_root(void **ptrs, mp_uint_t len) {
for (mp_uint_t i = 0; i < len; i++) {
mp_uint_t ptr = (mp_uint_t)ptrs[i];
VERIFY_MARK_AND_PUSH(ptr);
gc_drain_stack();
}
@@ -297,18 +311,19 @@ void gc_collect_root(void **ptrs, machine_uint_t len) {
void gc_collect_end(void) {
gc_deal_with_stack_overflow();
gc_sweep();
gc_last_free_atb_index = 0;
gc_unlock();
}
void gc_info(gc_info_t *info) {
info->total = (gc_pool_end - gc_pool_start) * sizeof(machine_uint_t);
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
info->used = 0;
info->free = 0;
info->num_1block = 0;
info->num_2block = 0;
info->max_block = 0;
for (machine_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
machine_uint_t kind = ATB_GET_KIND(block);
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
mp_uint_t kind = ATB_GET_KIND(block);
if (kind == AT_FREE || kind == AT_HEAD) {
if (len == 1) {
info->num_1block += 1;
@@ -345,8 +360,8 @@ void gc_info(gc_info_t *info) {
info->free *= BYTES_PER_BLOCK;
}
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
mp_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
// check if GC is locked
@@ -359,15 +374,15 @@ void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
return NULL;
}
machine_uint_t i;
machine_uint_t end_block;
machine_uint_t start_block;
machine_uint_t n_free = 0;
mp_uint_t i;
mp_uint_t end_block;
mp_uint_t start_block;
mp_uint_t n_free = 0;
int collected = 0;
for (;;) {
// look for a run of n_blocks available blocks
for (i = 0; i < gc_alloc_table_byte_len; i++) {
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
byte a = gc_alloc_table_start[i];
if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
@@ -390,24 +405,34 @@ found:
end_block = i;
start_block = i - n_free + 1;
// Set last free ATB index to block after last block we found, for start of
// next scan. To reduce fragmentation, we only do this if we were looking
// for a single free block, which guarantees that there are no free blocks
// before this one. Also, whenever we free or shink a block we must check
// if this index needs adjusting (see gc_realloc and gc_free).
if (n_free == 1) {
gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
}
// mark first block as used head
ATB_FREE_TO_HEAD(start_block);
// mark rest of blocks as used tail
// TODO for a run of many blocks can make this more efficient
for (machine_uint_t bl = start_block + 1; bl <= end_block; bl++) {
for (mp_uint_t bl = start_block + 1; bl <= end_block; bl++) {
ATB_FREE_TO_TAIL(bl);
}
// get pointer to first block
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
// zero out the additional bytes of the newly allocated blocks
// This is needed because the blocks may have previously held pointers
// to the heap and will not be set to something else if the caller
// doesn't actually use the entire block. As such they will continue
// to point to the heap and may prevent other blocks from being reclaimed.
memset(ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
#if MICROPY_ENABLE_FINALISER
if (has_finaliser) {
@@ -418,15 +443,19 @@ found:
}
#endif
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ret_ptr;
}
/*
void *gc_alloc(machine_uint_t n_bytes) {
void *gc_alloc(mp_uint_t n_bytes) {
return _gc_alloc(n_bytes, false);
}
void *gc_alloc_with_finaliser(machine_uint_t n_bytes) {
void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
return _gc_alloc(n_bytes, true);
}
*/
@@ -438,28 +467,38 @@ void gc_free(void *ptr_in) {
return;
}
machine_uint_t ptr = (machine_uint_t)ptr_in;
mp_uint_t ptr = (mp_uint_t)ptr_in;
DEBUG_printf("gc_free(%p)\n", ptr);
if (VERIFY_PTR(ptr)) {
machine_uint_t block = BLOCK_FROM_PTR(ptr);
mp_uint_t block = BLOCK_FROM_PTR(ptr);
if (ATB_GET_KIND(block) == AT_HEAD) {
// set the last_free pointer to this block if it's earlier in the heap
if (block / BLOCKS_PER_ATB < gc_last_free_atb_index) {
gc_last_free_atb_index = block / BLOCKS_PER_ATB;
}
// free head and all of its tail blocks
do {
ATB_ANY_TO_FREE(block);
block += 1;
} while (ATB_GET_KIND(block) == AT_TAIL);
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
}
}
}
machine_uint_t gc_nbytes(void *ptr_in) {
machine_uint_t ptr = (machine_uint_t)ptr_in;
mp_uint_t gc_nbytes(void *ptr_in) {
mp_uint_t ptr = (mp_uint_t)ptr_in;
if (VERIFY_PTR(ptr)) {
machine_uint_t block = BLOCK_FROM_PTR(ptr);
mp_uint_t block = BLOCK_FROM_PTR(ptr);
if (ATB_GET_KIND(block) == AT_HEAD) {
// work out number of consecutive blocks in the chain starting with this on
machine_uint_t n_blocks = 0;
mp_uint_t n_blocks = 0;
do {
n_blocks += 1;
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
@@ -473,8 +512,8 @@ machine_uint_t gc_nbytes(void *ptr_in) {
#if 0
// old, simple realloc that didn't expand memory in place
void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
machine_uint_t n_existing = gc_nbytes(ptr);
void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
mp_uint_t n_existing = gc_nbytes(ptr);
if (n_bytes <= n_existing) {
return ptr;
} else {
@@ -483,7 +522,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
has_finaliser = false;
} else {
#if MICROPY_ENABLE_FINALISER
has_finaliser = FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr));
has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
#else
has_finaliser = false;
#endif
@@ -500,7 +539,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
#else // Alternative gc_realloc impl
void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
if (gc_lock_depth > 0) {
return NULL;
}
@@ -510,7 +549,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
return gc_alloc(n_bytes, false);
}
machine_uint_t ptr = (machine_uint_t)ptr_in;
mp_uint_t ptr = (mp_uint_t)ptr_in;
// sanity check the ptr
if (!VERIFY_PTR(ptr)) {
@@ -518,7 +557,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
}
// get first block
machine_uint_t block = BLOCK_FROM_PTR(ptr);
mp_uint_t block = BLOCK_FROM_PTR(ptr);
// sanity check the ptr is pointing to the head of a block
if (ATB_GET_KIND(block) != AT_HEAD) {
@@ -526,14 +565,14 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
}
// compute number of new blocks that are requested
machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
// get the number of consecutive tail blocks and
// the number of free blocks after last tail block
// stop if we reach (or are at) end of heap
machine_uint_t n_free = 0;
machine_uint_t n_blocks = 1; // counting HEAD block
machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
mp_uint_t n_free = 0;
mp_uint_t n_blocks = 1; // counting HEAD block
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
while (block + n_blocks + n_free < max_block) {
if (n_blocks + n_free >= new_blocks) {
// stop as soon as we find enough blocks for n_bytes
@@ -556,22 +595,36 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
// check if we can shrink the allocated area
if (new_blocks < n_blocks) {
// free unneeded tail blocks
for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
ATB_ANY_TO_FREE(bl);
}
// set the last_free pointer to end of this block if it's earlier in the heap
if ((block + new_blocks) / BLOCKS_PER_ATB < gc_last_free_atb_index) {
gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
}
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ptr_in;
}
// check if we can expand in place
if (new_blocks <= n_blocks + n_free) {
// mark few more blocks as used tail
for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
for (mp_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
assert(ATB_GET_KIND(bl) == AT_FREE);
ATB_FREE_TO_TAIL(bl);
}
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
memset(ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ptr_in;
}
@@ -590,7 +643,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
return NULL;
}
DEBUG_printf("gc_realloc: allocating new block\n");
DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out);
memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
gc_free(ptr_in);
return ptr_out;
@@ -606,9 +659,34 @@ void gc_dump_info() {
}
void gc_dump_alloc_table(void) {
static const mp_uint_t DUMP_BYTES_PER_LINE = 64;
#if !EXTENSIVE_HEAP_PROFILING
// When comparing heap output we don't want to print the starting
// pointer of the heap because it changes from run to run.
printf("GC memory layout; from %p:", gc_pool_start);
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
if (bl % 64 == 0) {
#endif
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
if (bl % DUMP_BYTES_PER_LINE == 0) {
// a new line of blocks
#if EXTENSIVE_HEAP_PROFILING
{
// check if this line contains only free blocks
bool only_free_blocks = true;
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
if (ATB_GET_KIND(bl2) != AT_FREE) {
only_free_blocks = false;
break;
}
}
if (only_free_blocks) {
// line contains only free blocks, so skip printing it
bl += DUMP_BYTES_PER_LINE - 1;
continue;
}
}
#endif
// print header for new line of blocks
printf("\n%04x: ", (uint)bl);
}
int c = ' ';
@@ -617,12 +695,12 @@ void gc_dump_alloc_table(void) {
case AT_HEAD: c = 'h'; break;
/* this prints the uPy object type of the head block
case AT_HEAD: {
machine_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
if (*ptr == (machine_uint_t)&mp_type_tuple) { c = 'T'; }
else if (*ptr == (machine_uint_t)&mp_type_list) { c = 'L'; }
else if (*ptr == (machine_uint_t)&mp_type_dict) { c = 'D'; }
else if (*ptr == (machine_uint_t)&mp_type_float) { c = 'F'; }
else if (*ptr == (machine_uint_t)&mp_type_fun_bc) { c = 'B'; }
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; }
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
else { c = 'h'; }
break;
}
@@ -637,23 +715,23 @@ void gc_dump_alloc_table(void) {
#if DEBUG_PRINT
void gc_test(void) {
machine_uint_t len = 500;
machine_uint_t *heap = malloc(len);
gc_init(heap, heap + len / sizeof(machine_uint_t));
mp_uint_t len = 500;
mp_uint_t *heap = malloc(len);
gc_init(heap, heap + len / sizeof(mp_uint_t));
void *ptrs[100];
{
machine_uint_t **p = gc_alloc(16, false);
mp_uint_t **p = gc_alloc(16, false);
p[0] = gc_alloc(64, false);
p[1] = gc_alloc(1, false);
p[2] = gc_alloc(1, false);
p[3] = gc_alloc(1, false);
machine_uint_t ***p2 = gc_alloc(16, false);
mp_uint_t ***p2 = gc_alloc(16, false);
p2[0] = p;
p2[1] = p;
ptrs[0] = p2;
}
for (int i = 0; i < 25; i+=2) {
machine_uint_t *p = gc_alloc(i, false);
mp_uint_t *p = gc_alloc(i, false);
printf("p=%p\n", p);
if (i & 3) {
//ptrs[i] = p;

21
py/gc.h
View File

@@ -30,25 +30,26 @@ void gc_init(void *start, void *end);
// They can be used to prevent the GC from allocating/freeing.
void gc_lock(void);
void gc_unlock(void);
bool gc_is_locked(void);
// A given port must implement gc_collect by using the other collect functions.
void gc_collect(void);
void gc_collect_start(void);
void gc_collect_root(void **ptrs, machine_uint_t len);
void gc_collect_root(void **ptrs, mp_uint_t len);
void gc_collect_end(void);
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser);
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
void gc_free(void *ptr);
machine_uint_t gc_nbytes(void *ptr);
void *gc_realloc(void *ptr, machine_uint_t n_bytes);
mp_uint_t gc_nbytes(void *ptr);
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
typedef struct _gc_info_t {
machine_uint_t total;
machine_uint_t used;
machine_uint_t free;
machine_uint_t num_1block;
machine_uint_t num_2block;
machine_uint_t max_block;
mp_uint_t total;
mp_uint_t used;
mp_uint_t free;
mp_uint_t num_1block;
mp_uint_t num_2block;
mp_uint_t max_block;
} gc_info_t;
void gc_info(gc_info_t *info);

View File

@@ -32,8 +32,8 @@
#include <stdio.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
@@ -45,30 +45,30 @@
struct _mp_lexer_t {
qstr source_name; // name of source
void *stream_data; // data for stream
mp_lexer_stream_next_char_t stream_next_char; // stream callback to get next char
mp_lexer_stream_next_byte_t stream_next_byte; // stream callback to get next byte
mp_lexer_stream_close_t stream_close; // stream callback to free
unichar chr0, chr1, chr2; // current cached characters from source
uint line; // source line
uint column; // source column
mp_uint_t line; // source line
mp_uint_t column; // source column
int emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
int nested_bracket_level; // >0 when there are nested brackets over multiple lines
mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines
uint alloc_indent_level;
uint num_indent_level;
mp_uint_t alloc_indent_level;
mp_uint_t num_indent_level;
uint16_t *indent_level;
vstr_t vstr;
mp_token_t tok_cur;
};
uint mp_optimise_value;
mp_uint_t 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;
bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
mp_uint_t i = 0;
while (i < len && *str == *strn) {
++i;
@@ -81,10 +81,10 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
#ifdef MICROPY_DEBUG_PRINTERS
void mp_token_show(const mp_token_t *tok) {
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:" UINT_FMT, tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
if (tok->str != NULL && tok->len > 0) {
const char *i = tok->str;
const char *j = i + tok->len;
const byte *i = (const byte *)tok->str;
const byte *j = (const byte *)i + tok->len;
printf(" ");
while (i < j) {
unichar c = utf8_get_char(i);
@@ -103,7 +103,7 @@ void mp_token_show(const mp_token_t *tok) {
#define CUR_CHAR(lex) ((lex)->chr0)
STATIC bool is_end(mp_lexer_t *lex) {
return lex->chr0 == MP_LEXER_CHAR_EOF;
return lex->chr0 == MP_LEXER_EOF;
}
STATIC bool is_physical_newline(mp_lexer_t *lex) {
@@ -171,11 +171,11 @@ STATIC bool is_tail_of_identifier(mp_lexer_t *lex) {
}
STATIC void next_char(mp_lexer_t *lex) {
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
if (lex->chr0 == MP_LEXER_EOF) {
return;
}
int advance = 1;
mp_uint_t advance = 1;
if (lex->chr0 == '\n') {
// LF is a new line
@@ -200,17 +200,17 @@ STATIC void next_char(mp_lexer_t *lex) {
for (; advance > 0; advance--) {
lex->chr0 = lex->chr1;
lex->chr1 = lex->chr2;
lex->chr2 = lex->stream_next_char(lex->stream_data);
if (lex->chr2 == MP_LEXER_CHAR_EOF) {
lex->chr2 = lex->stream_next_byte(lex->stream_data);
if (lex->chr2 == MP_LEXER_EOF) {
// EOF
if (lex->chr1 != MP_LEXER_CHAR_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
if (lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
lex->chr2 = '\n'; // insert newline at end of file
}
}
}
}
void indent_push(mp_lexer_t *lex, uint indent) {
void indent_push(mp_lexer_t *lex, mp_uint_t 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 + MICROPY_ALLOC_LEXEL_INDENT_INC);
@@ -219,7 +219,7 @@ void indent_push(mp_lexer_t *lex, uint indent) {
lex->indent_level[lex->num_indent_level++] = indent;
}
uint indent_top(mp_lexer_t *lex) {
mp_uint_t indent_top(mp_lexer_t *lex) {
return lex->indent_level[lex->num_indent_level - 1];
}
@@ -308,9 +308,9 @@ STATIC const char *tok_kw[] = {
"__debug__",
};
STATIC int hex_digit(unichar c) {
STATIC mp_uint_t hex_digit(unichar c) {
// c is assumed to be hex digit
int n = c - '0';
mp_uint_t n = c - '0';
if (n > 9) {
n &= ~('a' - 'A');
n -= ('A' - ('9' + 1));
@@ -320,8 +320,9 @@ STATIC int hex_digit(unichar c) {
// This is called with CUR_CHAR() before first hex digit, and should return with
// it pointing to last hex digit
STATIC bool get_hex(mp_lexer_t *lex, int num_digits, uint *result) {
uint num = 0;
// num_digits must be greater than zero
STATIC bool get_hex(mp_lexer_t *lex, mp_uint_t num_digits, mp_uint_t *result) {
mp_uint_t num = 0;
while (num_digits-- != 0) {
next_char(lex);
unichar c = CUR_CHAR(lex);
@@ -394,7 +395,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
} else if (had_physical_newline && lex->nested_bracket_level == 0) {
tok->kind = MP_TOKEN_NEWLINE;
uint num_spaces = lex->column - 1;
mp_uint_t num_spaces = lex->column - 1;
lex->emit_dent = 0;
if (num_spaces == indent_top(lex)) {
} else if (num_spaces > indent_top(lex)) {
@@ -463,7 +464,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
next_char(lex);
// work out if it's a single or triple quoted literal
int num_quotes;
mp_uint_t num_quotes;
if (is_char_and(lex, quote_char, quote_char)) {
// triple quotes
next_char(lex);
@@ -475,7 +476,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
}
// parse the literal
int n_closing = 0;
mp_uint_t n_closing = 0;
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
if (is_char(lex, quote_char)) {
n_closing += 1;
@@ -490,8 +491,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
vstr_add_char(&lex->vstr, '\\');
} else {
switch (c) {
case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
case MP_LEXER_EOF: break; // TODO a proper error message?
case '\n': c = MP_LEXER_EOF; break; // TODO check this works correctly (we are supposed to ignore it
case '\\': break;
case '\'': break;
case '"': break;
@@ -502,24 +503,37 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
case 'v': c = 0x0b; break;
case 'f': c = 0x0c; break;
case 'r': c = 0x0d; break;
case 'u':
case 'U':
if (is_bytes) {
// b'\u1234' == b'\\u1234'
vstr_add_char(&lex->vstr, '\\');
break;
}
// Otherwise fall through.
case 'x':
{
uint num = 0;
if (!get_hex(lex, 2, &num)) {
mp_uint_t num = 0;
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
// TODO error message
assert(0);
}
c = num;
break;
}
case 'N': break; // TODO \N{name} only in strings
case 'u': break; // TODO \uxxxx only in strings
case 'U': break; // TODO \Uxxxxxxxx only in strings
case 'N':
// Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the
// entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly
// 3MB of text; even gzip-compressed and with minimal structure, it'll take
// roughly half a meg of storage. This form of Unicode escape may be added
// later on, but it's definitely not a priority right now. -- CJA 20140607
assert(!"Unicode name escapes not supported");
break;
default:
if (c >= '0' && c <= '7') {
// Octal sequence, 1-3 chars
int digits = 3;
int num = c - '0';
mp_uint_t digits = 3;
mp_uint_t num = c - '0';
while (is_following_odigit(lex) && --digits != 0) {
next_char(lex);
num = num * 8 + (CUR_CHAR(lex) - '0');
@@ -532,11 +546,19 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
break;
}
}
if (c != MP_LEXER_CHAR_EOF) {
vstr_add_char(&lex->vstr, c);
if (c != MP_LEXER_EOF) {
if (c < 0x110000 && !is_bytes) {
vstr_add_char(&lex->vstr, c);
} else if (c < 0x100 && is_bytes) {
vstr_add_byte(&lex->vstr, c);
} else {
assert(!"TODO: Throw an error, invalid escape code probably");
}
}
} else {
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
// Add the "character" as a byte so that we remain 8-bit clean.
// This way, strings are parsed correctly whether or not they contain utf-8 chars.
vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
}
}
next_char(lex);
@@ -608,7 +630,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// search for encoded delimiter or operator
const char *t = tok_enc;
uint tok_enc_index = 0;
mp_uint_t tok_enc_index = 0;
for (; *t != 0 && !is_char(lex, *t); t += 1) {
if (*t == 'e' || *t == 'c') {
t += 1;
@@ -630,7 +652,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// get the maximum characters for a valid token
t += 1;
uint t_index = tok_enc_index;
mp_uint_t t_index = tok_enc_index;
for (;;) {
for (; *t == 'e'; t += 1) {
t += 1;
@@ -693,11 +715,11 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// 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++) {
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
if (str_strn_equal(tok_kw[i], tok->str, tok->len)) {
if (i == ARRAY_SIZE(tok_kw) - 1) {
// tok_kw[ARRAY_SIZE(tok_kw) - 1] == "__debug__"
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
// tok_kw[MP_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;
@@ -708,7 +730,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
}
}
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close) {
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close) {
mp_lexer_t *lex = m_new_maybe(mp_lexer_t, 1);
// check for memory allocation error
@@ -721,7 +743,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
lex->source_name = src_name;
lex->stream_data = stream_data;
lex->stream_next_char = stream_next_char;
lex->stream_next_byte = stream_next_byte;
lex->stream_close = stream_close;
lex->line = 1;
lex->column = 1;
@@ -742,18 +764,18 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
lex->indent_level[0] = 0;
// preload characters
lex->chr0 = stream_next_char(stream_data);
lex->chr1 = stream_next_char(stream_data);
lex->chr2 = stream_next_char(stream_data);
lex->chr0 = stream_next_byte(stream_data);
lex->chr1 = stream_next_byte(stream_data);
lex->chr2 = stream_next_byte(stream_data);
// if input stream is 0, 1 or 2 characters long and doesn't end in a newline, then insert a newline at the end
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
if (lex->chr0 == MP_LEXER_EOF) {
lex->chr0 = '\n';
} else if (lex->chr1 == MP_LEXER_CHAR_EOF) {
} else if (lex->chr1 == MP_LEXER_EOF) {
if (lex->chr0 != '\n' && lex->chr0 != '\r') {
lex->chr1 = '\n';
}
} else if (lex->chr2 == MP_LEXER_CHAR_EOF) {
} else if (lex->chr2 == MP_LEXER_EOF) {
if (lex->chr1 != '\n' && lex->chr1 != '\r') {
lex->chr2 = '\n';
}

View File

@@ -131,27 +131,27 @@ typedef enum _mp_token_kind_t {
} mp_token_kind_t;
typedef struct _mp_token_t {
uint src_line; // source line
uint src_column; // source column
mp_uint_t src_line; // source line
mp_uint_t src_column; // source column
mp_token_kind_t kind; // kind of token
const char *str; // string of token (valid only while this token is current token)
uint len; // (byte) length of string of token
mp_uint_t len; // (byte) length of string of token
} mp_token_t;
// the next-char function must return the next character in the stream
// it must return MP_LEXER_CHAR_EOF if end of stream
// it can be called again after returning MP_LEXER_CHAR_EOF, and in that case must return MP_LEXER_CHAR_EOF
#define MP_LEXER_CHAR_EOF (-1)
typedef unichar (*mp_lexer_stream_next_char_t)(void*);
// the next-byte function must return the next byte in the stream
// it must return MP_LEXER_EOF if end of stream
// it can be called again after returning MP_LEXER_EOF, and in that case must return MP_LEXER_EOF
#define MP_LEXER_EOF (-1)
typedef mp_uint_t (*mp_lexer_stream_next_byte_t)(void*);
typedef void (*mp_lexer_stream_close_t)(void*);
typedef struct _mp_lexer_t mp_lexer_t;
void mp_token_show(const mp_token_t *tok);
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close);
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len);
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close);
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
void mp_lexer_free(mp_lexer_t *lex);
qstr mp_lexer_source_name(mp_lexer_t *lex);
@@ -177,4 +177,4 @@ 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;
extern mp_uint_t mp_optimise_value;

View File

@@ -24,23 +24,23 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
typedef struct _mp_lexer_str_buf_t {
uint free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
const char *src_beg; // beginning of source
const char *src_cur; // current location in source
const char *src_end; // end (exclusive) of source
} mp_lexer_str_buf_t;
STATIC unichar str_buf_next_char(mp_lexer_str_buf_t *sb) {
STATIC mp_uint_t str_buf_next_byte(mp_lexer_str_buf_t *sb) {
if (sb->src_cur < sb->src_end) {
return *sb->src_cur++;
} else {
return MP_LEXER_CHAR_EOF;
return MP_LEXER_EOF;
}
}
@@ -51,11 +51,11 @@ STATIC void str_buf_free(mp_lexer_str_buf_t *sb) {
m_del_obj(mp_lexer_str_buf_t, sb);
}
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len) {
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) {
mp_lexer_str_buf_t *sb = m_new_obj(mp_lexer_str_buf_t);
sb->free_len = free_len;
sb->src_beg = str;
sb->src_cur = str;
sb->src_end = str + len;
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_char_t)str_buf_next_char, (mp_lexer_stream_close_t)str_buf_free);
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str_buf_next_byte, (mp_lexer_stream_close_t)str_buf_free);
}

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#if MICROPY_HELPER_LEXER_UNIX
@@ -41,20 +41,20 @@
typedef struct _mp_lexer_file_buf_t {
int fd;
char buf[20];
uint len;
uint pos;
byte buf[20];
mp_uint_t len;
mp_uint_t pos;
} mp_lexer_file_buf_t;
STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
STATIC mp_uint_t file_buf_next_byte(mp_lexer_file_buf_t *fb) {
if (fb->pos >= fb->len) {
if (fb->len == 0) {
return MP_LEXER_CHAR_EOF;
return MP_LEXER_EOF;
} else {
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
if (n <= 0) {
fb->len = 0;
return MP_LEXER_CHAR_EOF;
return MP_LEXER_EOF;
}
fb->len = n;
fb->pos = 0;
@@ -78,7 +78,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
fb->len = n;
fb->pos = 0;
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);
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_byte_t)file_buf_next_byte, (mp_lexer_stream_close_t)file_buf_close);
}
#endif // MICROPY_HELPER_LEXER_UNIX

View File

@@ -28,8 +28,8 @@
#include <stdlib.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf

View File

@@ -27,8 +27,8 @@
#include <stdlib.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
@@ -167,7 +167,7 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
}
}
machine_uint_t hash = mp_obj_hash(index);
mp_uint_t hash = mp_obj_hash(index);
uint pos = hash % map->alloc;
uint start_pos = pos;
mp_map_elem_t *avail_slot = NULL;
@@ -270,7 +270,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
return NULL;
}
}
machine_uint_t hash = mp_obj_hash(index);
mp_uint_t hash = mp_obj_hash(index);
uint pos = hash % set->alloc;
uint start_pos = pos;
mp_obj_t *avail_slot = NULL;

View File

@@ -82,14 +82,17 @@ int m_get_peak_bytes_allocated(void);
/** array helpers ***********************************************/
// get the number of elements in a fixed-size array
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
// align ptr to the nearest multiple of "alignment"
#define MP_ALIGN(ptr, alignment) (void*)(((mp_uint_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
/** unichar / UTF-8 *********************************************/
typedef int unichar; // TODO
unichar utf8_get_char(const char *s);
char *utf8_next_char(const char *s);
unichar utf8_get_char(const byte *s);
const byte *utf8_next_char(const byte *s);
bool unichar_isspace(unichar c);
bool unichar_isalpha(unichar c);
@@ -100,6 +103,9 @@ bool unichar_isupper(unichar c);
bool unichar_islower(unichar c);
unichar unichar_tolower(unichar c);
unichar unichar_toupper(unichar c);
mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
/** variable string *********************************************/
@@ -163,4 +169,18 @@ int DEBUG_printf(const char *fmt, ...);
extern uint mp_verbose_flag;
// This is useful for unicode handling. Some CPU archs has
// special instructions for efficient implentation of this
// function (e.g. CLZ on ARM).
// NOTE: this function is unused at the moment
#ifndef count_lead_ones
static inline uint count_lead_ones(byte val) {
uint c = 0;
for (byte mask = 0x80; val & mask; mask >>= 1) {
c++;
}
return c;
}
#endif
#endif // _INCLUDED_MINILIB_H

View File

@@ -73,9 +73,9 @@ all: $(PROG)
$(PROG): $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
$(Q)$(CC) $(COPT) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
ifndef DEBUG
$(Q)$(STRIP) $(PROG)
$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
endif
$(Q)$(SIZE) $(PROG)
@@ -97,4 +97,10 @@ print-cfg:
$(ECHO) "OBJ = $(OBJ)"
.PHONY: print-cfg
print-def:
@$(ECHO) "The following defines are built into the $(CC) compiler"
touch __empty__.c
@$(CC) -E -Wp,-dM __empty__.c
@$(RM) -f __empty__.c
-include $(OBJ:.o=.P)

View File

@@ -24,12 +24,14 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#if MICROPY_PY_ARRAY
STATIC const mp_map_elem_t mp_module_array_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array },
@@ -40,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_array_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_array_globals_table),
.alloc = ARRAY_SIZE(mp_module_array_globals_table),
.used = MP_ARRAY_SIZE(mp_module_array_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_array_globals_table),
.table = (mp_map_elem_t*)mp_module_array_globals_table,
},
};
@@ -51,3 +53,5 @@ const mp_obj_module_t mp_module_array = {
.name = MP_QSTR_array,
.globals = (mp_obj_dict_t*)&mp_module_array_globals,
};
#endif

View File

@@ -26,18 +26,27 @@
#include <math.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
/// \module cmath - mathematical functions for complex numbers
///
/// The `cmath` module provides some basic mathematical funtions for
/// working with complex numbers.
// These are defined in modmath.c
/// \constant e - base of the natural logarithm
extern const mp_obj_float_t mp_math_e_obj;
/// \constant pi - the ratio of a circle's circumference to its diameter
extern const mp_obj_float_t mp_math_pi_obj;
/// \function phase(z)
/// Returns the phase of the number `z`, in the range (-pi, +pi].
mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -45,6 +54,8 @@ mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);
/// \function polar(z)
/// Returns, as a tuple, the polar form of `z`.
mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -56,6 +67,8 @@ mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar);
/// \function rect(r, phi)
/// Returns the complex number with modulus `r` and phase `phi`.
mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
mp_float_t r = mp_obj_get_float(r_obj);
mp_float_t phi = mp_obj_get_float(phi_obj);
@@ -63,6 +76,8 @@ mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect);
/// \function exp(z)
/// Return the exponential of `z`.
mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -71,6 +86,8 @@ mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
/// \function log(z)
/// Return the natural logarithm of `z`. The branch cut is along the negative real axis.
// TODO can take second argument, being the base
mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
mp_float_t real, imag;
@@ -79,6 +96,8 @@ mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
/// \function log10(z)
/// Return the base-10 logarithm of `z`. The branch cut is along the negative real axis.
mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -86,6 +105,8 @@ mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
/// \function sqrt(z)
/// Return the square-root of `z`.
mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -95,6 +116,8 @@ mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
/// \function cos(z)
/// Return the cosine of `z`.
mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -102,6 +125,8 @@ mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos);
/// \function sin(z)
/// Return the sine of `z`.
mp_obj_t mp_cmath_sin(mp_obj_t z_obj) {
mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag);
@@ -142,8 +167,8 @@ STATIC const mp_obj_dict_t mp_module_cmath_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_cmath_globals_table),
.alloc = ARRAY_SIZE(mp_module_cmath_globals_table),
.used = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
.table = (mp_map_elem_t*)mp_module_cmath_globals_table,
},
};

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -42,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_collections_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_collections_globals_table),
.alloc = ARRAY_SIZE(mp_module_collections_globals_table),
.used = MP_ARRAY_SIZE(mp_module_collections_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_collections_globals_table),
.table = (mp_map_elem_t*)mp_module_collections_globals_table,
},
};

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -37,35 +37,63 @@
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
/// \module gc - control the garbage collector
extern uint gc_collected;
/// \function collect()
/// Run a garbage collection.
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);
return MP_OBJ_NEW_SMALL_INT(gc_collected);
#else
return mp_const_none;
#endif
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
/// \function disable()
/// Disable the garbage collector.
STATIC mp_obj_t gc_disable(void) {
gc_lock();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
/// \function enable()
/// Enable the garbage collector.
STATIC mp_obj_t gc_enable(void) {
gc_unlock();
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
/// \function mem_free()
/// Return the number of bytes of available heap RAM.
STATIC mp_obj_t gc_mem_free(void) {
gc_info_t info;
gc_info(&info);
return MP_OBJ_NEW_SMALL_INT(info.free);
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);
/// \function mem_alloc()
/// Return the number of bytes of heap RAM that are allocated.
STATIC mp_obj_t gc_mem_alloc(void) {
gc_info_t info;
gc_info(&info);
return MP_OBJ_NEW_SMALL_INT(info.used);
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc);
STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gc) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
};
STATIC const mp_obj_dict_t mp_module_gc_globals = {
@@ -73,8 +101,8 @@ STATIC const mp_obj_dict_t mp_module_gc_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_gc_globals_table),
.alloc = ARRAY_SIZE(mp_module_gc_globals_table),
.used = MP_ARRAY_SIZE(mp_module_gc_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_gc_globals_table),
.table = (mp_map_elem_t*)mp_module_gc_globals_table,
},
};

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -57,8 +57,8 @@ STATIC const mp_obj_dict_t mp_module_io_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_io_globals_table),
.alloc = ARRAY_SIZE(mp_module_io_globals_table),
.used = MP_ARRAY_SIZE(mp_module_io_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_io_globals_table),
.table = (mp_map_elem_t*)mp_module_io_globals_table,
},
};

View File

@@ -26,14 +26,19 @@
#include <math.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
/// \module math - mathematical functions
///
/// The `math` module provides some basic mathematical funtions for
/// working with floating-point numbers.
//TODO: Change macros to check for overflow and raise OverflowError or RangeError
#define MATH_FUN_1(py_name, c_name) \
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
@@ -48,50 +53,95 @@
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
#define MATH_FUN_1_TO_INT(py_name, c_name) \
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((machine_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((mp_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
// These are also used by cmath.c
/// \constant e - base of the natural logarithm
const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E};
/// \constant pi - the ratio of a circle's circumference to its diameter
const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI};
/// \function sqrt(x)
/// Returns the square root of `x`.
MATH_FUN_1(sqrt, sqrt)
/// \function pow(x, y)
/// Returns `x` to the power of `y`.
MATH_FUN_2(pow, pow)
/// \function exp(x)
MATH_FUN_1(exp, exp)
/// \function expm1(x)
MATH_FUN_1(expm1, expm1)
/// \function log(x)
MATH_FUN_1(log, log)
/// \function log2(x)
MATH_FUN_1(log2, log2)
/// \function log10(x)
MATH_FUN_1(log10, log10)
/// \function cosh(x)
MATH_FUN_1(cosh, cosh)
/// \function sinh(x)
MATH_FUN_1(sinh, sinh)
/// \function tanh(x)
MATH_FUN_1(tanh, tanh)
/// \function acosh(x)
MATH_FUN_1(acosh, acosh)
/// \function asinh(x)
MATH_FUN_1(asinh, asinh)
/// \function atanh(x)
MATH_FUN_1(atanh, atanh)
/// \function cos(x)
MATH_FUN_1(cos, cos)
/// \function sin(x)
MATH_FUN_1(sin, sin)
/// \function tan(x)
MATH_FUN_1(tan, tan)
/// \function acos(x)
MATH_FUN_1(acos, acos)
/// \function asin(x)
MATH_FUN_1(asin, asin)
/// \function atan(x)
MATH_FUN_1(atan, atan)
/// \function atan2(y, x)
MATH_FUN_2(atan2, atan2)
/// \function ceil(x)
MATH_FUN_1_TO_INT(ceil, ceil)
/// \function copysign(x, y)
MATH_FUN_2(copysign, copysign)
/// \function fabs(x)
MATH_FUN_1(fabs, fabs)
/// \function floor(x)
MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
/// \function fmod(x, y)
MATH_FUN_2(fmod, fmod)
/// \function isfinite(x)
MATH_FUN_1_TO_BOOL(isfinite, isfinite)
/// \function isinf(x)
MATH_FUN_1_TO_BOOL(isinf, isinf)
/// \function isnan(x)
MATH_FUN_1_TO_BOOL(isnan, isnan)
/// \function trunc(x)
MATH_FUN_1_TO_INT(trunc, trunc)
/// \function ldexp(x, exp)
MATH_FUN_2(ldexp, ldexp)
/// \function erf(x)
/// Return the error function of `x`.
MATH_FUN_1(erf, erf)
/// \function erfc(x)
/// Return the complementary error function of `x`.
MATH_FUN_1(erfc, erfc)
/// \function gamma(x)
/// Return the gamma function of `x`.
MATH_FUN_1(gamma, tgamma)
/// \function lgamma(x)
/// return the natural logarithm of the gamma function of `x`.
MATH_FUN_1(lgamma, lgamma)
//TODO: factorial, fsum
// Functions that return a tuple
/// \function frexp(x)
/// Converts a floating-point number to fractional and integral components.
mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
int int_exponent = 0;
mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
@@ -102,6 +152,7 @@ mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
/// \function modf(x)
mp_obj_t mp_math_modf(mp_obj_t x_obj) {
mp_float_t int_part = 0.0;
mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
@@ -113,11 +164,14 @@ mp_obj_t mp_math_modf(mp_obj_t x_obj) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
// Angular conversions
/// \function radians(x)
mp_obj_t mp_math_radians(mp_obj_t x_obj) {
return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
/// \function degrees(x)
mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI);
}
@@ -172,8 +226,8 @@ STATIC const mp_obj_dict_t mp_module_math_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_math_globals_table),
.alloc = ARRAY_SIZE(mp_module_math_globals_table),
.used = MP_ARRAY_SIZE(mp_module_math_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_math_globals_table),
.table = (mp_map_elem_t*)mp_module_math_globals_table,
},
};

View File

@@ -24,8 +24,8 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -35,15 +35,15 @@
#if MICROPY_MEM_STATS
STATIC mp_obj_t mp_micropython_mem_total() {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_total_bytes_allocated());
return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());
}
STATIC mp_obj_t mp_micropython_mem_current() {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_current_bytes_allocated());
return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());
}
STATIC mp_obj_t mp_micropython_mem_peak() {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)m_get_peak_bytes_allocated());
return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
@@ -51,6 +51,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
#endif
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
#endif
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
#if MICROPY_MEM_STATS
@@ -58,6 +62,9 @@ STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
#endif
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
{ MP_OBJ_NEW_QSTR(MP_QSTR_alloc_emergency_exception_buf), (mp_obj_t)&mp_alloc_emergency_exception_buf_obj },
#endif
};
STATIC const mp_obj_dict_t mp_module_micropython_globals = {
@@ -65,8 +72,8 @@ STATIC const mp_obj_dict_t mp_module_micropython_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_micropython_globals_table),
.alloc = ARRAY_SIZE(mp_module_micropython_globals_table),
.used = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_micropython_globals_table),
.table = (mp_map_elem_t*)mp_module_micropython_globals_table,
},
};

View File

@@ -27,8 +27,8 @@
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -74,13 +74,13 @@ STATIC char get_fmt_type(const char **fmt) {
return t;
}
STATIC machine_uint_t get_fmt_num(const char **p) {
STATIC mp_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));
mp_uint_t val = (mp_uint_t)MP_OBJ_SMALL_INT_VALUE(mp_parse_num_integer(*p, len, 10));
*p = num;
return val;
}
@@ -99,10 +99,10 @@ STATIC uint calcsize_items(const char *fmt) {
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char *fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt);
machine_uint_t size;
mp_uint_t size;
for (size = 0; *fmt; fmt++) {
uint align = 1;
machine_uint_t cnt = 1;
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
@@ -111,14 +111,14 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
assert(*fmt == 's');
}
machine_uint_t sz;
mp_uint_t sz;
if (*fmt == 's') {
sz = cnt;
} else {
sz = (machine_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
sz = (mp_uint_t)mp_binary_get_size(fmt_type, *fmt, &align);
}
// TODO
assert(sz != (machine_uint_t)-1);
assert(sz != (mp_uint_t)-1);
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz;
@@ -138,7 +138,7 @@ 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++) {
machine_uint_t sz = 1;
mp_uint_t sz = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
@@ -170,7 +170,7 @@ 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++) {
machine_uint_t sz = 1;
mp_uint_t sz = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
@@ -182,7 +182,7 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
if (*fmt == 's') {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[i], &bufinfo, MP_BUFFER_READ);
machine_uint_t to_copy = sz;
mp_uint_t to_copy = sz;
if (bufinfo.len < to_copy) {
to_copy = bufinfo.len;
}
@@ -210,8 +210,8 @@ STATIC const mp_obj_dict_t mp_module_struct_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_struct_globals_table),
.alloc = ARRAY_SIZE(mp_module_struct_globals_table),
.used = MP_ARRAY_SIZE(mp_module_struct_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_struct_globals_table),
.table = (mp_map_elem_t*)mp_module_struct_globals_table,
},
};

View File

@@ -24,8 +24,10 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include <stdint.h>
#include <limits.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
@@ -33,25 +35,37 @@
#include "objlist.h"
#include "objtuple.h"
#include "objstr.h"
#include "mpz.h"
#include "objint.h"
#if MICROPY_PY_SYS
/// \module sys - system specific functions
// These should be implemented by ports, specific types don't matter,
// only addresses.
struct _dummy_t;
extern struct _dummy_t mp_sys_exit_obj;
extern struct _dummy_t mp_sys_stdin_obj;
extern struct _dummy_t mp_sys_stdout_obj;
extern struct _dummy_t mp_sys_stderr_obj;
extern mp_obj_int_t mp_maxsize_obj;
// TODO document these properly, they aren't constants or functions...
/// \constant path - a mutable list of directories to search for imported modules
mp_obj_list_t mp_sys_path_obj;
/// \constant argv - a mutable list of arguments this program started with
mp_obj_list_t mp_sys_argv_obj;
/// \constant version - Python language version that this implementation conforms to, as a string
STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
/// \constant version_info - Python language version that this implementation conforms to, as a tuple of ints
#define I(n) MP_OBJ_NEW_SMALL_INT(n)
// TODO: CPython is now at 5-element array, but save 2 els so far...
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
/// \constant platform - the platform that Micro Python is running on
STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
#endif
@@ -65,17 +79,32 @@ STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
#ifdef MICROPY_PY_SYS_PLATFORM
{ MP_OBJ_NEW_QSTR(MP_QSTR_platform), (mp_obj_t)&platform_obj },
#endif
/// \constant byteorder - the byte order of the system ("little" or "big")
#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_PY_SYS_MAXSIZE
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
// INT_MAX is not representable as small int, as we know that small int
// takes one bit for tag. So, we have little choice but to provide this
// value. Apps also should be careful to not try to compare sys.maxsize
// with some number (which may not fit in available int size), but instead
// count number of significant bits in sys.maxsize.
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), MP_OBJ_NEW_SMALL_INT(INT_MAX >> 1) },
#else
{ MP_OBJ_NEW_QSTR(MP_QSTR_maxsize), (mp_obj_t)&mp_maxsize_obj },
#endif
#endif
#if MICROPY_PY_SYS_EXIT
// documented per-port
{ MP_OBJ_NEW_QSTR(MP_QSTR_exit), (mp_obj_t)&mp_sys_exit_obj },
#endif
#if MICROPY_PY_SYS_STDFILES
// documented per-port
{ 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 },
@@ -87,8 +116,8 @@ STATIC const mp_obj_dict_t mp_module_sys_globals = {
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = ARRAY_SIZE(mp_module_sys_globals_table),
.alloc = ARRAY_SIZE(mp_module_sys_globals_table),
.used = MP_ARRAY_SIZE(mp_module_sys_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_sys_globals_table),
.table = (mp_map_elem_t*)mp_module_sys_globals_table,
},
};

View File

@@ -111,6 +111,14 @@
#define MICROPY_EMIT_INLINE_THUMB (0)
#endif
// Whether to emit ARM native code
#ifndef MICROPY_EMIT_ARM
#define MICROPY_EMIT_ARM (0)
#endif
// Convenience definition for whether any native emitter is enabled
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM)
/*****************************************************************************/
/* Compiler configuration */
@@ -157,6 +165,22 @@
#define MICROPY_ENABLE_GC_FINALISER (0)
#endif
// Whether to check C stack usage. C stack used for calling Python functions,
// etc. Not checking means segfault on overflow.
#ifndef MICROPY_STACK_CHECK
#define MICROPY_STACK_CHECK (1)
#endif
// Whether to have an emergency exception buffer
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
#endif
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
# ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
# define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0) // 0 - implies dynamic allocation
# endif
#endif
// Whether to include REPL helper function
#ifndef MICROPY_HELPER_REPL
#define MICROPY_HELPER_REPL (0)
@@ -223,6 +247,10 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_FLOAT (0)
#endif
#ifndef MICROPY_PY_BUILTINS_COMPLEX
#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT)
#endif
// Enable features which improve CPython compatibility
// but may lead to more code size/memory usage.
// TODO: Originally intended as generic category to not
@@ -239,6 +267,16 @@ typedef double mp_float_t;
/*****************************************************************************/
/* Fine control over Python builtins, classes, modules, etc */
// Whether str object is proper unicode
#ifndef MICROPY_PY_BUILTINS_STR_UNICODE
#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
#endif
// Whether to support bytearray object
#ifndef MICROPY_PY_BUILTINS_BYTEARRAY
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#endif
// Whether to support set object
#ifndef MICROPY_PY_BUILTINS_SET
#define MICROPY_PY_BUILTINS_SET (1)
@@ -259,6 +297,18 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_PROPERTY (1)
#endif
// Whether to set __file__ for imported modules
#ifndef MICROPY_PY___FILE__
#define MICROPY_PY___FILE__ (1)
#endif
// Whether to provide "array" module. Note that large chunk of the
// underlying code is shared with "bytearray" builtin type, so to
// get real savings, it should be disabled too.
#ifndef MICROPY_PY_ARRAY
#define MICROPY_PY_ARRAY (1)
#endif
// Whether to provide "collections" module
#ifndef MICROPY_PY_COLLECTIONS
#define MICROPY_PY_COLLECTIONS (1)
@@ -309,6 +359,11 @@ typedef double mp_float_t;
#define MICROPY_PY_SYS (1)
#endif
// Whether to provide "sys.maxsize" constant
#ifndef MICROPY_PY_SYS_MAXSIZE
#define MICROPY_PY_SYS_MAXSIZE (0)
#endif
// Whether to provide "sys.exit" function
#ifndef MICROPY_PY_SYS_EXIT
#define MICROPY_PY_SYS_EXIT (0)
@@ -319,6 +374,17 @@ typedef double mp_float_t;
#define MICROPY_PY_SYS_STDFILES (0)
#endif
// Extended modules
#ifndef MICROPY_PY_UCTYPES
#define MICROPY_PY_UCTYPES (0)
#endif
#ifndef MICROPY_PY_ZLIBD
#define MICROPY_PY_ZLIBD (0)
#endif
/*****************************************************************************/
/* Hooks for a port to add builtins */
@@ -340,6 +406,14 @@ typedef double mp_float_t;
/*****************************************************************************/
/* Miscellaneous settings */
// On embedded platforms, these will typically enable/disable irqs.
#ifndef MICROPY_BEGIN_ATOMIC_SECTION
#define MICROPY_BEGIN_ATOMIC_SECTION()
#endif
#ifndef MICROPY_END_ATOMIC_SECTION
#define MICROPY_END_ATOMIC_SECTION()
#endif
// Allow to override static modifier for global objects, e.g. to use with
// object code analysis tools which don't support static symbols.
#ifndef STATIC
@@ -348,8 +422,8 @@ typedef double mp_float_t;
#define BITS_PER_BYTE (8)
#define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
// machine_int_t value with most significant bit set
#define WORD_MSBIT_HIGH (((machine_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
// mp_int_t value with most significant bit set
#define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
#if !defined(MP_ENDIANNESS_LITTLE) && !defined(MP_ENDIANNESS_BIG)
// Just because most archs are such?
@@ -360,14 +434,20 @@ typedef double mp_float_t;
#define MP_ENDIANNESS_LITTLE (0)
#endif
// printf format spec to use for machine_int_t and friends
// Make a pointer to RAM callable (eg set lower bit for Thumb code)
// (This scheme won't work if we want to mix Thumb and normal ARM code.)
#ifndef MICROPY_MAKE_POINTER_CALLABLE
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
#endif
// printf format spec to use for mp_int_t and friends
#ifndef INT_FMT
#ifdef __LP64__
// Archs where machine_int_t == long, long != int
// Archs where mp_int_t == long, long != int
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
#else
// Archs where machine_int_t == int
// Archs where mp_int_t == int
#define UINT_FMT "%u"
#define INT_FMT "%d"
#endif
@@ -377,3 +457,8 @@ typedef double mp_float_t;
#ifndef NORETURN
#define NORETURN __attribute__((noreturn))
#endif
// Modifier for weak functions
#ifndef MP_WEAK
#define MP_WEAK __attribute__((weak))
#endif

View File

@@ -30,8 +30,8 @@
#include <string.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "mpz.h"
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
@@ -89,12 +89,12 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
mpz_dbl_dig_t d = 0;
for (uint i = jlen; i > 0; i--, idig--, jdig--) {
d |= *jdig;
*idig = d >> (DIG_SIZE - n_part);
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
d <<= DIG_SIZE;
}
// store remaining bits
*idig = d >> (DIG_SIZE - n_part);
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
idig -= n_whole - 1;
memset(idig, 0, (n_whole - 1) * sizeof(mpz_dig_t));
@@ -351,7 +351,7 @@ STATIC uint mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, mpz_dig_t *kdig
modifies den_dig memory, but restors it to original state at end
*/
STATIC void mpn_div(mpz_dig_t *num_dig, machine_uint_t *num_len, mpz_dig_t *den_dig, machine_uint_t den_len, mpz_dig_t *quo_dig, machine_uint_t *quo_len) {
STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) {
mpz_dig_t *orig_num_dig = num_dig;
mpz_dig_t *orig_quo_dig = quo_dig;
mpz_dig_t norm_shift = 0;
@@ -502,12 +502,12 @@ void mpz_init_zero(mpz_t *z) {
z->dig = NULL;
}
void mpz_init_from_int(mpz_t *z, machine_int_t val) {
void mpz_init_from_int(mpz_t *z, mp_int_t val) {
mpz_init_zero(z);
mpz_set_from_int(z, val);
}
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, machine_int_t val) {
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, mp_int_t val) {
z->neg = 0;
z->fixed_dig = 1;
z->alloc = alloc;
@@ -528,7 +528,7 @@ mpz_t *mpz_zero(void) {
return z;
}
mpz_t *mpz_from_int(machine_int_t val) {
mpz_t *mpz_from_int(mp_int_t val) {
mpz_t *z = mpz_zero();
mpz_set_from_int(z, val);
return z;
@@ -594,10 +594,10 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
memcpy(dest->dig, src->dig, src->len * sizeof(mpz_dig_t));
}
void mpz_set_from_int(mpz_t *z, machine_int_t val) {
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
machine_uint_t uval;
mp_uint_t uval;
if (val < 0) {
z->neg = 1;
uval = -val;
@@ -704,7 +704,7 @@ int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
#if 0
// obsolete
// compares mpz with an integer that fits within DIG_SIZE bits
int mpz_cmp_sml_int(const mpz_t *z, machine_int_t sml_int) {
int mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
int cmp;
if (z->neg == 0) {
if (sml_int < 0) return 1;
@@ -830,7 +830,7 @@ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
/* computes dest = lhs << rhs
can have dest, lhs the same
*/
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
if (lhs->len == 0 || rhs == 0) {
mpz_set(dest, lhs);
} else if (rhs < 0) {
@@ -845,7 +845,7 @@ void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
/* computes dest = lhs >> rhs
can have dest, lhs the same
*/
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs) {
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
if (lhs->len == 0 || rhs == 0) {
mpz_set(dest, lhs);
} else if (rhs < 0) {
@@ -1132,12 +1132,9 @@ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
lcm(0, 0) = 0
lcm(z, 0) = 0
*/
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2)
{
// braces below are required for compilation to succeed with CL, see bug report
// https://connect.microsoft.com/VisualStudio/feedback/details/864169/compilation-error-when-braces-are-left-out-of-single-line-if-statement
if (z1->len == 0 || z2->len == 0) {
return mpz_zero();
mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) {
if (z1->len == 0 || z2->len == 0) {
return mpz_zero();
}
mpz_t *gcd = mpz_gcd(z1, z2);
@@ -1213,45 +1210,32 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
}
#endif
// TODO check that this correctly handles overflow in all cases
machine_int_t mpz_as_int(const mpz_t *i) {
machine_int_t val = 0;
mpz_dig_t *d = i->dig + i->len;
// must return actual int value if it fits in mp_int_t
mp_int_t mpz_hash(const mpz_t *z) {
mp_int_t val = 0;
mpz_dig_t *d = z->dig + z->len;
while (--d >= i->dig) {
machine_int_t oldval = val;
while (--d >= z->dig) {
val = (val << DIG_SIZE) | *d;
if (val < oldval) {
// overflow, return +/- "infinity"
if (i->neg == 0) {
// +infinity
return ~WORD_MSBIT_HIGH;
} else {
// -infinity
return WORD_MSBIT_HIGH;
}
}
}
if (i->neg != 0) {
if (z->neg != 0) {
val = -val;
}
return val;
}
// TODO check that this correctly handles overflow in all cases
bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
machine_int_t val = 0;
bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
mp_int_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
machine_int_t oldval = val;
val = (val << DIG_SIZE) | *d;
if (val < oldval) {
// overflow
if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
// will overflow
return false;
}
val = (val << DIG_SIZE) | *d;
}
if (i->neg != 0) {
@@ -1262,6 +1246,27 @@ bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) {
return true;
}
bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
if (i->neg != 0) {
// can't represent signed values
return false;
}
mp_uint_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
if (val > ((~0) >> DIG_SIZE)) {
// will overflow
return false;
}
val = (val << DIG_SIZE) | *d;
}
*value = val;
return true;
}
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *i) {
mp_float_t val = 0;

View File

@@ -29,27 +29,27 @@ typedef uint32_t mpz_dbl_dig_t;
typedef int32_t mpz_dbl_dig_signed_t;
typedef struct _mpz_t {
machine_uint_t neg : 1;
machine_uint_t fixed_dig : 1;
machine_uint_t alloc : 30;
machine_uint_t len;
mp_uint_t neg : 1;
mp_uint_t fixed_dig : 1;
mp_uint_t alloc : 30;
mp_uint_t len;
mpz_dig_t *dig;
} mpz_t;
#define MPZ_DIG_SIZE (15) // see mpn_div for why this needs to be at most 15
#define MPZ_NUM_DIG_FOR_INT (sizeof(machine_int_t) * 8 / MPZ_DIG_SIZE + 1)
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
void mpz_init_zero(mpz_t *z);
void mpz_init_from_int(mpz_t *z, machine_int_t val);
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, machine_int_t val);
void mpz_init_from_int(mpz_t *z, mp_int_t val);
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, mp_int_t val);
void mpz_deinit(mpz_t *z);
mpz_t *mpz_zero();
mpz_t *mpz_from_int(machine_int_t i);
mpz_t *mpz_from_int(mp_int_t i);
mpz_t *mpz_from_ll(long long i);
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base);
void mpz_free(mpz_t *z);
@@ -57,7 +57,7 @@ void mpz_free(mpz_t *z);
mpz_t *mpz_clone(const mpz_t *src);
void mpz_set(mpz_t *dest, const mpz_t *src);
void mpz_set_from_int(mpz_t *z, machine_int_t src);
void mpz_set_from_int(mpz_t *z, mp_int_t src);
void mpz_set_from_ll(mpz_t *z, long long i);
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base);
@@ -79,8 +79,8 @@ mpz_t *mpz_pow(const mpz_t *lhs, const mpz_t *rhs);
void mpz_abs_inpl(mpz_t *dest, const mpz_t *z);
void mpz_neg_inpl(mpz_t *dest, const mpz_t *z);
void mpz_not_inpl(mpz_t *dest, const mpz_t *z);
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, machine_int_t rhs);
void mpz_shl_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs);
void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
void mpz_mul_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
@@ -96,8 +96,9 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs);
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);
mp_int_t mpz_hash(const mpz_t *z);
bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *z);
#endif

136
py/nativeglue.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
#include "emitglue.h"
#if MICROPY_EMIT_NATIVE
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
// convert a Micro Python object to a valid native value based on type
mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) {
DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type);
switch (type & 3) {
case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
case MP_NATIVE_TYPE_BOOL:
case MP_NATIVE_TYPE_INT:
case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
default: assert(0); return 0;
}
}
// convert a native value to a Micro Python object based on type
mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) {
DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
switch (type & 3) {
case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
default: assert(0); return mp_const_none;
}
}
// wrapper that accepts n_args and n_kw in one argument
// (native emitter can only pass at most 3 arguments to a function)
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args) {
return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
}
// wrapper that makes raise obj and raises it
NORETURN void mp_native_raise(mp_obj_t o) {
nlr_raise(mp_make_raise_obj(o));
}
// these must correspond to the respective enum in runtime0.h
void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_convert_obj_to_native,
mp_convert_native_to_obj,
mp_load_const_int,
mp_load_const_dec,
mp_load_const_str,
mp_load_const_bytes,
mp_load_name,
mp_load_global,
mp_load_build_class,
mp_load_attr,
mp_load_method,
mp_store_name,
mp_store_global,
mp_store_attr,
mp_obj_subscr,
mp_obj_is_true,
mp_unary_op,
mp_binary_op,
mp_obj_new_tuple,
mp_obj_new_list,
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_native_call_function_n_kw,
mp_call_method_n_kw,
mp_getiter,
mp_iternext,
nlr_push,
nlr_pop,
mp_native_raise,
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,
};
/*
void mp_f_vector(mp_fun_kind_t fun_kind) {
(mp_f_table[fun_kind])();
}
*/
#endif // MICROPY_EMIT_NATIVE

View File

@@ -29,6 +29,7 @@
#include <limits.h>
#include <setjmp.h>
#include <assert.h>
typedef struct _nlr_buf_t nlr_buf_t;
struct _nlr_buf_t {
@@ -44,7 +45,7 @@ struct _nlr_buf_t {
#else
void *regs[8];
#endif
#elif defined(__thumb2__)
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
void *regs[10];
#else
#define MICROPY_NLR_SETJMP (1)

View File

@@ -24,19 +24,21 @@
* THE SOFTWARE.
*/
#if defined(__thumb2__) && !MICROPY_NLR_SETJMP
/* thumb callee save: bx, bp, sp, r12, r14, r14, r15 */
#if !MICROPY_NLR_SETJMP && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
/* arm callee save: bx, bp, sp, r12, r14, r14, r15 */
.syntax unified
/*.cpu cortex-m4*/
.thumb
/*.thumb*/
.text
.align 2
/* uint nlr_push(r0=nlr_buf_t *nlr) */
.global nlr_push
#if defined(__thumb2__)
.thumb
.thumb_func
#endif
.type nlr_push, %function
nlr_push:
str lr, [r0, #8] @ store lr into nlr_buf
@@ -64,8 +66,10 @@ nlr_push:
@ void nlr_pop()
.global nlr_pop
#if defined(__thumb2__)
.thumb
.thumb_func
#endif
.type nlr_pop, %function
nlr_pop:
ldr r3, .L5 @ load addr of nlr_top
@@ -80,8 +84,10 @@ nlr_pop:
/* void nlr_jump(r0=uint val) */
.global nlr_jump
#if defined(__thumb2__)
.thumb
.thumb_func
#endif
.type nlr_jump, %function
nlr_jump:
ldr r3, .L2 @ load addr of nlr_top

View File

@@ -24,6 +24,7 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
@@ -33,8 +34,11 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "mpz.h"
#include "objint.h"
#include "runtime0.h"
#include "runtime.h"
#include "stackctrl.h"
mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
if (MP_OBJ_IS_SMALL_INT(o_in)) {
@@ -59,6 +63,8 @@ void printf_wrapper(void *env, const char *fmt, ...) {
}
void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
// There can be data structures nested too deep, or just recursive
MP_STACK_CHECK();
#if !NDEBUG
if (o_in == NULL) {
print(env, "(nil)");
@@ -80,7 +86,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
// helper function to print an exception with traceback
void mp_obj_print_exception(mp_obj_t exc) {
if (mp_obj_is_exception_instance(exc)) {
machine_uint_t n, *values;
mp_uint_t n, *values;
mp_obj_exception_get_traceback(exc, &n, &values);
if (n > 0) {
assert(n % 3 == 0);
@@ -142,23 +148,25 @@ bool mp_obj_is_callable(mp_obj_t o_in) {
return mp_obj_get_type(o_in)->call != NULL;
}
machine_int_t mp_obj_hash(mp_obj_t o_in) {
mp_int_t mp_obj_hash(mp_obj_t o_in) {
if (o_in == mp_const_false) {
return 0; // needs to hash to same as the integer 0, since False==0
} else if (o_in == mp_const_true) {
return 1; // needs to hash to same as the integer 1, since True==1
} else if (MP_OBJ_IS_SMALL_INT(o_in)) {
return MP_OBJ_SMALL_INT_VALUE(o_in);
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_int)) {
return mp_obj_int_hash(o_in);
} else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
return mp_obj_str_get_hash(o_in);
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {
return (machine_int_t)o_in;
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_fun_native) || MP_OBJ_IS_TYPE(o_in, &mp_type_fun_bc)) {
return (machine_int_t)o_in;
return (mp_int_t)o_in;
} else if (MP_OBJ_IS_FUN(o_in)) {
return (mp_int_t)o_in;
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) {
return mp_obj_tuple_hash(o_in);
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) {
return (machine_int_t)o_in;
return (mp_int_t)o_in;
// TODO hash class and instances
// TODO delegate to __hash__ method if it exists
@@ -222,7 +230,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
return false;
}
machine_int_t mp_obj_get_int(mp_const_obj_t arg) {
mp_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].
@@ -241,8 +249,8 @@ machine_int_t mp_obj_get_int(mp_const_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_const_obj_t arg, machine_int_t *value) {
// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
if (arg == mp_const_false) {
*value = 0;
} else if (arg == mp_const_true) {
@@ -274,6 +282,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
}
}
#if MICROPY_PY_BUILTINS_COMPLEX
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
if (arg == mp_const_false) {
*real = 0;
@@ -297,6 +306,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
}
}
#endif
#endif
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
@@ -325,8 +335,8 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
}
// is_slice determines whether the index is a slice index
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice) {
machine_int_t i;
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) {
mp_int_t i;
if (MP_OBJ_IS_SMALL_INT(index)) {
i = MP_OBJ_SMALL_INT_VALUE(index);
} else if (!mp_obj_get_int_maybe(index, &i)) {
@@ -350,10 +360,25 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index,
return i;
}
// will raise a TypeError if object has no length
mp_obj_t mp_obj_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in);
if (len == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
} else {
return len;
}
}
// may return MP_OBJ_NULL
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in));
if (
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// It's simple - unicode is slow, non-unicode is fast
MP_OBJ_IS_STR(o_in) ||
#endif
MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
return MP_OBJ_NEW_SMALL_INT(mp_obj_str_get_len(o_in));
} else {
mp_obj_type_t *type = mp_obj_get_type(o_in);
if (type->unary_op != NULL) {
@@ -395,7 +420,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
return false;
}
int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);
if (ret != 0 || bufinfo->buf == NULL) {
if (ret != 0) {
return false;
}
return true;

132
py/obj.h
View File

@@ -35,11 +35,6 @@
typedef machine_ptr_t mp_obj_t;
typedef machine_const_ptr_t mp_const_obj_t;
// Integers that fit in a pointer have this type
// (do we need to expose this in the public API?)
typedef machine_int_t mp_small_int_t;
// Anything that wants to be a Micro Python object must have
// mp_obj_base_t as its first member (except small ints and qstrs)
@@ -73,25 +68,27 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// These macros check for small int, qstr or object, and access small int and qstr values
// 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)
//#define MP_OBJ_IS_OBJ(o) ((((mp_small_int_t)(o)) & 3) == 0)
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking a string, use below macro for that
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_int_t)(o)) & 1) != 0)
//#define MP_OBJ_IS_QSTR(o) ((((mp_int_t)(o)) & 3) == 2)
//#define MP_OBJ_IS_OBJ(o) ((((mp_int_t)(o)) & 3) == 0)
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)(o))->type->binary_op == mp_obj_str_binary_op))
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type->binary_op == mp_obj_fun_binary_op))
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_small_int_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((small_int) << 1) | 1))
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
#define MP_OBJ_QSTR_VALUE(o) (((mp_small_int_t)(o)) >> 2)
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((machine_uint_t)qstr) << 2) | 2))
#define MP_OBJ_QSTR_VALUE(o) (((mp_int_t)(o)) >> 2)
#define MP_OBJ_NEW_QSTR(qstr) ((mp_obj_t)((((mp_uint_t)(qstr)) << 2) | 2))
// These macros are used to declare and define constant function objects
// You can put "static" in front of the definitions to make them local
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_native_t obj_name
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_native_t obj_name = {{&mp_type_fun_native}, is_kw, n_args_min, n_args_max, (void *)fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_builtin_t obj_name = {{&mp_type_fun_builtin}, is_kw, n_args_min, n_args_max, (void *)fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 0, 0, (mp_fun_0_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 1, 1, (mp_fun_1_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 2, 2, (mp_fun_2_t)fun_name)
@@ -137,10 +134,10 @@ typedef struct _mp_map_elem_t {
// would also need a trucated dict structure
typedef struct _mp_map_t {
machine_uint_t all_keys_are_qstrs : 1;
machine_uint_t table_is_fixed_array : 1;
machine_uint_t used : (8 * sizeof(machine_uint_t) - 2);
machine_uint_t alloc;
mp_uint_t all_keys_are_qstrs : 1;
mp_uint_t table_is_fixed_array : 1;
mp_uint_t used : (8 * sizeof(mp_uint_t) - 2);
mp_uint_t alloc;
mp_map_elem_t *table;
} mp_map_t;
@@ -151,7 +148,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(const 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, mp_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);
@@ -165,12 +162,12 @@ void mp_map_dump(mp_map_t *map);
// Underlying set implementation (not set object)
typedef struct _mp_set_t {
machine_uint_t alloc;
machine_uint_t used;
mp_uint_t alloc;
mp_uint_t used;
mp_obj_t *table;
} mp_set_t;
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); }
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, mp_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);
@@ -183,7 +180,6 @@ typedef mp_obj_t (*mp_fun_0_t)(void);
typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);
typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_t)(void);
typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *);
typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
@@ -215,8 +211,8 @@ typedef struct _mp_buffer_info_t {
// them with ver = sizeof(struct). Cons: overkill for *micro*?
//int ver; // ?
void *buf;
machine_int_t len; // in bytes
void *buf; // can be NULL if len == 0
mp_int_t len; // in bytes
int typecode; // as per binary.h
// Rationale: to load arbitrary-sized sprites directly to LCD
@@ -227,19 +223,20 @@ typedef struct _mp_buffer_info_t {
#define MP_BUFFER_WRITE (2)
#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE)
typedef struct _mp_buffer_p_t {
machine_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
} mp_buffer_p_t;
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
// Stream protocol
#define MP_STREAM_ERROR (-1)
typedef struct _mp_stream_p_t {
// On error, functions should return -1 and fill in *errcode (values are
// implementation-dependent, but will be exposed to user, e.g. via exception).
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);
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
// are implementation-dependent, but will be exposed to user, e.g. via exception).
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
// add seek() ?
int is_bytes : 1;
int is_text : 1; // default is bytes, set this for text stream
} mp_stream_p_t;
struct _mp_obj_type_t {
@@ -308,7 +305,7 @@ extern const mp_obj_type_t mp_type_zip;
extern const mp_obj_type_t mp_type_array;
extern const mp_obj_type_t mp_type_super;
extern const mp_obj_type_t mp_type_gen_instance;
extern const mp_obj_type_t mp_type_fun_native;
extern const mp_obj_type_t mp_type_fun_builtin;
extern const mp_obj_type_t mp_type_fun_bc;
extern const mp_obj_type_t mp_type_module;
extern const mp_obj_type_t mp_type_staticmethod;
@@ -316,6 +313,7 @@ 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;
extern const mp_obj_type_t mp_type_reversed;
// Exceptions
extern const mp_obj_type_t mp_type_BaseException;
@@ -365,8 +363,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);
mp_obj_t mp_obj_new_none(void);
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(mp_int_t value);
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
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 char* data, uint len, bool make_qstr_if_not_already);
@@ -380,8 +378,10 @@ 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, 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_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
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);
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
@@ -406,20 +406,20 @@ void mp_obj_print_exception(mp_obj_t exc);
int mp_obj_is_true(mp_obj_t arg);
// TODO make these all lower case when they have proven themselves
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 0); }
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 1) != 0); }
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); }
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 1) != 0); }
//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that
//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int
static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_small_int_t)(o)) & 3) == 2); }
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); }
//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); }
bool mp_obj_is_callable(mp_obj_t o_in);
machine_int_t mp_obj_hash(mp_obj_t o_in);
mp_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_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, machine_int_t *value);
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_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);
@@ -427,26 +427,27 @@ void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
//qstr mp_obj_get_qstr(mp_obj_t arg);
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items);
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items);
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, bool is_slice);
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice);
mp_obj_t mp_obj_len(mp_obj_t o_in);
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return MP_OBJ_NULL */
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);
// bool
// TODO make lower case when it has proven itself
static inline mp_obj_t MP_BOOL(machine_int_t x) { return x ? mp_const_true : mp_const_false; }
static inline mp_obj_t MP_BOOL(mp_int_t x) { return x ? mp_const_true : mp_const_false; }
// cell
mp_obj_t mp_obj_cell_get(mp_obj_t self_in);
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_const_obj_t self_in);
// For long int, returns value truncated to mp_int_t
mp_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_const_obj_t self_in);
// Will raise exception if value doesn't fit into mp_int_t
mp_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)
@@ -454,14 +455,17 @@ bool mp_obj_is_exception_type(mp_obj_t self_in);
bool mp_obj_is_exception_instance(mp_obj_t self_in);
bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type);
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block);
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values);
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block);
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
void mp_init_emergency_exception_buf(void);
// str
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in);
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len);
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);
uint mp_obj_str_get_hash(mp_obj_t self_in);
uint mp_obj_str_get_len(mp_obj_t self_in);
@@ -469,7 +473,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve
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);
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len, bool is_bytes);
#if MICROPY_PY_BUILTINS_FLOAT
// float
@@ -488,7 +492,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
// tuple
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
void mp_obj_tuple_del(mp_obj_t self_in);
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in);
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
// list
struct _mp_obj_list_t;
@@ -523,17 +527,15 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items);
// functions
#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM
mp_obj_base_t base;
bool is_kw : 1;
uint n_args_min : 15; // inclusive
uint n_args_max : 16; // inclusive
void *fun;
// TODO add mp_map_t *globals
// for const function objects, make an empty, const map
// such functions won't be able to access the global scope, but that's probably okay
} mp_obj_fun_native_t;
mp_uint_t n_args_min : 15; // inclusive
mp_uint_t n_args_max : 16; // inclusive
void *fun; // must be a pointer to a callable function in ROM
} mp_obj_fun_builtin_t;
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
const char *mp_obj_fun_get_name(mp_const_obj_t fun);
const char *mp_obj_code_get_name(const byte *code_info);
@@ -562,14 +564,14 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
// slice indexes resolved to particular sequence
typedef struct {
machine_uint_t start;
machine_uint_t stop;
machine_int_t step;
mp_uint_t start;
mp_uint_t stop;
mp_int_t step;
} mp_bound_slice_t;
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
#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);
bool mp_seq_get_fast_slice_indexes(mp_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)); }

View File

@@ -37,19 +37,22 @@
#include "runtime.h"
#include "binary.h"
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
typedef struct _mp_obj_array_t {
mp_obj_base_t base;
machine_uint_t typecode : 8;
mp_uint_t typecode : 8;
// free is number of unused elements after len used elements
// alloc size = len + free
machine_uint_t free : (8 * sizeof(machine_uint_t) - 8);
machine_uint_t len; // in elements
mp_uint_t free : (8 * sizeof(mp_uint_t) - 8);
mp_uint_t len; // in elements
void *items;
} mp_obj_array_t;
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
STATIC mp_obj_array_t *array_new(char typecode, uint n);
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags);
/******************************************************************************/
/* array */
@@ -57,8 +60,8 @@ STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_array_t *o = o_in;
if (o->typecode == BYTEARRAY_TYPECODE) {
print(env, "bytearray(b", o->typecode);
mp_str_print_quoted(print, env, o->items, o->len);
print(env, "bytearray(b");
mp_str_print_quoted(print, env, o->items, o->len, true);
} else {
print(env, "array('%c'", o->typecode);
if (o->len > 0) {
@@ -144,6 +147,22 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
}
}
STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
switch (op) {
case MP_BINARY_OP_EQUAL: {
mp_buffer_info_t lhs_bufinfo;
mp_buffer_info_t rhs_bufinfo;
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
return mp_const_false;
}
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
}
default:
return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_array) || MP_OBJ_IS_TYPE(self_in, &mp_type_bytearray));
mp_obj_array_t *self = self_in;
@@ -204,7 +223,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
}
}
STATIC machine_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
mp_obj_array_t *o = o_in;
bufinfo->buf = o->items;
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
@@ -225,6 +244,7 @@ const mp_obj_type_t mp_type_array = {
.make_new = array_make_new,
.getiter = array_iterator_new,
.unary_op = array_unary_op,
.binary_op = array_binary_op,
.subscr = array_subscr,
.buffer_p = { .get_buffer = array_get_buffer },
.locals_dict = (mp_obj_t)&array_locals_dict,
@@ -237,6 +257,7 @@ const mp_obj_type_t mp_type_bytearray = {
.make_new = bytearray_make_new,
.getiter = array_iterator_new,
.unary_op = array_unary_op,
.binary_op = array_binary_op,
.subscr = array_subscr,
.buffer_p = { .get_buffer = array_get_buffer },
.locals_dict = (mp_obj_t)&array_locals_dict,
@@ -283,7 +304,7 @@ mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
typedef struct _mp_obj_array_it_t {
mp_obj_base_t base;
mp_obj_array_t *array;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_array_it_t;
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
@@ -310,3 +331,5 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
o->cur = 0;
return o;
}
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY

View File

@@ -61,7 +61,7 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
}
STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
machine_int_t value = ((mp_obj_bool_t*)o_in)->value;
mp_int_t value = ((mp_obj_bool_t*)o_in)->value;
switch (op) {
case MP_UNARY_OP_BOOL: return o_in;
case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value);
@@ -74,7 +74,7 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
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_binary_op(op, MP_OBJ_NEW_SMALL_INT(mp_obj_is_true(lhs_in)), rhs_in);
}
return MP_OBJ_NULL; // op not supported
}

View File

@@ -37,7 +37,7 @@
typedef struct _mp_obj_closure_t {
mp_obj_base_t base;
mp_obj_t fun;
machine_uint_t n_closed;
mp_uint_t n_closed;
mp_obj_t closed[];
} mp_obj_closure_t;

View File

@@ -36,7 +36,7 @@
#include "runtime0.h"
#include "runtime.h"
#if MICROPY_PY_BUILTINS_FLOAT
#if MICROPY_PY_BUILTINS_COMPLEX
#include <math.h>
@@ -132,6 +132,15 @@ STATIC mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
}
STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_complex_t *self = self_in;
if (attr == MP_QSTR_real) {
dest[0] = mp_obj_new_float(self->real);
} else if (attr == MP_QSTR_imag) {
dest[0] = mp_obj_new_float(self->imag);
}
}
const mp_obj_type_t mp_type_complex = {
{ &mp_type_type },
.name = MP_QSTR_complex,
@@ -139,6 +148,7 @@ const mp_obj_type_t mp_type_complex = {
.make_new = complex_make_new,
.unary_op = complex_unary_op,
.binary_op = complex_binary_op,
.load_attr = complex_load_attr,
};
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {

View File

@@ -75,7 +75,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
mp_obj_dict_t *self = 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);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used);
default: return MP_OBJ_NULL; // op not supported
}
}
@@ -94,10 +94,10 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return mp_const_false;
}
machine_uint_t size = o->map.alloc;
mp_uint_t size = o->map.alloc;
mp_map_t *map = &o->map;
for (machine_uint_t i = 0; i < size; i++) {
for (mp_uint_t i = 0; i < size; i++) {
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, map->table[i].key, MP_MAP_LOOKUP);
if (elem == NULL || !mp_obj_equal(map->table[i].value, elem->value)) {
@@ -155,12 +155,12 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
typedef struct _mp_obj_dict_it_t {
mp_obj_base_t base;
mp_obj_dict_t *dict;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_dict_it_t;
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
mp_obj_dict_it_t *self = self_in;
machine_uint_t max = self->dict->map.alloc;
mp_uint_t max = self->dict->map.alloc;
mp_map_t *map = &self->dict->map;
for (int i = self->cur; i < max; i++) {
@@ -374,7 +374,7 @@ STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs)
}
// update the dict with any keyword args
for (machine_uint_t i = 0; i < kwargs->alloc; i++) {
for (mp_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;
}
@@ -403,7 +403,7 @@ typedef struct _mp_obj_dict_view_it_t {
mp_obj_base_t base;
mp_dict_view_kind_t kind;
mp_obj_dict_it_t *iter;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_dict_view_it_t;
typedef struct _mp_obj_dict_view_t {

View File

@@ -27,8 +27,8 @@
#include <stdlib.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
@@ -36,7 +36,7 @@
typedef struct _mp_obj_enumerate_t {
mp_obj_base_t base;
mp_obj_t iter;
machine_int_t cur;
mp_int_t cur;
} mp_obj_enumerate_t;
STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in);
@@ -45,7 +45,7 @@ STATIC const mp_arg_t enumerate_make_new_args[] = {
{ MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_start, MP_ARG_INT, {.u_int = 0} },
};
#define ENUMERATE_MAKE_NEW_NUM_ARGS ARRAY_SIZE(enumerate_make_new_args)
#define ENUMERATE_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(enumerate_make_new_args)
STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
#if MICROPY_CPYTHON_COMPAT

View File

@@ -27,16 +27,20 @@
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <stdio.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "objlist.h"
#include "objstr.h"
#include "objtuple.h"
#include "objtype.h"
#include "runtime.h"
#include "runtime0.h"
#include "gc.h"
typedef struct _mp_obj_exception_t {
mp_obj_base_t base;
@@ -50,6 +54,53 @@ const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_
// Local non-heap memory for allocating an exception when we run out of RAM
STATIC mp_obj_exception_t mp_emergency_exception_obj;
// Optionally allocated buffer for storing the first argument of an exception
// allocated when the heap is locked.
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
STATIC byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
#define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
void mp_init_emergency_exception_buf(void) {
// Nothing to do since the buffer was declared statically. We put this
// definition here so that the calling code can call this function
// regardless of how its configured (makes the calling code a bit cleaner).
}
#else
STATIC mp_int_t mp_emergency_exception_buf_size = 0;
STATIC byte *mp_emergency_exception_buf = NULL;
void mp_init_emergency_exception_buf(void) {
mp_emergency_exception_buf_size = 0;
mp_emergency_exception_buf = NULL;
}
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
mp_int_t size = mp_obj_get_int(size_in);
void *buf = NULL;
if (size > 0) {
buf = m_malloc(size);
}
int old_size = mp_emergency_exception_buf_size;
void *old_buf = mp_emergency_exception_buf;
// Update the 2 variables atomically so that an interrupt can't occur
// between the assignments.
mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
mp_emergency_exception_buf_size = size;
mp_emergency_exception_buf = buf;
MICROPY_END_ATOMIC_SECTION(irq_state);
if (old_buf != NULL) {
m_free(old_buf, old_size);
}
return mp_const_none;
}
#endif
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// Instance of GeneratorExit exception - needed by generator.close()
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
// definition module-private so far, have it here.
@@ -267,6 +318,50 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
o->base.type = exc_type;
o->traceback = MP_OBJ_NULL;
o->args = mp_const_empty_tuple;
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// If the user has provided a buffer, then we try to create a tuple
// of length 1, which has a string object and the string data.
if (mp_emergency_exception_buf_size > (sizeof(mp_obj_tuple_t) + sizeof(mp_obj_str_t) + sizeof(mp_obj_t))) {
mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_emergency_exception_buf;
mp_obj_str_t *str = (mp_obj_str_t *)&tuple->items[1];
tuple->base.type = &mp_type_tuple;
tuple->len = 1;
tuple->items[0] = str;
byte *str_data = (byte *)&str[1];
uint max_len = mp_emergency_exception_buf + mp_emergency_exception_buf_size
- str_data;
va_list ap;
va_start(ap, fmt);
str->len = vsnprintf((char *)str_data, max_len, fmt, ap);
va_end(ap);
str->base.type = &mp_type_str;
str->hash = qstr_compute_hash(str_data, str->len);
str->data = str_data;
o->args = tuple;
uint offset = &str_data[str->len] - mp_emergency_exception_buf;
offset += sizeof(void *) - 1;
offset &= ~(sizeof(void *) - 1);
if ((mp_emergency_exception_buf_size - offset) > (sizeof(mp_obj_list_t) + sizeof(mp_obj_t) * 3)) {
// We have room to store some traceback.
mp_obj_list_t *list = (mp_obj_list_t *)((byte *)mp_emergency_exception_buf + offset);
list->base.type = &mp_type_list;
list->items = (mp_obj_t)&list[1];
list->alloc = (mp_emergency_exception_buf + mp_emergency_exception_buf_size - (byte *)list->items) / sizeof(list->items[0]);
list->len = 0;
o->traceback = list;
}
}
#endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
} else {
o->base.type = exc_type;
o->traceback = MP_OBJ_NULL;
@@ -334,19 +429,35 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
self->traceback = MP_OBJ_NULL;
}
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) {
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block) {
GET_NATIVE_EXCEPTION(self, self_in);
#if MICROPY_ENABLE_GC
if (gc_is_locked()) {
if (self->traceback == MP_OBJ_NULL) {
// We can't allocate any memory, and no memory has been
// pre-allocated, so there is nothing else we can do.
return;
}
mp_obj_list_t *list = self->traceback;
if (list->alloc <= (list->len + 3)) {
// There is some preallocated memory, but not enough to store an
// entire record.
return;
}
}
#endif
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
if (self->traceback == MP_OBJ_NULL) {
self->traceback = mp_obj_new_list(0, NULL);
}
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file);
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line);
mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block);
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)file);
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)line);
mp_obj_list_append(self->traceback, (mp_obj_t)(mp_uint_t)block);
}
void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) {
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values) {
GET_NATIVE_EXCEPTION(self, self_in);
if (self->traceback == MP_OBJ_NULL) {

View File

@@ -102,9 +102,12 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) {
STATIC mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_float_t *lhs = lhs_in;
#if MICROPY_PY_BUILTINS_COMPLEX
if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
return mp_obj_complex_binary_op(op, lhs->value, 0, rhs_in);
} else {
} else
#endif
{
return mp_obj_float_binary_op(op, lhs->value, rhs_in);
}
}

View File

@@ -39,6 +39,7 @@
#include "runtime0.h"
#include "runtime.h"
#include "bc.h"
#include "stackctrl.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -46,12 +47,9 @@
#define DEBUG_printf(...) (void)0
#endif
/******************************************************************************/
/* native functions */
// mp_obj_fun_native_t defined in obj.h
STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// This binary_op method is used for all function types, and is also
// used to determine if an object is of generic function type.
mp_obj_t mp_obj_fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
switch (op) {
case MP_BINARY_OP_EQUAL:
// These objects can be equal only if it's the same underlying structure,
@@ -61,9 +59,14 @@ STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
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) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native));
mp_obj_fun_native_t *self = self_in;
/******************************************************************************/
/* builtin functions */
// mp_obj_fun_builtin_t defined in obj.h
STATIC mp_obj_t fun_builtin_call(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_fun_builtin));
mp_obj_fun_builtin_t *self = self_in;
// check number of arguments
mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw);
@@ -106,26 +109,16 @@ STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const
}
}
const mp_obj_type_t mp_type_fun_native = {
const mp_obj_type_t mp_type_fun_builtin = {
{ &mp_type_type },
.name = MP_QSTR_function,
.call = fun_native_call,
.binary_op = fun_binary_op,
.call = fun_builtin_call,
.binary_op = mp_obj_fun_binary_op,
};
// fun must have the correct signature for n_args fixed arguments
mp_obj_t mp_make_function_n(int n_args, void *fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
o->base.type = &mp_type_fun_native;
o->is_kw = false;
o->n_args_min = n_args;
o->n_args_max = n_args;
o->fun = fun;
return o;
}
#if 0 // currently unused, and semi-obsolete
mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
o->base.type = &mp_type_fun_native;
o->is_kw = false;
o->n_args_min = n_args_min;
@@ -136,7 +129,7 @@ mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun) {
// min and max are inclusive
mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun) {
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
mp_obj_fun_builtin_t *o = m_new_obj(mp_obj_fun_builtin_t);
o->base.type = &mp_type_fun_native;
o->is_kw = false;
o->n_args_min = n_args_min;
@@ -144,6 +137,7 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var
o->fun = fun;
return o;
}
#endif
/******************************************************************************/
/* byte code functions */
@@ -178,7 +172,7 @@ STATIC void dump_args(const mp_obj_t *a, int sz) {
#define dump_args(...) (void)0
#endif
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, uint given) {
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
// Generic message, to be reused for other argument issues
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
@@ -196,16 +190,18 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui
// 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))
#define VM_MAX_STATE_ON_STACK (10 * sizeof(mp_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) {
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t 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.
mp_obj_fun_bc_t *self = self_in;
machine_uint_t n_state = code_state->n_state;
mp_uint_t n_state = code_state->n_state;
const byte *ip = code_state->ip;
code_state->code_info = self->bytecode;
@@ -240,7 +236,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
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
for (uint i = n_args; i < self->n_pos_args; i++) {
for (mp_uint_t 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 {
@@ -250,7 +246,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
}
// copy positional args into state
for (uint i = 0; i < n_args; i++) {
for (mp_uint_t i = 0; i < n_args; i++) {
code_state->state[n_state - 1 - i] = args[i];
}
@@ -266,9 +262,9 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_arg
*var_pos_kw_args = dict;
}
for (uint i = 0; i < n_kw; i++) {
for (mp_uint_t 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++) {
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
if (arg_name == self->args[j]) {
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
@@ -311,7 +307,7 @@ continue2:;
// Check that all mandatory keyword args are specified
// Fill in default kw args if we have them
for (uint i = 0; i < self->n_kwonly_args; i++) {
for (mp_uint_t 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) {
@@ -338,8 +334,8 @@ continue2:;
}
// bytecode prelude: initialise closed over variables
for (uint n_local = *ip++; n_local > 0; n_local--) {
uint local_num = *ip++;
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
mp_uint_t local_num = *ip++;
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
}
@@ -353,8 +349,7 @@ continue2:;
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.
MP_STACK_CHECK();
DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
DEBUG_printf("Input pos args: ");
@@ -367,12 +362,12 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
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);
mp_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);
mp_uint_t n_state = ip[0] | (ip[1] << 8);
mp_uint_t n_exc_stack = ip[2] | (ip[3] << 8);
ip += 4;
#if VM_DETECT_STACK_OVERFLOW
@@ -380,7 +375,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
#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_uint_t 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);
@@ -411,7 +406,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o
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++) {
for (mp_uint_t 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;
@@ -463,12 +458,12 @@ const mp_obj_type_t mp_type_fun_bc = {
.print = fun_bc_print,
#endif
.call = fun_bc_call,
.binary_op = fun_binary_op,
.binary_op = mp_obj_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, mp_obj_t def_kw_args, const byte *code) {
uint n_def_args = 0;
uint n_extra_args = 0;
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
mp_uint_t n_def_args = 0;
mp_uint_t n_extra_args = 0;
mp_obj_tuple_t *def_args = def_args_in;
if (def_args != MP_OBJ_NULL) {
assert(MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
@@ -498,22 +493,144 @@ mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n
return o;
}
/******************************************************************************/
/* native functions */
#if MICROPY_EMIT_NATIVE
typedef struct _mp_obj_fun_native_t {
mp_obj_base_t base;
mp_uint_t n_args;
void *fun_data; // GC must be able to trace this pointer
// TODO add mp_map_t *globals
} mp_obj_fun_native_t;
typedef mp_obj_t (*native_fun_0_t)();
typedef mp_obj_t (*native_fun_1_t)(mp_obj_t);
typedef mp_obj_t (*native_fun_2_t)(mp_obj_t, mp_obj_t);
typedef mp_obj_t (*native_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_fun_native_t *self = self_in;
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
switch (n_args) {
case 0:
return ((native_fun_0_t)fun)();
case 1:
return ((native_fun_1_t)fun)(args[0]);
case 2:
return ((native_fun_2_t)fun)(args[0], args[1]);
case 3:
return ((native_fun_3_t)fun)(args[0], args[1], args[2]);
default:
assert(0);
return mp_const_none;
}
}
STATIC const mp_obj_type_t mp_type_fun_native = {
{ &mp_type_type },
.name = MP_QSTR_function,
.call = fun_native_call,
.binary_op = mp_obj_fun_binary_op,
};
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data) {
assert(0 <= n_args && n_args <= 3);
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
o->base.type = &mp_type_fun_native;
o->n_args = n_args;
o->fun_data = fun_data;
return o;
}
#endif // MICROPY_EMIT_NATIVE
/******************************************************************************/
/* viper functions */
#if MICROPY_EMIT_NATIVE
typedef struct _mp_obj_fun_viper_t {
mp_obj_base_t base;
mp_uint_t n_args;
void *fun_data; // GC must be able to trace this pointer
mp_uint_t type_sig;
} mp_obj_fun_viper_t;
typedef mp_uint_t (*viper_fun_0_t)();
typedef mp_uint_t (*viper_fun_1_t)(mp_uint_t);
typedef mp_uint_t (*viper_fun_2_t)(mp_uint_t, mp_uint_t);
typedef mp_uint_t (*viper_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
STATIC mp_obj_t fun_viper_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_fun_viper_t *self = self_in;
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
mp_uint_t ret;
if (n_args == 0) {
ret = ((viper_fun_0_t)fun)();
} else if (n_args == 1) {
ret = ((viper_fun_1_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2));
} else if (n_args == 2) {
ret = ((viper_fun_2_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4));
} else if (n_args == 3) {
ret = ((viper_fun_3_t)fun)(mp_convert_obj_to_native(args[0], self->type_sig >> 2), mp_convert_obj_to_native(args[1], self->type_sig >> 4), mp_convert_obj_to_native(args[2], self->type_sig >> 6));
} else {
assert(0);
ret = 0;
}
return mp_convert_native_to_obj(ret, self->type_sig);
}
STATIC const mp_obj_type_t mp_type_fun_viper = {
{ &mp_type_type },
.name = MP_QSTR_function,
.call = fun_viper_call,
.binary_op = mp_obj_fun_binary_op,
};
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig) {
mp_obj_fun_viper_t *o = m_new_obj(mp_obj_fun_viper_t);
o->base.type = &mp_type_fun_viper;
o->n_args = n_args;
o->fun_data = fun_data;
o->type_sig = type_sig;
return o;
}
#endif // MICROPY_EMIT_NATIVE
/******************************************************************************/
/* inline assembler functions */
#if MICROPY_EMIT_INLINE_THUMB
typedef struct _mp_obj_fun_asm_t {
mp_obj_base_t base;
int n_args;
void *fun;
mp_uint_t n_args;
void *fun_data; // GC must be able to trace this pointer
} mp_obj_fun_asm_t;
typedef machine_uint_t (*inline_asm_fun_0_t)();
typedef machine_uint_t (*inline_asm_fun_1_t)(machine_uint_t);
typedef machine_uint_t (*inline_asm_fun_2_t)(machine_uint_t, machine_uint_t);
typedef machine_uint_t (*inline_asm_fun_3_t)(machine_uint_t, machine_uint_t, machine_uint_t);
typedef mp_uint_t (*inline_asm_fun_0_t)();
typedef mp_uint_t (*inline_asm_fun_1_t)(mp_uint_t);
typedef mp_uint_t (*inline_asm_fun_2_t)(mp_uint_t, mp_uint_t);
typedef mp_uint_t (*inline_asm_fun_3_t)(mp_uint_t, mp_uint_t, mp_uint_t);
// convert a Micro Python object to a sensible value for inline asm
STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
// TODO for byte_array, pass pointer to the array
if (MP_OBJ_IS_SMALL_INT(obj)) {
return MP_OBJ_SMALL_INT_VALUE(obj);
@@ -526,42 +643,42 @@ STATIC machine_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
} else if (MP_OBJ_IS_STR(obj)) {
// pointer to the string (it's probably constant though!)
uint l;
return (machine_uint_t)mp_obj_str_get_data(obj, &l);
return (mp_uint_t)mp_obj_str_get_data(obj, &l);
} else {
mp_obj_type_t *type = mp_obj_get_type(obj);
if (0) {
#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);
return (mp_int_t)mp_obj_float_get(obj);
#endif
} else if (type == &mp_type_tuple) {
// pointer to start of tuple (could pass length, but then could use len(x) for that)
uint len;
mp_obj_t *items;
mp_obj_tuple_get(obj, &len, &items);
return (machine_uint_t)items;
return (mp_uint_t)items;
} else if (type == &mp_type_list) {
// pointer to start of list (could pass length, but then could use len(x) for that)
uint len;
mp_obj_t *items;
mp_obj_list_get(obj, &len, &items);
return (machine_uint_t)items;
return (mp_uint_t)items;
} else {
mp_buffer_info_t bufinfo;
if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_WRITE)) {
// supports the buffer protocol, return a pointer to the data
return (machine_uint_t)bufinfo.buf;
return (mp_uint_t)bufinfo.buf;
} else {
// just pass along a pointer to the object
return (machine_uint_t)obj;
return (mp_uint_t)obj;
}
}
}
}
// convert a return value from inline asm to a sensible Micro Python object
STATIC mp_obj_t convert_val_from_inline_asm(machine_uint_t val) {
STATIC mp_obj_t convert_val_from_inline_asm(mp_uint_t val) {
return MP_OBJ_NEW_SMALL_INT(val);
}
@@ -570,15 +687,17 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
machine_uint_t ret;
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
mp_uint_t ret;
if (n_args == 0) {
ret = ((inline_asm_fun_0_t)self->fun)();
ret = ((inline_asm_fun_0_t)fun)();
} else if (n_args == 1) {
ret = ((inline_asm_fun_1_t)self->fun)(convert_obj_for_inline_asm(args[0]));
ret = ((inline_asm_fun_1_t)fun)(convert_obj_for_inline_asm(args[0]));
} else if (n_args == 2) {
ret = ((inline_asm_fun_2_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
ret = ((inline_asm_fun_2_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]));
} else if (n_args == 3) {
ret = ((inline_asm_fun_3_t)self->fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
ret = ((inline_asm_fun_3_t)fun)(convert_obj_for_inline_asm(args[0]), convert_obj_for_inline_asm(args[1]), convert_obj_for_inline_asm(args[2]));
} else {
assert(0);
ret = 0;
@@ -591,13 +710,15 @@ STATIC const mp_obj_type_t mp_type_fun_asm = {
{ &mp_type_type },
.name = MP_QSTR_function,
.call = fun_asm_call,
.binary_op = fun_binary_op,
.binary_op = mp_obj_fun_binary_op,
};
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) {
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data) {
mp_obj_fun_asm_t *o = m_new_obj(mp_obj_fun_asm_t);
o->base.type = &mp_type_fun_asm;
o->n_args = n_args;
o->fun = fun;
o->fun_data = fun_data;
return o;
}
#endif // MICROPY_EMIT_INLINE_THUMB

View File

@@ -26,15 +26,15 @@
typedef struct _mp_obj_fun_bc_t {
mp_obj_base_t base;
mp_obj_dict_t *globals; // the context within which this function was defined
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)
mp_obj_dict_t *globals; // the context within which this function was defined
mp_uint_t n_pos_args : 16; // number of arguments this function takes
mp_uint_t n_kwonly_args : 16; // number of arguments this function takes
mp_uint_t n_def_args : 16; // number of default arguments
mp_uint_t has_def_kw_args : 1; // set if this function has default keyword args
mp_uint_t takes_var_args : 1; // set if this function takes variable args
mp_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)
// 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)

View File

@@ -59,12 +59,12 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp
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);
mp_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);
mp_uint_t n_state = bytecode[0] | (bytecode[1] << 8);
mp_uint_t n_exc_stack = bytecode[2] | (bytecode[3] << 8);
bytecode += 4;
// allocate the generator object, with room for local stack and exception stack

View File

@@ -38,6 +38,7 @@
#include "smallint.h"
#include "mpz.h"
#include "objint.h"
#include "objstr.h"
#include "runtime0.h"
#include "runtime.h"
@@ -57,14 +58,14 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
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])) {
} else if (MP_OBJ_IS_STR_OR_BYTES(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_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]))));
return MP_OBJ_NEW_SMALL_INT((MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
#endif
} else {
// try to convert to small int (eg from bool)
@@ -85,7 +86,7 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
// The size of this buffer is rather arbitrary. If it's not large
// enough, a dynamic one will be allocated.
char stack_buf[sizeof(machine_int_t) * 4];
char stack_buf[sizeof(mp_int_t) * 4];
char *buf = stack_buf;
int buf_size = sizeof(stack_buf);
int fmt_size;
@@ -101,7 +102,7 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
typedef mp_longint_impl_t fmt_int_t;
#else
typedef mp_small_int_t fmt_int_t;
typedef mp_int_t fmt_int_t;
#endif
STATIC const uint log_base2_floor[] = {
@@ -145,7 +146,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
// Not a small int.
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
const mp_obj_int_t *self = self_in;
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
// Get the value to format; mp_obj_get_int truncates to mp_int_t.
num = self->val;
#else
// Delegate to the implementation for the long int.
@@ -215,6 +216,10 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
bool mp_obj_int_is_positive(mp_obj_t self_in) {
return mp_obj_get_int(self_in) >= 0;
}
@@ -241,7 +246,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
return mp_const_none;
}
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
// SMALL_INT accepts only signed numbers, of one bit less size
// then word size, which totals 2 bits less for unsigned numbers.
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
@@ -251,7 +256,7 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
return mp_const_none;
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
mp_obj_t mp_obj_new_int(mp_int_t value) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
@@ -259,11 +264,11 @@ mp_obj_t mp_obj_new_int(machine_int_t value) {
return mp_const_none;
}
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
mp_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_const_obj_t self_in) {
mp_int_t mp_obj_int_get_checked(mp_const_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_
// true acts as 0
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
} else if (op == MP_BINARY_OP_MULTIPLY) {
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
// multiply is commutative for these types, so delegate to them
return mp_binary_op(op, rhs_in, lhs_in);
}
@@ -304,7 +309,7 @@ STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
// convert the bytes to an integer
machine_uint_t value = 0;
mp_uint_t value = 0;
for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
value = (value << 8) | *buf;
}
@@ -316,7 +321,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_fro
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, (const mp_obj_t)&int_from_bytes_fun_obj);
STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
machine_int_t val = mp_obj_int_get_checked(args[0]);
mp_int_t val = mp_obj_int_get_checked(args[0]);
uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
byte *data;
@@ -326,7 +331,7 @@ STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
// TODO: Support signed param
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
memset(data, 0, len);
memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
memcpy(data, &val, len < sizeof(mp_int_t) ? len : sizeof(mp_int_t));
return mp_obj_str_builder_end(o);
}

View File

@@ -38,6 +38,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
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_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
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);
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);

View File

@@ -50,6 +50,21 @@
#define SUFFIX ""
#endif
#if MICROPY_PY_SYS_MAXSIZE
// Export value for sys.maxsize
const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, INT_MAX};
#endif
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
mp_obj_int_t *self = self_in;
// truncate value to fit in mp_int_t, which gives the same hash as
// small int if the value fits without truncation
return self->val;
}
bool mp_obj_int_is_positive(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
@@ -140,14 +155,14 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
mp_obj_t mp_obj_new_int(mp_int_t value) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
return mp_obj_new_int_from_ll(value);
}
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
// SMALL_INT accepts only signed numbers, of one bit less size
// than word size, which totals 2 bits less for unsigned numbers.
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
@@ -174,7 +189,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint
return o;
}
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
mp_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 {
@@ -183,7 +198,7 @@ machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
}
}
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
// TODO: Check overflow
return mp_obj_int_get(self_in);
}

View File

@@ -43,6 +43,26 @@
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
#if MICROPY_PY_SYS_MAXSIZE
// Export value for sys.maxsize
#define DIG_MASK ((1 << MPZ_DIG_SIZE) - 1)
STATIC const mpz_dig_t maxsize_dig[MPZ_NUM_DIG_FOR_INT] = {
(INT_MAX >> MPZ_DIG_SIZE * 0) & DIG_MASK,
(INT_MAX >> MPZ_DIG_SIZE * 1) & DIG_MASK,
(INT_MAX >> MPZ_DIG_SIZE * 2) & DIG_MASK,
#if (INT_MAX >> MPZ_DIG_SIZE * 2) > DIG_MASK
(INT_MAX >> MPZ_DIG_SIZE * 3) & DIG_MASK,
(INT_MAX >> MPZ_DIG_SIZE * 4) & DIG_MASK,
// (INT_MAX >> MPZ_DIG_SIZE * 5) & DIG_MASK,
#endif
};
const mp_obj_int_t mp_maxsize_obj = {
{&mp_type_int},
{.fixed_dig = 1, .len = MPZ_NUM_DIG_FOR_INT, .alloc = MPZ_NUM_DIG_FOR_INT, .dig = (mpz_dig_t*)maxsize_dig}
};
#undef DIG_MASK
#endif
STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
o->base.type = &mp_type_int;
@@ -76,6 +96,14 @@ char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_con
return str;
}
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in);
}
mp_obj_int_t *self = self_in;
return mpz_hash(&self->mpz);
}
bool mp_obj_int_is_positive(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
@@ -121,8 +149,10 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
#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);
#if MICROPY_PY_BUILTINS_COMPLEX
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) {
return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
#endif
#endif
} else {
// delegate to generic function to check for extra cases
@@ -195,8 +225,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_INPLACE_LSHIFT:
case MP_BINARY_OP_RSHIFT:
case MP_BINARY_OP_INPLACE_RSHIFT: {
// TODO check conversion overflow
machine_int_t irhs = mpz_as_int(zrhs);
mp_int_t irhs = mp_obj_int_get_checked(rhs_in);
if (irhs < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
}
@@ -239,7 +268,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
}
mp_obj_t mp_obj_new_int(machine_int_t value) {
mp_obj_t mp_obj_new_int(mp_int_t value) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
}
@@ -252,7 +281,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
return o;
}
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
// SMALL_INT accepts only signed numbers, of one bit less size
// than word size, which totals 2 bits less for unsigned numbers.
if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
@@ -268,21 +297,22 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint
return o;
}
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
mp_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 {
const mp_obj_int_t *self = self_in;
return mpz_as_int(&self->mpz);
// TODO this is a hack until we remove mp_obj_int_get function entirely
return mpz_hash(&self->mpz);
}
}
machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
mp_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 {
const mp_obj_int_t *self = self_in;
machine_int_t value;
mp_int_t value;
if (mpz_as_int_checked(&self->mpz, &value)) {
return value;
} else {

View File

@@ -127,10 +127,13 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return o;
}
case MP_BINARY_OP_MULTIPLY: {
machine_int_t n;
mp_int_t n;
if (!mp_obj_get_int_maybe(rhs, &n)) {
return MP_OBJ_NULL; // op not supported
}
if (n < 0) {
n = 0;
}
mp_obj_list_t *s = list_new(o->len * n);
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
return s;
@@ -488,7 +491,7 @@ void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
typedef struct _mp_obj_list_it_t {
mp_obj_base_t base;
mp_obj_list_t *list;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_list_it_t;
mp_obj_t list_it_iternext(mp_obj_t self_in) {

View File

@@ -26,7 +26,7 @@
typedef struct _mp_obj_list_t {
mp_obj_base_t base;
machine_uint_t alloc;
machine_uint_t len;
mp_uint_t alloc;
mp_uint_t len;
mp_obj_t *items;
} mp_obj_list_t;

View File

@@ -36,7 +36,7 @@
typedef struct _mp_obj_map_t {
mp_obj_base_t base;
machine_uint_t n_iters;
mp_uint_t n_iters;
mp_obj_t fun;
mp_obj_t iters[];
} mp_obj_map_t;

View File

@@ -31,6 +31,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
/******************************************************************************/
@@ -39,9 +40,9 @@
typedef struct _mp_obj_range_it_t {
mp_obj_base_t base;
// TODO make these values generic objects or something
machine_int_t cur;
machine_int_t stop;
machine_int_t step;
mp_int_t cur;
mp_int_t stop;
mp_int_t step;
} mp_obj_range_it_t;
STATIC mp_obj_t range_it_iternext(mp_obj_t o_in) {
@@ -77,11 +78,21 @@ mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step) {
typedef struct _mp_obj_range_t {
mp_obj_base_t base;
// TODO make these values generic objects or something
machine_int_t start;
machine_int_t stop;
machine_int_t step;
mp_int_t start;
mp_int_t stop;
mp_int_t step;
} mp_obj_range_t;
STATIC void range_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_range_t *self = self_in;
print(env, "range(%d, %d", self->start, self->stop);
if (self->step == 1) {
print(env, ")");
} else {
print(env, ", %d)", self->step);
}
}
STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 3, false);
@@ -96,6 +107,7 @@ STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
o->start = mp_obj_get_int(args[0]);
o->stop = mp_obj_get_int(args[1]);
if (n_args == 3) {
// TODO check step is non-zero
o->step = mp_obj_get_int(args[2]);
}
}
@@ -103,6 +115,55 @@ STATIC mp_obj_t range_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
return o;
}
STATIC mp_int_t range_len(mp_obj_range_t *self) {
// When computing length, need to take into account step!=1 and step<0.
mp_int_t len = self->stop - self->start + self->step;
if (self->step > 0) {
len -= 1;
} else {
len += 1;
}
len = len / self->step;
if (len < 0) {
len = 0;
}
return len;
}
STATIC mp_obj_t range_unary_op(int op, mp_obj_t self_in) {
mp_obj_range_t *self = self_in;
mp_int_t len = range_len(self);
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(len > 0);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len);
default: return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) {
// load
mp_obj_range_t *self = self_in;
mp_int_t len = range_len(self);
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_bound_slice_t slice;
mp_seq_get_fast_slice_indexes(len, index, &slice);
mp_obj_range_t *o = m_new_obj(mp_obj_range_t);
o->base.type = &mp_type_range;
o->start = slice.start;
o->stop = slice.stop;
o->step = slice.step;
return o;
}
#endif
uint index_val = mp_get_index(self->base.type, len, index, false);
return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step);
} else {
return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
mp_obj_range_t *o = o_in;
return mp_obj_new_range_iterator(o->start, o->stop, o->step);
@@ -111,6 +172,9 @@ STATIC mp_obj_t range_getiter(mp_obj_t o_in) {
const mp_obj_type_t mp_type_range = {
{ &mp_type_type },
.name = MP_QSTR_range,
.print = range_print,
.make_new = range_make_new,
.unary_op = range_unary_op,
.subscr = range_subscr,
.getiter = range_getiter,
};

74
py/objreversed.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
typedef struct _mp_obj_reversed_t {
mp_obj_base_t base;
mp_obj_t seq; // sequence object that we are reversing
mp_uint_t cur_index; // current index, plus 1; 0=no more, 1=last one (index 0)
} mp_obj_reversed_t;
STATIC mp_obj_t reversed_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
mp_obj_reversed_t *o = m_new_obj(mp_obj_reversed_t);
o->base.type = &mp_type_reversed;
o->seq = args[0];
o->cur_index = mp_obj_get_int(mp_obj_len(args[0])); // start at the end of the sequence
return o;
}
STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed));
mp_obj_reversed_t *self = self_in;
// "raise" stop iteration if we are at the end (the start) of the sequence
if (self->cur_index == 0) {
return MP_OBJ_STOP_ITERATION;
}
// pre-decrement and index sequence
self->cur_index -= 1;
return mp_obj_subscr(self->seq, MP_OBJ_NEW_SMALL_INT(self->cur_index), MP_OBJ_SENTINEL);
}
const mp_obj_type_t mp_type_reversed = {
{ &mp_type_type },
.name = MP_QSTR_reversed,
.make_new = reversed_make_new,
.getiter = mp_identity,
.iternext = reversed_iternext,
};

View File

@@ -47,7 +47,7 @@ typedef struct _mp_obj_set_t {
typedef struct _mp_obj_set_it_t {
mp_obj_base_t base;
mp_obj_set_t *set;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_set_it_t;
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in);
@@ -160,10 +160,10 @@ const mp_obj_type_t mp_type_set_it = {
STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set_it));
mp_obj_set_it_t *self = self_in;
machine_uint_t max = self->set->set.alloc;
mp_uint_t max = self->set->set.alloc;
mp_set_t *set = &self->set->set;
for (machine_uint_t i = self->cur; i < max; i++) {
for (mp_uint_t i = self->cur; i < max; i++) {
if (MP_SET_SLOT_IS_FILLED(set, i)) {
self->cur = i + 1;
return set->table[i];
@@ -476,7 +476,7 @@ STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) {
mp_obj_set_t *self = 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);
case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->set.used);
default: return MP_OBJ_NULL; // op not supported
}
}

View File

@@ -32,6 +32,7 @@
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "unicode.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
@@ -43,28 +44,16 @@
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
#define GET_STR_HASH(str_obj_in, str_hash) uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
// use this macro to extract the string length
#define GET_STR_LEN(str_obj_in, str_len) uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; }
// use this macro to extract the string data and length
#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
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 NORETURN void bad_implicit_conversion(mp_obj_t self_in);
STATIC NORETURN void arg_type_mixup();
STATIC bool is_str_or_bytes(mp_obj_t o) {
return MP_OBJ_IS_STR(o) || MP_OBJ_IS_TYPE(o, &mp_type_bytes);
}
/******************************************************************************/
/* str */
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env,
const byte *str_data, uint str_len, bool is_bytes) {
// 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;
@@ -85,7 +74,10 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
print(env, "\\%c", quote_char);
} else if (*s == '\\') {
print(env, "\\\\");
} else if (32 <= *s && *s <= 126) {
} else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
// In strings, anything which is not ascii control character
// is printed as is, this includes characters in range 0x80-0xff
// (which can be non-Latin letters, etc.)
print(env, "%c", *s);
} else if (*s == '\n') {
print(env, "\\n");
@@ -109,7 +101,7 @@ STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env,
if (is_bytes) {
print(env, "b");
}
mp_str_print_quoted(print, env, str_data, str_len);
mp_str_print_quoted(print, env, str_data, str_len, is_bytes);
}
}
@@ -230,9 +222,9 @@ wrong_args:
// like strstr but with specified length and allows \0 bytes
// TODO replace with something more efficient/standard
STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, const byte *needle, machine_uint_t nlen, machine_int_t direction) {
STATIC const byte *find_subbytes(const byte *haystack, mp_uint_t hlen, const byte *needle, mp_uint_t nlen, mp_int_t direction) {
if (hlen >= nlen) {
machine_uint_t str_index, str_index_end;
mp_uint_t str_index, str_index_end;
if (direction > 0) {
str_index = 0;
str_index_end = hlen - nlen;
@@ -255,7 +247,10 @@ STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, cons
return NULL;
}
STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// Note: this function is used to check if an object is a str or bytes, which
// works because both those types use it as their binary_op method. Revisit
// MP_OBJ_IS_STR_OR_BYTES if this fact changes.
mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);
mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
mp_obj_type_t *rhs_type = mp_obj_get_type(rhs_in);
@@ -294,10 +289,16 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
break;
case MP_BINARY_OP_MULTIPLY: {
if (!MP_OBJ_IS_SMALL_INT(rhs_in)) {
mp_int_t n;
if (!mp_obj_get_int_maybe(rhs_in, &n)) {
return MP_OBJ_NULL; // op not supported
}
int n = MP_OBJ_SMALL_INT_VALUE(rhs_in);
if (n <= 0) {
if (lhs_type == &mp_type_str) {
return MP_OBJ_NEW_QSTR(MP_QSTR_); // empty str
}
n = 0;
}
byte *data;
mp_obj_t s = mp_obj_str_builder_start(lhs_type, lhs_len * n, &data);
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, data);
@@ -348,7 +349,17 @@ uncomparable:
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) {
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// objstrunicode defines own version
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
mp_obj_t index, bool is_slice) {
mp_uint_t index_val = mp_get_index(type, self_len, index, is_slice);
return self_data + index_val;
}
#endif
// This is used for both bytes and 8-bit strings. This is not used for unicode strings.
STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_type_t *type = mp_obj_get_type(self_in);
GET_STR_DATA_LEN(self_in, self_data, self_len);
if (value == MP_OBJ_SENTINEL) {
@@ -363,11 +374,12 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
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]);
mp_uint_t index_val = mp_get_index(type, self_len, index, false);
// If we have unicode enabled the type will always be bytes, so take the short cut.
if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
} else {
return mp_obj_new_str((char*)self_data + index_val, 1, true);
return mp_obj_new_str((char*)&self_data[index_val], 1, true);
}
} else {
return MP_OBJ_NULL; // op not supported
@@ -375,7 +387,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
}
STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
assert(is_str_or_bytes(self_in));
assert(MP_OBJ_IS_STR_OR_BYTES(self_in));
const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
// get separation string
@@ -430,7 +442,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
machine_int_t splits = -1;
mp_int_t splits = -1;
mp_obj_t sep = mp_const_none;
if (n_args > 1) {
sep = args[1];
@@ -467,6 +479,9 @@ STATIC mp_obj_t str_split(uint n_args, const mp_obj_t *args) {
} else {
// sep given
if (mp_obj_get_type(sep) != self_type) {
arg_type_mixup();
}
uint sep_len;
const char *sep_str = mp_obj_str_get_data(sep, &sep_len);
@@ -510,8 +525,8 @@ STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
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;
mp_int_t splits = mp_obj_get_int(args[2]);
mp_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);
@@ -561,8 +576,8 @@ STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) {
return res;
}
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) {
STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, mp_int_t direction, bool is_index) {
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
assert(2 <= n_args && n_args <= 4);
assert(MP_OBJ_IS_STR(args[0]));
assert(MP_OBJ_IS_STR(args[1]));
@@ -570,16 +585,16 @@ STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t dire
GET_STR_DATA_LEN(args[0], haystack, haystack_len);
GET_STR_DATA_LEN(args[1], needle, needle_len);
machine_uint_t start = 0;
machine_uint_t end = haystack_len;
const byte *start = haystack;
const byte *end = haystack + haystack_len;
if (n_args >= 3 && args[2] != mp_const_none) {
start = mp_get_index(&mp_type_str, haystack_len, args[2], true);
start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
}
if (n_args >= 4 && args[3] != mp_const_none) {
end = mp_get_index(&mp_type_str, haystack_len, args[3], true);
end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
}
const byte *p = find_subbytes(haystack + start, end - start, needle, needle_len, direction);
const byte *p = find_subbytes(start, end - start, needle, needle_len, direction);
if (p == NULL) {
// not found
if (is_index) {
@@ -589,6 +604,11 @@ STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t dire
}
} else {
// found
#if MICROPY_PY_BUILTINS_STR_UNICODE
if (self_type == &mp_type_str) {
return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p));
}
#endif
return MP_OBJ_NEW_SMALL_INT(p - haystack);
}
}
@@ -611,16 +631,17 @@ 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(uint n_args, const mp_obj_t *args) {
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
GET_STR_DATA_LEN(args[0], str, str_len);
GET_STR_DATA_LEN(args[1], prefix, prefix_len);
uint index_val = 0;
const byte *start = str;
if (n_args > 2) {
index_val = mp_get_index(&mp_type_str, str_len, args[2], true);
start = str_index_to_ptr(self_type, str, str_len, args[2], true);
}
if (prefix_len + index_val > str_len) {
if (prefix_len + (start - str) > str_len) {
return mp_const_false;
}
return MP_BOOL(memcmp(str + index_val, prefix, prefix_len) == 0);
return MP_BOOL(memcmp(start, prefix, prefix_len) == 0);
}
STATIC mp_obj_t str_endswith(uint n_args, const mp_obj_t *args) {
@@ -638,7 +659,7 @@ enum { LSTRIP, RSTRIP, STRIP };
STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
assert(1 <= n_args && n_args <= 2);
assert(is_str_or_bytes(args[0]));
assert(MP_OBJ_IS_STR_OR_BYTES(args[0]));
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
const byte *chars_to_del;
@@ -659,16 +680,16 @@ STATIC mp_obj_t str_uni_strip(int type, uint n_args, const mp_obj_t *args) {
GET_STR_DATA_LEN(args[0], orig_str, orig_str_len);
machine_uint_t first_good_char_pos = 0;
mp_uint_t first_good_char_pos = 0;
bool first_good_char_pos_set = false;
machine_uint_t last_good_char_pos = 0;
machine_uint_t i = 0;
machine_int_t delta = 1;
mp_uint_t last_good_char_pos = 0;
mp_uint_t i = 0;
mp_int_t delta = 1;
if (type == RSTRIP) {
i = orig_str_len - 1;
delta = -1;
}
for (machine_uint_t len = orig_str_len; len > 0; len--) {
for (mp_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;
@@ -694,7 +715,7 @@ 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;
mp_uint_t stripped_len = last_good_char_pos - first_good_char_pos + 1;
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()
@@ -757,7 +778,7 @@ static mp_obj_t arg_as_int(mp_obj_t arg) {
// TODO: Needs a way to construct an mpz integer from a float
mp_small_int_t num = mp_obj_get_float(arg);
mp_int_t num = mp_obj_get_float(arg);
return MP_OBJ_NEW_SMALL_INT(num);
}
#endif
@@ -1318,7 +1339,7 @@ not_enough_args:
STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_STR(args[0]));
machine_int_t max_rep = -1;
mp_int_t max_rep = -1;
if (n_args == 4) {
max_rep = mp_obj_get_int(args[3]);
if (max_rep == 0) {
@@ -1359,11 +1380,11 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
// first pass computes the required length of the replaced string
// second pass does the replacements
for (;;) {
machine_uint_t replaced_str_index = 0;
machine_uint_t num_replacements_done = 0;
mp_uint_t replaced_str_index = 0;
mp_uint_t num_replacements_done = 0;
const byte *old_occurrence;
const byte *offset_ptr = str;
machine_uint_t str_len_remain = str_len;
mp_uint_t str_len_remain = str_len;
if (old_len == 0) {
// if old_str is empty, copy new_str to start of replaced string
// copy the replacement string
@@ -1418,6 +1439,7 @@ STATIC mp_obj_t str_replace(uint n_args, const mp_obj_t *args) {
}
STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
assert(2 <= n_args && n_args <= 4);
assert(MP_OBJ_IS_STR(args[0]));
assert(MP_OBJ_IS_STR(args[1]));
@@ -1425,34 +1447,36 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
GET_STR_DATA_LEN(args[0], haystack, haystack_len);
GET_STR_DATA_LEN(args[1], needle, needle_len);
machine_uint_t start = 0;
machine_uint_t end = haystack_len;
const byte *start = haystack;
const byte *end = haystack + haystack_len;
if (n_args >= 3 && args[2] != mp_const_none) {
start = mp_get_index(&mp_type_str, haystack_len, args[2], true);
start = str_index_to_ptr(self_type, haystack, haystack_len, args[2], true);
}
if (n_args >= 4 && args[3] != mp_const_none) {
end = mp_get_index(&mp_type_str, haystack_len, args[3], true);
end = str_index_to_ptr(self_type, haystack, haystack_len, args[3], true);
}
// if needle_len is zero then we count each gap between characters as an occurrence
if (needle_len == 0) {
return MP_OBJ_NEW_SMALL_INT(end - start + 1);
return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1);
}
// count the occurrences
machine_int_t num_occurrences = 0;
for (machine_uint_t haystack_index = start; haystack_index + needle_len <= end; haystack_index++) {
if (memcmp(&haystack[haystack_index], needle, needle_len) == 0) {
mp_int_t num_occurrences = 0;
for (const byte *haystack_ptr = start; haystack_ptr + needle_len <= end;) {
if (memcmp(haystack_ptr, needle, needle_len) == 0) {
num_occurrences++;
haystack_index += needle_len - 1;
haystack_ptr += needle_len;
} else {
haystack_ptr = utf8_next_char(haystack_ptr);
}
}
return MP_OBJ_NEW_SMALL_INT(num_occurrences);
}
STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t direction) {
if (!is_str_or_bytes(self_in)) {
STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, mp_int_t direction) {
if (!MP_OBJ_IS_STR_OR_BYTES(self_in)) {
assert(0);
}
mp_obj_type_t *self_type = mp_obj_get_type(self_in);
@@ -1477,7 +1501,7 @@ 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;
mp_uint_t position = position_ptr - str;
result[0] = mp_obj_new_str_of_type(self_type, str, position);
result[1] = arg;
result[2] = mp_obj_new_str_of_type(self_type, str + position + sep_len, str_len - position - sep_len);
@@ -1595,7 +1619,7 @@ STATIC mp_obj_t str_encode(uint n_args, const mp_obj_t *args) {
}
#endif
STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) {
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) {
if (flags == MP_BUFFER_READ) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
bufinfo->buf = (void*)str_data;
@@ -1612,38 +1636,45 @@ STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
}
#if MICROPY_CPYTHON_COMPAT
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode);
#endif
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);
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_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);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
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);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip);
MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
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
{ MP_OBJ_NEW_QSTR(MP_QSTR_decode), (mp_obj_t)&bytes_decode_obj },
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// If we have separate unicode type, then here we have methods only
// for bytes type, and it should not have encode() methods. Otherwise,
// we have non-compliant-but-practical bytestring type, which shares
// method table with bytes, so they both have encode() and decode()
// methods (which should do type checking at runtime).
{ MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj },
#endif
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
@@ -1673,17 +1704,19 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
#if !MICROPY_PY_BUILTINS_STR_UNICODE
const mp_obj_type_t mp_type_str = {
{ &mp_type_type },
.name = MP_QSTR_str,
.print = str_print,
.make_new = str_make_new,
.binary_op = str_binary_op,
.subscr = str_subscr,
.binary_op = mp_obj_str_binary_op,
.subscr = bytes_subscr,
.getiter = mp_obj_new_str_iterator,
.buffer_p = { .get_buffer = str_get_buffer },
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
.locals_dict = (mp_obj_t)&str_locals_dict,
};
#endif
// Reuses most of methods from str
const mp_obj_type_t mp_type_bytes = {
@@ -1691,10 +1724,10 @@ const mp_obj_type_t mp_type_bytes = {
.name = MP_QSTR_bytes,
.print = str_print,
.make_new = bytes_make_new,
.binary_op = str_binary_op,
.subscr = str_subscr,
.binary_op = mp_obj_str_binary_op,
.subscr = bytes_subscr,
.getiter = mp_obj_new_bytes_iterator,
.buffer_p = { .get_buffer = str_get_buffer },
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
.locals_dict = (mp_obj_t)&str_locals_dict,
};
@@ -1721,6 +1754,16 @@ mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
return o;
}
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len) {
mp_obj_str_t *o = o_in;
o->data = m_renew(byte, (byte*)o->data, o->len + 1, len + 1);
o->len = len;
o->hash = qstr_compute_hash(o->data, o->len);
byte *p = (byte*)o->data;
p[o->len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
return o;
}
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;
@@ -1833,7 +1876,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) {
}
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len) {
if (is_str_or_bytes(self_in)) {
if (MP_OBJ_IS_STR_OR_BYTES(self_in)) {
GET_STR_DATA_LEN(self_in, s, l);
*len = l;
return (const char*)s;
@@ -1848,9 +1891,10 @@ const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len) {
typedef struct _mp_obj_str_it_t {
mp_obj_base_t base;
mp_obj_t str;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_str_it_t;
#if !MICROPY_PY_BUILTINS_STR_UNICODE
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);
@@ -1870,11 +1914,20 @@ STATIC const mp_obj_type_t mp_type_str_it = {
.iternext = str_it_iternext,
};
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
o->base.type = &mp_type_str_it;
o->str = str;
o->cur = 0;
return o;
}
#endif
STATIC mp_obj_t bytes_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_SMALL_INT((mp_small_int_t)str[self->cur]);
mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(str[self->cur]);
self->cur += 1;
return o_out;
} else {
@@ -1889,14 +1942,6 @@ STATIC const mp_obj_type_t mp_type_bytes_it = {
.iternext = bytes_it_iternext,
};
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
o->base.type = &mp_type_str_it;
o->str = str;
o->cur = 0;
return o;
}
mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str) {
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
o->base.type = &mp_type_bytes_it;

View File

@@ -26,14 +26,61 @@
typedef struct _mp_obj_str_t {
mp_obj_base_t base;
// XXX here we assume the hash size is 16 bits (it is at the moment; see qstr.c)
machine_uint_t hash : 16;
mp_uint_t hash;
// len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte
machine_uint_t len : 16;
mp_uint_t len;
const byte *data;
} 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};
// use this macro to extract the string hash
#define GET_STR_HASH(str_obj_in, str_hash) \
uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \
{ str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
// use this macro to extract the string length
#define GET_STR_LEN(str_obj_in, str_len) \
uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
{ str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; }
// use this macro to extract the string data and length
#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \
const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \
{ str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \
else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
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);
mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags);
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
mp_obj_t index, bool is_slice);
MP_DECLARE_CONST_FUN_OBJ(str_encode_obj);
MP_DECLARE_CONST_FUN_OBJ(str_find_obj);
MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj);
MP_DECLARE_CONST_FUN_OBJ(str_index_obj);
MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj);
MP_DECLARE_CONST_FUN_OBJ(str_join_obj);
MP_DECLARE_CONST_FUN_OBJ(str_split_obj);
MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj);
MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj);
MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj);
MP_DECLARE_CONST_FUN_OBJ(str_strip_obj);
MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj);
MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj);
MP_DECLARE_CONST_FUN_OBJ(str_format_obj);
MP_DECLARE_CONST_FUN_OBJ(str_replace_obj);
MP_DECLARE_CONST_FUN_OBJ(str_count_obj);
MP_DECLARE_CONST_FUN_OBJ(str_partition_obj);
MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj);
MP_DECLARE_CONST_FUN_OBJ(str_lower_obj);
MP_DECLARE_CONST_FUN_OBJ(str_upper_obj);
MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj);
MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj);
MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj);
MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj);
MP_DECLARE_CONST_FUN_OBJ(str_islower_obj);

View File

@@ -43,7 +43,7 @@ typedef struct _mp_obj_stringio_t {
mp_obj_base_t base;
vstr_t *vstr;
// StringIO has single pointer used for both reading and writing
machine_uint_t pos;
mp_uint_t pos;
} 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) {
@@ -51,9 +51,9 @@ STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void
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) {
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_stringio_t *o = o_in;
machine_uint_t remaining = o->vstr->len - o->pos;
mp_uint_t remaining = o->vstr->len - o->pos;
if (size > remaining) {
size = remaining;
}
@@ -62,9 +62,9 @@ STATIC machine_int_t stringio_read(mp_obj_t o_in, void *buf, machine_uint_t size
return size;
}
STATIC machine_int_t stringio_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) {
STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_stringio_t *o = o_in;
machine_uint_t remaining = o->vstr->alloc - o->pos;
mp_uint_t remaining = o->vstr->alloc - o->pos;
if (size > remaining) {
// Take all what's already allocated...
o->vstr->len = o->vstr->alloc;
@@ -137,12 +137,12 @@ STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
STATIC const mp_stream_p_t stringio_stream_p = {
.read = stringio_read,
.write = stringio_write,
.is_text = true,
};
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 = {

359
py/objstrunicode.c Normal file
View File

@@ -0,0 +1,359 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* 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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
#include "pfenv.h"
#include "objstr.h"
#include "objlist.h"
#if MICROPY_PY_BUILTINS_STR_UNICODE
STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
/******************************************************************************/
/* str */
STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
// 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_double_quote && s < top; s++) {
if (*s == '\'') {
has_single_quote = true;
} else if (*s == '"') {
has_double_quote = true;
}
}
int quote_char = '\'';
if (has_single_quote && !has_double_quote) {
quote_char = '"';
}
print(env, "%c", quote_char);
const byte *s = str_data, *top = str_data + str_len;
while (s < top) {
unichar ch;
ch = utf8_get_char(s);
s = utf8_next_char(s);
if (ch == quote_char) {
print(env, "\\%c", quote_char);
} else if (ch == '\\') {
print(env, "\\\\");
} else if (32 <= ch && ch <= 126) {
print(env, "%c", ch);
} else if (ch == '\n') {
print(env, "\\n");
} else if (ch == '\r') {
print(env, "\\r");
} else if (ch == '\t') {
print(env, "\\t");
} else if (ch < 0x100) {
print(env, "\\x%02x", ch);
} else if (ch < 0x10000) {
print(env, "\\u%04x", ch);
} else {
print(env, "\\U%08x", ch);
}
}
print(env, "%c", quote_char);
}
STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
if (kind == PRINT_STR) {
print(env, "%.*s", str_len, str_data);
} else {
uni_print_quoted(print, env, str_data, str_len);
}
}
STATIC mp_obj_t uni_unary_op(int op, mp_obj_t self_in) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
switch (op) {
case MP_UNARY_OP_BOOL:
return MP_BOOL(str_len != 0);
case MP_UNARY_OP_LEN:
return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len));
default:
return MP_OBJ_NULL; // op not supported
}
}
STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
#if MICROPY_CPYTHON_COMPAT
if (n_kw != 0) {
mp_arg_error_unimpl_kw();
}
#endif
switch (n_args) {
case 0:
return MP_OBJ_NEW_QSTR(MP_QSTR_);
case 1:
{
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(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
}
case 2:
case 3:
{
// TODO: validate 2nd/3rd args
if (!MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected"));
}
GET_STR_DATA_LEN(args[0], str_data, str_len);
GET_STR_HASH(args[0], str_hash);
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;
}
default:
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments"));
}
}
// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or
// be capped to the first/last character of the string, depending on is_slice.
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len,
mp_obj_t index, bool is_slice) {
mp_int_t i;
// Copied from mp_get_index; I don't want bounds checking, just give me
// the integer as-is. (I can't bounds-check without scanning the whole
// string; an out-of-bounds index will be caught in the loops below.)
if (MP_OBJ_IS_SMALL_INT(index)) {
i = MP_OBJ_SMALL_INT_VALUE(index);
} else if (!mp_obj_get_int_maybe(index, &i)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index)));
}
const byte *s, *top = self_data + self_len;
if (i < 0)
{
// Negative indexing is performed by counting from the end of the string.
for (s = top - 1; i; --s) {
if (s < self_data) {
if (is_slice) {
return self_data;
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
}
if (!UTF8_IS_CONT(*s)) {
++i;
}
}
++s;
} else if (!i) {
return self_data; // Shortcut - str[0] is its base pointer
} else {
// Positive indexing, correspondingly, counts from the start of the string.
// It's assumed that negative indexing will generally be used with small
// absolute values (eg str[-1], not str[-1000000]), which means it'll be
// more efficient this way.
for (s = self_data; true; ++s) {
if (s >= top) {
if (is_slice) {
return top;
}
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range"));
}
while (UTF8_IS_CONT(*s)) {
++s;
}
if (!i--) {
return s;
}
}
}
return s;
}
STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_type_t *type = mp_obj_get_type(self_in);
GET_STR_DATA_LEN(self_in, self_data, self_len);
if (value == MP_OBJ_SENTINEL) {
// load
#if MICROPY_PY_BUILTINS_SLICE
if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_obj_t ostart, ostop, ostep;
mp_obj_slice_get(index, &ostart, &ostop, &ostep);
if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
if (type == &mp_type_bytes) {
mp_int_t start = 0, stop = self_len;
if (ostart != mp_const_none) {
start = MP_OBJ_SMALL_INT_VALUE(ostart);
if (start < 0) {
start = self_len + start;
}
}
if (ostop != mp_const_none) {
stop = MP_OBJ_SMALL_INT_VALUE(ostop);
if (stop < 0) {
stop = self_len + stop;
}
}
return mp_obj_new_str_of_type(type, self_data + start, stop - start);
}
const byte *pstart, *pstop;
if (ostart != mp_const_none) {
pstart = str_index_to_ptr(type, self_data, self_len, ostart, true);
} else {
pstart = self_data;
}
if (ostop != mp_const_none) {
// pstop will point just after the stop character. This depends on
// the \0 at the end of the string.
pstop = str_index_to_ptr(type, self_data, self_len, ostop, true);
} else {
pstop = self_data + self_len;
}
if (pstop < pstart) {
return MP_OBJ_NEW_QSTR(MP_QSTR_);
}
return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart);
}
#endif
if (type == &mp_type_bytes) {
uint index_val = mp_get_index(type, self_len, index, false);
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
}
const byte *s = str_index_to_ptr(type, self_data, self_len, index, false);
int len = 1;
if (UTF8_IS_NONASCII(*s)) {
// Count the number of 1 bits (after the first)
for (char mask = 0x40; *s & mask; mask >>= 1) {
++len;
}
}
return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string
} else {
return MP_OBJ_NULL; // op not supported
}
}
STATIC const mp_map_elem_t str_locals_dict_table[] = {
#if MICROPY_CPYTHON_COMPAT
{ MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&str_index_obj },
{ 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 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&str_format_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&str_replace_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&str_count_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_partition), (mp_obj_t)&str_partition_obj },
{ 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);
const mp_obj_type_t mp_type_str = {
{ &mp_type_type },
.name = MP_QSTR_str,
.print = uni_print,
.make_new = str_make_new,
.unary_op = uni_unary_op,
.binary_op = mp_obj_str_binary_op,
.subscr = str_subscr,
.getiter = mp_obj_new_str_iterator,
.buffer_p = { .get_buffer = mp_obj_str_get_buffer },
.locals_dict = (mp_obj_t)&str_locals_dict,
};
/******************************************************************************/
/* str iterator */
typedef struct _mp_obj_str_it_t {
mp_obj_base_t base;
mp_obj_t str;
mp_uint_t cur;
} mp_obj_str_it_t;
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) {
const byte *cur = str + self->cur;
const byte *end = utf8_next_char(str + self->cur);
mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true);
self->cur += end - cur;
return o_out;
} else {
return MP_OBJ_STOP_ITERATION;
}
}
STATIC const mp_obj_type_t mp_type_str_it = {
{ &mp_type_type },
.name = MP_QSTR_iterator,
.getiter = mp_identity,
.iternext = str_it_iternext,
};
mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) {
mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t);
o->base.type = &mp_type_str_it;
o->str = str;
o->cur = 0;
return o;
}
#endif // MICROPY_PY_BUILTINS_STR_UNICODE

View File

@@ -137,10 +137,13 @@ mp_obj_t mp_obj_tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
return s;
}
case MP_BINARY_OP_MULTIPLY: {
if (!MP_OBJ_IS_SMALL_INT(rhs)) {
mp_int_t n;
if (!mp_obj_get_int_maybe(rhs, &n)) {
return MP_OBJ_NULL; // op not supported
}
int n = MP_OBJ_SMALL_INT_VALUE(rhs);
if (n <= 0) {
return mp_const_empty_tuple;
}
mp_obj_tuple_t *s = mp_obj_new_tuple(o->len * n, NULL);
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
return s;
@@ -252,11 +255,11 @@ void mp_obj_tuple_del(mp_obj_t self_in) {
m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self);
}
machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple));
mp_obj_tuple_t *self = self_in;
// start hash with pointer to empty tuple, to make it fairly unique
machine_int_t hash = (machine_int_t)mp_const_empty_tuple;
mp_int_t hash = (mp_int_t)mp_const_empty_tuple;
for (uint i = 0; i < self->len; i++) {
hash += mp_obj_hash(self->items[i]);
}
@@ -269,7 +272,7 @@ machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) {
typedef struct _mp_obj_tuple_it_t {
mp_obj_base_t base;
mp_obj_tuple_t *tuple;
machine_uint_t cur;
mp_uint_t cur;
} mp_obj_tuple_it_t;
STATIC mp_obj_t tuple_it_iternext(mp_obj_t self_in) {

View File

@@ -26,7 +26,7 @@
typedef struct _mp_obj_tuple_t {
mp_obj_base_t base;
machine_uint_t len;
mp_uint_t len;
mp_obj_t items[];
} mp_obj_tuple_t;

View File

@@ -46,6 +46,8 @@
#define DEBUG_printf(...) (void)0
#endif
STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
/******************************************************************************/
// instance object
@@ -101,7 +103,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
struct class_lookup_data {
mp_obj_instance_t *obj;
qstr attr;
machine_uint_t meth_offset;
mp_uint_t meth_offset;
mp_obj_t *dest;
bool is_type;
};
@@ -379,11 +381,12 @@ STATIC const qstr binary_op_method_name[] = {
MP_BINARY_OP_INPLACE_MODULO,
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_MORE] = MP_QSTR___gt__,
[MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
[MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
[MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
/*
MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
*/
[MP_BINARY_OP_IN] = MP_QSTR___contains__,
/*
@@ -749,6 +752,8 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
// TODO might need to make a copy of locals_dict; at least that's how CPython does it
// Basic validation of base classes
uint len;
mp_obj_t *items;
@@ -783,6 +788,16 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"));
}
mp_map_t *locals_map = mp_obj_dict_get_map(o->locals_dict);
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP);
if (elem != NULL) {
// __new__ slot exists; check if it is a function
if (MP_OBJ_IS_FUN(elem->value)) {
// __new__ is a function, wrap it in a staticmethod decorator
elem->value = static_class_method_make_new((mp_obj_t)&mp_type_staticmethod, 1, 0, &elem->value);
}
}
return o;
}

View File

@@ -30,8 +30,8 @@
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parsenumbase.h"
@@ -109,20 +109,20 @@ STATIC const rule_t *rules[] = {
};
typedef struct _rule_stack_t {
unsigned int src_line : 24;
unsigned int rule_id : 8;
int32_t arg_i; // what should be the size and signedness?
mp_uint_t src_line : 24;
mp_uint_t rule_id : 8;
mp_uint_t arg_i : 32; // what should the bit-size be?
} rule_stack_t;
typedef struct _parser_t {
bool had_memory_error;
uint rule_stack_alloc;
uint rule_stack_top;
mp_uint_t rule_stack_alloc;
mp_uint_t rule_stack_top;
rule_stack_t *rule_stack;
uint result_stack_alloc;
uint result_stack_top;
mp_uint_t result_stack_alloc;
mp_uint_t result_stack_top;
mp_parse_node_t *result_stack;
mp_lexer_t *lexer;
@@ -132,7 +132,7 @@ STATIC inline void memory_error(parser_t *parser) {
parser->had_memory_error = true;
}
STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) {
STATIC void push_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t arg_i) {
if (parser->had_memory_error) {
return;
}
@@ -151,14 +151,14 @@ STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int ar
rs->arg_i = arg_i;
}
STATIC void push_rule_from_arg(parser_t *parser, uint arg) {
STATIC void push_rule_from_arg(parser_t *parser, mp_uint_t arg) {
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
uint rule_id = arg & RULE_ARG_ARG_MASK;
mp_uint_t rule_id = arg & RULE_ARG_ARG_MASK;
assert(rule_id < RULE_maximum_number_of);
push_rule(parser, mp_lexer_cur(parser->lexer)->src_line, rules[rule_id], 0);
}
STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) {
STATIC void pop_rule(parser_t *parser, const rule_t **rule, mp_uint_t *arg_i, mp_uint_t *src_line) {
assert(!parser->had_memory_error);
parser->rule_stack_top -= 1;
*rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
@@ -166,7 +166,7 @@ STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *s
*src_line = parser->rule_stack[parser->rule_stack_top].src_line;
}
mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg) {
if (kind == MP_PARSE_NODE_SMALL_INT) {
return (mp_parse_node_t)(kind | (arg << 1));
}
@@ -176,8 +176,8 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
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);
mp_uint_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
mp_uint_t rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
if (rule_id == RULE_string) {
return;
}
@@ -185,7 +185,7 @@ void mp_parse_node_free(mp_parse_node_t pn) {
if (adjust) {
n--;
}
for (uint i = 0; i < n; i++) {
for (mp_uint_t i = 0; i < n; i++) {
mp_parse_node_free(pns->nodes[i]);
}
if (adjust) {
@@ -196,22 +196,22 @@ void mp_parse_node_free(mp_parse_node_t pn) {
}
#if MICROPY_DEBUG_PRINTERS
void mp_parse_node_print(mp_parse_node_t pn, int indent) {
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent) {
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
printf("[% 4d] ", (int)((mp_parse_node_struct_t*)pn)->source_line);
} else {
printf(" ");
}
for (int i = 0; i < indent; i++) {
for (mp_uint_t i = 0; i < indent; i++) {
printf(" ");
}
if (MP_PARSE_NODE_IS_NULL(pn)) {
printf("NULL\n");
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
printf("int(" INT_FMT ")\n", arg);
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break;
case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break;
@@ -227,13 +227,13 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
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);
mp_uint_t 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(" UINT_FMT ") (n=" UINT_FMT ")\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
#else
printf("rule(%u) (n=%d)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), n);
printf("rule(" UINT_FMT ") (n=" UINT_FMT ")\n", (mp_uint_t)MP_PARSE_NODE_STRUCT_KIND(pns), n);
#endif
for (uint i = 0; i < n; i++) {
for (mp_uint_t i = 0; i < n; i++) {
mp_parse_node_print(pns->nodes[i], indent + 2);
}
}
@@ -244,7 +244,7 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) {
/*
STATIC void result_stack_show(parser_t *parser) {
printf("result stack, most recent first\n");
for (int i = parser->result_stack_top - 1; i >= 0; i--) {
for (mp_int_t i = parser->result_stack_top - 1; i >= 0; i--) {
mp_parse_node_print(parser->result_stack[i], 0);
}
}
@@ -258,7 +258,7 @@ STATIC mp_parse_node_t pop_result(parser_t *parser) {
return parser->result_stack[--parser->result_stack_top];
}
STATIC mp_parse_node_t peek_result(parser_t *parser, int pos) {
STATIC mp_parse_node_t peek_result(parser_t *parser, mp_uint_t pos) {
if (parser->had_memory_error) {
return MP_PARSE_NODE_NULL;
}
@@ -282,7 +282,7 @@ STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {
parser->result_stack[parser->result_stack_top++] = pn;
}
STATIC void push_result_string(parser_t *parser, int src_line, const char *str, uint len) {
STATIC void push_result_string(parser_t *parser, mp_uint_t src_line, const char *str, mp_uint_t 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);
@@ -292,7 +292,7 @@ STATIC void push_result_string(parser_t *parser, int src_line, const char *str,
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[0] = (mp_int_t)p;
pn->nodes[1] = len;
push_result_node(parser, (mp_parse_node_t)pn);
}
@@ -305,14 +305,14 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
} else if (tok->kind == MP_TOKEN_NUMBER) {
bool dec = false;
bool small_int = true;
machine_int_t int_val = 0;
int len = tok->len;
mp_int_t int_val = 0;
mp_uint_t len = tok->len;
const char *str = tok->str;
int base = 0;
int i = mp_parse_num_base(str, len, &base);
mp_uint_t base = 0;
mp_uint_t i = mp_parse_num_base(str, len, &base);
bool overflow = false;
for (; i < len; i++) {
int dig;
mp_uint_t dig;
if (unichar_isdigit(str[i]) && str[i] - '0' < base) {
dig = str[i] - '0';
} else if (base == 16 && 'a' <= str[i] && str[i] <= 'f') {
@@ -369,7 +369,7 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
push_result_node(parser, pn);
}
STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) {
STATIC void push_result_rule(parser_t *parser, mp_uint_t src_line, const rule_t *rule, mp_uint_t num_args) {
mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args);
if (pn == NULL) {
memory_error(parser);
@@ -377,7 +377,7 @@ STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule,
}
pn->source_line = src_line;
pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8);
for (int i = num_args; i > 0; i--) {
for (mp_uint_t i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
push_result_node(parser, (mp_parse_node_t)pn);
@@ -407,7 +407,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
}
// work out the top-level rule to use, and push it on the stack
int top_level_rule;
mp_uint_t top_level_rule;
switch (input_kind) {
case MP_PARSE_SINGLE_INPUT: top_level_rule = RULE_single_input; break;
case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
@@ -417,8 +417,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
// parse!
uint n, i; // state for the current rule
uint rule_src_line; // source line for the first token matched by the current rule
mp_uint_t n, i; // state for the current rule
mp_uint_t rule_src_line; // source line for the first token matched by the current rule
bool backtrack = false;
const rule_t *rule = NULL;
mp_token_kind_t tok_kind;
@@ -541,7 +541,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
// count number of arguments for the parse_node
i = 0;
emit_rule = false;
for (int x = 0; x < n; ++x) {
for (mp_uint_t x = 0; x < n; ++x) {
if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
if (tok_kind >= MP_TOKEN_NAME) {
@@ -578,7 +578,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
// never emit these rules if they have only 1 argument
// NOTE: can't put atom_paren here because we need it to distinguisg, for example, [a,b] from [(a,b)]
// TODO possibly put varargslist_name, varargslist_equal here as well
if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef) {
if (rule->rule_id == RULE_else_stmt || rule->rule_id == RULE_testlist_comp_3b || rule->rule_id == RULE_import_as_names_paren || rule->rule_id == RULE_typedargslist_name || rule->rule_id == RULE_typedargslist_colon || rule->rule_id == RULE_typedargslist_equal || rule->rule_id == RULE_dictorsetmaker_colon || rule->rule_id == RULE_classdef_2 || rule->rule_id == RULE_with_item_as || rule->rule_id == RULE_assert_stmt_extra || rule->rule_id == RULE_as_name || rule->rule_id == RULE_raise_stmt_from || rule->rule_id == RULE_vfpdef || rule->rule_id == RULE_funcdefrettype) {
emit_rule = false;
}
@@ -589,8 +589,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
i += 1;
}
int num_not_nil = 0;
for (int x = 0; x < i; ++x) {
mp_uint_t num_not_nil = 0;
for (mp_uint_t x = 0; x < i; ++x) {
if (peek_result(&parser, x) != MP_PARSE_NODE_NULL) {
num_not_nil += 1;
}
@@ -605,7 +605,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
} else if (num_not_nil == 1) {
// single result, leave it on stack
mp_parse_node_t pn = MP_PARSE_NODE_NULL;
for (int x = 0; x < i; ++x) {
for (mp_uint_t x = 0; x < i; ++x) {
mp_parse_node_t pn2 = pop_result(&parser);
if (pn2 != MP_PARSE_NODE_NULL) {
pn = pn2;
@@ -653,7 +653,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
}
} else {
for (;;) {
uint arg = rule->arg[i & 1 & n];
mp_uint_t arg = rule->arg[i & 1 & n];
switch (arg & RULE_ARG_KIND_MASK) {
case RULE_ARG_TOK:
if (mp_lexer_is_kind(lex, arg & RULE_ARG_ARG_MASK)) {

View File

@@ -46,7 +46,7 @@ struct _mp_lexer_t;
#define MP_PARSE_NODE_BYTES (0x12)
#define MP_PARSE_NODE_TOKEN (0x16)
typedef machine_uint_t mp_parse_node_t; // must be pointer size
typedef mp_uint_t mp_parse_node_t; // must be pointer size
typedef struct _mp_parse_node_struct_t {
uint32_t source_line; // line number in source file
@@ -69,15 +69,15 @@ typedef struct _mp_parse_node_struct_t {
#define MP_PARSE_NODE_LEAF_KIND(pn) ((pn) & 0x1f)
// TODO should probably have int and uint versions of this macro
#define MP_PARSE_NODE_LEAF_ARG(pn) (((machine_uint_t)(pn)) >> 5)
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((machine_int_t)(pn)) >> 1)
#define MP_PARSE_NODE_LEAF_ARG(pn) (((mp_uint_t)(pn)) >> 5)
#define MP_PARSE_NODE_LEAF_SMALL_INT(pn) (((mp_int_t)(pn)) >> 1)
#define MP_PARSE_NODE_STRUCT_KIND(pns) ((pns)->kind_num_nodes & 0xff)
#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);
mp_parse_node_t mp_parse_node_new_leaf(mp_int_t kind, mp_int_t arg);
void mp_parse_node_free(mp_parse_node_t pn);
void mp_parse_node_print(mp_parse_node_t pn, int indent);
void mp_parse_node_print(mp_parse_node_t pn, mp_uint_t indent);
typedef enum {
MP_PARSE_SINGLE_INPUT,

View File

@@ -29,8 +29,8 @@
#include <stdint.h>
#include <stdio.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
@@ -43,7 +43,7 @@
#define STR_INVALID_SYNTAX "invalid syntax"
void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_kind) {
printf(" File \"%s\", line %d, column %d\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
printf(" File \"%s\", line " UINT_FMT ", column " UINT_FMT "\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
switch (parse_error_kind) {
case MP_PARSE_ERROR_MEMORY:
printf("MemoryError: %s\n", STR_MEMORY);

View File

@@ -27,21 +27,23 @@
#include <stdbool.h>
#include <stdlib.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "nlr.h"
#include "obj.h"
#include "parsenumbase.h"
#include "parsenum.h"
#include "smallint.h"
#include "runtime.h"
#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;
mp_obj_t mp_parse_num_integer(const char *restrict str_, mp_uint_t len, mp_uint_t base) {
const byte *restrict str = (const byte *)str_;
const byte *restrict top = str + len;
bool neg = false;
mp_obj_t ret_val;
@@ -65,14 +67,14 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
}
// parse optional base prefix
str += mp_parse_num_base(str, top - str, &base);
str += mp_parse_num_base((const char*)str, top - str, &base);
// string should be an integer number
machine_int_t int_val = 0;
const char *restrict str_val_start = str;
mp_int_t int_val = 0;
const byte *restrict str_val_start = str;
for (; str < top; str++) {
// get next digit as a value
int dig = *str;
mp_uint_t dig = *str;
if (unichar_isdigit(dig) && dig - '0' < base) {
// 0-9 digit
dig = dig - '0';
@@ -129,9 +131,9 @@ have_ret_val:
overflow:
// reparse using long int
{
const char *s2 = str_val_start;
const char *s2 = (const char*)str_val_start;
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
str = s2;
str = (const byte*)s2;
goto have_ret_val;
}
@@ -139,11 +141,13 @@ 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)
#define PARSE_DEC_IN_FRAC (2)
#define PARSE_DEC_IN_EXP (3)
typedef enum {
PARSE_DEC_IN_INTG,
PARSE_DEC_IN_FRAC,
PARSE_DEC_IN_EXP,
} parse_dec_in_t;
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex) {
#if MICROPY_PY_BUILTINS_FLOAT
const char *top = str + len;
mp_float_t dec_val = 0;
@@ -185,12 +189,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
}
} else {
// string should be a decimal number
int in = PARSE_DEC_IN_INTG;
parse_dec_in_t in = PARSE_DEC_IN_INTG;
bool exp_neg = false;
int exp_val = 0;
int exp_extra = 0;
mp_int_t exp_val = 0;
mp_int_t exp_extra = 0;
for (; str < top; str++) {
int dig = *str;
mp_uint_t dig = *str;
if ('0' <= dig && dig <= '9') {
dig -= '0';
if (in == PARSE_DEC_IN_EXP) {
@@ -251,10 +255,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f
}
// return the object
#if MICROPY_PY_BUILTINS_COMPLEX
if (imag) {
return mp_obj_new_complex(0, dec_val);
} else if (force_complex) {
return mp_obj_new_complex(dec_val, 0);
#else
if (imag || force_complex) {
mp_not_implemented("complex values not supported");
#endif
} else {
return mp_obj_new_float(dec_val);
}

View File

@@ -24,5 +24,5 @@
* THE SOFTWARE.
*/
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base);
mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex);
mp_obj_t mp_parse_num_integer(const char *restrict str, mp_uint_t len, mp_uint_t base);
mp_obj_t mp_parse_num_decimal(const char *str, mp_uint_t len, bool allow_imag, bool force_complex);

View File

@@ -24,15 +24,15 @@
* THE SOFTWARE.
*/
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "parsenumbase.h"
// find real radix base, and strip preceding '0x', '0o' and '0b'
// puts base in *base, and returns number of bytes to skip the prefix
int mp_parse_num_base(const char *str, uint len, int *base) {
const char *p = str;
int c = *(p++);
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base) {
const byte *p = (const byte*)str;
unichar c = *(p++);
if ((*base == 0 || *base == 16) && c == '0') {
c = *(p++);
if ((c | 32) == 'x') {
@@ -63,6 +63,5 @@ int mp_parse_num_base(const char *str, uint len, int *base) {
}
p--;
}
return p - str;
return p - (const byte*)str;
}

View File

@@ -24,4 +24,4 @@
* THE SOFTWARE.
*/
int mp_parse_num_base(const char *str, uint len, int *base);
mp_uint_t mp_parse_num_base(const char *str, mp_uint_t len, mp_uint_t *base);

View File

@@ -27,8 +27,8 @@
#include <stdint.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "mpz.h"
@@ -111,14 +111,14 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
// 32-bits is 10 digits, add 3 for commas, 1 for sign, 1 for terminating null
// We can use 16 characters for 32-bit and 32 characters for 64-bit
#define INT_BUF_SIZE (sizeof(machine_int_t) * 4)
#define INT_BUF_SIZE (sizeof(mp_int_t) * 4)
// This function is used by stmhal port to implement printf.
// It needs to be a separate function to pfenv_print_mp_int, since converting to a mp_int looses the MSB.
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_int(const pfenv_t *pfenv, mp_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
char sign = 0;
if (sgn) {
if ((machine_int_t)x < 0) {
if ((mp_int_t)x < 0) {
sign = '-';
x = -x;
} else if (flags & PF_FLAG_SHOW_SIGN) {
@@ -232,7 +232,7 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
// The size of this buffer is rather arbitrary. If it's not large
// enough, a dynamic one will be allocated.
char stack_buf[sizeof(machine_int_t) * 4];
char stack_buf[sizeof(mp_int_t) * 4];
char *buf = stack_buf;
int buf_size = sizeof(stack_buf);
int fmt_size = 0;

View File

@@ -44,8 +44,11 @@ typedef struct _pfenv_t {
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_int(const pfenv_t *pfenv, mp_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, 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
//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args);
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...);

199
py/pfenv_printf.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include "formatfloat.h"
#endif
int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args) {
int chrs = 0;
for (;;) {
{
const char *f = fmt;
while (*f != '\0' && *f != '%') {
++f; // XXX UTF8 advance char
}
if (f > fmt) {
pfenv->print_strn(pfenv->data, fmt, f - fmt);
chrs += f - fmt;
fmt = f;
}
}
if (*fmt == '\0') {
break;
}
// move past % character
++fmt;
// parse flags, if they exist
int flags = 0;
char fill = ' ';
while (*fmt != '\0') {
if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
else if (*fmt == '0') {
flags |= PF_FLAG_PAD_AFTER_SIGN;
fill = '0';
} else break;
++fmt;
}
// parse width, if it exists
int width = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
width = width * 10 + *fmt - '0';
}
// parse precision, if it exists
int prec = -1;
if (*fmt == '.') {
++fmt;
if (*fmt == '*') {
++fmt;
prec = va_arg(args, int);
} else {
prec = 0;
for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
prec = prec * 10 + *fmt - '0';
}
}
if (prec < 0) {
prec = 0;
}
}
// parse long specifiers (current not used)
//bool long_arg = false;
if (*fmt == 'l') {
++fmt;
//long_arg = true;
}
if (*fmt == '\0') {
break;
}
switch (*fmt) {
case 'b':
if (va_arg(args, int)) {
chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width);
}
break;
case 'c':
{
char str = va_arg(args, int);
chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width);
break;
}
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
if (prec < 0) {
prec = strlen(str);
}
chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width);
} else {
chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width);
}
break;
}
case 'u':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width);
break;
case 'd':
chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width);
break;
case 'x':
case 'p': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width);
break;
case 'X':
case 'P': // ?
chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
mp_float_t f = va_arg(args, double);
chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec);
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
// Currently pfenv_print_float uses snprintf, but snprintf
// itself may be implemented in terms of pfenv_vprintf() for
// some ports. So, for extra caution, this case is handled
// with assert below. Note that currently ports which
// use MICROPY_FLOAT_IMPL_DOUBLE, don't call pfenv_vprintf()
// with float format specifier at all.
// TODO: resolve this completely
assert(0);
//#error Calling pfenv_print_float with double not supported from within printf
#else
#error Unknown MICROPY FLOAT IMPL
#endif
break;
}
#endif
default:
pfenv->print_strn(pfenv->data, fmt, 1);
chrs += 1;
break;
}
++fmt;
}
return chrs;
}
int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = pfenv_vprintf(pfenv, fmt, ap);
va_end(ap);
return ret;
}

View File

@@ -38,11 +38,15 @@ PY_O_BASENAME = \
asmthumb.o \
emitnthumb.o \
emitinlinethumb.o \
asmarm.o \
emitnarm.o \
formatfloat.o \
parsenumbase.o \
parsenum.o \
emitglue.o \
runtime.o \
nativeglue.o \
stackctrl.o \
argcheck.o \
map.o \
obj.o \
@@ -71,9 +75,11 @@ PY_O_BASENAME = \
objnone.o \
objnamedtuple.o \
objrange.o \
objreversed.o \
objset.o \
objslice.o \
objstr.o \
objstrunicode.o \
objstringio.o \
objtuple.o \
objtype.o \
@@ -100,6 +106,9 @@ PY_O_BASENAME = \
repl.o \
smallint.o \
pfenv.o \
pfenv_printf.o \
../extmod/moductypes.o \
../extmod/modzlibd.o \
# prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
@@ -139,6 +148,10 @@ $(PY_BUILD)/emitnthumb.o: CFLAGS += -DN_THUMB
$(PY_BUILD)/emitnthumb.o: py/emitnative.c
$(call compile_c)
$(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM
$(PY_BUILD)/emitnarm.o: py/emitnative.c
$(call compile_c)
# optimising gc for speed; 5ms down to 4ms on pybv2
$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)

View File

@@ -27,8 +27,8 @@
#include <assert.h>
#include <string.h>
#include "misc.h"
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
@@ -55,9 +55,9 @@
#define Q_GET_DATA(q) ((q) + 4)
// this must match the equivalent function in makeqstrdata.py
machine_uint_t qstr_compute_hash(const byte *data, uint len) {
mp_uint_t qstr_compute_hash(const byte *data, uint len) {
// djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html
machine_uint_t hash = 5381;
mp_uint_t hash = 5381;
for (const byte *top = data + len; data < top; data++) {
hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data
}
@@ -132,7 +132,7 @@ STATIC qstr qstr_add(const byte *q_ptr) {
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);
mp_uint_t str_hash = qstr_compute_hash((const byte*)str, str_len);
// search pools for the data
for (qstr_pool_t *pool = last_pool; pool != NULL; pool = pool->prev) {
@@ -154,7 +154,7 @@ qstr qstr_from_str(const char *str) {
qstr qstr_from_strn(const char *str, uint len) {
qstr q = qstr_find_strn(str, len);
if (q == 0) {
machine_uint_t hash = qstr_compute_hash((const byte*)str, len);
mp_uint_t hash = qstr_compute_hash((const byte*)str, len);
byte *q_ptr = m_new(byte, 4 + len + 1);
q_ptr[0] = hash;
q_ptr[1] = hash >> 8;
@@ -178,8 +178,8 @@ byte *qstr_build_start(uint len, byte **q_ptr) {
qstr qstr_build_end(byte *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);
mp_uint_t len = Q_GET_LENGTH(q_ptr);
mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
q_ptr[0] = hash;
q_ptr[1] = hash >> 8;
q_ptr[4 + len] = '\0';
@@ -190,7 +190,7 @@ qstr qstr_build_end(byte *q_ptr) {
return q;
}
machine_uint_t qstr_hash(qstr q) {
mp_uint_t qstr_hash(qstr q) {
return Q_GET_HASH(find_qstr(q));
}

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